Xtensa improvements for 4.10:
- enable HAVE_DMA_CONTIGUOUS, configure shared DMA pool reservation in kc705 DTS; - update xtensa DMA-related Documentation/features entries; - clean up arch/xtensa/kernel/setup.c: move S32C1I self-test out of it, remove unused declarations, fix screen_info definition. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJYWCNXAAoJEFH5zJH4P6BEpMIP/1eW0U1oCXGU/xMb1h+YEGnb YKPeGLxnxH9C9H7RaGoG40YQTHNc1tpeI6R/1+WzNzUx3d08qVHKPrTxoM/DWOM5 erkd0xq0k9/9uZVCuwC7bAMvHlAYGXegiFUy27SVV8WE0P2EXnvP4PS0jGQfnIWZ PLkGfTjYte321Px25LQnmVW8vwY9Y/vS0UUBKbFEeXd3UWJ2M8coAzi4TfEc5m/U 8LVeypSEnNED/IBIArtFFV5RWRBxz0vtbUYWWnNWHQnZ2g6YA9Vx/64n2f4mZJp6 rxyTrsDMJ+OnXUXsCsxVR+O3RjBiDJarVbfvm+Ug3B++8NSFkUf41nZYMkYoA845 Akj5o5W/BqCFAmOetkQDmqEuJQ0HH+C9rqJ5hN0utz5cRzYf08h5t21YJ64HarTf 3K3f5G4WQiKB1i+ZIF3mPR6Oi7qIoGi3y/9UVYWvBIlDdB6i6mx8SyIujLxnxCwN tm1jospeDzMSCk7wwrNxvqXNzJ98D2zo1PNB+6bZToOAEXAxNLUsD3lO2q41GWJU +S1YHiMJSyBnMdGSh1drx72slxBHZI6UvHeb9zBqcqZJxlLnwM6COlNePuyYUOOk 1w5Z8V4liH4RO9DBAieVeB1pYNLg3317TbzN1YjqgUrevYzKN9R5T6GbdirMO+d1 h3jWKmKDlleCy+qWYkZ5 =eMKb -----END PGP SIGNATURE----- Merge tag 'xtensa-20161219' of git://github.com/jcmvbkbc/linux-xtensa Pull Xtensa updates from Max Filippov: - enable HAVE_DMA_CONTIGUOUS, configure shared DMA pool reservation in kc705 DTS - update xtensa DMA-related Documentation/features entries - clean up arch/xtensa/kernel/setup.c: move S32C1I self-test out of it, remove unused declarations, fix screen_info definition * tag 'xtensa-20161219' of git://github.com/jcmvbkbc/linux-xtensa: xtensa: update DMA-related Documentation/features entries xtensa: configure shared DMA pool reservation in kc705 DTS xtensa: enable HAVE_DMA_CONTIGUOUS xtensa: move S32C1I self-test to a separate file xtensa: fix screen_info, clean up unused declarations in setup.c
This commit is contained in:
commit
ec92b88c3c
|
@ -36,5 +36,5 @@
|
|||
| um: | TODO |
|
||||
| unicore32: | TODO |
|
||||
| x86: | ok |
|
||||
| xtensa: | TODO |
|
||||
| xtensa: | ok |
|
||||
-----------------------
|
||||
|
|
|
@ -36,5 +36,5 @@
|
|||
| um: | TODO |
|
||||
| unicore32: | TODO |
|
||||
| x86: | ok |
|
||||
| xtensa: | TODO |
|
||||
| xtensa: | ok |
|
||||
-----------------------
|
||||
|
|
|
@ -15,6 +15,7 @@ config XTENSA
|
|||
select GENERIC_SCHED_CLOCK
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
select HAVE_DMA_API_DEBUG
|
||||
select HAVE_DMA_CONTIGUOUS
|
||||
select HAVE_EXIT_THREAD
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_FUTEX_CMPXCHG if !MMU
|
||||
|
|
|
@ -11,4 +11,20 @@
|
|||
device_type = "memory";
|
||||
reg = <0x00000000 0x38000000>;
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
/* global autoconfigured region for contiguous allocations */
|
||||
linux,cma {
|
||||
compatible = "shared-dma-pool";
|
||||
reusable;
|
||||
size = <0x04000000>;
|
||||
alignment = <0x2000>;
|
||||
alloc-ranges = <0x00000000 0x20000000>;
|
||||
linux,cma-default;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ generic-y += bug.h
|
|||
generic-y += clkdev.h
|
||||
generic-y += cputime.h
|
||||
generic-y += div64.h
|
||||
generic-y += dma-contiguous.h
|
||||
generic-y += emergency-restart.h
|
||||
generic-y += errno.h
|
||||
generic-y += exec.h
|
||||
|
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
|
|||
obj-$(CONFIG_SMP) += smp.o mxhead.o
|
||||
obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
|
||||
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
|
||||
obj-$(CONFIG_S32C1I_SELFTEST) += s32c1i_selftest.o
|
||||
|
||||
AFLAGS_head.o += -mtext-section-literals
|
||||
AFLAGS_mxhead.o += -mtext-section-literals
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
|
||||
*/
|
||||
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/mm.h>
|
||||
|
@ -146,6 +147,8 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
|
|||
{
|
||||
unsigned long ret;
|
||||
unsigned long uncached = 0;
|
||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
struct page *page = NULL;
|
||||
|
||||
/* ignore region speicifiers */
|
||||
|
||||
|
@ -153,11 +156,18 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
|
|||
|
||||
if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
|
||||
flag |= GFP_DMA;
|
||||
ret = (unsigned long)__get_free_pages(flag, get_order(size));
|
||||
|
||||
if (ret == 0)
|
||||
if (gfpflags_allow_blocking(flag))
|
||||
page = dma_alloc_from_contiguous(dev, count, get_order(size));
|
||||
|
||||
if (!page)
|
||||
page = alloc_pages(flag, get_order(size));
|
||||
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
ret = (unsigned long)page_address(page);
|
||||
|
||||
/* We currently don't support coherent memory outside KSEG */
|
||||
|
||||
BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
|
||||
|
@ -170,16 +180,19 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
|
|||
return (void *)uncached;
|
||||
}
|
||||
|
||||
static void xtensa_dma_free(struct device *hwdev, size_t size, void *vaddr,
|
||||
static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, unsigned long attrs)
|
||||
{
|
||||
unsigned long addr = (unsigned long)vaddr +
|
||||
XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
|
||||
struct page *page = virt_to_page(addr);
|
||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
|
||||
BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
|
||||
addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
|
||||
|
||||
free_pages(addr, get_order(size));
|
||||
if (!dma_release_from_contiguous(dev, page, count))
|
||||
__free_pages(page, get_order(size));
|
||||
}
|
||||
|
||||
static dma_addr_t xtensa_map_page(struct device *dev, struct page *page,
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* S32C1I selftest.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2016 Cadence Design Systems Inc.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <asm/traps.h>
|
||||
|
||||
#if XCHAL_HAVE_S32C1I
|
||||
|
||||
static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
|
||||
|
||||
/*
|
||||
* Basic atomic compare-and-swap, that records PC of S32C1I for probing.
|
||||
*
|
||||
* If *v == cmp, set *v = set. Return previous *v.
|
||||
*/
|
||||
static inline int probed_compare_swap(int *v, int cmp, int set)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" movi %1, 1f\n"
|
||||
" s32i %1, %4, 0\n"
|
||||
" wsr %2, scompare1\n"
|
||||
"1: s32c1i %0, %3, 0\n"
|
||||
: "=a" (set), "=&a" (tmp)
|
||||
: "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
|
||||
: "memory"
|
||||
);
|
||||
return set;
|
||||
}
|
||||
|
||||
/* Handle probed exception */
|
||||
|
||||
static void __init do_probed_exception(struct pt_regs *regs,
|
||||
unsigned long exccause)
|
||||
{
|
||||
if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
|
||||
regs->pc += 3; /* skip the s32c1i instruction */
|
||||
rcw_exc = exccause;
|
||||
} else {
|
||||
do_unhandled(regs, exccause);
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple test of S32C1I (soc bringup assist) */
|
||||
|
||||
static int __init check_s32c1i(void)
|
||||
{
|
||||
int n, cause1, cause2;
|
||||
void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
|
||||
|
||||
rcw_probe_pc = 0;
|
||||
handbus = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
|
||||
do_probed_exception);
|
||||
handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
|
||||
do_probed_exception);
|
||||
handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
|
||||
do_probed_exception);
|
||||
|
||||
/* First try an S32C1I that does not store: */
|
||||
rcw_exc = 0;
|
||||
rcw_word = 1;
|
||||
n = probed_compare_swap(&rcw_word, 0, 2);
|
||||
cause1 = rcw_exc;
|
||||
|
||||
/* took exception? */
|
||||
if (cause1 != 0) {
|
||||
/* unclean exception? */
|
||||
if (n != 2 || rcw_word != 1)
|
||||
panic("S32C1I exception error");
|
||||
} else if (rcw_word != 1 || n != 1) {
|
||||
panic("S32C1I compare error");
|
||||
}
|
||||
|
||||
/* Then an S32C1I that stores: */
|
||||
rcw_exc = 0;
|
||||
rcw_word = 0x1234567;
|
||||
n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
|
||||
cause2 = rcw_exc;
|
||||
|
||||
if (cause2 != 0) {
|
||||
/* unclean exception? */
|
||||
if (n != 0xabcde || rcw_word != 0x1234567)
|
||||
panic("S32C1I exception error (b)");
|
||||
} else if (rcw_word != 0xabcde || n != 0x1234567) {
|
||||
panic("S32C1I store error");
|
||||
}
|
||||
|
||||
/* Verify consistency of exceptions: */
|
||||
if (cause1 || cause2) {
|
||||
pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
|
||||
/* If emulation of S32C1I upon bus error gets implemented,
|
||||
* we can get rid of this panic for single core (not SMP)
|
||||
*/
|
||||
panic("S32C1I exceptions not currently supported");
|
||||
}
|
||||
if (cause1 != cause2)
|
||||
panic("inconsistent S32C1I exceptions");
|
||||
|
||||
trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
|
||||
trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
|
||||
trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* XCHAL_HAVE_S32C1I */
|
||||
|
||||
/* This condition should not occur with a commercially deployed processor.
|
||||
* Display reminder for early engr test or demo chips / FPGA bitstreams
|
||||
*/
|
||||
static int __init check_s32c1i(void)
|
||||
{
|
||||
pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* XCHAL_HAVE_S32C1I */
|
||||
|
||||
early_initcall(check_s32c1i);
|
|
@ -31,10 +31,6 @@
|
|||
# include <linux/console.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC
|
||||
# include <linux/timex.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
# include <linux/seq_file.h>
|
||||
#endif
|
||||
|
@ -48,24 +44,22 @@
|
|||
#include <asm/page.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/param.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/sysmem.h>
|
||||
|
||||
#include <platform/hardware.h>
|
||||
|
||||
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
|
||||
struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
|
||||
struct screen_info screen_info = {
|
||||
.orig_x = 0,
|
||||
.orig_y = 24,
|
||||
.orig_video_cols = 80,
|
||||
.orig_video_lines = 24,
|
||||
.orig_video_isVGA = 1,
|
||||
.orig_video_points = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_FD
|
||||
extern struct fd_ops no_fd_ops;
|
||||
struct fd_ops *fd_ops;
|
||||
#endif
|
||||
|
||||
extern struct rtc_ops no_rtc_ops;
|
||||
struct rtc_ops *rtc_ops;
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
extern unsigned long initrd_start;
|
||||
extern unsigned long initrd_end;
|
||||
|
@ -77,7 +71,6 @@ extern int initrd_below_start_ok;
|
|||
void *dtb_start = __dtb_start;
|
||||
#endif
|
||||
|
||||
unsigned char aux_device_present;
|
||||
extern unsigned long loops_per_jiffy;
|
||||
|
||||
/* Command line specified as configuration option. */
|
||||
|
@ -317,120 +310,6 @@ extern char _SecondaryResetVector_text_start;
|
|||
extern char _SecondaryResetVector_text_end;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_S32C1I_SELFTEST
|
||||
#if XCHAL_HAVE_S32C1I
|
||||
|
||||
static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
|
||||
|
||||
/*
|
||||
* Basic atomic compare-and-swap, that records PC of S32C1I for probing.
|
||||
*
|
||||
* If *v == cmp, set *v = set. Return previous *v.
|
||||
*/
|
||||
static inline int probed_compare_swap(int *v, int cmp, int set)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" movi %1, 1f\n"
|
||||
" s32i %1, %4, 0\n"
|
||||
" wsr %2, scompare1\n"
|
||||
"1: s32c1i %0, %3, 0\n"
|
||||
: "=a" (set), "=&a" (tmp)
|
||||
: "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
|
||||
: "memory"
|
||||
);
|
||||
return set;
|
||||
}
|
||||
|
||||
/* Handle probed exception */
|
||||
|
||||
static void __init do_probed_exception(struct pt_regs *regs,
|
||||
unsigned long exccause)
|
||||
{
|
||||
if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
|
||||
regs->pc += 3; /* skip the s32c1i instruction */
|
||||
rcw_exc = exccause;
|
||||
} else {
|
||||
do_unhandled(regs, exccause);
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple test of S32C1I (soc bringup assist) */
|
||||
|
||||
static int __init check_s32c1i(void)
|
||||
{
|
||||
int n, cause1, cause2;
|
||||
void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
|
||||
|
||||
rcw_probe_pc = 0;
|
||||
handbus = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
|
||||
do_probed_exception);
|
||||
handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
|
||||
do_probed_exception);
|
||||
handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
|
||||
do_probed_exception);
|
||||
|
||||
/* First try an S32C1I that does not store: */
|
||||
rcw_exc = 0;
|
||||
rcw_word = 1;
|
||||
n = probed_compare_swap(&rcw_word, 0, 2);
|
||||
cause1 = rcw_exc;
|
||||
|
||||
/* took exception? */
|
||||
if (cause1 != 0) {
|
||||
/* unclean exception? */
|
||||
if (n != 2 || rcw_word != 1)
|
||||
panic("S32C1I exception error");
|
||||
} else if (rcw_word != 1 || n != 1) {
|
||||
panic("S32C1I compare error");
|
||||
}
|
||||
|
||||
/* Then an S32C1I that stores: */
|
||||
rcw_exc = 0;
|
||||
rcw_word = 0x1234567;
|
||||
n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
|
||||
cause2 = rcw_exc;
|
||||
|
||||
if (cause2 != 0) {
|
||||
/* unclean exception? */
|
||||
if (n != 0xabcde || rcw_word != 0x1234567)
|
||||
panic("S32C1I exception error (b)");
|
||||
} else if (rcw_word != 0xabcde || n != 0x1234567) {
|
||||
panic("S32C1I store error");
|
||||
}
|
||||
|
||||
/* Verify consistency of exceptions: */
|
||||
if (cause1 || cause2) {
|
||||
pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
|
||||
/* If emulation of S32C1I upon bus error gets implemented,
|
||||
we can get rid of this panic for single core (not SMP) */
|
||||
panic("S32C1I exceptions not currently supported");
|
||||
}
|
||||
if (cause1 != cause2)
|
||||
panic("inconsistent S32C1I exceptions");
|
||||
|
||||
trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
|
||||
trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
|
||||
trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* XCHAL_HAVE_S32C1I */
|
||||
|
||||
/* This condition should not occur with a commercially deployed processor.
|
||||
Display reminder for early engr test or demo chips / FPGA bitstreams */
|
||||
static int __init check_s32c1i(void)
|
||||
{
|
||||
pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* XCHAL_HAVE_S32C1I */
|
||||
early_initcall(check_s32c1i);
|
||||
#endif /* CONFIG_S32C1I_SELFTEST */
|
||||
|
||||
static inline int mem_reserve(unsigned long start, unsigned long end)
|
||||
{
|
||||
return memblock_reserve(start, end - start);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/nodemask.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/dma-contiguous.h>
|
||||
|
||||
#include <asm/bootparam.h>
|
||||
#include <asm/page.h>
|
||||
|
@ -60,6 +61,7 @@ void __init bootmem_init(void)
|
|||
max_low_pfn = min(max_pfn, MAX_LOW_PFN);
|
||||
|
||||
memblock_set_current_limit(PFN_PHYS(max_low_pfn));
|
||||
dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
|
||||
|
||||
memblock_dump_all();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue