csky-for-linus-5.4-rc1: arch/csky patches for 5.4-rc1

This round of csky subsystem just some fixups.
 
 Fixup:
  - Fixup mb() synchronization problem
  - Fixup dma_alloc_coherent with PAGE_SO attribute
  - Fixup cache_op failed when cross memory ZONEs
  - Optimize arch_sync_dma_for_cpu/device with dma_inv_range
  - Fixup ioremap function losing
  - Fixup arch_get_unmapped_area() implementation
  - Fixup defer cache flush for 610
  - Support kernel non-aligned access
  - Fixup 610 vipt cache flush mechanism
  - Fixup add zero_fp fixup perf backtrace panic
  - Move static keyword to the front of declaration
  - Fixup csky_pmu.max_period assignment
  - Use generic free_initrd_mem()
  - entry: Remove unneeded need_resched() loop
 
 CI-Tested: https://gitlab.com/c-sky/buildroot/pipelines/77689888
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE2KAv+isbWR/viAKHAXH1GYaIxXsFAl2Rfc0SHHJlbl9ndW9A
 Yy1za3kuY29tAAoJEAFx9RmGiMV7eEUQAIuuO1ym/o7zMWZsIRbISJYi6xuq752W
 RVhnPv957ktFYlqrtelDuZwkCPnK03YDTv8lPzcIhes+xYtuspN6NMum7SUWPt4c
 IbfQe4GmMwPGNrJ76NO9YcWQig8flT75wWE2CzOjhGpBfEkEHmtbOvOiZujcq4yN
 vhj8TKF9CjOSaDJNCOXinC6DeGoftRYTSRq6NMPfFfHIWqFcZIyb1Fz8tE/vFP4Y
 qEoG/ys/eu114DIZVnxr5ihmrJ4gjxmlXlnYA8WMRnRt6/oHEmmbtHLTT2eHbI2T
 u4TCssqrLoNADV7g7zyAyBnrgf4dXnJivGjc2NzVLAkgNbEJn+oGNYn+kdiRGd5X
 1CNVbzbZN0gHwLayDjJ4BWNxtpxxqmOjlDffjLVRW7dleTdfHvcxJwfhlvbQOPuq
 nMj4t1qJswn44f/bsj+F13hgXV0tWctYui/HS78xscE7t4yMNduf3JAm7TIxT0XN
 ej3102ffm4ycKZtfdwKwcACmMBJc+2QvGYmQo2L9pVLYIQe3QUWYs881V50PJXxV
 jdz4kmhpfKLie+yxmsdN1/8nTlcHF5wDiYwW9UColzfz1fCRkoPRx5tu/YI9zLoi
 K41CFEv4Z+aVzcp4HZNmOvVhGWgdmuwICMdY16wawhN6SAkvKJBFaP4g24h0J95M
 QyAPQl/VUMED
 =FLYg
 -----END PGP SIGNATURE-----

Merge tag 'csky-for-linus-5.4-rc1' of git://github.com/c-sky/csky-linux

Pull csky updates from Guo Ren:
 "This round of csky subsystem just some fixups:

   - Fix mb() synchronization problem

   - Fix dma_alloc_coherent with PAGE_SO attribute

   - Fix cache_op failed when cross memory ZONEs

   - Optimize arch_sync_dma_for_cpu/device with dma_inv_range

   - Fix ioremap function losing

   - Fix arch_get_unmapped_area() implementation

   - Fix defer cache flush for 610

   - Support kernel non-aligned access

   - Fix 610 vipt cache flush mechanism

   - Fix add zero_fp fixup perf backtrace panic

   - Move static keyword to the front of declaration

   - Fix csky_pmu.max_period assignment

   - Use generic free_initrd_mem()

   - entry: Remove unneeded need_resched() loop"

* tag 'csky-for-linus-5.4-rc1' of git://github.com/c-sky/csky-linux:
  csky: Move static keyword to the front of declaration
  csky: entry: Remove unneeded need_resched() loop
  csky: Fixup csky_pmu.max_period assignment
  csky: Fixup add zero_fp fixup perf backtrace panic
  csky: Use generic free_initrd_mem()
  csky: Fixup 610 vipt cache flush mechanism
  csky: Support kernel non-aligned access
  csky: Fixup defer cache flush for 610
  csky: Fixup arch_get_unmapped_area() implementation
  csky: Fixup ioremap function losing
  csky: Optimize arch_sync_dma_for_cpu/device with dma_inv_range
  csky/dma: Fixup cache_op failed when cross memory ZONEs
  csky: Fixup dma_alloc_coherent with PAGE_SO attribute
  csky: Fixup mb() synchronization problem
