From 8d49751580db804a02caf6a5b7cebe2ff26c0d7e Mon Sep 17 00:00:00 2001 From: Caz Yokoyama Date: Thu, 5 Sep 2013 16:42:39 -0700 Subject: Sample Implementation of Intel MIC User Space Daemon. This patch introduces a sample user space daemon which implements the virtio device backends on the host. The daemon creates/removes/configures virtio device backends by communicating with the Intel MIC Host Driver. The virtio devices currently supported are virtio net, virtio console and virtio block. Virtio net supports TSO/GSO. The daemon also monitors card shutdown status and takes appropriate actions like killing the virtio backends and resetting the card upon card shutdown and crashes. Co-author: Ashutosh Dixit Co-author: Sudeep Dutt Signed-off-by: Ashutosh Dixit Signed-off-by: Caz Yokoyama Signed-off-by: Dasaratharaman Chandramouli Signed-off-by: Nikhil Rao Signed-off-by: Harshavardhan R Kharche Signed-off-by: Sudeep Dutt Acked-by: Yaozu (Eddie) Dong Signed-off-by: Greg Kroah-Hartman --- Documentation/mic/mpssd/mpssd.c | 1701 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1701 insertions(+) create mode 100644 Documentation/mic/mpssd/mpssd.c (limited to 'Documentation/mic/mpssd/mpssd.c') diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c new file mode 100644 index 000000000000..8064804cdac3 --- /dev/null +++ b/Documentation/mic/mpssd/mpssd.c @@ -0,0 +1,1701 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpssd.h" +#include +#include + +static void init_mic(struct mic_info *mic); + +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 | + 1 << VIRTIO_NET_F_GUEST_UFO), +#else + .host_features = 0, +#endif +}; + +static const char *mic_config_dir = "/etc/sysconfig/mic"; +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<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); + + 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 | TUN_F_UFO; + + 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 = mic_aligned_size(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); + assert(0); + 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%x\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%lx\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; +} + +/* + * 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", + vr0->info->magic, MIC_MAGIC + type); + assert(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", + vr1->info->magic, MIC_MAGIC + type + 1); + assert(vr1->info->magic == MIC_MAGIC + type + 1); + } +done: + return va; +} + +static void +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); + + 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) { + mpsslog("%s %s Waiting... desc-> type %d status 0x%x\n", + mic->name, __func__, type, 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; + } + } + } +} + +/* 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] __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)) + wait_for_card_driver(mic, mic->mic_net.virtio_net_fd, + VIRTIO_ID_NET); + /* + * 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 %d\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%x ", len); + mpsslog("read_len 0x%x\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)) + wait_for_card_driver(mic, + mic->mic_console.virtio_console_fd, + VIRTIO_ID_CONSOLE); + + 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 %d\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%x ", len); + mpsslog("read_len 0x%x\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("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 (((__u64)&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, ©); +} + +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 = desc_idx = + next_desc(desc); + 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, "offline"))) { + 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) +{ + if (!strcmp(state, "offline")) + return MIC_OFFLINE; + if (!strcmp(state, "online")) + return MIC_ONLINE; + if (!strcmp(state, "shutting_down")) + return MIC_SHUTTING_DOWN; + if (!strcmp(state, "reset_failed")) + return MIC_RESET_FAILED; + mpsslog("%s: BUG invalid state %s\n", mic->name, state); + /* Invalid state */ + assert(0); +}; + +static void mic_handle_shutdown(struct mic_info *mic) +{ +#define SHUTDOWN_TIMEOUT 60 + int i = SHUTDOWN_TIMEOUT, ret, stat = 0; + char *shutdown_status; + while (i) { + shutdown_status = readsysfs(mic->name, "shutdown_status"); + if (!shutdown_status) + 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: + 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 (ret == mic->pid) + reset(mic); +} + +static void * +mic_config(void *arg) +{ + struct mic_info *mic = (struct mic_info *)arg; + char *state = NULL; + char pathname[PATH_MAX]; + int fd, ret; + struct pollfd ufds[1]; + char value[4096]; + + 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)); + goto error; + } + + do { + ret = read(fd, value, sizeof(value)); + if (ret < 0) { + mpsslog("%s: Failed to read sysfs entry '%s': %s\n", + mic->name, pathname, strerror(errno)); + goto close_error1; + } +retry: + state = readsysfs(mic->name, "state"); + if (!state) + goto retry; + mpsslog("%s: %s %d state %s\n", + mic->name, __func__, __LINE__, state); + switch (get_mic_state(mic, state)) { + case MIC_SHUTTING_DOWN: + mic_handle_shutdown(mic); + goto close_error; + default: + break; + } + free(state); + + ufds[0].fd = fd; + ufds[0].events = POLLERR | POLLPRI; + ret = poll(ufds, 1, -1); + if (ret < 0) { + mpsslog("%s: poll failed %s\n", + mic->name, strerror(errno)); + goto close_error1; + } + } while (1); +close_error: + free(state); +close_error1: + close(fd); +error: + 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, + "cpufreq_on;corec6_off;pc3_off;pc6_off "); + len += snprintf(buffer + len, PATH_MAX, + "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0", + mic->id); + + setsysfs(mic->name, "cmdline", buffer); + mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer); + snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id); + 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 init_mic(struct mic_info *mic); + +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 +init_mic(struct mic_info *mic) +{ + 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; + + /* + * 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); + + mic->pid = fork(); + switch (mic->pid) { + case 0: + set_log_buf_info(mic); + set_cmdline(mic); + 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: + 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; + } + pthread_create(&mic->config_thread, NULL, mic_config, mic); + } +} + +static void +start_daemon(void) +{ + struct mic_info *mic; + + for (mic = mic_list.next; mic != NULL; mic = mic->next) + init_mic(mic); + + 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 = malloc(sizeof(struct mic_info)); + if (mic->next) { + mic = mic->next; + mic->next = NULL; + memset(mic, 0, sizeof(struct mic_info)); + 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); +} -- cgit v1.2.3 From ced2c60fb5024a5cf5c33cb573b3d6a66d738f36 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Fri, 27 Sep 2013 09:49:53 -0700 Subject: misc: mic: cleanups for "--strict" checkpatch. These changes were mostly authored by Joe Perches @ https://lkml.org/lkml/2013/9/5/602 Reported-by: Joe Perches Signed-off-by: Ashutosh Dixit Signed-off-by: Dasaratharaman Chandramouli Signed-off-by: Nikhil Rao Signed-off-by: Harshavardhan R Kharche Signed-off-by: Sudeep Dutt Signed-off-by: Greg Kroah-Hartman --- Documentation/mic/mpssd/mpssd.c | 65 ++++++++++++++------------- Documentation/mic/mpssd/sysfs.c | 4 +- drivers/misc/mic/card/mic_device.c | 1 - drivers/misc/mic/card/mic_virtio.c | 17 ++++--- drivers/misc/mic/card/mic_x100.c | 4 +- drivers/misc/mic/host/mic_debugfs.c | 90 ++++++++++++++++++------------------- drivers/misc/mic/host/mic_fops.c | 6 +-- drivers/misc/mic/host/mic_intr.c | 34 +++++++------- drivers/misc/mic/host/mic_smpt.c | 14 +++--- drivers/misc/mic/host/mic_sysfs.c | 20 ++++----- drivers/misc/mic/host/mic_virtio.c | 37 +++++++-------- drivers/misc/mic/host/mic_x100.c | 33 +++++++------- 12 files changed, 158 insertions(+), 167 deletions(-) (limited to 'Documentation/mic/mpssd/mpssd.c') diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c index 8064804cdac3..f9327a29ae4c 100644 --- a/Documentation/mic/mpssd/mpssd.c +++ b/Documentation/mic/mpssd/mpssd.c @@ -246,7 +246,7 @@ static int tun_alloc(struct mic_info *mic, char *dev) if (*dev) strncpy(ifr.ifr_name, dev, IFNAMSIZ); - err = ioctl(fd, TUNSETIFF, (void *) &ifr); + err = ioctl(fd, TUNSETIFF, (void *)&ifr); if (err < 0) { mpsslog("%s %s %d TUNSETIFF failed %s\n", mic->name, __func__, __LINE__, strerror(errno)); @@ -363,7 +363,7 @@ static inline void verify_out_len(struct mic_info *mic, { if (copy->out_len != sum_iovec_len(copy)) { mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%x\n", - mic->name, __func__, __LINE__, + mic->name, __func__, __LINE__, copy->out_len, sum_iovec_len(copy)); assert(copy->out_len == sum_iovec_len(copy)); } @@ -372,7 +372,7 @@ static inline void verify_out_len(struct mic_info *mic, /* Display an iovec */ static void disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy, - const char *s, int line) + const char *s, int line) { int i; @@ -401,7 +401,7 @@ static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr, /* 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) + struct mic_vring *vr, struct mic_copy_desc *copy) { int ret; @@ -440,7 +440,7 @@ init_vr(struct mic_info *mic, int fd, int type, 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); + 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)); @@ -453,7 +453,7 @@ init_vr(struct mic_info *mic, int fd, int type, 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); + 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)); @@ -551,7 +551,7 @@ virtio_net(void *arg) 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, + VIRTIO_ID_NET, &tx_vr, &rx_vr, virtnet_dev_page.dd.num_vq)) { mpsslog("%s init_vr failed %s\n", mic->name, strerror(errno)); @@ -576,7 +576,7 @@ virtio_net(void *arg) } if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) wait_for_card_driver(mic, mic->mic_net.virtio_net_fd, - VIRTIO_ID_NET); + VIRTIO_ID_NET); /* * Check if there is data to be read from TUN and write to * virtio net fd if there is. @@ -587,7 +587,7 @@ virtio_net(void *arg) copy.iov, copy.iovcnt); if (len > 0) { struct virtio_net_hdr *hdr - = (struct virtio_net_hdr *) vnet_hdr[0]; + = (struct virtio_net_hdr *)vnet_hdr[0]; /* Disable checksums on the card since we are on a reliable PCIe link */ @@ -606,7 +606,7 @@ virtio_net(void *arg) #endif spin_for_descriptors(mic, &tx_vr); txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, ©, - len); + len); err = mic_virtio_copy(mic, mic->mic_net.virtio_net_fd, &tx_vr, @@ -644,7 +644,7 @@ virtio_net(void *arg) le16toh(rx_vr.vr.avail->idx)) { copy.iov = iov1; txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, ©, - MAX_NET_PKT_SIZE + MAX_NET_PKT_SIZE + sizeof(struct virtio_net_hdr)); err = mic_virtio_copy(mic, @@ -669,7 +669,7 @@ virtio_net(void *arg) verify_out_len(mic, ©); #ifdef DEBUG disp_iovec(mic, copy, __func__, - __LINE__); + __LINE__); mpsslog("%s %s %d ", mic->name, __func__, __LINE__); mpsslog("read from net 0x%lx\n", @@ -686,7 +686,7 @@ virtio_net(void *arg) } else { #ifdef DEBUG disp_iovec(mic, ©, __func__, - __LINE__); + __LINE__); mpsslog("%s %s %d ", mic->name, __func__, __LINE__); @@ -750,13 +750,13 @@ virtio_console(void *arg) err = grantpt(pty_fd); if (err < 0) { mpsslog("can't grant access: %s %s\n", - pts_name, strerror(errno)); + 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)); + pts_name, strerror(errno)); goto _close_pty; } console_poll[MONITOR_FD].fd = pty_fd; @@ -766,7 +766,7 @@ virtio_console(void *arg) 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, + VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr, virtcons_dev_page.dd.num_vq)) { mpsslog("%s init_vr failed %s\n", mic->name, strerror(errno)); @@ -787,7 +787,7 @@ virtio_console(void *arg) } if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) wait_for_card_driver(mic, - mic->mic_console.virtio_console_fd, + mic->mic_console.virtio_console_fd, VIRTIO_ID_CONSOLE); if (console_poll[MONITOR_FD].revents & POLLIN) { @@ -802,7 +802,7 @@ virtio_console(void *arg) #endif spin_for_descriptors(mic, &tx_vr); txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr, - ©, len); + ©, len); err = mic_virtio_copy(mic, mic->mic_console.virtio_console_fd, @@ -837,7 +837,7 @@ virtio_console(void *arg) le16toh(rx_vr.vr.avail->idx)) { copy.iov = iov1; txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr, - ©, PAGE_SIZE); + ©, PAGE_SIZE); err = mic_virtio_copy(mic, mic->mic_console.virtio_console_fd, @@ -848,7 +848,7 @@ virtio_console(void *arg) verify_out_len(mic, ©); #ifdef DEBUG disp_iovec(mic, copy, __func__, - __LINE__); + __LINE__); mpsslog("%s %s %d ", mic->name, __func__, __LINE__); mpsslog("read from net 0x%lx\n", @@ -865,7 +865,7 @@ virtio_console(void *arg) } else { #ifdef DEBUG disp_iovec(mic, copy, __func__, - __LINE__); + __LINE__); mpsslog("%s %s %d ", mic->name, __func__, __LINE__); @@ -1033,7 +1033,8 @@ start_virtblk(struct mic_info *mic, struct mic_vring *vring) } 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)) { + VIRTIO_ID_BLOCK, vring, NULL, + virtblk_dev_page.dd.num_vq)) { mpsslog("%s init_vr failed %s\n", mic->name, strerror(errno)); return false; @@ -1060,7 +1061,7 @@ 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__); + __func__, __LINE__); return -EIO; } if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) { @@ -1132,7 +1133,7 @@ write_status(int fd, __u8 *status) static void * virtio_block(void *arg) { - struct mic_info *mic = (struct mic_info *) arg; + struct mic_info *mic = (struct mic_info *)arg; int ret; struct pollfd block_poll; struct mic_vring vring; @@ -1219,8 +1220,8 @@ virtio_block(void *arg) status = 0; fos = mic->mic_virtblk.backend_addr + (hdr.sector * SECTOR_SIZE); - buffer_desc_idx = desc_idx = - next_desc(desc); + 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), @@ -1255,7 +1256,7 @@ virtio_block(void *arg) iovec, piov - iovec); if (ret < 0 && - status != 0) + status != 0) status = ret; } /* write status and update used pointer */ @@ -1391,7 +1392,7 @@ mic_config(void *arg) char value[4096]; snprintf(pathname, PATH_MAX - 1, "%s/%s/%s", - MICSYSFSDIR, mic->name, "state"); + MICSYSFSDIR, mic->name, "state"); fd = open(pathname, O_RDONLY); if (fd < 0) { @@ -1560,22 +1561,22 @@ init_mic(struct mic_info *mic) virtio_console, mic); if (err) mpsslog("%s virtcons pthread_create failed %s\n", - mic->name, strerror(err)); + 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)); + 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)); + 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)); + mic->name, strerror(errno)); while (1) sleep(60); case -1: diff --git a/Documentation/mic/mpssd/sysfs.c b/Documentation/mic/mpssd/sysfs.c index 11de72b63386..8dd326936083 100644 --- a/Documentation/mic/mpssd/sysfs.c +++ b/Documentation/mic/mpssd/sysfs.c @@ -35,7 +35,7 @@ readsysfs(char *dir, char *entry) snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry); else snprintf(filename, PATH_MAX, - "%s/%s/%s", MICSYSFSDIR, dir, entry); + "%s/%s/%s", MICSYSFSDIR, dir, entry); fd = open(filename, O_RDONLY); if (fd < 0) { @@ -75,7 +75,7 @@ setsysfs(char *dir, char *entry, char *value) snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry); else snprintf(filename, PATH_MAX, "%s/%s/%s", - MICSYSFSDIR, dir, entry); + MICSYSFSDIR, dir, entry); oldvalue = readsysfs(dir, entry); diff --git a/drivers/misc/mic/card/mic_device.c b/drivers/misc/mic/card/mic_device.c index 175d11425636..d0980ff96833 100644 --- a/drivers/misc/mic/card/mic_device.c +++ b/drivers/misc/mic/card/mic_device.c @@ -167,7 +167,6 @@ struct mic_irq *mic_request_card_irq(irqreturn_t (*func)(int irq, void *data), return (struct mic_irq *)cookie; err: return ERR_PTR(rc); - } /** diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c index 7420c33d8f65..914cc9b2caad 100644 --- a/drivers/misc/mic/card/mic_virtio.c +++ b/drivers/misc/mic/card/mic_virtio.c @@ -103,7 +103,7 @@ static void mic_finalize_features(struct virtio_device *vdev) for (i = 0; i < bits; i++) { if (test_bit(i, vdev->features)) iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)), - &out_features[i / 8]); + &out_features[i / 8]); } } @@ -197,10 +197,9 @@ static void mic_notify(struct virtqueue *vq) static void mic_del_vq(struct virtqueue *vq, int n) { struct mic_vdev *mvdev = to_micvdev(vq->vdev); - struct vring *vr = (struct vring *) (vq + 1); + struct vring *vr = (struct vring *)(vq + 1); - free_pages((unsigned long) vr->used, - get_order(mvdev->used_size[n])); + free_pages((unsigned long) vr->used, get_order(mvdev->used_size[n])); vring_del_virtqueue(vq); mic_card_unmap(mvdev->mdev, mvdev->vr[n]); mvdev->vr[n] = NULL; @@ -274,8 +273,8 @@ static struct virtqueue *mic_find_vq(struct virtio_device *vdev, /* Allocate and reassign used ring now */ mvdev->used_size[index] = PAGE_ALIGN(sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * config.num); - used = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(mvdev->used_size[index])); + used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(mvdev->used_size[index])); if (!used) { err = -ENOMEM; dev_err(mic_dev(mvdev), "%s %d err %d\n", @@ -291,7 +290,7 @@ static struct virtqueue *mic_find_vq(struct virtio_device *vdev, * vring_new_virtqueue() would ensure that * (&vq->vring == (struct vring *) (&vq->vq + 1)); */ - vr = (struct vring *) (vq + 1); + vr = (struct vring *)(vq + 1); vr->used = used; vq->priv = mvdev; @@ -544,7 +543,7 @@ static void mic_scan_devices(struct mic_driver *mdrv, bool remove) if (dev) { if (remove) iowrite8(MIC_VIRTIO_PARAM_DEV_REMOVE, - &dc->config_change); + &dc->config_change); put_device(dev); mic_handle_config_change(d, i, mdrv); ret = mic_remove_device(d, i, mdrv); @@ -559,7 +558,7 @@ static void mic_scan_devices(struct mic_driver *mdrv, bool remove) /* new device */ dev_dbg(mdrv->dev, "%s %d Adding new virtio device %p\n", - __func__, __LINE__, d); + __func__, __LINE__, d); if (!remove) mic_add_device(d, i, mdrv); } diff --git a/drivers/misc/mic/card/mic_x100.c b/drivers/misc/mic/card/mic_x100.c index f491c9163bb2..2868945c9a4d 100644 --- a/drivers/misc/mic/card/mic_x100.c +++ b/drivers/misc/mic/card/mic_x100.c @@ -66,8 +66,8 @@ void mic_send_intr(struct mic_device *mdev, int doorbell) /* Ensure that the interrupt is ordered w.r.t previous stores. */ wmb(); mic_mmio_write(mw, MIC_X100_SBOX_SDBIC0_DBREQ_BIT, - MIC_X100_SBOX_BASE_ADDRESS + - (MIC_X100_SBOX_SDBIC0 + (4 * doorbell))); + MIC_X100_SBOX_BASE_ADDRESS + + (MIC_X100_SBOX_SDBIC0 + (4 * doorbell))); } /** diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c index 98a61b4319f4..028ba5d6fd1c 100644 --- a/drivers/misc/mic/host/mic_debugfs.c +++ b/drivers/misc/mic/host/mic_debugfs.c @@ -103,7 +103,7 @@ static int mic_smpt_show(struct seq_file *s, void *pos) unsigned long flags; seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n", - mdev->id, "SMPT entry", "SW DMA addr", "RefCount"); + mdev->id, "SMPT entry", "SW DMA addr", "RefCount"); seq_puts(s, "====================================================\n"); if (mdev->smpt) { @@ -111,8 +111,8 @@ static int mic_smpt_show(struct seq_file *s, void *pos) spin_lock_irqsave(&smpt_info->smpt_lock, flags); for (i = 0; i < smpt_info->info.num_reg; i++) { seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n", - " ", i, smpt_info->entry[i].dma_addr, - smpt_info->entry[i].ref_count); + " ", i, smpt_info->entry[i].dma_addr, + smpt_info->entry[i].ref_count); } spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); } @@ -203,17 +203,17 @@ static int mic_dp_show(struct seq_file *s, void *pos) int i, j; seq_printf(s, "Bootparam: magic 0x%x\n", - bootparam->magic); + bootparam->magic); seq_printf(s, "Bootparam: h2c_shutdown_db %d\n", - bootparam->h2c_shutdown_db); + bootparam->h2c_shutdown_db); seq_printf(s, "Bootparam: h2c_config_db %d\n", - bootparam->h2c_config_db); + bootparam->h2c_config_db); seq_printf(s, "Bootparam: c2h_shutdown_db %d\n", - bootparam->c2h_shutdown_db); + bootparam->c2h_shutdown_db); seq_printf(s, "Bootparam: shutdown_status %d\n", - bootparam->shutdown_status); + bootparam->shutdown_status); seq_printf(s, "Bootparam: shutdown_card %d\n", - bootparam->shutdown_card); + bootparam->shutdown_card); for (i = sizeof(*bootparam); i < MIC_DP_SIZE; i += mic_total_desc_size(d)) { @@ -239,10 +239,10 @@ static int mic_dp_show(struct seq_file *s, void *pos) seq_printf(s, "address 0x%llx ", vqconfig->address); seq_printf(s, "num %d ", vqconfig->num); seq_printf(s, "used address 0x%llx\n", - vqconfig->used_address); + vqconfig->used_address); } - features = (__u32 *) mic_vq_features(d); + features = (__u32 *)mic_vq_features(d); seq_printf(s, "Features: Host 0x%x ", features[0]); seq_printf(s, "Guest 0x%x\n", features[1]); @@ -256,7 +256,7 @@ static int mic_dp_show(struct seq_file *s, void *pos) seq_printf(s, "Guest Ack %d ", dc->guest_ack); seq_printf(s, "Host ack %d\n", dc->host_ack); seq_printf(s, "Used address updated %d ", - dc->used_address_updated); + dc->used_address_updated); seq_printf(s, "Vdev 0x%llx\n", dc->vdev); seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db); seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db); @@ -294,10 +294,10 @@ static int mic_vdev_info_show(struct seq_file *s, void *unused) list_for_each_safe(pos, tmp, &mdev->vdev_list) { mvdev = list_entry(pos, struct mic_vdev, list); seq_printf(s, "VDEV type %d state %s in %ld out %ld\n", - mvdev->virtio_id, - mic_vdevup(mvdev) ? "UP" : "DOWN", - mvdev->in_bytes, - mvdev->out_bytes); + mvdev->virtio_id, + mic_vdevup(mvdev) ? "UP" : "DOWN", + mvdev->in_bytes, + mvdev->out_bytes); for (i = 0; i < MIC_MAX_VRINGS; i++) { struct vring_desc *desc; struct vring_avail *avail; @@ -309,38 +309,38 @@ static int mic_vdev_info_show(struct seq_file *s, void *unused) continue; desc = vrh->vring.desc; seq_printf(s, "vring i %d avail_idx %d", - i, mvr->vring.info->avail_idx & (num - 1)); + i, mvr->vring.info->avail_idx & (num - 1)); seq_printf(s, " vring i %d avail_idx %d\n", - i, mvr->vring.info->avail_idx); + i, mvr->vring.info->avail_idx); seq_printf(s, "vrh i %d weak_barriers %d", - i, vrh->weak_barriers); + i, vrh->weak_barriers); seq_printf(s, " last_avail_idx %d last_used_idx %d", - vrh->last_avail_idx, vrh->last_used_idx); + vrh->last_avail_idx, vrh->last_used_idx); seq_printf(s, " completed %d\n", vrh->completed); for (j = 0; j < num; j++) { seq_printf(s, "desc[%d] addr 0x%llx len %d", - j, desc->addr, desc->len); + j, desc->addr, desc->len); seq_printf(s, " flags 0x%x next %d\n", - desc->flags, - desc->next); + desc->flags, desc->next); desc++; } avail = vrh->vring.avail; seq_printf(s, "avail flags 0x%x idx %d\n", - avail->flags, avail->idx & (num - 1)); + avail->flags, avail->idx & (num - 1)); seq_printf(s, "avail flags 0x%x idx %d\n", - avail->flags, avail->idx); + avail->flags, avail->idx); for (j = 0; j < num; j++) seq_printf(s, "avail ring[%d] %d\n", - j, avail->ring[j]); + j, avail->ring[j]); used = vrh->vring.used; seq_printf(s, "used flags 0x%x idx %d\n", - used->flags, used->idx & (num - 1)); + used->flags, used->idx & (num - 1)); seq_printf(s, "used flags 0x%x idx %d\n", - used->flags, used->idx); + used->flags, used->idx); for (j = 0; j < num; j++) seq_printf(s, "used ring[%d] id %d len %d\n", - j, used->ring[j].id, used->ring[j].len); + j, used->ring[j].id, + used->ring[j].len); } } mutex_unlock(&mdev->mic_mutex); @@ -389,7 +389,7 @@ static int mic_msi_irq_info_show(struct seq_file *s, void *pos) reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry); seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n", - "IRQ:", vector, "Entry:", entry, i, reg); + "IRQ:", vector, "Entry:", entry, i, reg); seq_printf(s, "%-10s", "offset:"); for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--) @@ -400,8 +400,8 @@ static int mic_msi_irq_info_show(struct seq_file *s, void *pos) seq_printf(s, "%-10s", "count:"); for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--) seq_printf(s, "%4d ", - (mdev->irq_info.mic_msi_map[i] & BIT(j)) ? - 1 : 0); + (mdev->irq_info.mic_msi_map[i] & + BIT(j)) ? 1 : 0); seq_puts(s, "\n\n"); } } else { @@ -409,7 +409,6 @@ static int mic_msi_irq_info_show(struct seq_file *s, void *pos) } return 0; - } static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file) @@ -443,26 +442,23 @@ void mic_create_debug_dir(struct mic_device *mdev) if (!mdev->dbg_dir) return; - debugfs_create_file("log_buf", 0444, mdev->dbg_dir, - mdev, &log_buf_ops); + debugfs_create_file("log_buf", 0444, mdev->dbg_dir, mdev, &log_buf_ops); - debugfs_create_file("smpt", 0444, mdev->dbg_dir, - mdev, &smpt_file_ops); + debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops); - debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, - mdev, &soft_reset_ops); + debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, mdev, + &soft_reset_ops); - debugfs_create_file("post_code", 0444, mdev->dbg_dir, - mdev, &post_code_ops); + debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev, + &post_code_ops); - debugfs_create_file("dp", 0444, mdev->dbg_dir, - mdev, &dp_ops); + debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops); - debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, - mdev, &vdev_info_ops); + debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev, + &vdev_info_ops); - debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, - mdev, &msi_irq_info_ops); + debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev, + &msi_irq_info_ops); } /** diff --git a/drivers/misc/mic/host/mic_fops.c b/drivers/misc/mic/host/mic_fops.c index e699c80a8c0a..8dc6ff16845a 100644 --- a/drivers/misc/mic/host/mic_fops.c +++ b/drivers/misc/mic/host/mic_fops.c @@ -140,9 +140,9 @@ unsigned int mic_poll(struct file *f, poll_table *wait) poll_wait(f, &mvdev->waitq, wait); - if (mic_vdev_inited(mvdev)) + if (mic_vdev_inited(mvdev)) { mask = POLLERR; - else if (mvdev->poll_wake) { + } else if (mvdev->poll_wake) { mvdev->poll_wake = 0; mask = POLLIN | POLLOUT; } @@ -152,7 +152,7 @@ unsigned int mic_poll(struct file *f, poll_table *wait) static inline int mic_query_offset(struct mic_vdev *mvdev, unsigned long offset, - unsigned long *size, unsigned long *pa) + unsigned long *size, unsigned long *pa) { struct mic_device *mdev = mvdev->mdev; unsigned long start = MIC_DP_SIZE; diff --git a/drivers/misc/mic/host/mic_intr.c b/drivers/misc/mic/host/mic_intr.c index 71a7521cf1a4..f9c29bc918bc 100644 --- a/drivers/misc/mic/host/mic_intr.c +++ b/drivers/misc/mic/host/mic_intr.c @@ -71,8 +71,8 @@ static irqreturn_t mic_interrupt(int irq, void *dev) /* Return the interrupt offset from the index. Index is 0 based. */ static u16 mic_map_src_to_offset(struct mic_device *mdev, - int intr_src, enum mic_intr_type type) { - + int intr_src, enum mic_intr_type type) +{ if (type >= MIC_NUM_INTR_TYPES) return MIC_NUM_OFFSETS; if (intr_src >= mdev->intr_info->intr_len[type]) @@ -112,7 +112,7 @@ static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, struct mic_intr_cb *intr_cb; unsigned long flags; int rc; - intr_cb = kmalloc(sizeof(struct mic_intr_cb), GFP_KERNEL); + intr_cb = kmalloc(sizeof(*intr_cb), GFP_KERNEL); if (!intr_cb) return ERR_PTR(-ENOMEM); @@ -159,7 +159,7 @@ static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx) if (intr_cb->cb_id == idx) { list_del(pos); ida_simple_remove(&mdev->irq_info.cb_ida, - intr_cb->cb_id); + intr_cb->cb_id); kfree(intr_cb); spin_unlock_irqrestore( &mdev->irq_info.mic_intr_lock, flags); @@ -182,9 +182,10 @@ static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx) static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev) { int rc, i; + int entry_size = sizeof(*mdev->irq_info.msix_entries); - mdev->irq_info.msix_entries = kmalloc(sizeof(struct msix_entry) * - MIC_MIN_MSIX, GFP_KERNEL); + mdev->irq_info.msix_entries = kmalloc_array(MIC_MIN_MSIX, + entry_size, GFP_KERNEL); if (!mdev->irq_info.msix_entries) { rc = -ENOMEM; goto err_nomem1; @@ -231,8 +232,9 @@ static int mic_setup_callbacks(struct mic_device *mdev) { int i; - mdev->irq_info.cb_list = kmalloc(sizeof(struct list_head) * - MIC_NUM_OFFSETS, GFP_KERNEL); + mdev->irq_info.cb_list = kmalloc_array(MIC_NUM_OFFSETS, + sizeof(*mdev->irq_info.cb_list), + GFP_KERNEL); if (!mdev->irq_info.cb_list) return -ENOMEM; @@ -261,7 +263,7 @@ static void mic_release_callbacks(struct mic_device *mdev) if (list_empty(&mdev->irq_info.cb_list[i])) { spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, - flags); + flags); break; } @@ -269,7 +271,7 @@ static void mic_release_callbacks(struct mic_device *mdev) intr_cb = list_entry(pos, struct mic_intr_cb, list); list_del(pos); ida_simple_remove(&mdev->irq_info.cb_ida, - intr_cb->cb_id); + intr_cb->cb_id); kfree(intr_cb); } spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); @@ -427,8 +429,8 @@ struct mic_irq *mic_request_irq(struct mic_device *mdev, offset = mic_map_src_to_offset(mdev, intr_src, type); if (offset >= MIC_NUM_OFFSETS) { dev_err(mdev->sdev->parent, - "Error mapping index %d to a valid source id.\n", - intr_src); + "Error mapping index %d to a valid source id.\n", + intr_src); rc = -EINVAL; goto err; } @@ -437,7 +439,7 @@ struct mic_irq *mic_request_irq(struct mic_device *mdev, msix = mic_get_available_vector(mdev); if (!msix) { dev_err(mdev->sdev->parent, - "No MSIx vectors available for use.\n"); + "No MSIx vectors available for use.\n"); rc = -ENOSPC; goto err; } @@ -460,7 +462,7 @@ struct mic_irq *mic_request_irq(struct mic_device *mdev, offset, func, data); if (IS_ERR(intr_cb)) { dev_err(mdev->sdev->parent, - "No available callback entries for use\n"); + "No available callback entries for use\n"); rc = PTR_ERR(intr_cb); goto err; } @@ -506,7 +508,7 @@ void mic_free_irq(struct mic_device *mdev, if (mdev->irq_info.num_vectors > 1) { if (entry >= mdev->irq_info.num_vectors) { dev_warn(mdev->sdev->parent, - "entry %d should be < num_irq %d\n", + "entry %d should be < num_irq %d\n", entry, mdev->irq_info.num_vectors); return; } @@ -581,7 +583,7 @@ void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev) for (i = 0; i < mdev->irq_info.num_vectors; i++) { if (mdev->irq_info.mic_msi_map[i]) dev_warn(&pdev->dev, "irq %d may still be in use.\n", - mdev->irq_info.msix_entries[i].vector); + mdev->irq_info.msix_entries[i].vector); } kfree(mdev->irq_info.mic_msi_map); kfree(mdev->irq_info.msix_entries); diff --git a/drivers/misc/mic/host/mic_smpt.c b/drivers/misc/mic/host/mic_smpt.c index 003d02b212be..fae474c4899e 100644 --- a/drivers/misc/mic/host/mic_smpt.c +++ b/drivers/misc/mic/host/mic_smpt.c @@ -84,7 +84,7 @@ static void mic_add_smpt_entry(int spt, s64 *ref, u64 addr, for (i = spt; i < spt + entries; i++, addr += smpt_info->info.page_size) { if (!smpt_info->entry[i].ref_count && - (smpt_info->entry[i].dma_addr != addr)) { + (smpt_info->entry[i].dma_addr != addr)) { mdev->smpt_ops->set(mdev, addr, i); smpt_info->entry[i].dma_addr = addr; } @@ -183,7 +183,7 @@ mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr) if (!mic_is_system_addr(mdev, mic_addr)) { dev_err(mdev->sdev->parent, - "mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr); + "mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr); return -EINVAL; } spt = mic_sys_addr_to_smpt(mdev, mic_addr); @@ -286,7 +286,7 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) smpt_info->entry[i].ref_count -= ref[i - spt]; if (smpt_info->entry[i].ref_count < 0) dev_warn(mdev->sdev->parent, - "ref count for entry %d is negative\n", i); + "ref count for entry %d is negative\n", i); } spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); kfree(ref); @@ -320,7 +320,7 @@ dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size) "mic_map failed dma_addr 0x%llx size 0x%lx\n", dma_addr, size); pci_unmap_single(pdev, dma_addr, - size, PCI_DMA_BIDIRECTIONAL); + size, PCI_DMA_BIDIRECTIONAL); } } return mic_addr; @@ -366,8 +366,8 @@ int mic_smpt_init(struct mic_device *mdev) smpt_info = mdev->smpt; mdev->smpt_ops->init(mdev); - smpt_info->entry = kmalloc(sizeof(struct mic_smpt) - * smpt_info->info.num_reg, GFP_KERNEL); + smpt_info->entry = kmalloc_array(smpt_info->info.num_reg, + sizeof(*smpt_info->entry), GFP_KERNEL); if (!smpt_info->entry) { err = -ENOMEM; goto free_smpt; @@ -412,7 +412,7 @@ void mic_smpt_uninit(struct mic_device *mdev) smpt_info->entry[i].ref_count); if (smpt_info->entry[i].ref_count) dev_warn(mdev->sdev->parent, - "ref count for entry %d is not zero\n", i); + "ref count for entry %d is not zero\n", i); } kfree(smpt_info->entry); kfree(smpt_info); diff --git a/drivers/misc/mic/host/mic_sysfs.c b/drivers/misc/mic/host/mic_sysfs.c index 029a4f31bee7..75746adfb155 100644 --- a/drivers/misc/mic/host/mic_sysfs.c +++ b/drivers/misc/mic/host/mic_sysfs.c @@ -130,7 +130,7 @@ state_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t state_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { int rc = 0; struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -163,7 +163,7 @@ done: static DEVICE_ATTR_RW(state); static ssize_t shutdown_status_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -193,7 +193,7 @@ cmdline_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t cmdline_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -239,7 +239,7 @@ firmware_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t firmware_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -284,7 +284,7 @@ ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t ramdisk_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -330,7 +330,7 @@ bootmode_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t bootmode_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -363,7 +363,7 @@ static DEVICE_ATTR_RW(bootmode); static ssize_t log_buf_addr_show(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -375,7 +375,7 @@ log_buf_addr_show(struct device *dev, struct device_attribute *attr, static ssize_t log_buf_addr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct mic_device *mdev = dev_get_drvdata(dev->parent); int ret; @@ -397,7 +397,7 @@ static DEVICE_ATTR_RW(log_buf_addr); static ssize_t log_buf_len_show(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { struct mic_device *mdev = dev_get_drvdata(dev->parent); @@ -409,7 +409,7 @@ log_buf_len_show(struct device *dev, struct device_attribute *attr, static ssize_t log_buf_len_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct mic_device *mdev = dev_get_drvdata(dev->parent); int ret; diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c index 9e0456fb1ea8..0c883cd4f1d1 100644 --- a/drivers/misc/mic/host/mic_virtio.c +++ b/drivers/misc/mic/host/mic_virtio.c @@ -195,7 +195,7 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, MIC_VRINGH_READ, &out_len); if (ret) { dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); + __func__, __LINE__, ret); break; } len -= out_len; @@ -206,7 +206,7 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, !MIC_VRINGH_READ, &out_len); if (ret) { dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); + __func__, __LINE__, ret); break; } len -= out_len; @@ -225,8 +225,7 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, * Update the used ring if a descriptor was available and some data was * copied in/out and the user asked for a used ring update. */ - if (*head != USHRT_MAX && copy->out_len && - copy->update_used) { + if (*head != USHRT_MAX && copy->out_len && copy->update_used) { u32 total = 0; /* Determine the total data consumed */ @@ -367,7 +366,6 @@ void mic_bh_handler(struct work_struct *work) static irqreturn_t mic_virtio_intr_handler(int irq, void *data) { - struct mic_vdev *mvdev = data; struct mic_device *mdev = mvdev->mdev; @@ -394,7 +392,7 @@ int mic_virtio_config_change(struct mic_vdev *mvdev, } if (copy_from_user(mic_vq_configspace(mvdev->dd), - argp, mvdev->dd->config_len)) { + argp, mvdev->dd->config_len)) { dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, -EFAULT); ret = -EFAULT; @@ -438,8 +436,8 @@ static int mic_copy_dp_entry(struct mic_vdev *mvdev, return -EFAULT; } - if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE - || dd.num_vq > MIC_MAX_VRINGS) { + if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE || + dd.num_vq > MIC_MAX_VRINGS) { dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, -EINVAL); return -EINVAL; @@ -503,7 +501,7 @@ static void mic_init_device_ctrl(struct mic_vdev *mvdev, { struct mic_device_ctrl *dc; - dc = mvdev->dc = (void *)devpage + mic_aligned_desc_size(devpage); + dc = (void *)devpage + mic_aligned_desc_size(devpage); dc->config_change = 0; dc->guest_ack = 0; @@ -512,6 +510,7 @@ static void mic_init_device_ctrl(struct mic_vdev *mvdev, dc->used_address_updated = 0; dc->c2h_vdev_db = -1; dc->h2c_vdev_db = -1; + mvdev->dc = dc; } int mic_virtio_add_device(struct mic_vdev *mvdev, @@ -551,7 +550,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, sizeof(struct _mic_vring_info)); vr->va = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(vr_size)); + get_order(vr_size)); if (!vr->va) { ret = -ENOMEM; dev_err(mic_dev(mvdev), "%s %d err %d\n", @@ -564,8 +563,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, vqconfig[i].address = mic_map_single(mdev, vr->va, vr_size); if (mic_map_error(vqconfig[i].address)) { - free_pages((unsigned long)vr->va, - get_order(vr_size)); + free_pages((unsigned long)vr->va, get_order(vr_size)); ret = -ENOMEM; dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, ret); @@ -573,8 +571,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, } vqconfig[i].address = cpu_to_le64(vqconfig[i].address); - vring_init(&vr->vr, num, - vr->va, MIC_VIRTIO_RING_ALIGN); + vring_init(&vr->vr, num, vr->va, MIC_VIRTIO_RING_ALIGN); ret = vringh_init_kern(&mvr->vrh, *(u32 *)mic_vq_features(mvdev->dd), num, false, vr->vr.desc, vr->vr.avail, vr->vr.used); @@ -593,8 +590,8 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, __func__, __LINE__, i, vr->va, vr->info, vr_size); } - snprintf(irqname, sizeof(irqname), - "mic%dvirtio%d", mdev->id, mvdev->virtio_id); + snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, + mvdev->virtio_id); mvdev->virtio_db = mic_next_db(mdev); mvdev->virtio_cookie = mic_request_irq(mdev, mic_virtio_intr_handler, irqname, mvdev, mvdev->virtio_db, MIC_INTR_DB); @@ -628,9 +625,9 @@ err: for (j = 0; j < i; j++) { struct mic_vringh *mvr = &mvdev->mvr[j]; mic_unmap_single(mdev, le64_to_cpu(vqconfig[j].address), - mvr->vring.len); + mvr->vring.len); free_pages((unsigned long)mvr->vring.va, - get_order(mvr->vring.len)); + get_order(mvr->vring.len)); } mutex_unlock(&mdev->mic_mutex); return ret; @@ -676,9 +673,9 @@ skip_hot_remove: vringh_kiov_cleanup(&mvr->riov); vringh_kiov_cleanup(&mvr->wiov); mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), - mvr->vring.len); + mvr->vring.len); free_pages((unsigned long)mvr->vring.va, - get_order(mvr->vring.len)); + get_order(mvr->vring.len)); } list_for_each_safe(pos, tmp, &mdev->vdev_list) { diff --git a/drivers/misc/mic/host/mic_x100.c b/drivers/misc/mic/host/mic_x100.c index 3a0d660bad4a..81e9541b784c 100644 --- a/drivers/misc/mic/host/mic_x100.c +++ b/drivers/misc/mic/host/mic_x100.c @@ -46,8 +46,8 @@ mic_x100_write_spad(struct mic_device *mdev, unsigned int idx, u32 val) dev_dbg(mdev->sdev->parent, "Writing 0x%x to scratch pad index %d\n", val, idx); mic_mmio_write(&mdev->mmio, val, - MIC_X100_SBOX_BASE_ADDRESS + - MIC_X100_SBOX_SPAD0 + idx * 4); + MIC_X100_SBOX_BASE_ADDRESS + + MIC_X100_SBOX_SPAD0 + idx * 4); } /** @@ -130,8 +130,8 @@ static void mic_x100_send_sbox_intr(struct mic_device *mdev, { struct mic_mw *mw = &mdev->mmio; u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8; - u32 apicicr_low = mic_mmio_read(mw, - MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); + u32 apicicr_low = mic_mmio_read(mw, MIC_X100_SBOX_BASE_ADDRESS + + apic_icr_offset); /* for MIC we need to make sure we "hit" the send_icr bit (13) */ apicicr_low = (apicicr_low | (1 << 13)); @@ -139,7 +139,7 @@ static void mic_x100_send_sbox_intr(struct mic_device *mdev, /* Ensure that the interrupt is ordered w.r.t. previous stores. */ wmb(); mic_mmio_write(mw, apicicr_low, - MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); + MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); } /** @@ -153,7 +153,7 @@ static void mic_x100_send_rdmasr_intr(struct mic_device *mdev, /* Ensure that the interrupt is ordered w.r.t. previous stores. */ wmb(); mic_mmio_write(&mdev->mmio, 0, - MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset); + MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset); } /** @@ -212,7 +212,7 @@ done: */ static void mic_x100_hw_intr_init(struct mic_device *mdev) { - mdev->intr_info = (struct mic_intr_info *) mic_x100_intr_init; + mdev->intr_info = (struct mic_intr_info *)mic_x100_intr_init; } /** @@ -244,7 +244,7 @@ mic_x100_read_msi_to_src_map(struct mic_device *mdev, int idx) */ static void mic_x100_program_msi_to_src_map(struct mic_device *mdev, - int idx, int offset, bool set) + int idx, int offset, bool set) { unsigned long reg; struct mic_mw *mw = &mdev->mmio; @@ -308,12 +308,12 @@ static void mic_x100_send_firmware_intr(struct mic_device *mdev) apicicr_low = (vector | (1 << 13)); mic_mmio_write(mw, mic_x100_get_apic_id(mdev), - MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset + 4); + MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset + 4); /* Ensure that the interrupt is ordered w.r.t. previous stores. */ wmb(); mic_mmio_write(mw, apicicr_low, - MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); + MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); } /** @@ -365,8 +365,7 @@ mic_x100_load_command_line(struct mic_device *mdev, const struct firmware *fw) len += snprintf(buf, CMDLINE_SIZE - len, " mem=%dM", boot_mem); if (mdev->cmdline) - snprintf(buf + len, CMDLINE_SIZE - len, - " %s", mdev->cmdline); + snprintf(buf + len, CMDLINE_SIZE - len, " %s", mdev->cmdline); memcpy_toio(cmd_line_va, buf, strlen(buf) + 1); kfree(buf); return 0; @@ -397,8 +396,7 @@ mic_x100_load_ramdisk(struct mic_device *mdev) * Typically the bootaddr for card OS is 64M * so copy over the ramdisk @ 128M. */ - memcpy_toio(mdev->aper.va + (mdev->bootaddr << 1), - fw->data, fw->size); + memcpy_toio(mdev->aper.va + (mdev->bootaddr << 1), fw->data, fw->size); iowrite32(cpu_to_le32(mdev->bootaddr << 1), &bp->hdr.ramdisk_image); iowrite32(cpu_to_le32(fw->size), &bp->hdr.ramdisk_size); release_firmware(fw); @@ -484,8 +482,7 @@ mic_x100_load_firmware(struct mic_device *mdev, const char *buf) if (mdev->ramdisk) rc = mic_x100_load_ramdisk(mdev); error: - dev_dbg(mdev->sdev->parent, "%s %d rc %d\n", - __func__, __LINE__, rc); + dev_dbg(mdev->sdev->parent, "%s %d rc %d\n", __func__, __LINE__, rc); done: return rc; } @@ -524,8 +521,8 @@ mic_x100_smpt_set(struct mic_device *mdev, dma_addr_t dma_addr, u8 index) uint32_t smpt_reg_val = BUILD_SMPT(SNOOP_ON, dma_addr >> mdev->smpt->info.page_shift); mic_mmio_write(&mdev->mmio, smpt_reg_val, - MIC_X100_SBOX_BASE_ADDRESS + - MIC_X100_SBOX_SMPT00 + (4 * index)); + MIC_X100_SBOX_BASE_ADDRESS + + MIC_X100_SBOX_SMPT00 + (4 * index)); } /** -- cgit v1.2.3 From 6078e0bef2236f323377c53e77e26288fb52ee23 Mon Sep 17 00:00:00 2001 From: Sudeep Dutt Date: Wed, 2 Oct 2013 16:09:00 -0700 Subject: misc: mic: Fix build issues in sample daemon. Specifying gcc format function attribute for mpsslog(..) and building on 32 bit systems exposed a few build issues in the sample MIC daemon which are fixed by this patch. Some of these changes were authored by Joe Perches @ https://lkml.org/lkml/2013/9/27/419 Reported-by: Joe Perches Signed-off-by: Ashutosh Dixit Signed-off-by: Caz Yokoyama Signed-off-by: Sudeep Dutt Signed-off-by: Greg Kroah-Hartman --- Documentation/mic/mpssd/mpssd.c | 22 +++++++++++----------- Documentation/mic/mpssd/mpssd.h | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'Documentation/mic/mpssd/mpssd.c') diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c index f9327a29ae4c..82c6bc2e3cb6 100644 --- a/Documentation/mic/mpssd/mpssd.c +++ b/Documentation/mic/mpssd/mpssd.c @@ -362,9 +362,9 @@ 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%x\n", + 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)); + copy->out_len, sum_iovec_len(copy)); assert(copy->out_len == sum_iovec_len(copy)); } } @@ -377,7 +377,7 @@ disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy, int i; for (i = 0; i < copy->iovcnt; i++) - mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%lx\n", + 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); } @@ -630,7 +630,7 @@ virtio_net(void *arg) disp_iovec(mic, ©, __func__, __LINE__); mpsslog("%s %s %d read failed %s ", mic->name, __func__, __LINE__, strerror(errno)); - mpsslog("cnt %d sum %d\n", + mpsslog("cnt %d sum %zd\n", copy.iovcnt, sum_iovec_len(©)); } } @@ -680,8 +680,8 @@ virtio_net(void *arg) if (len != sum_iovec_len(©)) { mpsslog("Tun write failed %s ", strerror(errno)); - mpsslog("len 0x%x ", len); - mpsslog("read_len 0x%x\n", + mpsslog("len 0x%zx ", len); + mpsslog("read_len 0x%zx\n", sum_iovec_len(©)); } else { #ifdef DEBUG @@ -827,7 +827,7 @@ virtio_console(void *arg) mpsslog("%s %s %d read failed %s ", mic->name, __func__, __LINE__, strerror(errno)); - mpsslog("cnt %d sum %d\n", + mpsslog("cnt %d sum %zd\n", copy.iovcnt, sum_iovec_len(©)); } } @@ -859,8 +859,8 @@ virtio_console(void *arg) if (len != sum_iovec_len(©)) { mpsslog("Tun write failed %s ", strerror(errno)); - mpsslog("len 0x%x ", len); - mpsslog("read_len 0x%x\n", + mpsslog("len 0x%zx ", len); + mpsslog("read_len 0x%zx\n", sum_iovec_len(©)); } else { #ifdef DEBUG @@ -953,7 +953,7 @@ set_backend_file(struct mic_info *mic) return false; mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1); if (mic->mic_virtblk.backend_file == NULL) { - mpsslog("can't allocate memory\n", mic->name, mic->id); + mpsslog("%s %d can't allocate memory\n", mic->name, mic->id); return false; } strcpy(mic->mic_virtblk.backend_file, evv + 1); @@ -1026,7 +1026,7 @@ close_backend(struct mic_info *mic) static bool start_virtblk(struct mic_info *mic, struct mic_vring *vring) { - if (((__u64)&virtblk_dev_page.blk_config % 8) != 0) { + if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) { mpsslog("%s: blk_config is not 8 byte aligned.\n", mic->name); return false; diff --git a/Documentation/mic/mpssd/mpssd.h b/Documentation/mic/mpssd/mpssd.h index b6dee38ca5b1..ccd589ff9146 100644 --- a/Documentation/mic/mpssd/mpssd.h +++ b/Documentation/mic/mpssd/mpssd.h @@ -94,6 +94,7 @@ struct mic_info { 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); -- cgit v1.2.3 From af190494f9b2e1fb6e1c039e9626c3c334717da1 Mon Sep 17 00:00:00 2001 From: Dasaratharaman Chandramouli Date: Thu, 3 Oct 2013 18:06:23 -0700 Subject: misc: mic: Enable OSPM suspend and resume support. This patch enables support for OSPM suspend and resume in the MIC driver. During a host suspend event, the driver performs an orderly shutdown of the cards if they are online. Upon resume, any cards that were previously online before suspend are rebooted. The driver performs an orderly shutdown of the card primarily to ensure that applications in the card are terminated and mounted devices are safely un-mounted before the card is powered down in the event of an OSPM suspend. The driver makes use of the MIC daemon to accomplish OSPM suspend and resume. The driver registers a PM notifier per MIC device. The devices get notified synchronously during PM_SUSPEND_PREPARE and PM_POST_SUSPEND phases. During the PM_SUSPEND_PREPARE phase, the driver performs one of the following three tasks. 1) If the card is 'offline', the driver sets the card to a 'suspended' state and returns. 2) If the card is 'online', the driver initiates card shutdown by setting the card state to suspending. This notifies the MIC daemon which invokes shutdown and sets card state to 'suspended'. The driver returns after the shutdown is complete. 3) If the card is already being shutdown, possibly by a host user space application, the driver sets the card state to 'suspended' and returns after the shutdown is complete. During the PM_POST_SUSPEND phase, the driver simply notifies the daemon and returns. The daemon boots those cards that were previously online during the suspend phase. Signed-off-by: Ashutosh Dixit Signed-off-by: Nikhil Rao Signed-off-by: Harshavardhan R Kharche Signed-off-by: Sudeep Dutt Signed-off-by: Dasaratharaman Chandramouli Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-mic.txt | 60 +++++++------ Documentation/mic/mic_overview.txt | 4 +- Documentation/mic/mpssd/mpssd.c | 27 +++++- Documentation/mic/mpssd/mpssd.h | 1 + drivers/misc/mic/host/mic_boot.c | 120 +++++++++++++++++++++++++- drivers/misc/mic/host/mic_device.h | 8 ++ drivers/misc/mic/host/mic_main.c | 63 +++++++++++++- drivers/misc/mic/host/mic_sysfs.c | 7 ++ include/uapi/linux/mic_common.h | 2 + 9 files changed, 257 insertions(+), 35 deletions(-) (limited to 'Documentation/mic/mpssd/mpssd.c') diff --git a/Documentation/ABI/testing/sysfs-class-mic.txt b/Documentation/ABI/testing/sysfs-class-mic.txt index 82cdad3b614a..13f48afc534f 100644 --- a/Documentation/ABI/testing/sysfs-class-mic.txt +++ b/Documentation/ABI/testing/sysfs-class-mic.txt @@ -1,6 +1,6 @@ What: /sys/class/mic/ -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: The mic class directory belongs to Intel MIC devices and @@ -9,8 +9,8 @@ Description: Integrated Core (MIC) architecture that runs a Linux OS. What: /sys/class/mic/mic(x) -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: The directories /sys/class/mic/mic0, /sys/class/mic/mic1 etc., @@ -18,33 +18,41 @@ Description: information specific to that MIC device. What: /sys/class/mic/mic(x)/family -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: Provides information about the Coprocessor family for an Intel MIC device. For example - "x100" What: /sys/class/mic/mic(x)/stepping -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: Provides information about the silicon stepping for an Intel MIC device. For example - "A0" or "B0" What: /sys/class/mic/mic(x)/state -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: When read, this entry provides the current state of an Intel MIC device in the context of the card OS. Possible values that will be read are: - "offline" - The MIC device is ready to boot the card OS. + "offline" - The MIC device is ready to boot the card OS. On + reading this entry after an OSPM resume, a "boot" has to be + written to this entry if the card was previously shutdown + during OSPM suspend. "online" - The MIC device has initiated booting a card OS. "shutting_down" - The card OS is shutting down. "reset_failed" - The MIC device has failed to reset. + "suspending" - The MIC device is currently being prepared for + suspend. On reading this entry, a "suspend" has to be written + to the state sysfs entry to ensure the card is shutdown during + OSPM suspend. + "suspended" - The MIC device has been suspended. When written, this sysfs entry triggers different state change operations depending upon the current state of the card OS. @@ -54,10 +62,12 @@ Description: sysfs entries. "reset" - Initiates device reset. "shutdown" - Initiates card OS shutdown. + "suspend" - Initiates card OS shutdown and also marks the card + as suspended. What: /sys/class/mic/mic(x)/shutdown_status -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: An Intel MIC device runs a Linux OS during its operation. This @@ -72,8 +82,8 @@ Description: "restart" - Shutdown because of a restart command. What: /sys/class/mic/mic(x)/cmdline -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: An Intel MIC device runs a Linux OS during its operation. Before @@ -88,8 +98,8 @@ Description: line back to this entry. What: /sys/class/mic/mic(x)/firmware -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: When read, this sysfs entry provides the path name under @@ -98,8 +108,8 @@ Description: firmware image location under /lib/firmware/. What: /sys/class/mic/mic(x)/ramdisk -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: When read, this sysfs entry provides the path name under @@ -108,8 +118,8 @@ Description: the ramdisk image location under /lib/firmware/. What: /sys/class/mic/mic(x)/bootmode -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: When read, this sysfs entry provides the current bootmode for @@ -119,8 +129,8 @@ Description: b) elf - Boot an elf image for flash updates. What: /sys/class/mic/mic(x)/log_buf_addr -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: An Intel MIC device runs a Linux OS during its operation. For @@ -133,8 +143,8 @@ Description: file of the card OS. What: /sys/class/mic/mic(x)/log_buf_len -Date: August 2013 -KernelVersion: 3.11 +Date: October 2013 +KernelVersion: 3.13 Contact: Sudeep Dutt Description: An Intel MIC device runs a Linux OS during its operation. For diff --git a/Documentation/mic/mic_overview.txt b/Documentation/mic/mic_overview.txt index c4424ed1b746..b41929224804 100644 --- a/Documentation/mic/mic_overview.txt +++ b/Documentation/mic/mic_overview.txt @@ -4,7 +4,9 @@ that runs a Linux OS. It is a PCIe endpoint in a platform and therefore implements the three required standard address spaces i.e. configuration, memory and I/O. The host OS loads a device driver as is typical for PCIe devices. The card itself runs a bootstrap after reset that -transfers control to the card OS downloaded from the host driver. +transfers control to the card OS downloaded from the host driver. The +host driver supports OSPM suspend and resume operations. It shuts down +the card during suspend and reboots the card OS during resume. The card OS as shipped by Intel is a Linux kernel with modifications for the X100 devices. diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c index 82c6bc2e3cb6..0c980ad40b17 100644 --- a/Documentation/mic/mpssd/mpssd.c +++ b/Documentation/mic/mpssd/mpssd.c @@ -1295,7 +1295,13 @@ reset(struct mic_info *mic) goto retry; mpsslog("%s: %s %d state %s\n", mic->name, __func__, __LINE__, state); - if ((!strcmp(state, "offline"))) { + + /* + * If the shutdown was initiated by OSPM, the state stays + * in "suspended" which is also a valid condition for reset. + */ + if ((!strcmp(state, "offline")) || + (!strcmp(state, "suspended"))) { free(state); break; } @@ -1334,6 +1340,10 @@ static int get_mic_state(struct mic_info *mic, char *state) return MIC_SHUTTING_DOWN; if (!strcmp(state, "reset_failed")) return MIC_RESET_FAILED; + if (!strcmp(state, "suspending")) + return MIC_SUSPENDING; + if (!strcmp(state, "suspended")) + return MIC_SUSPENDED; mpsslog("%s: BUG invalid state %s\n", mic->name, state); /* Invalid state */ assert(0); @@ -1418,6 +1428,17 @@ retry: case MIC_SHUTTING_DOWN: mic_handle_shutdown(mic); goto close_error; + case MIC_SUSPENDING: + mic->boot_on_resume = 1; + setsysfs(mic->name, "state", "suspend"); + mic_handle_shutdown(mic); + goto close_error; + case MIC_OFFLINE: + if (mic->boot_on_resume) { + setsysfs(mic->name, "state", "boot"); + mic->boot_on_resume = 0; + } + break; default: break; } @@ -1621,11 +1642,9 @@ init_mic_list(void) while ((file = readdir(dp)) != NULL) { if (!strncmp(file->d_name, "mic", 3)) { - mic->next = malloc(sizeof(struct mic_info)); + mic->next = calloc(1, sizeof(struct mic_info)); if (mic->next) { mic = mic->next; - mic->next = NULL; - memset(mic, 0, sizeof(struct mic_info)); mic->id = atoi(&file->d_name[3]); mic->name = malloc(strlen(file->d_name) + 16); if (mic->name) diff --git a/Documentation/mic/mpssd/mpssd.h b/Documentation/mic/mpssd/mpssd.h index ccd589ff9146..f5f18b15d9a0 100644 --- a/Documentation/mic/mpssd/mpssd.h +++ b/Documentation/mic/mpssd/mpssd.h @@ -91,6 +91,7 @@ struct mic_info { struct mic_net_info mic_net; struct mic_virtblk_info mic_virtblk; int restart; + int boot_on_resume; struct mic_info *next; }; diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c index 60c54d5c43c2..d56b8bf4eaf6 100644 --- a/drivers/misc/mic/host/mic_boot.c +++ b/drivers/misc/mic/host/mic_boot.c @@ -37,12 +37,13 @@ static void mic_reset(struct mic_device *mdev) #define MIC_RESET_TO (45) + INIT_COMPLETION(mdev->reset_wait); mdev->ops->reset_fw_ready(mdev); mdev->ops->reset(mdev); for (i = 0; i < MIC_RESET_TO; i++) { if (mdev->ops->is_fw_ready(mdev)) - return; + goto done; /* * Resets typically take 10s of seconds to complete. * Since an MMIO read is required to check if the @@ -51,6 +52,8 @@ static void mic_reset(struct mic_device *mdev) msleep(1000); } mic_set_state(mdev, MIC_RESET_FAILED); +done: + complete_all(&mdev->reset_wait); } /* Initialize the MIC bootparams */ @@ -123,7 +126,8 @@ void mic_stop(struct mic_device *mdev, bool force) if (MIC_RESET_FAILED == mdev->state) goto unlock; mic_set_shutdown_status(mdev, MIC_NOP); - mic_set_state(mdev, MIC_OFFLINE); + if (MIC_SUSPENDED != mdev->state) + mic_set_state(mdev, MIC_OFFLINE); } unlock: mutex_unlock(&mdev->mic_mutex); @@ -165,7 +169,14 @@ void mic_shutdown_work(struct work_struct *work) mutex_lock(&mdev->mic_mutex); mic_set_shutdown_status(mdev, bootparam->shutdown_status); bootparam->shutdown_status = 0; - if (MIC_SHUTTING_DOWN != mdev->state) + + /* + * if state is MIC_SUSPENDED, OSPM suspend is in progress. We do not + * change the state here so as to prevent users from booting the card + * during and after the suspend operation. + */ + if (MIC_SHUTTING_DOWN != mdev->state && + MIC_SUSPENDED != mdev->state) mic_set_state(mdev, MIC_SHUTTING_DOWN); mutex_unlock(&mdev->mic_mutex); } @@ -183,3 +194,106 @@ void mic_reset_trigger_work(struct work_struct *work) mic_stop(mdev, false); } + +/** + * mic_complete_resume - Complete MIC Resume after an OSPM suspend/hibernate + * event. + * @mdev: pointer to mic_device instance + * + * RETURNS: None. + */ +void mic_complete_resume(struct mic_device *mdev) +{ + if (mdev->state != MIC_SUSPENDED) { + dev_warn(mdev->sdev->parent, "state %d should be %d\n", + mdev->state, MIC_SUSPENDED); + return; + } + + /* Make sure firmware is ready */ + if (!mdev->ops->is_fw_ready(mdev)) + mic_stop(mdev, true); + + mutex_lock(&mdev->mic_mutex); + mic_set_state(mdev, MIC_OFFLINE); + mutex_unlock(&mdev->mic_mutex); +} + +/** + * mic_prepare_suspend - Handle suspend notification for the MIC device. + * @mdev: pointer to mic_device instance + * + * RETURNS: None. + */ +void mic_prepare_suspend(struct mic_device *mdev) +{ + int rc; + +#define MIC_SUSPEND_TIMEOUT (60 * HZ) + + mutex_lock(&mdev->mic_mutex); + switch (mdev->state) { + case MIC_OFFLINE: + /* + * Card is already offline. Set state to MIC_SUSPENDED + * to prevent users from booting the card. + */ + mic_set_state(mdev, MIC_SUSPENDED); + mutex_unlock(&mdev->mic_mutex); + break; + case MIC_ONLINE: + /* + * Card is online. Set state to MIC_SUSPENDING and notify + * MIC user space daemon which will issue card + * shutdown and reset. + */ + mic_set_state(mdev, MIC_SUSPENDING); + mutex_unlock(&mdev->mic_mutex); + rc = wait_for_completion_timeout(&mdev->reset_wait, + MIC_SUSPEND_TIMEOUT); + /* Force reset the card if the shutdown completion timed out */ + if (!rc) { + mutex_lock(&mdev->mic_mutex); + mic_set_state(mdev, MIC_SUSPENDED); + mutex_unlock(&mdev->mic_mutex); + mic_stop(mdev, true); + } + break; + case MIC_SHUTTING_DOWN: + /* + * Card is shutting down. Set state to MIC_SUSPENDED + * to prevent further boot of the card. + */ + mic_set_state(mdev, MIC_SUSPENDED); + mutex_unlock(&mdev->mic_mutex); + rc = wait_for_completion_timeout(&mdev->reset_wait, + MIC_SUSPEND_TIMEOUT); + /* Force reset the card if the shutdown completion timed out */ + if (!rc) + mic_stop(mdev, true); + break; + default: + mutex_unlock(&mdev->mic_mutex); + break; + } +} + +/** + * mic_suspend - Initiate MIC suspend. Suspend merely issues card shutdown. + * @mdev: pointer to mic_device instance + * + * RETURNS: None. + */ +void mic_suspend(struct mic_device *mdev) +{ + struct mic_bootparam *bootparam = mdev->dp; + s8 db = bootparam->h2c_shutdown_db; + + mutex_lock(&mdev->mic_mutex); + if (MIC_SUSPENDING == mdev->state && db != -1) { + bootparam->shutdown_card = 1; + mdev->ops->send_intr(mdev, db); + mic_set_state(mdev, MIC_SUSPENDED); + } + mutex_unlock(&mdev->mic_mutex); +} diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h index dcba2a59e77f..3574cc375bb9 100644 --- a/drivers/misc/mic/host/mic_device.h +++ b/drivers/misc/mic/host/mic_device.h @@ -23,6 +23,7 @@ #include #include +#include #include "mic_intr.h" @@ -75,6 +76,7 @@ enum mic_stepping { * @state: MIC state. * @shutdown_status: MIC status reported by card for shutdown/crashes. * @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes. + * @reset_wait: Waitqueue for sleeping while reset completes. * @log_buf_addr: Log buffer address for MIC. * @log_buf_len: Log buffer length address for MIC. * @dp: virtio device page @@ -83,6 +85,7 @@ enum mic_stepping { * @shutdown_cookie: shutdown cookie. * @cdev: Character device for MIC. * @vdev_list: list of virtio devices. + * @pm_notifier: Handles PM notifications from the OS. */ struct mic_device { struct mic_mw mmio; @@ -110,6 +113,7 @@ struct mic_device { u8 state; u8 shutdown_status; struct sysfs_dirent *state_sysfs; + struct completion reset_wait; void *log_buf_addr; int *log_buf_len; void *dp; @@ -118,6 +122,7 @@ struct mic_device { struct mic_irq *shutdown_cookie; struct cdev cdev; struct list_head vdev_list; + struct notifier_block pm_notifier; }; /** @@ -192,4 +197,7 @@ void mic_create_debug_dir(struct mic_device *dev); void mic_delete_debug_dir(struct mic_device *dev); void __init mic_init_debugfs(void); void mic_exit_debugfs(void); +void mic_prepare_suspend(struct mic_device *mdev); +void mic_complete_resume(struct mic_device *mdev); +void mic_suspend(struct mic_device *mdev); #endif diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c index ca06aa9b7114..b3520859abd3 100644 --- a/drivers/misc/mic/host/mic_main.c +++ b/drivers/misc/mic/host/mic_main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "../common/mic_dev.h" @@ -186,6 +187,43 @@ static enum mic_hw_family mic_get_family(struct pci_dev *pdev) return family; } +/** +* mic_pm_notifier: Notifier callback function that handles +* PM notifications. +* +* @notifier_block: The notifier structure. +* @pm_event: The event for which the driver was notified. +* @unused: Meaningless. Always NULL. +* +* returns NOTIFY_DONE +*/ +static int mic_pm_notifier(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + struct mic_device *mdev = container_of(notifier, + struct mic_device, pm_notifier); + + switch (pm_event) { + case PM_HIBERNATION_PREPARE: + /* Fall through */ + case PM_SUSPEND_PREPARE: + mic_prepare_suspend(mdev); + break; + case PM_POST_HIBERNATION: + /* Fall through */ + case PM_POST_SUSPEND: + /* Fall through */ + case PM_POST_RESTORE: + mic_complete_resume(mdev); + break; + case PM_RESTORE_PREPARE: + break; + default: + break; + } + return NOTIFY_DONE; +} + /** * mic_device_init - Allocates and initializes the MIC device structure * @@ -194,9 +232,11 @@ static enum mic_hw_family mic_get_family(struct pci_dev *pdev) * * returns none. */ -static void +static int mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) { + int rc; + mdev->family = mic_get_family(pdev); mdev->stepping = pdev->revision; mic_ops_init(mdev); @@ -205,7 +245,20 @@ mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) mdev->irq_info.next_avail_src = 0; INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work); INIT_WORK(&mdev->shutdown_work, mic_shutdown_work); + init_completion(&mdev->reset_wait); INIT_LIST_HEAD(&mdev->vdev_list); + mdev->pm_notifier.notifier_call = mic_pm_notifier; + rc = register_pm_notifier(&mdev->pm_notifier); + if (rc) { + dev_err(&pdev->dev, "register_pm_notifier failed rc %d\n", + rc); + goto register_pm_notifier_fail; + } + return 0; +register_pm_notifier_fail: + flush_work(&mdev->shutdown_work); + flush_work(&mdev->reset_trigger_work); + return rc; } /** @@ -224,6 +277,7 @@ static void mic_device_uninit(struct mic_device *mdev) kfree(mdev->bootmode); flush_work(&mdev->reset_trigger_work); flush_work(&mdev->shutdown_work); + unregister_pm_notifier(&mdev->pm_notifier); } /** @@ -253,7 +307,11 @@ static int mic_probe(struct pci_dev *pdev, goto ida_fail; } - mic_device_init(mdev, pdev); + rc = mic_device_init(mdev, pdev); + if (rc) { + dev_err(&pdev->dev, "mic_device_init failed rc %d\n", rc); + goto device_init_fail; + } rc = pci_enable_device(pdev); if (rc) { @@ -376,6 +434,7 @@ disable_device: pci_disable_device(pdev); uninit_device: mic_device_uninit(mdev); +device_init_fail: ida_simple_remove(&g_mic_ida, mdev->id); ida_fail: kfree(mdev); diff --git a/drivers/misc/mic/host/mic_sysfs.c b/drivers/misc/mic/host/mic_sysfs.c index 75746adfb155..6dd864e4a617 100644 --- a/drivers/misc/mic/host/mic_sysfs.c +++ b/drivers/misc/mic/host/mic_sysfs.c @@ -33,6 +33,8 @@ static const char * const mic_state_string[] = { [MIC_ONLINE] = "online", [MIC_SHUTTING_DOWN] = "shutting_down", [MIC_RESET_FAILED] = "reset_failed", + [MIC_SUSPENDING] = "suspending", + [MIC_SUSPENDED] = "suspended", }; /* @@ -156,6 +158,11 @@ state_store(struct device *dev, struct device_attribute *attr, goto done; } + if (sysfs_streq(buf, "suspend")) { + mic_suspend(mdev); + goto done; + } + count = -EINVAL; done: return count; diff --git a/include/uapi/linux/mic_common.h b/include/uapi/linux/mic_common.h index 364ac751bd04..17e7d95e4f53 100644 --- a/include/uapi/linux/mic_common.h +++ b/include/uapi/linux/mic_common.h @@ -219,6 +219,8 @@ enum mic_states { MIC_ONLINE, MIC_SHUTTING_DOWN, MIC_RESET_FAILED, + MIC_SUSPENDING, + MIC_SUSPENDED, MIC_LAST }; -- cgit v1.2.3