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
);