This commit is contained in:
Linus Torvalds 2019-09-30 10:16:17 -07:00
commit 80b29b6b8c
17 changed files with 292 additions and 213 deletions

View File

@ -5,8 +5,10 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
static int align_enable = 1; static int align_kern_enable = 1;
static int align_count; static int align_usr_enable = 1;
static int align_kern_count = 0;
static int align_usr_count = 0;
static inline uint32_t get_ptreg(struct pt_regs *regs, uint32_t rx) static inline uint32_t get_ptreg(struct pt_regs *regs, uint32_t rx)
{ {
@ -32,9 +34,6 @@ static int ldb_asm(uint32_t addr, uint32_t *valp)
uint32_t val; uint32_t val;
int err; int err;
if (!access_ok((void *)addr, 1))
return 1;
asm volatile ( asm volatile (
"movi %0, 0\n" "movi %0, 0\n"
"1:\n" "1:\n"
@ -67,9 +66,6 @@ static int stb_asm(uint32_t addr, uint32_t val)
{ {
int err; int err;
if (!access_ok((void *)addr, 1))
return 1;
asm volatile ( asm volatile (
"movi %0, 0\n" "movi %0, 0\n"
"1:\n" "1:\n"
@ -203,8 +199,6 @@ static int stw_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
if (stb_asm(addr, byte3)) if (stb_asm(addr, byte3))
return 1; return 1;
align_count++;
return 0; return 0;
} }
@ -226,7 +220,14 @@ void csky_alignment(struct pt_regs *regs)
uint32_t addr = 0; uint32_t addr = 0;
if (!user_mode(regs)) if (!user_mode(regs))
goto kernel_area;
if (!align_usr_enable) {
pr_err("%s user disabled.\n", __func__);
goto bad_area; goto bad_area;
}
align_usr_count++;
ret = get_user(tmp, (uint16_t *)instruction_pointer(regs)); ret = get_user(tmp, (uint16_t *)instruction_pointer(regs));
if (ret) { if (ret) {
@ -234,6 +235,19 @@ void csky_alignment(struct pt_regs *regs)
goto bad_area; goto bad_area;
} }
goto good_area;
kernel_area:
if (!align_kern_enable) {
pr_err("%s kernel disabled.\n", __func__);
goto bad_area;
}
align_kern_count++;
tmp = *(uint16_t *)instruction_pointer(regs);
good_area:
opcode = (uint32_t)tmp; opcode = (uint32_t)tmp;
rx = opcode & 0xf; rx = opcode & 0xf;
@ -286,18 +300,32 @@ void csky_alignment(struct pt_regs *regs)
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr); force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr);
} }
static struct ctl_table alignment_tbl[4] = { static struct ctl_table alignment_tbl[5] = {
{ {
.procname = "enable", .procname = "kernel_enable",
.data = &align_enable, .data = &align_kern_enable,
.maxlen = sizeof(align_enable), .maxlen = sizeof(align_kern_enable),
.mode = 0666, .mode = 0666,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
}, },
{ {
.procname = "count", .procname = "user_enable",
.data = &align_count, .data = &align_usr_enable,
.maxlen = sizeof(align_count), .maxlen = sizeof(align_usr_enable),
.mode = 0666,
.proc_handler = &proc_dointvec
},
{
.procname = "kernel_count",
.data = &align_kern_count,
.maxlen = sizeof(align_kern_count),
.mode = 0666,
.proc_handler = &proc_dointvec
},
{
.procname = "user_count",
.data = &align_usr_count,
.maxlen = sizeof(align_usr_count),
.mode = 0666, .mode = 0666,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
}, },

View File

@ -11,42 +11,66 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cachectl.h> #include <asm/cachectl.h>
#define PG_dcache_clean PG_arch_1
void flush_dcache_page(struct page *page) void flush_dcache_page(struct page *page)
{ {
struct address_space *mapping = page_mapping(page); struct address_space *mapping;
unsigned long addr;
if (mapping && !mapping_mapped(mapping)) { if (page == ZERO_PAGE(0))
set_bit(PG_arch_1, &(page)->flags);
return; return;
mapping = page_mapping_file(page);
if (mapping && !page_mapcount(page))
clear_bit(PG_dcache_clean, &page->flags);
else {
dcache_wbinv_all();
if (mapping)
icache_inv_all();
set_bit(PG_dcache_clean, &page->flags);
} }
/*
* We could delay the flush for the !page_mapping case too. But that
* case is for exec env/arg pages and those are %99 certainly going to
* get faulted into the tlb (and thus flushed) anyways.
*/
addr = (unsigned long) page_address(page);
dcache_wb_range(addr, addr + PAGE_SIZE);
} }
EXPORT_SYMBOL(flush_dcache_page);
void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
pte_t *pte) pte_t *ptep)
{ {
unsigned long addr; unsigned long pfn = pte_pfn(*ptep);
struct page *page; struct page *page;
unsigned long pfn;
pfn = pte_pfn(*pte); if (!pfn_valid(pfn))
if (unlikely(!pfn_valid(pfn)))
return; return;
page = pfn_to_page(pfn); page = pfn_to_page(pfn);
addr = (unsigned long) page_address(page); if (page == ZERO_PAGE(0))
return;
if (vma->vm_flags & VM_EXEC || if (!test_and_set_bit(PG_dcache_clean, &page->flags))
pages_do_alias(addr, address & PAGE_MASK)) dcache_wbinv_all();
cache_wbinv_all();
clear_bit(PG_arch_1, &(page)->flags); if (page_mapping_file(page)) {
if (vma->vm_flags & VM_EXEC)
icache_inv_all();
}
}
void flush_kernel_dcache_page(struct page *page)
{
struct address_space *mapping;
mapping = page_mapping_file(page);
if (!mapping || mapping_mapped(mapping))
dcache_wbinv_all();
}
EXPORT_SYMBOL(flush_kernel_dcache_page);
void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
dcache_wbinv_all();
if (vma->vm_flags & VM_EXEC)
icache_inv_all();
} }

View File

@ -4,46 +4,63 @@
#ifndef __ABI_CSKY_CACHEFLUSH_H #ifndef __ABI_CSKY_CACHEFLUSH_H
#define __ABI_CSKY_CACHEFLUSH_H #define __ABI_CSKY_CACHEFLUSH_H
#include <linux/compiler.h> #include <linux/mm.h>
#include <asm/string.h> #include <asm/string.h>
#include <asm/cache.h> #include <asm/cache.h>
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
extern void flush_dcache_page(struct page *); extern void flush_dcache_page(struct page *);
#define flush_cache_mm(mm) cache_wbinv_all() #define flush_cache_mm(mm) dcache_wbinv_all()
#define flush_cache_page(vma, page, pfn) cache_wbinv_all() #define flush_cache_page(vma, page, pfn) cache_wbinv_all()
#define flush_cache_dup_mm(mm) cache_wbinv_all() #define flush_cache_dup_mm(mm) cache_wbinv_all()
#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
extern void flush_kernel_dcache_page(struct page *);
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
static inline void flush_kernel_vmap_range(void *addr, int size)
{
dcache_wbinv_all();
}
static inline void invalidate_kernel_vmap_range(void *addr, int size)
{
dcache_wbinv_all();
}
#define ARCH_HAS_FLUSH_ANON_PAGE
static inline void flush_anon_page(struct vm_area_struct *vma,
struct page *page, unsigned long vmaddr)
{
if (PageAnon(page))
cache_wbinv_all();
}
/* /*
* if (current_mm != vma->mm) cache_wbinv_range(start, end) will be broken. * if (current_mm != vma->mm) cache_wbinv_range(start, end) will be broken.
* Use cache_wbinv_all() here and need to be improved in future. * Use cache_wbinv_all() here and need to be improved in future.
*/ */
#define flush_cache_range(vma, start, end) cache_wbinv_all() extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
#define flush_cache_vmap(start, end) cache_wbinv_range(start, end) #define flush_cache_vmap(start, end) cache_wbinv_all()
#define flush_cache_vunmap(start, end) cache_wbinv_range(start, end) #define flush_cache_vunmap(start, end) cache_wbinv_all()
#define flush_icache_page(vma, page) cache_wbinv_all() #define flush_icache_page(vma, page) do {} while (0);
#define flush_icache_range(start, end) cache_wbinv_range(start, end) #define flush_icache_range(start, end) cache_wbinv_range(start, end)
#define flush_icache_user_range(vma, pg, adr, len) \ #define flush_icache_user_range(vma,page,addr,len) \
cache_wbinv_range(adr, adr + len) flush_dcache_page(page)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
do { \ do { \
cache_wbinv_all(); \
memcpy(dst, src, len); \ memcpy(dst, src, len); \
cache_wbinv_all(); \
} while (0) } while (0)
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
do { \ do { \
cache_wbinv_all(); \
memcpy(dst, src, len); \ memcpy(dst, src, len); \
cache_wbinv_all(); \ cache_wbinv_all(); \
} while (0) } while (0)
#define flush_dcache_mmap_lock(mapping) do {} while (0)
#define flush_dcache_mmap_unlock(mapping) do {} while (0)
#endif /* __ABI_CSKY_CACHEFLUSH_H */ #endif /* __ABI_CSKY_CACHEFLUSH_H */

View File

@ -1,13 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
extern unsigned long shm_align_mask; #include <asm/shmparam.h>
extern void flush_dcache_page(struct page *page); extern void flush_dcache_page(struct page *page);
static inline unsigned long pages_do_alias(unsigned long addr1, static inline unsigned long pages_do_alias(unsigned long addr1,
unsigned long addr2) unsigned long addr2)
{ {
return (addr1 ^ addr2) & shm_align_mask; return (addr1 ^ addr2) & (SHMLBA-1);
} }
static inline void clear_user_page(void *addr, unsigned long vaddr, static inline void clear_user_page(void *addr, unsigned long vaddr,

View File

@ -9,58 +9,63 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/io.h> #include <linux/io.h>
unsigned long shm_align_mask = (0x4000 >> 1) - 1; /* Sane caches */ #define COLOUR_ALIGN(addr,pgoff) \
((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
(((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
#define COLOUR_ALIGN(addr, pgoff) \ /*
((((addr) + shm_align_mask) & ~shm_align_mask) + \ * We need to ensure that shared mappings are correctly aligned to
(((pgoff) << PAGE_SHIFT) & shm_align_mask)) * avoid aliasing issues with VIPT caches. We need to ensure that
* a specific page of an object is always mapped at a multiple of
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, * SHMLBA bytes.
*
* We unconditionally provide this function for all cases.
*/
unsigned long
arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags) unsigned long len, unsigned long pgoff, unsigned long flags)
{ {
struct vm_area_struct *vmm; struct mm_struct *mm = current->mm;
int do_color_align; struct vm_area_struct *vma;
int do_align = 0;
struct vm_unmapped_area_info info;
/*
* We only need to do colour alignment if either the I or D
* caches alias.
*/
do_align = filp || (flags & MAP_SHARED);
/*
* We enforce the MAP_FIXED case.
*/
if (flags & MAP_FIXED) { if (flags & MAP_FIXED) {
/* if (flags & MAP_SHARED &&
* We do not accept a shared mapping if it would violate (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
* cache aliasing constraints.
*/
if ((flags & MAP_SHARED) &&
((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
return -EINVAL; return -EINVAL;
return addr; return addr;
} }
if (len > TASK_SIZE) if (len > TASK_SIZE)
return -ENOMEM; return -ENOMEM;
do_color_align = 0;
if (filp || (flags & MAP_SHARED))
do_color_align = 1;
if (addr) { if (addr) {
if (do_color_align) if (do_align)
addr = COLOUR_ALIGN(addr, pgoff); addr = COLOUR_ALIGN(addr, pgoff);
else else
addr = PAGE_ALIGN(addr); addr = PAGE_ALIGN(addr);
vmm = find_vma(current->mm, addr);
if (TASK_SIZE - len >= addr &&
(!vmm || addr + len <= vmm->vm_start))
return addr;
}
addr = TASK_UNMAPPED_BASE;
if (do_color_align)
addr = COLOUR_ALIGN(addr, pgoff);
else
addr = PAGE_ALIGN(addr);
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { vma = find_vma(mm, addr);
/* At this point: (!vmm || addr < vmm->vm_end). */ if (TASK_SIZE - len >= addr &&
if (TASK_SIZE - len < addr) (!vma || addr + len <= vm_start_gap(vma)))
return -ENOMEM;
if (!vmm || addr + len <= vmm->vm_start)
return addr; return addr;
addr = vmm->vm_end;
if (do_color_align)
addr = COLOUR_ALIGN(addr, pgoff);
} }
info.flags = 0;
info.length = len;
info.low_limit = mm->mmap_base;
info.high_limit = TASK_SIZE;
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
info.align_offset = pgoff << PAGE_SHIFT;
return vm_unmapped_area(&info);
} }

View File

@ -9,11 +9,12 @@
#define nop() asm volatile ("nop\n":::"memory") #define nop() asm volatile ("nop\n":::"memory")
/* /*
* sync: completion barrier * sync: completion barrier, all sync.xx instructions
* sync.s: completion barrier and shareable to other cores * guarantee the last response recieved by bus transaction
* sync.i: completion barrier with flush cpu pipeline * made by ld/st instructions before sync.s
* sync.is: completion barrier with flush cpu pipeline and shareable to * sync.s: inherit from sync, but also shareable to other cores
* other cores * sync.i: inherit from sync, but also flush cpu pipeline
* sync.is: the same with sync.i + sync.s
* *
* bar.brwarw: ordering barrier for all load/store instructions before it * bar.brwarw: ordering barrier for all load/store instructions before it
* bar.brwarws: ordering barrier for all load/store instructions before it * bar.brwarws: ordering barrier for all load/store instructions before it
@ -27,9 +28,7 @@
*/ */
#ifdef CONFIG_CPU_HAS_CACHEV2 #ifdef CONFIG_CPU_HAS_CACHEV2
#define mb() asm volatile ("bar.brwarw\n":::"memory") #define mb() asm volatile ("sync.s\n":::"memory")
#define rmb() asm volatile ("bar.brar\n":::"memory")
#define wmb() asm volatile ("bar.bwaw\n":::"memory")
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#define __smp_mb() asm volatile ("bar.brwarws\n":::"memory") #define __smp_mb() asm volatile ("bar.brwarws\n":::"memory")

View File

@ -24,6 +24,7 @@ void cache_wbinv_range(unsigned long start, unsigned long end);
void cache_wbinv_all(void); void cache_wbinv_all(void);
void dma_wbinv_range(unsigned long start, unsigned long end); void dma_wbinv_range(unsigned long start, unsigned long end);
void dma_inv_range(unsigned long start, unsigned long end);
void dma_wb_range(unsigned long start, unsigned long end); void dma_wb_range(unsigned long start, unsigned long end);
#endif #endif

View File

@ -4,17 +4,10 @@
#ifndef __ASM_CSKY_IO_H #ifndef __ASM_CSKY_IO_H
#define __ASM_CSKY_IO_H #define __ASM_CSKY_IO_H
#include <abi/pgtable-bits.h> #include <asm/pgtable.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/version.h> #include <linux/version.h>
extern void __iomem *ioremap(phys_addr_t offset, size_t size);
extern void iounmap(void *addr);
extern int remap_area_pages(unsigned long address, phys_addr_t phys_addr,
size_t size, unsigned long flags);
/* /*
* I/O memory access primitives. Reads are ordered relative to any * I/O memory access primitives. Reads are ordered relative to any
* following Normal memory access. Writes are ordered relative to any prior * following Normal memory access. Writes are ordered relative to any prior
@ -40,9 +33,17 @@ extern int remap_area_pages(unsigned long address, phys_addr_t phys_addr,
#define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); mb(); }) #define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); mb(); })
#endif #endif
#define ioremap_nocache(phy, sz) ioremap(phy, sz) /*
#define ioremap_wc ioremap_nocache * I/O memory mapping functions.
#define ioremap_wt ioremap_nocache */
extern void __iomem *ioremap_cache(phys_addr_t addr, size_t size);
extern void __iomem *__ioremap(phys_addr_t addr, size_t size, pgprot_t prot);
extern void iounmap(void *addr);
#define ioremap(addr, size) __ioremap((addr), (size), pgprot_noncached(PAGE_KERNEL))
#define ioremap_wc(addr, size) __ioremap((addr), (size), pgprot_writecombine(PAGE_KERNEL))
#define ioremap_nocache(addr, size) ioremap((addr), (size))
#define ioremap_cache ioremap_cache
#include <asm-generic/io.h> #include <asm-generic/io.h>

View File

@ -258,6 +258,16 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
{ {
unsigned long prot = pgprot_val(_prot); unsigned long prot = pgprot_val(_prot);
prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED | _PAGE_SO;
return __pgprot(prot);
}
#define pgprot_writecombine pgprot_writecombine
static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
{
unsigned long prot = pgprot_val(_prot);
prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED; prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
return __pgprot(prot); return __pgprot(prot);

View File

@ -17,6 +17,12 @@
#define PTE_INDX_SHIFT 10 #define PTE_INDX_SHIFT 10
#define _PGDIR_SHIFT 22 #define _PGDIR_SHIFT 22
.macro zero_fp
#ifdef CONFIG_STACKTRACE
movi r8, 0
#endif
.endm
.macro tlbop_begin name, val0, val1, val2 .macro tlbop_begin name, val0, val1, val2
ENTRY(csky_\name) ENTRY(csky_\name)
mtcr a3, ss2 mtcr a3, ss2
@ -96,6 +102,7 @@ ENTRY(csky_\name)
SAVE_ALL 0 SAVE_ALL 0
.endm .endm
.macro tlbop_end is_write .macro tlbop_end is_write
zero_fp
RD_MEH a2 RD_MEH a2
psrset ee, ie psrset ee, ie
mov a0, sp mov a0, sp
@ -120,6 +127,7 @@ tlbop_end 1
ENTRY(csky_systemcall) ENTRY(csky_systemcall)
SAVE_ALL TRAP0_SIZE SAVE_ALL TRAP0_SIZE
zero_fp
psrset ee, ie psrset ee, ie
@ -136,9 +144,9 @@ ENTRY(csky_systemcall)
mov r9, sp mov r9, sp
bmaski r10, THREAD_SHIFT bmaski r10, THREAD_SHIFT
andn r9, r10 andn r9, r10
ldw r8, (r9, TINFO_FLAGS) ldw r12, (r9, TINFO_FLAGS)
ANDI_R3 r8, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT) ANDI_R3 r12, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
cmpnei r8, 0 cmpnei r12, 0
bt csky_syscall_trace bt csky_syscall_trace
#if defined(__CSKYABIV2__) #if defined(__CSKYABIV2__)
subi sp, 8 subi sp, 8
@ -180,7 +188,7 @@ csky_syscall_trace:
ENTRY(ret_from_kernel_thread) ENTRY(ret_from_kernel_thread)
jbsr schedule_tail jbsr schedule_tail
mov a0, r8 mov a0, r10
jsr r9 jsr r9
jbsr ret_from_exception jbsr ret_from_exception
@ -189,9 +197,9 @@ ENTRY(ret_from_fork)
mov r9, sp mov r9, sp
bmaski r10, THREAD_SHIFT bmaski r10, THREAD_SHIFT
andn r9, r10 andn r9, r10
ldw r8, (r9, TINFO_FLAGS) ldw r12, (r9, TINFO_FLAGS)
ANDI_R3 r8, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT) ANDI_R3 r12, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
cmpnei r8, 0 cmpnei r12, 0
bf ret_from_exception bf ret_from_exception
mov a0, sp /* sp = pt_regs pointer */ mov a0, sp /* sp = pt_regs pointer */
jbsr syscall_trace_exit jbsr syscall_trace_exit
@ -209,9 +217,9 @@ ret_from_exception:
bmaski r10, THREAD_SHIFT bmaski r10, THREAD_SHIFT
andn r9, r10 andn r9, r10
ldw r8, (r9, TINFO_FLAGS) ldw r12, (r9, TINFO_FLAGS)
andi r8, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED) andi r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
cmpnei r8, 0 cmpnei r12, 0
bt exit_work bt exit_work
1: 1:
RESTORE_ALL RESTORE_ALL
@ -220,11 +228,11 @@ exit_work:
lrw syscallid, ret_from_exception lrw syscallid, ret_from_exception
mov lr, syscallid mov lr, syscallid
btsti r8, TIF_NEED_RESCHED btsti r12, TIF_NEED_RESCHED
bt work_resched bt work_resched
mov a0, sp mov a0, sp
mov a1, r8 mov a1, r12
jmpi do_notify_resume jmpi do_notify_resume
work_resched: work_resched:
@ -232,6 +240,7 @@ work_resched:
ENTRY(csky_trap) ENTRY(csky_trap)
SAVE_ALL 0 SAVE_ALL 0
zero_fp
psrset ee psrset ee
mov a0, sp /* Push Stack pointer arg */ mov a0, sp /* Push Stack pointer arg */
jbsr trap_c /* Call C-level trap handler */ jbsr trap_c /* Call C-level trap handler */
@ -265,6 +274,7 @@ ENTRY(csky_get_tls)
ENTRY(csky_irq) ENTRY(csky_irq)
SAVE_ALL 0 SAVE_ALL 0
zero_fp
psrset ee psrset ee
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
@ -276,27 +286,23 @@ ENTRY(csky_irq)
* Get task_struct->stack.preempt_count for current, * Get task_struct->stack.preempt_count for current,
* and increase 1. * and increase 1.
*/ */
ldw r8, (r9, TINFO_PREEMPT) ldw r12, (r9, TINFO_PREEMPT)
addi r8, 1 addi r12, 1
stw r8, (r9, TINFO_PREEMPT) stw r12, (r9, TINFO_PREEMPT)
#endif #endif
mov a0, sp mov a0, sp
jbsr csky_do_IRQ jbsr csky_do_IRQ
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
subi r8, 1 subi r12, 1
stw r8, (r9, TINFO_PREEMPT) stw r12, (r9, TINFO_PREEMPT)
cmpnei r8, 0 cmpnei r12, 0
bt 2f bt 2f
ldw r8, (r9, TINFO_FLAGS) ldw r12, (r9, TINFO_FLAGS)
btsti r8, TIF_NEED_RESCHED btsti r12, TIF_NEED_RESCHED
bf 2f bf 2f
1:
jbsr preempt_schedule_irq /* irq en/disable is done inside */ jbsr preempt_schedule_irq /* irq en/disable is done inside */
ldw r7, (r9, TINFO_FLAGS) /* get new tasks TI_FLAGS */
btsti r7, TIF_NEED_RESCHED
bt 1b /* go again */
#endif #endif
2: 2:
jmpi ret_from_exception jmpi ret_from_exception

View File

@ -1306,7 +1306,7 @@ int csky_pmu_device_probe(struct platform_device *pdev,
&csky_pmu.count_width)) { &csky_pmu.count_width)) {
csky_pmu.count_width = DEFAULT_COUNT_WIDTH; csky_pmu.count_width = DEFAULT_COUNT_WIDTH;
} }
csky_pmu.max_period = BIT(csky_pmu.count_width) - 1; csky_pmu.max_period = BIT_ULL(csky_pmu.count_width) - 1;
csky_pmu.plat_device = pdev; csky_pmu.plat_device = pdev;
@ -1337,7 +1337,7 @@ int csky_pmu_device_probe(struct platform_device *pdev,
return ret; return ret;
} }
const static struct of_device_id csky_pmu_of_device_ids[] = { static const struct of_device_id csky_pmu_of_device_ids[] = {
{.compatible = "csky,csky-pmu"}, {.compatible = "csky,csky-pmu"},
{}, {},
}; };

View File

@ -55,7 +55,7 @@ int copy_thread(unsigned long clone_flags,
if (unlikely(p->flags & PF_KTHREAD)) { if (unlikely(p->flags & PF_KTHREAD)) {
memset(childregs, 0, sizeof(struct pt_regs)); memset(childregs, 0, sizeof(struct pt_regs));
childstack->r15 = (unsigned long) ret_from_kernel_thread; childstack->r15 = (unsigned long) ret_from_kernel_thread;
childstack->r8 = kthread_arg; childstack->r10 = kthread_arg;
childstack->r9 = usp; childstack->r9 = usp;
childregs->sr = mfcr("psr"); childregs->sr = mfcr("psr");
} else { } else {

View File

@ -120,7 +120,12 @@ void dma_wbinv_range(unsigned long start, unsigned long end)
cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1); cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
} }
void dma_inv_range(unsigned long start, unsigned long end)
{
cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
}
void dma_wb_range(unsigned long start, unsigned long end) void dma_wb_range(unsigned long start, unsigned long end)
{ {
cache_op_range(start, end, DATA_CACHE|CACHE_INV, 1); cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
} }

View File

@ -69,11 +69,20 @@ void dma_wbinv_range(unsigned long start, unsigned long end)
sync_is(); sync_is();
} }
void dma_inv_range(unsigned long start, unsigned long end)
{
unsigned long i = start & ~(L1_CACHE_BYTES - 1);
for (; i < end; i += L1_CACHE_BYTES)
asm volatile("dcache.iva %0\n"::"r"(i):"memory");
sync_is();
}
void dma_wb_range(unsigned long start, unsigned long end) void dma_wb_range(unsigned long start, unsigned long end)
{ {
unsigned long i = start & ~(L1_CACHE_BYTES - 1); unsigned long i = start & ~(L1_CACHE_BYTES - 1);
for (; i < end; i += L1_CACHE_BYTES) for (; i < end; i += L1_CACHE_BYTES)
asm volatile("dcache.civa %0\n"::"r"(i):"memory"); asm volatile("dcache.cva %0\n"::"r"(i):"memory");
sync_is(); sync_is();
} }

View File

@ -14,69 +14,50 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/cache.h> #include <asm/cache.h>
void arch_dma_prep_coherent(struct page *page, size_t size)
{
if (PageHighMem(page)) {
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
do {
void *ptr = kmap_atomic(page);
size_t _size = (size < PAGE_SIZE) ? size : PAGE_SIZE;
memset(ptr, 0, _size);
dma_wbinv_range((unsigned long)ptr,
(unsigned long)ptr + _size);
kunmap_atomic(ptr);
page++;
size -= PAGE_SIZE;
count--;
} while (count);
} else {
void *ptr = page_address(page);
memset(ptr, 0, size);
dma_wbinv_range((unsigned long)ptr, (unsigned long)ptr + size);
}
}
static inline void cache_op(phys_addr_t paddr, size_t size, static inline void cache_op(phys_addr_t paddr, size_t size,
void (*fn)(unsigned long start, unsigned long end)) void (*fn)(unsigned long start, unsigned long end))
{ {
struct page *page = pfn_to_page(paddr >> PAGE_SHIFT); struct page *page = phys_to_page(paddr);
unsigned int offset = paddr & ~PAGE_MASK; void *start = __va(page_to_phys(page));
size_t left = size; unsigned long offset = offset_in_page(paddr);
unsigned long start; size_t left = size;
do { do {
size_t len = left; size_t len = left;
if (offset + len > PAGE_SIZE)
len = PAGE_SIZE - offset;
if (PageHighMem(page)) { if (PageHighMem(page)) {
void *addr; start = kmap_atomic(page);
if (offset + len > PAGE_SIZE) { fn((unsigned long)start + offset,
if (offset >= PAGE_SIZE) { (unsigned long)start + offset + len);
page += offset >> PAGE_SHIFT;
offset &= ~PAGE_MASK;
}
len = PAGE_SIZE - offset;
}
addr = kmap_atomic(page); kunmap_atomic(start);
start = (unsigned long)(addr + offset);
fn(start, start + len);
kunmap_atomic(addr);
} else { } else {
start = (unsigned long)phys_to_virt(paddr); fn((unsigned long)start + offset,
fn(start, start + size); (unsigned long)start + offset + len);
} }
offset = 0; offset = 0;
page++; page++;
start += PAGE_SIZE;
left -= len; left -= len;
} while (left); } while (left);
} }
static void dma_wbinv_set_zero_range(unsigned long start, unsigned long end)
{
memset((void *)start, 0, end - start);
dma_wbinv_range(start, end);
}
void arch_dma_prep_coherent(struct page *page, size_t size)
{
cache_op(page_to_phys(page), size, dma_wbinv_set_zero_range);
}
void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
@ -98,11 +79,10 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
{ {
switch (dir) { switch (dir) {
case DMA_TO_DEVICE: case DMA_TO_DEVICE:
cache_op(paddr, size, dma_wb_range); return;
break;
case DMA_FROM_DEVICE: case DMA_FROM_DEVICE:
case DMA_BIDIRECTIONAL: case DMA_BIDIRECTIONAL:
cache_op(paddr, size, dma_wbinv_range); cache_op(paddr, size, dma_inv_range);
break; break;
default: default:
BUG(); BUG();

View File

@ -60,22 +60,6 @@ void __init mem_init(void)
mem_init_print_info(NULL); mem_init_print_info(NULL);
} }
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (start < end)
pr_info("Freeing initrd memory: %ldk freed\n",
(end - start) >> 10);
for (; start < end; start += PAGE_SIZE) {
ClearPageReserved(virt_to_page(start));
init_page_count(virt_to_page(start));
free_page(start);
totalram_pages_inc();
}
}
#endif
extern char __init_begin[], __init_end[]; extern char __init_begin[], __init_end[];
void free_initmem(void) void free_initmem(void)

View File

@ -8,12 +8,12 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
void __iomem *ioremap(phys_addr_t addr, size_t size) static void __iomem *__ioremap_caller(phys_addr_t addr, size_t size,
pgprot_t prot, void *caller)
{ {
phys_addr_t last_addr; phys_addr_t last_addr;
unsigned long offset, vaddr; unsigned long offset, vaddr;
struct vm_struct *area; struct vm_struct *area;
pgprot_t prot;
last_addr = addr + size - 1; last_addr = addr + size - 1;
if (!size || last_addr < addr) if (!size || last_addr < addr)
@ -23,15 +23,12 @@ void __iomem *ioremap(phys_addr_t addr, size_t size)
addr &= PAGE_MASK; addr &= PAGE_MASK;
size = PAGE_ALIGN(size + offset); size = PAGE_ALIGN(size + offset);
area = get_vm_area_caller(size, VM_ALLOC, __builtin_return_address(0)); area = get_vm_area_caller(size, VM_IOREMAP, caller);
if (!area) if (!area)
return NULL; return NULL;
vaddr = (unsigned long)area->addr; vaddr = (unsigned long)area->addr;
prot = __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE |
_PAGE_GLOBAL | _CACHE_UNCACHED | _PAGE_SO);
if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) { if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) {
free_vm_area(area); free_vm_area(area);
return NULL; return NULL;
@ -39,7 +36,20 @@ void __iomem *ioremap(phys_addr_t addr, size_t size)
return (void __iomem *)(vaddr + offset); return (void __iomem *)(vaddr + offset);
} }
EXPORT_SYMBOL(ioremap);
void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
{
return __ioremap_caller(phys_addr, size, prot,
__builtin_return_address(0));
}
EXPORT_SYMBOL(__ioremap);
void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
{
return __ioremap_caller(phys_addr, size, PAGE_KERNEL,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_cache);
void iounmap(void __iomem *addr) void iounmap(void __iomem *addr)
{ {
@ -51,10 +61,9 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot) unsigned long size, pgprot_t vma_prot)
{ {
if (!pfn_valid(pfn)) { if (!pfn_valid(pfn)) {
vma_prot.pgprot |= _PAGE_SO;
return pgprot_noncached(vma_prot); return pgprot_noncached(vma_prot);
} else if (file->f_flags & O_SYNC) { } else if (file->f_flags & O_SYNC) {
return pgprot_noncached(vma_prot); return pgprot_writecombine(vma_prot);
} }
return vma_prot; return vma_prot;