opal_console: fix serial console output corruption on powerpc64
Adds OPAL_CONSOLE_WRITE error handling and implements a call to OPAL_CONSOLE_WRITE_BUFFER_SPACE to verify if there's enough space before writing to console. This fixes serial port output getting corrupted on fast writes, like on "dmesg" output. Tested on Raptor Blackbird running powerpc64 BE kernel Reviewed by: luporl Sponsored by: Eldorado Reserach Institute (eldorado.org.br) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D29063
This commit is contained in:
parent
3e34783420
commit
b8bc6b7954
@ -56,6 +56,7 @@ int opal_call(uint64_t token, ...);
|
|||||||
#define OPAL_PCI_CONFIG_WRITE_HALF_WORD 17
|
#define OPAL_PCI_CONFIG_WRITE_HALF_WORD 17
|
||||||
#define OPAL_PCI_CONFIG_WRITE_WORD 18
|
#define OPAL_PCI_CONFIG_WRITE_WORD 18
|
||||||
#define OPAL_PCI_EEH_FREEZE_STATUS 23
|
#define OPAL_PCI_EEH_FREEZE_STATUS 23
|
||||||
|
#define OPAL_CONSOLE_WRITE_BUFFER_SPACE 25
|
||||||
#define OPAL_PCI_EEH_FREEZE_CLEAR 26
|
#define OPAL_PCI_EEH_FREEZE_CLEAR 26
|
||||||
#define OPAL_PCI_PHB_MMIO_ENABLE 27
|
#define OPAL_PCI_PHB_MMIO_ENABLE 27
|
||||||
#define OPAL_PCI_SET_PHB_MEM_WINDOW 28
|
#define OPAL_PCI_SET_PHB_MEM_WINDOW 28
|
||||||
|
@ -171,6 +171,24 @@ uart_opal_real_unmap_outbuffer(uint64_t *len)
|
|||||||
mtx_unlock_spin(&opalcons_buffer.mtx);
|
mtx_unlock_spin(&opalcons_buffer.mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
uart_opal_console_write_buffer_space(int vtermid)
|
||||||
|
{
|
||||||
|
int64_t buffer_space_val = 0;
|
||||||
|
vm_paddr_t buffer_space_ptr;
|
||||||
|
|
||||||
|
if (pmap_bootstrapped)
|
||||||
|
buffer_space_ptr = vtophys(&buffer_space_val);
|
||||||
|
else
|
||||||
|
buffer_space_ptr = (vm_paddr_t)&buffer_space_val;
|
||||||
|
|
||||||
|
if (opal_call(OPAL_CONSOLE_WRITE_BUFFER_SPACE, vtermid,
|
||||||
|
buffer_space_ptr) != OPAL_SUCCESS)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
return (be64toh(buffer_space_val));
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
uart_opal_probe_node(struct uart_opal_softc *sc)
|
uart_opal_probe_node(struct uart_opal_softc *sc)
|
||||||
{
|
{
|
||||||
@ -420,12 +438,12 @@ uart_opal_put(struct uart_opal_softc *sc, void *buffer, size_t bufsize)
|
|||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (err == OPAL_SUCCESS)
|
||||||
if (err != OPAL_SUCCESS)
|
return (len);
|
||||||
len = 0;
|
else if (err == OPAL_BUSY_EVENT)
|
||||||
#endif
|
return(0);
|
||||||
|
|
||||||
return (len);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -481,11 +499,28 @@ uart_opal_ttyoutwakeup(struct tty *tp)
|
|||||||
struct uart_opal_softc *sc;
|
struct uart_opal_softc *sc;
|
||||||
char buffer[8];
|
char buffer[8];
|
||||||
int len;
|
int len;
|
||||||
|
int64_t buffer_space;
|
||||||
|
|
||||||
sc = tty_softc(tp);
|
sc = tty_softc(tp);
|
||||||
|
|
||||||
while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0)
|
while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) {
|
||||||
uart_opal_put(sc, buffer, len);
|
int bytes_written = 0;
|
||||||
|
while (bytes_written == 0) {
|
||||||
|
buffer_space = uart_opal_console_write_buffer_space(sc->vtermid);
|
||||||
|
if (buffer_space == -1)
|
||||||
|
/* OPAL failure or invalid terminal */
|
||||||
|
break;
|
||||||
|
else if (buffer_space >= len)
|
||||||
|
bytes_written = uart_opal_put(sc, buffer, len);
|
||||||
|
|
||||||
|
if (bytes_written == 0)
|
||||||
|
/* OPAL must be busy, poll and retry */
|
||||||
|
opal_call(OPAL_POLL_EVENTS, NULL);
|
||||||
|
else if (bytes_written == -1)
|
||||||
|
/* OPAL failure or invalid terminal */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user