diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-08-13 07:27:37 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-14 16:51:02 -0400 |
commit | bad41a5bf1775cdf6026d5a1b233bdc4853f27ca (patch) | |
tree | f3e75a02337bad3cd38ddfbf8d1fa37290dd9cb7 | |
parent | 2fcd1c9b327c23414a5215a0fa53df9d75871a46 (diff) |
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: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/serial/keyspan.c | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 3d2ce56e1009..e731bbc166a0 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
@@ -50,6 +50,10 @@ | |||
50 | #define INSTAT_BUFLEN 32 | 50 | #define INSTAT_BUFLEN 32 |
51 | #define GLOCONT_BUFLEN 64 | 51 | #define GLOCONT_BUFLEN 64 |
52 | #define INDAT49W_BUFLEN 512 | 52 | #define INDAT49W_BUFLEN 512 |
53 | #define IN_BUFLEN 64 | ||
54 | #define OUT_BUFLEN 64 | ||
55 | #define INACK_BUFLEN 1 | ||
56 | #define OUTCONT_BUFLEN 64 | ||
53 | 57 | ||
54 | /* Per device and per port private data */ | 58 | /* Per device and per port private data */ |
55 | struct keyspan_serial_private { | 59 | struct keyspan_serial_private { |
@@ -81,18 +85,18 @@ struct keyspan_port_private { | |||
81 | 85 | ||
82 | /* Input endpoints and buffer for this port */ | 86 | /* Input endpoints and buffer for this port */ |
83 | struct urb *in_urbs[2]; | 87 | struct urb *in_urbs[2]; |
84 | char in_buffer[2][64]; | 88 | char *in_buffer[2]; |
85 | /* Output endpoints and buffer for this port */ | 89 | /* Output endpoints and buffer for this port */ |
86 | struct urb *out_urbs[2]; | 90 | struct urb *out_urbs[2]; |
87 | char out_buffer[2][64]; | 91 | char *out_buffer[2]; |
88 | 92 | ||
89 | /* Input ack endpoint */ | 93 | /* Input ack endpoint */ |
90 | struct urb *inack_urb; | 94 | struct urb *inack_urb; |
91 | char inack_buffer[1]; | 95 | char *inack_buffer; |
92 | 96 | ||
93 | /* Output control endpoint */ | 97 | /* Output control endpoint */ |
94 | struct urb *outcont_urb; | 98 | struct urb *outcont_urb; |
95 | char outcont_buffer[64]; | 99 | char *outcont_buffer; |
96 | 100 | ||
97 | /* Settings for the port */ | 101 | /* Settings for the port */ |
98 | int baud; | 102 | int baud; |
@@ -2406,6 +2410,26 @@ static int keyspan_port_probe(struct usb_serial_port *port) | |||
2406 | if (!p_priv) | 2410 | if (!p_priv) |
2407 | return -ENOMEM; | 2411 | return -ENOMEM; |
2408 | 2412 | ||
2413 | for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) { | ||
2414 | p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL); | ||
2415 | if (!p_priv->in_buffer[i]) | ||
2416 | goto err_in_buffer; | ||
2417 | } | ||
2418 | |||
2419 | for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) { | ||
2420 | p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL); | ||
2421 | if (!p_priv->out_buffer[i]) | ||
2422 | goto err_out_buffer; | ||
2423 | } | ||
2424 | |||
2425 | p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL); | ||
2426 | if (!p_priv->inack_buffer) | ||
2427 | goto err_inack_buffer; | ||
2428 | |||
2429 | p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL); | ||
2430 | if (!p_priv->outcont_buffer) | ||
2431 | goto err_outcont_buffer; | ||
2432 | |||
2409 | p_priv->device_details = d_details; | 2433 | p_priv->device_details = d_details; |
2410 | 2434 | ||
2411 | /* Setup values for the various callback routines */ | 2435 | /* Setup values for the various callback routines */ |
@@ -2418,7 +2442,8 @@ static int keyspan_port_probe(struct usb_serial_port *port) | |||
2418 | for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) { | 2442 | for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) { |
2419 | p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp, | 2443 | p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp, |
2420 | USB_DIR_IN, port, | 2444 | USB_DIR_IN, port, |
2421 | p_priv->in_buffer[i], 64, | 2445 | p_priv->in_buffer[i], |
2446 | IN_BUFLEN, | ||
2422 | cback->indat_callback); | 2447 | cback->indat_callback); |
2423 | } | 2448 | } |
2424 | /* outdat endpoints also have flip */ | 2449 | /* outdat endpoints also have flip */ |
@@ -2426,25 +2451,41 @@ static int keyspan_port_probe(struct usb_serial_port *port) | |||
2426 | for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) { | 2451 | for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) { |
2427 | p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp, | 2452 | p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp, |
2428 | USB_DIR_OUT, port, | 2453 | USB_DIR_OUT, port, |
2429 | p_priv->out_buffer[i], 64, | 2454 | p_priv->out_buffer[i], |
2455 | OUT_BUFLEN, | ||
2430 | cback->outdat_callback); | 2456 | cback->outdat_callback); |
2431 | } | 2457 | } |
2432 | /* inack endpoint */ | 2458 | /* inack endpoint */ |
2433 | p_priv->inack_urb = keyspan_setup_urb(serial, | 2459 | p_priv->inack_urb = keyspan_setup_urb(serial, |
2434 | d_details->inack_endpoints[port_num], | 2460 | d_details->inack_endpoints[port_num], |
2435 | USB_DIR_IN, port, | 2461 | USB_DIR_IN, port, |
2436 | p_priv->inack_buffer, 1, | 2462 | p_priv->inack_buffer, |
2463 | INACK_BUFLEN, | ||
2437 | cback->inack_callback); | 2464 | cback->inack_callback); |
2438 | /* outcont endpoint */ | 2465 | /* outcont endpoint */ |
2439 | p_priv->outcont_urb = keyspan_setup_urb(serial, | 2466 | p_priv->outcont_urb = keyspan_setup_urb(serial, |
2440 | d_details->outcont_endpoints[port_num], | 2467 | d_details->outcont_endpoints[port_num], |
2441 | USB_DIR_OUT, port, | 2468 | USB_DIR_OUT, port, |
2442 | p_priv->outcont_buffer, 64, | 2469 | p_priv->outcont_buffer, |
2470 | OUTCONT_BUFLEN, | ||
2443 | cback->outcont_callback); | 2471 | cback->outcont_callback); |
2444 | 2472 | ||
2445 | usb_set_serial_port_data(port, p_priv); | 2473 | usb_set_serial_port_data(port, p_priv); |
2446 | 2474 | ||
2447 | return 0; | 2475 | return 0; |
2476 | |||
2477 | err_outcont_buffer: | ||
2478 | kfree(p_priv->inack_buffer); | ||
2479 | err_inack_buffer: | ||
2480 | for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) | ||
2481 | kfree(p_priv->out_buffer[i]); | ||
2482 | err_out_buffer: | ||
2483 | for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) | ||
2484 | kfree(p_priv->in_buffer[i]); | ||
2485 | err_in_buffer: | ||
2486 | kfree(p_priv); | ||
2487 | |||
2488 | return -ENOMEM; | ||
2448 | } | 2489 | } |
2449 | 2490 | ||
2450 | static int keyspan_port_remove(struct usb_serial_port *port) | 2491 | static int keyspan_port_remove(struct usb_serial_port *port) |
@@ -2468,6 +2509,13 @@ static int keyspan_port_remove(struct usb_serial_port *port) | |||
2468 | usb_free_urb(p_priv->out_urbs[i]); | 2509 | usb_free_urb(p_priv->out_urbs[i]); |
2469 | } | 2510 | } |
2470 | 2511 | ||
2512 | kfree(p_priv->outcont_buffer); | ||
2513 | kfree(p_priv->inack_buffer); | ||
2514 | for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) | ||
2515 | kfree(p_priv->out_buffer[i]); | ||
2516 | for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) | ||
2517 | kfree(p_priv->in_buffer[i]); | ||
2518 | |||
2471 | kfree(p_priv); | 2519 | kfree(p_priv); |
2472 | 2520 | ||
2473 | return 0; | 2521 | return 0; |