diff options
-rw-r--r-- | drivers/tty/hvc/hvc_vio.c | 58 |
1 files changed, 37 insertions, 21 deletions
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 710c06ca70f4..ae659a4596b0 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c | |||
@@ -71,41 +71,53 @@ struct hvterm_priv { | |||
71 | u32 termno; /* HV term number */ | 71 | u32 termno; /* HV term number */ |
72 | hv_protocol_t proto; /* Raw data or HVSI packets */ | 72 | hv_protocol_t proto; /* Raw data or HVSI packets */ |
73 | struct hvsi_priv hvsi; /* HVSI specific data */ | 73 | struct hvsi_priv hvsi; /* HVSI specific data */ |
74 | spinlock_t buf_lock; | ||
75 | char buf[SIZE_VIO_GET_CHARS]; | ||
76 | int left; | ||
77 | int offset; | ||
74 | }; | 78 | }; |
75 | static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES]; | 79 | static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES]; |
76 | |||
77 | /* For early boot console */ | 80 | /* For early boot console */ |
78 | static struct hvterm_priv hvterm_priv0; | 81 | static struct hvterm_priv hvterm_priv0; |
79 | 82 | ||
80 | static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) | 83 | static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) |
81 | { | 84 | { |
82 | struct hvterm_priv *pv = hvterm_privs[vtermno]; | 85 | struct hvterm_priv *pv = hvterm_privs[vtermno]; |
83 | unsigned long got, i; | 86 | unsigned long i; |
87 | unsigned long flags; | ||
88 | int got; | ||
84 | 89 | ||
85 | if (WARN_ON(!pv)) | 90 | if (WARN_ON(!pv)) |
86 | return 0; | 91 | return 0; |
87 | 92 | ||
88 | /* | 93 | spin_lock_irqsave(&pv->buf_lock, flags); |
89 | * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion | 94 | |
90 | * so we play safe and avoid the situation where got > count which could | 95 | if (pv->left == 0) { |
91 | * overload the flip buffer. | 96 | pv->offset = 0; |
92 | */ | 97 | pv->left = hvc_get_chars(pv->termno, pv->buf, count); |
93 | if (count < SIZE_VIO_GET_CHARS) | 98 | |
94 | return -EAGAIN; | 99 | /* |
95 | 100 | * Work around a HV bug where it gives us a null | |
96 | got = hvc_get_chars(pv->termno, buf, count); | 101 | * after every \r. -- paulus |
97 | 102 | */ | |
98 | /* | 103 | for (i = 1; i < pv->left; ++i) { |
99 | * Work around a HV bug where it gives us a null | 104 | if (pv->buf[i] == 0 && pv->buf[i-1] == '\r') { |
100 | * after every \r. -- paulus | 105 | --pv->left; |
101 | */ | 106 | if (i < pv->left) { |
102 | for (i = 1; i < got; ++i) { | 107 | memmove(&pv->buf[i], &pv->buf[i+1], |
103 | if (buf[i] == 0 && buf[i-1] == '\r') { | 108 | pv->left - i); |
104 | --got; | 109 | } |
105 | if (i < got) | 110 | } |
106 | memmove(&buf[i], &buf[i+1], got - i); | ||
107 | } | 111 | } |
108 | } | 112 | } |
113 | |||
114 | got = min(count, pv->left); | ||
115 | memcpy(buf, &pv->buf[pv->offset], got); | ||
116 | pv->offset += got; | ||
117 | pv->left -= got; | ||
118 | |||
119 | spin_unlock_irqrestore(&pv->buf_lock, flags); | ||
120 | |||
109 | return got; | 121 | return got; |
110 | } | 122 | } |
111 | 123 | ||
@@ -266,6 +278,7 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev, | |||
266 | return -ENOMEM; | 278 | return -ENOMEM; |
267 | pv->termno = vdev->unit_address; | 279 | pv->termno = vdev->unit_address; |
268 | pv->proto = proto; | 280 | pv->proto = proto; |
281 | spin_lock_init(&pv->buf_lock); | ||
269 | hvterm_privs[termno] = pv; | 282 | hvterm_privs[termno] = pv; |
270 | hvsilib_init(&pv->hvsi, hvc_get_chars, hvc_put_chars, | 283 | hvsilib_init(&pv->hvsi, hvc_get_chars, hvc_put_chars, |
271 | pv->termno, 0); | 284 | pv->termno, 0); |
@@ -406,6 +419,7 @@ void __init hvc_vio_init_early(void) | |||
406 | if (termno == NULL) | 419 | if (termno == NULL) |
407 | goto out; | 420 | goto out; |
408 | hvterm_priv0.termno = *termno; | 421 | hvterm_priv0.termno = *termno; |
422 | spin_lock_init(&hvterm_priv0.buf_lock); | ||
409 | hvterm_privs[0] = &hvterm_priv0; | 423 | hvterm_privs[0] = &hvterm_priv0; |
410 | 424 | ||
411 | /* Check the protocol */ | 425 | /* Check the protocol */ |
@@ -447,6 +461,7 @@ void __init udbg_init_debug_lpar(void) | |||
447 | hvterm_privs[0] = &hvterm_priv0; | 461 | hvterm_privs[0] = &hvterm_priv0; |
448 | hvterm_priv0.termno = 0; | 462 | hvterm_priv0.termno = 0; |
449 | hvterm_priv0.proto = HV_PROTOCOL_RAW; | 463 | hvterm_priv0.proto = HV_PROTOCOL_RAW; |
464 | spin_lock_init(&hvterm_priv0.buf_lock) | ||
450 | udbg_putc = udbg_hvc_putc; | 465 | udbg_putc = udbg_hvc_putc; |
451 | udbg_getc = udbg_hvc_getc; | 466 | udbg_getc = udbg_hvc_getc; |
452 | udbg_getc_poll = udbg_hvc_getc_poll; | 467 | udbg_getc_poll = udbg_hvc_getc_poll; |
@@ -459,6 +474,7 @@ void __init udbg_init_debug_lpar_hvsi(void) | |||
459 | hvterm_privs[0] = &hvterm_priv0; | 474 | hvterm_privs[0] = &hvterm_priv0; |
460 | hvterm_priv0.termno = CONFIG_PPC_EARLY_DEBUG_HVSI_VTERMNO; | 475 | hvterm_priv0.termno = CONFIG_PPC_EARLY_DEBUG_HVSI_VTERMNO; |
461 | hvterm_priv0.proto = HV_PROTOCOL_HVSI; | 476 | hvterm_priv0.proto = HV_PROTOCOL_HVSI; |
477 | spin_lock_init(&hvterm_priv0.buf_lock) | ||
462 | udbg_putc = udbg_hvc_putc; | 478 | udbg_putc = udbg_hvc_putc; |
463 | udbg_getc = udbg_hvc_getc; | 479 | udbg_getc = udbg_hvc_getc; |
464 | udbg_getc_poll = udbg_hvc_getc_poll; | 480 | udbg_getc_poll = udbg_hvc_getc_poll; |