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>
45 static void init_mic(struct mic_info
*mic
);
48 static struct mic_info mic_list
;
50 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
52 #define min_t(type, x, y) ({ \
55 __min1 < __min2 ? __min1 : __min2; })
57 /* align addr on a size boundary - adjust address up/down if needed */
58 #define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
59 #define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
61 /* align addr on a size boundary - adjust address up if needed */
62 #define _ALIGN(addr, size) _ALIGN_UP(addr, size)
64 /* to align the pointer to the (next) page boundary */
65 #define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
67 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
70 #define MAX_GSO_SIZE (64 * 1024)
72 #define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
73 #define MIC_DEVICE_PAGE_END 0x1000
75 #ifndef VIRTIO_NET_HDR_F_DATA_VALID
76 #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
80 struct mic_device_desc dd
;
81 struct mic_vqconfig vqconfig
[2];
82 __u32 host_features
, guest_acknowledgements
;
83 struct virtio_console_config cons_config
;
84 } virtcons_dev_page
= {
86 .type
= VIRTIO_ID_CONSOLE
,
87 .num_vq
= ARRAY_SIZE(virtcons_dev_page
.vqconfig
),
88 .feature_len
= sizeof(virtcons_dev_page
.host_features
),
89 .config_len
= sizeof(virtcons_dev_page
.cons_config
),
92 .num
= htole16(MIC_VRING_ENTRIES
),
95 .num
= htole16(MIC_VRING_ENTRIES
),
100 struct mic_device_desc dd
;
101 struct mic_vqconfig vqconfig
[2];
102 __u32 host_features
, guest_acknowledgements
;
103 struct virtio_net_config net_config
;
104 } virtnet_dev_page
= {
106 .type
= VIRTIO_ID_NET
,
107 .num_vq
= ARRAY_SIZE(virtnet_dev_page
.vqconfig
),
108 .feature_len
= sizeof(virtnet_dev_page
.host_features
),
109 .config_len
= sizeof(virtnet_dev_page
.net_config
),
112 .num
= htole16(MIC_VRING_ENTRIES
),
115 .num
= htole16(MIC_VRING_ENTRIES
),
118 .host_features
= htole32(
119 1 << VIRTIO_NET_F_CSUM
|
120 1 << VIRTIO_NET_F_GSO
|
121 1 << VIRTIO_NET_F_GUEST_TSO4
|
122 1 << VIRTIO_NET_F_GUEST_TSO6
|
123 1 << VIRTIO_NET_F_GUEST_ECN
|
124 1 << VIRTIO_NET_F_GUEST_UFO
),
130 static const char *mic_config_dir
= "/etc/sysconfig/mic";
131 static const char *virtblk_backend
= "VIRTBLK_BACKEND";
133 struct mic_device_desc dd
;
134 struct mic_vqconfig vqconfig
[1];
135 __u32 host_features
, guest_acknowledgements
;
136 struct virtio_blk_config blk_config
;
137 } virtblk_dev_page
= {
139 .type
= VIRTIO_ID_BLOCK
,
140 .num_vq
= ARRAY_SIZE(virtblk_dev_page
.vqconfig
),
141 .feature_len
= sizeof(virtblk_dev_page
.host_features
),
142 .config_len
= sizeof(virtblk_dev_page
.blk_config
),
145 .num
= htole16(MIC_VRING_ENTRIES
),
148 htole32(1<<VIRTIO_BLK_F_SEG_MAX
),
150 .seg_max
= htole32(MIC_VRING_ENTRIES
- 2),
151 .capacity
= htole64(0),
158 tap_configure(struct mic_info
*mic
, char *dev
)
162 char ipaddr
[IFNAMSIZ
];
173 mpsslog("Configuring %s\n", dev
);
174 ret
= execvp("ip", ifargv
);
176 mpsslog("%s execvp failed errno %s\n",
177 mic
->name
, strerror(errno
));
182 mpsslog("%s fork failed errno %s\n",
183 mic
->name
, strerror(errno
));
187 ret
= waitpid(pid
, NULL
, 0);
189 mpsslog("%s waitpid failed errno %s\n",
190 mic
->name
, strerror(errno
));
194 snprintf(ipaddr
, IFNAMSIZ
, "172.31.%d.254/24", mic
->id
);
205 mpsslog("Configuring %s ipaddr %s\n", dev
, ipaddr
);
206 ret
= execvp("ip", ifargv
);
208 mpsslog("%s execvp failed errno %s\n",
209 mic
->name
, strerror(errno
));
214 mpsslog("%s fork failed errno %s\n",
215 mic
->name
, strerror(errno
));
219 ret
= waitpid(pid
, NULL
, 0);
221 mpsslog("%s waitpid failed errno %s\n",
222 mic
->name
, strerror(errno
));
225 mpsslog("MIC name %s %s %d DONE!\n",
226 mic
->name
, __func__
, __LINE__
);
230 static int tun_alloc(struct mic_info
*mic
, char *dev
)
237 fd
= open("/dev/net/tun", O_RDWR
);
239 mpsslog("Could not open /dev/net/tun %s\n", strerror(errno
));
243 memset(&ifr
, 0, sizeof(ifr
));
245 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
| IFF_VNET_HDR
;
247 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
249 err
= ioctl(fd
, TUNSETIFF
, (void *)&ifr
);
251 mpsslog("%s %s %d TUNSETIFF failed %s\n",
252 mic
->name
, __func__
, __LINE__
, strerror(errno
));
257 offload
= TUN_F_CSUM
| TUN_F_TSO4
| TUN_F_TSO6
|
258 TUN_F_TSO_ECN
| TUN_F_UFO
;
260 err
= ioctl(fd
, TUNSETOFFLOAD
, offload
);
262 mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
263 mic
->name
, __func__
, __LINE__
, strerror(errno
));
268 strcpy(dev
, ifr
.ifr_name
);
269 mpsslog("Created TAP %s\n", dev
);
274 #define NET_FD_VIRTIO_NET 0
278 static void set_dp(struct mic_info
*mic
, int type
, void *dp
)
281 case VIRTIO_ID_CONSOLE
:
282 mic
->mic_console
.console_dp
= dp
;
285 mic
->mic_net
.net_dp
= dp
;
287 case VIRTIO_ID_BLOCK
:
288 mic
->mic_virtblk
.block_dp
= dp
;
291 mpsslog("%s %s %d not found\n", mic
->name
, __func__
, type
);
295 static void *get_dp(struct mic_info
*mic
, int type
)
298 case VIRTIO_ID_CONSOLE
:
299 return mic
->mic_console
.console_dp
;
301 return mic
->mic_net
.net_dp
;
302 case VIRTIO_ID_BLOCK
:
303 return mic
->mic_virtblk
.block_dp
;
305 mpsslog("%s %s %d not found\n", mic
->name
, __func__
, type
);
310 static struct mic_device_desc
*get_device_desc(struct mic_info
*mic
, int type
)
312 struct mic_device_desc
*d
;
314 void *dp
= get_dp(mic
, type
);
316 for (i
= mic_aligned_size(struct mic_bootparam
); i
< PAGE_SIZE
;
317 i
+= mic_total_desc_size(d
)) {
327 mpsslog("%s %s d-> type %d d %p\n",
328 mic
->name
, __func__
, d
->type
, d
);
330 if (d
->type
== (__u8
)type
)
333 mpsslog("%s %s %d not found\n", mic
->name
, __func__
, type
);
338 /* See comments in vhost.c for explanation of next_desc() */
339 static unsigned next_desc(struct vring_desc
*desc
)
343 if (!(le16toh(desc
->flags
) & VRING_DESC_F_NEXT
))
345 next
= le16toh(desc
->next
);
349 /* Sum up all the IOVEC length */
351 sum_iovec_len(struct mic_copy_desc
*copy
)
356 for (i
= 0; i
< copy
->iovcnt
; i
++)
357 sum
+= copy
->iov
[i
].iov_len
;
361 static inline void verify_out_len(struct mic_info
*mic
,
362 struct mic_copy_desc
*copy
)
364 if (copy
->out_len
!= sum_iovec_len(copy
)) {
365 mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%x\n",
366 mic
->name
, __func__
, __LINE__
,
367 copy
->out_len
, sum_iovec_len(copy
));
368 assert(copy
->out_len
== sum_iovec_len(copy
));
372 /* Display an iovec */
374 disp_iovec(struct mic_info
*mic
, struct mic_copy_desc
*copy
,
375 const char *s
, int line
)
379 for (i
= 0; i
< copy
->iovcnt
; i
++)
380 mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%lx\n",
381 mic
->name
, s
, line
, i
,
382 copy
->iov
[i
].iov_base
, copy
->iov
[i
].iov_len
);
385 static inline __u16
read_avail_idx(struct mic_vring
*vr
)
387 return ACCESS_ONCE(vr
->info
->avail_idx
);
390 static inline void txrx_prepare(int type
, bool tx
, struct mic_vring
*vr
,
391 struct mic_copy_desc
*copy
, ssize_t len
)
393 copy
->vr_idx
= tx
? 0 : 1;
394 copy
->update_used
= true;
395 if (type
== VIRTIO_ID_NET
)
396 copy
->iov
[1].iov_len
= len
- sizeof(struct virtio_net_hdr
);
398 copy
->iov
[0].iov_len
= len
;
401 /* Central API which triggers the copies */
403 mic_virtio_copy(struct mic_info
*mic
, int fd
,
404 struct mic_vring
*vr
, struct mic_copy_desc
*copy
)
408 ret
= ioctl(fd
, MIC_VIRTIO_COPY_DESC
, copy
);
410 mpsslog("%s %s %d errno %s ret %d\n",
411 mic
->name
, __func__
, __LINE__
,
412 strerror(errno
), ret
);
418 * This initialization routine requires at least one
419 * vring i.e. vr0. vr1 is optional.
422 init_vr(struct mic_info
*mic
, int fd
, int type
,
423 struct mic_vring
*vr0
, struct mic_vring
*vr1
, int num_vq
)
428 vr_size
= PAGE_ALIGN(vring_size(MIC_VRING_ENTRIES
,
429 MIC_VIRTIO_RING_ALIGN
) + sizeof(struct _mic_vring_info
));
430 va
= mmap(NULL
, MIC_DEVICE_PAGE_END
+ vr_size
* num_vq
,
431 PROT_READ
, MAP_SHARED
, fd
, 0);
432 if (MAP_FAILED
== va
) {
433 mpsslog("%s %s %d mmap failed errno %s\n",
434 mic
->name
, __func__
, __LINE__
,
438 set_dp(mic
, type
, va
);
439 vr0
->va
= (struct mic_vring
*)&va
[MIC_DEVICE_PAGE_END
];
440 vr0
->info
= vr0
->va
+
441 vring_size(MIC_VRING_ENTRIES
, MIC_VIRTIO_RING_ALIGN
);
443 MIC_VRING_ENTRIES
, vr0
->va
, MIC_VIRTIO_RING_ALIGN
);
444 mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
445 __func__
, mic
->name
, vr0
->va
, vr0
->info
, vr_size
,
446 vring_size(MIC_VRING_ENTRIES
, MIC_VIRTIO_RING_ALIGN
));
447 mpsslog("magic 0x%x expected 0x%x\n",
448 vr0
->info
->magic
, MIC_MAGIC
+ type
);
449 assert(vr0
->info
->magic
== MIC_MAGIC
+ type
);
451 vr1
->va
= (struct mic_vring
*)
452 &va
[MIC_DEVICE_PAGE_END
+ vr_size
];
453 vr1
->info
= vr1
->va
+ vring_size(MIC_VRING_ENTRIES
,
454 MIC_VIRTIO_RING_ALIGN
);
456 MIC_VRING_ENTRIES
, vr1
->va
, MIC_VIRTIO_RING_ALIGN
);
457 mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
458 __func__
, mic
->name
, vr1
->va
, vr1
->info
, vr_size
,
459 vring_size(MIC_VRING_ENTRIES
, MIC_VIRTIO_RING_ALIGN
));
460 mpsslog("magic 0x%x expected 0x%x\n",
461 vr1
->info
->magic
, MIC_MAGIC
+ type
+ 1);
462 assert(vr1
->info
->magic
== MIC_MAGIC
+ type
+ 1);
469 wait_for_card_driver(struct mic_info
*mic
, int fd
, int type
)
471 struct pollfd pollfd
;
473 struct mic_device_desc
*desc
= get_device_desc(mic
, type
);
476 mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
477 mic
->name
, __func__
, type
, desc
->status
);
479 pollfd
.events
= POLLIN
;
481 err
= poll(&pollfd
, 1, -1);
483 mpsslog("%s %s poll failed %s\n",
484 mic
->name
, __func__
, strerror(errno
));
488 if (pollfd
.revents
) {
489 mpsslog("%s %s Waiting... desc-> type %d status 0x%x\n",
490 mic
->name
, __func__
, type
, desc
->status
);
491 if (desc
->status
& VIRTIO_CONFIG_S_DRIVER_OK
) {
492 mpsslog("%s %s poll.revents %d\n",
493 mic
->name
, __func__
, pollfd
.revents
);
494 mpsslog("%s %s desc-> type %d status 0x%x\n",
495 mic
->name
, __func__
, type
,
503 /* Spin till we have some descriptors */
505 spin_for_descriptors(struct mic_info
*mic
, struct mic_vring
*vr
)
507 __u16 avail_idx
= read_avail_idx(vr
);
509 while (avail_idx
== le16toh(ACCESS_ONCE(vr
->vr
.avail
->idx
))) {
511 mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
513 le16toh(vr
->vr
.avail
->idx
), vr
->info
->avail_idx
);
520 virtio_net(void *arg
)
522 static __u8 vnet_hdr
[2][sizeof(struct virtio_net_hdr
)];
523 static __u8 vnet_buf
[2][MAX_NET_PKT_SIZE
] __aligned(64);
524 struct iovec vnet_iov
[2][2] = {
525 { { .iov_base
= vnet_hdr
[0], .iov_len
= sizeof(vnet_hdr
[0]) },
526 { .iov_base
= vnet_buf
[0], .iov_len
= sizeof(vnet_buf
[0]) } },
527 { { .iov_base
= vnet_hdr
[1], .iov_len
= sizeof(vnet_hdr
[1]) },
528 { .iov_base
= vnet_buf
[1], .iov_len
= sizeof(vnet_buf
[1]) } },
530 struct iovec
*iov0
= vnet_iov
[0], *iov1
= vnet_iov
[1];
531 struct mic_info
*mic
= (struct mic_info
*)arg
;
532 char if_name
[IFNAMSIZ
];
533 struct pollfd net_poll
[MAX_NET_FD
];
534 struct mic_vring tx_vr
, rx_vr
;
535 struct mic_copy_desc copy
;
536 struct mic_device_desc
*desc
;
539 snprintf(if_name
, IFNAMSIZ
, "mic%d", mic
->id
);
540 mic
->mic_net
.tap_fd
= tun_alloc(mic
, if_name
);
541 if (mic
->mic_net
.tap_fd
< 0)
544 if (tap_configure(mic
, if_name
))
546 mpsslog("MIC name %s id %d\n", mic
->name
, mic
->id
);
548 net_poll
[NET_FD_VIRTIO_NET
].fd
= mic
->mic_net
.virtio_net_fd
;
549 net_poll
[NET_FD_VIRTIO_NET
].events
= POLLIN
;
550 net_poll
[NET_FD_TUN
].fd
= mic
->mic_net
.tap_fd
;
551 net_poll
[NET_FD_TUN
].events
= POLLIN
;
553 if (MAP_FAILED
== init_vr(mic
, mic
->mic_net
.virtio_net_fd
,
554 VIRTIO_ID_NET
, &tx_vr
, &rx_vr
,
555 virtnet_dev_page
.dd
.num_vq
)) {
556 mpsslog("%s init_vr failed %s\n",
557 mic
->name
, strerror(errno
));
562 desc
= get_device_desc(mic
, VIRTIO_ID_NET
);
567 net_poll
[NET_FD_VIRTIO_NET
].revents
= 0;
568 net_poll
[NET_FD_TUN
].revents
= 0;
570 /* Start polling for data from tap and virtio net */
571 err
= poll(net_poll
, 2, -1);
573 mpsslog("%s poll failed %s\n",
574 __func__
, strerror(errno
));
577 if (!(desc
->status
& VIRTIO_CONFIG_S_DRIVER_OK
))
578 wait_for_card_driver(mic
, mic
->mic_net
.virtio_net_fd
,
581 * Check if there is data to be read from TUN and write to
582 * virtio net fd if there is.
584 if (net_poll
[NET_FD_TUN
].revents
& POLLIN
) {
586 len
= readv(net_poll
[NET_FD_TUN
].fd
,
587 copy
.iov
, copy
.iovcnt
);
589 struct virtio_net_hdr
*hdr
590 = (struct virtio_net_hdr
*)vnet_hdr
[0];
592 /* Disable checksums on the card since we are on
593 a reliable PCIe link */
594 hdr
->flags
|= VIRTIO_NET_HDR_F_DATA_VALID
;
596 mpsslog("%s %s %d hdr->flags 0x%x ", mic
->name
,
597 __func__
, __LINE__
, hdr
->flags
);
598 mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
599 copy
.out_len
, hdr
->gso_type
);
602 disp_iovec(mic
, copy
, __func__
, __LINE__
);
603 mpsslog("%s %s %d read from tap 0x%lx\n",
604 mic
->name
, __func__
, __LINE__
,
607 spin_for_descriptors(mic
, &tx_vr
);
608 txrx_prepare(VIRTIO_ID_NET
, 1, &tx_vr
, ©
,
611 err
= mic_virtio_copy(mic
,
612 mic
->mic_net
.virtio_net_fd
, &tx_vr
,
615 mpsslog("%s %s %d mic_virtio_copy %s\n",
616 mic
->name
, __func__
, __LINE__
,
620 verify_out_len(mic
, ©
);
622 disp_iovec(mic
, copy
, __func__
, __LINE__
);
623 mpsslog("%s %s %d wrote to net 0x%lx\n",
624 mic
->name
, __func__
, __LINE__
,
625 sum_iovec_len(©
));
627 /* Reinitialize IOV for next run */
628 iov0
[1].iov_len
= MAX_NET_PKT_SIZE
;
629 } else if (len
< 0) {
630 disp_iovec(mic
, ©
, __func__
, __LINE__
);
631 mpsslog("%s %s %d read failed %s ", mic
->name
,
632 __func__
, __LINE__
, strerror(errno
));
633 mpsslog("cnt %d sum %d\n",
634 copy
.iovcnt
, sum_iovec_len(©
));
639 * Check if there is data to be read from virtio net and
640 * write to TUN if there is.
642 if (net_poll
[NET_FD_VIRTIO_NET
].revents
& POLLIN
) {
643 while (rx_vr
.info
->avail_idx
!=
644 le16toh(rx_vr
.vr
.avail
->idx
)) {
646 txrx_prepare(VIRTIO_ID_NET
, 0, &rx_vr
, ©
,
648 + sizeof(struct virtio_net_hdr
));
650 err
= mic_virtio_copy(mic
,
651 mic
->mic_net
.virtio_net_fd
, &rx_vr
,
655 struct virtio_net_hdr
*hdr
656 = (struct virtio_net_hdr
*)
659 mpsslog("%s %s %d hdr->flags 0x%x, ",
660 mic
->name
, __func__
, __LINE__
,
662 mpsslog("out_len %d gso_type 0x%x\n",
666 /* Set the correct output iov_len */
667 iov1
[1].iov_len
= copy
.out_len
-
668 sizeof(struct virtio_net_hdr
);
669 verify_out_len(mic
, ©
);
671 disp_iovec(mic
, copy
, __func__
,
674 mic
->name
, __func__
, __LINE__
);
675 mpsslog("read from net 0x%lx\n",
676 sum_iovec_len(copy
));
678 len
= writev(net_poll
[NET_FD_TUN
].fd
,
679 copy
.iov
, copy
.iovcnt
);
680 if (len
!= sum_iovec_len(©
)) {
681 mpsslog("Tun write failed %s ",
683 mpsslog("len 0x%x ", len
);
684 mpsslog("read_len 0x%x\n",
685 sum_iovec_len(©
));
688 disp_iovec(mic
, ©
, __func__
,
693 mpsslog("wrote to tap 0x%lx\n",
698 mpsslog("%s %s %d mic_virtio_copy %s\n",
699 mic
->name
, __func__
, __LINE__
,
705 if (net_poll
[NET_FD_VIRTIO_NET
].revents
& POLLERR
)
706 mpsslog("%s: %s: POLLERR\n", __func__
, mic
->name
);
713 #define VIRTIO_CONSOLE_FD 0
714 #define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
715 #define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
716 #define MAX_BUFFER_SIZE PAGE_SIZE
719 virtio_console(void *arg
)
721 static __u8 vcons_buf
[2][PAGE_SIZE
];
722 struct iovec vcons_iov
[2] = {
723 { .iov_base
= vcons_buf
[0], .iov_len
= sizeof(vcons_buf
[0]) },
724 { .iov_base
= vcons_buf
[1], .iov_len
= sizeof(vcons_buf
[1]) },
726 struct iovec
*iov0
= &vcons_iov
[0], *iov1
= &vcons_iov
[1];
727 struct mic_info
*mic
= (struct mic_info
*)arg
;
729 struct pollfd console_poll
[MAX_CONSOLE_FD
];
733 struct mic_vring tx_vr
, rx_vr
;
734 struct mic_copy_desc copy
;
735 struct mic_device_desc
*desc
;
737 pty_fd
= posix_openpt(O_RDWR
);
739 mpsslog("can't open a pseudoterminal master device: %s\n",
743 pts_name
= ptsname(pty_fd
);
744 if (pts_name
== NULL
) {
745 mpsslog("can't get pts name\n");
748 printf("%s console message goes to %s\n", mic
->name
, pts_name
);
749 mpsslog("%s console message goes to %s\n", mic
->name
, pts_name
);
750 err
= grantpt(pty_fd
);
752 mpsslog("can't grant access: %s %s\n",
753 pts_name
, strerror(errno
));
756 err
= unlockpt(pty_fd
);
758 mpsslog("can't unlock a pseudoterminal: %s %s\n",
759 pts_name
, strerror(errno
));
762 console_poll
[MONITOR_FD
].fd
= pty_fd
;
763 console_poll
[MONITOR_FD
].events
= POLLIN
;
765 console_poll
[VIRTIO_CONSOLE_FD
].fd
= mic
->mic_console
.virtio_console_fd
;
766 console_poll
[VIRTIO_CONSOLE_FD
].events
= POLLIN
;
768 if (MAP_FAILED
== init_vr(mic
, mic
->mic_console
.virtio_console_fd
,
769 VIRTIO_ID_CONSOLE
, &tx_vr
, &rx_vr
,
770 virtcons_dev_page
.dd
.num_vq
)) {
771 mpsslog("%s init_vr failed %s\n",
772 mic
->name
, strerror(errno
));
777 desc
= get_device_desc(mic
, VIRTIO_ID_CONSOLE
);
780 console_poll
[MONITOR_FD
].revents
= 0;
781 console_poll
[VIRTIO_CONSOLE_FD
].revents
= 0;
782 err
= poll(console_poll
, MAX_CONSOLE_FD
, -1);
784 mpsslog("%s %d: poll failed: %s\n", __func__
, __LINE__
,
788 if (!(desc
->status
& VIRTIO_CONFIG_S_DRIVER_OK
))
789 wait_for_card_driver(mic
,
790 mic
->mic_console
.virtio_console_fd
,
793 if (console_poll
[MONITOR_FD
].revents
& POLLIN
) {
795 len
= readv(pty_fd
, copy
.iov
, copy
.iovcnt
);
798 disp_iovec(mic
, copy
, __func__
, __LINE__
);
799 mpsslog("%s %s %d read from tap 0x%lx\n",
800 mic
->name
, __func__
, __LINE__
,
803 spin_for_descriptors(mic
, &tx_vr
);
804 txrx_prepare(VIRTIO_ID_CONSOLE
, 1, &tx_vr
,
807 err
= mic_virtio_copy(mic
,
808 mic
->mic_console
.virtio_console_fd
,
811 mpsslog("%s %s %d mic_virtio_copy %s\n",
812 mic
->name
, __func__
, __LINE__
,
816 verify_out_len(mic
, ©
);
818 disp_iovec(mic
, copy
, __func__
, __LINE__
);
819 mpsslog("%s %s %d wrote to net 0x%lx\n",
820 mic
->name
, __func__
, __LINE__
,
821 sum_iovec_len(copy
));
823 /* Reinitialize IOV for next run */
824 iov0
->iov_len
= PAGE_SIZE
;
825 } else if (len
< 0) {
826 disp_iovec(mic
, ©
, __func__
, __LINE__
);
827 mpsslog("%s %s %d read failed %s ",
828 mic
->name
, __func__
, __LINE__
,
830 mpsslog("cnt %d sum %d\n",
831 copy
.iovcnt
, sum_iovec_len(©
));
835 if (console_poll
[VIRTIO_CONSOLE_FD
].revents
& POLLIN
) {
836 while (rx_vr
.info
->avail_idx
!=
837 le16toh(rx_vr
.vr
.avail
->idx
)) {
839 txrx_prepare(VIRTIO_ID_CONSOLE
, 0, &rx_vr
,
842 err
= mic_virtio_copy(mic
,
843 mic
->mic_console
.virtio_console_fd
,
846 /* Set the correct output iov_len */
847 iov1
->iov_len
= copy
.out_len
;
848 verify_out_len(mic
, ©
);
850 disp_iovec(mic
, copy
, __func__
,
853 mic
->name
, __func__
, __LINE__
);
854 mpsslog("read from net 0x%lx\n",
855 sum_iovec_len(copy
));
858 copy
.iov
, copy
.iovcnt
);
859 if (len
!= sum_iovec_len(©
)) {
860 mpsslog("Tun write failed %s ",
862 mpsslog("len 0x%x ", len
);
863 mpsslog("read_len 0x%x\n",
864 sum_iovec_len(©
));
867 disp_iovec(mic
, copy
, __func__
,
872 mpsslog("wrote to tap 0x%lx\n",
877 mpsslog("%s %s %d mic_virtio_copy %s\n",
878 mic
->name
, __func__
, __LINE__
,
884 if (console_poll
[NET_FD_VIRTIO_NET
].revents
& POLLERR
)
885 mpsslog("%s: %s: POLLERR\n", __func__
, mic
->name
);
894 add_virtio_device(struct mic_info
*mic
, struct mic_device_desc
*dd
)
899 snprintf(path
, PATH_MAX
, "/dev/mic%d", mic
->id
);
900 fd
= open(path
, O_RDWR
);
902 mpsslog("Could not open %s %s\n", path
, strerror(errno
));
906 err
= ioctl(fd
, MIC_VIRTIO_ADD_DEVICE
, dd
);
908 mpsslog("Could not add %d %s\n", dd
->type
, strerror(errno
));
914 mic
->mic_net
.virtio_net_fd
= fd
;
915 mpsslog("Added VIRTIO_ID_NET for %s\n", mic
->name
);
917 case VIRTIO_ID_CONSOLE
:
918 mic
->mic_console
.virtio_console_fd
= fd
;
919 mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic
->name
);
921 case VIRTIO_ID_BLOCK
:
922 mic
->mic_virtblk
.virtio_block_fd
= fd
;
923 mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic
->name
);
929 set_backend_file(struct mic_info
*mic
)
932 char buff
[PATH_MAX
], *line
, *evv
, *p
;
934 snprintf(buff
, PATH_MAX
, "%s/mpssd%03d.conf", mic_config_dir
, mic
->id
);
935 config
= fopen(buff
, "r");
938 do { /* look for "virtblk_backend=XXXX" */
939 line
= fgets(buff
, PATH_MAX
, config
);
944 p
= strchr(line
, '\n');
947 } while (strncmp(line
, virtblk_backend
, strlen(virtblk_backend
)) != 0);
951 evv
= strchr(line
, '=');
954 mic
->mic_virtblk
.backend_file
= malloc(strlen(evv
) + 1);
955 if (mic
->mic_virtblk
.backend_file
== NULL
) {
956 mpsslog("can't allocate memory\n", mic
->name
, mic
->id
);
959 strcpy(mic
->mic_virtblk
.backend_file
, evv
+ 1);
963 #define SECTOR_SIZE 512
965 set_backend_size(struct mic_info
*mic
)
967 mic
->mic_virtblk
.backend_size
= lseek(mic
->mic_virtblk
.backend
, 0,
969 if (mic
->mic_virtblk
.backend_size
< 0) {
970 mpsslog("%s: can't seek: %s\n",
971 mic
->name
, mic
->mic_virtblk
.backend_file
);
974 virtblk_dev_page
.blk_config
.capacity
=
975 mic
->mic_virtblk
.backend_size
/ SECTOR_SIZE
;
976 if ((mic
->mic_virtblk
.backend_size
% SECTOR_SIZE
) != 0)
977 virtblk_dev_page
.blk_config
.capacity
++;
979 virtblk_dev_page
.blk_config
.capacity
=
980 htole64(virtblk_dev_page
.blk_config
.capacity
);
986 open_backend(struct mic_info
*mic
)
988 if (!set_backend_file(mic
))
990 mic
->mic_virtblk
.backend
= open(mic
->mic_virtblk
.backend_file
, O_RDWR
);
991 if (mic
->mic_virtblk
.backend
< 0) {
992 mpsslog("%s: can't open: %s\n", mic
->name
,
993 mic
->mic_virtblk
.backend_file
);
996 if (!set_backend_size(mic
))
998 mic
->mic_virtblk
.backend_addr
= mmap(NULL
,
999 mic
->mic_virtblk
.backend_size
,
1000 PROT_READ
|PROT_WRITE
, MAP_SHARED
,
1001 mic
->mic_virtblk
.backend
, 0L);
1002 if (mic
->mic_virtblk
.backend_addr
== MAP_FAILED
) {
1003 mpsslog("%s: can't map: %s %s\n",
1004 mic
->name
, mic
->mic_virtblk
.backend_file
,
1011 close(mic
->mic_virtblk
.backend
);
1013 free(mic
->mic_virtblk
.backend_file
);
1019 close_backend(struct mic_info
*mic
)
1021 munmap(mic
->mic_virtblk
.backend_addr
, mic
->mic_virtblk
.backend_size
);
1022 close(mic
->mic_virtblk
.backend
);
1023 free(mic
->mic_virtblk
.backend_file
);
1027 start_virtblk(struct mic_info
*mic
, struct mic_vring
*vring
)
1029 if (((__u64
)&virtblk_dev_page
.blk_config
% 8) != 0) {
1030 mpsslog("%s: blk_config is not 8 byte aligned.\n",
1034 add_virtio_device(mic
, &virtblk_dev_page
.dd
);
1035 if (MAP_FAILED
== init_vr(mic
, mic
->mic_virtblk
.virtio_block_fd
,
1036 VIRTIO_ID_BLOCK
, vring
, NULL
,
1037 virtblk_dev_page
.dd
.num_vq
)) {
1038 mpsslog("%s init_vr failed %s\n",
1039 mic
->name
, strerror(errno
));
1046 stop_virtblk(struct mic_info
*mic
)
1050 vr_size
= PAGE_ALIGN(vring_size(MIC_VRING_ENTRIES
,
1051 MIC_VIRTIO_RING_ALIGN
) + sizeof(struct _mic_vring_info
));
1052 ret
= munmap(mic
->mic_virtblk
.block_dp
,
1053 MIC_DEVICE_PAGE_END
+ vr_size
* virtblk_dev_page
.dd
.num_vq
);
1055 mpsslog("%s munmap errno %d\n", mic
->name
, errno
);
1056 close(mic
->mic_virtblk
.virtio_block_fd
);
1060 header_error_check(struct vring_desc
*desc
)
1062 if (le32toh(desc
->len
) != sizeof(struct virtio_blk_outhdr
)) {
1063 mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
1064 __func__
, __LINE__
);
1067 if (!(le16toh(desc
->flags
) & VRING_DESC_F_NEXT
)) {
1068 mpsslog("%s() %d: alone\n",
1069 __func__
, __LINE__
);
1072 if (le16toh(desc
->flags
) & VRING_DESC_F_WRITE
) {
1073 mpsslog("%s() %d: not read\n",
1074 __func__
, __LINE__
);
1081 read_header(int fd
, struct virtio_blk_outhdr
*hdr
, __u32 desc_idx
)
1084 struct mic_copy_desc copy
;
1086 iovec
.iov_len
= sizeof(*hdr
);
1087 iovec
.iov_base
= hdr
;
1090 copy
.vr_idx
= 0; /* only one vring on virtio_block */
1091 copy
.update_used
= false; /* do not update used index */
1092 return ioctl(fd
, MIC_VIRTIO_COPY_DESC
, ©
);
1096 transfer_blocks(int fd
, struct iovec
*iovec
, __u32 iovcnt
)
1098 struct mic_copy_desc copy
;
1101 copy
.iovcnt
= iovcnt
;
1102 copy
.vr_idx
= 0; /* only one vring on virtio_block */
1103 copy
.update_used
= false; /* do not update used index */
1104 return ioctl(fd
, MIC_VIRTIO_COPY_DESC
, ©
);
1108 status_error_check(struct vring_desc
*desc
)
1110 if (le32toh(desc
->len
) != sizeof(__u8
)) {
1111 mpsslog("%s() %d: length is not sizeof(status)\n",
1112 __func__
, __LINE__
);
1119 write_status(int fd
, __u8
*status
)
1122 struct mic_copy_desc copy
;
1124 iovec
.iov_base
= status
;
1125 iovec
.iov_len
= sizeof(*status
);
1128 copy
.vr_idx
= 0; /* only one vring on virtio_block */
1129 copy
.update_used
= true; /* Update used index */
1130 return ioctl(fd
, MIC_VIRTIO_COPY_DESC
, ©
);
1134 virtio_block(void *arg
)
1136 struct mic_info
*mic
= (struct mic_info
*)arg
;
1138 struct pollfd block_poll
;
1139 struct mic_vring vring
;
1142 struct vring_desc
*desc
;
1143 struct iovec
*iovec
, *piov
;
1145 __u32 buffer_desc_idx
;
1146 struct virtio_blk_outhdr hdr
;
1149 for (;;) { /* forever */
1150 if (!open_backend(mic
)) { /* No virtblk */
1151 for (mic
->mic_virtblk
.signaled
= 0;
1152 !mic
->mic_virtblk
.signaled
;)
1157 /* backend file is specified. */
1158 if (!start_virtblk(mic
, &vring
))
1159 goto _close_backend
;
1160 iovec
= malloc(sizeof(*iovec
) *
1161 le32toh(virtblk_dev_page
.blk_config
.seg_max
));
1163 mpsslog("%s: can't alloc iovec: %s\n",
1164 mic
->name
, strerror(ENOMEM
));
1168 block_poll
.fd
= mic
->mic_virtblk
.virtio_block_fd
;
1169 block_poll
.events
= POLLIN
;
1170 for (mic
->mic_virtblk
.signaled
= 0;
1171 !mic
->mic_virtblk
.signaled
;) {
1172 block_poll
.revents
= 0;
1173 /* timeout in 1 sec to see signaled */
1174 ret
= poll(&block_poll
, 1, 1000);
1176 mpsslog("%s %d: poll failed: %s\n",
1182 if (!(block_poll
.revents
& POLLIN
)) {
1184 mpsslog("%s %d: block_poll.revents=0x%x\n",
1185 __func__
, __LINE__
, block_poll
.revents
);
1191 while (vring
.info
->avail_idx
!=
1192 le16toh(vring
.vr
.avail
->idx
)) {
1193 /* read header element */
1195 vring
.info
->avail_idx
&
1198 vring
.vr
.avail
->ring
[avail_idx
]);
1199 desc
= &vring
.vr
.desc
[desc_idx
];
1201 mpsslog("%s() %d: avail_idx=%d ",
1203 vring
.info
->avail_idx
);
1204 mpsslog("vring.vr.num=%d desc=%p\n",
1205 vring
.vr
.num
, desc
);
1207 status
= header_error_check(desc
);
1209 mic
->mic_virtblk
.virtio_block_fd
,
1212 mpsslog("%s() %d %s: ret=%d %s\n",
1218 /* buffer element */
1221 fos
= mic
->mic_virtblk
.backend_addr
+
1222 (hdr
.sector
* SECTOR_SIZE
);
1223 buffer_desc_idx
= next_desc(desc
);
1224 desc_idx
= buffer_desc_idx
;
1225 for (desc
= &vring
.vr
.desc
[buffer_desc_idx
];
1226 desc
->flags
& VRING_DESC_F_NEXT
;
1227 desc_idx
= next_desc(desc
),
1228 desc
= &vring
.vr
.desc
[desc_idx
]) {
1229 piov
->iov_len
= desc
->len
;
1230 piov
->iov_base
= fos
;
1234 /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
1235 if (hdr
.type
& ~(VIRTIO_BLK_T_OUT
|
1236 VIRTIO_BLK_T_GET_ID
)) {
1238 VIRTIO_BLK_T_IN - does not do
1239 anything. Probably for documenting.
1240 VIRTIO_BLK_T_SCSI_CMD - for
1242 VIRTIO_BLK_T_FLUSH - turned off in
1244 VIRTIO_BLK_T_BARRIER - defined but not
1247 mpsslog("%s() %d: type %x ",
1250 mpsslog("is not supported\n");
1254 ret
= transfer_blocks(
1255 mic
->mic_virtblk
.virtio_block_fd
,
1262 /* write status and update used pointer */
1264 status
= status_error_check(desc
);
1266 mic
->mic_virtblk
.virtio_block_fd
,
1269 mpsslog("%s() %d: write status=%d on desc=%p\n",
1286 reset(struct mic_info
*mic
)
1288 #define RESET_TIMEOUT 120
1289 int i
= RESET_TIMEOUT
;
1290 setsysfs(mic
->name
, "state", "reset");
1293 state
= readsysfs(mic
->name
, "state");
1296 mpsslog("%s: %s %d state %s\n",
1297 mic
->name
, __func__
, __LINE__
, state
);
1298 if ((!strcmp(state
, "offline"))) {
1310 get_mic_shutdown_status(struct mic_info
*mic
, char *shutdown_status
)
1312 if (!strcmp(shutdown_status
, "nop"))
1314 if (!strcmp(shutdown_status
, "crashed"))
1316 if (!strcmp(shutdown_status
, "halted"))
1318 if (!strcmp(shutdown_status
, "poweroff"))
1319 return MIC_POWER_OFF
;
1320 if (!strcmp(shutdown_status
, "restart"))
1322 mpsslog("%s: BUG invalid status %s\n", mic
->name
, shutdown_status
);
1327 static int get_mic_state(struct mic_info
*mic
, char *state
)
1329 if (!strcmp(state
, "offline"))
1331 if (!strcmp(state
, "online"))
1333 if (!strcmp(state
, "shutting_down"))
1334 return MIC_SHUTTING_DOWN
;
1335 if (!strcmp(state
, "reset_failed"))
1336 return MIC_RESET_FAILED
;
1337 mpsslog("%s: BUG invalid state %s\n", mic
->name
, state
);
1342 static void mic_handle_shutdown(struct mic_info
*mic
)
1344 #define SHUTDOWN_TIMEOUT 60
1345 int i
= SHUTDOWN_TIMEOUT
, ret
, stat
= 0;
1346 char *shutdown_status
;
1348 shutdown_status
= readsysfs(mic
->name
, "shutdown_status");
1349 if (!shutdown_status
)
1351 mpsslog("%s: %s %d shutdown_status %s\n",
1352 mic
->name
, __func__
, __LINE__
, shutdown_status
);
1353 switch (get_mic_shutdown_status(mic
, shutdown_status
)) {
1359 free(shutdown_status
);
1364 free(shutdown_status
);
1369 ret
= kill(mic
->pid
, SIGTERM
);
1370 mpsslog("%s: %s %d kill pid %d ret %d\n",
1371 mic
->name
, __func__
, __LINE__
,
1374 ret
= waitpid(mic
->pid
, &stat
,
1376 mpsslog("%s: %s %d waitpid ret %d pid %d\n",
1377 mic
->name
, __func__
, __LINE__
,
1380 if (ret
== mic
->pid
)
1385 mic_config(void *arg
)
1387 struct mic_info
*mic
= (struct mic_info
*)arg
;
1389 char pathname
[PATH_MAX
];
1391 struct pollfd ufds
[1];
1394 snprintf(pathname
, PATH_MAX
- 1, "%s/%s/%s",
1395 MICSYSFSDIR
, mic
->name
, "state");
1397 fd
= open(pathname
, O_RDONLY
);
1399 mpsslog("%s: opening file %s failed %s\n",
1400 mic
->name
, pathname
, strerror(errno
));
1405 ret
= read(fd
, value
, sizeof(value
));
1407 mpsslog("%s: Failed to read sysfs entry '%s': %s\n",
1408 mic
->name
, pathname
, strerror(errno
));
1412 state
= readsysfs(mic
->name
, "state");
1415 mpsslog("%s: %s %d state %s\n",
1416 mic
->name
, __func__
, __LINE__
, state
);
1417 switch (get_mic_state(mic
, state
)) {
1418 case MIC_SHUTTING_DOWN
:
1419 mic_handle_shutdown(mic
);
1427 ufds
[0].events
= POLLERR
| POLLPRI
;
1428 ret
= poll(ufds
, 1, -1);
1430 mpsslog("%s: poll failed %s\n",
1431 mic
->name
, strerror(errno
));
1445 set_cmdline(struct mic_info
*mic
)
1447 char buffer
[PATH_MAX
];
1450 len
= snprintf(buffer
, PATH_MAX
,
1451 "clocksource=tsc highres=off nohz=off ");
1452 len
+= snprintf(buffer
+ len
, PATH_MAX
,
1453 "cpufreq_on;corec6_off;pc3_off;pc6_off ");
1454 len
+= snprintf(buffer
+ len
, PATH_MAX
,
1455 "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
1458 setsysfs(mic
->name
, "cmdline", buffer
);
1459 mpsslog("%s: Command line: \"%s\"\n", mic
->name
, buffer
);
1460 snprintf(buffer
, PATH_MAX
, "172.31.%d.1", mic
->id
);
1461 mpsslog("%s: IPADDR: \"%s\"\n", mic
->name
, buffer
);
1465 set_log_buf_info(struct mic_info
*mic
)
1469 char system_map
[] = "/lib/firmware/mic/System.map";
1470 char *map
, *temp
, log_buf
[17] = {'\0'};
1472 fd
= open(system_map
, O_RDONLY
);
1474 mpsslog("%s: Opening System.map failed: %d\n",
1478 len
= lseek(fd
, 0, SEEK_END
);
1480 mpsslog("%s: Reading System.map size failed: %d\n",
1485 map
= mmap(NULL
, len
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
1486 if (map
== MAP_FAILED
) {
1487 mpsslog("%s: mmap of System.map failed: %d\n",
1492 temp
= strstr(map
, "__log_buf");
1494 mpsslog("%s: __log_buf not found: %d\n", mic
->name
, errno
);
1499 strncpy(log_buf
, temp
- 19, 16);
1500 setsysfs(mic
->name
, "log_buf_addr", log_buf
);
1501 mpsslog("%s: log_buf_addr: %s\n", mic
->name
, log_buf
);
1502 temp
= strstr(map
, "log_buf_len");
1504 mpsslog("%s: log_buf_len not found: %d\n", mic
->name
, errno
);
1509 strncpy(log_buf
, temp
- 19, 16);
1510 setsysfs(mic
->name
, "log_buf_len", log_buf
);
1511 mpsslog("%s: log_buf_len: %s\n", mic
->name
, log_buf
);
1516 static void init_mic(struct mic_info
*mic
);
1519 change_virtblk_backend(int x
, siginfo_t
*siginfo
, void *p
)
1521 struct mic_info
*mic
;
1523 for (mic
= mic_list
.next
; mic
!= NULL
; mic
= mic
->next
)
1524 mic
->mic_virtblk
.signaled
= 1/* true */;
1528 init_mic(struct mic_info
*mic
)
1530 struct sigaction ignore
= {
1532 .sa_handler
= SIG_IGN
1534 struct sigaction act
= {
1535 .sa_flags
= SA_SIGINFO
,
1536 .sa_sigaction
= change_virtblk_backend
,
1538 char buffer
[PATH_MAX
];
1542 * Currently, one virtio block device is supported for each MIC card
1543 * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
1544 * The signal informs the virtio block backend about a change in the
1545 * configuration file which specifies the virtio backend file name on
1546 * the host. Virtio block backend then re-reads the configuration file
1547 * and switches to the new block device. This signalling mechanism may
1548 * not be required once multiple virtio block devices are supported by
1551 sigaction(SIGUSR1
, &ignore
, NULL
);
1556 set_log_buf_info(mic
);
1558 add_virtio_device(mic
, &virtcons_dev_page
.dd
);
1559 add_virtio_device(mic
, &virtnet_dev_page
.dd
);
1560 err
= pthread_create(&mic
->mic_console
.console_thread
, NULL
,
1561 virtio_console
, mic
);
1563 mpsslog("%s virtcons pthread_create failed %s\n",
1564 mic
->name
, strerror(err
));
1565 err
= pthread_create(&mic
->mic_net
.net_thread
, NULL
,
1568 mpsslog("%s virtnet pthread_create failed %s\n",
1569 mic
->name
, strerror(err
));
1570 err
= pthread_create(&mic
->mic_virtblk
.block_thread
, NULL
,
1573 mpsslog("%s virtblk pthread_create failed %s\n",
1574 mic
->name
, strerror(err
));
1575 sigemptyset(&act
.sa_mask
);
1576 err
= sigaction(SIGUSR1
, &act
, NULL
);
1578 mpsslog("%s sigaction SIGUSR1 failed %s\n",
1579 mic
->name
, strerror(errno
));
1583 mpsslog("fork failed MIC name %s id %d errno %d\n",
1584 mic
->name
, mic
->id
, errno
);
1588 snprintf(buffer
, PATH_MAX
, "boot");
1589 setsysfs(mic
->name
, "state", buffer
);
1590 mpsslog("%s restarting mic %d\n",
1591 mic
->name
, mic
->restart
);
1594 pthread_create(&mic
->config_thread
, NULL
, mic_config
, mic
);
1601 struct mic_info
*mic
;
1603 for (mic
= mic_list
.next
; mic
!= NULL
; mic
= mic
->next
)
1613 struct mic_info
*mic
= &mic_list
;
1614 struct dirent
*file
;
1618 dp
= opendir(MICSYSFSDIR
);
1622 while ((file
= readdir(dp
)) != NULL
) {
1623 if (!strncmp(file
->d_name
, "mic", 3)) {
1624 mic
->next
= malloc(sizeof(struct mic_info
));
1628 memset(mic
, 0, sizeof(struct mic_info
));
1629 mic
->id
= atoi(&file
->d_name
[3]);
1630 mic
->name
= malloc(strlen(file
->d_name
) + 16);
1632 strcpy(mic
->name
, file
->d_name
);
1633 mpsslog("MIC name %s id %d\n", mic
->name
,
1645 mpsslog(char *format
, ...)
1655 va_start(args
, format
);
1656 vsprintf(buffer
, format
, args
);
1660 ts1
= ctime_r(&t
, ts
);
1661 ts1
[strlen(ts1
) - 1] = '\0';
1662 fprintf(logfp
, "%s: %s", ts1
, buffer
);
1668 main(int argc
, char *argv
[])
1675 logfp
= fopen(LOGFILE_NAME
, "a+");
1677 fprintf(stderr
, "cannot open logfile '%s'\n", LOGFILE_NAME
);
1690 mpsslog("MIC Daemon start\n");
1692 cnt
= init_mic_list();
1694 mpsslog("MIC module not loaded\n");
1697 mpsslog("MIC found %d devices\n", cnt
);