/* Lock to guard over changes to global variables */ static DEFINE_SPINLOCK(sclp_con_lock); /* List of free pages that can be used for console output buffering */ static LIST_HEAD(sclp_con_pages); /* List of full struct sclp_buffer structures ready for output */ static LIST_HEAD(sclp_con_outqueue); /* Pointer to current console buffer */ staticstruct sclp_buffer *sclp_conbuf; /* Timer for delayed output of console messages */ staticstruct timer_list sclp_con_timer; /* Flag that output queue is currently running */ staticint sclp_con_queue_running;
/* Output format for console messages */ #define SCLP_CON_COLUMNS 320 #define SPACES_PER_TAB 8
/* Check if there is a pending buffer on the out queue. */
buffer = NULL; if (!list_empty(&sclp_con_outqueue))
buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, list); if (!buffer) {
sclp_con_queue_running = 0;
spin_unlock_irqrestore(&sclp_con_lock, flags); break;
}
spin_unlock_irqrestore(&sclp_con_lock, flags);
} while (sclp_emit_buffer(buffer, sclp_conbuf_callback));
}
/* * Finalize and emit first pending buffer.
*/ staticvoid sclp_conbuf_emit(void)
{ struct sclp_buffer* buffer; unsignedlong flags; int rc;
spin_lock_irqsave(&sclp_con_lock, flags); if (sclp_conbuf)
list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue);
sclp_conbuf = NULL; if (sclp_con_queue_running) goto out_unlock; if (list_empty(&sclp_con_outqueue)) goto out_unlock;
buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer,
list);
sclp_con_queue_running = 1;
spin_unlock_irqrestore(&sclp_con_lock, flags);
/* * When this routine is called from the timer then we flush the * temporary write buffer without further waiting on a final new line.
*/ staticvoid
sclp_console_timeout(struct timer_list *unused)
{
sclp_conbuf_emit();
}
/* * Drop oldest console buffer if sclp_con_drop is set
*/ staticint
sclp_console_drop_buffer(void)
{ struct list_head *list; struct sclp_buffer *buffer; void *page;
if (!sclp_console_drop) return 0;
list = sclp_con_outqueue.next; if (sclp_con_queue_running) /* The first element is in I/O */
list = list->next; if (list == &sclp_con_outqueue) return 0;
list_del(list);
buffer = list_entry(list, struct sclp_buffer, list);
page = sclp_unmake_buffer(buffer);
list_add_tail((struct list_head *) page, &sclp_con_pages); return 1;
}
/* * Writes the given message to S390 system console
*/ staticvoid
sclp_console_write(struct console *console, constchar *message, unsignedint count)
{ unsignedlong flags; void *page; int written;
if (count == 0) return;
spin_lock_irqsave(&sclp_con_lock, flags); /* * process escape characters, write message into buffer, * send buffer to SCLP
*/ do { /* make sure we have a console output buffer */ if (sclp_conbuf == NULL) { if (list_empty(&sclp_con_pages))
sclp_console_full++; while (list_empty(&sclp_con_pages)) { if (sclp_console_drop_buffer()) break;
spin_unlock_irqrestore(&sclp_con_lock, flags);
sclp_sync_wait();
spin_lock_irqsave(&sclp_con_lock, flags);
}
page = sclp_con_pages.next;
list_del((struct list_head *) page);
sclp_conbuf = sclp_make_buffer(page, SCLP_CON_COLUMNS,
SPACES_PER_TAB);
} /* try to write the string to the current output buffer */
written = sclp_write(sclp_conbuf, (constunsignedchar *)
message, count); if (written == count) break; /* * Not all characters could be written to the current * output buffer. Emit the buffer, create a new buffer * and then output the rest of the string.
*/
spin_unlock_irqrestore(&sclp_con_lock, flags);
sclp_conbuf_emit();
spin_lock_irqsave(&sclp_con_lock, flags);
message += written;
count -= written;
} while (count > 0); /* Setup timer to output current console buffer after 1/10 second */ if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 &&
!timer_pending(&sclp_con_timer)) {
mod_timer(&sclp_con_timer, jiffies + HZ / 10);
}
spin_unlock_irqrestore(&sclp_con_lock, flags);
}
/* * This panic/reboot notifier makes sure that all buffers * will be flushed to the SCLP.
*/ staticint sclp_console_notify(struct notifier_block *self, unsignedlong event, void *data)
{ /* * Perform the lock check before effectively getting the * lock on sclp_conbuf_emit() / sclp_console_sync_queue() * to prevent potential lockups in atomic context.
*/ if (spin_is_locked(&sclp_con_lock)) return NOTIFY_DONE;
sclp_conbuf_emit();
sclp_console_sync_queue();
return NOTIFY_DONE;
}
staticstruct notifier_block on_panic_nb = {
.notifier_call = sclp_console_notify,
.priority = INT_MIN + 1, /* run the callback late */
};
staticstruct notifier_block on_reboot_nb = {
.notifier_call = sclp_console_notify,
.priority = INT_MIN + 1, /* run the callback late */
};
/* * used to register the SCLP console to the kernel and to * give printk necessary information
*/ staticstruct console sclp_console =
{
.name = sclp_console_name,
.write = sclp_console_write,
.device = sclp_console_device,
.flags = CON_PRINTBUFFER,
.index = 0 /* ttyS0 */
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.