A few cosmetic changes found while making the previous commit.
[xeon-phi-kernel-module] / host / linvcons.c
CommitLineData
800f879a
AT
1/*
2 * Copyright 2010-2017 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * Disclaimer: The codes contained in these modules may be specific to
14 * the Intel Software Development Platform codenamed Knights Ferry,
15 * and the Intel product codenamed Knights Corner, and are not backward
16 * compatible with other Intel products. Additionally, Intel will NOT
17 * support the codes or instruction set in future products.
18 *
19 * Intel offers no warranty of any kind regarding the code. This code is
20 * licensed on an "AS IS" basis and Intel is not obligated to provide
21 * any support, assistance, installation, training, or other services
22 * of any kind. Intel is also not obligated to provide any updates,
23 * enhancements or extensions. Intel specifically disclaims any warranty
24 * of merchantability, non-infringement, fitness for any particular
25 * purpose, and any other warranty.
26 *
27 * Further, Intel disclaims all liability of any kind, including but
28 * not limited to liability for infringement of any proprietary rights,
29 * relating to the use of the code, even if Intel is notified of the
30 * possibility of such liability. Except as expressly stated in an Intel
31 * license agreement provided with this code and agreed upon with Intel,
32 * no license, express or implied, by estoppel or otherwise, to any
33 * intellectual property rights is granted herein.
34 */
35
36#include "micint.h"
37
38/* TODO: Improve debug messages */
39
40static int micvcons_open(struct tty_struct * tty, struct file * filp);
41static void micvcons_close(struct tty_struct * tty, struct file * filp);
42static int micvcons_write(struct tty_struct * tty, const unsigned char *buf,
43 int count);
44static int micvcons_write_room(struct tty_struct *tty);
45static void micvcons_set_termios(struct tty_struct *tty, struct ktermios * old);
46static void micvcons_timeout(unsigned long);
47static void micvcons_throttle(struct tty_struct *tty);
48static void micvcons_unthrottle(struct tty_struct *tty);
49static void micvcons_wakeup_readbuf(struct work_struct *work);
50static int micvcons_resume(struct _mic_ctx_t *mic_ctx);
51
52static struct tty_operations micvcons_tty_ops = {
53 .open = micvcons_open,
54 .close = micvcons_close,
55 .write = micvcons_write,
56 .write_room = micvcons_write_room,
57 .set_termios = micvcons_set_termios,
58 .throttle = micvcons_throttle,
59 .unthrottle = micvcons_unthrottle,
60};
61
62static struct tty_driver *micvcons_tty = NULL;
63static u16 extra_timeout = 0;
64static u8 restart_timer_flag = MICVCONS_TIMER_RESTART;
65static struct timer_list vcons_timer;
66static struct list_head timer_list_head;
67static spinlock_t timer_list_lock;
68
69int
70micvcons_create(int num_bds)
71{
72 micvcons_port_t *port;
73 bd_info_t *bd_info;
74 int bd, ret = 0;
75 char wq_name[14];
76 struct device *dev;
77
78 INIT_LIST_HEAD(&timer_list_head);
79
80 if (micvcons_tty)
81 goto exit;
82
83 micvcons_tty = alloc_tty_driver(num_bds);
84 if (!micvcons_tty) {
85 ret = -ENOMEM;
86 goto exit;
87 }
88 micvcons_tty->owner = THIS_MODULE;
89 micvcons_tty->driver_name = MICVCONS_DEVICE_NAME;
90 micvcons_tty->name = MICVCONS_DEVICE_NAME;
91 micvcons_tty->major = 0;
92#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
93 micvcons_tty->minor_num = num_bds;
94#endif
95 micvcons_tty->minor_start = 0;
96 micvcons_tty->type = TTY_DRIVER_TYPE_SERIAL;
97 micvcons_tty->subtype = SERIAL_TYPE_NORMAL;
98 micvcons_tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
99 micvcons_tty->init_termios = tty_std_termios;
100 micvcons_tty->init_termios.c_iflag = IGNCR;
101 micvcons_tty->init_termios.c_oflag = 0;
102 micvcons_tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
103 micvcons_tty->init_termios.c_lflag = 0;
104
105 tty_set_operations(micvcons_tty, &micvcons_tty_ops);
106
107 if ((ret = tty_register_driver(micvcons_tty)) != 0) {
108 printk("Failed to register vcons tty driver\n");
109 put_tty_driver(micvcons_tty);
110 micvcons_tty = NULL;
111 goto exit;
112 }
113
114 for (bd = 0; bd < num_bds; bd++) {
115 port = &mic_data.dd_ports[bd];
116 port->dp_bdinfo = mic_data.dd_bi[bd];
117
118 spin_lock_init(&port->dp_lock);
119 mutex_init (&port->dp_mutex);
120
121 bd_info = (bd_info_t *)port->dp_bdinfo;
122 bd_info->bi_port = port;
123
124#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
125 tty_port_init(&port->port);
126 dev = tty_port_register_device(&port->port, micvcons_tty, bd, NULL);
127#else
128 dev = tty_register_device(micvcons_tty, bd, NULL);
129 if (IS_ERR(dev)) {
130 printk("Failed to register vcons tty device\n");
131 micvcons_destroy(bd);
132 ret = PTR_ERR(dev);
133 goto exit;
134 }
135#endif
136 snprintf(wq_name, sizeof(wq_name), "VCONS MIC %d", bd);
137 port->dp_wq = __mic_create_singlethread_workqueue(wq_name);
138 if (!port->dp_wq) {
139 printk(KERN_ERR "%s: create_singlethread_workqueue\n",
140 __func__);
141 tty_unregister_device(micvcons_tty, bd);
142 micvcons_destroy(bd);
143 ret = -ENOMEM;
144 goto exit;
145 }
146 INIT_WORK(&port->dp_wakeup_read_buf, micvcons_wakeup_readbuf);
147 }
148 vcons_timer.function = micvcons_timeout;
149 vcons_timer.data = (unsigned long)(&timer_list_head);
150 init_timer(&vcons_timer);
151exit:
152 return ret;
153}
154
155void micvcons_destroy(int num_bds)
156{
157 int bd, ret;
158 micvcons_port_t *port;
159
160 if (!micvcons_tty)
161 return;
162 for (bd = 0; bd < num_bds; bd++) {
163 port = &mic_data.dd_ports[bd];
164 destroy_workqueue(port->dp_wq);
165 tty_unregister_device(micvcons_tty, bd);
166 }
167 ret = tty_unregister_driver(micvcons_tty);
168 put_tty_driver(micvcons_tty);
169 micvcons_tty = NULL;
170
171 if (ret)
172 printk(KERN_ERR "tty unregister_driver failed with code %d\n", ret);
173}
174
175static int
176micvcons_open(struct tty_struct * tty, struct file * filp)
177{
178 micvcons_port_t *port = &mic_data.dd_ports[tty->index];
179 int ret = 0;
180 mic_ctx_t *mic_ctx = get_per_dev_ctx(tty->index);
181
182 tty->driver_data = port;
183
184 mutex_lock(&port->dp_mutex);
185 spin_lock_bh(&port->dp_lock);
186
187 if ((filp->f_flags & O_ACCMODE) != O_RDONLY) {
188 if (port->dp_writer) {
189 ret = -EBUSY;
190 goto exit_locked;
191 }
192 port->dp_writer = filp;
193 port->dp_bytes = 0;
194 }
195
196 if ((filp->f_flags & O_ACCMODE) != O_WRONLY) {
197 if (port->dp_reader) {
198 ret = -EBUSY;
199 goto exit_locked;
200 }
201 port->dp_reader = filp;
202 port->dp_canread = 1;
203 }
204
205#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
206 tty->low_latency = 0;
207#endif
208
209 if (!port->dp_tty)
210 port->dp_tty = tty;
211 if (!port->dp_vcons)
212 port->dp_vcons = &mic_ctx->bi_vcons;
213 if (tty->count == 1) {
214 ret = micvcons_start(mic_ctx);
215 if (ret != 0)
216 goto exit_locked;
217 spin_lock(&timer_list_lock);
218 list_add_tail_rcu(&port->list_member, &timer_list_head);
219 if (list_is_singular(&timer_list_head)) {
220 restart_timer_flag = MICVCONS_TIMER_RESTART;
221 mod_timer(&vcons_timer, jiffies +
222 msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT));
223 }
224 spin_unlock(&timer_list_lock);
225 }
226
227exit_locked:
228 spin_unlock_bh(&port->dp_lock);
229 mutex_unlock(&port->dp_mutex);
230 return ret;
231}
232
233static inline void
234micvcons_del_timer_entry(micvcons_port_t *port)
235{
236 spin_lock(&timer_list_lock);
237 list_del_rcu(&port->list_member);
238 if (list_empty(&timer_list_head)) {
239 restart_timer_flag = MICVCONS_TIMER_SHUTDOWN;
240 spin_unlock(&timer_list_lock);
241 del_timer_sync(&vcons_timer);
242 } else {
243 spin_unlock(&timer_list_lock);
244 }
245 synchronize_rcu();
246}
247
248static void
249micvcons_close(struct tty_struct * tty, struct file * filp)
250{
251 micvcons_port_t *port = (micvcons_port_t *)tty->driver_data;
252
253 mutex_lock(&port->dp_mutex);
254 if (tty->count == 1) {
255 micvcons_del_timer_entry(port);
256 flush_workqueue(port->dp_wq);
257 }
258 spin_lock_bh(&port->dp_lock);
259 if (port->dp_reader == filp)
260 port->dp_reader = 0;
261
262 if (port->dp_writer == filp)
263 port->dp_writer = 0;
264
265 if (tty->count == 1)
266 port->dp_tty = 0;
267 spin_unlock_bh(&port->dp_lock);
268 mutex_unlock(&port->dp_mutex);
269}
270
271static int
272micvcons_write(struct tty_struct * tty, const unsigned char *buf, int count)
273{
274 micvcons_port_t *port = (micvcons_port_t *)tty->driver_data;
275 mic_ctx_t *mic_ctx = get_per_dev_ctx(tty->index);
276 int bytes=0, status;
277 struct vcons_buf *vcons_host_header;
278 u8 card_alive = 1;
279
280 spin_lock_bh(&port->dp_lock);
281 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
282 if (vcons_host_header->mic_magic == MIC_VCONS_SLEEPING) {
283 status = micvcons_resume(mic_ctx);
284 if (status != 0) {
285 /* If card can not wakeup, it is dead. */
286 card_alive = 0;
287 goto exit;
288 }
289 }
290 if (vcons_host_header->mic_magic != MIC_VCONS_READY)
291 goto exit;
292 bytes = micvcons_port_write(port, buf, count);
293 if (bytes) {
294 mic_send_hvc_intr(mic_ctx);
295 extra_timeout = 0;
296 }
297exit:
298 spin_unlock_bh(&port->dp_lock);
299 if (!card_alive)
300 micvcons_del_timer_entry(port);
301 return bytes;
302}
303
304static int
305micvcons_write_room(struct tty_struct *tty)
306{
307 micvcons_port_t *port = (micvcons_port_t *)tty->driver_data;
308 int room;
309
310 spin_lock_bh(&port->dp_lock);
311 if (port->dp_out)
312 room = micscif_rb_space(port->dp_out);
313 else
314 room = 0;
315 spin_unlock_bh(&port->dp_lock);
316
317 return room;
318}
319
320static void
321micvcons_set_termios(struct tty_struct *tty, struct ktermios * old)
322{
323}
324
325static int
326micvcons_readchars(micvcons_port_t *port)
327{
328 int len, ret, get_count;
329 int bytes_total = 0;
330 int bytes_read = 0;
331 char buf[64];
332
333 for (;;) {
334 len = micscif_rb_count(port->dp_in, sizeof(buf));
335 if (!len)
336 break;
337 get_count = min(len, (int)sizeof(buf));
338 ret = micscif_rb_get_next(port->dp_in, buf, get_count);
339 micscif_rb_update_read_ptr(port->dp_in);
340 if (port->dp_reader && port->dp_canread) {
341#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
342 if ((bytes_read = tty_insert_flip_string(
343 &port->port, buf, get_count)) != 0)
344 tty_flip_buffer_push(&port->port);
345#else
346 bytes_read = tty_insert_flip_string(port->dp_tty,
347 buf, get_count);
348 tty_flip_buffer_push(port->dp_tty);
349#endif
350 bytes_total += bytes_read;
351 if (bytes_read != get_count) {
352 printk(KERN_WARNING "dropping characters: \
353 bytes_read %d, get_count %d\n",
354 bytes_read, get_count);
355 break;
356 }
357 }
358 }
359 return bytes_total;
360}
361
362static int
363micvcons_initport(micvcons_port_t *port)
364{
365 struct vcons_buf *vcons_host_header;
366 struct vcons_mic_header *vcons_mic_header;
367 char *mic_hdr, *mic_buf, *host_buf;
368
369 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
370 if (!vcons_host_header) {
371 printk(KERN_ERR "vcons_host_header NULL\n");
372 return -EFAULT;
373 }
374
375 host_buf = (char *)port->dp_vcons->dc_buf_virt;
376 if (!host_buf) {
377 printk(KERN_ERR "host_buf NULL\n");
378 return -EFAULT;
379 }
380
381 if (port->dp_bdinfo->bi_ctx.bi_family == FAMILY_ABR) {
382 set_pci_aperture(&port->dp_bdinfo->bi_ctx,
383 (port->dp_bdinfo->bi_ctx.aper.len - PAGE_SIZE) >> PAGE_SHIFT,
384 vcons_host_header->i_hdr_addr & PAGE_MASK, PAGE_SIZE);
385 mic_hdr = port->dp_bdinfo->bi_ctx.aper.va +
386 port->dp_bdinfo->bi_ctx.aper.len - PAGE_SIZE;
387 mic_buf = mic_hdr + PAGE_SIZE/2;
388 } else {
389 mic_hdr = port->dp_bdinfo->bi_ctx.aper.va + vcons_host_header->i_hdr_addr;
390 mic_buf = port->dp_bdinfo->bi_ctx.aper.va + vcons_host_header->i_buf_addr;
391 }
392
393 port->dp_in = kmalloc(sizeof(struct micscif_rb), GFP_ATOMIC);
394 if (port->dp_in)
395 port->dp_out = kmalloc(sizeof(struct micscif_rb), GFP_ATOMIC);
396 else
397 return -ENOMEM;
398
399 if (port->dp_out) {
400 vcons_mic_header = (struct vcons_mic_header *)mic_hdr;
401 micscif_rb_init(port->dp_in,
402 &vcons_mic_header->o_rd,
403 &vcons_host_header->o_wr,
404 host_buf,
405 vcons_host_header->o_size);
406 micscif_rb_init(port->dp_out, &vcons_host_header->i_rd,
407 &vcons_mic_header->i_wr,
408 mic_buf,
409 vcons_host_header->i_size);
410 wmb();
411 writel(MIC_VCONS_HOST_OPEN, &vcons_mic_header->host_status);
412 } else {
413 kfree(port->dp_in);
414 return -ENOMEM;
415 }
416 return 0;
417}
418
419static int
420micvcons_readport(micvcons_port_t *port)
421{
422 int num_chars_read = 0, status;
423 static uint32_t prev_mic_magic;
424 struct vcons_buf *vcons_host_header;
425
426 if (!port || !port->dp_vcons)
427 return 0;
428
429 spin_lock_bh(&port->dp_lock);
430 if (!port->dp_tty) {
431 spin_unlock_bh(&port->dp_lock);
432 return 0;
433 }
434
435 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
436 if ((vcons_host_header->mic_magic != MIC_VCONS_READY) &&
437 (vcons_host_header->mic_magic != MIC_VCONS_SLEEPING)) {
438 if ((vcons_host_header->mic_magic == MIC_VCONS_RB_VER_ERR)
439 && (vcons_host_header->mic_magic != prev_mic_magic)) {
440 printk(KERN_ERR "Card and host ring buffer versions mismatch.");
441 printk(KERN_ERR "Card version: %d, Host version: %d \n",
442 vcons_host_header->mic_rb_ver,
443 vcons_host_header->host_rb_ver);
444 }
445 goto exit;
446 }
447 if (!port->dp_in) {
448 status = micvcons_initport(port);
449 if (status != 0) {
450 spin_unlock_bh(&port->dp_lock);
451 return status;
452 }
453 }
454
455 if (port->dp_in) {
456 if (vcons_host_header->mic_magic == MIC_VCONS_SLEEPING) {
457 /*
458 * If the card is sleeping and there is data in the
459 * buffer, schedule work in a work queue to wake-up
460 * the card and read from the buffer.
461 */
462 if (micscif_rb_count(port->dp_in, 1))
463 queue_work(port->dp_wq,
464 &port->dp_wakeup_read_buf);
465 } else {
466 num_chars_read = micvcons_readchars(port);
467 tty_wakeup(port->dp_tty);
468 }
469 }
470exit:
471 prev_mic_magic = vcons_host_header->mic_magic;
472 spin_unlock_bh(&port->dp_lock);
473 return num_chars_read;
474}
475
476static void
477micvcons_wakeup_readbuf(struct work_struct *work)
478{
479 u8 card_alive = 1;
480 int status;
481 micvcons_port_t *port;
482 struct vcons_buf *vcons_host_header;
483
484 port = container_of(work, micvcons_port_t, dp_wakeup_read_buf);
485
486 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
487 spin_lock_bh(&port->dp_lock);
488 status = micvcons_resume(get_per_dev_ctx(port->dp_tty->index));
489 if (status == 0) {
490 micvcons_readchars(port);
491 tty_wakeup(port->dp_tty);
492 } else {
493 /* If card can not wakeup, it is dead. */
494 card_alive = 0;
495 }
496 spin_unlock_bh(&port->dp_lock);
497 if (!card_alive)
498 micvcons_del_timer_entry(port);
499}
500
501static void
502micvcons_timeout(unsigned long data)
503{
504 struct list_head *timer_list_ptr = (struct list_head *)data;
505 micvcons_port_t *port;
506 u8 console_active = 0;
507 int num_chars_read = 0;
508
509 rcu_read_lock();
510 list_for_each_entry_rcu(port, timer_list_ptr, list_member) {
511 num_chars_read = micvcons_readport(port);
512 if (num_chars_read != 0)
513 console_active = 1;
514 }
515 rcu_read_unlock();
516
517 spin_lock(&timer_list_lock);
518 if (restart_timer_flag == MICVCONS_TIMER_RESTART) {
519 extra_timeout = (console_active ? 0 :
520 extra_timeout + MICVCONS_SHORT_TIMEOUT);
521 extra_timeout = min(extra_timeout, (u16)MICVCONS_MAX_TIMEOUT);
522 mod_timer(&vcons_timer, jiffies +
523 msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT+extra_timeout));
524 }
525 spin_unlock(&timer_list_lock);
526}
527
528static void
529micvcons_throttle(struct tty_struct *tty)
530{
531 micvcons_port_t *port = (micvcons_port_t *)tty->driver_data;
532 port->dp_canread = 0;
533}
534
535static void
536micvcons_unthrottle(struct tty_struct *tty)
537{
538 micvcons_port_t *port = (micvcons_port_t *)tty->driver_data;
539 port->dp_canread = 1;
540}
541
542int micvcons_start(mic_ctx_t *mic_ctx)
543{
544 struct vcons_buf *vcons_host_header;
545 int status;
546 micvcons_port_t *port = mic_ctx->bd_info->bi_port;
547
548 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
549 if (vcons_host_header->mic_magic == MIC_VCONS_SLEEPING) {
550 status = micvcons_resume(mic_ctx);
551 if (status != 0)
552 return status;
553 }
554 if (vcons_host_header->mic_magic == MIC_VCONS_READY) {
555 if (!port->dp_in) {
556 status = micvcons_initport(port);
557 if (status != 0)
558 return status;
559 }
560 }
561 return 0;
562}
563
564int micvcons_port_write(struct micvcons_port *port, const unsigned char *buf,
565 int count)
566{
567 int ret;
568 uint32_t bytes = 0;
569
570 if (port->dp_out) {
571 bytes = min(count, micscif_rb_space(port->dp_out));
572 ret = micscif_rb_write(port->dp_out, (void *)buf, bytes);
573 BUG_ON(ret);
574 port->dp_bytes += bytes;
575 micscif_rb_commit(port->dp_out);
576 }
577 return bytes;
578}
579
580/**
581 * micvcons_stop - cleans up before a node is rebooted
582 * @ mic_ctx: node to clean up
583 *
584 * Called before rebooting a node, reads remaining characters
585 * from the node's vcons output buffer, resets the input/output
586 * ring buffers so that things work when the node comes up again
587 */
588void
589micvcons_stop(mic_ctx_t *mic_ctx)
590{
591 micvcons_port_t *port;
592 struct vcons_buf *vcons_host_header;
593
594 port = mic_ctx->bd_info->bi_port;
595 micvcons_readport(port);
596 spin_lock_bh(&port->dp_lock);
597 if (port->dp_in) {
598 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
599 vcons_host_header->mic_magic = 0;
600 kfree(port->dp_in);
601 kfree(port->dp_out);
602 port->dp_in = NULL;
603 port->dp_out = NULL;
604 }
605 spin_unlock_bh(&port->dp_lock);
606}
607
608/**
609 * micvcons_resume - sets the state of a node's console to ready
610 * @ mic_ctx: node to clean up
611 *
612 * @ return: zero if successful.
613 * called before resuming a node from PC6. MUST acquire the spinlock
614 * port->dp_lock with bottom-halves disabled before calling this function.
615 */
616static int
617micvcons_resume(mic_ctx_t *mic_ctx)
618{
619 int status = 0;
620 micvcons_port_t *port;
621 struct vcons_buf *vcons_host_header;
622
623 port = mic_ctx->bd_info->bi_port;
624 vcons_host_header = mic_ctx->bi_vcons.dc_hdr_virt;
625 if (vcons_host_header->mic_magic == MIC_VCONS_SLEEPING) {
626 do {
627 vcons_host_header->mic_magic = MIC_VCONS_WAKINGUP;
628 spin_unlock_bh(&port->dp_lock);
629 status = micscif_connect_node(mic_get_scifnode_id(mic_ctx), false);
630 spin_lock_bh(&port->dp_lock);
631 } while ((status == 0) &&
632 (vcons_host_header->mic_magic == MIC_VCONS_SLEEPING));
633 if (status == 0)
634 vcons_host_header->mic_magic = MIC_VCONS_READY;
635 }
636 return status;
637}
638
639/**
640 * micvcons_pm_disconnect_node - Check if a card can be put to sleep in case
641 * there is any activity on the virtual console. If yes, it also sets the
642 * internal state of a node's console to sleeping.
643 * @ node_bitmask: bits set indicate which cards to check.
644 * Bit-1 for the first, Bit-2 for the second,...
645 * Ignore Bit-0 which indicates host.
646 * @ return: bits set indicating which cards can sleep.
647 * This is called from PM to check if a card can be put to sleep (PC-6 state).
648 * This is called when the node is disconnected from the SCIF network
649 * before putting it into the PC6 state where it should no longer
650 * receive an PCIe transactions until woken up by the host driver.
651 */
652int
653micvcons_pm_disconnect_node(uint8_t *node_bitmask, enum disconn_type type)
654{
655 int err = 0;
656 if ((type == DISCONN_TYPE_POWER_MGMT) && (node_bitmask)) {
657 int i = 0;
658 mic_ctx_t *mic_ctx;
659 micvcons_port_t *port;
660 struct vcons_buf *vcons_host_header;
661
662 for (i = 0; i <= mic_data.dd_numdevs; i++) {
663 if (!get_nodemask_bit(node_bitmask, i))
664 continue;
665
666 if (!(mic_ctx = get_per_dev_ctx(i - 1)))
667 continue;
668
669 port = mic_ctx->bd_info->bi_port;
670 micvcons_readport(port);
671 /*
672 * If this function is called when virtual console is
673 * not active, port->dp_vcons needs to be initialized.
674 */
675 if (!port->dp_vcons)
676 port->dp_vcons = &mic_ctx->bi_vcons;
677
678 vcons_host_header = (struct vcons_buf *)port->dp_vcons->dc_hdr_virt;
679 spin_lock_bh(&port->dp_lock);
680 vcons_host_header->mic_magic = MIC_VCONS_SLEEPING;
681 spin_unlock_bh(&port->dp_lock);
682 }
683 }
684
685 return err;
686}
687