aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2011-07-12 15:19:57 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-07-19 01:13:07 -0400
commit19df9abdd30a0448e5940c6aa3527096bb69aca7 (patch)
tree207168aac6dc399419eb0048c4ba47e69628a7cf
parent88962934226c570717c346684ab5ed2f09c2b359 (diff)
powerpc/pseries: Fix hvterm_raw_get_chars to accept < 16 chars, fixing xmon
commit 4d2bb3f50036 (powerpc/pseries: Re-implement HVSI as part of hvc_vio) changed udbg_getc to be based on hvterm_raw_get_chars. Unfortunately hvterm_raw_get_chars returns -EAGAIN if you ask for anything less than 16 characters. As a result xmon no longer accepts input and prints a stream of junk to the screen. The recent change highlights a problem that xmon on pseries VIO has had all along, that it can drop input characters. The issue is the hypervisor call does not take a count argument and can return up to 16 characters. This patch adds a per vterm buffer that we copy input data into and give it out as requested. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--drivers/tty/hvc/hvc_vio.c58
1 files changed, 37 insertions, 21 deletions
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 710c06ca70f..ae659a4596b 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};
75static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES]; 79static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES];
76
77/* For early boot console */ 80/* For early boot console */
78static struct hvterm_priv hvterm_priv0; 81static struct hvterm_priv hvterm_priv0;
79 82
80static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) 83static 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;