diff options
author | Jiri Slaby <jslaby@suse.cz> | 2012-04-02 07:54:08 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-09 14:27:28 -0400 |
commit | fe2fc9ca5d7e5d9144a4039d89a6f1f8967d9263 (patch) | |
tree | c1e74648f89313c92e86ac2943dabefc5c4d0e05 /drivers/s390 | |
parent | 9f8c0b081daff1dbf9ca889560bf25aef0a75207 (diff) |
TTY: con3215, centralize allocation
There are two copies of allocations of device information. One of them
is totally broken. See:
raw->cdev = cdev;
raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
memset(raw, 0, sizeof(struct raw3215_info));
It suggests that this path was never executed. The code uses both
raw->cdev and raw->inbuf all over. And it is NULL due to the memset
here, so it would panic immediately. I believe nobody used that driver
without being a system console.
Either way, let us fix it by moving the allocations (and
initializations) to a single place. This will save us some double
initializations later too.
And while at it, initialize the timer properly -- once, at the
allocation.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux390@de.ibm.com
Cc: linux-s390@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/char/con3215.c | 74 |
1 files changed, 39 insertions, 35 deletions
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 4f9f1dcc1551..7e30f85ee3a5 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -324,10 +324,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw) | |||
324 | } | 324 | } |
325 | } else if (!(raw->flags & RAW3215_TIMER_RUNS)) { | 325 | } else if (!(raw->flags & RAW3215_TIMER_RUNS)) { |
326 | /* delay small writes */ | 326 | /* delay small writes */ |
327 | init_timer(&raw->timer); | ||
328 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | 327 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; |
329 | raw->timer.data = (unsigned long) raw; | ||
330 | raw->timer.function = raw3215_timeout; | ||
331 | add_timer(&raw->timer); | 328 | add_timer(&raw->timer); |
332 | raw->flags |= RAW3215_TIMER_RUNS; | 329 | raw->flags |= RAW3215_TIMER_RUNS; |
333 | } | 330 | } |
@@ -648,6 +645,35 @@ static void raw3215_shutdown(struct raw3215_info *raw) | |||
648 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 645 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
649 | } | 646 | } |
650 | 647 | ||
648 | static struct raw3215_info *raw3215_alloc_info(void) | ||
649 | { | ||
650 | struct raw3215_info *info; | ||
651 | |||
652 | info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); | ||
653 | if (!info) | ||
654 | return NULL; | ||
655 | |||
656 | info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); | ||
657 | info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); | ||
658 | if (!info->buffer || !info->inbuf) { | ||
659 | kfree(info); | ||
660 | return NULL; | ||
661 | } | ||
662 | |||
663 | setup_timer(&info->timer, raw3215_timeout, (unsigned long)info); | ||
664 | init_waitqueue_head(&info->empty_wait); | ||
665 | tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info); | ||
666 | |||
667 | return info; | ||
668 | } | ||
669 | |||
670 | static void raw3215_free_info(struct raw3215_info *raw) | ||
671 | { | ||
672 | kfree(raw->inbuf); | ||
673 | kfree(raw->buffer); | ||
674 | kfree(raw); | ||
675 | } | ||
676 | |||
651 | static int raw3215_probe (struct ccw_device *cdev) | 677 | static int raw3215_probe (struct ccw_device *cdev) |
652 | { | 678 | { |
653 | struct raw3215_info *raw; | 679 | struct raw3215_info *raw; |
@@ -656,11 +682,15 @@ static int raw3215_probe (struct ccw_device *cdev) | |||
656 | /* Console is special. */ | 682 | /* Console is special. */ |
657 | if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev))) | 683 | if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev))) |
658 | return 0; | 684 | return 0; |
659 | raw = kmalloc(sizeof(struct raw3215_info) + | 685 | |
660 | RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); | 686 | raw = raw3215_alloc_info(); |
661 | if (raw == NULL) | 687 | if (raw == NULL) |
662 | return -ENOMEM; | 688 | return -ENOMEM; |
663 | 689 | ||
690 | raw->cdev = cdev; | ||
691 | dev_set_drvdata(&cdev->dev, raw); | ||
692 | cdev->handler = raw3215_irq; | ||
693 | |||
664 | spin_lock(&raw3215_device_lock); | 694 | spin_lock(&raw3215_device_lock); |
665 | for (line = 0; line < NR_3215; line++) { | 695 | for (line = 0; line < NR_3215; line++) { |
666 | if (!raw3215[line]) { | 696 | if (!raw3215[line]) { |
@@ -670,28 +700,10 @@ static int raw3215_probe (struct ccw_device *cdev) | |||
670 | } | 700 | } |
671 | spin_unlock(&raw3215_device_lock); | 701 | spin_unlock(&raw3215_device_lock); |
672 | if (line == NR_3215) { | 702 | if (line == NR_3215) { |
673 | kfree(raw); | 703 | raw3215_free_info(raw); |
674 | return -ENODEV; | 704 | return -ENODEV; |
675 | } | 705 | } |
676 | 706 | ||
677 | raw->cdev = cdev; | ||
678 | raw->inbuf = (char *) raw + sizeof(struct raw3215_info); | ||
679 | memset(raw, 0, sizeof(struct raw3215_info)); | ||
680 | raw->buffer = kmalloc(RAW3215_BUFFER_SIZE, | ||
681 | GFP_KERNEL|GFP_DMA); | ||
682 | if (raw->buffer == NULL) { | ||
683 | spin_lock(&raw3215_device_lock); | ||
684 | raw3215[line] = NULL; | ||
685 | spin_unlock(&raw3215_device_lock); | ||
686 | kfree(raw); | ||
687 | return -ENOMEM; | ||
688 | } | ||
689 | init_waitqueue_head(&raw->empty_wait); | ||
690 | tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw); | ||
691 | |||
692 | dev_set_drvdata(&cdev->dev, raw); | ||
693 | cdev->handler = raw3215_irq; | ||
694 | |||
695 | return 0; | 707 | return 0; |
696 | } | 708 | } |
697 | 709 | ||
@@ -703,8 +715,7 @@ static void raw3215_remove (struct ccw_device *cdev) | |||
703 | raw = dev_get_drvdata(&cdev->dev); | 715 | raw = dev_get_drvdata(&cdev->dev); |
704 | if (raw) { | 716 | if (raw) { |
705 | dev_set_drvdata(&cdev->dev, NULL); | 717 | dev_set_drvdata(&cdev->dev, NULL); |
706 | kfree(raw->buffer); | 718 | raw3215_free_info(raw); |
707 | kfree(raw); | ||
708 | } | 719 | } |
709 | } | 720 | } |
710 | 721 | ||
@@ -897,23 +908,16 @@ static int __init con3215_init(void) | |||
897 | if (IS_ERR(cdev)) | 908 | if (IS_ERR(cdev)) |
898 | return -ENODEV; | 909 | return -ENODEV; |
899 | 910 | ||
900 | raw3215[0] = raw = (struct raw3215_info *) | 911 | raw3215[0] = raw = raw3215_alloc_info(); |
901 | kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); | ||
902 | raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); | ||
903 | raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); | ||
904 | raw->cdev = cdev; | 912 | raw->cdev = cdev; |
905 | dev_set_drvdata(&cdev->dev, raw); | 913 | dev_set_drvdata(&cdev->dev, raw); |
906 | cdev->handler = raw3215_irq; | 914 | cdev->handler = raw3215_irq; |
907 | 915 | ||
908 | raw->flags |= RAW3215_FIXED; | 916 | raw->flags |= RAW3215_FIXED; |
909 | init_waitqueue_head(&raw->empty_wait); | ||
910 | tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw); | ||
911 | 917 | ||
912 | /* Request the console irq */ | 918 | /* Request the console irq */ |
913 | if (raw3215_startup(raw) != 0) { | 919 | if (raw3215_startup(raw) != 0) { |
914 | kfree(raw->inbuf); | 920 | raw3215_free_info(raw); |
915 | kfree(raw->buffer); | ||
916 | kfree(raw); | ||
917 | raw3215[0] = NULL; | 921 | raw3215[0] = NULL; |
918 | return -ENODEV; | 922 | return -ENODEV; |
919 | } | 923 | } |