Delay creation of khcvd thread

This changes hvc_init() to be called only when someone actually uses the
hvc_console driver.  Dave Jones complained when profiling bootup.

hvc_console used to only be for Power aka pSeries: now lguest and Xen both
want it built-in in case the kernel is a guest under one of those, even
though usually it will be a native boot.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Rusty Russell 2007-10-16 23:30:13 -07:00 committed by Linus Torvalds
parent fd5eea4214
commit 3e6c6f630a
2 changed files with 42 additions and 18 deletions

View File

@ -585,8 +585,8 @@ config TIPAR
config HVC_DRIVER
bool
help
Users of pSeries machines that want to utilize the hvc console front-end
module for their backend console driver should select this option.
Generic "hypervisor virtual console" infrastructure for various
hypervisors (pSeries, Xen, lguest).
It will automatically be selected if one of the back-end console drivers
is selected.

View File

@ -69,6 +69,8 @@ static struct task_struct *hvc_task;
/* Picks up late kicks after list walk but before schedule() */
static int hvc_kicked;
static int hvc_init(void);
#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
#endif
@ -754,6 +756,13 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
struct hvc_struct *hp;
int i;
/* We wait until a driver actually comes along */
if (!hvc_driver) {
int err = hvc_init();
if (err)
return ERR_PTR(err);
}
hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
GFP_KERNEL);
if (!hp)
@ -829,16 +838,18 @@ int __devexit hvc_remove(struct hvc_struct *hp)
return 0;
}
/* Driver initialization. Follow console initialization. This is where the TTY
* interfaces start to become available. */
static int __init hvc_init(void)
/* Driver initialization: called as soon as someone uses hvc_alloc(). */
static int hvc_init(void)
{
struct tty_driver *drv;
int err;
/* We need more than hvc_count adapters due to hotplug additions. */
drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
if (!drv)
return -ENOMEM;
if (!drv) {
err = -ENOMEM;
goto out;
}
drv->owner = THIS_MODULE;
drv->driver_name = "hvc";
@ -854,30 +865,43 @@ static int __init hvc_init(void)
* added later. */
hvc_task = kthread_run(khvcd, NULL, "khvcd");
if (IS_ERR(hvc_task)) {
panic("Couldn't create kthread for console.\n");
put_tty_driver(drv);
return -EIO;
printk(KERN_ERR "Couldn't create kthread for console.\n");
err = PTR_ERR(hvc_task);
goto put_tty;
}
if (tty_register_driver(drv))
panic("Couldn't register hvc console driver\n");
err = tty_register_driver(drv);
if (err) {
printk(KERN_ERR "Couldn't register hvc console driver\n");
goto stop_thread;
}
/* FIXME: This mb() seems completely random. Remove it. */
mb();
hvc_driver = drv;
return 0;
put_tty:
put_tty_driver(hvc_driver);
stop_thread:
kthread_stop(hvc_task);
hvc_task = NULL;
out:
return err;
}
module_init(hvc_init);
/* This isn't particularly necessary due to this being a console driver
* but it is nice to be thorough.
*/
static void __exit hvc_exit(void)
{
kthread_stop(hvc_task);
if (hvc_driver) {
kthread_stop(hvc_task);
tty_unregister_driver(hvc_driver);
/* return tty_struct instances allocated in hvc_init(). */
put_tty_driver(hvc_driver);
unregister_console(&hvc_con_driver);
tty_unregister_driver(hvc_driver);
/* return tty_struct instances allocated in hvc_init(). */
put_tty_driver(hvc_driver);
unregister_console(&hvc_con_driver);
}
}
module_exit(hvc_exit);