2 * Intel MIC Platform Software Stack (MPSS)
4 * Copyright(c) 2013 Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
18 * Intel MIC User Space Tools.
32 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <linux/virtio_ring.h>
37 #include <linux/virtio_net.h>
38 #include <linux/virtio_console.h>
39 #include <linux/virtio_blk.h>
40 #include <linux/version.h>
42 #include <linux/mic_ioctl.h>
43 #include <linux/mic_common.h>
44 #include <tools/endian.h>
46 static void init_mic(struct mic_info *mic);
49 static struct mic_info mic_list;
51 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
53 #define min_t(type, x, y) ({ \
56 __min1 < __min2 ? __min1 : __min2; })
58 /* align addr on a size boundary - adjust address up/down if needed */
59 #define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
60 #define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
62 /* align addr on a size boundary - adjust address up if needed */
63 #define _ALIGN(addr, size) _ALIGN_UP(addr, size)
65 /* to align the pointer to the (next) page boundary */
66 #define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
68 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
71 #define MAX_GSO_SIZE (64 * 1024)
73 #define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
74 #define MIC_DEVICE_PAGE_END 0x1000
76 #ifndef VIRTIO_NET_HDR_F_DATA_VALID
77 #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
81 struct mic_device_desc dd;
82 struct mic_vqconfig vqconfig[2];
83 __u32 host_features, guest_acknowledgements;
84 struct virtio_console_config cons_config;
85 } virtcons_dev_page = {
87 .type = VIRTIO_ID_CONSOLE,
88 .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig),
89 .feature_len = sizeof(virtcons_dev_page.host_features),
90 .config_len = sizeof(virtcons_dev_page.cons_config),
93 .num = htole16(MIC_VRING_ENTRIES),
96 .num = htole16(MIC_VRING_ENTRIES),
101 struct mic_device_desc dd;
102 struct mic_vqconfig vqconfig[2];
103 __u32 host_features, guest_acknowledgements;
104 struct virtio_net_config net_config;
105 } virtnet_dev_page = {
107 .type = VIRTIO_ID_NET,
108 .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig),
109 .feature_len = sizeof(virtnet_dev_page.host_features),
110 .config_len = sizeof(virtnet_dev_page.net_config),
113 .num = htole16(MIC_VRING_ENTRIES),
116 .num = htole16(MIC_VRING_ENTRIES),
119 .host_features = htole32(
120 1 << VIRTIO_NET_F_CSUM |
121 1 << VIRTIO_NET_F_GSO |
122 1 << VIRTIO_NET_F_GUEST_TSO4 |
123 1 << VIRTIO_NET_F_GUEST_TSO6 |
124 1 << VIRTIO_NET_F_GUEST_ECN |
125 1 << VIRTIO_NET_F_GUEST_UFO),
131 static const char *mic_config_dir = "/etc/sysconfig/mic";
132 static const char *virtblk_backend = "VIRTBLK_BACKEND";
134 struct mic_device_desc dd;
135 struct mic_vqconfig vqconfig[1];
136 __u32 host_features, guest_acknowledgements;
137 struct virtio_blk_config blk_config;
138 } virtblk_dev_page = {
140 .type = VIRTIO_ID_BLOCK,
141 .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig),
142 .feature_len = sizeof(virtblk_dev_page.host_features),
143 .config_len = sizeof(virtblk_dev_page.blk_config),
146 .num = htole16(MIC_VRING_ENTRIES),
149 htole32(1<<VIRTIO_BLK_F_SEG_MAX),
151 .seg_max = htole32(MIC_VRING_ENTRIES - 2),
152 .capacity = htole64(0),
159 tap_configure(struct mic_info *mic, char *dev)
163 char ipaddr[IFNAMSIZ];
174 mpsslog("Configuring %s\n", dev);
175 ret = execvp("ip", ifargv);
177 mpsslog("%s execvp failed errno %s\n",
178 mic->name, strerror(errno));
183 mpsslog("%s fork failed errno %s\n",
184 mic->name, strerror(errno));
188 ret = waitpid(pid, NULL, 0);
190 mpsslog("%s waitpid failed errno %s\n",
191 mic->name, strerror(errno));
195 snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id);
206 mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr);
207 ret = execvp("ip", ifargv);
209 mpsslog("%s execvp failed errno %s\n",
210 mic->name, strerror(errno));
215 mpsslog("%s fork failed errno %s\n",
216 mic->name, strerror(errno));
220 ret = waitpid(pid, NULL, 0);
222 mpsslog("%s waitpid failed errno %s\n",
223 mic->name, strerror(errno));
226 mpsslog("MIC name %s %s %d DONE!\n",
227 mic->name, __func__, __LINE__);
231 static int tun_alloc(struct mic_info *mic, char *dev)
238 fd = open("/dev/net/tun", O_RDWR);
240 mpsslog("Could not open /dev/net/tun %s\n", strerror(errno));
244 memset(&ifr, 0, sizeof(ifr));
246 ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
248 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
250 err = ioctl(fd, TUNSETIFF, (void *)&ifr);
252 mpsslog("%s %s %d TUNSETIFF failed %s\n",
253 mic->name, __func__, __LINE__, strerror(errno));
258 offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
259 TUN_F_TSO_ECN | TUN_F_UFO;
261 err = ioctl(fd, TUNSETOFFLOAD, offload);
263 mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
264 mic->name, __func__, __LINE__, strerror(errno));
269 strcpy(dev, ifr.ifr_name);
270 mpsslog("Created TAP %s\n", dev);
275 #define NET_FD_VIRTIO_NET 0
279 static void set_dp(struct mic_info *mic, int type, void *dp)
282 case VIRTIO_ID_CONSOLE:
283 mic->mic_console.console_dp = dp;
286 mic->mic_net.net_dp = dp;
288 case VIRTIO_ID_BLOCK:
289 mic->mic_virtblk.block_dp = dp;
292 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
296 static void *get_dp(struct mic_info *mic, int type)
299 case VIRTIO_ID_CONSOLE:
300 return mic->mic_console.console_dp;
302 return mic->mic_net.net_dp;
303 case VIRTIO_ID_BLOCK:
304 return mic->mic_virtblk.block_dp;
306 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
311 static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type)
313 struct mic_device_desc *d;
315 void *dp = get_dp(mic, type);
317 for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE;
318 i += mic_total_desc_size(d)) {
328 mpsslog("%s %s d-> type %d d %p\n",
329 mic->name, __func__, d->type, d);
331 if (d->type == (__u8)type)
334 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
339 /* See comments in vhost.c for explanation of next_desc() */
340 static unsigned next_desc(struct vring_desc *desc)
344 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT))
346 next = le16toh(desc->next);
350 /* Sum up all the IOVEC length */
352 sum_iovec_len(struct mic_copy_desc *copy)
357 for (i = 0; i < copy->iovcnt; i++)
358 sum += copy->iov[i].iov_len;
362 static inline void verify_out_len(struct mic_info *mic,
363 struct mic_copy_desc *copy)
365 if (copy->out_len != sum_iovec_len(copy)) {
366 mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n",
367 mic->name, __func__, __LINE__,
368 copy->out_len, sum_iovec_len(copy));
369 assert(copy->out_len == sum_iovec_len(copy));
373 /* Display an iovec */
375 disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
376 const char *s, int line)
380 for (i = 0; i < copy->iovcnt; i++)
381 mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n",
382 mic->name, s, line, i,
383 copy->iov[i].iov_base, copy->iov[i].iov_len);
386 static inline __u16 read_avail_idx(struct mic_vring *vr)
388 return ACCESS_ONCE(vr->info->avail_idx);
391 static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
392 struct mic_copy_desc *copy, ssize_t len)
394 copy->vr_idx = tx ? 0 : 1;
395 copy->update_used = true;
396 if (type == VIRTIO_ID_NET)
397 copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr);
399 copy->iov[0].iov_len = len;
402 /* Central API which triggers the copies */
404 mic_virtio_copy(struct mic_info *mic, int fd,
405 struct mic_vring *vr, struct mic_copy_desc *copy)
409 ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy);
411 mpsslog("%s %s %d errno %s ret %d\n",
412 mic->name, __func__, __LINE__,
413 strerror(errno), ret);
419 * This initialization routine requires at least one
420 * vring i.e. vr0. vr1 is optional.
423 init_vr(struct mic_info *mic, int fd, int type,
424 struct mic_vring *vr0, struct mic_vring *vr1, int num_vq)
429 vr_size = PAGE_ALIGN(vring_size(MIC_VRING_ENTRIES,
430 MIC_VIRTIO_RING_ALIGN) + sizeof(struct _mic_vring_info));
431 va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq,
432 PROT_READ, MAP_SHARED, fd, 0);
433 if (MAP_FAILED == va) {
434 mpsslog("%s %s %d mmap failed errno %s\n",
435 mic->name, __func__, __LINE__,
439 set_dp(mic, type, va);
440 vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END];
441 vr0->info = vr0->va +
442 vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN);
444 MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN);
445 mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
446 __func__, mic->name, vr0->va, vr0->info, vr_size,
447 vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
448 mpsslog("magic 0x%x expected 0x%x\n",
449 le32toh(vr0->info->magic), MIC_MAGIC + type);
450 assert(le32toh(vr0->info->magic) == MIC_MAGIC + type);
452 vr1->va = (struct mic_vring *)
453 &va[MIC_DEVICE_PAGE_END + vr_size];
454 vr1->info = vr1->va + vring_size(MIC_VRING_ENTRIES,
455 MIC_VIRTIO_RING_ALIGN);
457 MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN);
458 mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
459 __func__, mic->name, vr1->va, vr1->info, vr_size,
460 vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
461 mpsslog("magic 0x%x expected 0x%x\n",
462 le32toh(vr1->info->magic), MIC_MAGIC + type + 1);
463 assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1);
470 wait_for_card_driver(struct mic_info *mic, int fd, int type)
472 struct pollfd pollfd;
474 struct mic_device_desc *desc = get_device_desc(mic, type);
477 mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
478 mic->name, __func__, type, desc->status);
480 pollfd.events = POLLIN;
482 err = poll(&pollfd, 1, -1);
484 mpsslog("%s %s poll failed %s\n",
485 mic->name, __func__, strerror(errno));
489 if (pollfd.revents) {
490 mpsslog("%s %s Waiting... desc-> type %d status 0x%x\n",
491 mic->name, __func__, type, desc->status);
492 if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
493 mpsslog("%s %s poll.revents %d\n",
494 mic->name, __func__, pollfd.revents);
495 mpsslog("%s %s desc-> type %d status 0x%x\n",
496 mic->name, __func__, type,
504 /* Spin till we have some descriptors */
506 spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
508 __u16 avail_idx = read_avail_idx(vr);
510 while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) {
512 mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
514 le16toh(vr->vr.avail->idx), vr->info->avail_idx);
521 virtio_net(void *arg)
523 static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)];
524 static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __attribute__ ((aligned(64)));
525 struct iovec vnet_iov[2][2] = {
526 { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) },
527 { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } },
528 { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) },
529 { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } },
531 struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1];
532 struct mic_info *mic = (struct mic_info *)arg;
533 char if_name[IFNAMSIZ];
534 struct pollfd net_poll[MAX_NET_FD];
535 struct mic_vring tx_vr, rx_vr;
536 struct mic_copy_desc copy;
537 struct mic_device_desc *desc;
540 snprintf(if_name, IFNAMSIZ, "mic%d", mic->id);
541 mic->mic_net.tap_fd = tun_alloc(mic, if_name);
542 if (mic->mic_net.tap_fd < 0)
545 if (tap_configure(mic, if_name))
547 mpsslog("MIC name %s id %d\n", mic->name, mic->id);
549 net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd;
550 net_poll[NET_FD_VIRTIO_NET].events = POLLIN;
551 net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd;
552 net_poll[NET_FD_TUN].events = POLLIN;
554 if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd,
555 VIRTIO_ID_NET, &tx_vr, &rx_vr,
556 virtnet_dev_page.dd.num_vq)) {
557 mpsslog("%s init_vr failed %s\n",
558 mic->name, strerror(errno));
563 desc = get_device_desc(mic, VIRTIO_ID_NET);
568 net_poll[NET_FD_VIRTIO_NET].revents = 0;
569 net_poll[NET_FD_TUN].revents = 0;
571 /* Start polling for data from tap and virtio net */
572 err = poll(net_poll, 2, -1);
574 mpsslog("%s poll failed %s\n",
575 __func__, strerror(errno));
578 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK))
579 wait_for_card_driver(mic, mic->mic_net.virtio_net_fd,
582 * Check if there is data to be read from TUN and write to
583 * virtio net fd if there is.
585 if (net_poll[NET_FD_TUN].revents & POLLIN) {
587 len = readv(net_poll[NET_FD_TUN].fd,
588 copy.iov, copy.iovcnt);
590 struct virtio_net_hdr *hdr
591 = (struct virtio_net_hdr *)vnet_hdr[0];
593 /* Disable checksums on the card since we are on
594 a reliable PCIe link */
595 hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
597 mpsslog("%s %s %d hdr->flags 0x%x ", mic->name,
598 __func__, __LINE__, hdr->flags);
599 mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
600 copy.out_len, hdr->gso_type);
603 disp_iovec(mic, copy, __func__, __LINE__);
604 mpsslog("%s %s %d read from tap 0x%lx\n",
605 mic->name, __func__, __LINE__,
608 spin_for_descriptors(mic, &tx_vr);
609 txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, ©,
612 err = mic_virtio_copy(mic,
613 mic->mic_net.virtio_net_fd, &tx_vr,
616 mpsslog("%s %s %d mic_virtio_copy %s\n",
617 mic->name, __func__, __LINE__,
621 verify_out_len(mic, ©);
623 disp_iovec(mic, copy, __func__, __LINE__);
624 mpsslog("%s %s %d wrote to net 0x%lx\n",
625 mic->name, __func__, __LINE__,
626 sum_iovec_len(©));
628 /* Reinitialize IOV for next run */
629 iov0[1].iov_len = MAX_NET_PKT_SIZE;
630 } else if (len < 0) {
631 disp_iovec(mic, ©, __func__, __LINE__);
632 mpsslog("%s %s %d read failed %s ", mic->name,
633 __func__, __LINE__, strerror(errno));
634 mpsslog("cnt %d sum %zd\n",
635 copy.iovcnt, sum_iovec_len(©));
640 * Check if there is data to be read from virtio net and
641 * write to TUN if there is.
643 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) {
644 while (rx_vr.info->avail_idx !=
645 le16toh(rx_vr.vr.avail->idx)) {
647 txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, ©,
649 + sizeof(struct virtio_net_hdr));
651 err = mic_virtio_copy(mic,
652 mic->mic_net.virtio_net_fd, &rx_vr,
656 struct virtio_net_hdr *hdr
657 = (struct virtio_net_hdr *)
660 mpsslog("%s %s %d hdr->flags 0x%x, ",
661 mic->name, __func__, __LINE__,
663 mpsslog("out_len %d gso_type 0x%x\n",
667 /* Set the correct output iov_len */
668 iov1[1].iov_len = copy.out_len -
669 sizeof(struct virtio_net_hdr);
670 verify_out_len(mic, ©);
672 disp_iovec(mic, copy, __func__,
675 mic->name, __func__, __LINE__);
676 mpsslog("read from net 0x%lx\n",
677 sum_iovec_len(copy));
679 len = writev(net_poll[NET_FD_TUN].fd,
680 copy.iov, copy.iovcnt);
681 if (len != sum_iovec_len(©)) {
682 mpsslog("Tun write failed %s ",
684 mpsslog("len 0x%zx ", len);
685 mpsslog("read_len 0x%zx\n",
686 sum_iovec_len(©));
689 disp_iovec(mic, ©, __func__,
694 mpsslog("wrote to tap 0x%lx\n",
699 mpsslog("%s %s %d mic_virtio_copy %s\n",
700 mic->name, __func__, __LINE__,
706 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
707 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
714 #define VIRTIO_CONSOLE_FD 0
715 #define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
716 #define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
717 #define MAX_BUFFER_SIZE PAGE_SIZE
720 virtio_console(void *arg)
722 static __u8 vcons_buf[2][PAGE_SIZE];
723 struct iovec vcons_iov[2] = {
724 { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) },
725 { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) },
727 struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1];
728 struct mic_info *mic = (struct mic_info *)arg;
730 struct pollfd console_poll[MAX_CONSOLE_FD];
734 struct mic_vring tx_vr, rx_vr;
735 struct mic_copy_desc copy;
736 struct mic_device_desc *desc;
738 pty_fd = posix_openpt(O_RDWR);
740 mpsslog("can't open a pseudoterminal master device: %s\n",
744 pts_name = ptsname(pty_fd);
745 if (pts_name == NULL) {
746 mpsslog("can't get pts name\n");
749 printf("%s console message goes to %s\n", mic->name, pts_name);
750 mpsslog("%s console message goes to %s\n", mic->name, pts_name);
751 err = grantpt(pty_fd);
753 mpsslog("can't grant access: %s %s\n",
754 pts_name, strerror(errno));
757 err = unlockpt(pty_fd);
759 mpsslog("can't unlock a pseudoterminal: %s %s\n",
760 pts_name, strerror(errno));
763 console_poll[MONITOR_FD].fd = pty_fd;
764 console_poll[MONITOR_FD].events = POLLIN;
766 console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd;
767 console_poll[VIRTIO_CONSOLE_FD].events = POLLIN;
769 if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd,
770 VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr,
771 virtcons_dev_page.dd.num_vq)) {
772 mpsslog("%s init_vr failed %s\n",
773 mic->name, strerror(errno));
778 desc = get_device_desc(mic, VIRTIO_ID_CONSOLE);
781 console_poll[MONITOR_FD].revents = 0;
782 console_poll[VIRTIO_CONSOLE_FD].revents = 0;
783 err = poll(console_poll, MAX_CONSOLE_FD, -1);
785 mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__,
789 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK))
790 wait_for_card_driver(mic,
791 mic->mic_console.virtio_console_fd,
794 if (console_poll[MONITOR_FD].revents & POLLIN) {
796 len = readv(pty_fd, copy.iov, copy.iovcnt);
799 disp_iovec(mic, copy, __func__, __LINE__);
800 mpsslog("%s %s %d read from tap 0x%lx\n",
801 mic->name, __func__, __LINE__,
804 spin_for_descriptors(mic, &tx_vr);
805 txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr,
808 err = mic_virtio_copy(mic,
809 mic->mic_console.virtio_console_fd,
812 mpsslog("%s %s %d mic_virtio_copy %s\n",
813 mic->name, __func__, __LINE__,
817 verify_out_len(mic, ©);
819 disp_iovec(mic, copy, __func__, __LINE__);
820 mpsslog("%s %s %d wrote to net 0x%lx\n",
821 mic->name, __func__, __LINE__,
822 sum_iovec_len(copy));
824 /* Reinitialize IOV for next run */
825 iov0->iov_len = PAGE_SIZE;
826 } else if (len < 0) {
827 disp_iovec(mic, ©, __func__, __LINE__);
828 mpsslog("%s %s %d read failed %s ",
829 mic->name, __func__, __LINE__,
831 mpsslog("cnt %d sum %zd\n",
832 copy.iovcnt, sum_iovec_len(©));
836 if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) {
837 while (rx_vr.info->avail_idx !=
838 le16toh(rx_vr.vr.avail->idx)) {
840 txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr,
843 err = mic_virtio_copy(mic,
844 mic->mic_console.virtio_console_fd,
847 /* Set the correct output iov_len */
848 iov1->iov_len = copy.out_len;
849 verify_out_len(mic, ©);
851 disp_iovec(mic, copy, __func__,
854 mic->name, __func__, __LINE__);
855 mpsslog("read from net 0x%lx\n",
856 sum_iovec_len(copy));
859 copy.iov, copy.iovcnt);
860 if (len != sum_iovec_len(©)) {
861 mpsslog("Tun write failed %s ",
863 mpsslog("len 0x%zx ", len);
864 mpsslog("read_len 0x%zx\n",
865 sum_iovec_len(©));
868 disp_iovec(mic, copy, __func__,
873 mpsslog("wrote to tap 0x%lx\n",
878 mpsslog("%s %s %d mic_virtio_copy %s\n",
879 mic->name, __func__, __LINE__,
885 if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
886 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
895 add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd)
900 snprintf(path, PATH_MAX, "/dev/mic%d", mic->id);
901 fd = open(path, O_RDWR);
903 mpsslog("Could not open %s %s\n", path, strerror(errno));
907 err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd);
909 mpsslog("Could not add %d %s\n", dd->type, strerror(errno));
915 mic->mic_net.virtio_net_fd = fd;
916 mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name);
918 case VIRTIO_ID_CONSOLE:
919 mic->mic_console.virtio_console_fd = fd;
920 mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name);
922 case VIRTIO_ID_BLOCK:
923 mic->mic_virtblk.virtio_block_fd = fd;
924 mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name);
930 set_backend_file(struct mic_info *mic)
933 char buff[PATH_MAX], *line, *evv, *p;
935 snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id);
936 config = fopen(buff, "r");
939 do { /* look for "virtblk_backend=XXXX" */
940 line = fgets(buff, PATH_MAX, config);
945 p = strchr(line, '\n');
948 } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0);
952 evv = strchr(line, '=');
955 mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1);
956 if (mic->mic_virtblk.backend_file == NULL) {
957 mpsslog("%s %d can't allocate memory\n", mic->name, mic->id);
960 strcpy(mic->mic_virtblk.backend_file, evv + 1);
964 #define SECTOR_SIZE 512
966 set_backend_size(struct mic_info *mic)
968 mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0,
970 if (mic->mic_virtblk.backend_size < 0) {
971 mpsslog("%s: can't seek: %s\n",
972 mic->name, mic->mic_virtblk.backend_file);
975 virtblk_dev_page.blk_config.capacity =
976 mic->mic_virtblk.backend_size / SECTOR_SIZE;
977 if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0)
978 virtblk_dev_page.blk_config.capacity++;
980 virtblk_dev_page.blk_config.capacity =
981 htole64(virtblk_dev_page.blk_config.capacity);
987 open_backend(struct mic_info *mic)
989 if (!set_backend_file(mic))
991 mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR);
992 if (mic->mic_virtblk.backend < 0) {
993 mpsslog("%s: can't open: %s\n", mic->name,
994 mic->mic_virtblk.backend_file);
997 if (!set_backend_size(mic))
999 mic->mic_virtblk.backend_addr = mmap(NULL,
1000 mic->mic_virtblk.backend_size,
1001 PROT_READ|PROT_WRITE, MAP_SHARED,
1002 mic->mic_virtblk.backend, 0L);
1003 if (mic->mic_virtblk.backend_addr == MAP_FAILED) {
1004 mpsslog("%s: can't map: %s %s\n",
1005 mic->name, mic->mic_virtblk.backend_file,
1012 close(mic->mic_virtblk.backend);
1014 free(mic->mic_virtblk.backend_file);
1020 close_backend(struct mic_info *mic)
1022 munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size);
1023 close(mic->mic_virtblk.backend);
1024 free(mic->mic_virtblk.backend_file);
1028 start_virtblk(struct mic_info *mic, struct mic_vring *vring)
1030 if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) {
1031 mpsslog("%s: blk_config is not 8 byte aligned.\n",
1035 add_virtio_device(mic, &virtblk_dev_page.dd);
1036 if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd,
1037 VIRTIO_ID_BLOCK, vring, NULL,
1038 virtblk_dev_page.dd.num_vq)) {
1039 mpsslog("%s init_vr failed %s\n",
1040 mic->name, strerror(errno));
1047 stop_virtblk(struct mic_info *mic)
1051 vr_size = PAGE_ALIGN(vring_size(MIC_VRING_ENTRIES,
1052 MIC_VIRTIO_RING_ALIGN) + sizeof(struct _mic_vring_info));
1053 ret = munmap(mic->mic_virtblk.block_dp,
1054 MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq);
1056 mpsslog("%s munmap errno %d\n", mic->name, errno);
1057 close(mic->mic_virtblk.virtio_block_fd);
1061 header_error_check(struct vring_desc *desc)
1063 if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) {
1064 mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
1065 __func__, __LINE__);
1068 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) {
1069 mpsslog("%s() %d: alone\n",
1070 __func__, __LINE__);
1073 if (le16toh(desc->flags) & VRING_DESC_F_WRITE) {
1074 mpsslog("%s() %d: not read\n",
1075 __func__, __LINE__);
1082 read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx)
1085 struct mic_copy_desc copy;
1087 iovec.iov_len = sizeof(*hdr);
1088 iovec.iov_base = hdr;
1091 copy.vr_idx = 0; /* only one vring on virtio_block */
1092 copy.update_used = false; /* do not update used index */
1093 return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©);
1097 transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt)
1099 struct mic_copy_desc copy;
1102 copy.iovcnt = iovcnt;
1103 copy.vr_idx = 0; /* only one vring on virtio_block */
1104 copy.update_used = false; /* do not update used index */
1105 return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©);
1109 status_error_check(struct vring_desc *desc)
1111 if (le32toh(desc->len) != sizeof(__u8)) {
1112 mpsslog("%s() %d: length is not sizeof(status)\n",
1113 __func__, __LINE__);
1120 write_status(int fd, __u8 *status)
1123 struct mic_copy_desc copy;
1125 iovec.iov_base = status;
1126 iovec.iov_len = sizeof(*status);
1129 copy.vr_idx = 0; /* only one vring on virtio_block */
1130 copy.update_used = true; /* Update used index */
1131 return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©);
1135 virtio_block(void *arg)
1137 struct mic_info *mic = (struct mic_info *)arg;
1139 struct pollfd block_poll;
1140 struct mic_vring vring;
1143 struct vring_desc *desc;
1144 struct iovec *iovec, *piov;
1146 __u32 buffer_desc_idx;
1147 struct virtio_blk_outhdr hdr;
1150 for (;;) { /* forever */
1151 if (!open_backend(mic)) { /* No virtblk */
1152 for (mic->mic_virtblk.signaled = 0;
1153 !mic->mic_virtblk.signaled;)
1158 /* backend file is specified. */
1159 if (!start_virtblk(mic, &vring))
1160 goto _close_backend;
1161 iovec = malloc(sizeof(*iovec) *
1162 le32toh(virtblk_dev_page.blk_config.seg_max));
1164 mpsslog("%s: can't alloc iovec: %s\n",
1165 mic->name, strerror(ENOMEM));
1169 block_poll.fd = mic->mic_virtblk.virtio_block_fd;
1170 block_poll.events = POLLIN;
1171 for (mic->mic_virtblk.signaled = 0;
1172 !mic->mic_virtblk.signaled;) {
1173 block_poll.revents = 0;
1174 /* timeout in 1 sec to see signaled */
1175 ret = poll(&block_poll, 1, 1000);
1177 mpsslog("%s %d: poll failed: %s\n",
1183 if (!(block_poll.revents & POLLIN)) {
1185 mpsslog("%s %d: block_poll.revents=0x%x\n",
1186 __func__, __LINE__, block_poll.revents);
1192 while (vring.info->avail_idx !=
1193 le16toh(vring.vr.avail->idx)) {
1194 /* read header element */
1196 vring.info->avail_idx &
1199 vring.vr.avail->ring[avail_idx]);
1200 desc = &vring.vr.desc[desc_idx];
1202 mpsslog("%s() %d: avail_idx=%d ",
1204 vring.info->avail_idx);
1205 mpsslog("vring.vr.num=%d desc=%p\n",
1206 vring.vr.num, desc);
1208 status = header_error_check(desc);
1210 mic->mic_virtblk.virtio_block_fd,
1213 mpsslog("%s() %d %s: ret=%d %s\n",
1219 /* buffer element */
1222 fos = mic->mic_virtblk.backend_addr +
1223 (hdr.sector * SECTOR_SIZE);
1224 buffer_desc_idx = next_desc(desc);
1225 desc_idx = buffer_desc_idx;
1226 for (desc = &vring.vr.desc[buffer_desc_idx];
1227 desc->flags & VRING_DESC_F_NEXT;
1228 desc_idx = next_desc(desc),
1229 desc = &vring.vr.desc[desc_idx]) {
1230 piov->iov_len = desc->len;
1231 piov->iov_base = fos;
1235 /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
1236 if (hdr.type & ~(VIRTIO_BLK_T_OUT |
1237 VIRTIO_BLK_T_GET_ID)) {
1239 VIRTIO_BLK_T_IN - does not do
1240 anything. Probably for documenting.
1241 VIRTIO_BLK_T_SCSI_CMD - for
1243 VIRTIO_BLK_T_FLUSH - turned off in
1245 VIRTIO_BLK_T_BARRIER - defined but not
1248 mpsslog("%s() %d: type %x ",
1251 mpsslog("is not supported\n");
1255 ret = transfer_blocks(
1256 mic->mic_virtblk.virtio_block_fd,
1263 /* write status and update used pointer */
1265 status = status_error_check(desc);
1267 mic->mic_virtblk.virtio_block_fd,
1270 mpsslog("%s() %d: write status=%d on desc=%p\n",
1287 reset(struct mic_info *mic)
1289 #define RESET_TIMEOUT 120
1290 int i = RESET_TIMEOUT;
1291 setsysfs(mic->name, "state", "reset");
1294 state = readsysfs(mic->name, "state");
1297 mpsslog("%s: %s %d state %s\n",
1298 mic->name, __func__, __LINE__, state);
1301 * If the shutdown was initiated by OSPM, the state stays
1302 * in "suspended" which is also a valid condition for reset.
1304 if ((!strcmp(state, "offline")) ||
1305 (!strcmp(state, "suspended"))) {
1317 get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status)
1319 if (!strcmp(shutdown_status, "nop"))
1321 if (!strcmp(shutdown_status, "crashed"))
1323 if (!strcmp(shutdown_status, "halted"))
1325 if (!strcmp(shutdown_status, "poweroff"))
1326 return MIC_POWER_OFF;
1327 if (!strcmp(shutdown_status, "restart"))
1329 mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status);
1334 static int get_mic_state(struct mic_info *mic, char *state)
1336 if (!strcmp(state, "offline"))
1338 if (!strcmp(state, "online"))
1340 if (!strcmp(state, "shutting_down"))
1341 return MIC_SHUTTING_DOWN;
1342 if (!strcmp(state, "reset_failed"))
1343 return MIC_RESET_FAILED;
1344 if (!strcmp(state, "suspending"))
1345 return MIC_SUSPENDING;
1346 if (!strcmp(state, "suspended"))
1347 return MIC_SUSPENDED;
1348 mpsslog("%s: BUG invalid state %s\n", mic->name, state);
1353 static void mic_handle_shutdown(struct mic_info *mic)
1355 #define SHUTDOWN_TIMEOUT 60
1356 int i = SHUTDOWN_TIMEOUT, ret, stat = 0;
1357 char *shutdown_status;
1359 shutdown_status = readsysfs(mic->name, "shutdown_status");
1360 if (!shutdown_status)
1362 mpsslog("%s: %s %d shutdown_status %s\n",
1363 mic->name, __func__, __LINE__, shutdown_status);
1364 switch (get_mic_shutdown_status(mic, shutdown_status)) {
1370 free(shutdown_status);
1375 free(shutdown_status);
1380 ret = kill(mic->pid, SIGTERM);
1381 mpsslog("%s: %s %d kill pid %d ret %d\n",
1382 mic->name, __func__, __LINE__,
1385 ret = waitpid(mic->pid, &stat,
1387 mpsslog("%s: %s %d waitpid ret %d pid %d\n",
1388 mic->name, __func__, __LINE__,
1391 if (ret == mic->pid)
1396 mic_config(void *arg)
1398 struct mic_info *mic = (struct mic_info *)arg;
1400 char pathname[PATH_MAX];
1402 struct pollfd ufds[1];
1405 snprintf(pathname, PATH_MAX - 1, "%s/%s/%s",
1406 MICSYSFSDIR, mic->name, "state");
1408 fd = open(pathname, O_RDONLY);
1410 mpsslog("%s: opening file %s failed %s\n",
1411 mic->name, pathname, strerror(errno));
1416 ret = lseek(fd, 0, SEEK_SET);
1418 mpsslog("%s: Failed to seek to file start '%s': %s\n",
1419 mic->name, pathname, strerror(errno));
1422 ret = read(fd, value, sizeof(value));
1424 mpsslog("%s: Failed to read sysfs entry '%s': %s\n",
1425 mic->name, pathname, strerror(errno));
1429 state = readsysfs(mic->name, "state");
1432 mpsslog("%s: %s %d state %s\n",
1433 mic->name, __func__, __LINE__, state);
1434 switch (get_mic_state(mic, state)) {
1435 case MIC_SHUTTING_DOWN:
1436 mic_handle_shutdown(mic);
1438 case MIC_SUSPENDING:
1439 mic->boot_on_resume = 1;
1440 setsysfs(mic->name, "state", "suspend");
1441 mic_handle_shutdown(mic);
1444 if (mic->boot_on_resume) {
1445 setsysfs(mic->name, "state", "boot");
1446 mic->boot_on_resume = 0;
1455 ufds[0].events = POLLERR | POLLPRI;
1456 ret = poll(ufds, 1, -1);
1458 mpsslog("%s: poll failed %s\n",
1459 mic->name, strerror(errno));
1473 set_cmdline(struct mic_info *mic)
1475 char buffer[PATH_MAX];
1478 len = snprintf(buffer, PATH_MAX,
1479 "clocksource=tsc highres=off nohz=off ");
1480 len += snprintf(buffer + len, PATH_MAX - len,
1481 "cpufreq_on;corec6_off;pc3_off;pc6_off ");
1482 len += snprintf(buffer + len, PATH_MAX - len,
1483 "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
1486 setsysfs(mic->name, "cmdline", buffer);
1487 mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer);
1488 snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id);
1489 mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer);
1493 set_log_buf_info(struct mic_info *mic)
1497 char system_map[] = "/lib/firmware/mic/System.map";
1498 char *map, *temp, log_buf[17] = {'\0'};
1500 fd = open(system_map, O_RDONLY);
1502 mpsslog("%s: Opening System.map failed: %d\n",
1506 len = lseek(fd, 0, SEEK_END);
1508 mpsslog("%s: Reading System.map size failed: %d\n",
1513 map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
1514 if (map == MAP_FAILED) {
1515 mpsslog("%s: mmap of System.map failed: %d\n",
1520 temp = strstr(map, "__log_buf");
1522 mpsslog("%s: __log_buf not found: %d\n", mic->name, errno);
1527 strncpy(log_buf, temp - 19, 16);
1528 setsysfs(mic->name, "log_buf_addr", log_buf);
1529 mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf);
1530 temp = strstr(map, "log_buf_len");
1532 mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno);
1537 strncpy(log_buf, temp - 19, 16);
1538 setsysfs(mic->name, "log_buf_len", log_buf);
1539 mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf);
1544 static void init_mic(struct mic_info *mic);
1547 change_virtblk_backend(int x, siginfo_t *siginfo, void *p)
1549 struct mic_info *mic;
1551 for (mic = mic_list.next; mic != NULL; mic = mic->next)
1552 mic->mic_virtblk.signaled = 1/* true */;
1556 init_mic(struct mic_info *mic)
1558 struct sigaction ignore = {
1560 .sa_handler = SIG_IGN
1562 struct sigaction act = {
1563 .sa_flags = SA_SIGINFO,
1564 .sa_sigaction = change_virtblk_backend,
1566 char buffer[PATH_MAX];
1570 * Currently, one virtio block device is supported for each MIC card
1571 * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
1572 * The signal informs the virtio block backend about a change in the
1573 * configuration file which specifies the virtio backend file name on
1574 * the host. Virtio block backend then re-reads the configuration file
1575 * and switches to the new block device. This signalling mechanism may
1576 * not be required once multiple virtio block devices are supported by
1579 sigaction(SIGUSR1, &ignore, NULL);
1584 set_log_buf_info(mic);
1586 add_virtio_device(mic, &virtcons_dev_page.dd);
1587 add_virtio_device(mic, &virtnet_dev_page.dd);
1588 err = pthread_create(&mic->mic_console.console_thread, NULL,
1589 virtio_console, mic);
1591 mpsslog("%s virtcons pthread_create failed %s\n",
1592 mic->name, strerror(err));
1593 err = pthread_create(&mic->mic_net.net_thread, NULL,
1596 mpsslog("%s virtnet pthread_create failed %s\n",
1597 mic->name, strerror(err));
1598 err = pthread_create(&mic->mic_virtblk.block_thread, NULL,
1601 mpsslog("%s virtblk pthread_create failed %s\n",
1602 mic->name, strerror(err));
1603 sigemptyset(&act.sa_mask);
1604 err = sigaction(SIGUSR1, &act, NULL);
1606 mpsslog("%s sigaction SIGUSR1 failed %s\n",
1607 mic->name, strerror(errno));
1611 mpsslog("fork failed MIC name %s id %d errno %d\n",
1612 mic->name, mic->id, errno);
1616 snprintf(buffer, PATH_MAX, "boot");
1617 setsysfs(mic->name, "state", buffer);
1618 mpsslog("%s restarting mic %d\n",
1619 mic->name, mic->restart);
1622 pthread_create(&mic->config_thread, NULL, mic_config, mic);
1629 struct mic_info *mic;
1631 for (mic = mic_list.next; mic != NULL; mic = mic->next)
1641 struct mic_info *mic = &mic_list;
1642 struct dirent *file;
1646 dp = opendir(MICSYSFSDIR);
1650 while ((file = readdir(dp)) != NULL) {
1651 if (!strncmp(file->d_name, "mic", 3)) {
1652 mic->next = calloc(1, sizeof(struct mic_info));
1655 mic->id = atoi(&file->d_name[3]);
1656 mic->name = malloc(strlen(file->d_name) + 16);
1658 strcpy(mic->name, file->d_name);
1659 mpsslog("MIC name %s id %d\n", mic->name,
1671 mpsslog(char *format, ...)
1681 va_start(args, format);
1682 vsprintf(buffer, format, args);
1686 ts1 = ctime_r(&t, ts);
1687 ts1[strlen(ts1) - 1] = '\0';
1688 fprintf(logfp, "%s: %s", ts1, buffer);
1694 main(int argc, char *argv[])
1701 logfp = fopen(LOGFILE_NAME, "a+");
1703 fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME);
1716 mpsslog("MIC Daemon start\n");
1718 cnt = init_mic_list();
1720 mpsslog("MIC module not loaded\n");
1723 mpsslog("MIC found %d devices\n", cnt);