aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/hvc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-02-06 13:26:25 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-03-02 00:50:25 -0500
commitc7704d352d45de47333f2d9f10aead820b49044c (patch)
treedf766e4740d3efe6a0f3f5f57b496f2b1b36fb10 /drivers/tty/hvc
parent9ff0c61d08ac4defa5ad6c65935a67643b8f4ce3 (diff)
powerpc/pseries: Reduce HVCS driver insanity
The HVCS driver, for those who don't know, is a driver for the "server" side of the IBM virtual terminal mechanism allowing Linux partitions to act as terminal servers under IBM PowerVM hypervisor. It's almost never used on the field at the moment. However, it's part of our configs, and in its current incarnation, will allocate the tty driver & major (with 64 minors) and create a kernel thread whether it's used or not, ie, whether the hypervisor did put a virtual terminal server device node in the partition or not (or whether running on a pseries machine or not even). This in turns causes modern distro's udev's to start trying to open all those 64 minors at boot, which, since they aren't linked to anything, causes the driver to spew errors in the kernel log for each of them. Not nice. This moves all that initialization to a function which is now only called the first time a terminal server virtual IO device is actually probed (that is almost never). There's still a _LOT_ of cleanup that can be done in this driver, some simple (almost all printk's statements in there shall either just be removed or in some case turned into better written & more informative messages, including using the dev_* variants etc...). This is left as an exercise for whoever actually cares about that driver. One could also try to be smart and dispose of all the tty related resources when the last instance of the VIO server device is removed (Hotplug anybody ?). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r--drivers/tty/hvc/hvcs.c74
1 files changed, 43 insertions, 31 deletions
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index bedc6c1b6fa5..7e315b7f8700 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -309,6 +309,7 @@ struct hvcs_struct {
309 309
310static LIST_HEAD(hvcs_structs); 310static LIST_HEAD(hvcs_structs);
311static DEFINE_SPINLOCK(hvcs_structs_lock); 311static DEFINE_SPINLOCK(hvcs_structs_lock);
312static DEFINE_MUTEX(hvcs_init_mutex);
312 313
313static void hvcs_unthrottle(struct tty_struct *tty); 314static void hvcs_unthrottle(struct tty_struct *tty);
314static void hvcs_throttle(struct tty_struct *tty); 315static void hvcs_throttle(struct tty_struct *tty);
@@ -340,6 +341,7 @@ static int __devinit hvcs_probe(struct vio_dev *dev,
340static int __devexit hvcs_remove(struct vio_dev *dev); 341static int __devexit hvcs_remove(struct vio_dev *dev);
341static int __init hvcs_module_init(void); 342static int __init hvcs_module_init(void);
342static void __exit hvcs_module_exit(void); 343static void __exit hvcs_module_exit(void);
344static int __devinit hvcs_initialize(void);
343 345
344#define HVCS_SCHED_READ 0x00000001 346#define HVCS_SCHED_READ 0x00000001
345#define HVCS_QUICK_READ 0x00000002 347#define HVCS_QUICK_READ 0x00000002
@@ -762,7 +764,7 @@ static int __devinit hvcs_probe(
762 const struct vio_device_id *id) 764 const struct vio_device_id *id)
763{ 765{
764 struct hvcs_struct *hvcsd; 766 struct hvcs_struct *hvcsd;
765 int index; 767 int index, rc;
766 int retval; 768 int retval;
767 769
768 if (!dev || !id) { 770 if (!dev || !id) {
@@ -770,6 +772,13 @@ static int __devinit hvcs_probe(
770 return -EPERM; 772 return -EPERM;
771 } 773 }
772 774
775 /* Make sure we are properly initialized */
776 rc = hvcs_initialize();
777 if (rc) {
778 pr_err("HVCS: Failed to initialize core driver.\n");
779 return rc;
780 }
781
773 /* early to avoid cleanup on failure */ 782 /* early to avoid cleanup on failure */
774 index = hvcs_get_index(); 783 index = hvcs_get_index();
775 if (index < 0) { 784 if (index < 0) {
@@ -1464,12 +1473,15 @@ static void hvcs_free_index_list(void)
1464 hvcs_index_count = 0; 1473 hvcs_index_count = 0;
1465} 1474}
1466 1475
1467static int __init hvcs_module_init(void) 1476static int __devinit hvcs_initialize(void)
1468{ 1477{
1469 int rc; 1478 int rc, num_ttys_to_alloc;
1470 int num_ttys_to_alloc;
1471 1479
1472 printk(KERN_INFO "Initializing %s\n", hvcs_driver_string); 1480 mutex_lock(&hvcs_init_mutex);
1481 if (hvcs_task) {
1482 mutex_unlock(&hvcs_init_mutex);
1483 return 0;
1484 }
1473 1485
1474 /* Has the user specified an overload with an insmod param? */ 1486 /* Has the user specified an overload with an insmod param? */
1475 if (hvcs_parm_num_devs <= 0 || 1487 if (hvcs_parm_num_devs <= 0 ||
@@ -1528,35 +1540,13 @@ static int __init hvcs_module_init(void)
1528 1540
1529 hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); 1541 hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
1530 if (IS_ERR(hvcs_task)) { 1542 if (IS_ERR(hvcs_task)) {
1531 printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); 1543 printk(KERN_ERR "HVCS: khvcsd creation failed.\n");
1532 rc = -EIO; 1544 rc = -EIO;
1533 goto kthread_fail; 1545 goto kthread_fail;
1534 } 1546 }
1535 1547 mutex_unlock(&hvcs_init_mutex);
1536 rc = vio_register_driver(&hvcs_vio_driver);
1537 if (rc) {
1538 printk(KERN_ERR "HVCS: can't register vio driver\n");
1539 goto vio_fail;
1540 }
1541
1542 /*
1543 * This needs to be done AFTER the vio_register_driver() call or else
1544 * the kobjects won't be initialized properly.
1545 */
1546 rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
1547 if (rc) {
1548 printk(KERN_ERR "HVCS: sysfs attr create failed\n");
1549 goto attr_fail;
1550 }
1551
1552 printk(KERN_INFO "HVCS: driver module inserted.\n");
1553
1554 return 0; 1548 return 0;
1555 1549
1556attr_fail:
1557 vio_unregister_driver(&hvcs_vio_driver);
1558vio_fail:
1559 kthread_stop(hvcs_task);
1560kthread_fail: 1550kthread_fail:
1561 kfree(hvcs_pi_buff); 1551 kfree(hvcs_pi_buff);
1562buff_alloc_fail: 1552buff_alloc_fail:
@@ -1566,15 +1556,39 @@ register_fail:
1566index_fail: 1556index_fail:
1567 put_tty_driver(hvcs_tty_driver); 1557 put_tty_driver(hvcs_tty_driver);
1568 hvcs_tty_driver = NULL; 1558 hvcs_tty_driver = NULL;
1559 mutex_unlock(&hvcs_init_mutex);
1569 return rc; 1560 return rc;
1570} 1561}
1571 1562
1563static int __init hvcs_module_init(void)
1564{
1565 int rc = vio_register_driver(&hvcs_vio_driver);
1566 if (rc) {
1567 printk(KERN_ERR "HVCS: can't register vio driver\n");
1568 return rc;
1569 }
1570
1571 pr_info("HVCS: Driver registered.\n");
1572
1573 /* This needs to be done AFTER the vio_register_driver() call or else
1574 * the kobjects won't be initialized properly.
1575 */
1576 rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
1577 if (rc)
1578 pr_warning(KERN_ERR "HVCS: Failed to create rescan file (err %d)\n", rc);
1579
1580 return 0;
1581}
1582
1572static void __exit hvcs_module_exit(void) 1583static void __exit hvcs_module_exit(void)
1573{ 1584{
1574 /* 1585 /*
1575 * This driver receives hvcs_remove callbacks for each device upon 1586 * This driver receives hvcs_remove callbacks for each device upon
1576 * module removal. 1587 * module removal.
1577 */ 1588 */
1589 vio_unregister_driver(&hvcs_vio_driver);
1590 if (!hvcs_task)
1591 return;
1578 1592
1579 /* 1593 /*
1580 * This synchronous operation will wake the khvcsd kthread if it is 1594 * This synchronous operation will wake the khvcsd kthread if it is
@@ -1589,8 +1603,6 @@ static void __exit hvcs_module_exit(void)
1589 1603
1590 driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); 1604 driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
1591 1605
1592 vio_unregister_driver(&hvcs_vio_driver);
1593
1594 tty_unregister_driver(hvcs_tty_driver); 1606 tty_unregister_driver(hvcs_tty_driver);
1595 1607
1596 hvcs_free_index_list(); 1608 hvcs_free_index_list();