u32 termno; /* HV term number */
hv_protocol_t proto; /* Raw data or HVSI packets */
struct hvsi_priv hvsi; /* HVSI specific data */
+ spinlock_t buf_lock;
+ char buf[SIZE_VIO_GET_CHARS];
+ int left;
+ int offset;
};
static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES];
-
/* For early boot console */
static struct hvterm_priv hvterm_priv0;
static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
- unsigned long got, i;
+ unsigned long i;
+ unsigned long flags;
+ int got;
if (WARN_ON(!pv))
return 0;
- /*
- * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion
- * so we play safe and avoid the situation where got > count which could
- * overload the flip buffer.
- */
- if (count < SIZE_VIO_GET_CHARS)
- return -EAGAIN;
-
- got = hvc_get_chars(pv->termno, buf, count);
-
- /*
- * Work around a HV bug where it gives us a null
- * after every \r. -- paulus
- */
- for (i = 1; i < got; ++i) {
- if (buf[i] == 0 && buf[i-1] == '\r') {
- --got;
- if (i < got)
- memmove(&buf[i], &buf[i+1], got - i);
+ spin_lock_irqsave(&pv->buf_lock, flags);
+
+ if (pv->left == 0) {
+ pv->offset = 0;
+ pv->left = hvc_get_chars(pv->termno, pv->buf, count);
+
+ /*
+ * Work around a HV bug where it gives us a null
+ * after every \r. -- paulus
+ */
+ for (i = 1; i < pv->left; ++i) {
+ if (pv->buf[i] == 0 && pv->buf[i-1] == '\r') {
+ --pv->left;
+ if (i < pv->left) {
+ memmove(&pv->buf[i], &pv->buf[i+1],
+ pv->left - i);
+ }
+ }
}
}
+
+ got = min(count, pv->left);
+ memcpy(buf, &pv->buf[pv->offset], got);
+ pv->offset += got;
+ pv->left -= got;
+
+ spin_unlock_irqrestore(&pv->buf_lock, flags);
+
return got;
}
if (WARN_ON(!pv))
return 0;
- return hvsi_get_chars(&pv->hvsi, buf, count);
+ return hvsilib_get_chars(&pv->hvsi, buf, count);
}
static int hvterm_hvsi_put_chars(uint32_t vtermno, const char *buf, int count)
if (WARN_ON(!pv))
return 0;
- return hvsi_put_chars(&pv->hvsi, buf, count);
+ return hvsilib_put_chars(&pv->hvsi, buf, count);
}
static int hvterm_hvsi_open(struct hvc_struct *hp, int data)
if (rc)
return rc;
- return hvsi_open(&pv->hvsi, hp);
+ return hvsilib_open(&pv->hvsi, hp);
}
static void hvterm_hvsi_close(struct hvc_struct *hp, int data)
pr_devel("HVSI@%x: do close !\n", pv->termno);
- hvsi_close(&pv->hvsi, hp);
+ hvsilib_close(&pv->hvsi, hp);
notifier_del_irq(hp, data);
}
pr_devel("HVSI@%x: do hangup !\n", pv->termno);
- hvsi_close(&pv->hvsi, hp);
+ hvsilib_close(&pv->hvsi, hp);
notifier_hangup_irq(hp, data);
}
pv->termno, set, clear);
if (set & TIOCM_DTR)
- hvsi_write_mctrl(&pv->hvsi, 1);
+ hvsilib_write_mctrl(&pv->hvsi, 1);
else if (clear & TIOCM_DTR)
- hvsi_write_mctrl(&pv->hvsi, 0);
+ hvsilib_write_mctrl(&pv->hvsi, 0);
return 0;
}
return -ENOMEM;
pv->termno = vdev->unit_address;
pv->proto = proto;
+ spin_lock_init(&pv->buf_lock);
hvterm_privs[termno] = pv;
- hvsi_init(&pv->hvsi, hvc_get_chars, hvc_put_chars,
- pv->termno, 0);
+ hvsilib_init(&pv->hvsi, hvc_get_chars, hvc_put_chars,
+ pv->termno, 0);
}
hp = hvc_alloc(termno, vdev->irq, ops, MAX_VIO_PUT_CHARS);
if (termno == NULL)
goto out;
hvterm_priv0.termno = *termno;
+ spin_lock_init(&hvterm_priv0.buf_lock);
hvterm_privs[0] = &hvterm_priv0;
/* Check the protocol */
else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) {
hvterm_priv0.proto = HV_PROTOCOL_HVSI;
ops = &hvterm_hvsi_ops;
- hvsi_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars,
- hvterm_priv0.termno, 1);
+ hvsilib_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars,
+ hvterm_priv0.termno, 1);
/* HVSI, perform the handshake now */
- hvsi_establish(&hvterm_priv0.hvsi);
+ hvsilib_establish(&hvterm_priv0.hvsi);
} else
goto out;
udbg_putc = udbg_hvc_putc;
hvterm_privs[0] = &hvterm_priv0;
hvterm_priv0.termno = 0;
hvterm_priv0.proto = HV_PROTOCOL_RAW;
+ spin_lock_init(&hvterm_priv0.buf_lock);
udbg_putc = udbg_hvc_putc;
udbg_getc = udbg_hvc_getc;
udbg_getc_poll = udbg_hvc_getc_poll;
hvterm_privs[0] = &hvterm_priv0;
hvterm_priv0.termno = CONFIG_PPC_EARLY_DEBUG_HVSI_VTERMNO;
hvterm_priv0.proto = HV_PROTOCOL_HVSI;
+ spin_lock_init(&hvterm_priv0.buf_lock);
udbg_putc = udbg_hvc_putc;
udbg_getc = udbg_hvc_getc;
udbg_getc_poll = udbg_hvc_getc_poll;
- hvsi_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars,
- hvterm_priv0.termno, 1);
- hvsi_establish(&hvterm_priv0.hvsi);
+ hvsilib_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars,
+ hvterm_priv0.termno, 1);
+ hvsilib_establish(&hvterm_priv0.hvsi);
}
#endif /* CONFIG_PPC_EARLY_DEBUG_LPAR_HVSI */