diff options
author | Oliver Neukum <oneukum@suse.de> | 2008-02-01 07:58:52 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-21 18:38:48 -0500 |
commit | 2129c4e1b4469e1f9711a54e97e8ddf8b26bb62d (patch) | |
tree | 90b58e9648ebff476c90ce7c3f28a0c832396e76 /drivers/usb/serial | |
parent | bbc5d276ec1e24d48f794dae1c4bdfc1512f65d5 (diff) |
USB: Sane memory allocation in option driver
The option driver
- violates DMA coherency rules
- allocates ~16500 bytes in one chunk
This patch splits out the buffers and uses __get_free_page() to avoid
higher order allocations.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Acked-By: Matthias Urlichs <matthias@urlichs.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/option.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5e8bf1bc1e50..a8126988efe6 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -247,10 +247,10 @@ static int debug; | |||
247 | struct option_port_private { | 247 | struct option_port_private { |
248 | /* Input endpoints and buffer for this port */ | 248 | /* Input endpoints and buffer for this port */ |
249 | struct urb *in_urbs[N_IN_URB]; | 249 | struct urb *in_urbs[N_IN_URB]; |
250 | char in_buffer[N_IN_URB][IN_BUFLEN]; | 250 | u8 *in_buffer[N_IN_URB]; |
251 | /* Output endpoints and buffer for this port */ | 251 | /* Output endpoints and buffer for this port */ |
252 | struct urb *out_urbs[N_OUT_URB]; | 252 | struct urb *out_urbs[N_OUT_URB]; |
253 | char out_buffer[N_OUT_URB][OUT_BUFLEN]; | 253 | u8 *out_buffer[N_OUT_URB]; |
254 | unsigned long out_busy; /* Bit vector of URBs in use */ | 254 | unsigned long out_busy; /* Bit vector of URBs in use */ |
255 | 255 | ||
256 | /* Settings for the port */ | 256 | /* Settings for the port */ |
@@ -737,9 +737,10 @@ static int option_send_setup(struct usb_serial_port *port) | |||
737 | 737 | ||
738 | static int option_startup(struct usb_serial *serial) | 738 | static int option_startup(struct usb_serial *serial) |
739 | { | 739 | { |
740 | int i, err; | 740 | int i, j, err; |
741 | struct usb_serial_port *port; | 741 | struct usb_serial_port *port; |
742 | struct option_port_private *portdata; | 742 | struct option_port_private *portdata; |
743 | u8 *buffer; | ||
743 | 744 | ||
744 | dbg("%s", __FUNCTION__); | 745 | dbg("%s", __FUNCTION__); |
745 | 746 | ||
@@ -753,6 +754,20 @@ static int option_startup(struct usb_serial *serial) | |||
753 | return (1); | 754 | return (1); |
754 | } | 755 | } |
755 | 756 | ||
757 | for (j = 0; j < N_IN_URB; j++) { | ||
758 | buffer = (u8 *)__get_free_page(GFP_KERNEL); | ||
759 | if (!buffer) | ||
760 | goto bail_out_error; | ||
761 | portdata->in_buffer[j] = buffer; | ||
762 | } | ||
763 | |||
764 | for (j = 0; j < N_OUT_URB; j++) { | ||
765 | buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); | ||
766 | if (!buffer) | ||
767 | goto bail_out_error2; | ||
768 | portdata->out_buffer[j] = buffer; | ||
769 | } | ||
770 | |||
756 | usb_set_serial_port_data(port, portdata); | 771 | usb_set_serial_port_data(port, portdata); |
757 | 772 | ||
758 | if (! port->interrupt_in_urb) | 773 | if (! port->interrupt_in_urb) |
@@ -766,6 +781,16 @@ static int option_startup(struct usb_serial *serial) | |||
766 | option_setup_urbs(serial); | 781 | option_setup_urbs(serial); |
767 | 782 | ||
768 | return (0); | 783 | return (0); |
784 | |||
785 | bail_out_error2: | ||
786 | for (j = 0; j < N_OUT_URB; j++) | ||
787 | kfree(portdata->out_buffer[j]); | ||
788 | bail_out_error: | ||
789 | for (j = 0; j < N_IN_URB; j++) | ||
790 | if (portdata->in_buffer[j]) | ||
791 | free_page((unsigned long)portdata->in_buffer[j]); | ||
792 | kfree(portdata); | ||
793 | return 1; | ||
769 | } | 794 | } |
770 | 795 | ||
771 | static void option_shutdown(struct usb_serial *serial) | 796 | static void option_shutdown(struct usb_serial *serial) |
@@ -794,12 +819,14 @@ static void option_shutdown(struct usb_serial *serial) | |||
794 | for (j = 0; j < N_IN_URB; j++) { | 819 | for (j = 0; j < N_IN_URB; j++) { |
795 | if (portdata->in_urbs[j]) { | 820 | if (portdata->in_urbs[j]) { |
796 | usb_free_urb(portdata->in_urbs[j]); | 821 | usb_free_urb(portdata->in_urbs[j]); |
822 | free_page((unsigned long)portdata->in_buffer[j]); | ||
797 | portdata->in_urbs[j] = NULL; | 823 | portdata->in_urbs[j] = NULL; |
798 | } | 824 | } |
799 | } | 825 | } |
800 | for (j = 0; j < N_OUT_URB; j++) { | 826 | for (j = 0; j < N_OUT_URB; j++) { |
801 | if (portdata->out_urbs[j]) { | 827 | if (portdata->out_urbs[j]) { |
802 | usb_free_urb(portdata->out_urbs[j]); | 828 | usb_free_urb(portdata->out_urbs[j]); |
829 | kfree(portdata->out_buffer[j]); | ||
803 | portdata->out_urbs[j] = NULL; | 830 | portdata->out_urbs[j] = NULL; |
804 | } | 831 | } |
805 | } | 832 | } |