Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe2fc9ca authored by Jiri Slaby's avatar Jiri Slaby Committed by Greg Kroah-Hartman
Browse files

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: default avatarJiri Slaby <jslaby@suse.cz>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Acked-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux390@de.ibm.com
Cc: linux-s390@vger.kernel.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9f8c0b08
Loading
Loading
Loading
Loading
+39 −35
Original line number Diff line number Diff line
@@ -324,10 +324,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
			}
		} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
			/* delay small writes */
			init_timer(&raw->timer);
			raw->timer.expires = RAW3215_TIMEOUT + jiffies;
			raw->timer.data = (unsigned long) raw;
			raw->timer.function = raw3215_timeout;
			add_timer(&raw->timer);
			raw->flags |= RAW3215_TIMER_RUNS;
		}
@@ -648,6 +645,35 @@ static void raw3215_shutdown(struct raw3215_info *raw)
	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}

static struct raw3215_info *raw3215_alloc_info(void)
{
	struct raw3215_info *info;

	info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
	if (!info)
		return NULL;

	info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
	info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
	if (!info->buffer || !info->inbuf) {
		kfree(info);
		return NULL;
	}

	setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
	init_waitqueue_head(&info->empty_wait);
	tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);

	return info;
}

static void raw3215_free_info(struct raw3215_info *raw)
{
	kfree(raw->inbuf);
	kfree(raw->buffer);
	kfree(raw);
}

static int raw3215_probe (struct ccw_device *cdev)
{
	struct raw3215_info *raw;
@@ -656,11 +682,15 @@ static int raw3215_probe (struct ccw_device *cdev)
	/* Console is special. */
	if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
		return 0;
	raw = kmalloc(sizeof(struct raw3215_info) +
		      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);

	raw = raw3215_alloc_info();
	if (raw == NULL)
		return -ENOMEM;

	raw->cdev = cdev;
	dev_set_drvdata(&cdev->dev, raw);
	cdev->handler = raw3215_irq;

	spin_lock(&raw3215_device_lock);
	for (line = 0; line < NR_3215; line++) {
		if (!raw3215[line]) {
@@ -670,28 +700,10 @@ static int raw3215_probe (struct ccw_device *cdev)
	}
	spin_unlock(&raw3215_device_lock);
	if (line == NR_3215) {
		kfree(raw);
		raw3215_free_info(raw);
		return -ENODEV;
	}

	raw->cdev = cdev;
	raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
	memset(raw, 0, sizeof(struct raw3215_info));
	raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
				       GFP_KERNEL|GFP_DMA);
	if (raw->buffer == NULL) {
		spin_lock(&raw3215_device_lock);
		raw3215[line] = NULL;
		spin_unlock(&raw3215_device_lock);
		kfree(raw);
		return -ENOMEM;
	}
	init_waitqueue_head(&raw->empty_wait);
	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);

	dev_set_drvdata(&cdev->dev, raw);
	cdev->handler = raw3215_irq;

	return 0;
}

@@ -703,8 +715,7 @@ static void raw3215_remove (struct ccw_device *cdev)
	raw = dev_get_drvdata(&cdev->dev);
	if (raw) {
		dev_set_drvdata(&cdev->dev, NULL);
		kfree(raw->buffer);
		kfree(raw);
		raw3215_free_info(raw);
	}
}

@@ -897,23 +908,16 @@ static int __init con3215_init(void)
	if (IS_ERR(cdev))
		return -ENODEV;

	raw3215[0] = raw = (struct raw3215_info *)
		kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
	raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
	raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
	raw3215[0] = raw = raw3215_alloc_info();
	raw->cdev = cdev;
	dev_set_drvdata(&cdev->dev, raw);
	cdev->handler = raw3215_irq;

	raw->flags |= RAW3215_FIXED;
	init_waitqueue_head(&raw->empty_wait);
	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);

	/* Request the console irq */
	if (raw3215_startup(raw) != 0) {
		kfree(raw->inbuf);
		kfree(raw->buffer);
		kfree(raw);
		raw3215_free_info(raw);
		raw3215[0] = NULL;
		return -ENODEV;
	}