Skip to content

Commit

Permalink
arm64: wait for transmit completion before next character transmission
Browse files Browse the repository at this point in the history
Previous transmission must be completed before next character to be
transmitted, otherwise TX buffer may saturate and we will not see all
the characters on screen.

Signed-off-by: Pratyush Anand <panand@redhat.com>
  • Loading branch information
Pratyush Anand committed Oct 29, 2015
1 parent d7d1bec commit 57344a8
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 2 deletions.
7 changes: 6 additions & 1 deletion kexec/arch/arm64/include/arch/options.h
Expand Up @@ -7,7 +7,8 @@
#define OPT_PAGE_OFFSET ((OPT_MAX)+3)
#define OPT_PORT ((OPT_MAX)+4)
#define OPT_REUSE_CMDLINE ((OPT_MAX)+5)
#define OPT_ARCH_MAX ((OPT_MAX)+6)
#define OPT_PORT_LSR ((OPT_MAX)+6)
#define OPT_ARCH_MAX ((OPT_MAX)+7)

#define KEXEC_ARCH_OPTIONS \
KEXEC_OPTIONS \
Expand All @@ -17,6 +18,7 @@
{ "initrd", 1, NULL, OPT_INITRD }, \
{ "page-offset", 1, NULL, OPT_PAGE_OFFSET }, \
{ "port", 1, NULL, OPT_PORT }, \
{ "port-lsr", 1, NULL, OPT_PORT_LSR }, \
{ "ramdisk", 1, NULL, OPT_INITRD }, \
{ "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \

Expand All @@ -30,6 +32,7 @@ static const char arm64_opts_usage[] __attribute__ ((unused)) =
" --dtb=FILE Use FILE as the device tree blob.\n"
" --initrd=FILE Use FILE as the kernel initial ramdisk.\n"
" --port=ADDRESS Purgatory output to port ADDRESS.\n"
" --port-lsr=ADDR,VAL Purgatory output port line status address and TX Empty Bit Field.\n"
" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n"
" --reuse-cmdline Use command line arg of primary kernel.\n";

Expand All @@ -39,6 +42,8 @@ struct arm64_opts {
const char *initrd;
uint64_t page_offset;
uint64_t port;
uint64_t port_lsr;
uint32_t port_lsr_val;
};

extern struct arm64_opts arm64_opts;
Expand Down
17 changes: 17 additions & 0 deletions kexec/arch/arm64/kexec-arm64.c
Expand Up @@ -97,6 +97,12 @@ int arch_process_options(int argc, char **argv)
case OPT_PORT:
arm64_opts.port = strtoull(optarg, NULL, 0);
break;
case OPT_PORT_LSR:
arm64_opts.port_lsr = strtoull(strtok(optarg, ","),
NULL, 0);
arm64_opts.port_lsr_val = strtoul(strtok(NULL, ","),
NULL, 0);
break;
case OPT_PAGE_OFFSET:
arm64_opts.page_offset = strtoull(optarg, NULL, 0);
break;
Expand Down Expand Up @@ -589,6 +595,8 @@ int arm64_load_other_segments(struct kexec_info *info,
uint64_t dtb_base;
unsigned long hole_min, hole_max;
uint64_t purgatory_sink;
uint64_t purgatory_sink_lsr;
uint32_t purgatory_sink_lsr_val;
struct mem_ehdr ehdr;
char *initrd_buf = NULL;
struct dtb dtb_1 = {.name = "dtb_1"};
Expand All @@ -611,6 +619,9 @@ int arm64_load_other_segments(struct kexec_info *info,
dbgprintf("%s:%d: purgatory sink: 0x%" PRIx64 "\n", __func__, __LINE__,
purgatory_sink);

purgatory_sink_lsr = arm64_opts.port_lsr;
purgatory_sink_lsr_val = arm64_opts.port_lsr_val;

if (arm64_opts.dtb) {
dtb_2.buf = slurp_file(arm64_opts.dtb, &dtb_2.size);
assert(dtb_2.buf);
Expand Down Expand Up @@ -707,6 +718,12 @@ int arm64_load_other_segments(struct kexec_info *info,
elf_rel_set_symbol(&info->rhdr, "arm64_sink", &purgatory_sink,
sizeof(purgatory_sink));

elf_rel_set_symbol(&info->rhdr, "arm64_sink_lsr", &purgatory_sink_lsr,
sizeof(purgatory_sink_lsr));

elf_rel_set_symbol(&info->rhdr, "arm64_sink_lsr_val",
&purgatory_sink_lsr_val, sizeof(purgatory_sink_lsr_val));

elf_rel_set_symbol(&info->rhdr, "arm64_kernel_entry", &kernel_entry,
sizeof(kernel_entry));

Expand Down
10 changes: 10 additions & 0 deletions purgatory/arch/arm64/entry.S
Expand Up @@ -43,6 +43,11 @@ arm64_sink:
.quad 0
size arm64_sink

.globl arm64_sink_lsr
arm64_sink_lsr:
.quad 0
size arm64_sink_lsr

.globl arm64_kernel_entry
arm64_kernel_entry:
.quad 0
Expand All @@ -57,3 +62,8 @@ size arm64_dtb_addr
arm64_kexec_lite:
.quad 0
size arm64_kexec_lite

.globl arm64_sink_lsr_val
arm64_sink_lsr_val:
.long 0
size arm64_sink_lsr_val
22 changes: 21 additions & 1 deletion purgatory/arch/arm64/purgatory-arm64.c
Expand Up @@ -8,18 +8,38 @@
/* Symbols set by kexec. */

extern uint32_t *arm64_sink;
extern uint32_t *arm64_sink_lsr;
extern uint32_t arm64_sink_lsr_val;
extern void (*arm64_kernel_entry)(uint64_t);
extern uint64_t arm64_dtb_addr;

static void wait_for_xmit_complete(void)
{
volatile uint32_t status;
volatile uint32_t *status_reg = (volatile uint32_t *)arm64_sink_lsr;

if (!arm64_sink_lsr)
return;

while (1) {
status = *status_reg;
if ((status & arm64_sink_lsr_val) == arm64_sink_lsr_val)
break;
}
}

void putchar(int ch)
{
if (!arm64_sink)
return;

wait_for_xmit_complete();
*arm64_sink = ch;

if (ch == '\n')
if (ch == '\n') {
wait_for_xmit_complete();
*arm64_sink = '\r';
}
}

void post_verification_setup_arch(void)
Expand Down

0 comments on commit 57344a8

Please sign in to comment.