diff options
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r-- | drivers/tty/tty_buffer.c | 131 |
1 files changed, 42 insertions, 89 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 45d916198f78..bb119934e76c 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/bitops.h> | 16 | #include <linux/bitops.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/ratelimit.h> | ||
19 | 20 | ||
20 | /** | 21 | /** |
21 | * tty_buffer_free_all - free buffers used by a tty | 22 | * tty_buffer_free_all - free buffers used by a tty |
@@ -119,11 +120,14 @@ static void __tty_buffer_flush(struct tty_port *port) | |||
119 | struct tty_bufhead *buf = &port->buf; | 120 | struct tty_bufhead *buf = &port->buf; |
120 | struct tty_buffer *thead; | 121 | struct tty_buffer *thead; |
121 | 122 | ||
122 | while ((thead = buf->head) != NULL) { | 123 | if (unlikely(buf->head == NULL)) |
123 | buf->head = thead->next; | 124 | return; |
124 | tty_buffer_free(port, thead); | 125 | while ((thead = buf->head->next) != NULL) { |
126 | tty_buffer_free(port, buf->head); | ||
127 | buf->head = thead; | ||
125 | } | 128 | } |
126 | buf->tail = NULL; | 129 | WARN_ON(buf->head != buf->tail); |
130 | buf->head->read = buf->head->commit; | ||
127 | } | 131 | } |
128 | 132 | ||
129 | /** | 133 | /** |
@@ -194,19 +198,22 @@ static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size) | |||
194 | have queued and recycle that ? */ | 198 | have queued and recycle that ? */ |
195 | } | 199 | } |
196 | /** | 200 | /** |
197 | * __tty_buffer_request_room - grow tty buffer if needed | 201 | * tty_buffer_request_room - grow tty buffer if needed |
198 | * @tty: tty structure | 202 | * @tty: tty structure |
199 | * @size: size desired | 203 | * @size: size desired |
200 | * | 204 | * |
201 | * Make at least size bytes of linear space available for the tty | 205 | * Make at least size bytes of linear space available for the tty |
202 | * buffer. If we fail return the size we managed to find. | 206 | * buffer. If we fail return the size we managed to find. |
203 | * Locking: Caller must hold port->buf.lock | 207 | * |
208 | * Locking: Takes port->buf.lock | ||
204 | */ | 209 | */ |
205 | static int __tty_buffer_request_room(struct tty_port *port, size_t size) | 210 | int tty_buffer_request_room(struct tty_port *port, size_t size) |
206 | { | 211 | { |
207 | struct tty_bufhead *buf = &port->buf; | 212 | struct tty_bufhead *buf = &port->buf; |
208 | struct tty_buffer *b, *n; | 213 | struct tty_buffer *b, *n; |
209 | int left; | 214 | int left; |
215 | unsigned long flags; | ||
216 | spin_lock_irqsave(&buf->lock, flags); | ||
210 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | 217 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to |
211 | remove this conditional if its worth it. This would be invisible | 218 | remove this conditional if its worth it. This would be invisible |
212 | to the callers */ | 219 | to the callers */ |
@@ -228,37 +235,14 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size) | |||
228 | } else | 235 | } else |
229 | size = left; | 236 | size = left; |
230 | } | 237 | } |
231 | 238 | spin_unlock_irqrestore(&buf->lock, flags); | |
232 | return size; | 239 | return size; |
233 | } | 240 | } |
234 | |||
235 | |||
236 | /** | ||
237 | * tty_buffer_request_room - grow tty buffer if needed | ||
238 | * @tty: tty structure | ||
239 | * @size: size desired | ||
240 | * | ||
241 | * Make at least size bytes of linear space available for the tty | ||
242 | * buffer. If we fail return the size we managed to find. | ||
243 | * | ||
244 | * Locking: Takes port->buf.lock | ||
245 | */ | ||
246 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | ||
247 | { | ||
248 | struct tty_port *port = tty->port; | ||
249 | unsigned long flags; | ||
250 | int length; | ||
251 | |||
252 | spin_lock_irqsave(&port->buf.lock, flags); | ||
253 | length = __tty_buffer_request_room(port, size); | ||
254 | spin_unlock_irqrestore(&port->buf.lock, flags); | ||
255 | return length; | ||
256 | } | ||
257 | EXPORT_SYMBOL_GPL(tty_buffer_request_room); | 241 | EXPORT_SYMBOL_GPL(tty_buffer_request_room); |
258 | 242 | ||
259 | /** | 243 | /** |
260 | * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer | 244 | * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer |
261 | * @tty: tty structure | 245 | * @port: tty port |
262 | * @chars: characters | 246 | * @chars: characters |
263 | * @flag: flag value for each character | 247 | * @flag: flag value for each character |
264 | * @size: size | 248 | * @size: size |
@@ -269,29 +253,21 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room); | |||
269 | * Locking: Called functions may take port->buf.lock | 253 | * Locking: Called functions may take port->buf.lock |
270 | */ | 254 | */ |
271 | 255 | ||
272 | int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, | 256 | int tty_insert_flip_string_fixed_flag(struct tty_port *port, |
273 | const unsigned char *chars, char flag, size_t size) | 257 | const unsigned char *chars, char flag, size_t size) |
274 | { | 258 | { |
275 | struct tty_bufhead *buf = &tty->port->buf; | ||
276 | int copied = 0; | 259 | int copied = 0; |
277 | do { | 260 | do { |
278 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); | 261 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); |
279 | int space; | 262 | int space = tty_buffer_request_room(port, goal); |
280 | unsigned long flags; | 263 | struct tty_buffer *tb = port->buf.tail; |
281 | struct tty_buffer *tb; | ||
282 | |||
283 | spin_lock_irqsave(&buf->lock, flags); | ||
284 | space = __tty_buffer_request_room(tty->port, goal); | ||
285 | tb = buf->tail; | ||
286 | /* If there is no space then tb may be NULL */ | 264 | /* If there is no space then tb may be NULL */ |
287 | if (unlikely(space == 0)) { | 265 | if (unlikely(space == 0)) { |
288 | spin_unlock_irqrestore(&buf->lock, flags); | ||
289 | break; | 266 | break; |
290 | } | 267 | } |
291 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | 268 | memcpy(tb->char_buf_ptr + tb->used, chars, space); |
292 | memset(tb->flag_buf_ptr + tb->used, flag, space); | 269 | memset(tb->flag_buf_ptr + tb->used, flag, space); |
293 | tb->used += space; | 270 | tb->used += space; |
294 | spin_unlock_irqrestore(&buf->lock, flags); | ||
295 | copied += space; | 271 | copied += space; |
296 | chars += space; | 272 | chars += space; |
297 | /* There is a small chance that we need to split the data over | 273 | /* There is a small chance that we need to split the data over |
@@ -303,7 +279,7 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); | |||
303 | 279 | ||
304 | /** | 280 | /** |
305 | * tty_insert_flip_string_flags - Add characters to the tty buffer | 281 | * tty_insert_flip_string_flags - Add characters to the tty buffer |
306 | * @tty: tty structure | 282 | * @port: tty port |
307 | * @chars: characters | 283 | * @chars: characters |
308 | * @flags: flag bytes | 284 | * @flags: flag bytes |
309 | * @size: size | 285 | * @size: size |
@@ -315,29 +291,21 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); | |||
315 | * Locking: Called functions may take port->buf.lock | 291 | * Locking: Called functions may take port->buf.lock |
316 | */ | 292 | */ |
317 | 293 | ||
318 | int tty_insert_flip_string_flags(struct tty_struct *tty, | 294 | int tty_insert_flip_string_flags(struct tty_port *port, |
319 | const unsigned char *chars, const char *flags, size_t size) | 295 | const unsigned char *chars, const char *flags, size_t size) |
320 | { | 296 | { |
321 | struct tty_bufhead *buf = &tty->port->buf; | ||
322 | int copied = 0; | 297 | int copied = 0; |
323 | do { | 298 | do { |
324 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); | 299 | int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); |
325 | int space; | 300 | int space = tty_buffer_request_room(port, goal); |
326 | unsigned long __flags; | 301 | struct tty_buffer *tb = port->buf.tail; |
327 | struct tty_buffer *tb; | ||
328 | |||
329 | spin_lock_irqsave(&buf->lock, __flags); | ||
330 | space = __tty_buffer_request_room(tty->port, goal); | ||
331 | tb = buf->tail; | ||
332 | /* If there is no space then tb may be NULL */ | 302 | /* If there is no space then tb may be NULL */ |
333 | if (unlikely(space == 0)) { | 303 | if (unlikely(space == 0)) { |
334 | spin_unlock_irqrestore(&buf->lock, __flags); | ||
335 | break; | 304 | break; |
336 | } | 305 | } |
337 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | 306 | memcpy(tb->char_buf_ptr + tb->used, chars, space); |
338 | memcpy(tb->flag_buf_ptr + tb->used, flags, space); | 307 | memcpy(tb->flag_buf_ptr + tb->used, flags, space); |
339 | tb->used += space; | 308 | tb->used += space; |
340 | spin_unlock_irqrestore(&buf->lock, __flags); | ||
341 | copied += space; | 309 | copied += space; |
342 | chars += space; | 310 | chars += space; |
343 | flags += space; | 311 | flags += space; |
@@ -350,7 +318,7 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); | |||
350 | 318 | ||
351 | /** | 319 | /** |
352 | * tty_schedule_flip - push characters to ldisc | 320 | * tty_schedule_flip - push characters to ldisc |
353 | * @tty: tty to push from | 321 | * @port: tty port to push from |
354 | * | 322 | * |
355 | * Takes any pending buffers and transfers their ownership to the | 323 | * Takes any pending buffers and transfers their ownership to the |
356 | * ldisc side of the queue. It then schedules those characters for | 324 | * ldisc side of the queue. It then schedules those characters for |
@@ -361,11 +329,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); | |||
361 | * Locking: Takes port->buf.lock | 329 | * Locking: Takes port->buf.lock |
362 | */ | 330 | */ |
363 | 331 | ||
364 | void tty_schedule_flip(struct tty_struct *tty) | 332 | void tty_schedule_flip(struct tty_port *port) |
365 | { | 333 | { |
366 | struct tty_bufhead *buf = &tty->port->buf; | 334 | struct tty_bufhead *buf = &port->buf; |
367 | unsigned long flags; | 335 | unsigned long flags; |
368 | WARN_ON(tty->low_latency); | 336 | WARN_ON(port->low_latency); |
369 | 337 | ||
370 | spin_lock_irqsave(&buf->lock, flags); | 338 | spin_lock_irqsave(&buf->lock, flags); |
371 | if (buf->tail != NULL) | 339 | if (buf->tail != NULL) |
@@ -377,7 +345,7 @@ EXPORT_SYMBOL(tty_schedule_flip); | |||
377 | 345 | ||
378 | /** | 346 | /** |
379 | * tty_prepare_flip_string - make room for characters | 347 | * tty_prepare_flip_string - make room for characters |
380 | * @tty: tty | 348 | * @port: tty port |
381 | * @chars: return pointer for character write area | 349 | * @chars: return pointer for character write area |
382 | * @size: desired size | 350 | * @size: desired size |
383 | * | 351 | * |
@@ -390,31 +358,23 @@ EXPORT_SYMBOL(tty_schedule_flip); | |||
390 | * Locking: May call functions taking port->buf.lock | 358 | * Locking: May call functions taking port->buf.lock |
391 | */ | 359 | */ |
392 | 360 | ||
393 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, | 361 | int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, |
394 | size_t size) | 362 | size_t size) |
395 | { | 363 | { |
396 | struct tty_bufhead *buf = &tty->port->buf; | 364 | int space = tty_buffer_request_room(port, size); |
397 | int space; | ||
398 | unsigned long flags; | ||
399 | struct tty_buffer *tb; | ||
400 | |||
401 | spin_lock_irqsave(&buf->lock, flags); | ||
402 | space = __tty_buffer_request_room(tty->port, size); | ||
403 | |||
404 | tb = buf->tail; | ||
405 | if (likely(space)) { | 365 | if (likely(space)) { |
366 | struct tty_buffer *tb = port->buf.tail; | ||
406 | *chars = tb->char_buf_ptr + tb->used; | 367 | *chars = tb->char_buf_ptr + tb->used; |
407 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | 368 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); |
408 | tb->used += space; | 369 | tb->used += space; |
409 | } | 370 | } |
410 | spin_unlock_irqrestore(&buf->lock, flags); | ||
411 | return space; | 371 | return space; |
412 | } | 372 | } |
413 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | 373 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string); |
414 | 374 | ||
415 | /** | 375 | /** |
416 | * tty_prepare_flip_string_flags - make room for characters | 376 | * tty_prepare_flip_string_flags - make room for characters |
417 | * @tty: tty | 377 | * @port: tty port |
418 | * @chars: return pointer for character write area | 378 | * @chars: return pointer for character write area |
419 | * @flags: return pointer for status flag write area | 379 | * @flags: return pointer for status flag write area |
420 | * @size: desired size | 380 | * @size: desired size |
@@ -428,24 +388,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | |||
428 | * Locking: May call functions taking port->buf.lock | 388 | * Locking: May call functions taking port->buf.lock |
429 | */ | 389 | */ |
430 | 390 | ||
431 | int tty_prepare_flip_string_flags(struct tty_struct *tty, | 391 | int tty_prepare_flip_string_flags(struct tty_port *port, |
432 | unsigned char **chars, char **flags, size_t size) | 392 | unsigned char **chars, char **flags, size_t size) |
433 | { | 393 | { |
434 | struct tty_bufhead *buf = &tty->port->buf; | 394 | int space = tty_buffer_request_room(port, size); |
435 | int space; | ||
436 | unsigned long __flags; | ||
437 | struct tty_buffer *tb; | ||
438 | |||
439 | spin_lock_irqsave(&buf->lock, __flags); | ||
440 | space = __tty_buffer_request_room(tty->port, size); | ||
441 | |||
442 | tb = buf->tail; | ||
443 | if (likely(space)) { | 395 | if (likely(space)) { |
396 | struct tty_buffer *tb = port->buf.tail; | ||
444 | *chars = tb->char_buf_ptr + tb->used; | 397 | *chars = tb->char_buf_ptr + tb->used; |
445 | *flags = tb->flag_buf_ptr + tb->used; | 398 | *flags = tb->flag_buf_ptr + tb->used; |
446 | tb->used += space; | 399 | tb->used += space; |
447 | } | 400 | } |
448 | spin_unlock_irqrestore(&buf->lock, __flags); | ||
449 | return space; | 401 | return space; |
450 | } | 402 | } |
451 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); | 403 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); |
@@ -539,16 +491,17 @@ static void flush_to_ldisc(struct work_struct *work) | |||
539 | */ | 491 | */ |
540 | void tty_flush_to_ldisc(struct tty_struct *tty) | 492 | void tty_flush_to_ldisc(struct tty_struct *tty) |
541 | { | 493 | { |
542 | if (!tty->low_latency) | 494 | if (!tty->port->low_latency) |
543 | flush_work(&tty->port->buf.work); | 495 | flush_work(&tty->port->buf.work); |
544 | } | 496 | } |
545 | 497 | ||
546 | /** | 498 | /** |
547 | * tty_flip_buffer_push - terminal | 499 | * tty_flip_buffer_push - terminal |
548 | * @tty: tty to push | 500 | * @port: tty port to push |
549 | * | 501 | * |
550 | * Queue a push of the terminal flip buffers to the line discipline. This | 502 | * Queue a push of the terminal flip buffers to the line discipline. This |
551 | * function must not be called from IRQ context if tty->low_latency is set. | 503 | * function must not be called from IRQ context if port->low_latency is |
504 | * set. | ||
552 | * | 505 | * |
553 | * In the event of the queue being busy for flipping the work will be | 506 | * In the event of the queue being busy for flipping the work will be |
554 | * held off and retried later. | 507 | * held off and retried later. |
@@ -556,9 +509,9 @@ void tty_flush_to_ldisc(struct tty_struct *tty) | |||
556 | * Locking: tty buffer lock. Driver locks in low latency mode. | 509 | * Locking: tty buffer lock. Driver locks in low latency mode. |
557 | */ | 510 | */ |
558 | 511 | ||
559 | void tty_flip_buffer_push(struct tty_struct *tty) | 512 | void tty_flip_buffer_push(struct tty_port *port) |
560 | { | 513 | { |
561 | struct tty_bufhead *buf = &tty->port->buf; | 514 | struct tty_bufhead *buf = &port->buf; |
562 | unsigned long flags; | 515 | unsigned long flags; |
563 | 516 | ||
564 | spin_lock_irqsave(&buf->lock, flags); | 517 | spin_lock_irqsave(&buf->lock, flags); |
@@ -566,7 +519,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) | |||
566 | buf->tail->commit = buf->tail->used; | 519 | buf->tail->commit = buf->tail->used; |
567 | spin_unlock_irqrestore(&buf->lock, flags); | 520 | spin_unlock_irqrestore(&buf->lock, flags); |
568 | 521 | ||
569 | if (tty->low_latency) | 522 | if (port->low_latency) |
570 | flush_to_ldisc(&buf->work); | 523 | flush_to_ldisc(&buf->work); |
571 | else | 524 | else |
572 | schedule_work(&buf->work); | 525 | schedule_work(&buf->work); |