powerpc/powernv: Support for OPAL console

This adds a udbg and an hvc console backend for supporting a console
using the OPAL console interfaces.

On OPAL v1 we have hvc0 mapped to whatever console the system was
configured for (network or hvsi serial port) via the service
processor.

On OPAL v2 we have hvcN mapped to the Nth console provided by OPAL
which generally corresponds to:

	hvc0 : network console (raw protocol)
	hvc1 : serial port S1 (hvsi)
	hvc2 : serial port S2 (hvsi)

Note: At this point, early debug console only works with OPAL v1
and shouldn't be enabled in a normal kernel.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 6e35d5da
...@@ -265,8 +265,27 @@ config PPC_EARLY_DEBUG_PS3GELIC ...@@ -265,8 +265,27 @@ config PPC_EARLY_DEBUG_PS3GELIC
Select this to enable early debugging for the PlayStation3 via Select this to enable early debugging for the PlayStation3 via
UDP broadcasts sent out through the Ethernet port. UDP broadcasts sent out through the Ethernet port.
config PPC_EARLY_DEBUG_OPAL_RAW
bool "OPAL raw console"
depends on HVC_OPAL
help
Select this to enable early debugging for the PowerNV platform
using a "raw" console
config PPC_EARLY_DEBUG_OPAL_HVSI
bool "OPAL hvsi console"
depends on HVC_OPAL
help
Select this to enable early debugging for the PowerNV platform
using an "hvsi" console
endchoice endchoice
config PPC_EARLY_DEBUG_OPAL
def_bool y
depends on PPC_EARLY_DEBUG_OPAL_RAW || PPC_EARLY_DEBUG_OPAL_HVSI
config PPC_EARLY_DEBUG_HVSI_VTERMNO config PPC_EARLY_DEBUG_HVSI_VTERMNO
hex "vterm number to use with early debug HVSI" hex "vterm number to use with early debug HVSI"
depends on PPC_EARLY_DEBUG_LPAR_HVSI depends on PPC_EARLY_DEBUG_LPAR_HVSI
...@@ -275,6 +294,18 @@ config PPC_EARLY_DEBUG_HVSI_VTERMNO ...@@ -275,6 +294,18 @@ config PPC_EARLY_DEBUG_HVSI_VTERMNO
You probably want 0x30000000 for your first serial port and You probably want 0x30000000 for your first serial port and
0x30000001 for your second one 0x30000001 for your second one
config PPC_EARLY_DEBUG_OPAL_VTERMNO
hex "vterm number to use with OPAL early debug"
depends on PPC_EARLY_DEBUG_OPAL
default "0"
help
This correspond to which /dev/hvcN you want to use for early
debug.
On OPAL v1 (takeover) this should always be 0
On OPAL v2, this will be 0 for network console and 1 or 2 for
the machine built-in serial ports.
config PPC_EARLY_DEBUG_44x_PHYSLOW config PPC_EARLY_DEBUG_44x_PHYSLOW
hex "Low 32 bits of early debug UART physical address" hex "Low 32 bits of early debug UART physical address"
depends on PPC_EARLY_DEBUG_44x depends on PPC_EARLY_DEBUG_44x
......
...@@ -425,6 +425,11 @@ extern void hvc_opal_init_early(void); ...@@ -425,6 +425,11 @@ extern void hvc_opal_init_early(void);
extern int early_init_dt_scan_opal(unsigned long node, const char *uname, extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
int depth, void *data); int depth, void *data);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
extern void hvc_opal_init_early(void);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __OPAL_H */ #endif /* __OPAL_H */
...@@ -55,6 +55,8 @@ extern void __init udbg_init_cpm(void); ...@@ -55,6 +55,8 @@ extern void __init udbg_init_cpm(void);
extern void __init udbg_init_usbgecko(void); extern void __init udbg_init_usbgecko(void);
extern void __init udbg_init_wsp(void); extern void __init udbg_init_wsp(void);
extern void __init udbg_init_ps3gelic(void); extern void __init udbg_init_ps3gelic(void);
extern void __init udbg_init_debug_opal_raw(void);
extern void __init udbg_init_debug_opal_hvsi(void);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UDBG_H */ #endif /* _ASM_POWERPC_UDBG_H */
...@@ -53,7 +53,8 @@ ...@@ -53,7 +53,8 @@
* 2. The kernel is entered at __start * 2. The kernel is entered at __start
* -or- For OPAL entry: * -or- For OPAL entry:
* 1. The MMU is off, processor in HV mode, primary CPU enters at 0 * 1. The MMU is off, processor in HV mode, primary CPU enters at 0
* with device-tree in gpr3 * with device-tree in gpr3. We also get OPAL base in r8 and
* entry in r9 for debugging purposes
* 2. Secondary processors enter at 0x60 with PIR in gpr3 * 2. Secondary processors enter at 0x60 with PIR in gpr3
* *
* For iSeries: * For iSeries:
...@@ -335,6 +336,11 @@ _GLOBAL(__start_initialization_multiplatform) ...@@ -335,6 +336,11 @@ _GLOBAL(__start_initialization_multiplatform)
/* Save parameters */ /* Save parameters */
mr r31,r3 mr r31,r3
mr r30,r4 mr r30,r4
#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
/* Save OPAL entry */
mr r28,r8
mr r29,r9
#endif
#ifdef CONFIG_PPC_BOOK3E #ifdef CONFIG_PPC_BOOK3E
bl .start_initialization_book3e bl .start_initialization_book3e
...@@ -711,6 +717,12 @@ _INIT_STATIC(start_here_multiplatform) ...@@ -711,6 +717,12 @@ _INIT_STATIC(start_here_multiplatform)
bdnz 3b bdnz 3b
4: 4:
#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
/* Setup OPAL entry */
std r28,0(r11);
std r29,8(r11);
#endif
#ifndef CONFIG_PPC_BOOK3E #ifndef CONFIG_PPC_BOOK3E
mfmsr r6 mfmsr r6
ori r6,r6,MSR_RI ori r6,r6,MSR_RI
......
...@@ -69,6 +69,10 @@ void __init udbg_early_init(void) ...@@ -69,6 +69,10 @@ void __init udbg_early_init(void)
udbg_init_wsp(); udbg_init_wsp();
#elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC) #elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC)
udbg_init_ps3gelic(); udbg_init_ps3gelic();
#elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_RAW)
udbg_init_debug_opal_raw();
#elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI)
udbg_init_debug_opal_hvsi();
#endif #endif
#ifdef CONFIG_PPC_EARLY_DEBUG #ifdef CONFIG_PPC_EARLY_DEBUG
......
...@@ -67,7 +67,7 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) ...@@ -67,7 +67,7 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count)
u64 evt; u64 evt;
if (!opal.entry) if (!opal.entry)
return 0; return -ENODEV;
opal_poll_events(&evt); opal_poll_events(&evt);
if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0) if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0)
return 0; return 0;
...@@ -81,31 +81,38 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) ...@@ -81,31 +81,38 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count)
int opal_put_chars(uint32_t vtermno, const char *data, int total_len) int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
{ {
int written = 0; int written = 0;
s64 len, rc = OPAL_BUSY; s64 len, rc;
unsigned long flags; unsigned long flags;
u64 evt; u64 evt;
if (!opal.entry) if (!opal.entry)
return 0; return -ENODEV;
/* We want put_chars to be atomic to avoid mangling of hvsi /* We want put_chars to be atomic to avoid mangling of hvsi
* packets. To do that, we first test for room and return * packets. To do that, we first test for room and return
* -EAGAIN if there isn't enough * -EAGAIN if there isn't enough.
*
* Unfortunately, opal_console_write_buffer_space() doesn't
* appear to work on opal v1, so we just assume there is
* enough room and be done with it
*/ */
spin_lock_irqsave(&opal_write_lock, flags); spin_lock_irqsave(&opal_write_lock, flags);
rc = opal_console_write_buffer_space(vtermno, &len); if (firmware_has_feature(FW_FEATURE_OPALv2)) {
if (rc || len < total_len) { rc = opal_console_write_buffer_space(vtermno, &len);
spin_unlock_irqrestore(&opal_write_lock, flags); if (rc || len < total_len) {
/* Closed -> drop characters */ spin_unlock_irqrestore(&opal_write_lock, flags);
if (rc) /* Closed -> drop characters */
return total_len; if (rc)
opal_poll_events(&evt); return total_len;
return -EAGAIN; opal_poll_events(&evt);
return -EAGAIN;
}
} }
/* We still try to handle partial completions, though they /* We still try to handle partial completions, though they
* should no longer happen. * should no longer happen.
*/ */
rc = OPAL_BUSY;
while(total_len > 0 && (rc == OPAL_BUSY || while(total_len > 0 && (rc == OPAL_BUSY ||
rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) { rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) {
len = total_len; len = total_len;
......
...@@ -29,17 +29,12 @@ ...@@ -29,17 +29,12 @@
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#include <asm/xics.h> #include <asm/xics.h>
#include <asm/opal.h>
#include "powernv.h" #include "powernv.h"
static void __init pnv_setup_arch(void) static void __init pnv_setup_arch(void)
{ {
/* Force console to hvc for now until we have sorted out the
* real console situation for the platform. This will make
* hvc_udbg work at least.
*/
add_preferred_console("hvc", 0, NULL);
/* Initialize SMP */ /* Initialize SMP */
pnv_smp_init(); pnv_smp_init();
...@@ -55,7 +50,12 @@ static void __init pnv_setup_arch(void) ...@@ -55,7 +50,12 @@ static void __init pnv_setup_arch(void)
static void __init pnv_init_early(void) static void __init pnv_init_early(void)
{ {
/* XXX IOMMU */ #ifdef CONFIG_HVC_OPAL
if (firmware_has_feature(FW_FEATURE_OPAL))
hvc_opal_init_early();
else
#endif
add_preferred_console("hvc", 0, NULL);
} }
static void __init pnv_init_IRQ(void) static void __init pnv_init_IRQ(void)
......
...@@ -34,6 +34,15 @@ config HVC_ISERIES ...@@ -34,6 +34,15 @@ config HVC_ISERIES
help help
iSeries machines support a hypervisor virtual console. iSeries machines support a hypervisor virtual console.
config HVC_OPAL
bool "OPAL Console support"
depends on PPC_POWERNV
select HVC_DRIVER
select HVC_IRQ
default y
help
PowerNV machines running under OPAL need that driver to get a console
config HVC_RTAS config HVC_RTAS
bool "IBM RTAS Console support" bool "IBM RTAS Console support"
depends on PPC_RTAS depends on PPC_RTAS
......
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o
obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o
obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
......
This diff is collapsed.
...@@ -183,7 +183,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) ...@@ -183,7 +183,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
unsigned int tries, read = 0; unsigned int tries, read = 0;
if (WARN_ON(!pv)) if (WARN_ON(!pv))
return 0; return -ENXIO;
/* If we aren't open, don't do anything in order to avoid races /* If we aren't open, don't do anything in order to avoid races
* with connection establishment. The hvc core will call this * 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,7 +234,7 @@ int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count)
int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA);
if (WARN_ON(!pv)) if (WARN_ON(!pv))
return 0; return -ENODEV;
dp.hdr.type = VS_DATA_PACKET_HEADER; dp.hdr.type = VS_DATA_PACKET_HEADER;
dp.hdr.len = adjcount + sizeof(struct hvsi_header); dp.hdr.len = adjcount + sizeof(struct hvsi_header);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment