86f7d75eb7
On AR7, we already redefine PHYS_OFFSET to match the system specifities, it is however not sufficient when unsing dma_{map,unmap}_single, specifically in the ethernet driver, we must also adjust CAC_ADDR and UNCAC_ADDR for DMA to work correctly. This patch fixes the following issue, seen in cpmac_open: ops[#1]: Cpu 0 $ 0 : 00000000 10008400 a0f5b120 00000000 $ 4 : 94c59000 94270f64 00000020 00000010 $ 8 : 00000010 94103ce0 0000000a 94c03400 $12 : ffffffff 94c03408 94c03410 00000001 $16 : a0f5ba20 00000041 94c592c0 94c59200 $20 : 94c59000 000005ee 00002000 9438c8f0 $24 : 00000010 00000000 $28 : 94fac000 94fadd58 94390000 942724a8 Hi : 00000000 Lo : 00000001 epc : 94272518 cpmac_open+0x208/0x3f8 Not tainted ra : 942724a8 cpmac_open+0x198/0x3f8 Status: 10008403 KERNEL EXL IE Cause : 3080000c BadVA : 00000000 PrId : 00018448 (MIPS 4KEc) Modules linked in: Process ifconfig (pid: 278, threadinfo=94fac000, task=94e79590, tls=00000000) Stack : 7f8da120 2ab05cb0 94c59000 943356f0 00000000 943d0000 94c59000 943356f0 94c59030 943d0000 943c27c0 94fade10 00000000 94fade20 94c59000 9428e5a4 00000000 94c59000 00000041 94289768 94c59000 00000041 00001002 00001043 00000000 9428d810 00000000 94fade10 7f8da4e8 9428e6b8 00000000 7f8da4a8 7f8da4e8 00008914 00000000 942f7f2c 00000000 00000008 00408000 00008913 ... Call Trace: [<94272518>] cpmac_open+0x208/0x3f8 [<9428e5a4>] dev_open+0x164/0x264 [<9428d810>] dev_change_flags+0xd0/0x1bc [<942f7f2c>] devinet_ioctl+0x2d8/0x908 [<942771f8>] sock_ioctl+0x29c/0x2fc [<941a0fb4>] vfs_ioctl+0x2c/0x7c [<941a16ec>] do_vfs_ioctl+0x5dc/0x630 [<941a1790>] sys_ioctl+0x50/0x88 [<94101e10>] stack_done+0x20/0x3c Signed-off-by: peter fuerst <post@pfrst.de> Signed-off-by: Florian Fainelli <florian@openwrt.org> To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/1050/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
200 lines
5.3 KiB
C
200 lines
5.3 KiB
C
/*
|
|
* 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) 1994 - 1999, 2000, 03 Ralf Baechle
|
|
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
|
*/
|
|
#ifndef _ASM_PAGE_H
|
|
#define _ASM_PAGE_H
|
|
|
|
#include <spaces.h>
|
|
#include <linux/const.h>
|
|
|
|
/*
|
|
* PAGE_SHIFT determines the page size
|
|
*/
|
|
#ifdef CONFIG_PAGE_SIZE_4KB
|
|
#define PAGE_SHIFT 12
|
|
#endif
|
|
#ifdef CONFIG_PAGE_SIZE_8KB
|
|
#define PAGE_SHIFT 13
|
|
#endif
|
|
#ifdef CONFIG_PAGE_SIZE_16KB
|
|
#define PAGE_SHIFT 14
|
|
#endif
|
|
#ifdef CONFIG_PAGE_SIZE_32KB
|
|
#define PAGE_SHIFT 15
|
|
#endif
|
|
#ifdef CONFIG_PAGE_SIZE_64KB
|
|
#define PAGE_SHIFT 16
|
|
#endif
|
|
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
|
|
#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
|
|
|
|
#ifdef CONFIG_HUGETLB_PAGE
|
|
#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3)
|
|
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
|
|
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
|
|
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
|
|
#endif /* CONFIG_HUGETLB_PAGE */
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/pfn.h>
|
|
#include <asm/io.h>
|
|
|
|
extern void build_clear_page(void);
|
|
extern void build_copy_page(void);
|
|
|
|
/*
|
|
* It's normally defined only for FLATMEM config but it's
|
|
* used in our early mem init code for all memory models.
|
|
* So always define it.
|
|
*/
|
|
#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET)
|
|
|
|
extern void clear_page(void * page);
|
|
extern void copy_page(void * to, void * from);
|
|
|
|
extern unsigned long shm_align_mask;
|
|
|
|
static inline unsigned long pages_do_alias(unsigned long addr1,
|
|
unsigned long addr2)
|
|
{
|
|
return (addr1 ^ addr2) & shm_align_mask;
|
|
}
|
|
|
|
struct page;
|
|
|
|
static inline void clear_user_page(void *addr, unsigned long vaddr,
|
|
struct page *page)
|
|
{
|
|
extern void (*flush_data_cache_page)(unsigned long addr);
|
|
|
|
clear_page(addr);
|
|
if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK))
|
|
flush_data_cache_page((unsigned long)addr);
|
|
}
|
|
|
|
extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
|
|
struct page *to);
|
|
struct vm_area_struct;
|
|
extern void copy_user_highpage(struct page *to, struct page *from,
|
|
unsigned long vaddr, struct vm_area_struct *vma);
|
|
|
|
#define __HAVE_ARCH_COPY_USER_HIGHPAGE
|
|
|
|
/*
|
|
* These are used to make use of C type-checking..
|
|
*/
|
|
#ifdef CONFIG_64BIT_PHYS_ADDR
|
|
#ifdef CONFIG_CPU_MIPS32
|
|
typedef struct { unsigned long pte_low, pte_high; } pte_t;
|
|
#define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
|
|
#define __pte(x) ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; })
|
|
#else
|
|
typedef struct { unsigned long long pte; } pte_t;
|
|
#define pte_val(x) ((x).pte)
|
|
#define __pte(x) ((pte_t) { (x) } )
|
|
#endif
|
|
#else
|
|
typedef struct { unsigned long pte; } pte_t;
|
|
#define pte_val(x) ((x).pte)
|
|
#define __pte(x) ((pte_t) { (x) } )
|
|
#endif
|
|
typedef struct page *pgtable_t;
|
|
|
|
/*
|
|
* Right now we don't support 4-level pagetables, so all pud-related
|
|
* definitions come from <asm-generic/pgtable-nopud.h>.
|
|
*/
|
|
|
|
/*
|
|
* Finall the top of the hierarchy, the pgd
|
|
*/
|
|
typedef struct { unsigned long pgd; } pgd_t;
|
|
#define pgd_val(x) ((x).pgd)
|
|
#define __pgd(x) ((pgd_t) { (x) } )
|
|
|
|
/*
|
|
* Manipulate page protection bits
|
|
*/
|
|
typedef struct { unsigned long pgprot; } pgprot_t;
|
|
#define pgprot_val(x) ((x).pgprot)
|
|
#define __pgprot(x) ((pgprot_t) { (x) } )
|
|
|
|
/*
|
|
* On R4000-style MMUs where a TLB entry is mapping a adjacent even / odd
|
|
* pair of pages we only have a single global bit per pair of pages. When
|
|
* writing to the TLB make sure we always have the bit set for both pages
|
|
* or none. This macro is used to access the `buddy' of the pte we're just
|
|
* working on.
|
|
*/
|
|
#define ptep_buddy(x) ((pte_t *)((unsigned long)(x) ^ sizeof(pte_t)))
|
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
/*
|
|
* __pa()/__va() should be used only during mem init.
|
|
*/
|
|
#ifdef CONFIG_64BIT
|
|
#define __pa(x) \
|
|
({ \
|
|
unsigned long __x = (unsigned long)(x); \
|
|
__x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x); \
|
|
})
|
|
#else
|
|
#define __pa(x) \
|
|
((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
|
|
#endif
|
|
#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
|
|
#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
|
|
|
|
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
|
|
|
|
#ifdef CONFIG_FLATMEM
|
|
|
|
#define pfn_valid(pfn) \
|
|
({ \
|
|
unsigned long __pfn = (pfn); \
|
|
/* avoid <linux/bootmem.h> include hell */ \
|
|
extern unsigned long min_low_pfn; \
|
|
\
|
|
__pfn >= min_low_pfn && __pfn < max_mapnr; \
|
|
})
|
|
|
|
#elif defined(CONFIG_SPARSEMEM)
|
|
|
|
/* pfn_valid is defined in linux/mmzone.h */
|
|
|
|
#elif defined(CONFIG_NEED_MULTIPLE_NODES)
|
|
|
|
#define pfn_valid(pfn) \
|
|
({ \
|
|
unsigned long __pfn = (pfn); \
|
|
int __n = pfn_to_nid(__pfn); \
|
|
((__n >= 0) ? (__pfn < NODE_DATA(__n)->node_start_pfn + \
|
|
NODE_DATA(__n)->node_spanned_pages) \
|
|
: 0); \
|
|
})
|
|
|
|
#endif
|
|
|
|
#define virt_to_page(kaddr) pfn_to_page(PFN_DOWN(virt_to_phys(kaddr)))
|
|
#define virt_addr_valid(kaddr) pfn_valid(PFN_DOWN(virt_to_phys(kaddr)))
|
|
|
|
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
|
|
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
|
|
|
|
#define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + UNCAC_BASE + \
|
|
PHYS_OFFSET)
|
|
#define CAC_ADDR(addr) ((addr) - UNCAC_BASE + PAGE_OFFSET - \
|
|
PHYS_OFFSET)
|
|
|
|
#include <asm-generic/memory_model.h>
|
|
#include <asm-generic/getorder.h>
|
|
|
|
#endif /* _ASM_PAGE_H */
|