diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-17 02:30:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:43:00 -0400 |
commit | 3e6c6f630a5282df8f3393a59f10eb9c56536d23 (patch) | |
tree | 744539fb9d35425784149e2f015589d593e2b968 /drivers/char/hvc_console.c | |
parent | fd5eea4214f72bd7ac77c1c5346a9c096319131a (diff) |
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>
Diffstat (limited to 'drivers/char/hvc_console.c')
-rw-r--r-- | drivers/char/hvc_console.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 83c1151ec7a2..8252f8668538 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -69,6 +69,8 @@ static struct task_struct *hvc_task; | |||
69 | /* Picks up late kicks after list walk but before schedule() */ | 69 | /* Picks up late kicks after list walk but before schedule() */ |
70 | static int hvc_kicked; | 70 | static int hvc_kicked; |
71 | 71 | ||
72 | static int hvc_init(void); | ||
73 | |||
72 | #ifdef CONFIG_MAGIC_SYSRQ | 74 | #ifdef CONFIG_MAGIC_SYSRQ |
73 | static int sysrq_pressed; | 75 | static int sysrq_pressed; |
74 | #endif | 76 | #endif |
@@ -754,6 +756,13 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, | |||
754 | struct hvc_struct *hp; | 756 | struct hvc_struct *hp; |
755 | int i; | 757 | int i; |
756 | 758 | ||
759 | /* We wait until a driver actually comes along */ | ||
760 | if (!hvc_driver) { | ||
761 | int err = hvc_init(); | ||
762 | if (err) | ||
763 | return ERR_PTR(err); | ||
764 | } | ||
765 | |||
757 | hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, | 766 | hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, |
758 | GFP_KERNEL); | 767 | GFP_KERNEL); |
759 | if (!hp) | 768 | if (!hp) |
@@ -829,16 +838,18 @@ int __devexit hvc_remove(struct hvc_struct *hp) | |||
829 | return 0; | 838 | return 0; |
830 | } | 839 | } |
831 | 840 | ||
832 | /* Driver initialization. Follow console initialization. This is where the TTY | 841 | /* Driver initialization: called as soon as someone uses hvc_alloc(). */ |
833 | * interfaces start to become available. */ | 842 | static int hvc_init(void) |
834 | static int __init hvc_init(void) | ||
835 | { | 843 | { |
836 | struct tty_driver *drv; | 844 | struct tty_driver *drv; |
845 | int err; | ||
837 | 846 | ||
838 | /* We need more than hvc_count adapters due to hotplug additions. */ | 847 | /* We need more than hvc_count adapters due to hotplug additions. */ |
839 | drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); | 848 | drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); |
840 | if (!drv) | 849 | if (!drv) { |
841 | return -ENOMEM; | 850 | err = -ENOMEM; |
851 | goto out; | ||
852 | } | ||
842 | 853 | ||
843 | drv->owner = THIS_MODULE; | 854 | drv->owner = THIS_MODULE; |
844 | drv->driver_name = "hvc"; | 855 | drv->driver_name = "hvc"; |
@@ -854,30 +865,43 @@ static int __init hvc_init(void) | |||
854 | * added later. */ | 865 | * added later. */ |
855 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); | 866 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); |
856 | if (IS_ERR(hvc_task)) { | 867 | if (IS_ERR(hvc_task)) { |
857 | panic("Couldn't create kthread for console.\n"); | 868 | printk(KERN_ERR "Couldn't create kthread for console.\n"); |
858 | put_tty_driver(drv); | 869 | err = PTR_ERR(hvc_task); |
859 | return -EIO; | 870 | goto put_tty; |
860 | } | 871 | } |
861 | 872 | ||
862 | if (tty_register_driver(drv)) | 873 | err = tty_register_driver(drv); |
863 | panic("Couldn't register hvc console driver\n"); | 874 | if (err) { |
875 | printk(KERN_ERR "Couldn't register hvc console driver\n"); | ||
876 | goto stop_thread; | ||
877 | } | ||
864 | 878 | ||
879 | /* FIXME: This mb() seems completely random. Remove it. */ | ||
865 | mb(); | 880 | mb(); |
866 | hvc_driver = drv; | 881 | hvc_driver = drv; |
867 | return 0; | 882 | return 0; |
883 | |||
884 | put_tty: | ||
885 | put_tty_driver(hvc_driver); | ||
886 | stop_thread: | ||
887 | kthread_stop(hvc_task); | ||
888 | hvc_task = NULL; | ||
889 | out: | ||
890 | return err; | ||
868 | } | 891 | } |
869 | module_init(hvc_init); | ||
870 | 892 | ||
871 | /* This isn't particularly necessary due to this being a console driver | 893 | /* This isn't particularly necessary due to this being a console driver |
872 | * but it is nice to be thorough. | 894 | * but it is nice to be thorough. |
873 | */ | 895 | */ |
874 | static void __exit hvc_exit(void) | 896 | static void __exit hvc_exit(void) |
875 | { | 897 | { |
876 | kthread_stop(hvc_task); | 898 | if (hvc_driver) { |
899 | kthread_stop(hvc_task); | ||
877 | 900 | ||
878 | tty_unregister_driver(hvc_driver); | 901 | tty_unregister_driver(hvc_driver); |
879 | /* return tty_struct instances allocated in hvc_init(). */ | 902 | /* return tty_struct instances allocated in hvc_init(). */ |
880 | put_tty_driver(hvc_driver); | 903 | put_tty_driver(hvc_driver); |
881 | unregister_console(&hvc_con_driver); | 904 | unregister_console(&hvc_con_driver); |
905 | } | ||
882 | } | 906 | } |
883 | module_exit(hvc_exit); | 907 | module_exit(hvc_exit); |