diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/tty/hvc | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/Kconfig | 25 | ||||
-rw-r--r-- | drivers/tty/hvc/Makefile | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_beat.c | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 168 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.h | 4 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_irq.c | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_opal.c | 425 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_rtas.c | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_udbg.c | 10 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_vio.c | 143 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_xen.c | 470 | ||||
-rw-r--r-- | drivers/tty/hvc/hvcs.c | 209 | ||||
-rw-r--r-- | drivers/tty/hvc/hvsi.c | 143 | ||||
-rw-r--r-- | drivers/tty/hvc/hvsi_lib.c | 8 |
14 files changed, 384 insertions, 1229 deletions
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index f47b734c6a7..e371753ba92 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig | |||
@@ -24,14 +24,15 @@ config HVC_OLD_HVSI | |||
24 | depends on HVC_CONSOLE | 24 | depends on HVC_CONSOLE |
25 | default n | 25 | default n |
26 | 26 | ||
27 | config HVC_OPAL | 27 | config HVC_ISERIES |
28 | bool "OPAL Console support" | 28 | bool "iSeries Hypervisor Virtual Console support" |
29 | depends on PPC_POWERNV | 29 | depends on PPC_ISERIES |
30 | default y | ||
30 | select HVC_DRIVER | 31 | select HVC_DRIVER |
31 | select HVC_IRQ | 32 | select HVC_IRQ |
32 | default y | 33 | select VIOPATH |
33 | help | 34 | help |
34 | PowerNV machines running under OPAL need that driver to get a console | 35 | iSeries machines support a hypervisor virtual console. |
35 | 36 | ||
36 | config HVC_RTAS | 37 | config HVC_RTAS |
37 | bool "IBM RTAS Console support" | 38 | bool "IBM RTAS Console support" |
@@ -66,23 +67,11 @@ config HVC_XEN | |||
66 | help | 67 | help |
67 | Xen virtual console device driver | 68 | Xen virtual console device driver |
68 | 69 | ||
69 | config HVC_XEN_FRONTEND | ||
70 | bool "Xen Hypervisor Multiple Consoles support" | ||
71 | depends on HVC_XEN | ||
72 | select XEN_XENBUS_FRONTEND | ||
73 | default y | ||
74 | help | ||
75 | Xen driver for secondary virtual consoles | ||
76 | |||
77 | config HVC_UDBG | 70 | config HVC_UDBG |
78 | bool "udbg based fake hypervisor console" | 71 | bool "udbg based fake hypervisor console" |
79 | depends on PPC | 72 | depends on PPC && EXPERIMENTAL |
80 | select HVC_DRIVER | 73 | select HVC_DRIVER |
81 | default n | 74 | default n |
82 | help | ||
83 | This is meant to be used during HW bring up or debugging when | ||
84 | no other console mechanism exist but udbg, to get you a quick | ||
85 | console for userspace. Do NOT enable in production kernels. | ||
86 | 75 | ||
87 | config HVC_DCC | 76 | config HVC_DCC |
88 | bool "ARM JTAG DCC console" | 77 | bool "ARM JTAG DCC console" |
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index 4ca3723b0a3..e2920531637 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o | 1 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o |
2 | obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o | ||
3 | obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o | 2 | obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o |
3 | obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o | ||
4 | obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o | 4 | obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o |
5 | obj-$(CONFIG_HVC_TILE) += hvc_tile.o | 5 | obj-$(CONFIG_HVC_TILE) += hvc_tile.o |
6 | obj-$(CONFIG_HVC_DCC) += hvc_dcc.o | 6 | obj-$(CONFIG_HVC_DCC) += hvc_dcc.o |
diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c index 1560d235449..5fe4631e2a6 100644 --- a/drivers/tty/hvc/hvc_beat.c +++ b/drivers/tty/hvc/hvc_beat.c | |||
@@ -113,7 +113,7 @@ static int __init hvc_beat_init(void) | |||
113 | if (!firmware_has_feature(FW_FEATURE_BEAT)) | 113 | if (!firmware_has_feature(FW_FEATURE_BEAT)) |
114 | return -ENODEV; | 114 | return -ENODEV; |
115 | 115 | ||
116 | hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); | 116 | hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); |
117 | if (IS_ERR(hp)) | 117 | if (IS_ERR(hp)) |
118 | return PTR_ERR(hp); | 118 | return PTR_ERR(hp); |
119 | hvc_beat_dev = hp; | 119 | hvc_beat_dev = hp; |
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 13ee53bd0bf..e1aaf4f309b 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c | |||
@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index) | |||
107 | list_for_each_entry(hp, &hvc_structs, next) { | 107 | list_for_each_entry(hp, &hvc_structs, next) { |
108 | spin_lock_irqsave(&hp->lock, flags); | 108 | spin_lock_irqsave(&hp->lock, flags); |
109 | if (hp->index == index) { | 109 | if (hp->index == index) { |
110 | tty_port_get(&hp->port); | 110 | kref_get(&hp->kref); |
111 | spin_unlock_irqrestore(&hp->lock, flags); | 111 | spin_unlock_irqrestore(&hp->lock, flags); |
112 | spin_unlock(&hvc_structs_lock); | 112 | spin_unlock(&hvc_structs_lock); |
113 | return hp; | 113 | return hp; |
@@ -229,9 +229,9 @@ static int __init hvc_console_init(void) | |||
229 | console_initcall(hvc_console_init); | 229 | console_initcall(hvc_console_init); |
230 | 230 | ||
231 | /* callback when the kboject ref count reaches zero. */ | 231 | /* callback when the kboject ref count reaches zero. */ |
232 | static void hvc_port_destruct(struct tty_port *port) | 232 | static void destroy_hvc_struct(struct kref *kref) |
233 | { | 233 | { |
234 | struct hvc_struct *hp = container_of(port, struct hvc_struct, port); | 234 | struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); |
235 | unsigned long flags; | 235 | unsigned long flags; |
236 | 236 | ||
237 | spin_lock(&hvc_structs_lock); | 237 | spin_lock(&hvc_structs_lock); |
@@ -245,20 +245,6 @@ static void hvc_port_destruct(struct tty_port *port) | |||
245 | kfree(hp); | 245 | kfree(hp); |
246 | } | 246 | } |
247 | 247 | ||
248 | static void hvc_check_console(int index) | ||
249 | { | ||
250 | /* Already enabled, bail out */ | ||
251 | if (hvc_console.flags & CON_ENABLED) | ||
252 | return; | ||
253 | |||
254 | /* If this index is what the user requested, then register | ||
255 | * now (setup won't fail at this point). It's ok to just | ||
256 | * call register again if previously .setup failed. | ||
257 | */ | ||
258 | if (index == hvc_console.index) | ||
259 | register_console(&hvc_console); | ||
260 | } | ||
261 | |||
262 | /* | 248 | /* |
263 | * hvc_instantiate() is an early console discovery method which locates | 249 | * hvc_instantiate() is an early console discovery method which locates |
264 | * consoles * prior to the vio subsystem discovering them. Hotplugged | 250 | * consoles * prior to the vio subsystem discovering them. Hotplugged |
@@ -278,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) | |||
278 | /* make sure no no tty has been registered in this index */ | 264 | /* make sure no no tty has been registered in this index */ |
279 | hp = hvc_get_by_index(index); | 265 | hp = hvc_get_by_index(index); |
280 | if (hp) { | 266 | if (hp) { |
281 | tty_port_put(&hp->port); | 267 | kref_put(&hp->kref, destroy_hvc_struct); |
282 | return -1; | 268 | return -1; |
283 | } | 269 | } |
284 | 270 | ||
@@ -289,8 +275,12 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) | |||
289 | if (last_hvc < index) | 275 | if (last_hvc < index) |
290 | last_hvc = index; | 276 | last_hvc = index; |
291 | 277 | ||
292 | /* check if we need to re-register the kernel console */ | 278 | /* if this index is what the user requested, then register |
293 | hvc_check_console(index); | 279 | * now (setup won't fail at this point). It's ok to just |
280 | * call register again if previously .setup failed. | ||
281 | */ | ||
282 | if (index == hvc_console.index) | ||
283 | register_console(&hvc_console); | ||
294 | 284 | ||
295 | return 0; | 285 | return 0; |
296 | } | 286 | } |
@@ -309,43 +299,34 @@ static void hvc_unthrottle(struct tty_struct *tty) | |||
309 | hvc_kick(); | 299 | hvc_kick(); |
310 | } | 300 | } |
311 | 301 | ||
312 | static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) | ||
313 | { | ||
314 | struct hvc_struct *hp; | ||
315 | int rc; | ||
316 | |||
317 | /* Auto increments kref reference if found. */ | ||
318 | if (!(hp = hvc_get_by_index(tty->index))) | ||
319 | return -ENODEV; | ||
320 | |||
321 | tty->driver_data = hp; | ||
322 | |||
323 | rc = tty_port_install(&hp->port, driver, tty); | ||
324 | if (rc) | ||
325 | tty_port_put(&hp->port); | ||
326 | return rc; | ||
327 | } | ||
328 | |||
329 | /* | 302 | /* |
330 | * The TTY interface won't be used until after the vio layer has exposed the vty | 303 | * The TTY interface won't be used until after the vio layer has exposed the vty |
331 | * adapter to the kernel. | 304 | * adapter to the kernel. |
332 | */ | 305 | */ |
333 | static int hvc_open(struct tty_struct *tty, struct file * filp) | 306 | static int hvc_open(struct tty_struct *tty, struct file * filp) |
334 | { | 307 | { |
335 | struct hvc_struct *hp = tty->driver_data; | 308 | struct hvc_struct *hp; |
336 | unsigned long flags; | 309 | unsigned long flags; |
337 | int rc = 0; | 310 | int rc = 0; |
338 | 311 | ||
339 | spin_lock_irqsave(&hp->port.lock, flags); | 312 | /* Auto increments kref reference if found. */ |
313 | if (!(hp = hvc_get_by_index(tty->index))) | ||
314 | return -ENODEV; | ||
315 | |||
316 | spin_lock_irqsave(&hp->lock, flags); | ||
340 | /* Check and then increment for fast path open. */ | 317 | /* Check and then increment for fast path open. */ |
341 | if (hp->port.count++ > 0) { | 318 | if (hp->count++ > 0) { |
342 | spin_unlock_irqrestore(&hp->port.lock, flags); | 319 | tty_kref_get(tty); |
320 | spin_unlock_irqrestore(&hp->lock, flags); | ||
343 | hvc_kick(); | 321 | hvc_kick(); |
344 | return 0; | 322 | return 0; |
345 | } /* else count == 0 */ | 323 | } /* else count == 0 */ |
346 | spin_unlock_irqrestore(&hp->port.lock, flags); | ||
347 | 324 | ||
348 | tty_port_tty_set(&hp->port, tty); | 325 | tty->driver_data = hp; |
326 | |||
327 | hp->tty = tty_kref_get(tty); | ||
328 | |||
329 | spin_unlock_irqrestore(&hp->lock, flags); | ||
349 | 330 | ||
350 | if (hp->ops->notifier_add) | 331 | if (hp->ops->notifier_add) |
351 | rc = hp->ops->notifier_add(hp, hp->data); | 332 | rc = hp->ops->notifier_add(hp, hp->data); |
@@ -357,9 +338,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) | |||
357 | * tty fields and return the kref reference. | 338 | * tty fields and return the kref reference. |
358 | */ | 339 | */ |
359 | if (rc) { | 340 | if (rc) { |
360 | tty_port_tty_set(&hp->port, NULL); | 341 | spin_lock_irqsave(&hp->lock, flags); |
342 | hp->tty = NULL; | ||
343 | spin_unlock_irqrestore(&hp->lock, flags); | ||
344 | tty_kref_put(tty); | ||
361 | tty->driver_data = NULL; | 345 | tty->driver_data = NULL; |
362 | tty_port_put(&hp->port); | 346 | kref_put(&hp->kref, destroy_hvc_struct); |
363 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); | 347 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); |
364 | } | 348 | } |
365 | /* Force wakeup of the polling thread */ | 349 | /* Force wakeup of the polling thread */ |
@@ -386,12 +370,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) | |||
386 | 370 | ||
387 | hp = tty->driver_data; | 371 | hp = tty->driver_data; |
388 | 372 | ||
389 | spin_lock_irqsave(&hp->port.lock, flags); | 373 | spin_lock_irqsave(&hp->lock, flags); |
390 | 374 | ||
391 | if (--hp->port.count == 0) { | 375 | if (--hp->count == 0) { |
392 | spin_unlock_irqrestore(&hp->port.lock, flags); | ||
393 | /* We are done with the tty pointer now. */ | 376 | /* We are done with the tty pointer now. */ |
394 | tty_port_tty_set(&hp->port, NULL); | 377 | hp->tty = NULL; |
378 | spin_unlock_irqrestore(&hp->lock, flags); | ||
395 | 379 | ||
396 | if (hp->ops->notifier_del) | 380 | if (hp->ops->notifier_del) |
397 | hp->ops->notifier_del(hp, hp->data); | 381 | hp->ops->notifier_del(hp, hp->data); |
@@ -404,26 +388,23 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) | |||
404 | * there is no buffered data otherwise sleeps on a wait queue | 388 | * there is no buffered data otherwise sleeps on a wait queue |
405 | * waking periodically to check chars_in_buffer(). | 389 | * waking periodically to check chars_in_buffer(). |
406 | */ | 390 | */ |
407 | tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); | 391 | tty_wait_until_sent(tty, HVC_CLOSE_WAIT); |
408 | } else { | 392 | } else { |
409 | if (hp->port.count < 0) | 393 | if (hp->count < 0) |
410 | printk(KERN_ERR "hvc_close %X: oops, count is %d\n", | 394 | printk(KERN_ERR "hvc_close %X: oops, count is %d\n", |
411 | hp->vtermno, hp->port.count); | 395 | hp->vtermno, hp->count); |
412 | spin_unlock_irqrestore(&hp->port.lock, flags); | 396 | spin_unlock_irqrestore(&hp->lock, flags); |
413 | } | 397 | } |
414 | } | ||
415 | 398 | ||
416 | static void hvc_cleanup(struct tty_struct *tty) | 399 | tty_kref_put(tty); |
417 | { | 400 | kref_put(&hp->kref, destroy_hvc_struct); |
418 | struct hvc_struct *hp = tty->driver_data; | ||
419 | |||
420 | tty_port_put(&hp->port); | ||
421 | } | 401 | } |
422 | 402 | ||
423 | static void hvc_hangup(struct tty_struct *tty) | 403 | static void hvc_hangup(struct tty_struct *tty) |
424 | { | 404 | { |
425 | struct hvc_struct *hp = tty->driver_data; | 405 | struct hvc_struct *hp = tty->driver_data; |
426 | unsigned long flags; | 406 | unsigned long flags; |
407 | int temp_open_count; | ||
427 | 408 | ||
428 | if (!hp) | 409 | if (!hp) |
429 | return; | 410 | return; |
@@ -431,26 +412,33 @@ static void hvc_hangup(struct tty_struct *tty) | |||
431 | /* cancel pending tty resize work */ | 412 | /* cancel pending tty resize work */ |
432 | cancel_work_sync(&hp->tty_resize); | 413 | cancel_work_sync(&hp->tty_resize); |
433 | 414 | ||
434 | spin_lock_irqsave(&hp->port.lock, flags); | 415 | spin_lock_irqsave(&hp->lock, flags); |
435 | 416 | ||
436 | /* | 417 | /* |
437 | * The N_TTY line discipline has problems such that in a close vs | 418 | * The N_TTY line discipline has problems such that in a close vs |
438 | * open->hangup case this can be called after the final close so prevent | 419 | * open->hangup case this can be called after the final close so prevent |
439 | * that from happening for now. | 420 | * that from happening for now. |
440 | */ | 421 | */ |
441 | if (hp->port.count <= 0) { | 422 | if (hp->count <= 0) { |
442 | spin_unlock_irqrestore(&hp->port.lock, flags); | 423 | spin_unlock_irqrestore(&hp->lock, flags); |
443 | return; | 424 | return; |
444 | } | 425 | } |
445 | 426 | ||
446 | hp->port.count = 0; | 427 | temp_open_count = hp->count; |
447 | spin_unlock_irqrestore(&hp->port.lock, flags); | 428 | hp->count = 0; |
448 | tty_port_tty_set(&hp->port, NULL); | ||
449 | |||
450 | hp->n_outbuf = 0; | 429 | hp->n_outbuf = 0; |
430 | hp->tty = NULL; | ||
431 | |||
432 | spin_unlock_irqrestore(&hp->lock, flags); | ||
451 | 433 | ||
452 | if (hp->ops->notifier_hangup) | 434 | if (hp->ops->notifier_hangup) |
453 | hp->ops->notifier_hangup(hp, hp->data); | 435 | hp->ops->notifier_hangup(hp, hp->data); |
436 | |||
437 | while(temp_open_count) { | ||
438 | --temp_open_count; | ||
439 | tty_kref_put(tty); | ||
440 | kref_put(&hp->kref, destroy_hvc_struct); | ||
441 | } | ||
454 | } | 442 | } |
455 | 443 | ||
456 | /* | 444 | /* |
@@ -490,8 +478,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count | |||
490 | if (!hp) | 478 | if (!hp) |
491 | return -EPIPE; | 479 | return -EPIPE; |
492 | 480 | ||
493 | /* FIXME what's this (unprotected) check for? */ | 481 | if (hp->count <= 0) |
494 | if (hp->port.count <= 0) | ||
495 | return -EIO; | 482 | return -EIO; |
496 | 483 | ||
497 | spin_lock_irqsave(&hp->lock, flags); | 484 | spin_lock_irqsave(&hp->lock, flags); |
@@ -539,12 +526,13 @@ static void hvc_set_winsz(struct work_struct *work) | |||
539 | 526 | ||
540 | hp = container_of(work, struct hvc_struct, tty_resize); | 527 | hp = container_of(work, struct hvc_struct, tty_resize); |
541 | 528 | ||
542 | tty = tty_port_tty_get(&hp->port); | ||
543 | if (!tty) | ||
544 | return; | ||
545 | |||
546 | spin_lock_irqsave(&hp->lock, hvc_flags); | 529 | spin_lock_irqsave(&hp->lock, hvc_flags); |
547 | ws = hp->ws; | 530 | if (!hp->tty) { |
531 | spin_unlock_irqrestore(&hp->lock, hvc_flags); | ||
532 | return; | ||
533 | } | ||
534 | ws = hp->ws; | ||
535 | tty = tty_kref_get(hp->tty); | ||
548 | spin_unlock_irqrestore(&hp->lock, hvc_flags); | 536 | spin_unlock_irqrestore(&hp->lock, hvc_flags); |
549 | 537 | ||
550 | tty_do_resize(tty, &ws); | 538 | tty_do_resize(tty, &ws); |
@@ -561,7 +549,7 @@ static int hvc_write_room(struct tty_struct *tty) | |||
561 | struct hvc_struct *hp = tty->driver_data; | 549 | struct hvc_struct *hp = tty->driver_data; |
562 | 550 | ||
563 | if (!hp) | 551 | if (!hp) |
564 | return 0; | 552 | return -1; |
565 | 553 | ||
566 | return hp->outbuf_size - hp->n_outbuf; | 554 | return hp->outbuf_size - hp->n_outbuf; |
567 | } | 555 | } |
@@ -613,7 +601,7 @@ int hvc_poll(struct hvc_struct *hp) | |||
613 | } | 601 | } |
614 | 602 | ||
615 | /* No tty attached, just skip */ | 603 | /* No tty attached, just skip */ |
616 | tty = tty_port_tty_get(&hp->port); | 604 | tty = tty_kref_get(hp->tty); |
617 | if (tty == NULL) | 605 | if (tty == NULL) |
618 | goto bail; | 606 | goto bail; |
619 | 607 | ||
@@ -693,7 +681,8 @@ int hvc_poll(struct hvc_struct *hp) | |||
693 | 681 | ||
694 | tty_flip_buffer_push(tty); | 682 | tty_flip_buffer_push(tty); |
695 | } | 683 | } |
696 | tty_kref_put(tty); | 684 | if (tty) |
685 | tty_kref_put(tty); | ||
697 | 686 | ||
698 | return poll_mask; | 687 | return poll_mask; |
699 | } | 688 | } |
@@ -812,10 +801,8 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) | |||
812 | #endif | 801 | #endif |
813 | 802 | ||
814 | static const struct tty_operations hvc_ops = { | 803 | static const struct tty_operations hvc_ops = { |
815 | .install = hvc_install, | ||
816 | .open = hvc_open, | 804 | .open = hvc_open, |
817 | .close = hvc_close, | 805 | .close = hvc_close, |
818 | .cleanup = hvc_cleanup, | ||
819 | .write = hvc_write, | 806 | .write = hvc_write, |
820 | .hangup = hvc_hangup, | 807 | .hangup = hvc_hangup, |
821 | .unthrottle = hvc_unthrottle, | 808 | .unthrottle = hvc_unthrottle, |
@@ -830,10 +817,6 @@ static const struct tty_operations hvc_ops = { | |||
830 | #endif | 817 | #endif |
831 | }; | 818 | }; |
832 | 819 | ||
833 | static const struct tty_port_operations hvc_port_ops = { | ||
834 | .destruct = hvc_port_destruct, | ||
835 | }; | ||
836 | |||
837 | struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, | 820 | struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, |
838 | const struct hv_ops *ops, | 821 | const struct hv_ops *ops, |
839 | int outbuf_size) | 822 | int outbuf_size) |
@@ -859,8 +842,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, | |||
859 | hp->outbuf_size = outbuf_size; | 842 | hp->outbuf_size = outbuf_size; |
860 | hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; | 843 | hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; |
861 | 844 | ||
862 | tty_port_init(&hp->port); | 845 | kref_init(&hp->kref); |
863 | hp->port.ops = &hvc_port_ops; | ||
864 | 846 | ||
865 | INIT_WORK(&hp->tty_resize, hvc_set_winsz); | 847 | INIT_WORK(&hp->tty_resize, hvc_set_winsz); |
866 | spin_lock_init(&hp->lock); | 848 | spin_lock_init(&hp->lock); |
@@ -880,15 +862,10 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, | |||
880 | i = ++last_hvc; | 862 | i = ++last_hvc; |
881 | 863 | ||
882 | hp->index = i; | 864 | hp->index = i; |
883 | cons_ops[i] = ops; | ||
884 | vtermnos[i] = vtermno; | ||
885 | 865 | ||
886 | list_add_tail(&(hp->next), &hvc_structs); | 866 | list_add_tail(&(hp->next), &hvc_structs); |
887 | spin_unlock(&hvc_structs_lock); | 867 | spin_unlock(&hvc_structs_lock); |
888 | 868 | ||
889 | /* check if we need to re-register the kernel console */ | ||
890 | hvc_check_console(i); | ||
891 | |||
892 | return hp; | 869 | return hp; |
893 | } | 870 | } |
894 | EXPORT_SYMBOL_GPL(hvc_alloc); | 871 | EXPORT_SYMBOL_GPL(hvc_alloc); |
@@ -898,15 +875,11 @@ int hvc_remove(struct hvc_struct *hp) | |||
898 | unsigned long flags; | 875 | unsigned long flags; |
899 | struct tty_struct *tty; | 876 | struct tty_struct *tty; |
900 | 877 | ||
901 | tty = tty_port_tty_get(&hp->port); | ||
902 | |||
903 | spin_lock_irqsave(&hp->lock, flags); | 878 | spin_lock_irqsave(&hp->lock, flags); |
904 | if (hp->index < MAX_NR_HVC_CONSOLES) { | 879 | tty = tty_kref_get(hp->tty); |
905 | console_lock(); | 880 | |
881 | if (hp->index < MAX_NR_HVC_CONSOLES) | ||
906 | vtermnos[hp->index] = -1; | 882 | vtermnos[hp->index] = -1; |
907 | cons_ops[hp->index] = NULL; | ||
908 | console_unlock(); | ||
909 | } | ||
910 | 883 | ||
911 | /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ | 884 | /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ |
912 | 885 | ||
@@ -918,7 +891,7 @@ int hvc_remove(struct hvc_struct *hp) | |||
918 | * kref cause it to be removed, which will probably be the tty_vhangup | 891 | * kref cause it to be removed, which will probably be the tty_vhangup |
919 | * below. | 892 | * below. |
920 | */ | 893 | */ |
921 | tty_port_put(&hp->port); | 894 | kref_put(&hp->kref, destroy_hvc_struct); |
922 | 895 | ||
923 | /* | 896 | /* |
924 | * This function call will auto chain call hvc_hangup. | 897 | * This function call will auto chain call hvc_hangup. |
@@ -944,6 +917,7 @@ static int hvc_init(void) | |||
944 | goto out; | 917 | goto out; |
945 | } | 918 | } |
946 | 919 | ||
920 | drv->owner = THIS_MODULE; | ||
947 | drv->driver_name = "hvc"; | 921 | drv->driver_name = "hvc"; |
948 | drv->name = "hvc"; | 922 | drv->name = "hvc"; |
949 | drv->major = HVC_MAJOR; | 923 | drv->major = HVC_MAJOR; |
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 674d23cb919..c335a1492a5 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h | |||
@@ -46,9 +46,10 @@ | |||
46 | #define HVC_ALLOC_TTY_ADAPTERS 8 | 46 | #define HVC_ALLOC_TTY_ADAPTERS 8 |
47 | 47 | ||
48 | struct hvc_struct { | 48 | struct hvc_struct { |
49 | struct tty_port port; | ||
50 | spinlock_t lock; | 49 | spinlock_t lock; |
51 | int index; | 50 | int index; |
51 | struct tty_struct *tty; | ||
52 | int count; | ||
52 | int do_wakeup; | 53 | int do_wakeup; |
53 | char *outbuf; | 54 | char *outbuf; |
54 | int outbuf_size; | 55 | int outbuf_size; |
@@ -60,6 +61,7 @@ struct hvc_struct { | |||
60 | struct winsize ws; | 61 | struct winsize ws; |
61 | struct work_struct tty_resize; | 62 | struct work_struct tty_resize; |
62 | struct list_head next; | 63 | struct list_head next; |
64 | struct kref kref; /* ref count & hvc_struct lifetime */ | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | /* implemented by a low level driver */ | 67 | /* implemented by a low level driver */ |
diff --git a/drivers/tty/hvc/hvc_irq.c b/drivers/tty/hvc/hvc_irq.c index c9adb0559f6..2623e177e8d 100644 --- a/drivers/tty/hvc/hvc_irq.c +++ b/drivers/tty/hvc/hvc_irq.c | |||
@@ -28,7 +28,7 @@ int notifier_add_irq(struct hvc_struct *hp, int irq) | |||
28 | hp->irq_requested = 0; | 28 | hp->irq_requested = 0; |
29 | return 0; | 29 | return 0; |
30 | } | 30 | } |
31 | rc = request_irq(irq, hvc_handle_interrupt, 0, | 31 | rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, |
32 | "hvc_console", hp); | 32 | "hvc_console", hp); |
33 | if (!rc) | 33 | if (!rc) |
34 | hp->irq_requested = 1; | 34 | hp->irq_requested = 1; |
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c deleted file mode 100644 index cd69b48f6df..00000000000 --- a/drivers/tty/hvc/hvc_opal.c +++ /dev/null | |||
@@ -1,425 +0,0 @@ | |||
1 | /* | ||
2 | * opal driver interface to hvc_console.c | ||
3 | * | ||
4 | * Copyright 2011 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #undef DEBUG | ||
23 | |||
24 | #include <linux/types.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/console.h> | ||
29 | #include <linux/of.h> | ||
30 | #include <linux/of_platform.h> | ||
31 | #include <linux/export.h> | ||
32 | |||
33 | #include <asm/hvconsole.h> | ||
34 | #include <asm/prom.h> | ||
35 | #include <asm/firmware.h> | ||
36 | #include <asm/hvsi.h> | ||
37 | #include <asm/udbg.h> | ||
38 | #include <asm/opal.h> | ||
39 | |||
40 | #include "hvc_console.h" | ||
41 | |||
42 | static const char hvc_opal_name[] = "hvc_opal"; | ||
43 | |||
44 | static struct of_device_id hvc_opal_match[] = { | ||
45 | { .name = "serial", .compatible = "ibm,opal-console-raw" }, | ||
46 | { .name = "serial", .compatible = "ibm,opal-console-hvsi" }, | ||
47 | { }, | ||
48 | }; | ||
49 | |||
50 | typedef enum hv_protocol { | ||
51 | HV_PROTOCOL_RAW, | ||
52 | HV_PROTOCOL_HVSI | ||
53 | } hv_protocol_t; | ||
54 | |||
55 | struct hvc_opal_priv { | ||
56 | hv_protocol_t proto; /* Raw data or HVSI packets */ | ||
57 | struct hvsi_priv hvsi; /* HVSI specific data */ | ||
58 | }; | ||
59 | static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES]; | ||
60 | |||
61 | /* For early boot console */ | ||
62 | static struct hvc_opal_priv hvc_opal_boot_priv; | ||
63 | static u32 hvc_opal_boot_termno; | ||
64 | |||
65 | static const struct hv_ops hvc_opal_raw_ops = { | ||
66 | .get_chars = opal_get_chars, | ||
67 | .put_chars = opal_put_chars, | ||
68 | .notifier_add = notifier_add_irq, | ||
69 | .notifier_del = notifier_del_irq, | ||
70 | .notifier_hangup = notifier_hangup_irq, | ||
71 | }; | ||
72 | |||
73 | static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count) | ||
74 | { | ||
75 | struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; | ||
76 | |||
77 | if (WARN_ON(!pv)) | ||
78 | return -ENODEV; | ||
79 | |||
80 | return hvsilib_get_chars(&pv->hvsi, buf, count); | ||
81 | } | ||
82 | |||
83 | static int hvc_opal_hvsi_put_chars(uint32_t vtermno, const char *buf, int count) | ||
84 | { | ||
85 | struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; | ||
86 | |||
87 | if (WARN_ON(!pv)) | ||
88 | return -ENODEV; | ||
89 | |||
90 | return hvsilib_put_chars(&pv->hvsi, buf, count); | ||
91 | } | ||
92 | |||
93 | static int hvc_opal_hvsi_open(struct hvc_struct *hp, int data) | ||
94 | { | ||
95 | struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; | ||
96 | int rc; | ||
97 | |||
98 | pr_devel("HVSI@%x: do open !\n", hp->vtermno); | ||
99 | |||
100 | rc = notifier_add_irq(hp, data); | ||
101 | if (rc) | ||
102 | return rc; | ||
103 | |||
104 | return hvsilib_open(&pv->hvsi, hp); | ||
105 | } | ||
106 | |||
107 | static void hvc_opal_hvsi_close(struct hvc_struct *hp, int data) | ||
108 | { | ||
109 | struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; | ||
110 | |||
111 | pr_devel("HVSI@%x: do close !\n", hp->vtermno); | ||
112 | |||
113 | hvsilib_close(&pv->hvsi, hp); | ||
114 | |||
115 | notifier_del_irq(hp, data); | ||
116 | } | ||
117 | |||
118 | void hvc_opal_hvsi_hangup(struct hvc_struct *hp, int data) | ||
119 | { | ||
120 | struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; | ||
121 | |||
122 | pr_devel("HVSI@%x: do hangup !\n", hp->vtermno); | ||
123 | |||
124 | hvsilib_close(&pv->hvsi, hp); | ||
125 | |||
126 | notifier_hangup_irq(hp, data); | ||
127 | } | ||
128 | |||
129 | static int hvc_opal_hvsi_tiocmget(struct hvc_struct *hp) | ||
130 | { | ||
131 | struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; | ||
132 | |||
133 | if (!pv) | ||
134 | return -EINVAL; | ||
135 | return pv->hvsi.mctrl; | ||
136 | } | ||
137 | |||
138 | static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set, | ||
139 | unsigned int clear) | ||
140 | { | ||
141 | struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; | ||
142 | |||
143 | pr_devel("HVSI@%x: Set modem control, set=%x,clr=%x\n", | ||
144 | hp->vtermno, set, clear); | ||
145 | |||
146 | if (set & TIOCM_DTR) | ||
147 | hvsilib_write_mctrl(&pv->hvsi, 1); | ||
148 | else if (clear & TIOCM_DTR) | ||
149 | hvsilib_write_mctrl(&pv->hvsi, 0); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static const struct hv_ops hvc_opal_hvsi_ops = { | ||
155 | .get_chars = hvc_opal_hvsi_get_chars, | ||
156 | .put_chars = hvc_opal_hvsi_put_chars, | ||
157 | .notifier_add = hvc_opal_hvsi_open, | ||
158 | .notifier_del = hvc_opal_hvsi_close, | ||
159 | .notifier_hangup = hvc_opal_hvsi_hangup, | ||
160 | .tiocmget = hvc_opal_hvsi_tiocmget, | ||
161 | .tiocmset = hvc_opal_hvsi_tiocmset, | ||
162 | }; | ||
163 | |||
164 | static int hvc_opal_probe(struct platform_device *dev) | ||
165 | { | ||
166 | const struct hv_ops *ops; | ||
167 | struct hvc_struct *hp; | ||
168 | struct hvc_opal_priv *pv; | ||
169 | hv_protocol_t proto; | ||
170 | unsigned int termno, boot = 0; | ||
171 | const __be32 *reg; | ||
172 | |||
173 | if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) { | ||
174 | proto = HV_PROTOCOL_RAW; | ||
175 | ops = &hvc_opal_raw_ops; | ||
176 | } else if (of_device_is_compatible(dev->dev.of_node, | ||
177 | "ibm,opal-console-hvsi")) { | ||
178 | proto = HV_PROTOCOL_HVSI; | ||
179 | ops = &hvc_opal_hvsi_ops; | ||
180 | } else { | ||
181 | pr_err("hvc_opal: Unknown protocol for %s\n", | ||
182 | dev->dev.of_node->full_name); | ||
183 | return -ENXIO; | ||
184 | } | ||
185 | |||
186 | reg = of_get_property(dev->dev.of_node, "reg", NULL); | ||
187 | termno = reg ? be32_to_cpup(reg) : 0; | ||
188 | |||
189 | /* Is it our boot one ? */ | ||
190 | if (hvc_opal_privs[termno] == &hvc_opal_boot_priv) { | ||
191 | pv = hvc_opal_privs[termno]; | ||
192 | boot = 1; | ||
193 | } else if (hvc_opal_privs[termno] == NULL) { | ||
194 | pv = kzalloc(sizeof(struct hvc_opal_priv), GFP_KERNEL); | ||
195 | if (!pv) | ||
196 | return -ENOMEM; | ||
197 | pv->proto = proto; | ||
198 | hvc_opal_privs[termno] = pv; | ||
199 | if (proto == HV_PROTOCOL_HVSI) | ||
200 | hvsilib_init(&pv->hvsi, opal_get_chars, opal_put_chars, | ||
201 | termno, 0); | ||
202 | |||
203 | /* Instanciate now to establish a mapping index==vtermno */ | ||
204 | hvc_instantiate(termno, termno, ops); | ||
205 | } else { | ||
206 | pr_err("hvc_opal: Device %s has duplicate terminal number #%d\n", | ||
207 | dev->dev.of_node->full_name, termno); | ||
208 | return -ENXIO; | ||
209 | } | ||
210 | |||
211 | pr_info("hvc%d: %s protocol on %s%s\n", termno, | ||
212 | proto == HV_PROTOCOL_RAW ? "raw" : "hvsi", | ||
213 | dev->dev.of_node->full_name, | ||
214 | boot ? " (boot console)" : ""); | ||
215 | |||
216 | /* We don't do IRQ yet */ | ||
217 | hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS); | ||
218 | if (IS_ERR(hp)) | ||
219 | return PTR_ERR(hp); | ||
220 | dev_set_drvdata(&dev->dev, hp); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int hvc_opal_remove(struct platform_device *dev) | ||
226 | { | ||
227 | struct hvc_struct *hp = dev_get_drvdata(&dev->dev); | ||
228 | int rc, termno; | ||
229 | |||
230 | termno = hp->vtermno; | ||
231 | rc = hvc_remove(hp); | ||
232 | if (rc == 0) { | ||
233 | if (hvc_opal_privs[termno] != &hvc_opal_boot_priv) | ||
234 | kfree(hvc_opal_privs[termno]); | ||
235 | hvc_opal_privs[termno] = NULL; | ||
236 | } | ||
237 | return rc; | ||
238 | } | ||
239 | |||
240 | static struct platform_driver hvc_opal_driver = { | ||
241 | .probe = hvc_opal_probe, | ||
242 | .remove = hvc_opal_remove, | ||
243 | .driver = { | ||
244 | .name = hvc_opal_name, | ||
245 | .owner = THIS_MODULE, | ||
246 | .of_match_table = hvc_opal_match, | ||
247 | } | ||
248 | }; | ||
249 | |||
250 | static int __init hvc_opal_init(void) | ||
251 | { | ||
252 | if (!firmware_has_feature(FW_FEATURE_OPAL)) | ||
253 | return -ENODEV; | ||
254 | |||
255 | /* Register as a vio device to receive callbacks */ | ||
256 | return platform_driver_register(&hvc_opal_driver); | ||
257 | } | ||
258 | module_init(hvc_opal_init); | ||
259 | |||
260 | static void __exit hvc_opal_exit(void) | ||
261 | { | ||
262 | platform_driver_unregister(&hvc_opal_driver); | ||
263 | } | ||
264 | module_exit(hvc_opal_exit); | ||
265 | |||
266 | static void udbg_opal_putc(char c) | ||
267 | { | ||
268 | unsigned int termno = hvc_opal_boot_termno; | ||
269 | int count = -1; | ||
270 | |||
271 | if (c == '\n') | ||
272 | udbg_opal_putc('\r'); | ||
273 | |||
274 | do { | ||
275 | switch(hvc_opal_boot_priv.proto) { | ||
276 | case HV_PROTOCOL_RAW: | ||
277 | count = opal_put_chars(termno, &c, 1); | ||
278 | break; | ||
279 | case HV_PROTOCOL_HVSI: | ||
280 | count = hvc_opal_hvsi_put_chars(termno, &c, 1); | ||
281 | break; | ||
282 | } | ||
283 | } while(count == 0 || count == -EAGAIN); | ||
284 | } | ||
285 | |||
286 | static int udbg_opal_getc_poll(void) | ||
287 | { | ||
288 | unsigned int termno = hvc_opal_boot_termno; | ||
289 | int rc = 0; | ||
290 | char c; | ||
291 | |||
292 | switch(hvc_opal_boot_priv.proto) { | ||
293 | case HV_PROTOCOL_RAW: | ||
294 | rc = opal_get_chars(termno, &c, 1); | ||
295 | break; | ||
296 | case HV_PROTOCOL_HVSI: | ||
297 | rc = hvc_opal_hvsi_get_chars(termno, &c, 1); | ||
298 | break; | ||
299 | } | ||
300 | if (!rc) | ||
301 | return -1; | ||
302 | return c; | ||
303 | } | ||
304 | |||
305 | static int udbg_opal_getc(void) | ||
306 | { | ||
307 | int ch; | ||
308 | for (;;) { | ||
309 | ch = udbg_opal_getc_poll(); | ||
310 | if (ch == -1) { | ||
311 | /* This shouldn't be needed...but... */ | ||
312 | volatile unsigned long delay; | ||
313 | for (delay=0; delay < 2000000; delay++) | ||
314 | ; | ||
315 | } else { | ||
316 | return ch; | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | static void udbg_init_opal_common(void) | ||
322 | { | ||
323 | udbg_putc = udbg_opal_putc; | ||
324 | udbg_getc = udbg_opal_getc; | ||
325 | udbg_getc_poll = udbg_opal_getc_poll; | ||
326 | tb_ticks_per_usec = 0x200; /* Make udelay not suck */ | ||
327 | } | ||
328 | |||
329 | void __init hvc_opal_init_early(void) | ||
330 | { | ||
331 | struct device_node *stdout_node = NULL; | ||
332 | const u32 *termno; | ||
333 | const char *name = NULL; | ||
334 | const struct hv_ops *ops; | ||
335 | u32 index; | ||
336 | |||
337 | /* find the boot console from /chosen/stdout */ | ||
338 | if (of_chosen) | ||
339 | name = of_get_property(of_chosen, "linux,stdout-path", NULL); | ||
340 | if (name) { | ||
341 | stdout_node = of_find_node_by_path(name); | ||
342 | if (!stdout_node) { | ||
343 | pr_err("hvc_opal: Failed to locate default console!\n"); | ||
344 | return; | ||
345 | } | ||
346 | } else { | ||
347 | struct device_node *opal, *np; | ||
348 | |||
349 | /* Current OPAL takeover doesn't provide the stdout | ||
350 | * path, so we hard wire it | ||
351 | */ | ||
352 | opal = of_find_node_by_path("/ibm,opal/consoles"); | ||
353 | if (opal) | ||
354 | pr_devel("hvc_opal: Found consoles in new location\n"); | ||
355 | if (!opal) { | ||
356 | opal = of_find_node_by_path("/ibm,opal"); | ||
357 | if (opal) | ||
358 | pr_devel("hvc_opal: " | ||
359 | "Found consoles in old location\n"); | ||
360 | } | ||
361 | if (!opal) | ||
362 | return; | ||
363 | for_each_child_of_node(opal, np) { | ||
364 | if (!strcmp(np->name, "serial")) { | ||
365 | stdout_node = np; | ||
366 | break; | ||
367 | } | ||
368 | } | ||
369 | of_node_put(opal); | ||
370 | } | ||
371 | if (!stdout_node) | ||
372 | return; | ||
373 | termno = of_get_property(stdout_node, "reg", NULL); | ||
374 | index = termno ? *termno : 0; | ||
375 | if (index >= MAX_NR_HVC_CONSOLES) | ||
376 | return; | ||
377 | hvc_opal_privs[index] = &hvc_opal_boot_priv; | ||
378 | |||
379 | /* Check the protocol */ | ||
380 | if (of_device_is_compatible(stdout_node, "ibm,opal-console-raw")) { | ||
381 | hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW; | ||
382 | ops = &hvc_opal_raw_ops; | ||
383 | pr_devel("hvc_opal: Found RAW console\n"); | ||
384 | } | ||
385 | else if (of_device_is_compatible(stdout_node,"ibm,opal-console-hvsi")) { | ||
386 | hvc_opal_boot_priv.proto = HV_PROTOCOL_HVSI; | ||
387 | ops = &hvc_opal_hvsi_ops; | ||
388 | hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, | ||
389 | opal_put_chars, index, 1); | ||
390 | /* HVSI, perform the handshake now */ | ||
391 | hvsilib_establish(&hvc_opal_boot_priv.hvsi); | ||
392 | pr_devel("hvc_opal: Found HVSI console\n"); | ||
393 | } else | ||
394 | goto out; | ||
395 | hvc_opal_boot_termno = index; | ||
396 | udbg_init_opal_common(); | ||
397 | add_preferred_console("hvc", index, NULL); | ||
398 | hvc_instantiate(index, index, ops); | ||
399 | out: | ||
400 | of_node_put(stdout_node); | ||
401 | } | ||
402 | |||
403 | #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW | ||
404 | void __init udbg_init_debug_opal_raw(void) | ||
405 | { | ||
406 | u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; | ||
407 | hvc_opal_privs[index] = &hvc_opal_boot_priv; | ||
408 | hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW; | ||
409 | hvc_opal_boot_termno = index; | ||
410 | udbg_init_opal_common(); | ||
411 | } | ||
412 | #endif /* CONFIG_PPC_EARLY_DEBUG_OPAL_RAW */ | ||
413 | |||
414 | #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI | ||
415 | void __init udbg_init_debug_opal_hvsi(void) | ||
416 | { | ||
417 | u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; | ||
418 | hvc_opal_privs[index] = &hvc_opal_boot_priv; | ||
419 | hvc_opal_boot_termno = index; | ||
420 | udbg_init_opal_common(); | ||
421 | hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, opal_put_chars, | ||
422 | index, 1); | ||
423 | hvsilib_establish(&hvc_opal_boot_priv.hvsi); | ||
424 | } | ||
425 | #endif /* CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI */ | ||
diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c index 0069bb86ba4..61c4a61558d 100644 --- a/drivers/tty/hvc/hvc_rtas.c +++ b/drivers/tty/hvc/hvc_rtas.c | |||
@@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void) | |||
94 | 94 | ||
95 | /* Allocate an hvc_struct for the console device we instantiated | 95 | /* Allocate an hvc_struct for the console device we instantiated |
96 | * earlier. Save off hp so that we can return it on exit */ | 96 | * earlier. Save off hp so that we can return it on exit */ |
97 | hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16); | 97 | hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); |
98 | if (IS_ERR(hp)) | 98 | if (IS_ERR(hp)) |
99 | return PTR_ERR(hp); | 99 | return PTR_ERR(hp); |
100 | 100 | ||
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index 72228276fe3..b0957e61a7b 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c | |||
@@ -36,7 +36,7 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) | |||
36 | { | 36 | { |
37 | int i; | 37 | int i; |
38 | 38 | ||
39 | for (i = 0; i < count && udbg_putc; i++) | 39 | for (i = 0; i < count; i++) |
40 | udbg_putc(buf[i]); | 40 | udbg_putc(buf[i]); |
41 | 41 | ||
42 | return i; | 42 | return i; |
@@ -67,12 +67,9 @@ static int __init hvc_udbg_init(void) | |||
67 | { | 67 | { |
68 | struct hvc_struct *hp; | 68 | struct hvc_struct *hp; |
69 | 69 | ||
70 | if (!udbg_putc) | ||
71 | return -ENODEV; | ||
72 | |||
73 | BUG_ON(hvc_udbg_dev); | 70 | BUG_ON(hvc_udbg_dev); |
74 | 71 | ||
75 | hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16); | 72 | hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); |
76 | if (IS_ERR(hp)) | 73 | if (IS_ERR(hp)) |
77 | return PTR_ERR(hp); | 74 | return PTR_ERR(hp); |
78 | 75 | ||
@@ -91,9 +88,6 @@ module_exit(hvc_udbg_exit); | |||
91 | 88 | ||
92 | static int __init hvc_udbg_console_init(void) | 89 | static int __init hvc_udbg_console_init(void) |
93 | { | 90 | { |
94 | if (!udbg_putc) | ||
95 | return -ENODEV; | ||
96 | |||
97 | hvc_instantiate(0, 0, &hvc_udbg_ops); | 91 | hvc_instantiate(0, 0, &hvc_udbg_ops); |
98 | add_preferred_console("hvc", 0, NULL); | 92 | add_preferred_console("hvc", 0, NULL); |
99 | 93 | ||
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 0c629807610..130aace67f3 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c | |||
@@ -41,11 +41,11 @@ | |||
41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/console.h> | 43 | #include <linux/console.h> |
44 | #include <linux/module.h> | ||
45 | 44 | ||
46 | #include <asm/hvconsole.h> | 45 | #include <asm/hvconsole.h> |
47 | #include <asm/vio.h> | 46 | #include <asm/vio.h> |
48 | #include <asm/prom.h> | 47 | #include <asm/prom.h> |
48 | #include <asm/firmware.h> | ||
49 | #include <asm/hvsi.h> | 49 | #include <asm/hvsi.h> |
50 | #include <asm/udbg.h> | 50 | #include <asm/udbg.h> |
51 | 51 | ||
@@ -53,7 +53,7 @@ | |||
53 | 53 | ||
54 | static const char hvc_driver_name[] = "hvc_console"; | 54 | static const char hvc_driver_name[] = "hvc_console"; |
55 | 55 | ||
56 | static struct vio_device_id hvc_driver_table[] = { | 56 | static struct vio_device_id hvc_driver_table[] __devinitdata = { |
57 | {"serial", "hvterm1"}, | 57 | {"serial", "hvterm1"}, |
58 | #ifndef HVC_OLD_HVSI | 58 | #ifndef HVC_OLD_HVSI |
59 | {"serial", "hvterm-protocol"}, | 59 | {"serial", "hvterm-protocol"}, |
@@ -230,70 +230,7 @@ static const struct hv_ops hvterm_hvsi_ops = { | |||
230 | .tiocmset = hvterm_hvsi_tiocmset, | 230 | .tiocmset = hvterm_hvsi_tiocmset, |
231 | }; | 231 | }; |
232 | 232 | ||
233 | static void udbg_hvc_putc(char c) | 233 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, |
234 | { | ||
235 | int count = -1; | ||
236 | |||
237 | if (!hvterm_privs[0]) | ||
238 | return; | ||
239 | |||
240 | if (c == '\n') | ||
241 | udbg_hvc_putc('\r'); | ||
242 | |||
243 | do { | ||
244 | switch(hvterm_privs[0]->proto) { | ||
245 | case HV_PROTOCOL_RAW: | ||
246 | count = hvterm_raw_put_chars(0, &c, 1); | ||
247 | break; | ||
248 | case HV_PROTOCOL_HVSI: | ||
249 | count = hvterm_hvsi_put_chars(0, &c, 1); | ||
250 | break; | ||
251 | } | ||
252 | } while(count == 0); | ||
253 | } | ||
254 | |||
255 | static int udbg_hvc_getc_poll(void) | ||
256 | { | ||
257 | int rc = 0; | ||
258 | char c; | ||
259 | |||
260 | if (!hvterm_privs[0]) | ||
261 | return -1; | ||
262 | |||
263 | switch(hvterm_privs[0]->proto) { | ||
264 | case HV_PROTOCOL_RAW: | ||
265 | rc = hvterm_raw_get_chars(0, &c, 1); | ||
266 | break; | ||
267 | case HV_PROTOCOL_HVSI: | ||
268 | rc = hvterm_hvsi_get_chars(0, &c, 1); | ||
269 | break; | ||
270 | } | ||
271 | if (!rc) | ||
272 | return -1; | ||
273 | return c; | ||
274 | } | ||
275 | |||
276 | static int udbg_hvc_getc(void) | ||
277 | { | ||
278 | int ch; | ||
279 | |||
280 | if (!hvterm_privs[0]) | ||
281 | return -1; | ||
282 | |||
283 | for (;;) { | ||
284 | ch = udbg_hvc_getc_poll(); | ||
285 | if (ch == -1) { | ||
286 | /* This shouldn't be needed...but... */ | ||
287 | volatile unsigned long delay; | ||
288 | for (delay=0; delay < 2000000; delay++) | ||
289 | ; | ||
290 | } else { | ||
291 | return ch; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static int hvc_vio_probe(struct vio_dev *vdev, | ||
297 | const struct vio_device_id *id) | 234 | const struct vio_device_id *id) |
298 | { | 235 | { |
299 | const struct hv_ops *ops; | 236 | const struct hv_ops *ops; |
@@ -313,7 +250,7 @@ static int hvc_vio_probe(struct vio_dev *vdev, | |||
313 | proto = HV_PROTOCOL_HVSI; | 250 | proto = HV_PROTOCOL_HVSI; |
314 | ops = &hvterm_hvsi_ops; | 251 | ops = &hvterm_hvsi_ops; |
315 | } else { | 252 | } else { |
316 | pr_err("hvc_vio: Unknown protocol for %s\n", vdev->dev.of_node->full_name); | 253 | pr_err("hvc_vio: Unkown protocol for %s\n", vdev->dev.of_node->full_name); |
317 | return -ENXIO; | 254 | return -ENXIO; |
318 | } | 255 | } |
319 | 256 | ||
@@ -352,17 +289,10 @@ static int hvc_vio_probe(struct vio_dev *vdev, | |||
352 | return PTR_ERR(hp); | 289 | return PTR_ERR(hp); |
353 | dev_set_drvdata(&vdev->dev, hp); | 290 | dev_set_drvdata(&vdev->dev, hp); |
354 | 291 | ||
355 | /* register udbg if it's not there already for console 0 */ | ||
356 | if (hp->index == 0 && !udbg_putc) { | ||
357 | udbg_putc = udbg_hvc_putc; | ||
358 | udbg_getc = udbg_hvc_getc; | ||
359 | udbg_getc_poll = udbg_hvc_getc_poll; | ||
360 | } | ||
361 | |||
362 | return 0; | 292 | return 0; |
363 | } | 293 | } |
364 | 294 | ||
365 | static int hvc_vio_remove(struct vio_dev *vdev) | 295 | static int __devexit hvc_vio_remove(struct vio_dev *vdev) |
366 | { | 296 | { |
367 | struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); | 297 | struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); |
368 | int rc, termno; | 298 | int rc, termno; |
@@ -380,14 +310,20 @@ static int hvc_vio_remove(struct vio_dev *vdev) | |||
380 | static struct vio_driver hvc_vio_driver = { | 310 | static struct vio_driver hvc_vio_driver = { |
381 | .id_table = hvc_driver_table, | 311 | .id_table = hvc_driver_table, |
382 | .probe = hvc_vio_probe, | 312 | .probe = hvc_vio_probe, |
383 | .remove = hvc_vio_remove, | 313 | .remove = __devexit_p(hvc_vio_remove), |
384 | .name = hvc_driver_name, | 314 | .driver = { |
315 | .name = hvc_driver_name, | ||
316 | .owner = THIS_MODULE, | ||
317 | } | ||
385 | }; | 318 | }; |
386 | 319 | ||
387 | static int __init hvc_vio_init(void) | 320 | static int __init hvc_vio_init(void) |
388 | { | 321 | { |
389 | int rc; | 322 | int rc; |
390 | 323 | ||
324 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
325 | return -EIO; | ||
326 | |||
391 | /* Register as a vio device to receive callbacks */ | 327 | /* Register as a vio device to receive callbacks */ |
392 | rc = vio_register_driver(&hvc_vio_driver); | 328 | rc = vio_register_driver(&hvc_vio_driver); |
393 | 329 | ||
@@ -401,6 +337,59 @@ static void __exit hvc_vio_exit(void) | |||
401 | } | 337 | } |
402 | module_exit(hvc_vio_exit); | 338 | module_exit(hvc_vio_exit); |
403 | 339 | ||
340 | static void udbg_hvc_putc(char c) | ||
341 | { | ||
342 | int count = -1; | ||
343 | |||
344 | if (c == '\n') | ||
345 | udbg_hvc_putc('\r'); | ||
346 | |||
347 | do { | ||
348 | switch(hvterm_priv0.proto) { | ||
349 | case HV_PROTOCOL_RAW: | ||
350 | count = hvterm_raw_put_chars(0, &c, 1); | ||
351 | break; | ||
352 | case HV_PROTOCOL_HVSI: | ||
353 | count = hvterm_hvsi_put_chars(0, &c, 1); | ||
354 | break; | ||
355 | } | ||
356 | } while(count == 0); | ||
357 | } | ||
358 | |||
359 | static int udbg_hvc_getc_poll(void) | ||
360 | { | ||
361 | int rc = 0; | ||
362 | char c; | ||
363 | |||
364 | switch(hvterm_priv0.proto) { | ||
365 | case HV_PROTOCOL_RAW: | ||
366 | rc = hvterm_raw_get_chars(0, &c, 1); | ||
367 | break; | ||
368 | case HV_PROTOCOL_HVSI: | ||
369 | rc = hvterm_hvsi_get_chars(0, &c, 1); | ||
370 | break; | ||
371 | } | ||
372 | if (!rc) | ||
373 | return -1; | ||
374 | return c; | ||
375 | } | ||
376 | |||
377 | static int udbg_hvc_getc(void) | ||
378 | { | ||
379 | int ch; | ||
380 | for (;;) { | ||
381 | ch = udbg_hvc_getc_poll(); | ||
382 | if (ch == -1) { | ||
383 | /* This shouldn't be needed...but... */ | ||
384 | volatile unsigned long delay; | ||
385 | for (delay=0; delay < 2000000; delay++) | ||
386 | ; | ||
387 | } else { | ||
388 | return ch; | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
404 | void __init hvc_vio_init_early(void) | 393 | void __init hvc_vio_init_early(void) |
405 | { | 394 | { |
406 | struct device_node *stdout_node; | 395 | struct device_node *stdout_node; |
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 19843ec3f80..52fdf60bdbe 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c | |||
@@ -21,78 +21,46 @@ | |||
21 | #include <linux/console.h> | 21 | #include <linux/console.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <linux/irq.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/types.h> | 25 | #include <linux/types.h> |
27 | #include <linux/list.h> | ||
28 | 26 | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/xen/hypervisor.h> | 27 | #include <asm/xen/hypervisor.h> |
31 | 28 | ||
32 | #include <xen/xen.h> | 29 | #include <xen/xen.h> |
33 | #include <xen/interface/xen.h> | ||
34 | #include <xen/hvm.h> | ||
35 | #include <xen/grant_table.h> | ||
36 | #include <xen/page.h> | 30 | #include <xen/page.h> |
37 | #include <xen/events.h> | 31 | #include <xen/events.h> |
38 | #include <xen/interface/io/console.h> | 32 | #include <xen/interface/io/console.h> |
39 | #include <xen/interface/sched.h> | ||
40 | #include <xen/hvc-console.h> | 33 | #include <xen/hvc-console.h> |
41 | #include <xen/xenbus.h> | ||
42 | 34 | ||
43 | #include "hvc_console.h" | 35 | #include "hvc_console.h" |
44 | 36 | ||
45 | #define HVC_COOKIE 0x58656e /* "Xen" in hex */ | 37 | #define HVC_COOKIE 0x58656e /* "Xen" in hex */ |
46 | 38 | ||
47 | struct xencons_info { | 39 | static struct hvc_struct *hvc; |
48 | struct list_head list; | 40 | static int xencons_irq; |
49 | struct xenbus_device *xbdev; | ||
50 | struct xencons_interface *intf; | ||
51 | unsigned int evtchn; | ||
52 | struct hvc_struct *hvc; | ||
53 | int irq; | ||
54 | int vtermno; | ||
55 | grant_ref_t gntref; | ||
56 | }; | ||
57 | |||
58 | static LIST_HEAD(xenconsoles); | ||
59 | static DEFINE_SPINLOCK(xencons_lock); | ||
60 | 41 | ||
61 | /* ------------------------------------------------------------------ */ | 42 | /* ------------------------------------------------------------------ */ |
62 | 43 | ||
63 | static struct xencons_info *vtermno_to_xencons(int vtermno) | 44 | static unsigned long console_pfn = ~0ul; |
64 | { | ||
65 | struct xencons_info *entry, *n, *ret = NULL; | ||
66 | |||
67 | if (list_empty(&xenconsoles)) | ||
68 | return NULL; | ||
69 | 45 | ||
70 | list_for_each_entry_safe(entry, n, &xenconsoles, list) { | 46 | static inline struct xencons_interface *xencons_interface(void) |
71 | if (entry->vtermno == vtermno) { | ||
72 | ret = entry; | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | static inline int xenbus_devid_to_vtermno(int devid) | ||
81 | { | 47 | { |
82 | return devid + HVC_COOKIE; | 48 | if (console_pfn == ~0ul) |
49 | return mfn_to_virt(xen_start_info->console.domU.mfn); | ||
50 | else | ||
51 | return __va(console_pfn << PAGE_SHIFT); | ||
83 | } | 52 | } |
84 | 53 | ||
85 | static inline void notify_daemon(struct xencons_info *cons) | 54 | static inline void notify_daemon(void) |
86 | { | 55 | { |
87 | /* Use evtchn: this is called early, before irq is set up. */ | 56 | /* Use evtchn: this is called early, before irq is set up. */ |
88 | notify_remote_via_evtchn(cons->evtchn); | 57 | notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); |
89 | } | 58 | } |
90 | 59 | ||
91 | static int __write_console(struct xencons_info *xencons, | 60 | static int __write_console(const char *data, int len) |
92 | const char *data, int len) | ||
93 | { | 61 | { |
62 | struct xencons_interface *intf = xencons_interface(); | ||
94 | XENCONS_RING_IDX cons, prod; | 63 | XENCONS_RING_IDX cons, prod; |
95 | struct xencons_interface *intf = xencons->intf; | ||
96 | int sent = 0; | 64 | int sent = 0; |
97 | 65 | ||
98 | cons = intf->out_cons; | 66 | cons = intf->out_cons; |
@@ -107,16 +75,13 @@ static int __write_console(struct xencons_info *xencons, | |||
107 | intf->out_prod = prod; | 75 | intf->out_prod = prod; |
108 | 76 | ||
109 | if (sent) | 77 | if (sent) |
110 | notify_daemon(xencons); | 78 | notify_daemon(); |
111 | return sent; | 79 | return sent; |
112 | } | 80 | } |
113 | 81 | ||
114 | static int domU_write_console(uint32_t vtermno, const char *data, int len) | 82 | static int domU_write_console(uint32_t vtermno, const char *data, int len) |
115 | { | 83 | { |
116 | int ret = len; | 84 | int ret = len; |
117 | struct xencons_info *cons = vtermno_to_xencons(vtermno); | ||
118 | if (cons == NULL) | ||
119 | return -EINVAL; | ||
120 | 85 | ||
121 | /* | 86 | /* |
122 | * Make sure the whole buffer is emitted, polling if | 87 | * Make sure the whole buffer is emitted, polling if |
@@ -125,7 +90,7 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) | |||
125 | * kernel is crippled. | 90 | * kernel is crippled. |
126 | */ | 91 | */ |
127 | while (len) { | 92 | while (len) { |
128 | int sent = __write_console(cons, data, len); | 93 | int sent = __write_console(data, len); |
129 | 94 | ||
130 | data += sent; | 95 | data += sent; |
131 | len -= sent; | 96 | len -= sent; |
@@ -139,13 +104,9 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) | |||
139 | 104 | ||
140 | static int domU_read_console(uint32_t vtermno, char *buf, int len) | 105 | static int domU_read_console(uint32_t vtermno, char *buf, int len) |
141 | { | 106 | { |
142 | struct xencons_interface *intf; | 107 | struct xencons_interface *intf = xencons_interface(); |
143 | XENCONS_RING_IDX cons, prod; | 108 | XENCONS_RING_IDX cons, prod; |
144 | int recv = 0; | 109 | int recv = 0; |
145 | struct xencons_info *xencons = vtermno_to_xencons(vtermno); | ||
146 | if (xencons == NULL) | ||
147 | return -EINVAL; | ||
148 | intf = xencons->intf; | ||
149 | 110 | ||
150 | cons = intf->in_cons; | 111 | cons = intf->in_cons; |
151 | prod = intf->in_prod; | 112 | prod = intf->in_prod; |
@@ -158,7 +119,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len) | |||
158 | mb(); /* read ring before consuming */ | 119 | mb(); /* read ring before consuming */ |
159 | intf->in_cons = cons; | 120 | intf->in_cons = cons; |
160 | 121 | ||
161 | notify_daemon(xencons); | 122 | notify_daemon(); |
162 | return recv; | 123 | return recv; |
163 | } | 124 | } |
164 | 125 | ||
@@ -196,410 +157,68 @@ static struct hv_ops dom0_hvc_ops = { | |||
196 | .notifier_hangup = notifier_hangup_irq, | 157 | .notifier_hangup = notifier_hangup_irq, |
197 | }; | 158 | }; |
198 | 159 | ||
199 | static int xen_hvm_console_init(void) | 160 | static int __init xen_hvc_init(void) |
200 | { | ||
201 | int r; | ||
202 | uint64_t v = 0; | ||
203 | unsigned long mfn; | ||
204 | struct xencons_info *info; | ||
205 | |||
206 | if (!xen_hvm_domain()) | ||
207 | return -ENODEV; | ||
208 | |||
209 | info = vtermno_to_xencons(HVC_COOKIE); | ||
210 | if (!info) { | ||
211 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | ||
212 | if (!info) | ||
213 | return -ENOMEM; | ||
214 | } else if (info->intf != NULL) { | ||
215 | /* already configured */ | ||
216 | return 0; | ||
217 | } | ||
218 | /* | ||
219 | * If the toolstack (or the hypervisor) hasn't set these values, the | ||
220 | * default value is 0. Even though mfn = 0 and evtchn = 0 are | ||
221 | * theoretically correct values, in practice they never are and they | ||
222 | * mean that a legacy toolstack hasn't initialized the pv console correctly. | ||
223 | */ | ||
224 | r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); | ||
225 | if (r < 0 || v == 0) | ||
226 | goto err; | ||
227 | info->evtchn = v; | ||
228 | v = 0; | ||
229 | r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); | ||
230 | if (r < 0 || v == 0) | ||
231 | goto err; | ||
232 | mfn = v; | ||
233 | info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE); | ||
234 | if (info->intf == NULL) | ||
235 | goto err; | ||
236 | info->vtermno = HVC_COOKIE; | ||
237 | |||
238 | spin_lock(&xencons_lock); | ||
239 | list_add_tail(&info->list, &xenconsoles); | ||
240 | spin_unlock(&xencons_lock); | ||
241 | |||
242 | return 0; | ||
243 | err: | ||
244 | kfree(info); | ||
245 | return -ENODEV; | ||
246 | } | ||
247 | |||
248 | static int xen_pv_console_init(void) | ||
249 | { | 161 | { |
250 | struct xencons_info *info; | 162 | struct hvc_struct *hp; |
163 | struct hv_ops *ops; | ||
251 | 164 | ||
252 | if (!xen_pv_domain()) | 165 | if (!xen_pv_domain()) |
253 | return -ENODEV; | 166 | return -ENODEV; |
254 | 167 | ||
255 | if (!xen_start_info->console.domU.evtchn) | 168 | if (xen_initial_domain()) { |
256 | return -ENODEV; | 169 | ops = &dom0_hvc_ops; |
257 | 170 | xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); | |
258 | info = vtermno_to_xencons(HVC_COOKIE); | 171 | } else { |
259 | if (!info) { | 172 | if (!xen_start_info->console.domU.evtchn) |
260 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | 173 | return -ENODEV; |
261 | if (!info) | ||
262 | return -ENOMEM; | ||
263 | } else if (info->intf != NULL) { | ||
264 | /* already configured */ | ||
265 | return 0; | ||
266 | } | ||
267 | info->evtchn = xen_start_info->console.domU.evtchn; | ||
268 | info->intf = mfn_to_virt(xen_start_info->console.domU.mfn); | ||
269 | info->vtermno = HVC_COOKIE; | ||
270 | |||
271 | spin_lock(&xencons_lock); | ||
272 | list_add_tail(&info->list, &xenconsoles); | ||
273 | spin_unlock(&xencons_lock); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int xen_initial_domain_console_init(void) | ||
279 | { | ||
280 | struct xencons_info *info; | ||
281 | |||
282 | if (!xen_initial_domain()) | ||
283 | return -ENODEV; | ||
284 | |||
285 | info = vtermno_to_xencons(HVC_COOKIE); | ||
286 | if (!info) { | ||
287 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | ||
288 | if (!info) | ||
289 | return -ENOMEM; | ||
290 | } | ||
291 | |||
292 | info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); | ||
293 | info->vtermno = HVC_COOKIE; | ||
294 | |||
295 | spin_lock(&xencons_lock); | ||
296 | list_add_tail(&info->list, &xenconsoles); | ||
297 | spin_unlock(&xencons_lock); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | void xen_console_resume(void) | ||
303 | { | ||
304 | struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE); | ||
305 | if (info != NULL && info->irq) | ||
306 | rebind_evtchn_irq(info->evtchn, info->irq); | ||
307 | } | ||
308 | |||
309 | static void xencons_disconnect_backend(struct xencons_info *info) | ||
310 | { | ||
311 | if (info->irq > 0) | ||
312 | unbind_from_irqhandler(info->irq, NULL); | ||
313 | info->irq = 0; | ||
314 | if (info->evtchn > 0) | ||
315 | xenbus_free_evtchn(info->xbdev, info->evtchn); | ||
316 | info->evtchn = 0; | ||
317 | if (info->gntref > 0) | ||
318 | gnttab_free_grant_references(info->gntref); | ||
319 | info->gntref = 0; | ||
320 | if (info->hvc != NULL) | ||
321 | hvc_remove(info->hvc); | ||
322 | info->hvc = NULL; | ||
323 | } | ||
324 | |||
325 | static void xencons_free(struct xencons_info *info) | ||
326 | { | ||
327 | free_page((unsigned long)info->intf); | ||
328 | info->intf = NULL; | ||
329 | info->vtermno = 0; | ||
330 | kfree(info); | ||
331 | } | ||
332 | 174 | ||
333 | static int xen_console_remove(struct xencons_info *info) | 175 | ops = &domU_hvc_ops; |
334 | { | 176 | xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); |
335 | xencons_disconnect_backend(info); | ||
336 | spin_lock(&xencons_lock); | ||
337 | list_del(&info->list); | ||
338 | spin_unlock(&xencons_lock); | ||
339 | if (info->xbdev != NULL) | ||
340 | xencons_free(info); | ||
341 | else { | ||
342 | if (xen_hvm_domain()) | ||
343 | iounmap(info->intf); | ||
344 | kfree(info); | ||
345 | } | 177 | } |
346 | return 0; | 178 | if (xencons_irq < 0) |
347 | } | 179 | xencons_irq = 0; /* NO_IRQ */ |
348 | |||
349 | #ifdef CONFIG_HVC_XEN_FRONTEND | ||
350 | static struct xenbus_driver xencons_driver; | ||
351 | |||
352 | static int xencons_remove(struct xenbus_device *dev) | ||
353 | { | ||
354 | return xen_console_remove(dev_get_drvdata(&dev->dev)); | ||
355 | } | ||
356 | |||
357 | static int xencons_connect_backend(struct xenbus_device *dev, | ||
358 | struct xencons_info *info) | ||
359 | { | ||
360 | int ret, evtchn, devid, ref, irq; | ||
361 | struct xenbus_transaction xbt; | ||
362 | grant_ref_t gref_head; | ||
363 | unsigned long mfn; | ||
364 | |||
365 | ret = xenbus_alloc_evtchn(dev, &evtchn); | ||
366 | if (ret) | ||
367 | return ret; | ||
368 | info->evtchn = evtchn; | ||
369 | irq = bind_evtchn_to_irq(evtchn); | ||
370 | if (irq < 0) | ||
371 | return irq; | ||
372 | info->irq = irq; | ||
373 | devid = dev->nodename[strlen(dev->nodename) - 1] - '0'; | ||
374 | info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid), | ||
375 | irq, &domU_hvc_ops, 256); | ||
376 | if (IS_ERR(info->hvc)) | ||
377 | return PTR_ERR(info->hvc); | ||
378 | if (xen_pv_domain()) | ||
379 | mfn = virt_to_mfn(info->intf); | ||
380 | else | 180 | else |
381 | mfn = __pa(info->intf) >> PAGE_SHIFT; | 181 | irq_set_noprobe(xencons_irq); |
382 | ret = gnttab_alloc_grant_references(1, &gref_head); | ||
383 | if (ret < 0) | ||
384 | return ret; | ||
385 | info->gntref = gref_head; | ||
386 | ref = gnttab_claim_grant_reference(&gref_head); | ||
387 | if (ref < 0) | ||
388 | return ref; | ||
389 | gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, | ||
390 | mfn, 0); | ||
391 | |||
392 | again: | ||
393 | ret = xenbus_transaction_start(&xbt); | ||
394 | if (ret) { | ||
395 | xenbus_dev_fatal(dev, ret, "starting transaction"); | ||
396 | return ret; | ||
397 | } | ||
398 | ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref); | ||
399 | if (ret) | ||
400 | goto error_xenbus; | ||
401 | ret = xenbus_printf(xbt, dev->nodename, "port", "%u", | ||
402 | evtchn); | ||
403 | if (ret) | ||
404 | goto error_xenbus; | ||
405 | ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu"); | ||
406 | if (ret) | ||
407 | goto error_xenbus; | ||
408 | ret = xenbus_transaction_end(xbt, 0); | ||
409 | if (ret) { | ||
410 | if (ret == -EAGAIN) | ||
411 | goto again; | ||
412 | xenbus_dev_fatal(dev, ret, "completing transaction"); | ||
413 | return ret; | ||
414 | } | ||
415 | 182 | ||
416 | xenbus_switch_state(dev, XenbusStateInitialised); | 183 | hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); |
417 | return 0; | 184 | if (IS_ERR(hp)) |
185 | return PTR_ERR(hp); | ||
418 | 186 | ||
419 | error_xenbus: | 187 | hvc = hp; |
420 | xenbus_transaction_end(xbt, 1); | ||
421 | xenbus_dev_fatal(dev, ret, "writing xenstore"); | ||
422 | return ret; | ||
423 | } | ||
424 | 188 | ||
425 | static int xencons_probe(struct xenbus_device *dev, | 189 | console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn); |
426 | const struct xenbus_device_id *id) | ||
427 | { | ||
428 | int ret, devid; | ||
429 | struct xencons_info *info; | ||
430 | |||
431 | devid = dev->nodename[strlen(dev->nodename) - 1] - '0'; | ||
432 | if (devid == 0) | ||
433 | return -ENODEV; | ||
434 | |||
435 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); | ||
436 | if (!info) | ||
437 | return -ENOMEM; | ||
438 | dev_set_drvdata(&dev->dev, info); | ||
439 | info->xbdev = dev; | ||
440 | info->vtermno = xenbus_devid_to_vtermno(devid); | ||
441 | info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
442 | if (!info->intf) | ||
443 | goto error_nomem; | ||
444 | |||
445 | ret = xencons_connect_backend(dev, info); | ||
446 | if (ret < 0) | ||
447 | goto error; | ||
448 | spin_lock(&xencons_lock); | ||
449 | list_add_tail(&info->list, &xenconsoles); | ||
450 | spin_unlock(&xencons_lock); | ||
451 | 190 | ||
452 | return 0; | 191 | return 0; |
453 | |||
454 | error_nomem: | ||
455 | ret = -ENOMEM; | ||
456 | xenbus_dev_fatal(dev, ret, "allocating device memory"); | ||
457 | error: | ||
458 | xencons_disconnect_backend(info); | ||
459 | xencons_free(info); | ||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | static int xencons_resume(struct xenbus_device *dev) | ||
464 | { | ||
465 | struct xencons_info *info = dev_get_drvdata(&dev->dev); | ||
466 | |||
467 | xencons_disconnect_backend(info); | ||
468 | memset(info->intf, 0, PAGE_SIZE); | ||
469 | return xencons_connect_backend(dev, info); | ||
470 | } | ||
471 | |||
472 | static void xencons_backend_changed(struct xenbus_device *dev, | ||
473 | enum xenbus_state backend_state) | ||
474 | { | ||
475 | switch (backend_state) { | ||
476 | case XenbusStateReconfiguring: | ||
477 | case XenbusStateReconfigured: | ||
478 | case XenbusStateInitialising: | ||
479 | case XenbusStateInitialised: | ||
480 | case XenbusStateUnknown: | ||
481 | break; | ||
482 | |||
483 | case XenbusStateInitWait: | ||
484 | break; | ||
485 | |||
486 | case XenbusStateConnected: | ||
487 | xenbus_switch_state(dev, XenbusStateConnected); | ||
488 | break; | ||
489 | |||
490 | case XenbusStateClosed: | ||
491 | if (dev->state == XenbusStateClosed) | ||
492 | break; | ||
493 | /* Missed the backend's CLOSING state -- fallthrough */ | ||
494 | case XenbusStateClosing: | ||
495 | xenbus_frontend_closed(dev); | ||
496 | break; | ||
497 | } | ||
498 | } | 192 | } |
499 | 193 | ||
500 | static const struct xenbus_device_id xencons_ids[] = { | 194 | void xen_console_resume(void) |
501 | { "console" }, | ||
502 | { "" } | ||
503 | }; | ||
504 | |||
505 | |||
506 | static DEFINE_XENBUS_DRIVER(xencons, "xenconsole", | ||
507 | .probe = xencons_probe, | ||
508 | .remove = xencons_remove, | ||
509 | .resume = xencons_resume, | ||
510 | .otherend_changed = xencons_backend_changed, | ||
511 | ); | ||
512 | #endif /* CONFIG_HVC_XEN_FRONTEND */ | ||
513 | |||
514 | static int __init xen_hvc_init(void) | ||
515 | { | 195 | { |
516 | int r; | 196 | if (xencons_irq) |
517 | struct xencons_info *info; | 197 | rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); |
518 | const struct hv_ops *ops; | ||
519 | |||
520 | if (!xen_domain()) | ||
521 | return -ENODEV; | ||
522 | |||
523 | if (xen_initial_domain()) { | ||
524 | ops = &dom0_hvc_ops; | ||
525 | r = xen_initial_domain_console_init(); | ||
526 | if (r < 0) | ||
527 | return r; | ||
528 | info = vtermno_to_xencons(HVC_COOKIE); | ||
529 | } else { | ||
530 | ops = &domU_hvc_ops; | ||
531 | if (xen_hvm_domain()) | ||
532 | r = xen_hvm_console_init(); | ||
533 | else | ||
534 | r = xen_pv_console_init(); | ||
535 | if (r < 0) | ||
536 | return r; | ||
537 | |||
538 | info = vtermno_to_xencons(HVC_COOKIE); | ||
539 | info->irq = bind_evtchn_to_irq(info->evtchn); | ||
540 | } | ||
541 | if (info->irq < 0) | ||
542 | info->irq = 0; /* NO_IRQ */ | ||
543 | else | ||
544 | irq_set_noprobe(info->irq); | ||
545 | |||
546 | info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256); | ||
547 | if (IS_ERR(info->hvc)) { | ||
548 | r = PTR_ERR(info->hvc); | ||
549 | spin_lock(&xencons_lock); | ||
550 | list_del(&info->list); | ||
551 | spin_unlock(&xencons_lock); | ||
552 | if (info->irq) | ||
553 | unbind_from_irqhandler(info->irq, NULL); | ||
554 | kfree(info); | ||
555 | return r; | ||
556 | } | ||
557 | |||
558 | r = 0; | ||
559 | #ifdef CONFIG_HVC_XEN_FRONTEND | ||
560 | r = xenbus_register_frontend(&xencons_driver); | ||
561 | #endif | ||
562 | return r; | ||
563 | } | 198 | } |
564 | 199 | ||
565 | static void __exit xen_hvc_fini(void) | 200 | static void __exit xen_hvc_fini(void) |
566 | { | 201 | { |
567 | struct xencons_info *entry, *next; | 202 | if (hvc) |
568 | 203 | hvc_remove(hvc); | |
569 | if (list_empty(&xenconsoles)) | ||
570 | return; | ||
571 | |||
572 | list_for_each_entry_safe(entry, next, &xenconsoles, list) { | ||
573 | xen_console_remove(entry); | ||
574 | } | ||
575 | } | 204 | } |
576 | 205 | ||
577 | static int xen_cons_init(void) | 206 | static int xen_cons_init(void) |
578 | { | 207 | { |
579 | const struct hv_ops *ops; | 208 | struct hv_ops *ops; |
580 | 209 | ||
581 | if (!xen_domain()) | 210 | if (!xen_pv_domain()) |
582 | return 0; | 211 | return 0; |
583 | 212 | ||
584 | if (xen_initial_domain()) | 213 | if (xen_initial_domain()) |
585 | ops = &dom0_hvc_ops; | 214 | ops = &dom0_hvc_ops; |
586 | else { | 215 | else |
587 | int r; | ||
588 | ops = &domU_hvc_ops; | 216 | ops = &domU_hvc_ops; |
589 | 217 | ||
590 | if (xen_hvm_domain()) | ||
591 | r = xen_hvm_console_init(); | ||
592 | else | ||
593 | r = xen_pv_console_init(); | ||
594 | if (r < 0) | ||
595 | return r; | ||
596 | } | ||
597 | |||
598 | hvc_instantiate(HVC_COOKIE, 0, ops); | 218 | hvc_instantiate(HVC_COOKIE, 0, ops); |
599 | return 0; | 219 | return 0; |
600 | } | 220 | } |
601 | 221 | ||
602 | |||
603 | module_init(xen_hvc_init); | 222 | module_init(xen_hvc_init); |
604 | module_exit(xen_hvc_fini); | 223 | module_exit(xen_hvc_fini); |
605 | console_initcall(xen_cons_init); | 224 | console_initcall(xen_cons_init); |
@@ -611,9 +230,6 @@ static void xenboot_write_console(struct console *console, const char *string, | |||
611 | unsigned int linelen, off = 0; | 230 | unsigned int linelen, off = 0; |
612 | const char *pos; | 231 | const char *pos; |
613 | 232 | ||
614 | if (!xen_pv_domain()) | ||
615 | return; | ||
616 | |||
617 | dom0_write_console(0, string, len); | 233 | dom0_write_console(0, string, len); |
618 | 234 | ||
619 | if (xen_initial_domain()) | 235 | if (xen_initial_domain()) |
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 87763573395..4c8b6654693 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c | |||
@@ -261,7 +261,6 @@ static DEFINE_SPINLOCK(hvcs_pi_lock); | |||
261 | 261 | ||
262 | /* One vty-server per hvcs_struct */ | 262 | /* One vty-server per hvcs_struct */ |
263 | struct hvcs_struct { | 263 | struct hvcs_struct { |
264 | struct tty_port port; | ||
265 | spinlock_t lock; | 264 | spinlock_t lock; |
266 | 265 | ||
267 | /* | 266 | /* |
@@ -270,6 +269,9 @@ struct hvcs_struct { | |||
270 | */ | 269 | */ |
271 | unsigned int index; | 270 | unsigned int index; |
272 | 271 | ||
272 | struct tty_struct *tty; | ||
273 | int open_count; | ||
274 | |||
273 | /* | 275 | /* |
274 | * Used to tell the driver kernel_thread what operations need to take | 276 | * Used to tell the driver kernel_thread what operations need to take |
275 | * place upon this hvcs_struct instance. | 277 | * place upon this hvcs_struct instance. |
@@ -288,11 +290,12 @@ struct hvcs_struct { | |||
288 | int chars_in_buffer; | 290 | int chars_in_buffer; |
289 | 291 | ||
290 | /* | 292 | /* |
291 | * Any variable below is valid before a tty is connected and | 293 | * Any variable below the kref is valid before a tty is connected and |
292 | * stays valid after the tty is disconnected. These shouldn't be | 294 | * stays valid after the tty is disconnected. These shouldn't be |
293 | * whacked until the kobject refcount reaches zero though some entries | 295 | * whacked until the kobject refcount reaches zero though some entries |
294 | * may be changed via sysfs initiatives. | 296 | * may be changed via sysfs initiatives. |
295 | */ | 297 | */ |
298 | struct kref kref; /* ref count & hvcs_struct lifetime */ | ||
296 | int connected; /* is the vty-server currently connected to a vty? */ | 299 | int connected; /* is the vty-server currently connected to a vty? */ |
297 | uint32_t p_unit_address; /* partner unit address */ | 300 | uint32_t p_unit_address; /* partner unit address */ |
298 | uint32_t p_partition_ID; /* partner partition ID */ | 301 | uint32_t p_partition_ID; /* partner partition ID */ |
@@ -301,6 +304,9 @@ struct hvcs_struct { | |||
301 | struct vio_dev *vdev; | 304 | struct vio_dev *vdev; |
302 | }; | 305 | }; |
303 | 306 | ||
307 | /* Required to back map a kref to its containing object */ | ||
308 | #define from_kref(k) container_of(k, struct hvcs_struct, kref) | ||
309 | |||
304 | static LIST_HEAD(hvcs_structs); | 310 | static LIST_HEAD(hvcs_structs); |
305 | static DEFINE_SPINLOCK(hvcs_structs_lock); | 311 | static DEFINE_SPINLOCK(hvcs_structs_lock); |
306 | static DEFINE_MUTEX(hvcs_init_mutex); | 312 | static DEFINE_MUTEX(hvcs_init_mutex); |
@@ -330,12 +336,12 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp); | |||
330 | static void hvcs_close(struct tty_struct *tty, struct file *filp); | 336 | static void hvcs_close(struct tty_struct *tty, struct file *filp); |
331 | static void hvcs_hangup(struct tty_struct * tty); | 337 | static void hvcs_hangup(struct tty_struct * tty); |
332 | 338 | ||
333 | static int hvcs_probe(struct vio_dev *dev, | 339 | static int __devinit hvcs_probe(struct vio_dev *dev, |
334 | const struct vio_device_id *id); | 340 | const struct vio_device_id *id); |
335 | static int hvcs_remove(struct vio_dev *dev); | 341 | static int __devexit hvcs_remove(struct vio_dev *dev); |
336 | static int __init hvcs_module_init(void); | 342 | static int __init hvcs_module_init(void); |
337 | static void __exit hvcs_module_exit(void); | 343 | static void __exit hvcs_module_exit(void); |
338 | static int hvcs_initialize(void); | 344 | static int __devinit hvcs_initialize(void); |
339 | 345 | ||
340 | #define HVCS_SCHED_READ 0x00000001 | 346 | #define HVCS_SCHED_READ 0x00000001 |
341 | #define HVCS_QUICK_READ 0x00000002 | 347 | #define HVCS_QUICK_READ 0x00000002 |
@@ -416,7 +422,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut | |||
416 | 422 | ||
417 | spin_lock_irqsave(&hvcsd->lock, flags); | 423 | spin_lock_irqsave(&hvcsd->lock, flags); |
418 | 424 | ||
419 | if (hvcsd->port.count > 0) { | 425 | if (hvcsd->open_count > 0) { |
420 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 426 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
421 | printk(KERN_INFO "HVCS: vterm state unchanged. " | 427 | printk(KERN_INFO "HVCS: vterm state unchanged. " |
422 | "The hvcs device node is still in use.\n"); | 428 | "The hvcs device node is still in use.\n"); |
@@ -558,7 +564,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) | |||
558 | static void hvcs_try_write(struct hvcs_struct *hvcsd) | 564 | static void hvcs_try_write(struct hvcs_struct *hvcsd) |
559 | { | 565 | { |
560 | uint32_t unit_address = hvcsd->vdev->unit_address; | 566 | uint32_t unit_address = hvcsd->vdev->unit_address; |
561 | struct tty_struct *tty = hvcsd->port.tty; | 567 | struct tty_struct *tty = hvcsd->tty; |
562 | int sent; | 568 | int sent; |
563 | 569 | ||
564 | if (hvcsd->todo_mask & HVCS_TRY_WRITE) { | 570 | if (hvcsd->todo_mask & HVCS_TRY_WRITE) { |
@@ -596,7 +602,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) | |||
596 | spin_lock_irqsave(&hvcsd->lock, flags); | 602 | spin_lock_irqsave(&hvcsd->lock, flags); |
597 | 603 | ||
598 | unit_address = hvcsd->vdev->unit_address; | 604 | unit_address = hvcsd->vdev->unit_address; |
599 | tty = hvcsd->port.tty; | 605 | tty = hvcsd->tty; |
600 | 606 | ||
601 | hvcs_try_write(hvcsd); | 607 | hvcs_try_write(hvcsd); |
602 | 608 | ||
@@ -676,7 +682,7 @@ static int khvcsd(void *unused) | |||
676 | return 0; | 682 | return 0; |
677 | } | 683 | } |
678 | 684 | ||
679 | static struct vio_device_id hvcs_driver_table[] = { | 685 | static struct vio_device_id hvcs_driver_table[] __devinitdata= { |
680 | {"serial-server", "hvterm2"}, | 686 | {"serial-server", "hvterm2"}, |
681 | { "", "" } | 687 | { "", "" } |
682 | }; | 688 | }; |
@@ -695,9 +701,10 @@ static void hvcs_return_index(int index) | |||
695 | hvcs_index_list[index] = -1; | 701 | hvcs_index_list[index] = -1; |
696 | } | 702 | } |
697 | 703 | ||
698 | static void hvcs_destruct_port(struct tty_port *p) | 704 | /* callback when the kref ref count reaches zero */ |
705 | static void destroy_hvcs_struct(struct kref *kref) | ||
699 | { | 706 | { |
700 | struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port); | 707 | struct hvcs_struct *hvcsd = from_kref(kref); |
701 | struct vio_dev *vdev; | 708 | struct vio_dev *vdev; |
702 | unsigned long flags; | 709 | unsigned long flags; |
703 | 710 | ||
@@ -734,10 +741,6 @@ static void hvcs_destruct_port(struct tty_port *p) | |||
734 | kfree(hvcsd); | 741 | kfree(hvcsd); |
735 | } | 742 | } |
736 | 743 | ||
737 | static const struct tty_port_operations hvcs_port_ops = { | ||
738 | .destruct = hvcs_destruct_port, | ||
739 | }; | ||
740 | |||
741 | static int hvcs_get_index(void) | 744 | static int hvcs_get_index(void) |
742 | { | 745 | { |
743 | int i; | 746 | int i; |
@@ -756,7 +759,7 @@ static int hvcs_get_index(void) | |||
756 | return -1; | 759 | return -1; |
757 | } | 760 | } |
758 | 761 | ||
759 | static int hvcs_probe( | 762 | static int __devinit hvcs_probe( |
760 | struct vio_dev *dev, | 763 | struct vio_dev *dev, |
761 | const struct vio_device_id *id) | 764 | const struct vio_device_id *id) |
762 | { | 765 | { |
@@ -786,9 +789,10 @@ static int hvcs_probe( | |||
786 | if (!hvcsd) | 789 | if (!hvcsd) |
787 | return -ENODEV; | 790 | return -ENODEV; |
788 | 791 | ||
789 | tty_port_init(&hvcsd->port); | 792 | |
790 | hvcsd->port.ops = &hvcs_port_ops; | ||
791 | spin_lock_init(&hvcsd->lock); | 793 | spin_lock_init(&hvcsd->lock); |
794 | /* Automatically incs the refcount the first time */ | ||
795 | kref_init(&hvcsd->kref); | ||
792 | 796 | ||
793 | hvcsd->vdev = dev; | 797 | hvcsd->vdev = dev; |
794 | dev_set_drvdata(&dev->dev, hvcsd); | 798 | dev_set_drvdata(&dev->dev, hvcsd); |
@@ -835,7 +839,7 @@ static int hvcs_probe( | |||
835 | return 0; | 839 | return 0; |
836 | } | 840 | } |
837 | 841 | ||
838 | static int hvcs_remove(struct vio_dev *dev) | 842 | static int __devexit hvcs_remove(struct vio_dev *dev) |
839 | { | 843 | { |
840 | struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); | 844 | struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); |
841 | unsigned long flags; | 845 | unsigned long flags; |
@@ -848,7 +852,7 @@ static int hvcs_remove(struct vio_dev *dev) | |||
848 | 852 | ||
849 | spin_lock_irqsave(&hvcsd->lock, flags); | 853 | spin_lock_irqsave(&hvcsd->lock, flags); |
850 | 854 | ||
851 | tty = hvcsd->port.tty; | 855 | tty = hvcsd->tty; |
852 | 856 | ||
853 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 857 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
854 | 858 | ||
@@ -856,7 +860,7 @@ static int hvcs_remove(struct vio_dev *dev) | |||
856 | * Let the last holder of this object cause it to be removed, which | 860 | * Let the last holder of this object cause it to be removed, which |
857 | * would probably be tty_hangup below. | 861 | * would probably be tty_hangup below. |
858 | */ | 862 | */ |
859 | tty_port_put(&hvcsd->port); | 863 | kref_put(&hvcsd->kref, destroy_hvcs_struct); |
860 | 864 | ||
861 | /* | 865 | /* |
862 | * The hangup is a scheduled function which will auto chain call | 866 | * The hangup is a scheduled function which will auto chain call |
@@ -874,8 +878,11 @@ static int hvcs_remove(struct vio_dev *dev) | |||
874 | static struct vio_driver hvcs_vio_driver = { | 878 | static struct vio_driver hvcs_vio_driver = { |
875 | .id_table = hvcs_driver_table, | 879 | .id_table = hvcs_driver_table, |
876 | .probe = hvcs_probe, | 880 | .probe = hvcs_probe, |
877 | .remove = hvcs_remove, | 881 | .remove = __devexit_p(hvcs_remove), |
878 | .name = hvcs_driver_name, | 882 | .driver = { |
883 | .name = hvcs_driver_name, | ||
884 | .owner = THIS_MODULE, | ||
885 | } | ||
879 | }; | 886 | }; |
880 | 887 | ||
881 | /* Only called from hvcs_get_pi please */ | 888 | /* Only called from hvcs_get_pi please */ |
@@ -1050,7 +1057,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, | |||
1050 | * the conn was registered and now. | 1057 | * the conn was registered and now. |
1051 | */ | 1058 | */ |
1052 | if (!(rc = request_irq(irq, &hvcs_handle_interrupt, | 1059 | if (!(rc = request_irq(irq, &hvcs_handle_interrupt, |
1053 | 0, "ibmhvcs", hvcsd))) { | 1060 | IRQF_DISABLED, "ibmhvcs", hvcsd))) { |
1054 | /* | 1061 | /* |
1055 | * It is possible the vty-server was removed after the irq was | 1062 | * It is possible the vty-server was removed after the irq was |
1056 | * requested but before we have time to enable interrupts. | 1063 | * requested but before we have time to enable interrupts. |
@@ -1083,39 +1090,50 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, | |||
1083 | */ | 1090 | */ |
1084 | static struct hvcs_struct *hvcs_get_by_index(int index) | 1091 | static struct hvcs_struct *hvcs_get_by_index(int index) |
1085 | { | 1092 | { |
1086 | struct hvcs_struct *hvcsd; | 1093 | struct hvcs_struct *hvcsd = NULL; |
1087 | unsigned long flags; | 1094 | unsigned long flags; |
1088 | 1095 | ||
1089 | spin_lock(&hvcs_structs_lock); | 1096 | spin_lock(&hvcs_structs_lock); |
1090 | list_for_each_entry(hvcsd, &hvcs_structs, next) { | 1097 | /* We can immediately discard OOB requests */ |
1091 | spin_lock_irqsave(&hvcsd->lock, flags); | 1098 | if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { |
1092 | if (hvcsd->index == index) { | 1099 | list_for_each_entry(hvcsd, &hvcs_structs, next) { |
1093 | tty_port_get(&hvcsd->port); | 1100 | spin_lock_irqsave(&hvcsd->lock, flags); |
1101 | if (hvcsd->index == index) { | ||
1102 | kref_get(&hvcsd->kref); | ||
1103 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1104 | spin_unlock(&hvcs_structs_lock); | ||
1105 | return hvcsd; | ||
1106 | } | ||
1094 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1107 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
1095 | spin_unlock(&hvcs_structs_lock); | ||
1096 | return hvcsd; | ||
1097 | } | 1108 | } |
1098 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1109 | hvcsd = NULL; |
1099 | } | 1110 | } |
1100 | spin_unlock(&hvcs_structs_lock); | ||
1101 | 1111 | ||
1102 | return NULL; | 1112 | spin_unlock(&hvcs_structs_lock); |
1113 | return hvcsd; | ||
1103 | } | 1114 | } |
1104 | 1115 | ||
1105 | static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) | 1116 | /* |
1117 | * This is invoked via the tty_open interface when a user app connects to the | ||
1118 | * /dev node. | ||
1119 | */ | ||
1120 | static int hvcs_open(struct tty_struct *tty, struct file *filp) | ||
1106 | { | 1121 | { |
1107 | struct hvcs_struct *hvcsd; | 1122 | struct hvcs_struct *hvcsd; |
1108 | struct vio_dev *vdev; | 1123 | int rc, retval = 0; |
1109 | unsigned long unit_address, flags; | 1124 | unsigned long flags; |
1110 | unsigned int irq; | 1125 | unsigned int irq; |
1111 | int retval; | 1126 | struct vio_dev *vdev; |
1127 | unsigned long unit_address; | ||
1128 | |||
1129 | if (tty->driver_data) | ||
1130 | goto fast_open; | ||
1112 | 1131 | ||
1113 | /* | 1132 | /* |
1114 | * Is there a vty-server that shares the same index? | 1133 | * Is there a vty-server that shares the same index? |
1115 | * This function increments the kref index. | 1134 | * This function increments the kref index. |
1116 | */ | 1135 | */ |
1117 | hvcsd = hvcs_get_by_index(tty->index); | 1136 | if (!(hvcsd = hvcs_get_by_index(tty->index))) { |
1118 | if (!hvcsd) { | ||
1119 | printk(KERN_WARNING "HVCS: open failed, no device associated" | 1137 | printk(KERN_WARNING "HVCS: open failed, no device associated" |
1120 | " with tty->index %d.\n", tty->index); | 1138 | " with tty->index %d.\n", tty->index); |
1121 | return -ENODEV; | 1139 | return -ENODEV; |
@@ -1123,17 +1141,12 @@ static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) | |||
1123 | 1141 | ||
1124 | spin_lock_irqsave(&hvcsd->lock, flags); | 1142 | spin_lock_irqsave(&hvcsd->lock, flags); |
1125 | 1143 | ||
1126 | if (hvcsd->connected == 0) { | 1144 | if (hvcsd->connected == 0) |
1127 | retval = hvcs_partner_connect(hvcsd); | 1145 | if ((retval = hvcs_partner_connect(hvcsd))) |
1128 | if (retval) { | 1146 | goto error_release; |
1129 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1130 | printk(KERN_WARNING "HVCS: partner connect failed.\n"); | ||
1131 | goto err_put; | ||
1132 | } | ||
1133 | } | ||
1134 | 1147 | ||
1135 | hvcsd->port.count = 0; | 1148 | hvcsd->open_count = 1; |
1136 | hvcsd->port.tty = tty; | 1149 | hvcsd->tty = tty; |
1137 | tty->driver_data = hvcsd; | 1150 | tty->driver_data = hvcsd; |
1138 | 1151 | ||
1139 | memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); | 1152 | memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); |
@@ -1153,55 +1166,44 @@ static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) | |||
1153 | * This must be done outside of the spinlock because it requests irqs | 1166 | * This must be done outside of the spinlock because it requests irqs |
1154 | * and will grab the spinlock and free the connection if it fails. | 1167 | * and will grab the spinlock and free the connection if it fails. |
1155 | */ | 1168 | */ |
1156 | retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev); | 1169 | if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { |
1157 | if (retval) { | 1170 | kref_put(&hvcsd->kref, destroy_hvcs_struct); |
1158 | printk(KERN_WARNING "HVCS: enable device failed.\n"); | 1171 | printk(KERN_WARNING "HVCS: enable device failed.\n"); |
1159 | goto err_put; | 1172 | return rc; |
1160 | } | 1173 | } |
1161 | 1174 | ||
1162 | retval = tty_port_install(&hvcsd->port, driver, tty); | 1175 | goto open_success; |
1163 | if (retval) | ||
1164 | goto err_irq; | ||
1165 | 1176 | ||
1166 | return 0; | 1177 | fast_open: |
1167 | err_irq: | 1178 | hvcsd = tty->driver_data; |
1168 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1169 | vio_disable_interrupts(hvcsd->vdev); | ||
1170 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1171 | free_irq(irq, hvcsd); | ||
1172 | err_put: | ||
1173 | tty_port_put(&hvcsd->port); | ||
1174 | |||
1175 | return retval; | ||
1176 | } | ||
1177 | |||
1178 | /* | ||
1179 | * This is invoked via the tty_open interface when a user app connects to the | ||
1180 | * /dev node. | ||
1181 | */ | ||
1182 | static int hvcs_open(struct tty_struct *tty, struct file *filp) | ||
1183 | { | ||
1184 | struct hvcs_struct *hvcsd = tty->driver_data; | ||
1185 | unsigned long flags; | ||
1186 | 1179 | ||
1187 | spin_lock_irqsave(&hvcsd->lock, flags); | 1180 | spin_lock_irqsave(&hvcsd->lock, flags); |
1188 | hvcsd->port.count++; | 1181 | kref_get(&hvcsd->kref); |
1182 | hvcsd->open_count++; | ||
1189 | hvcsd->todo_mask |= HVCS_SCHED_READ; | 1183 | hvcsd->todo_mask |= HVCS_SCHED_READ; |
1190 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1184 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
1191 | 1185 | ||
1186 | open_success: | ||
1192 | hvcs_kick(); | 1187 | hvcs_kick(); |
1193 | 1188 | ||
1194 | printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", | 1189 | printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", |
1195 | hvcsd->vdev->unit_address ); | 1190 | hvcsd->vdev->unit_address ); |
1196 | 1191 | ||
1197 | return 0; | 1192 | return 0; |
1193 | |||
1194 | error_release: | ||
1195 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1196 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | ||
1197 | |||
1198 | printk(KERN_WARNING "HVCS: partner connect failed.\n"); | ||
1199 | return retval; | ||
1198 | } | 1200 | } |
1199 | 1201 | ||
1200 | static void hvcs_close(struct tty_struct *tty, struct file *filp) | 1202 | static void hvcs_close(struct tty_struct *tty, struct file *filp) |
1201 | { | 1203 | { |
1202 | struct hvcs_struct *hvcsd; | 1204 | struct hvcs_struct *hvcsd; |
1203 | unsigned long flags; | 1205 | unsigned long flags; |
1204 | int irq; | 1206 | int irq = NO_IRQ; |
1205 | 1207 | ||
1206 | /* | 1208 | /* |
1207 | * Is someone trying to close the file associated with this device after | 1209 | * Is someone trying to close the file associated with this device after |
@@ -1221,7 +1223,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
1221 | hvcsd = tty->driver_data; | 1223 | hvcsd = tty->driver_data; |
1222 | 1224 | ||
1223 | spin_lock_irqsave(&hvcsd->lock, flags); | 1225 | spin_lock_irqsave(&hvcsd->lock, flags); |
1224 | if (--hvcsd->port.count == 0) { | 1226 | if (--hvcsd->open_count == 0) { |
1225 | 1227 | ||
1226 | vio_disable_interrupts(hvcsd->vdev); | 1228 | vio_disable_interrupts(hvcsd->vdev); |
1227 | 1229 | ||
@@ -1230,12 +1232,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
1230 | * execute any operations on the TTY even though it is obligated | 1232 | * execute any operations on the TTY even though it is obligated |
1231 | * to deliver any pending I/O to the hypervisor. | 1233 | * to deliver any pending I/O to the hypervisor. |
1232 | */ | 1234 | */ |
1233 | hvcsd->port.tty = NULL; | 1235 | hvcsd->tty = NULL; |
1234 | 1236 | ||
1235 | irq = hvcsd->vdev->irq; | 1237 | irq = hvcsd->vdev->irq; |
1236 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1238 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
1237 | 1239 | ||
1238 | tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT); | 1240 | tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); |
1239 | 1241 | ||
1240 | /* | 1242 | /* |
1241 | * This line is important because it tells hvcs_open that this | 1243 | * This line is important because it tells hvcs_open that this |
@@ -1245,21 +1247,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
1245 | tty->driver_data = NULL; | 1247 | tty->driver_data = NULL; |
1246 | 1248 | ||
1247 | free_irq(irq, hvcsd); | 1249 | free_irq(irq, hvcsd); |
1250 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | ||
1248 | return; | 1251 | return; |
1249 | } else if (hvcsd->port.count < 0) { | 1252 | } else if (hvcsd->open_count < 0) { |
1250 | printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" | 1253 | printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" |
1251 | " is missmanaged.\n", | 1254 | " is missmanaged.\n", |
1252 | hvcsd->vdev->unit_address, hvcsd->port.count); | 1255 | hvcsd->vdev->unit_address, hvcsd->open_count); |
1253 | } | 1256 | } |
1254 | 1257 | ||
1255 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1258 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
1256 | } | 1259 | kref_put(&hvcsd->kref, destroy_hvcs_struct); |
1257 | |||
1258 | static void hvcs_cleanup(struct tty_struct * tty) | ||
1259 | { | ||
1260 | struct hvcs_struct *hvcsd = tty->driver_data; | ||
1261 | |||
1262 | tty_port_put(&hvcsd->port); | ||
1263 | } | 1260 | } |
1264 | 1261 | ||
1265 | static void hvcs_hangup(struct tty_struct * tty) | 1262 | static void hvcs_hangup(struct tty_struct * tty) |
@@ -1267,11 +1264,11 @@ static void hvcs_hangup(struct tty_struct * tty) | |||
1267 | struct hvcs_struct *hvcsd = tty->driver_data; | 1264 | struct hvcs_struct *hvcsd = tty->driver_data; |
1268 | unsigned long flags; | 1265 | unsigned long flags; |
1269 | int temp_open_count; | 1266 | int temp_open_count; |
1270 | int irq; | 1267 | int irq = NO_IRQ; |
1271 | 1268 | ||
1272 | spin_lock_irqsave(&hvcsd->lock, flags); | 1269 | spin_lock_irqsave(&hvcsd->lock, flags); |
1273 | /* Preserve this so that we know how many kref refs to put */ | 1270 | /* Preserve this so that we know how many kref refs to put */ |
1274 | temp_open_count = hvcsd->port.count; | 1271 | temp_open_count = hvcsd->open_count; |
1275 | 1272 | ||
1276 | /* | 1273 | /* |
1277 | * Don't kref put inside the spinlock because the destruction | 1274 | * Don't kref put inside the spinlock because the destruction |
@@ -1283,10 +1280,10 @@ static void hvcs_hangup(struct tty_struct * tty) | |||
1283 | hvcsd->todo_mask = 0; | 1280 | hvcsd->todo_mask = 0; |
1284 | 1281 | ||
1285 | /* I don't think the tty needs the hvcs_struct pointer after a hangup */ | 1282 | /* I don't think the tty needs the hvcs_struct pointer after a hangup */ |
1286 | tty->driver_data = NULL; | 1283 | hvcsd->tty->driver_data = NULL; |
1287 | hvcsd->port.tty = NULL; | 1284 | hvcsd->tty = NULL; |
1288 | 1285 | ||
1289 | hvcsd->port.count = 0; | 1286 | hvcsd->open_count = 0; |
1290 | 1287 | ||
1291 | /* This will drop any buffered data on the floor which is OK in a hangup | 1288 | /* This will drop any buffered data on the floor which is OK in a hangup |
1292 | * scenario. */ | 1289 | * scenario. */ |
@@ -1311,7 +1308,7 @@ static void hvcs_hangup(struct tty_struct * tty) | |||
1311 | * NOTE: If this hangup was signaled from user space then the | 1308 | * NOTE: If this hangup was signaled from user space then the |
1312 | * final put will never happen. | 1309 | * final put will never happen. |
1313 | */ | 1310 | */ |
1314 | tty_port_put(&hvcsd->port); | 1311 | kref_put(&hvcsd->kref, destroy_hvcs_struct); |
1315 | } | 1312 | } |
1316 | } | 1313 | } |
1317 | 1314 | ||
@@ -1357,7 +1354,7 @@ static int hvcs_write(struct tty_struct *tty, | |||
1357 | * the middle of a write operation? This is a crummy place to do this | 1354 | * the middle of a write operation? This is a crummy place to do this |
1358 | * but we want to keep it all in the spinlock. | 1355 | * but we want to keep it all in the spinlock. |
1359 | */ | 1356 | */ |
1360 | if (hvcsd->port.count <= 0) { | 1357 | if (hvcsd->open_count <= 0) { |
1361 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1358 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
1362 | return -ENODEV; | 1359 | return -ENODEV; |
1363 | } | 1360 | } |
@@ -1431,7 +1428,7 @@ static int hvcs_write_room(struct tty_struct *tty) | |||
1431 | { | 1428 | { |
1432 | struct hvcs_struct *hvcsd = tty->driver_data; | 1429 | struct hvcs_struct *hvcsd = tty->driver_data; |
1433 | 1430 | ||
1434 | if (!hvcsd || hvcsd->port.count <= 0) | 1431 | if (!hvcsd || hvcsd->open_count <= 0) |
1435 | return 0; | 1432 | return 0; |
1436 | 1433 | ||
1437 | return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; | 1434 | return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; |
@@ -1445,10 +1442,8 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) | |||
1445 | } | 1442 | } |
1446 | 1443 | ||
1447 | static const struct tty_operations hvcs_ops = { | 1444 | static const struct tty_operations hvcs_ops = { |
1448 | .install = hvcs_install, | ||
1449 | .open = hvcs_open, | 1445 | .open = hvcs_open, |
1450 | .close = hvcs_close, | 1446 | .close = hvcs_close, |
1451 | .cleanup = hvcs_cleanup, | ||
1452 | .hangup = hvcs_hangup, | 1447 | .hangup = hvcs_hangup, |
1453 | .write = hvcs_write, | 1448 | .write = hvcs_write, |
1454 | .write_room = hvcs_write_room, | 1449 | .write_room = hvcs_write_room, |
@@ -1478,7 +1473,7 @@ static void hvcs_free_index_list(void) | |||
1478 | hvcs_index_count = 0; | 1473 | hvcs_index_count = 0; |
1479 | } | 1474 | } |
1480 | 1475 | ||
1481 | static int hvcs_initialize(void) | 1476 | static int __devinit hvcs_initialize(void) |
1482 | { | 1477 | { |
1483 | int rc, num_ttys_to_alloc; | 1478 | int rc, num_ttys_to_alloc; |
1484 | 1479 | ||
@@ -1496,16 +1491,16 @@ static int hvcs_initialize(void) | |||
1496 | num_ttys_to_alloc = hvcs_parm_num_devs; | 1491 | num_ttys_to_alloc = hvcs_parm_num_devs; |
1497 | 1492 | ||
1498 | hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc); | 1493 | hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc); |
1499 | if (!hvcs_tty_driver) { | 1494 | if (!hvcs_tty_driver) |
1500 | mutex_unlock(&hvcs_init_mutex); | ||
1501 | return -ENOMEM; | 1495 | return -ENOMEM; |
1502 | } | ||
1503 | 1496 | ||
1504 | if (hvcs_alloc_index_list(num_ttys_to_alloc)) { | 1497 | if (hvcs_alloc_index_list(num_ttys_to_alloc)) { |
1505 | rc = -ENOMEM; | 1498 | rc = -ENOMEM; |
1506 | goto index_fail; | 1499 | goto index_fail; |
1507 | } | 1500 | } |
1508 | 1501 | ||
1502 | hvcs_tty_driver->owner = THIS_MODULE; | ||
1503 | |||
1509 | hvcs_tty_driver->driver_name = hvcs_driver_name; | 1504 | hvcs_tty_driver->driver_name = hvcs_driver_name; |
1510 | hvcs_tty_driver->name = hvcs_device_node; | 1505 | hvcs_tty_driver->name = hvcs_device_node; |
1511 | 1506 | ||
@@ -1537,7 +1532,7 @@ static int hvcs_initialize(void) | |||
1537 | goto register_fail; | 1532 | goto register_fail; |
1538 | } | 1533 | } |
1539 | 1534 | ||
1540 | hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL); | 1535 | hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); |
1541 | if (!hvcs_pi_buff) { | 1536 | if (!hvcs_pi_buff) { |
1542 | rc = -ENOMEM; | 1537 | rc = -ENOMEM; |
1543 | goto buff_alloc_fail; | 1538 | goto buff_alloc_fail; |
@@ -1553,7 +1548,7 @@ static int hvcs_initialize(void) | |||
1553 | return 0; | 1548 | return 0; |
1554 | 1549 | ||
1555 | kthread_fail: | 1550 | kthread_fail: |
1556 | free_page((unsigned long)hvcs_pi_buff); | 1551 | kfree(hvcs_pi_buff); |
1557 | buff_alloc_fail: | 1552 | buff_alloc_fail: |
1558 | tty_unregister_driver(hvcs_tty_driver); | 1553 | tty_unregister_driver(hvcs_tty_driver); |
1559 | register_fail: | 1554 | register_fail: |
@@ -1602,7 +1597,7 @@ static void __exit hvcs_module_exit(void) | |||
1602 | kthread_stop(hvcs_task); | 1597 | kthread_stop(hvcs_task); |
1603 | 1598 | ||
1604 | spin_lock(&hvcs_pi_lock); | 1599 | spin_lock(&hvcs_pi_lock); |
1605 | free_page((unsigned long)hvcs_pi_buff); | 1600 | kfree(hvcs_pi_buff); |
1606 | hvcs_pi_buff = NULL; | 1601 | hvcs_pi_buff = NULL; |
1607 | spin_unlock(&hvcs_pi_lock); | 1602 | spin_unlock(&hvcs_pi_lock); |
1608 | 1603 | ||
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 68357a6e4de..c94e2f5853d 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c | |||
@@ -69,13 +69,14 @@ | |||
69 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) | 69 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) |
70 | 70 | ||
71 | struct hvsi_struct { | 71 | struct hvsi_struct { |
72 | struct tty_port port; | ||
73 | struct delayed_work writer; | 72 | struct delayed_work writer; |
74 | struct work_struct handshaker; | 73 | struct work_struct handshaker; |
75 | wait_queue_head_t emptyq; /* woken when outbuf is emptied */ | 74 | wait_queue_head_t emptyq; /* woken when outbuf is emptied */ |
76 | wait_queue_head_t stateq; /* woken when HVSI state changes */ | 75 | wait_queue_head_t stateq; /* woken when HVSI state changes */ |
77 | spinlock_t lock; | 76 | spinlock_t lock; |
78 | int index; | 77 | int index; |
78 | struct tty_struct *tty; | ||
79 | int count; | ||
79 | uint8_t throttle_buf[128]; | 80 | uint8_t throttle_buf[128]; |
80 | uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ | 81 | uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ |
81 | /* inbuf is for packet reassembly. leave a little room for leftovers. */ | 82 | /* inbuf is for packet reassembly. leave a little room for leftovers. */ |
@@ -236,7 +237,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) | |||
236 | } | 237 | } |
237 | 238 | ||
238 | static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, | 239 | static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, |
239 | struct tty_struct *tty, struct hvsi_struct **to_handshake) | 240 | struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) |
240 | { | 241 | { |
241 | struct hvsi_control *header = (struct hvsi_control *)packet; | 242 | struct hvsi_control *header = (struct hvsi_control *)packet; |
242 | 243 | ||
@@ -246,8 +247,9 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, | |||
246 | /* CD went away; no more connection */ | 247 | /* CD went away; no more connection */ |
247 | pr_debug("hvsi%i: CD dropped\n", hp->index); | 248 | pr_debug("hvsi%i: CD dropped\n", hp->index); |
248 | hp->mctrl &= TIOCM_CD; | 249 | hp->mctrl &= TIOCM_CD; |
249 | if (tty && !C_CLOCAL(tty)) | 250 | /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ |
250 | tty_hangup(tty); | 251 | if (hp->tty && !(hp->tty->flags & CLOCAL)) |
252 | *to_hangup = hp->tty; | ||
251 | } | 253 | } |
252 | break; | 254 | break; |
253 | case VSV_CLOSE_PROTOCOL: | 255 | case VSV_CLOSE_PROTOCOL: |
@@ -329,8 +331,7 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) | |||
329 | } | 331 | } |
330 | } | 332 | } |
331 | 333 | ||
332 | static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, | 334 | static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) |
333 | const char *buf, int len) | ||
334 | { | 335 | { |
335 | int i; | 336 | int i; |
336 | 337 | ||
@@ -346,7 +347,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, | |||
346 | continue; | 347 | continue; |
347 | } | 348 | } |
348 | #endif /* CONFIG_MAGIC_SYSRQ */ | 349 | #endif /* CONFIG_MAGIC_SYSRQ */ |
349 | tty_insert_flip_char(tty, c, 0); | 350 | tty_insert_flip_char(hp->tty, c, 0); |
350 | } | 351 | } |
351 | } | 352 | } |
352 | 353 | ||
@@ -359,7 +360,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, | |||
359 | * revisited. | 360 | * revisited. |
360 | */ | 361 | */ |
361 | #define TTY_THRESHOLD_THROTTLE 128 | 362 | #define TTY_THRESHOLD_THROTTLE 128 |
362 | static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, | 363 | static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, |
363 | const uint8_t *packet) | 364 | const uint8_t *packet) |
364 | { | 365 | { |
365 | const struct hvsi_header *header = (const struct hvsi_header *)packet; | 366 | const struct hvsi_header *header = (const struct hvsi_header *)packet; |
@@ -370,14 +371,14 @@ static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, | |||
370 | pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); | 371 | pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); |
371 | 372 | ||
372 | if (datalen == 0) | 373 | if (datalen == 0) |
373 | return false; | 374 | return NULL; |
374 | 375 | ||
375 | if (overflow > 0) { | 376 | if (overflow > 0) { |
376 | pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); | 377 | pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); |
377 | datalen = TTY_THRESHOLD_THROTTLE; | 378 | datalen = TTY_THRESHOLD_THROTTLE; |
378 | } | 379 | } |
379 | 380 | ||
380 | hvsi_insert_chars(hp, tty, data, datalen); | 381 | hvsi_insert_chars(hp, data, datalen); |
381 | 382 | ||
382 | if (overflow > 0) { | 383 | if (overflow > 0) { |
383 | /* | 384 | /* |
@@ -389,7 +390,7 @@ static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, | |||
389 | hp->n_throttle = overflow; | 390 | hp->n_throttle = overflow; |
390 | } | 391 | } |
391 | 392 | ||
392 | return true; | 393 | return hp->tty; |
393 | } | 394 | } |
394 | 395 | ||
395 | /* | 396 | /* |
@@ -398,13 +399,14 @@ static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, | |||
398 | * machine during console handshaking (in which case tty = NULL and we ignore | 399 | * machine during console handshaking (in which case tty = NULL and we ignore |
399 | * incoming data). | 400 | * incoming data). |
400 | */ | 401 | */ |
401 | static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, | 402 | static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, |
402 | struct hvsi_struct **handshake) | 403 | struct tty_struct **hangup, struct hvsi_struct **handshake) |
403 | { | 404 | { |
404 | uint8_t *packet = hp->inbuf; | 405 | uint8_t *packet = hp->inbuf; |
405 | int chunklen; | 406 | int chunklen; |
406 | bool flip = false; | ||
407 | 407 | ||
408 | *flip = NULL; | ||
409 | *hangup = NULL; | ||
408 | *handshake = NULL; | 410 | *handshake = NULL; |
409 | 411 | ||
410 | chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); | 412 | chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); |
@@ -438,12 +440,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, | |||
438 | case VS_DATA_PACKET_HEADER: | 440 | case VS_DATA_PACKET_HEADER: |
439 | if (!is_open(hp)) | 441 | if (!is_open(hp)) |
440 | break; | 442 | break; |
441 | if (tty == NULL) | 443 | if (hp->tty == NULL) |
442 | break; /* no tty buffer to put data in */ | 444 | break; /* no tty buffer to put data in */ |
443 | flip = hvsi_recv_data(hp, tty, packet); | 445 | *flip = hvsi_recv_data(hp, packet); |
444 | break; | 446 | break; |
445 | case VS_CONTROL_PACKET_HEADER: | 447 | case VS_CONTROL_PACKET_HEADER: |
446 | hvsi_recv_control(hp, packet, tty, handshake); | 448 | hvsi_recv_control(hp, packet, hangup, handshake); |
447 | break; | 449 | break; |
448 | case VS_QUERY_RESPONSE_PACKET_HEADER: | 450 | case VS_QUERY_RESPONSE_PACKET_HEADER: |
449 | hvsi_recv_response(hp, packet); | 451 | hvsi_recv_response(hp, packet); |
@@ -460,26 +462,28 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, | |||
460 | 462 | ||
461 | packet += len_packet(packet); | 463 | packet += len_packet(packet); |
462 | 464 | ||
463 | if (*handshake) { | 465 | if (*hangup || *handshake) { |
464 | pr_debug("%s: handshake\n", __func__); | 466 | pr_debug("%s: hangup or handshake\n", __func__); |
467 | /* | ||
468 | * we need to send the hangup now before receiving any more data. | ||
469 | * If we get "data, hangup, data", we can't deliver the second | ||
470 | * data before the hangup. | ||
471 | */ | ||
465 | break; | 472 | break; |
466 | } | 473 | } |
467 | } | 474 | } |
468 | 475 | ||
469 | compact_inbuf(hp, packet); | 476 | compact_inbuf(hp, packet); |
470 | 477 | ||
471 | if (flip) | ||
472 | tty_flip_buffer_push(tty); | ||
473 | |||
474 | return 1; | 478 | return 1; |
475 | } | 479 | } |
476 | 480 | ||
477 | static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty) | 481 | static void hvsi_send_overflow(struct hvsi_struct *hp) |
478 | { | 482 | { |
479 | pr_debug("%s: delivering %i bytes overflow\n", __func__, | 483 | pr_debug("%s: delivering %i bytes overflow\n", __func__, |
480 | hp->n_throttle); | 484 | hp->n_throttle); |
481 | 485 | ||
482 | hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle); | 486 | hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); |
483 | hp->n_throttle = 0; | 487 | hp->n_throttle = 0; |
484 | } | 488 | } |
485 | 489 | ||
@@ -490,20 +494,35 @@ static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty) | |||
490 | static irqreturn_t hvsi_interrupt(int irq, void *arg) | 494 | static irqreturn_t hvsi_interrupt(int irq, void *arg) |
491 | { | 495 | { |
492 | struct hvsi_struct *hp = (struct hvsi_struct *)arg; | 496 | struct hvsi_struct *hp = (struct hvsi_struct *)arg; |
497 | struct tty_struct *flip; | ||
498 | struct tty_struct *hangup; | ||
493 | struct hvsi_struct *handshake; | 499 | struct hvsi_struct *handshake; |
494 | struct tty_struct *tty; | ||
495 | unsigned long flags; | 500 | unsigned long flags; |
496 | int again = 1; | 501 | int again = 1; |
497 | 502 | ||
498 | pr_debug("%s\n", __func__); | 503 | pr_debug("%s\n", __func__); |
499 | 504 | ||
500 | tty = tty_port_tty_get(&hp->port); | ||
501 | |||
502 | while (again) { | 505 | while (again) { |
503 | spin_lock_irqsave(&hp->lock, flags); | 506 | spin_lock_irqsave(&hp->lock, flags); |
504 | again = hvsi_load_chunk(hp, tty, &handshake); | 507 | again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); |
505 | spin_unlock_irqrestore(&hp->lock, flags); | 508 | spin_unlock_irqrestore(&hp->lock, flags); |
506 | 509 | ||
510 | /* | ||
511 | * we have to call tty_flip_buffer_push() and tty_hangup() outside our | ||
512 | * spinlock. But we also have to keep going until we've read all the | ||
513 | * available data. | ||
514 | */ | ||
515 | |||
516 | if (flip) { | ||
517 | /* there was data put in the tty flip buffer */ | ||
518 | tty_flip_buffer_push(flip); | ||
519 | flip = NULL; | ||
520 | } | ||
521 | |||
522 | if (hangup) { | ||
523 | tty_hangup(hangup); | ||
524 | } | ||
525 | |||
507 | if (handshake) { | 526 | if (handshake) { |
508 | pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); | 527 | pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); |
509 | schedule_work(&handshake->handshaker); | 528 | schedule_work(&handshake->handshaker); |
@@ -511,15 +530,18 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) | |||
511 | } | 530 | } |
512 | 531 | ||
513 | spin_lock_irqsave(&hp->lock, flags); | 532 | spin_lock_irqsave(&hp->lock, flags); |
514 | if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { | 533 | if (hp->tty && hp->n_throttle |
515 | /* we weren't hung up and we weren't throttled, so we can | 534 | && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { |
516 | * deliver the rest now */ | 535 | /* we weren't hung up and we weren't throttled, so we can deliver the |
517 | hvsi_send_overflow(hp, tty); | 536 | * rest now */ |
518 | tty_flip_buffer_push(tty); | 537 | flip = hp->tty; |
538 | hvsi_send_overflow(hp); | ||
519 | } | 539 | } |
520 | spin_unlock_irqrestore(&hp->lock, flags); | 540 | spin_unlock_irqrestore(&hp->lock, flags); |
521 | 541 | ||
522 | tty_kref_put(tty); | 542 | if (flip) { |
543 | tty_flip_buffer_push(flip); | ||
544 | } | ||
523 | 545 | ||
524 | return IRQ_HANDLED; | 546 | return IRQ_HANDLED; |
525 | } | 547 | } |
@@ -715,11 +737,14 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) | |||
715 | { | 737 | { |
716 | struct hvsi_struct *hp; | 738 | struct hvsi_struct *hp; |
717 | unsigned long flags; | 739 | unsigned long flags; |
740 | int line = tty->index; | ||
718 | int ret; | 741 | int ret; |
719 | 742 | ||
720 | pr_debug("%s\n", __func__); | 743 | pr_debug("%s\n", __func__); |
721 | 744 | ||
722 | hp = &hvsi_ports[tty->index]; | 745 | if (line < 0 || line >= hvsi_count) |
746 | return -ENODEV; | ||
747 | hp = &hvsi_ports[line]; | ||
723 | 748 | ||
724 | tty->driver_data = hp; | 749 | tty->driver_data = hp; |
725 | 750 | ||
@@ -727,9 +752,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) | |||
727 | if (hp->state == HVSI_FSP_DIED) | 752 | if (hp->state == HVSI_FSP_DIED) |
728 | return -EIO; | 753 | return -EIO; |
729 | 754 | ||
730 | tty_port_tty_set(&hp->port, tty); | ||
731 | spin_lock_irqsave(&hp->lock, flags); | 755 | spin_lock_irqsave(&hp->lock, flags); |
732 | hp->port.count++; | 756 | hp->tty = tty; |
757 | hp->count++; | ||
733 | atomic_set(&hp->seqno, 0); | 758 | atomic_set(&hp->seqno, 0); |
734 | h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); | 759 | h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); |
735 | spin_unlock_irqrestore(&hp->lock, flags); | 760 | spin_unlock_irqrestore(&hp->lock, flags); |
@@ -765,7 +790,7 @@ static void hvsi_flush_output(struct hvsi_struct *hp) | |||
765 | 790 | ||
766 | /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ | 791 | /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ |
767 | cancel_delayed_work_sync(&hp->writer); | 792 | cancel_delayed_work_sync(&hp->writer); |
768 | flush_work(&hp->handshaker); | 793 | flush_work_sync(&hp->handshaker); |
769 | 794 | ||
770 | /* | 795 | /* |
771 | * it's also possible that our timeout expired and hvsi_write_worker | 796 | * it's also possible that our timeout expired and hvsi_write_worker |
@@ -786,8 +811,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) | |||
786 | 811 | ||
787 | spin_lock_irqsave(&hp->lock, flags); | 812 | spin_lock_irqsave(&hp->lock, flags); |
788 | 813 | ||
789 | if (--hp->port.count == 0) { | 814 | if (--hp->count == 0) { |
790 | tty_port_tty_set(&hp->port, NULL); | 815 | hp->tty = NULL; |
791 | hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ | 816 | hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ |
792 | 817 | ||
793 | /* only close down connection if it is not the console */ | 818 | /* only close down connection if it is not the console */ |
@@ -819,9 +844,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) | |||
819 | 844 | ||
820 | spin_lock_irqsave(&hp->lock, flags); | 845 | spin_lock_irqsave(&hp->lock, flags); |
821 | } | 846 | } |
822 | } else if (hp->port.count < 0) | 847 | } else if (hp->count < 0) |
823 | printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", | 848 | printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", |
824 | hp - hvsi_ports, hp->port.count); | 849 | hp - hvsi_ports, hp->count); |
825 | 850 | ||
826 | spin_unlock_irqrestore(&hp->lock, flags); | 851 | spin_unlock_irqrestore(&hp->lock, flags); |
827 | } | 852 | } |
@@ -833,11 +858,12 @@ static void hvsi_hangup(struct tty_struct *tty) | |||
833 | 858 | ||
834 | pr_debug("%s\n", __func__); | 859 | pr_debug("%s\n", __func__); |
835 | 860 | ||
836 | tty_port_tty_set(&hp->port, NULL); | ||
837 | |||
838 | spin_lock_irqsave(&hp->lock, flags); | 861 | spin_lock_irqsave(&hp->lock, flags); |
839 | hp->port.count = 0; | 862 | |
863 | hp->count = 0; | ||
840 | hp->n_outbuf = 0; | 864 | hp->n_outbuf = 0; |
865 | hp->tty = NULL; | ||
866 | |||
841 | spin_unlock_irqrestore(&hp->lock, flags); | 867 | spin_unlock_irqrestore(&hp->lock, flags); |
842 | } | 868 | } |
843 | 869 | ||
@@ -865,7 +891,6 @@ static void hvsi_write_worker(struct work_struct *work) | |||
865 | { | 891 | { |
866 | struct hvsi_struct *hp = | 892 | struct hvsi_struct *hp = |
867 | container_of(work, struct hvsi_struct, writer.work); | 893 | container_of(work, struct hvsi_struct, writer.work); |
868 | struct tty_struct *tty; | ||
869 | unsigned long flags; | 894 | unsigned long flags; |
870 | #ifdef DEBUG | 895 | #ifdef DEBUG |
871 | static long start_j = 0; | 896 | static long start_j = 0; |
@@ -899,11 +924,7 @@ static void hvsi_write_worker(struct work_struct *work) | |||
899 | start_j = 0; | 924 | start_j = 0; |
900 | #endif /* DEBUG */ | 925 | #endif /* DEBUG */ |
901 | wake_up_all(&hp->emptyq); | 926 | wake_up_all(&hp->emptyq); |
902 | tty = tty_port_tty_get(&hp->port); | 927 | tty_wakeup(hp->tty); |
903 | if (tty) { | ||
904 | tty_wakeup(tty); | ||
905 | tty_kref_put(tty); | ||
906 | } | ||
907 | } | 928 | } |
908 | 929 | ||
909 | out: | 930 | out: |
@@ -948,8 +969,8 @@ static int hvsi_write(struct tty_struct *tty, | |||
948 | * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls | 969 | * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls |
949 | * will see there is no room in outbuf and return. | 970 | * will see there is no room in outbuf and return. |
950 | */ | 971 | */ |
951 | while ((count > 0) && (hvsi_write_room(tty) > 0)) { | 972 | while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { |
952 | int chunksize = min(count, hvsi_write_room(tty)); | 973 | int chunksize = min(count, hvsi_write_room(hp->tty)); |
953 | 974 | ||
954 | BUG_ON(hp->n_outbuf < 0); | 975 | BUG_ON(hp->n_outbuf < 0); |
955 | memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); | 976 | memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); |
@@ -996,16 +1017,19 @@ static void hvsi_unthrottle(struct tty_struct *tty) | |||
996 | { | 1017 | { |
997 | struct hvsi_struct *hp = tty->driver_data; | 1018 | struct hvsi_struct *hp = tty->driver_data; |
998 | unsigned long flags; | 1019 | unsigned long flags; |
1020 | int shouldflip = 0; | ||
999 | 1021 | ||
1000 | pr_debug("%s\n", __func__); | 1022 | pr_debug("%s\n", __func__); |
1001 | 1023 | ||
1002 | spin_lock_irqsave(&hp->lock, flags); | 1024 | spin_lock_irqsave(&hp->lock, flags); |
1003 | if (hp->n_throttle) { | 1025 | if (hp->n_throttle) { |
1004 | hvsi_send_overflow(hp, tty); | 1026 | hvsi_send_overflow(hp); |
1005 | tty_flip_buffer_push(tty); | 1027 | shouldflip = 1; |
1006 | } | 1028 | } |
1007 | spin_unlock_irqrestore(&hp->lock, flags); | 1029 | spin_unlock_irqrestore(&hp->lock, flags); |
1008 | 1030 | ||
1031 | if (shouldflip) | ||
1032 | tty_flip_buffer_push(hp->tty); | ||
1009 | 1033 | ||
1010 | h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); | 1034 | h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); |
1011 | } | 1035 | } |
@@ -1064,6 +1088,7 @@ static int __init hvsi_init(void) | |||
1064 | if (!hvsi_driver) | 1088 | if (!hvsi_driver) |
1065 | return -ENOMEM; | 1089 | return -ENOMEM; |
1066 | 1090 | ||
1091 | hvsi_driver->owner = THIS_MODULE; | ||
1067 | hvsi_driver->driver_name = "hvsi"; | 1092 | hvsi_driver->driver_name = "hvsi"; |
1068 | hvsi_driver->name = "hvsi"; | 1093 | hvsi_driver->name = "hvsi"; |
1069 | hvsi_driver->major = HVSI_MAJOR; | 1094 | hvsi_driver->major = HVSI_MAJOR; |
@@ -1080,9 +1105,7 @@ static int __init hvsi_init(void) | |||
1080 | struct hvsi_struct *hp = &hvsi_ports[i]; | 1105 | struct hvsi_struct *hp = &hvsi_ports[i]; |
1081 | int ret = 1; | 1106 | int ret = 1; |
1082 | 1107 | ||
1083 | tty_port_link_device(&hp->port, hvsi_driver, i); | 1108 | ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp); |
1084 | |||
1085 | ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp); | ||
1086 | if (ret) | 1109 | if (ret) |
1087 | printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", | 1110 | printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", |
1088 | hp->virq, ret); | 1111 | hp->virq, ret); |
@@ -1209,16 +1232,14 @@ static int __init hvsi_console_init(void) | |||
1209 | init_waitqueue_head(&hp->emptyq); | 1232 | init_waitqueue_head(&hp->emptyq); |
1210 | init_waitqueue_head(&hp->stateq); | 1233 | init_waitqueue_head(&hp->stateq); |
1211 | spin_lock_init(&hp->lock); | 1234 | spin_lock_init(&hp->lock); |
1212 | tty_port_init(&hp->port); | ||
1213 | hp->index = hvsi_count; | 1235 | hp->index = hvsi_count; |
1214 | hp->inbuf_end = hp->inbuf; | 1236 | hp->inbuf_end = hp->inbuf; |
1215 | hp->state = HVSI_CLOSED; | 1237 | hp->state = HVSI_CLOSED; |
1216 | hp->vtermno = *vtermno; | 1238 | hp->vtermno = *vtermno; |
1217 | hp->virq = irq_create_mapping(NULL, irq[0]); | 1239 | hp->virq = irq_create_mapping(NULL, irq[0]); |
1218 | if (hp->virq == 0) { | 1240 | if (hp->virq == NO_IRQ) { |
1219 | printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", | 1241 | printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", |
1220 | __func__, irq[0]); | 1242 | __func__, irq[0]); |
1221 | tty_port_destroy(&hp->port); | ||
1222 | continue; | 1243 | continue; |
1223 | } | 1244 | } |
1224 | 1245 | ||
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 3396eb9d57a..bd9b09827b2 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c | |||
@@ -183,7 +183,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) | |||
183 | unsigned int tries, read = 0; | 183 | unsigned int tries, read = 0; |
184 | 184 | ||
185 | if (WARN_ON(!pv)) | 185 | if (WARN_ON(!pv)) |
186 | return -ENXIO; | 186 | return 0; |
187 | 187 | ||
188 | /* If we aren't open, don't do anything in order to avoid races | 188 | /* If we aren't open, don't do anything in order to avoid races |
189 | * with connection establishment. The hvc core will call this | 189 | * with connection establishment. The hvc core will call this |
@@ -234,7 +234,7 @@ int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count) | |||
234 | int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); | 234 | int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); |
235 | 235 | ||
236 | if (WARN_ON(!pv)) | 236 | if (WARN_ON(!pv)) |
237 | return -ENODEV; | 237 | return 0; |
238 | 238 | ||
239 | dp.hdr.type = VS_DATA_PACKET_HEADER; | 239 | dp.hdr.type = VS_DATA_PACKET_HEADER; |
240 | dp.hdr.len = adjcount + sizeof(struct hvsi_header); | 240 | dp.hdr.len = adjcount + sizeof(struct hvsi_header); |
@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp) | |||
377 | pr_devel("HVSI@%x: open !\n", pv->termno); | 377 | pr_devel("HVSI@%x: open !\n", pv->termno); |
378 | 378 | ||
379 | /* Keep track of the tty data structure */ | 379 | /* Keep track of the tty data structure */ |
380 | pv->tty = tty_port_tty_get(&hp->port); | 380 | pv->tty = tty_kref_get(hp->tty); |
381 | 381 | ||
382 | hvsilib_establish(pv); | 382 | hvsilib_establish(pv); |
383 | 383 | ||
@@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp) | |||
400 | spin_unlock_irqrestore(&hp->lock, flags); | 400 | spin_unlock_irqrestore(&hp->lock, flags); |
401 | 401 | ||
402 | /* Clear our own DTR */ | 402 | /* Clear our own DTR */ |
403 | if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL)) | 403 | if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL)) |
404 | hvsilib_write_mctrl(pv, 0); | 404 | hvsilib_write_mctrl(pv, 0); |
405 | 405 | ||
406 | /* Tear down the connection */ | 406 | /* Tear down the connection */ |