diff options
-rw-r--r-- | drivers/usb/serial/generic.c | 132 | ||||
-rw-r--r-- | include/linux/usb/serial.h | 9 |
2 files changed, 62 insertions, 79 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index be52c748bccb..ad4823bbfa19 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -25,6 +25,8 @@ | |||
25 | 25 | ||
26 | static int debug; | 26 | static int debug; |
27 | 27 | ||
28 | #define MAX_TX_URBS 40 | ||
29 | |||
28 | #ifdef CONFIG_USB_SERIAL_GENERIC | 30 | #ifdef CONFIG_USB_SERIAL_GENERIC |
29 | 31 | ||
30 | static int generic_probe(struct usb_interface *interface, | 32 | static int generic_probe(struct usb_interface *interface, |
@@ -172,78 +174,63 @@ static int usb_serial_multi_urb_write(struct tty_struct *tty, | |||
172 | struct urb *urb; | 174 | struct urb *urb; |
173 | unsigned char *buffer; | 175 | unsigned char *buffer; |
174 | int status; | 176 | int status; |
175 | int towrite; | ||
176 | int bwrite = 0; | ||
177 | |||
178 | dbg("%s - port %d", __func__, port->number); | ||
179 | |||
180 | if (count == 0) | ||
181 | dbg("%s - write request of 0 bytes", __func__); | ||
182 | 177 | ||
183 | while (count > 0) { | 178 | spin_lock_irqsave(&port->lock, flags); |
184 | towrite = (count > port->bulk_out_size) ? | 179 | if (port->tx_urbs == MAX_TX_URBS) { |
185 | port->bulk_out_size : count; | ||
186 | spin_lock_irqsave(&port->lock, flags); | ||
187 | if (port->urbs_in_flight > | ||
188 | port->serial->type->max_in_flight_urbs) { | ||
189 | spin_unlock_irqrestore(&port->lock, flags); | ||
190 | dbg("%s - write limit hit", __func__); | ||
191 | return bwrite; | ||
192 | } | ||
193 | port->tx_bytes_flight += towrite; | ||
194 | port->urbs_in_flight++; | ||
195 | spin_unlock_irqrestore(&port->lock, flags); | 180 | spin_unlock_irqrestore(&port->lock, flags); |
181 | dbg("%s - write limit hit", __func__); | ||
182 | return 0; | ||
183 | } | ||
184 | port->tx_urbs++; | ||
185 | spin_unlock_irqrestore(&port->lock, flags); | ||
196 | 186 | ||
197 | buffer = kmalloc(towrite, GFP_ATOMIC); | 187 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
198 | if (!buffer) { | 188 | if (!urb) { |
199 | dev_err(&port->dev, | 189 | dev_err(&port->dev, "%s - no free urbs available\n", __func__); |
200 | "%s ran out of kernel memory for urb ...\n", __func__); | 190 | status = -ENOMEM; |
201 | goto error_no_buffer; | 191 | goto err_urb; |
202 | } | 192 | } |
203 | 193 | ||
204 | urb = usb_alloc_urb(0, GFP_ATOMIC); | 194 | count = min_t(int, count, PAGE_SIZE); |
205 | if (!urb) { | 195 | buffer = kmalloc(count, GFP_ATOMIC); |
206 | dev_err(&port->dev, "%s - no more free urbs\n", | 196 | if (!buffer) { |
197 | dev_err(&port->dev, "%s - could not allocate buffer\n", | ||
207 | __func__); | 198 | __func__); |
208 | goto error_no_urb; | 199 | status = -ENOMEM; |
209 | } | 200 | goto err_buf; |
201 | } | ||
210 | 202 | ||
211 | /* Copy data */ | 203 | memcpy(buffer, buf, count); |
212 | memcpy(buffer, buf + bwrite, towrite); | 204 | usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); |
213 | usb_serial_debug_data(debug, &port->dev, __func__, | 205 | usb_fill_bulk_urb(urb, port->serial->dev, |
214 | towrite, buffer); | ||
215 | /* fill the buffer and send it */ | ||
216 | usb_fill_bulk_urb(urb, port->serial->dev, | ||
217 | usb_sndbulkpipe(port->serial->dev, | 206 | usb_sndbulkpipe(port->serial->dev, |
218 | port->bulk_out_endpointAddress), | 207 | port->bulk_out_endpointAddress), |
219 | buffer, towrite, | 208 | buffer, count, |
220 | port->serial->type->write_bulk_callback, port); | 209 | port->serial->type->write_bulk_callback, port); |
221 | 210 | ||
222 | status = usb_submit_urb(urb, GFP_ATOMIC); | 211 | status = usb_submit_urb(urb, GFP_ATOMIC); |
223 | if (status) { | 212 | if (status) { |
224 | dev_err(&port->dev, "%s - error submitting urb: %d\n", | 213 | dev_err(&port->dev, "%s - error submitting urb: %d\n", |
225 | __func__, status); | 214 | __func__, status); |
226 | goto error; | 215 | goto err; |
227 | } | ||
228 | |||
229 | /* This urb is the responsibility of the host driver now */ | ||
230 | usb_free_urb(urb); | ||
231 | dbg("%s write: %d", __func__, towrite); | ||
232 | count -= towrite; | ||
233 | bwrite += towrite; | ||
234 | } | 216 | } |
235 | return bwrite; | 217 | spin_lock_irqsave(&port->lock, flags); |
218 | port->tx_bytes += urb->transfer_buffer_length; | ||
219 | spin_unlock_irqrestore(&port->lock, flags); | ||
236 | 220 | ||
237 | error: | ||
238 | usb_free_urb(urb); | 221 | usb_free_urb(urb); |
239 | error_no_urb: | 222 | |
223 | return count; | ||
224 | err: | ||
240 | kfree(buffer); | 225 | kfree(buffer); |
241 | error_no_buffer: | 226 | err_buf: |
227 | usb_free_urb(urb); | ||
228 | err_urb: | ||
242 | spin_lock_irqsave(&port->lock, flags); | 229 | spin_lock_irqsave(&port->lock, flags); |
243 | port->urbs_in_flight--; | 230 | port->tx_urbs--; |
244 | port->tx_bytes_flight -= towrite; | ||
245 | spin_unlock_irqrestore(&port->lock, flags); | 231 | spin_unlock_irqrestore(&port->lock, flags); |
246 | return bwrite; | 232 | |
233 | return status; | ||
247 | } | 234 | } |
248 | 235 | ||
249 | /** | 236 | /** |
@@ -286,7 +273,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port) | |||
286 | } | 273 | } |
287 | 274 | ||
288 | spin_lock_irqsave(&port->lock, flags); | 275 | spin_lock_irqsave(&port->lock, flags); |
289 | port->tx_bytes_flight += count; | 276 | port->tx_bytes += count; |
290 | spin_unlock_irqrestore(&port->lock, flags); | 277 | spin_unlock_irqrestore(&port->lock, flags); |
291 | 278 | ||
292 | return count; | 279 | return count; |
@@ -318,9 +305,8 @@ int usb_serial_generic_write(struct tty_struct *tty, | |||
318 | if (!count) | 305 | if (!count) |
319 | return 0; | 306 | return 0; |
320 | 307 | ||
321 | if (serial->type->max_in_flight_urbs) | 308 | if (serial->type->multi_urb_write) |
322 | return usb_serial_multi_urb_write(tty, port, | 309 | return usb_serial_multi_urb_write(tty, port, buf, count); |
323 | buf, count); | ||
324 | 310 | ||
325 | count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); | 311 | count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); |
326 | result = usb_serial_generic_write_start(port); | 312 | result = usb_serial_generic_write_start(port); |
@@ -337,7 +323,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty) | |||
337 | struct usb_serial_port *port = tty->driver_data; | 323 | struct usb_serial_port *port = tty->driver_data; |
338 | struct usb_serial *serial = port->serial; | 324 | struct usb_serial *serial = port->serial; |
339 | unsigned long flags; | 325 | unsigned long flags; |
340 | int room = 0; | 326 | int room; |
341 | 327 | ||
342 | dbg("%s - port %d", __func__, port->number); | 328 | dbg("%s - port %d", __func__, port->number); |
343 | 329 | ||
@@ -345,14 +331,10 @@ int usb_serial_generic_write_room(struct tty_struct *tty) | |||
345 | return 0; | 331 | return 0; |
346 | 332 | ||
347 | spin_lock_irqsave(&port->lock, flags); | 333 | spin_lock_irqsave(&port->lock, flags); |
348 | if (serial->type->max_in_flight_urbs) { | 334 | if (serial->type->multi_urb_write) |
349 | if (port->urbs_in_flight < serial->type->max_in_flight_urbs) | 335 | room = (MAX_TX_URBS - port->tx_urbs) * PAGE_SIZE; |
350 | room = port->bulk_out_size * | 336 | else |
351 | (serial->type->max_in_flight_urbs - | ||
352 | port->urbs_in_flight); | ||
353 | } else { | ||
354 | room = kfifo_avail(&port->write_fifo); | 337 | room = kfifo_avail(&port->write_fifo); |
355 | } | ||
356 | spin_unlock_irqrestore(&port->lock, flags); | 338 | spin_unlock_irqrestore(&port->lock, flags); |
357 | 339 | ||
358 | dbg("%s - returns %d", __func__, room); | 340 | dbg("%s - returns %d", __func__, room); |
@@ -372,10 +354,10 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) | |||
372 | return 0; | 354 | return 0; |
373 | 355 | ||
374 | spin_lock_irqsave(&port->lock, flags); | 356 | spin_lock_irqsave(&port->lock, flags); |
375 | if (serial->type->max_in_flight_urbs) | 357 | if (serial->type->multi_urb_write) |
376 | chars = port->tx_bytes_flight; | 358 | chars = port->tx_bytes; |
377 | else | 359 | else |
378 | chars = kfifo_len(&port->write_fifo) + port->tx_bytes_flight; | 360 | chars = kfifo_len(&port->write_fifo) + port->tx_bytes; |
379 | spin_unlock_irqrestore(&port->lock, flags); | 361 | spin_unlock_irqrestore(&port->lock, flags); |
380 | 362 | ||
381 | dbg("%s - returns %d", __func__, chars); | 363 | dbg("%s - returns %d", __func__, chars); |
@@ -461,18 +443,16 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) | |||
461 | 443 | ||
462 | dbg("%s - port %d", __func__, port->number); | 444 | dbg("%s - port %d", __func__, port->number); |
463 | 445 | ||
464 | if (port->serial->type->max_in_flight_urbs) { | 446 | if (port->serial->type->multi_urb_write) { |
465 | kfree(urb->transfer_buffer); | 447 | kfree(urb->transfer_buffer); |
466 | 448 | ||
467 | spin_lock_irqsave(&port->lock, flags); | 449 | spin_lock_irqsave(&port->lock, flags); |
468 | --port->urbs_in_flight; | 450 | port->tx_bytes -= urb->transfer_buffer_length; |
469 | port->tx_bytes_flight -= urb->transfer_buffer_length; | 451 | port->tx_urbs--; |
470 | if (port->urbs_in_flight < 0) | ||
471 | port->urbs_in_flight = 0; | ||
472 | spin_unlock_irqrestore(&port->lock, flags); | 452 | spin_unlock_irqrestore(&port->lock, flags); |
473 | } else { | 453 | } else { |
474 | spin_lock_irqsave(&port->lock, flags); | 454 | spin_lock_irqsave(&port->lock, flags); |
475 | port->tx_bytes_flight -= urb->transfer_buffer_length; | 455 | port->tx_bytes -= urb->transfer_buffer_length; |
476 | port->write_urb_busy = 0; | 456 | port->write_urb_busy = 0; |
477 | spin_unlock_irqrestore(&port->lock, flags); | 457 | spin_unlock_irqrestore(&port->lock, flags); |
478 | 458 | ||
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index ff8872eba3ac..2a3283761600 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h | |||
@@ -60,6 +60,8 @@ enum port_dev_state { | |||
60 | * @write_urb: pointer to the bulk out struct urb for this port. | 60 | * @write_urb: pointer to the bulk out struct urb for this port. |
61 | * @write_fifo: kfifo used to buffer outgoing data | 61 | * @write_fifo: kfifo used to buffer outgoing data |
62 | * @write_urb_busy: port`s writing status | 62 | * @write_urb_busy: port`s writing status |
63 | * @tx_bytes: number of bytes currently in host stack queues | ||
64 | * @tx_urbs: number of urbs currently in host stack queues | ||
63 | * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this | 65 | * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this |
64 | * port. | 66 | * port. |
65 | * @write_wait: a wait_queue_head_t used by the port. | 67 | * @write_wait: a wait_queue_head_t used by the port. |
@@ -98,8 +100,8 @@ struct usb_serial_port { | |||
98 | int write_urb_busy; | 100 | int write_urb_busy; |
99 | __u8 bulk_out_endpointAddress; | 101 | __u8 bulk_out_endpointAddress; |
100 | 102 | ||
101 | int tx_bytes_flight; | 103 | int tx_bytes; |
102 | int urbs_in_flight; | 104 | int tx_urbs; |
103 | 105 | ||
104 | wait_queue_head_t write_wait; | 106 | wait_queue_head_t write_wait; |
105 | struct work_struct work; | 107 | struct work_struct work; |
@@ -223,7 +225,8 @@ struct usb_serial_driver { | |||
223 | struct device_driver driver; | 225 | struct device_driver driver; |
224 | struct usb_driver *usb_driver; | 226 | struct usb_driver *usb_driver; |
225 | struct usb_dynids dynids; | 227 | struct usb_dynids dynids; |
226 | int max_in_flight_urbs; | 228 | |
229 | unsigned char multi_urb_write:1; | ||
227 | 230 | ||
228 | size_t bulk_in_size; | 231 | size_t bulk_in_size; |
229 | size_t bulk_out_size; | 232 | size_t bulk_out_size; |