Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351193
b: refs/heads/master
c: 2475ff9
h: refs/heads/master
i:
  351191: 9062223
v: v3
  • Loading branch information
Catalin Marinas committed Jan 22, 2013
1 parent a270a25 commit 7168024
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d6bafb9b821a3a5ddeb600a9fd015085760d818e
refs/heads/master: 2475ff9d2c6ea3bbfed55c4635426c371f9ad327
2 changes: 2 additions & 0 deletions trunk/Documentation/arm64/memory.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap

ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap]

ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device

ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O space

ffffffbbffff0000 ffffffbcffffffff ~2MB [guard]
Expand Down
9 changes: 9 additions & 0 deletions trunk/arch/arm64/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,13 @@ config DEBUG_STACK_USAGE
Enables the display of the minimum amount of free stack which each
task has ever had available in the sysrq-T output.

config EARLY_PRINTK
bool "Early printk support"
default y
help
Say Y here if you want to have an early console using the
earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It
is assumed that the early console device has been initialised
by the boot loader prior to starting the Linux kernel.

endmenu
3 changes: 3 additions & 0 deletions trunk/arch/arm64/include/asm/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ extern void __iounmap(volatile void __iomem *addr);
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define iounmap __iounmap

#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF)
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PTE_PXN | PTE_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))

#define ARCH_HAS_IOREMAP_WC
#include <asm-generic/iomap.h>

Expand Down
1 change: 1 addition & 0 deletions trunk/arch/arm64/include/asm/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define PAGE_OFFSET UL(0xffffffc000000000)
#define MODULES_END (PAGE_OFFSET)
#define MODULES_VADDR (MODULES_END - SZ_64M)
#define EARLYCON_IOBASE (MODULES_VADDR - SZ_4M)
#define VA_BITS (39)
#define TASK_SIZE_64 (UL(1) << VA_BITS)

Expand Down
1 change: 1 addition & 0 deletions trunk/arch/arm64/include/asm/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ typedef struct {

extern void paging_init(void);
extern void setup_mm_for_reboot(void);
extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);

#endif
1 change: 1 addition & 0 deletions trunk/arch/arm64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o

obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
Expand Down
118 changes: 118 additions & 0 deletions trunk/arch/arm64/kernel/early_printk.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Earlyprintk support.
*
* Copyright (C) 2012 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/io.h>

#include <linux/amba/serial.h>

static void __iomem *early_base;
static void (*printch)(char ch);

/*
* PL011 single character TX.
*/
static void pl011_printch(char ch)
{
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
;
writeb_relaxed(ch, early_base + UART01x_DR);
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
;
}

struct earlycon_match {
const char *name;
void (*printch)(char ch);
};

static const struct earlycon_match earlycon_match[] __initconst = {
{ .name = "pl011", .printch = pl011_printch, },
{}
};

static void early_write(struct console *con, const char *s, unsigned n)
{
while (n-- > 0) {
if (*s == '\n')
printch('\r');
printch(*s);
s++;
}
}

static struct console early_console = {
.name = "earlycon",
.write = early_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};

/*
* Parse earlyprintk=... parameter in the format:
*
* <name>[,<addr>][,<options>]
*
* and register the early console. It is assumed that the UART has been
* initialised by the bootloader already.
*/
static int __init setup_early_printk(char *buf)
{
const struct earlycon_match *match = earlycon_match;
phys_addr_t paddr = 0;

if (!buf) {
pr_warning("No earlyprintk arguments passed.\n");
return 0;
}

while (match->name) {
size_t len = strlen(match->name);
if (!strncmp(buf, match->name, len)) {
buf += len;
break;
}
match++;
}
if (!match->name) {
pr_warning("Unknown earlyprintk arguments: %s\n", buf);
return 0;
}

/* I/O address */
if (!strncmp(buf, ",0x", 3)) {
char *e;
paddr = simple_strtoul(buf + 1, &e, 16);
buf = e;
}
/* no options parsing yet */

if (paddr)
early_base = early_io_map(paddr, EARLYCON_IOBASE);

printch = match->printch;
register_console(&early_console);

return 0;
}

early_param("earlyprintk", setup_early_printk);
12 changes: 10 additions & 2 deletions trunk/arch/arm64/kernel/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,8 @@

#ifdef CONFIG_ARM64_64K_PAGES
#define MM_MMUFLAGS PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS
#define IO_MMUFLAGS PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS
#else
#define MM_MMUFLAGS PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS
#define IO_MMUFLAGS PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS
#endif

/*
Expand Down Expand Up @@ -368,6 +366,7 @@ ENDPROC(__calc_phys_offset)
* - identity mapping to enable the MMU (low address, TTBR0)
* - first few MB of the kernel linear mapping to jump to once the MMU has
* been enabled, including the FDT blob (TTBR1)
* - UART mapping if CONFIG_EARLY_PRINTK is enabled (TTBR1)
*/
__create_page_tables:
pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses
Expand Down Expand Up @@ -420,6 +419,15 @@ __create_page_tables:
sub x6, x6, #1 // inclusive range
create_block_map x0, x7, x3, x5, x6
1:
#ifdef CONFIG_EARLY_PRINTK
/*
* Create the pgd entry for the UART mapping. The full mapping is done
* later based earlyprintk kernel parameter.
*/
ldr x5, =EARLYCON_IOBASE // UART virtual address
add x0, x26, #2 * PAGE_SIZE // section table address
create_pgd_entry x26, x0, x5, x6, x7
#endif
ret
ENDPROC(__create_page_tables)
.ltorg
Expand Down
42 changes: 42 additions & 0 deletions trunk/arch/arm64/mm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/nodemask.h>
#include <linux/memblock.h>
#include <linux/fs.h>
#include <linux/io.h>

#include <asm/cputype.h>
#include <asm/sections.h>
Expand Down Expand Up @@ -251,6 +252,47 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
} while (pgd++, addr = next, addr != end);
}

#ifdef CONFIG_EARLY_PRINTK
/*
* Create an early I/O mapping using the pgd/pmd entries already populated
* in head.S as this function is called too early to allocated any memory. The
* mapping size is 2MB with 4KB pages or 64KB or 64KB pages.
*/
void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
{
unsigned long size, mask;
bool page64k = IS_ENABLED(ARM64_64K_PAGES);
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;

/*
* No early pte entries with !ARM64_64K_PAGES configuration, so using
* sections (pmd).
*/
size = page64k ? PAGE_SIZE : SECTION_SIZE;
mask = ~(size - 1);

pgd = pgd_offset_k(virt);
pud = pud_offset(pgd, virt);
if (pud_none(*pud))
return NULL;
pmd = pmd_offset(pud, virt);

if (page64k) {
if (pmd_none(*pmd))
return NULL;
pte = pte_offset_kernel(pmd, virt);
set_pte(pte, __pte((phys & mask) | PROT_DEVICE_nGnRE));
} else {
set_pmd(pmd, __pmd((phys & mask) | PROT_SECT_DEVICE_nGnRE));
}

return (void __iomem *)((virt & mask) + (phys & ~mask));
}
#endif

static void __init map_mem(void)
{
struct memblock_region *reg;
Expand Down

0 comments on commit 7168024

Please sign in to comment.