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

Commit bad41a5b authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

USB: keyspan: fix port DMA-buffer allocations



Make sure port DMA-buffers are allocated separately from containing
structure to prevent potential memory corruption on non-cache-coherent
systems.

Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2fcd1c9b
Loading
Loading
Loading
Loading
+56 −8
Original line number Diff line number Diff line
@@ -50,6 +50,10 @@
#define INSTAT_BUFLEN	32
#define GLOCONT_BUFLEN	64
#define INDAT49W_BUFLEN	512
#define IN_BUFLEN	64
#define OUT_BUFLEN	64
#define INACK_BUFLEN	1
#define OUTCONT_BUFLEN	64

	/* Per device and per port private data */
struct keyspan_serial_private {
@@ -81,18 +85,18 @@ struct keyspan_port_private {

	/* Input endpoints and buffer for this port */
	struct urb	*in_urbs[2];
	char		in_buffer[2][64];
	char		*in_buffer[2];
	/* Output endpoints and buffer for this port */
	struct urb	*out_urbs[2];
	char		out_buffer[2][64];
	char		*out_buffer[2];

	/* Input ack endpoint */
	struct urb	*inack_urb;
	char		inack_buffer[1];
	char		*inack_buffer;

	/* Output control endpoint */
	struct urb	*outcont_urb;
	char		outcont_buffer[64];
	char		*outcont_buffer;

	/* Settings for the port */
	int		baud;
@@ -2406,6 +2410,26 @@ static int keyspan_port_probe(struct usb_serial_port *port)
	if (!p_priv)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
		if (!p_priv->in_buffer[i])
			goto err_in_buffer;
	}

	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
		if (!p_priv->out_buffer[i])
			goto err_out_buffer;
	}

	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
	if (!p_priv->inack_buffer)
		goto err_inack_buffer;

	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
	if (!p_priv->outcont_buffer)
		goto err_outcont_buffer;

	p_priv->device_details = d_details;

	/* Setup values for the various callback routines */
@@ -2418,7 +2442,8 @@ static int keyspan_port_probe(struct usb_serial_port *port)
	for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
		p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
						USB_DIR_IN, port,
						p_priv->in_buffer[i], 64,
						p_priv->in_buffer[i],
						IN_BUFLEN,
						cback->indat_callback);
	}
	/* outdat endpoints also have flip */
@@ -2426,25 +2451,41 @@ static int keyspan_port_probe(struct usb_serial_port *port)
	for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
		p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
						USB_DIR_OUT, port,
						p_priv->out_buffer[i], 64,
						p_priv->out_buffer[i],
						OUT_BUFLEN,
						cback->outdat_callback);
	}
	/* inack endpoint */
	p_priv->inack_urb = keyspan_setup_urb(serial,
					d_details->inack_endpoints[port_num],
					USB_DIR_IN, port,
					p_priv->inack_buffer, 1,
					p_priv->inack_buffer,
					INACK_BUFLEN,
					cback->inack_callback);
	/* outcont endpoint */
	p_priv->outcont_urb = keyspan_setup_urb(serial,
					d_details->outcont_endpoints[port_num],
					USB_DIR_OUT, port,
					p_priv->outcont_buffer, 64,
					p_priv->outcont_buffer,
					OUTCONT_BUFLEN,
					 cback->outcont_callback);

	usb_set_serial_port_data(port, p_priv);

	return 0;

err_outcont_buffer:
	kfree(p_priv->inack_buffer);
err_inack_buffer:
	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
		kfree(p_priv->out_buffer[i]);
err_out_buffer:
	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
		kfree(p_priv->in_buffer[i]);
err_in_buffer:
	kfree(p_priv);

	return -ENOMEM;
}

static int keyspan_port_remove(struct usb_serial_port *port)
@@ -2468,6 +2509,13 @@ static int keyspan_port_remove(struct usb_serial_port *port)
		usb_free_urb(p_priv->out_urbs[i]);
	}

	kfree(p_priv->outcont_buffer);
	kfree(p_priv->inack_buffer);
	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
		kfree(p_priv->out_buffer[i]);
	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
		kfree(p_priv->in_buffer[i]);

	kfree(p_priv);

	return 0;