Merge branch 'highmem' into devel
Conflicts: arch/arm/mach-clps7500/include/mach/memory.h
This commit is contained in:
@@ -112,10 +112,8 @@
|
|||||||
* private definitions which should NOT be used outside memory.h
|
* private definitions which should NOT be used outside memory.h
|
||||||
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
|
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
|
||||||
*/
|
*/
|
||||||
#ifndef __virt_to_phys
|
|
||||||
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
|
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
|
||||||
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
|
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a physical address to a Page Frame Number and back
|
* Convert a physical address to a Page Frame Number and back
|
||||||
@@ -180,6 +178,11 @@ static inline void *phys_to_virt(unsigned long x)
|
|||||||
* memory. Use of these is *deprecated* (and that doesn't mean
|
* memory. Use of these is *deprecated* (and that doesn't mean
|
||||||
* use the __ prefixed forms instead.) See dma-mapping.h.
|
* use the __ prefixed forms instead.) See dma-mapping.h.
|
||||||
*/
|
*/
|
||||||
|
#ifndef __virt_to_bus
|
||||||
|
#define __virt_to_bus __virt_to_phys
|
||||||
|
#define __bus_to_virt __phys_to_virt
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline __deprecated unsigned long virt_to_bus(void *x)
|
static inline __deprecated unsigned long virt_to_bus(void *x)
|
||||||
{
|
{
|
||||||
return __virt_to_bus((unsigned long)x);
|
return __virt_to_bus((unsigned long)x);
|
||||||
|
@@ -108,30 +108,36 @@
|
|||||||
#error Unknown user operations model
|
#error Unknown user operations model
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct page;
|
||||||
|
|
||||||
struct cpu_user_fns {
|
struct cpu_user_fns {
|
||||||
void (*cpu_clear_user_page)(void *p, unsigned long user);
|
void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr);
|
||||||
void (*cpu_copy_user_page)(void *to, const void *from,
|
void (*cpu_copy_user_highpage)(struct page *to, struct page *from,
|
||||||
unsigned long user);
|
unsigned long vaddr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef MULTI_USER
|
#ifdef MULTI_USER
|
||||||
extern struct cpu_user_fns cpu_user;
|
extern struct cpu_user_fns cpu_user;
|
||||||
|
|
||||||
#define __cpu_clear_user_page cpu_user.cpu_clear_user_page
|
#define __cpu_clear_user_highpage cpu_user.cpu_clear_user_highpage
|
||||||
#define __cpu_copy_user_page cpu_user.cpu_copy_user_page
|
#define __cpu_copy_user_highpage cpu_user.cpu_copy_user_highpage
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define __cpu_clear_user_page __glue(_USER,_clear_user_page)
|
#define __cpu_clear_user_highpage __glue(_USER,_clear_user_highpage)
|
||||||
#define __cpu_copy_user_page __glue(_USER,_copy_user_page)
|
#define __cpu_copy_user_highpage __glue(_USER,_copy_user_highpage)
|
||||||
|
|
||||||
extern void __cpu_clear_user_page(void *p, unsigned long user);
|
extern void __cpu_clear_user_highpage(struct page *page, unsigned long vaddr);
|
||||||
extern void __cpu_copy_user_page(void *to, const void *from,
|
extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
|
||||||
unsigned long user);
|
unsigned long vaddr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define clear_user_page(addr,vaddr,pg) __cpu_clear_user_page(addr, vaddr)
|
#define clear_user_highpage(page,vaddr) \
|
||||||
#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
|
__cpu_clear_user_highpage(page, vaddr)
|
||||||
|
|
||||||
|
#define __HAVE_ARCH_COPY_USER_HIGHPAGE
|
||||||
|
#define copy_user_highpage(to,from,vaddr,vma) \
|
||||||
|
__cpu_copy_user_highpage(to, from, vaddr)
|
||||||
|
|
||||||
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
|
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
|
||||||
extern void copy_page(void *to, const void *from);
|
extern void copy_page(void *to, const void *from);
|
||||||
|
@@ -209,9 +209,11 @@ struct meminfo {
|
|||||||
struct membank bank[NR_BANKS];
|
struct membank bank[NR_BANKS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern struct meminfo meminfo;
|
||||||
|
|
||||||
#define for_each_nodebank(iter,mi,no) \
|
#define for_each_nodebank(iter,mi,no) \
|
||||||
for (iter = 0; iter < mi->nr_banks; iter++) \
|
for (iter = 0; iter < (mi)->nr_banks; iter++) \
|
||||||
if (mi->bank[iter].node == no)
|
if ((mi)->bank[iter].node == no)
|
||||||
|
|
||||||
#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
|
#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
|
||||||
#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
|
#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
|
||||||
|
@@ -59,7 +59,7 @@ static int __init fpe_setup(char *line)
|
|||||||
__setup("fpe=", fpe_setup);
|
__setup("fpe=", fpe_setup);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void paging_init(struct meminfo *, struct machine_desc *desc);
|
extern void paging_init(struct machine_desc *desc);
|
||||||
extern void reboot_setup(char *str);
|
extern void reboot_setup(char *str);
|
||||||
extern void _text, _etext, __data_start, _edata, _end;
|
extern void _text, _etext, __data_start, _edata, _end;
|
||||||
|
|
||||||
@@ -112,7 +112,6 @@ static struct stack stacks[NR_CPUS];
|
|||||||
char elf_platform[ELF_PLATFORM_SIZE];
|
char elf_platform[ELF_PLATFORM_SIZE];
|
||||||
EXPORT_SYMBOL(elf_platform);
|
EXPORT_SYMBOL(elf_platform);
|
||||||
|
|
||||||
static struct meminfo meminfo __initdata = { 0, };
|
|
||||||
static const char *cpu_name;
|
static const char *cpu_name;
|
||||||
static const char *machine_name;
|
static const char *machine_name;
|
||||||
static char __initdata command_line[COMMAND_LINE_SIZE];
|
static char __initdata command_line[COMMAND_LINE_SIZE];
|
||||||
@@ -367,21 +366,34 @@ static struct machine_desc * __init setup_machine(unsigned int nr)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init arm_add_memory(unsigned long start, unsigned long size)
|
static int __init arm_add_memory(unsigned long start, unsigned long size)
|
||||||
{
|
{
|
||||||
struct membank *bank;
|
struct membank *bank = &meminfo.bank[meminfo.nr_banks];
|
||||||
|
|
||||||
|
if (meminfo.nr_banks >= NR_BANKS) {
|
||||||
|
printk(KERN_CRIT "NR_BANKS too low, "
|
||||||
|
"ignoring memory at %#lx\n", start);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that start/size are aligned to a page boundary.
|
* Ensure that start/size are aligned to a page boundary.
|
||||||
* Size is appropriately rounded down, start is rounded up.
|
* Size is appropriately rounded down, start is rounded up.
|
||||||
*/
|
*/
|
||||||
size -= start & ~PAGE_MASK;
|
size -= start & ~PAGE_MASK;
|
||||||
|
|
||||||
bank = &meminfo.bank[meminfo.nr_banks++];
|
|
||||||
|
|
||||||
bank->start = PAGE_ALIGN(start);
|
bank->start = PAGE_ALIGN(start);
|
||||||
bank->size = size & PAGE_MASK;
|
bank->size = size & PAGE_MASK;
|
||||||
bank->node = PHYS_TO_NID(start);
|
bank->node = PHYS_TO_NID(start);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether this memory region has non-zero size or
|
||||||
|
* invalid node number.
|
||||||
|
*/
|
||||||
|
if (bank->size == 0 || bank->node >= MAX_NUMNODES)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
meminfo.nr_banks++;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -539,14 +551,7 @@ __tagtable(ATAG_CORE, parse_tag_core);
|
|||||||
|
|
||||||
static int __init parse_tag_mem32(const struct tag *tag)
|
static int __init parse_tag_mem32(const struct tag *tag)
|
||||||
{
|
{
|
||||||
if (meminfo.nr_banks >= NR_BANKS) {
|
return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
|
||||||
printk(KERN_WARNING
|
|
||||||
"Ignoring memory bank 0x%08x size %dKB\n",
|
|
||||||
tag->u.mem.start, tag->u.mem.size / 1024);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
arm_add_memory(tag->u.mem.start, tag->u.mem.size);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__tagtable(ATAG_MEM, parse_tag_mem32);
|
__tagtable(ATAG_MEM, parse_tag_mem32);
|
||||||
@@ -718,7 +723,7 @@ void __init setup_arch(char **cmdline_p)
|
|||||||
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
|
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
|
||||||
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
|
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
|
||||||
parse_cmdline(cmdline_p, from);
|
parse_cmdline(cmdline_p, from);
|
||||||
paging_init(&meminfo, mdesc);
|
paging_init(mdesc);
|
||||||
request_standard_resources(&meminfo, mdesc);
|
request_standard_resources(&meminfo, mdesc);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
@@ -14,9 +14,6 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0xf0000000)
|
#define PHYS_OFFSET UL(0xf0000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The nodes are the followings:
|
* The nodes are the followings:
|
||||||
*
|
*
|
||||||
|
@@ -25,15 +25,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET (AT91_SDRAM_BASE)
|
#define PHYS_OFFSET (AT91_SDRAM_BASE)
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -26,25 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0xc0000000)
|
#define PHYS_OFFSET UL(0xc0000000)
|
||||||
|
|
||||||
/*
|
#if !defined(CONFIG_ARCH_CDB89712) && !defined (CONFIG_ARCH_AUTCPU12)
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_CDB89712)
|
|
||||||
|
|
||||||
#define __virt_to_bus(x) (x)
|
|
||||||
#define __bus_to_virt(x) (x)
|
|
||||||
|
|
||||||
#elif defined (CONFIG_ARCH_AUTCPU12)
|
|
||||||
|
|
||||||
#define __virt_to_bus(x) (x)
|
|
||||||
#define __bus_to_virt(x) (x)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
|
#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
|
||||||
#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
|
#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
|
||||||
|
@@ -55,10 +55,4 @@ __arch_adjust_zones(int node, unsigned long *size, unsigned long *holes)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Bus address is physical address
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif /* __ASM_ARCH_MEMORY_H */
|
#endif /* __ASM_ARCH_MEMORY_H */
|
||||||
|
@@ -21,13 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* We keep this 1:1 so that we don't interfere
|
|
||||||
* with the PCMCIA memory regions
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) (x)
|
|
||||||
#define __bus_to_virt(x) (x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cache flushing area - SRAM
|
* Cache flushing area - SRAM
|
||||||
*/
|
*/
|
||||||
|
@@ -7,8 +7,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -30,9 +30,18 @@
|
|||||||
extern unsigned long __virt_to_bus(unsigned long);
|
extern unsigned long __virt_to_bus(unsigned long);
|
||||||
extern unsigned long __bus_to_virt(unsigned long);
|
extern unsigned long __bus_to_virt(unsigned long);
|
||||||
#endif
|
#endif
|
||||||
|
#define __virt_to_bus __virt_to_bus
|
||||||
|
#define __bus_to_virt __bus_to_virt
|
||||||
|
|
||||||
#elif defined(CONFIG_FOOTBRIDGE_HOST)
|
#elif defined(CONFIG_FOOTBRIDGE_HOST)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The footbridge is programmed to expose the system RAM at the corresponding
|
||||||
|
* address. So, if PAGE_OFFSET is 0xc0000000, RAM appears at 0xe0000000.
|
||||||
|
* If 0x80000000, then its exposed at 0xa0000000 on the bus. etc.
|
||||||
|
* The only requirement is that the RAM isn't placed at bus address 0 which
|
||||||
|
* would clash with VGA cards.
|
||||||
|
*/
|
||||||
#define __virt_to_bus(x) ((x) - 0xe0000000)
|
#define __virt_to_bus(x) ((x) - 0xe0000000)
|
||||||
#define __bus_to_virt(x) ((x) + 0xe0000000)
|
#define __bus_to_virt(x) ((x) + 0xe0000000)
|
||||||
|
|
||||||
|
@@ -7,23 +7,6 @@
|
|||||||
#ifndef __ASM_ARCH_MEMORY_H
|
#ifndef __ASM_ARCH_MEMORY_H
|
||||||
#define __ASM_ARCH_MEMORY_H
|
#define __ASM_ARCH_MEMORY_H
|
||||||
|
|
||||||
/*
|
|
||||||
* Page offset:
|
|
||||||
* ( 0xc0000000UL )
|
|
||||||
*/
|
|
||||||
#define PHYS_OFFSET UL(0x40000000)
|
#define PHYS_OFFSET UL(0x40000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*
|
|
||||||
* There is something to do here later !, Mar 2000, Jungjun Kim
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -23,14 +23,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x08000000)
|
#define PHYS_OFFSET UL(0x08000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) (x - PAGE_OFFSET + PHYS_OFFSET)
|
|
||||||
#define __bus_to_virt(x) (x - PHYS_OFFSET + PAGE_OFFSET)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -24,15 +24,8 @@
|
|||||||
* Physical DRAM offset.
|
* Physical DRAM offset.
|
||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
#define BUS_OFFSET UL(0x80000000)
|
|
||||||
|
|
||||||
/*
|
#define BUS_OFFSET UL(0x80000000)
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) (x - PAGE_OFFSET + BUS_OFFSET)
|
#define __virt_to_bus(x) (x - PAGE_OFFSET + BUS_OFFSET)
|
||||||
#define __bus_to_virt(x) (x - BUS_OFFSET + PAGE_OFFSET)
|
#define __bus_to_virt(x) (x - BUS_OFFSET + PAGE_OFFSET)
|
||||||
|
|
||||||
|
@@ -16,18 +16,6 @@
|
|||||||
#define IOP13XX_PMMR_P_START (IOP13XX_PMMR_PHYS_MEM_BASE)
|
#define IOP13XX_PMMR_P_START (IOP13XX_PMMR_PHYS_MEM_BASE)
|
||||||
#define IOP13XX_PMMR_P_END (IOP13XX_PMMR_PHYS_MEM_BASE + IOP13XX_PMMR_SIZE)
|
#define IOP13XX_PMMR_P_END (IOP13XX_PMMR_PHYS_MEM_BASE + IOP13XX_PMMR_SIZE)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> PCI DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* RAM has 1:1 mapping on the PCIe/x Busses */
|
|
||||||
#define __virt_to_bus(x) (__virt_to_phys(x))
|
|
||||||
#define __bus_to_virt(x) (__phys_to_virt(x))
|
|
||||||
|
|
||||||
static inline dma_addr_t __virt_to_lbus(unsigned long x)
|
static inline dma_addr_t __virt_to_lbus(unsigned long x)
|
||||||
{
|
{
|
||||||
return x + IOP13XX_PMMR_PHYS_MEM_BASE - IOP13XX_PMMR_VIRT_MEM_BASE;
|
return x + IOP13XX_PMMR_PHYS_MEM_BASE - IOP13XX_PMMR_VIRT_MEM_BASE;
|
||||||
@@ -55,7 +43,7 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
|
|||||||
if (is_lbus_device(dev) && __is_lbus_dma(__dma)) \
|
if (is_lbus_device(dev) && __is_lbus_dma(__dma)) \
|
||||||
__virt = __lbus_to_virt(__dma); \
|
__virt = __lbus_to_virt(__dma); \
|
||||||
else \
|
else \
|
||||||
__virt = __bus_to_virt(__dma); \
|
__virt = __phys_to_virt(__dma); \
|
||||||
(void *)__virt; \
|
(void *)__virt; \
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -66,7 +54,7 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
|
|||||||
if (is_lbus_device(dev) && __is_lbus_virt(__virt)) \
|
if (is_lbus_device(dev) && __is_lbus_virt(__virt)) \
|
||||||
__dma = __virt_to_lbus(__virt); \
|
__dma = __virt_to_lbus(__virt); \
|
||||||
else \
|
else \
|
||||||
__dma = __virt_to_bus(__virt); \
|
__dma = __virt_to_phys(__virt); \
|
||||||
__dma; \
|
__dma; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -12,15 +12,4 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0xa0000000)
|
#define PHYS_OFFSET UL(0xa0000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> PCI DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) (__virt_to_phys(x))
|
|
||||||
#define __bus_to_virt(x) (__phys_to_virt(x))
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -12,15 +12,4 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> PCI DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) (__virt_to_phys(x))
|
|
||||||
#define __bus_to_virt(x) (__phys_to_virt(x))
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -15,13 +15,6 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#include <mach/ixp2000-regs.h>
|
#include <mach/ixp2000-regs.h>
|
||||||
|
|
||||||
#define __virt_to_bus(v) \
|
#define __virt_to_bus(v) \
|
||||||
|
@@ -19,16 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET (0x00000000)
|
#define PHYS_OFFSET (0x00000000)
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#ifndef __ASSEMBLY__
|
|
||||||
|
|
||||||
#define __virt_to_bus(v) \
|
#define __virt_to_bus(v) \
|
||||||
({ unsigned int ret; \
|
({ unsigned int ret; \
|
||||||
ret = ((__virt_to_phys(v) - 0x00000000) + \
|
ret = ((__virt_to_phys(v) - 0x00000000) + \
|
||||||
@@ -43,6 +33,3 @@
|
|||||||
#define arch_is_coherent() 1
|
#define arch_is_coherent() 1
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@@ -25,16 +25,4 @@ void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*
|
|
||||||
* These are dummies for now.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -7,8 +7,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -37,11 +37,6 @@ extern struct bus_type platform_bus_type;
|
|||||||
(dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); })
|
(dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); })
|
||||||
#define __arch_page_to_dma(dev, x) __arch_virt_to_dma(dev, page_address(x))
|
#define __arch_page_to_dma(dev, x) __arch_virt_to_dma(dev, page_address(x))
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -17,9 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0xf0000000)
|
#define PHYS_OFFSET UL(0xf0000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cache flushing area - ROM
|
* Cache flushing area - ROM
|
||||||
*/
|
*/
|
||||||
|
@@ -19,16 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0xc0000000)
|
#define PHYS_OFFSET UL(0xc0000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#ifdef CONFIG_DISCONTIGMEM
|
#ifdef CONFIG_DISCONTIGMEM
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -7,8 +7,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -19,9 +19,5 @@
|
|||||||
/* physical offset of RAM */
|
/* physical offset of RAM */
|
||||||
#define PHYS_OFFSET UL(0x10000000)
|
#define PHYS_OFFSET UL(0x10000000)
|
||||||
|
|
||||||
/* bus address and physical addresses are identical */
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -7,8 +7,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -22,15 +22,5 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x80000000)
|
#define PHYS_OFFSET UL(0x80000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -21,7 +21,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -9,8 +9,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -18,7 +18,4 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET (0x80000000)
|
#define PHYS_OFFSET (0x80000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
|
|
||||||
#define __bus_to_virt(x) ((x) + PAGE_OFFSET - PHYS_OFFSET)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -17,16 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0xa0000000)
|
#define PHYS_OFFSET UL(0xa0000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The nodes are matched with the physical SDRAM banks as follows:
|
* The nodes are matched with the physical SDRAM banks as follows:
|
||||||
*
|
*
|
||||||
|
@@ -565,7 +565,7 @@ static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state)
|
|||||||
u32 *mem_resume_unknown = phys_to_virt(RESUME_UNKNOWN_ADDR);
|
u32 *mem_resume_unknown = phys_to_virt(RESUME_UNKNOWN_ADDR);
|
||||||
|
|
||||||
/* Devices prepare suspend */
|
/* Devices prepare suspend */
|
||||||
is_bt_on = gpio_get_value(GPIO83_BT_ON);
|
is_bt_on = !!gpio_get_value(GPIO83_BT_ON);
|
||||||
pxa2xx_mfp_set_lpm(GPIO83_BT_ON,
|
pxa2xx_mfp_set_lpm(GPIO83_BT_ON,
|
||||||
is_bt_on ? MFP_LPM_DRIVE_HIGH : MFP_LPM_DRIVE_LOW);
|
is_bt_on ? MFP_LPM_DRIVE_HIGH : MFP_LPM_DRIVE_LOW);
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ ENTRY(mioa701_jumpaddr)
|
|||||||
1:
|
1:
|
||||||
mov r0, #0xa0000000 @ Don't suppose memory access works
|
mov r0, #0xa0000000 @ Don't suppose memory access works
|
||||||
orr r0, r0, #0x00200000 @ even if it's supposed to
|
orr r0, r0, #0x00200000 @ even if it's supposed to
|
||||||
|
orr r0, r0, #0x0000b000
|
||||||
mov r1, #0
|
mov r1, #0
|
||||||
str r1, [r0] @ Early disable resume for next boot
|
str r1, [r0] @ Early disable resume for next boot
|
||||||
ldr r0, mioa701_jumpaddr @ (Murphy's Law)
|
ldr r0, mioa701_jumpaddr @ (Murphy's Law)
|
||||||
|
@@ -25,14 +25,4 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
|
|
||||||
#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -23,13 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0x10000000)
|
#define PHYS_OFFSET UL(0x10000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* These are exactly the same on the RiscPC as the
|
|
||||||
* physical memory view.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cache flushing area - ROM
|
* Cache flushing area - ROM
|
||||||
*/
|
*/
|
||||||
|
@@ -17,7 +17,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x0C000000)
|
#define PHYS_OFFSET UL(0x0C000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -13,7 +13,4 @@
|
|||||||
|
|
||||||
#define PHYS_OFFSET UL(0x30000000)
|
#define PHYS_OFFSET UL(0x30000000)
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -27,18 +27,6 @@ void sa1111_adjust_zones(int node, unsigned long *size, unsigned long *holes);
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*
|
|
||||||
* On the SA1100, bus addresses are equivalent to physical addresses.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Because of the wide memory address space between physical RAM banks on the
|
* Because of the wide memory address space between physical RAM banks on the
|
||||||
* SA1100, it's much convenient to use Linux's SparseMEM support to implement
|
* SA1100, it's much convenient to use Linux's SparseMEM support to implement
|
||||||
|
@@ -36,9 +36,6 @@ static inline void __arch_adjust_zones(int node, unsigned long *zone_size, unsig
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cache flushing area
|
* Cache flushing area
|
||||||
*/
|
*/
|
||||||
|
@@ -25,14 +25,4 @@
|
|||||||
*/
|
*/
|
||||||
#define PHYS_OFFSET UL(0x00000000)
|
#define PHYS_OFFSET UL(0x00000000)
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* virt_to_bus: Used to translate the virtual address to an
|
|
||||||
* address suitable to be passed to set_dma_addr
|
|
||||||
* bus_to_virt: Used to convert an address for DMA operations
|
|
||||||
* to an address that the kernel can use.
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
|
|
||||||
#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/arch/arm/lib/copypage-feroceon.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 2008 Marvell Semiconductors
|
|
||||||
*
|
|
||||||
* 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 handles copy_user_page and clear_user_page on Feroceon
|
|
||||||
* more optimally than the generic implementations.
|
|
||||||
*/
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <asm/asm-offsets.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
|
|
||||||
ENTRY(feroceon_copy_user_page)
|
|
||||||
stmfd sp!, {r4-r9, lr}
|
|
||||||
mov ip, #PAGE_SZ
|
|
||||||
1: mov lr, r1
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
pld [lr, #32]
|
|
||||||
pld [lr, #64]
|
|
||||||
pld [lr, #96]
|
|
||||||
pld [lr, #128]
|
|
||||||
pld [lr, #160]
|
|
||||||
pld [lr, #192]
|
|
||||||
pld [lr, #224]
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
ldmia r1!, {r2 - r9}
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
stmia r0, {r2 - r9}
|
|
||||||
subs ip, ip, #(32 * 8)
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
bne 1b
|
|
||||||
mcr p15, 0, ip, c7, c10, 4 @ drain WB
|
|
||||||
ldmfd sp!, {r4-r9, pc}
|
|
||||||
|
|
||||||
.align 5
|
|
||||||
|
|
||||||
ENTRY(feroceon_clear_user_page)
|
|
||||||
stmfd sp!, {r4-r7, lr}
|
|
||||||
mov r1, #PAGE_SZ/32
|
|
||||||
mov r2, #0
|
|
||||||
mov r3, #0
|
|
||||||
mov r4, #0
|
|
||||||
mov r5, #0
|
|
||||||
mov r6, #0
|
|
||||||
mov r7, #0
|
|
||||||
mov ip, #0
|
|
||||||
mov lr, #0
|
|
||||||
1: stmia r0, {r2-r7, ip, lr}
|
|
||||||
subs r1, r1, #1
|
|
||||||
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
|
|
||||||
add r0, r0, #32
|
|
||||||
bne 1b
|
|
||||||
mcr p15, 0, r1, c7, c10, 4 @ drain WB
|
|
||||||
ldmfd sp!, {r4-r7, pc}
|
|
||||||
|
|
||||||
__INITDATA
|
|
||||||
|
|
||||||
.type feroceon_user_fns, #object
|
|
||||||
ENTRY(feroceon_user_fns)
|
|
||||||
.long feroceon_clear_user_page
|
|
||||||
.long feroceon_copy_user_page
|
|
||||||
.size feroceon_user_fns, . - feroceon_user_fns
|
|
111
arch/arm/mm/copypage-feroceon.c
Normal file
111
arch/arm/mm/copypage-feroceon.c
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/arm/mm/copypage-feroceon.S
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Marvell Semiconductors
|
||||||
|
*
|
||||||
|
* 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 handles copy_user_highpage and clear_user_page on Feroceon
|
||||||
|
* more optimally than the generic implementations.
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
|
static void __attribute__((naked))
|
||||||
|
feroceon_copy_user_page(void *kto, const void *kfrom)
|
||||||
|
{
|
||||||
|
asm("\
|
||||||
|
stmfd sp!, {r4-r9, lr} \n\
|
||||||
|
mov ip, %0 \n\
|
||||||
|
1: mov lr, r1 \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
pld [lr, #32] \n\
|
||||||
|
pld [lr, #64] \n\
|
||||||
|
pld [lr, #96] \n\
|
||||||
|
pld [lr, #128] \n\
|
||||||
|
pld [lr, #160] \n\
|
||||||
|
pld [lr, #192] \n\
|
||||||
|
pld [lr, #224] \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
ldmia r1!, {r2 - r9} \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
stmia r0, {r2 - r9} \n\
|
||||||
|
subs ip, ip, #(32 * 8) \n\
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add r0, r0, #32 \n\
|
||||||
|
bne 1b \n\
|
||||||
|
mcr p15, 0, ip, c7, c10, 4 @ drain WB\n\
|
||||||
|
ldmfd sp!, {r4-r9, pc}"
|
||||||
|
:
|
||||||
|
: "I" (PAGE_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void feroceon_copy_user_highpage(struct page *to, struct page *from,
|
||||||
|
unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *kto, *kfrom;
|
||||||
|
|
||||||
|
kto = kmap_atomic(to, KM_USER0);
|
||||||
|
kfrom = kmap_atomic(from, KM_USER1);
|
||||||
|
feroceon_copy_user_page(kto, kfrom);
|
||||||
|
kunmap_atomic(kfrom, KM_USER1);
|
||||||
|
kunmap_atomic(kto, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void feroceon_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
|
asm volatile ("\
|
||||||
|
mov r1, %2 \n\
|
||||||
|
mov r2, #0 \n\
|
||||||
|
mov r3, #0 \n\
|
||||||
|
mov r4, #0 \n\
|
||||||
|
mov r5, #0 \n\
|
||||||
|
mov r6, #0 \n\
|
||||||
|
mov r7, #0 \n\
|
||||||
|
mov ip, #0 \n\
|
||||||
|
mov lr, #0 \n\
|
||||||
|
1: stmia %0, {r2-r7, ip, lr} \n\
|
||||||
|
subs r1, r1, #1 \n\
|
||||||
|
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
|
||||||
|
add %0, %0, #32 \n\
|
||||||
|
bne 1b \n\
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ drain WB"
|
||||||
|
: "=r" (ptr)
|
||||||
|
: "0" (kaddr), "I" (PAGE_SIZE / 32)
|
||||||
|
: "r1", "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_user_fns feroceon_user_fns __initdata = {
|
||||||
|
.cpu_clear_user_highpage = feroceon_clear_user_highpage,
|
||||||
|
.cpu_copy_user_highpage = feroceon_copy_user_highpage,
|
||||||
|
};
|
||||||
|
|
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/arch/arm/lib/copypage.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 1995-1999 Russell King
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* ASM optimised string functions
|
|
||||||
*/
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <asm/assembler.h>
|
|
||||||
#include <asm/asm-offsets.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* ARMv3 optimised copy_user_page
|
|
||||||
*
|
|
||||||
* FIXME: do we need to handle cache stuff...
|
|
||||||
*/
|
|
||||||
ENTRY(v3_copy_user_page)
|
|
||||||
stmfd sp!, {r4, lr} @ 2
|
|
||||||
mov r2, #PAGE_SZ/64 @ 1
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4+1
|
|
||||||
1: stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4+1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4+1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
subs r2, r2, #1 @ 1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmneia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
bne 1b @ 1
|
|
||||||
ldmfd sp!, {r4, pc} @ 3
|
|
||||||
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* ARMv3 optimised clear_user_page
|
|
||||||
*
|
|
||||||
* FIXME: do we need to handle cache stuff...
|
|
||||||
*/
|
|
||||||
ENTRY(v3_clear_user_page)
|
|
||||||
str lr, [sp, #-4]!
|
|
||||||
mov r1, #PAGE_SZ/64 @ 1
|
|
||||||
mov r2, #0 @ 1
|
|
||||||
mov r3, #0 @ 1
|
|
||||||
mov ip, #0 @ 1
|
|
||||||
mov lr, #0 @ 1
|
|
||||||
1: stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
subs r1, r1, #1 @ 1
|
|
||||||
bne 1b @ 1
|
|
||||||
ldr pc, [sp], #4
|
|
||||||
|
|
||||||
__INITDATA
|
|
||||||
|
|
||||||
.type v3_user_fns, #object
|
|
||||||
ENTRY(v3_user_fns)
|
|
||||||
.long v3_clear_user_page
|
|
||||||
.long v3_copy_user_page
|
|
||||||
.size v3_user_fns, . - v3_user_fns
|
|
81
arch/arm/mm/copypage-v3.c
Normal file
81
arch/arm/mm/copypage-v3.c
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/arm/mm/copypage-v3.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995-1999 Russell King
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv3 optimised copy_user_highpage
|
||||||
|
*
|
||||||
|
* FIXME: do we need to handle cache stuff...
|
||||||
|
*/
|
||||||
|
static void __attribute__((naked))
|
||||||
|
v3_copy_user_page(void *kto, const void *kfrom)
|
||||||
|
{
|
||||||
|
asm("\n\
|
||||||
|
stmfd sp!, {r4, lr} @ 2\n\
|
||||||
|
mov r2, %2 @ 1\n\
|
||||||
|
ldmia %0!, {r3, r4, ip, lr} @ 4+1\n\
|
||||||
|
1: stmia %1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia %0!, {r3, r4, ip, lr} @ 4+1\n\
|
||||||
|
stmia %1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia %0!, {r3, r4, ip, lr} @ 4+1\n\
|
||||||
|
stmia %1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia %0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
subs r2, r2, #1 @ 1\n\
|
||||||
|
stmia %1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmneia %0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
bne 1b @ 1\n\
|
||||||
|
ldmfd sp!, {r4, pc} @ 3"
|
||||||
|
:
|
||||||
|
: "r" (kfrom), "r" (kto), "I" (PAGE_SIZE / 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
void v3_copy_user_highpage(struct page *to, struct page *from,
|
||||||
|
unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *kto, *kfrom;
|
||||||
|
|
||||||
|
kto = kmap_atomic(to, KM_USER0);
|
||||||
|
kfrom = kmap_atomic(from, KM_USER1);
|
||||||
|
v3_copy_user_page(kto, kfrom);
|
||||||
|
kunmap_atomic(kfrom, KM_USER1);
|
||||||
|
kunmap_atomic(kto, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv3 optimised clear_user_page
|
||||||
|
*
|
||||||
|
* FIXME: do we need to handle cache stuff...
|
||||||
|
*/
|
||||||
|
void v3_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
|
asm volatile("\n\
|
||||||
|
mov r1, %2 @ 1\n\
|
||||||
|
mov r2, #0 @ 1\n\
|
||||||
|
mov r3, #0 @ 1\n\
|
||||||
|
mov ip, #0 @ 1\n\
|
||||||
|
mov lr, #0 @ 1\n\
|
||||||
|
1: stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
subs r1, r1, #1 @ 1\n\
|
||||||
|
bne 1b @ 1"
|
||||||
|
: "=r" (ptr)
|
||||||
|
: "0" (kaddr), "I" (PAGE_SIZE / 64)
|
||||||
|
: "r1", "r2", "r3", "ip", "lr");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_user_fns v3_user_fns __initdata = {
|
||||||
|
.cpu_clear_user_highpage = v3_clear_user_highpage,
|
||||||
|
.cpu_copy_user_highpage = v3_copy_user_highpage,
|
||||||
|
};
|
@@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
#include <asm/page.h>
|
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
static DEFINE_SPINLOCK(minicache_lock);
|
static DEFINE_SPINLOCK(minicache_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ARMv4 mini-dcache optimised copy_user_page
|
* ARMv4 mini-dcache optimised copy_user_highpage
|
||||||
*
|
*
|
||||||
* We flush the destination cache lines just before we write the data into the
|
* We flush the destination cache lines just before we write the data into the
|
||||||
* corresponding address. Since the Dcache is read-allocate, this removes the
|
* corresponding address. Since the Dcache is read-allocate, this removes the
|
||||||
@@ -42,7 +42,7 @@ static DEFINE_SPINLOCK(minicache_lock);
|
|||||||
*
|
*
|
||||||
* Note: We rely on all ARMv4 processors implementing the "invalidate D line"
|
* Note: We rely on all ARMv4 processors implementing the "invalidate D line"
|
||||||
* instruction. If your processor does not supply this, you have to write your
|
* instruction. If your processor does not supply this, you have to write your
|
||||||
* own copy_user_page that does the right thing.
|
* own copy_user_highpage that does the right thing.
|
||||||
*/
|
*/
|
||||||
static void __attribute__((naked))
|
static void __attribute__((naked))
|
||||||
mc_copy_user_page(void *from, void *to)
|
mc_copy_user_page(void *from, void *to)
|
||||||
@@ -68,50 +68,53 @@ mc_copy_user_page(void *from, void *to)
|
|||||||
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
|
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
|
||||||
}
|
}
|
||||||
|
|
||||||
void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
|
void v4_mc_copy_user_highpage(struct page *from, struct page *to,
|
||||||
|
unsigned long vaddr)
|
||||||
{
|
{
|
||||||
struct page *page = virt_to_page(kfrom);
|
void *kto = kmap_atomic(to, KM_USER1);
|
||||||
|
|
||||||
if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
|
if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
|
||||||
__flush_dcache_page(page_mapping(page), page);
|
__flush_dcache_page(page_mapping(from), from);
|
||||||
|
|
||||||
spin_lock(&minicache_lock);
|
spin_lock(&minicache_lock);
|
||||||
|
|
||||||
set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
|
set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
|
||||||
flush_tlb_kernel_page(0xffff8000);
|
flush_tlb_kernel_page(0xffff8000);
|
||||||
|
|
||||||
mc_copy_user_page((void *)0xffff8000, kto);
|
mc_copy_user_page((void *)0xffff8000, kto);
|
||||||
|
|
||||||
spin_unlock(&minicache_lock);
|
spin_unlock(&minicache_lock);
|
||||||
|
|
||||||
|
kunmap_atomic(kto, KM_USER1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ARMv4 optimised clear_user_page
|
* ARMv4 optimised clear_user_page
|
||||||
*/
|
*/
|
||||||
void __attribute__((naked))
|
void v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
|
|
||||||
{
|
{
|
||||||
asm volatile(
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
"str lr, [sp, #-4]!\n\
|
asm volatile("\
|
||||||
mov r1, %0 @ 1\n\
|
mov r1, %2 @ 1\n\
|
||||||
mov r2, #0 @ 1\n\
|
mov r2, #0 @ 1\n\
|
||||||
mov r3, #0 @ 1\n\
|
mov r3, #0 @ 1\n\
|
||||||
mov ip, #0 @ 1\n\
|
mov ip, #0 @ 1\n\
|
||||||
mov lr, #0 @ 1\n\
|
mov lr, #0 @ 1\n\
|
||||||
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
|
1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4\n\
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4\n\
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
|
mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4\n\
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4\n\
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
subs r1, r1, #1 @ 1\n\
|
subs r1, r1, #1 @ 1\n\
|
||||||
bne 1b @ 1\n\
|
bne 1b @ 1"
|
||||||
ldr pc, [sp], #4"
|
: "=r" (ptr)
|
||||||
:
|
: "0" (kaddr), "I" (PAGE_SIZE / 64)
|
||||||
: "I" (PAGE_SIZE / 64));
|
: "r1", "r2", "r3", "ip", "lr");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cpu_user_fns v4_mc_user_fns __initdata = {
|
struct cpu_user_fns v4_mc_user_fns __initdata = {
|
||||||
.cpu_clear_user_page = v4_mc_clear_user_page,
|
.cpu_clear_user_highpage = v4_mc_clear_user_highpage,
|
||||||
.cpu_copy_user_page = v4_mc_copy_user_page,
|
.cpu_copy_user_highpage = v4_mc_copy_user_highpage,
|
||||||
};
|
};
|
||||||
|
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/arch/arm/lib/copypage.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 1995-1999 Russell King
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* ASM optimised string functions
|
|
||||||
*/
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <asm/asm-offsets.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* ARMv4 optimised copy_user_page
|
|
||||||
*
|
|
||||||
* We flush the destination cache lines just before we write the data into the
|
|
||||||
* corresponding address. Since the Dcache is read-allocate, this removes the
|
|
||||||
* Dcache aliasing issue. The writes will be forwarded to the write buffer,
|
|
||||||
* and merged as appropriate.
|
|
||||||
*
|
|
||||||
* Note: We rely on all ARMv4 processors implementing the "invalidate D line"
|
|
||||||
* instruction. If your processor does not supply this, you have to write your
|
|
||||||
* own copy_user_page that does the right thing.
|
|
||||||
*/
|
|
||||||
ENTRY(v4wb_copy_user_page)
|
|
||||||
stmfd sp!, {r4, lr} @ 2
|
|
||||||
mov r2, #PAGE_SZ/64 @ 1
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4+1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
subs r2, r2, #1 @ 1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmneia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
bne 1b @ 1
|
|
||||||
mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB
|
|
||||||
ldmfd sp!, {r4, pc} @ 3
|
|
||||||
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* ARMv4 optimised clear_user_page
|
|
||||||
*
|
|
||||||
* Same story as above.
|
|
||||||
*/
|
|
||||||
ENTRY(v4wb_clear_user_page)
|
|
||||||
str lr, [sp, #-4]!
|
|
||||||
mov r1, #PAGE_SZ/64 @ 1
|
|
||||||
mov r2, #0 @ 1
|
|
||||||
mov r3, #0 @ 1
|
|
||||||
mov ip, #0 @ 1
|
|
||||||
mov lr, #0 @ 1
|
|
||||||
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
subs r1, r1, #1 @ 1
|
|
||||||
bne 1b @ 1
|
|
||||||
mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB
|
|
||||||
ldr pc, [sp], #4
|
|
||||||
|
|
||||||
__INITDATA
|
|
||||||
|
|
||||||
.type v4wb_user_fns, #object
|
|
||||||
ENTRY(v4wb_user_fns)
|
|
||||||
.long v4wb_clear_user_page
|
|
||||||
.long v4wb_copy_user_page
|
|
||||||
.size v4wb_user_fns, . - v4wb_user_fns
|
|
94
arch/arm/mm/copypage-v4wb.c
Normal file
94
arch/arm/mm/copypage-v4wb.c
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/arm/mm/copypage-v4wb.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995-1999 Russell King
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv4 optimised copy_user_highpage
|
||||||
|
*
|
||||||
|
* We flush the destination cache lines just before we write the data into the
|
||||||
|
* corresponding address. Since the Dcache is read-allocate, this removes the
|
||||||
|
* Dcache aliasing issue. The writes will be forwarded to the write buffer,
|
||||||
|
* and merged as appropriate.
|
||||||
|
*
|
||||||
|
* Note: We rely on all ARMv4 processors implementing the "invalidate D line"
|
||||||
|
* instruction. If your processor does not supply this, you have to write your
|
||||||
|
* own copy_user_highpage that does the right thing.
|
||||||
|
*/
|
||||||
|
static void __attribute__((naked))
|
||||||
|
v4wb_copy_user_page(void *kto, const void *kfrom)
|
||||||
|
{
|
||||||
|
asm("\
|
||||||
|
stmfd sp!, {r4, lr} @ 2\n\
|
||||||
|
mov r2, %0 @ 1\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
subs r2, r2, #1 @ 1\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmneia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
bne 1b @ 1\n\
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB\n\
|
||||||
|
ldmfd sp!, {r4, pc} @ 3"
|
||||||
|
:
|
||||||
|
: "I" (PAGE_SIZE / 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
void v4wb_copy_user_highpage(struct page *to, struct page *from,
|
||||||
|
unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *kto, *kfrom;
|
||||||
|
|
||||||
|
kto = kmap_atomic(to, KM_USER0);
|
||||||
|
kfrom = kmap_atomic(from, KM_USER1);
|
||||||
|
v4wb_copy_user_page(kto, kfrom);
|
||||||
|
kunmap_atomic(kfrom, KM_USER1);
|
||||||
|
kunmap_atomic(kto, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv4 optimised clear_user_page
|
||||||
|
*
|
||||||
|
* Same story as above.
|
||||||
|
*/
|
||||||
|
void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
|
asm volatile("\
|
||||||
|
mov r1, %2 @ 1\n\
|
||||||
|
mov r2, #0 @ 1\n\
|
||||||
|
mov r3, #0 @ 1\n\
|
||||||
|
mov ip, #0 @ 1\n\
|
||||||
|
mov lr, #0 @ 1\n\
|
||||||
|
1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
subs r1, r1, #1 @ 1\n\
|
||||||
|
bne 1b @ 1\n\
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB"
|
||||||
|
: "=r" (ptr)
|
||||||
|
: "0" (kaddr), "I" (PAGE_SIZE / 64)
|
||||||
|
: "r1", "r2", "r3", "ip", "lr");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_user_fns v4wb_user_fns __initdata = {
|
||||||
|
.cpu_clear_user_highpage = v4wb_clear_user_highpage,
|
||||||
|
.cpu_copy_user_highpage = v4wb_copy_user_highpage,
|
||||||
|
};
|
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/arch/arm/lib/copypage-v4.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 1995-1999 Russell King
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* ASM optimised string functions
|
|
||||||
*
|
|
||||||
* This is for CPUs with a writethrough cache and 'flush ID cache' is
|
|
||||||
* the only supported cache operation.
|
|
||||||
*/
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <asm/asm-offsets.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* ARMv4 optimised copy_user_page
|
|
||||||
*
|
|
||||||
* Since we have writethrough caches, we don't have to worry about
|
|
||||||
* dirty data in the cache. However, we do have to ensure that
|
|
||||||
* subsequent reads are up to date.
|
|
||||||
*/
|
|
||||||
ENTRY(v4wt_copy_user_page)
|
|
||||||
stmfd sp!, {r4, lr} @ 2
|
|
||||||
mov r2, #PAGE_SZ/64 @ 1
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
1: stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4+1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
subs r2, r2, #1 @ 1
|
|
||||||
stmia r0!, {r3, r4, ip, lr} @ 4
|
|
||||||
ldmneia r1!, {r3, r4, ip, lr} @ 4
|
|
||||||
bne 1b @ 1
|
|
||||||
mcr p15, 0, r2, c7, c7, 0 @ flush ID cache
|
|
||||||
ldmfd sp!, {r4, pc} @ 3
|
|
||||||
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* ARMv4 optimised clear_user_page
|
|
||||||
*
|
|
||||||
* Same story as above.
|
|
||||||
*/
|
|
||||||
ENTRY(v4wt_clear_user_page)
|
|
||||||
str lr, [sp, #-4]!
|
|
||||||
mov r1, #PAGE_SZ/64 @ 1
|
|
||||||
mov r2, #0 @ 1
|
|
||||||
mov r3, #0 @ 1
|
|
||||||
mov ip, #0 @ 1
|
|
||||||
mov lr, #0 @ 1
|
|
||||||
1: stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
stmia r0!, {r2, r3, ip, lr} @ 4
|
|
||||||
subs r1, r1, #1 @ 1
|
|
||||||
bne 1b @ 1
|
|
||||||
mcr p15, 0, r2, c7, c7, 0 @ flush ID cache
|
|
||||||
ldr pc, [sp], #4
|
|
||||||
|
|
||||||
__INITDATA
|
|
||||||
|
|
||||||
.type v4wt_user_fns, #object
|
|
||||||
ENTRY(v4wt_user_fns)
|
|
||||||
.long v4wt_clear_user_page
|
|
||||||
.long v4wt_copy_user_page
|
|
||||||
.size v4wt_user_fns, . - v4wt_user_fns
|
|
88
arch/arm/mm/copypage-v4wt.c
Normal file
88
arch/arm/mm/copypage-v4wt.c
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/arm/mm/copypage-v4wt.S
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995-1999 Russell King
|
||||||
|
*
|
||||||
|
* 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 is for CPUs with a writethrough cache and 'flush ID cache' is
|
||||||
|
* the only supported cache operation.
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv4 optimised copy_user_highpage
|
||||||
|
*
|
||||||
|
* Since we have writethrough caches, we don't have to worry about
|
||||||
|
* dirty data in the cache. However, we do have to ensure that
|
||||||
|
* subsequent reads are up to date.
|
||||||
|
*/
|
||||||
|
static void __attribute__((naked))
|
||||||
|
v4wt_copy_user_page(void *kto, const void *kfrom)
|
||||||
|
{
|
||||||
|
asm("\
|
||||||
|
stmfd sp!, {r4, lr} @ 2\n\
|
||||||
|
mov r2, %0 @ 1\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
1: stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
subs r2, r2, #1 @ 1\n\
|
||||||
|
stmia r0!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
ldmneia r1!, {r3, r4, ip, lr} @ 4\n\
|
||||||
|
bne 1b @ 1\n\
|
||||||
|
mcr p15, 0, r2, c7, c7, 0 @ flush ID cache\n\
|
||||||
|
ldmfd sp!, {r4, pc} @ 3"
|
||||||
|
:
|
||||||
|
: "I" (PAGE_SIZE / 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
void v4wt_copy_user_highpage(struct page *to, struct page *from,
|
||||||
|
unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *kto, *kfrom;
|
||||||
|
|
||||||
|
kto = kmap_atomic(to, KM_USER0);
|
||||||
|
kfrom = kmap_atomic(from, KM_USER1);
|
||||||
|
v4wt_copy_user_page(kto, kfrom);
|
||||||
|
kunmap_atomic(kfrom, KM_USER1);
|
||||||
|
kunmap_atomic(kto, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv4 optimised clear_user_page
|
||||||
|
*
|
||||||
|
* Same story as above.
|
||||||
|
*/
|
||||||
|
void v4wt_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
|
asm volatile("\
|
||||||
|
mov r1, %2 @ 1\n\
|
||||||
|
mov r2, #0 @ 1\n\
|
||||||
|
mov r3, #0 @ 1\n\
|
||||||
|
mov ip, #0 @ 1\n\
|
||||||
|
mov lr, #0 @ 1\n\
|
||||||
|
1: stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
stmia %0!, {r2, r3, ip, lr} @ 4\n\
|
||||||
|
subs r1, r1, #1 @ 1\n\
|
||||||
|
bne 1b @ 1\n\
|
||||||
|
mcr p15, 0, r2, c7, c7, 0 @ flush ID cache"
|
||||||
|
: "=r" (ptr)
|
||||||
|
: "0" (kaddr), "I" (PAGE_SIZE / 64)
|
||||||
|
: "r1", "r2", "r3", "ip", "lr");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_user_fns v4wt_user_fns __initdata = {
|
||||||
|
.cpu_clear_user_highpage = v4wt_clear_user_highpage,
|
||||||
|
.cpu_copy_user_highpage = v4wt_copy_user_highpage,
|
||||||
|
};
|
@@ -10,8 +10,8 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
#include <asm/page.h>
|
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/shmparam.h>
|
#include <asm/shmparam.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
@@ -33,41 +33,56 @@ static DEFINE_SPINLOCK(v6_lock);
|
|||||||
* Copy the user page. No aliasing to deal with so we can just
|
* Copy the user page. No aliasing to deal with so we can just
|
||||||
* attack the kernel's existing mapping of these pages.
|
* attack the kernel's existing mapping of these pages.
|
||||||
*/
|
*/
|
||||||
static void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr)
|
static void v6_copy_user_highpage_nonaliasing(struct page *to,
|
||||||
|
struct page *from, unsigned long vaddr)
|
||||||
{
|
{
|
||||||
|
void *kto, *kfrom;
|
||||||
|
|
||||||
|
kfrom = kmap_atomic(from, KM_USER0);
|
||||||
|
kto = kmap_atomic(to, KM_USER1);
|
||||||
copy_page(kto, kfrom);
|
copy_page(kto, kfrom);
|
||||||
|
kunmap_atomic(kto, KM_USER1);
|
||||||
|
kunmap_atomic(kfrom, KM_USER0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the user page. No aliasing to deal with so we can just
|
* Clear the user page. No aliasing to deal with so we can just
|
||||||
* attack the kernel's existing mapping of this page.
|
* attack the kernel's existing mapping of this page.
|
||||||
*/
|
*/
|
||||||
static void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr)
|
static void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr)
|
||||||
{
|
{
|
||||||
|
void *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
clear_page(kaddr);
|
clear_page(kaddr);
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy the page, taking account of the cache colour.
|
* Discard data in the kernel mapping for the new page.
|
||||||
|
* FIXME: needs this MCRR to be supported.
|
||||||
*/
|
*/
|
||||||
static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr)
|
static void discard_old_kernel_data(void *kto)
|
||||||
{
|
{
|
||||||
unsigned int offset = CACHE_COLOUR(vaddr);
|
|
||||||
unsigned long from, to;
|
|
||||||
struct page *page = virt_to_page(kfrom);
|
|
||||||
|
|
||||||
if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
|
|
||||||
__flush_dcache_page(page_mapping(page), page);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Discard data in the kernel mapping for the new page.
|
|
||||||
* FIXME: needs this MCRR to be supported.
|
|
||||||
*/
|
|
||||||
__asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06"
|
__asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06"
|
||||||
:
|
:
|
||||||
: "r" (kto),
|
: "r" (kto),
|
||||||
"r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
|
"r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
|
||||||
: "cc");
|
: "cc");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the page, taking account of the cache colour.
|
||||||
|
*/
|
||||||
|
static void v6_copy_user_highpage_aliasing(struct page *to,
|
||||||
|
struct page *from, unsigned long vaddr)
|
||||||
|
{
|
||||||
|
unsigned int offset = CACHE_COLOUR(vaddr);
|
||||||
|
unsigned long kfrom, kto;
|
||||||
|
|
||||||
|
if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
|
||||||
|
__flush_dcache_page(page_mapping(from), from);
|
||||||
|
|
||||||
|
/* FIXME: not highmem safe */
|
||||||
|
discard_old_kernel_data(page_address(to));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now copy the page using the same cache colour as the
|
* Now copy the page using the same cache colour as the
|
||||||
@@ -75,16 +90,16 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
|
|||||||
*/
|
*/
|
||||||
spin_lock(&v6_lock);
|
spin_lock(&v6_lock);
|
||||||
|
|
||||||
set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL), 0);
|
set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(page_to_pfn(from), PAGE_KERNEL), 0);
|
||||||
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL), 0);
|
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(to), PAGE_KERNEL), 0);
|
||||||
|
|
||||||
from = from_address + (offset << PAGE_SHIFT);
|
kfrom = from_address + (offset << PAGE_SHIFT);
|
||||||
to = to_address + (offset << PAGE_SHIFT);
|
kto = to_address + (offset << PAGE_SHIFT);
|
||||||
|
|
||||||
flush_tlb_kernel_page(from);
|
flush_tlb_kernel_page(kfrom);
|
||||||
flush_tlb_kernel_page(to);
|
flush_tlb_kernel_page(kto);
|
||||||
|
|
||||||
copy_page((void *)to, (void *)from);
|
copy_page((void *)kto, (void *)kfrom);
|
||||||
|
|
||||||
spin_unlock(&v6_lock);
|
spin_unlock(&v6_lock);
|
||||||
}
|
}
|
||||||
@@ -94,20 +109,13 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
|
|||||||
* so remap the kernel page into the same cache colour as the user
|
* so remap the kernel page into the same cache colour as the user
|
||||||
* page.
|
* page.
|
||||||
*/
|
*/
|
||||||
static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
|
static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr)
|
||||||
{
|
{
|
||||||
unsigned int offset = CACHE_COLOUR(vaddr);
|
unsigned int offset = CACHE_COLOUR(vaddr);
|
||||||
unsigned long to = to_address + (offset << PAGE_SHIFT);
|
unsigned long to = to_address + (offset << PAGE_SHIFT);
|
||||||
|
|
||||||
/*
|
/* FIXME: not highmem safe */
|
||||||
* Discard data in the kernel mapping for the new page
|
discard_old_kernel_data(page_address(page));
|
||||||
* FIXME: needs this MCRR to be supported.
|
|
||||||
*/
|
|
||||||
__asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06"
|
|
||||||
:
|
|
||||||
: "r" (kaddr),
|
|
||||||
"r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES)
|
|
||||||
: "cc");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now clear the page using the same cache colour as
|
* Now clear the page using the same cache colour as
|
||||||
@@ -115,7 +123,7 @@ static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
|
|||||||
*/
|
*/
|
||||||
spin_lock(&v6_lock);
|
spin_lock(&v6_lock);
|
||||||
|
|
||||||
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL), 0);
|
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(page), PAGE_KERNEL), 0);
|
||||||
flush_tlb_kernel_page(to);
|
flush_tlb_kernel_page(to);
|
||||||
clear_page((void *)to);
|
clear_page((void *)to);
|
||||||
|
|
||||||
@@ -123,15 +131,15 @@ static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct cpu_user_fns v6_user_fns __initdata = {
|
struct cpu_user_fns v6_user_fns __initdata = {
|
||||||
.cpu_clear_user_page = v6_clear_user_page_nonaliasing,
|
.cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing,
|
||||||
.cpu_copy_user_page = v6_copy_user_page_nonaliasing,
|
.cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init v6_userpage_init(void)
|
static int __init v6_userpage_init(void)
|
||||||
{
|
{
|
||||||
if (cache_is_vipt_aliasing()) {
|
if (cache_is_vipt_aliasing()) {
|
||||||
cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
|
cpu_user.cpu_clear_user_highpage = v6_clear_user_highpage_aliasing;
|
||||||
cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
|
cpu_user.cpu_copy_user_highpage = v6_copy_user_highpage_aliasing;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/arch/arm/lib/copypage-xsc3.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 2004 Intel Corp.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Adapted for 3rd gen XScale core, no more mini-dcache
|
|
||||||
* Author: Matt Gilbert (matthew.m.gilbert@intel.com)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <asm/asm-offsets.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* General note:
|
|
||||||
* We don't really want write-allocate cache behaviour for these functions
|
|
||||||
* since that will just eat through 8K of the cache.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* XSC3 optimised copy_user_page
|
|
||||||
* r0 = destination
|
|
||||||
* r1 = source
|
|
||||||
* r2 = virtual user address of ultimate destination page
|
|
||||||
*
|
|
||||||
* The source page may have some clean entries in the cache already, but we
|
|
||||||
* can safely ignore them - break_cow() will flush them out of the cache
|
|
||||||
* if we eventually end up using our copied page.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
ENTRY(xsc3_mc_copy_user_page)
|
|
||||||
stmfd sp!, {r4, r5, lr}
|
|
||||||
mov lr, #PAGE_SZ/64-1
|
|
||||||
|
|
||||||
pld [r1, #0]
|
|
||||||
pld [r1, #32]
|
|
||||||
1: pld [r1, #64]
|
|
||||||
pld [r1, #96]
|
|
||||||
|
|
||||||
2: ldrd r2, [r1], #8
|
|
||||||
mov ip, r0
|
|
||||||
ldrd r4, [r1], #8
|
|
||||||
mcr p15, 0, ip, c7, c6, 1 @ invalidate
|
|
||||||
strd r2, [r0], #8
|
|
||||||
ldrd r2, [r1], #8
|
|
||||||
strd r4, [r0], #8
|
|
||||||
ldrd r4, [r1], #8
|
|
||||||
strd r2, [r0], #8
|
|
||||||
strd r4, [r0], #8
|
|
||||||
ldrd r2, [r1], #8
|
|
||||||
mov ip, r0
|
|
||||||
ldrd r4, [r1], #8
|
|
||||||
mcr p15, 0, ip, c7, c6, 1 @ invalidate
|
|
||||||
strd r2, [r0], #8
|
|
||||||
ldrd r2, [r1], #8
|
|
||||||
subs lr, lr, #1
|
|
||||||
strd r4, [r0], #8
|
|
||||||
ldrd r4, [r1], #8
|
|
||||||
strd r2, [r0], #8
|
|
||||||
strd r4, [r0], #8
|
|
||||||
bgt 1b
|
|
||||||
beq 2b
|
|
||||||
|
|
||||||
ldmfd sp!, {r4, r5, pc}
|
|
||||||
|
|
||||||
.align 5
|
|
||||||
/*
|
|
||||||
* XScale optimised clear_user_page
|
|
||||||
* r0 = destination
|
|
||||||
* r1 = virtual user address of ultimate destination page
|
|
||||||
*/
|
|
||||||
ENTRY(xsc3_mc_clear_user_page)
|
|
||||||
mov r1, #PAGE_SZ/32
|
|
||||||
mov r2, #0
|
|
||||||
mov r3, #0
|
|
||||||
1: mcr p15, 0, r0, c7, c6, 1 @ invalidate line
|
|
||||||
strd r2, [r0], #8
|
|
||||||
strd r2, [r0], #8
|
|
||||||
strd r2, [r0], #8
|
|
||||||
strd r2, [r0], #8
|
|
||||||
subs r1, r1, #1
|
|
||||||
bne 1b
|
|
||||||
mov pc, lr
|
|
||||||
|
|
||||||
__INITDATA
|
|
||||||
|
|
||||||
.type xsc3_mc_user_fns, #object
|
|
||||||
ENTRY(xsc3_mc_user_fns)
|
|
||||||
.long xsc3_mc_clear_user_page
|
|
||||||
.long xsc3_mc_copy_user_page
|
|
||||||
.size xsc3_mc_user_fns, . - xsc3_mc_user_fns
|
|
113
arch/arm/mm/copypage-xsc3.c
Normal file
113
arch/arm/mm/copypage-xsc3.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/arm/mm/copypage-xsc3.S
|
||||||
|
*
|
||||||
|
* Copyright (C) 2004 Intel Corp.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Adapted for 3rd gen XScale core, no more mini-dcache
|
||||||
|
* Author: Matt Gilbert (matthew.m.gilbert@intel.com)
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* General note:
|
||||||
|
* We don't really want write-allocate cache behaviour for these functions
|
||||||
|
* since that will just eat through 8K of the cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XSC3 optimised copy_user_highpage
|
||||||
|
* r0 = destination
|
||||||
|
* r1 = source
|
||||||
|
*
|
||||||
|
* The source page may have some clean entries in the cache already, but we
|
||||||
|
* can safely ignore them - break_cow() will flush them out of the cache
|
||||||
|
* if we eventually end up using our copied page.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void __attribute__((naked))
|
||||||
|
xsc3_mc_copy_user_page(void *kto, const void *kfrom)
|
||||||
|
{
|
||||||
|
asm("\
|
||||||
|
stmfd sp!, {r4, r5, lr} \n\
|
||||||
|
mov lr, %0 \n\
|
||||||
|
\n\
|
||||||
|
pld [r1, #0] \n\
|
||||||
|
pld [r1, #32] \n\
|
||||||
|
1: pld [r1, #64] \n\
|
||||||
|
pld [r1, #96] \n\
|
||||||
|
\n\
|
||||||
|
2: ldrd r2, [r1], #8 \n\
|
||||||
|
mov ip, r0 \n\
|
||||||
|
ldrd r4, [r1], #8 \n\
|
||||||
|
mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\
|
||||||
|
strd r2, [r0], #8 \n\
|
||||||
|
ldrd r2, [r1], #8 \n\
|
||||||
|
strd r4, [r0], #8 \n\
|
||||||
|
ldrd r4, [r1], #8 \n\
|
||||||
|
strd r2, [r0], #8 \n\
|
||||||
|
strd r4, [r0], #8 \n\
|
||||||
|
ldrd r2, [r1], #8 \n\
|
||||||
|
mov ip, r0 \n\
|
||||||
|
ldrd r4, [r1], #8 \n\
|
||||||
|
mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\
|
||||||
|
strd r2, [r0], #8 \n\
|
||||||
|
ldrd r2, [r1], #8 \n\
|
||||||
|
subs lr, lr, #1 \n\
|
||||||
|
strd r4, [r0], #8 \n\
|
||||||
|
ldrd r4, [r1], #8 \n\
|
||||||
|
strd r2, [r0], #8 \n\
|
||||||
|
strd r4, [r0], #8 \n\
|
||||||
|
bgt 1b \n\
|
||||||
|
beq 2b \n\
|
||||||
|
\n\
|
||||||
|
ldmfd sp!, {r4, r5, pc}"
|
||||||
|
:
|
||||||
|
: "I" (PAGE_SIZE / 64 - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xsc3_mc_copy_user_highpage(struct page *to, struct page *from,
|
||||||
|
unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *kto, *kfrom;
|
||||||
|
|
||||||
|
kto = kmap_atomic(to, KM_USER0);
|
||||||
|
kfrom = kmap_atomic(from, KM_USER1);
|
||||||
|
xsc3_mc_copy_user_page(kto, kfrom);
|
||||||
|
kunmap_atomic(kfrom, KM_USER1);
|
||||||
|
kunmap_atomic(kto, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XScale optimised clear_user_page
|
||||||
|
* r0 = destination
|
||||||
|
* r1 = virtual user address of ultimate destination page
|
||||||
|
*/
|
||||||
|
void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
|
{
|
||||||
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
|
asm volatile ("\
|
||||||
|
mov r1, %2 \n\
|
||||||
|
mov r2, #0 \n\
|
||||||
|
mov r3, #0 \n\
|
||||||
|
1: mcr p15, 0, %0, c7, c6, 1 @ invalidate line\n\
|
||||||
|
strd r2, [%0], #8 \n\
|
||||||
|
strd r2, [%0], #8 \n\
|
||||||
|
strd r2, [%0], #8 \n\
|
||||||
|
strd r2, [%0], #8 \n\
|
||||||
|
subs r1, r1, #1 \n\
|
||||||
|
bne 1b"
|
||||||
|
: "=r" (ptr)
|
||||||
|
: "0" (kaddr), "I" (PAGE_SIZE / 32)
|
||||||
|
: "r1", "r2", "r3");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_user_fns xsc3_mc_user_fns __initdata = {
|
||||||
|
.cpu_clear_user_highpage = xsc3_mc_clear_user_highpage,
|
||||||
|
.cpu_copy_user_highpage = xsc3_mc_copy_user_highpage,
|
||||||
|
};
|
@@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
#include <asm/page.h>
|
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
static DEFINE_SPINLOCK(minicache_lock);
|
static DEFINE_SPINLOCK(minicache_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XScale mini-dcache optimised copy_user_page
|
* XScale mini-dcache optimised copy_user_highpage
|
||||||
*
|
*
|
||||||
* We flush the destination cache lines just before we write the data into the
|
* We flush the destination cache lines just before we write the data into the
|
||||||
* corresponding address. Since the Dcache is read-allocate, this removes the
|
* corresponding address. Since the Dcache is read-allocate, this removes the
|
||||||
@@ -90,48 +90,53 @@ mc_copy_user_page(void *from, void *to)
|
|||||||
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1));
|
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void xscale_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
|
void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
|
||||||
|
unsigned long vaddr)
|
||||||
{
|
{
|
||||||
struct page *page = virt_to_page(kfrom);
|
void *kto = kmap_atomic(to, KM_USER1);
|
||||||
|
|
||||||
if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
|
if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
|
||||||
__flush_dcache_page(page_mapping(page), page);
|
__flush_dcache_page(page_mapping(from), from);
|
||||||
|
|
||||||
spin_lock(&minicache_lock);
|
spin_lock(&minicache_lock);
|
||||||
|
|
||||||
set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
|
set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
|
||||||
flush_tlb_kernel_page(COPYPAGE_MINICACHE);
|
flush_tlb_kernel_page(COPYPAGE_MINICACHE);
|
||||||
|
|
||||||
mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
|
mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
|
||||||
|
|
||||||
spin_unlock(&minicache_lock);
|
spin_unlock(&minicache_lock);
|
||||||
|
|
||||||
|
kunmap_atomic(kto, KM_USER1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XScale optimised clear_user_page
|
* XScale optimised clear_user_page
|
||||||
*/
|
*/
|
||||||
void __attribute__((naked))
|
void
|
||||||
xscale_mc_clear_user_page(void *kaddr, unsigned long vaddr)
|
xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
{
|
{
|
||||||
|
void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"mov r1, %0 \n\
|
"mov r1, %2 \n\
|
||||||
mov r2, #0 \n\
|
mov r2, #0 \n\
|
||||||
mov r3, #0 \n\
|
mov r3, #0 \n\
|
||||||
1: mov ip, r0 \n\
|
1: mov ip, %0 \n\
|
||||||
strd r2, [r0], #8 \n\
|
strd r2, [%0], #8 \n\
|
||||||
strd r2, [r0], #8 \n\
|
strd r2, [%0], #8 \n\
|
||||||
strd r2, [r0], #8 \n\
|
strd r2, [%0], #8 \n\
|
||||||
strd r2, [r0], #8 \n\
|
strd r2, [%0], #8 \n\
|
||||||
mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
|
mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
|
||||||
subs r1, r1, #1 \n\
|
subs r1, r1, #1 \n\
|
||||||
mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
|
mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
|
||||||
bne 1b \n\
|
bne 1b"
|
||||||
mov pc, lr"
|
: "=r" (ptr)
|
||||||
:
|
: "0" (kaddr), "I" (PAGE_SIZE / 32)
|
||||||
: "I" (PAGE_SIZE / 32));
|
: "r1", "r2", "r3", "ip");
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cpu_user_fns xscale_mc_user_fns __initdata = {
|
struct cpu_user_fns xscale_mc_user_fns __initdata = {
|
||||||
.cpu_clear_user_page = xscale_mc_clear_user_page,
|
.cpu_clear_user_highpage = xscale_mc_clear_user_highpage,
|
||||||
.cpu_copy_user_page = xscale_mc_copy_user_page,
|
.cpu_copy_user_highpage = xscale_mc_copy_user_highpage,
|
||||||
};
|
};
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/page-flags.h>
|
||||||
|
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
@@ -83,13 +84,14 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_HIGHMEM
|
|
||||||
/* We must not map this if we have highmem enabled */
|
/* We must not map this if we have highmem enabled */
|
||||||
|
if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
|
||||||
|
break;
|
||||||
|
|
||||||
pte = pte_offset_map(pmd, addr);
|
pte = pte_offset_map(pmd, addr);
|
||||||
printk(", *pte=%08lx", pte_val(*pte));
|
printk(", *pte=%08lx", pte_val(*pte));
|
||||||
printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
|
printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
|
||||||
pte_unmap(pte);
|
pte_unmap(pte);
|
||||||
#endif
|
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
printk("\n");
|
printk("\n");
|
||||||
|
@@ -64,10 +64,11 @@ static int __init parse_tag_initrd2(const struct tag *tag)
|
|||||||
__tagtable(ATAG_INITRD2, parse_tag_initrd2);
|
__tagtable(ATAG_INITRD2, parse_tag_initrd2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used to pass memory configuration data from paging_init
|
* This keeps memory configuration data used by a couple memory
|
||||||
* to mem_init, and by show_mem() to skip holes in the memory map.
|
* initialization functions, as well as show_mem() for the skipping
|
||||||
|
* of holes in the memory map. It is populated by arm_add_memory().
|
||||||
*/
|
*/
|
||||||
static struct meminfo meminfo = { 0, };
|
struct meminfo meminfo;
|
||||||
|
|
||||||
void show_mem(void)
|
void show_mem(void)
|
||||||
{
|
{
|
||||||
@@ -331,13 +332,12 @@ static void __init bootmem_free_node(int node, struct meminfo *mi)
|
|||||||
free_area_init_node(node, zone_size, start_pfn, zhole_size);
|
free_area_init_node(node, zone_size, start_pfn, zhole_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init bootmem_init(struct meminfo *mi)
|
void __init bootmem_init(void)
|
||||||
{
|
{
|
||||||
|
struct meminfo *mi = &meminfo;
|
||||||
unsigned long memend_pfn = 0;
|
unsigned long memend_pfn = 0;
|
||||||
int node, initrd_node;
|
int node, initrd_node;
|
||||||
|
|
||||||
memcpy(&meminfo, mi, sizeof(meminfo));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locate which node contains the ramdisk image, if any.
|
* Locate which node contains the ramdisk image, if any.
|
||||||
*/
|
*/
|
||||||
@@ -394,20 +394,22 @@ void __init bootmem_init(struct meminfo *mi)
|
|||||||
max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET;
|
max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void free_area(unsigned long addr, unsigned long end, char *s)
|
static inline int free_area(unsigned long pfn, unsigned long end, char *s)
|
||||||
{
|
{
|
||||||
unsigned int size = (end - addr) >> 10;
|
unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
|
||||||
|
|
||||||
for (; addr < end; addr += PAGE_SIZE) {
|
for (; pfn < end; pfn++) {
|
||||||
struct page *page = virt_to_page(addr);
|
struct page *page = pfn_to_page(pfn);
|
||||||
ClearPageReserved(page);
|
ClearPageReserved(page);
|
||||||
init_page_count(page);
|
init_page_count(page);
|
||||||
free_page(addr);
|
__free_page(page);
|
||||||
totalram_pages++;
|
pages++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size && s)
|
if (size && s)
|
||||||
printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
|
printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
|
||||||
|
|
||||||
|
return pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -478,13 +480,9 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)
|
|||||||
*/
|
*/
|
||||||
void __init mem_init(void)
|
void __init mem_init(void)
|
||||||
{
|
{
|
||||||
unsigned int codepages, datapages, initpages;
|
unsigned int codesize, datasize, initsize;
|
||||||
int i, node;
|
int i, node;
|
||||||
|
|
||||||
codepages = &_etext - &_text;
|
|
||||||
datapages = &_end - &__data_start;
|
|
||||||
initpages = &__init_end - &__init_begin;
|
|
||||||
|
|
||||||
#ifndef CONFIG_DISCONTIGMEM
|
#ifndef CONFIG_DISCONTIGMEM
|
||||||
max_mapnr = virt_to_page(high_memory) - mem_map;
|
max_mapnr = virt_to_page(high_memory) - mem_map;
|
||||||
#endif
|
#endif
|
||||||
@@ -501,7 +499,8 @@ void __init mem_init(void)
|
|||||||
|
|
||||||
#ifdef CONFIG_SA1111
|
#ifdef CONFIG_SA1111
|
||||||
/* now that our DMA memory is actually so designated, we can free it */
|
/* now that our DMA memory is actually so designated, we can free it */
|
||||||
free_area(PAGE_OFFSET, (unsigned long)swapper_pg_dir, NULL);
|
totalram_pages += free_area(PHYS_PFN_OFFSET,
|
||||||
|
__phys_to_pfn(__pa(swapper_pg_dir)), NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -509,18 +508,21 @@ void __init mem_init(void)
|
|||||||
* real number of pages we have in this system
|
* real number of pages we have in this system
|
||||||
*/
|
*/
|
||||||
printk(KERN_INFO "Memory:");
|
printk(KERN_INFO "Memory:");
|
||||||
|
|
||||||
num_physpages = 0;
|
num_physpages = 0;
|
||||||
for (i = 0; i < meminfo.nr_banks; i++) {
|
for (i = 0; i < meminfo.nr_banks; i++) {
|
||||||
num_physpages += bank_pfn_size(&meminfo.bank[i]);
|
num_physpages += bank_pfn_size(&meminfo.bank[i]);
|
||||||
printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20);
|
printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
|
printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
|
||||||
|
|
||||||
|
codesize = &_etext - &_text;
|
||||||
|
datasize = &_end - &__data_start;
|
||||||
|
initsize = &__init_end - &__init_begin;
|
||||||
|
|
||||||
printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
|
printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
|
||||||
"%dK data, %dK init)\n",
|
"%dK data, %dK init)\n",
|
||||||
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
|
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
|
||||||
codepages >> 10, datapages >> 10, initpages >> 10);
|
codesize >> 10, datasize >> 10, initsize >> 10);
|
||||||
|
|
||||||
if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
|
if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
|
||||||
extern int sysctl_overcommit_memory;
|
extern int sysctl_overcommit_memory;
|
||||||
@@ -535,11 +537,10 @@ void __init mem_init(void)
|
|||||||
|
|
||||||
void free_initmem(void)
|
void free_initmem(void)
|
||||||
{
|
{
|
||||||
if (!machine_is_integrator() && !machine_is_cintegrator()) {
|
if (!machine_is_integrator() && !machine_is_cintegrator())
|
||||||
free_area((unsigned long)(&__init_begin),
|
totalram_pages += free_area(__phys_to_pfn(__pa(&__init_begin)),
|
||||||
(unsigned long)(&__init_end),
|
__phys_to_pfn(__pa(&__init_end)),
|
||||||
"init");
|
"init");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INITRD
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||||||
@@ -549,7 +550,9 @@ static int keep_initrd;
|
|||||||
void free_initrd_mem(unsigned long start, unsigned long end)
|
void free_initrd_mem(unsigned long start, unsigned long end)
|
||||||
{
|
{
|
||||||
if (!keep_initrd)
|
if (!keep_initrd)
|
||||||
free_area(start, end, "initrd");
|
totalram_pages += free_area(__phys_to_pfn(__pa(start)),
|
||||||
|
__phys_to_pfn(__pa(end)),
|
||||||
|
"initrd");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init keepinitrd_setup(char *__unused)
|
static int __init keepinitrd_setup(char *__unused)
|
||||||
|
@@ -32,7 +32,7 @@ struct meminfo;
|
|||||||
struct pglist_data;
|
struct pglist_data;
|
||||||
|
|
||||||
void __init create_mapping(struct map_desc *md);
|
void __init create_mapping(struct map_desc *md);
|
||||||
void __init bootmem_init(struct meminfo *mi);
|
void __init bootmem_init(void);
|
||||||
void reserve_node_zero(struct pglist_data *pgdat);
|
void reserve_node_zero(struct pglist_data *pgdat);
|
||||||
|
|
||||||
extern void _text, _stext, _etext, __data_start, _end, __init_begin, __init_end;
|
extern void _text, _stext, _etext, __data_start, _end, __init_begin, __init_end;
|
||||||
|
@@ -646,61 +646,79 @@ static void __init early_vmalloc(char **arg)
|
|||||||
"vmalloc area too small, limiting to %luMB\n",
|
"vmalloc area too small, limiting to %luMB\n",
|
||||||
vmalloc_reserve >> 20);
|
vmalloc_reserve >> 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {
|
||||||
|
vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"vmalloc area is too big, limiting to %luMB\n",
|
||||||
|
vmalloc_reserve >> 20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
__early_param("vmalloc=", early_vmalloc);
|
__early_param("vmalloc=", early_vmalloc);
|
||||||
|
|
||||||
#define VMALLOC_MIN (void *)(VMALLOC_END - vmalloc_reserve)
|
#define VMALLOC_MIN (void *)(VMALLOC_END - vmalloc_reserve)
|
||||||
|
|
||||||
static int __init check_membank_valid(struct membank *mb)
|
static void __init sanity_check_meminfo(void)
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Check whether this memory region has non-zero size or
|
|
||||||
* invalid node number.
|
|
||||||
*/
|
|
||||||
if (mb->size == 0 || mb->node >= MAX_NUMNODES)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether this memory region would entirely overlap
|
|
||||||
* the vmalloc area.
|
|
||||||
*/
|
|
||||||
if (phys_to_virt(mb->start) >= VMALLOC_MIN) {
|
|
||||||
printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
|
|
||||||
"(vmalloc region overlap).\n",
|
|
||||||
mb->start, mb->start + mb->size - 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether this memory region would partially overlap
|
|
||||||
* the vmalloc area.
|
|
||||||
*/
|
|
||||||
if (phys_to_virt(mb->start + mb->size) < phys_to_virt(mb->start) ||
|
|
||||||
phys_to_virt(mb->start + mb->size) > VMALLOC_MIN) {
|
|
||||||
unsigned long newsize = VMALLOC_MIN - phys_to_virt(mb->start);
|
|
||||||
|
|
||||||
printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx "
|
|
||||||
"to -%.8lx (vmalloc region overlap).\n",
|
|
||||||
mb->start, mb->start + mb->size - 1,
|
|
||||||
mb->start + newsize - 1);
|
|
||||||
mb->size = newsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init sanity_check_meminfo(struct meminfo *mi)
|
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0, j = 0; i < mi->nr_banks; i++) {
|
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
|
||||||
if (check_membank_valid(&mi->bank[i]))
|
struct membank *bank = &meminfo.bank[j];
|
||||||
mi->bank[j++] = mi->bank[i];
|
*bank = meminfo.bank[i];
|
||||||
|
|
||||||
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
/*
|
||||||
|
* Split those memory banks which are partially overlapping
|
||||||
|
* the vmalloc area greatly simplifying things later.
|
||||||
|
*/
|
||||||
|
if (__va(bank->start) < VMALLOC_MIN &&
|
||||||
|
bank->size > VMALLOC_MIN - __va(bank->start)) {
|
||||||
|
if (meminfo.nr_banks >= NR_BANKS) {
|
||||||
|
printk(KERN_CRIT "NR_BANKS too low, "
|
||||||
|
"ignoring high memory\n");
|
||||||
|
} else {
|
||||||
|
memmove(bank + 1, bank,
|
||||||
|
(meminfo.nr_banks - i) * sizeof(*bank));
|
||||||
|
meminfo.nr_banks++;
|
||||||
|
i++;
|
||||||
|
bank[1].size -= VMALLOC_MIN - __va(bank->start);
|
||||||
|
bank[1].start = __pa(VMALLOC_MIN - 1) + 1;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
bank->size = VMALLOC_MIN - __va(bank->start);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* Check whether this memory bank would entirely overlap
|
||||||
|
* the vmalloc area.
|
||||||
|
*/
|
||||||
|
if (__va(bank->start) >= VMALLOC_MIN) {
|
||||||
|
printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
|
||||||
|
"(vmalloc region overlap).\n",
|
||||||
|
bank->start, bank->start + bank->size - 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether this memory bank would partially overlap
|
||||||
|
* the vmalloc area.
|
||||||
|
*/
|
||||||
|
if (__va(bank->start + bank->size) > VMALLOC_MIN ||
|
||||||
|
__va(bank->start + bank->size) < __va(bank->start)) {
|
||||||
|
unsigned long newsize = VMALLOC_MIN - __va(bank->start);
|
||||||
|
printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx "
|
||||||
|
"to -%.8lx (vmalloc region overlap).\n",
|
||||||
|
bank->start, bank->start + bank->size - 1,
|
||||||
|
bank->start + newsize - 1);
|
||||||
|
bank->size = newsize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
mi->nr_banks = j;
|
meminfo.nr_banks = j;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void prepare_page_table(struct meminfo *mi)
|
static inline void prepare_page_table(void)
|
||||||
{
|
{
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
|
||||||
@@ -721,7 +739,7 @@ static inline void prepare_page_table(struct meminfo *mi)
|
|||||||
* Clear out all the kernel space mappings, except for the first
|
* Clear out all the kernel space mappings, except for the first
|
||||||
* memory bank, up to the end of the vmalloc region.
|
* memory bank, up to the end of the vmalloc region.
|
||||||
*/
|
*/
|
||||||
for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
|
for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0]));
|
||||||
addr < VMALLOC_END; addr += PGDIR_SIZE)
|
addr < VMALLOC_END; addr += PGDIR_SIZE)
|
||||||
pmd_clear(pmd_off_k(addr));
|
pmd_clear(pmd_off_k(addr));
|
||||||
}
|
}
|
||||||
@@ -880,14 +898,14 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
|
|||||||
* paging_init() sets up the page tables, initialises the zone memory
|
* paging_init() sets up the page tables, initialises the zone memory
|
||||||
* maps, and sets up the zero page, bad page and bad page tables.
|
* maps, and sets up the zero page, bad page and bad page tables.
|
||||||
*/
|
*/
|
||||||
void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
|
void __init paging_init(struct machine_desc *mdesc)
|
||||||
{
|
{
|
||||||
void *zero_page;
|
void *zero_page;
|
||||||
|
|
||||||
build_mem_type_table();
|
build_mem_type_table();
|
||||||
sanity_check_meminfo(mi);
|
sanity_check_meminfo();
|
||||||
prepare_page_table(mi);
|
prepare_page_table();
|
||||||
bootmem_init(mi);
|
bootmem_init();
|
||||||
devicemaps_init(mdesc);
|
devicemaps_init(mdesc);
|
||||||
|
|
||||||
top_pmd = pmd_off_k(0xffff0000);
|
top_pmd = pmd_off_k(0xffff0000);
|
||||||
|
@@ -41,27 +41,13 @@ void __init reserve_node_zero(pg_data_t *pgdat)
|
|||||||
BOOTMEM_DEFAULT);
|
BOOTMEM_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init sanity_check_meminfo(struct meminfo *mi)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0, j = 0; i < mi->nr_banks; i++) {
|
|
||||||
struct membank *mb = &mi->bank[i];
|
|
||||||
|
|
||||||
if (mb->size != 0 && mb->node < MAX_NUMNODES)
|
|
||||||
mi->bank[j++] = mi->bank[i];
|
|
||||||
}
|
|
||||||
mi->nr_banks = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* paging_init() sets up the page tables, initialises the zone memory
|
* paging_init() sets up the page tables, initialises the zone memory
|
||||||
* maps, and sets up the zero page, bad page and bad page tables.
|
* maps, and sets up the zero page, bad page and bad page tables.
|
||||||
*/
|
*/
|
||||||
void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
|
void __init paging_init(struct machine_desc *mdesc)
|
||||||
{
|
{
|
||||||
sanity_check_meminfo(mi);
|
bootmem_init();
|
||||||
bootmem_init(mi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -33,8 +33,8 @@ EXPORT_SYMBOL(cpu_cache);
|
|||||||
|
|
||||||
#ifdef CONFIG_MMU
|
#ifdef CONFIG_MMU
|
||||||
#ifndef MULTI_USER
|
#ifndef MULTI_USER
|
||||||
EXPORT_SYMBOL(__cpu_clear_user_page);
|
EXPORT_SYMBOL(__cpu_clear_user_highpage);
|
||||||
EXPORT_SYMBOL(__cpu_copy_user_page);
|
EXPORT_SYMBOL(__cpu_copy_user_highpage);
|
||||||
#else
|
#else
|
||||||
EXPORT_SYMBOL(cpu_user);
|
EXPORT_SYMBOL(cpu_user);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -13,17 +13,4 @@
|
|||||||
|
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Virtual view <-> DMA view memory address translations
|
|
||||||
* This macro is used to translate the virtual address to an address
|
|
||||||
* suitable to be passed to set_dma_addr()
|
|
||||||
*/
|
|
||||||
#define __virt_to_bus(a) __virt_to_phys(a)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used to convert an address for DMA operations to an address that the
|
|
||||||
* kernel can use.
|
|
||||||
*/
|
|
||||||
#define __bus_to_virt(a) __phys_to_virt(a)
|
|
||||||
|
|
||||||
#endif /* __ASM_ARCH_MXC_MEMORY_H__ */
|
#endif /* __ASM_ARCH_MXC_MEMORY_H__ */
|
||||||
|
@@ -101,6 +101,7 @@
|
|||||||
#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
|
#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
|
||||||
#define OMAP24XX_GPIO_IRQENABLE2 0x002c
|
#define OMAP24XX_GPIO_IRQENABLE2 0x002c
|
||||||
#define OMAP24XX_GPIO_IRQENABLE1 0x001c
|
#define OMAP24XX_GPIO_IRQENABLE1 0x001c
|
||||||
|
#define OMAP24XX_GPIO_WAKE_EN 0x0020
|
||||||
#define OMAP24XX_GPIO_CTRL 0x0030
|
#define OMAP24XX_GPIO_CTRL 0x0030
|
||||||
#define OMAP24XX_GPIO_OE 0x0034
|
#define OMAP24XX_GPIO_OE 0x0034
|
||||||
#define OMAP24XX_GPIO_DATAIN 0x0038
|
#define OMAP24XX_GPIO_DATAIN 0x0038
|
||||||
@@ -1551,7 +1552,7 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
|
|||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
|
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
|
||||||
case METHOD_GPIO_24XX:
|
case METHOD_GPIO_24XX:
|
||||||
wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN;
|
||||||
wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
|
wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
|
||||||
wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
||||||
break;
|
break;
|
||||||
@@ -1574,7 +1575,7 @@ static int omap_gpio_resume(struct sys_device *dev)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
|
if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < gpio_bank_count; i++) {
|
for (i = 0; i < gpio_bank_count; i++) {
|
||||||
|
@@ -42,19 +42,8 @@
|
|||||||
#define PHYS_OFFSET UL(0x80000000)
|
#define PHYS_OFFSET UL(0x80000000)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Conversion between SDRAM and fake PCI bus, used by USB
|
|
||||||
* NOTE: Physical address must be converted to Local Bus address
|
|
||||||
* on OMAP-1510 only
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bus address is physical address, except for OMAP-1510 Local Bus.
|
* Bus address is physical address, except for OMAP-1510 Local Bus.
|
||||||
*/
|
|
||||||
#define __virt_to_bus(x) __virt_to_phys(x)
|
|
||||||
#define __bus_to_virt(x) __phys_to_virt(x)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OMAP-1510 bus address is translated into a Local Bus address if the
|
* OMAP-1510 bus address is translated into a Local Bus address if the
|
||||||
* OMAP bus type is lbus. We do the address translation based on the
|
* OMAP bus type is lbus. We do the address translation based on the
|
||||||
* device overriding the defaults used in the dma-mapping API.
|
* device overriding the defaults used in the dma-mapping API.
|
||||||
@@ -74,16 +63,16 @@
|
|||||||
|
|
||||||
#define __arch_page_to_dma(dev, page) ({is_lbus_device(dev) ? \
|
#define __arch_page_to_dma(dev, page) ({is_lbus_device(dev) ? \
|
||||||
(dma_addr_t)virt_to_lbus(page_address(page)) : \
|
(dma_addr_t)virt_to_lbus(page_address(page)) : \
|
||||||
(dma_addr_t)__virt_to_bus(page_address(page));})
|
(dma_addr_t)__virt_to_phys(page_address(page));})
|
||||||
|
|
||||||
#define __arch_dma_to_virt(dev, addr) ({ (void *) (is_lbus_device(dev) ? \
|
#define __arch_dma_to_virt(dev, addr) ({ (void *) (is_lbus_device(dev) ? \
|
||||||
lbus_to_virt(addr) : \
|
lbus_to_virt(addr) : \
|
||||||
__bus_to_virt(addr)); })
|
__phys_to_virt(addr)); })
|
||||||
|
|
||||||
#define __arch_virt_to_dma(dev, addr) ({ unsigned long __addr = (unsigned long)(addr); \
|
#define __arch_virt_to_dma(dev, addr) ({ unsigned long __addr = (unsigned long)(addr); \
|
||||||
(dma_addr_t) (is_lbus_device(dev) ? \
|
(dma_addr_t) (is_lbus_device(dev) ? \
|
||||||
virt_to_lbus(__addr) : \
|
virt_to_lbus(__addr) : \
|
||||||
__virt_to_bus(__addr)); })
|
__virt_to_phys(__addr)); })
|
||||||
|
|
||||||
#endif /* CONFIG_ARCH_OMAP15XX */
|
#endif /* CONFIG_ARCH_OMAP15XX */
|
||||||
|
|
||||||
|
@@ -128,7 +128,7 @@ void clk_deny_idle(struct clk *clk);
|
|||||||
* clk_allow_idle - Counters previous clk_deny_idle
|
* clk_allow_idle - Counters previous clk_deny_idle
|
||||||
* @clk: clock signal handle
|
* @clk: clock signal handle
|
||||||
*/
|
*/
|
||||||
void clk_deny_idle(struct clk *clk);
|
void clk_allow_idle(struct clk *clk);
|
||||||
|
|
||||||
extern void omap_pm_idle(void);
|
extern void omap_pm_idle(void);
|
||||||
extern void omap_pm_suspend(void);
|
extern void omap_pm_suspend(void);
|
||||||
|
@@ -141,7 +141,11 @@ static int is_vbus_present(void)
|
|||||||
|
|
||||||
if (mach->gpio_vbus) {
|
if (mach->gpio_vbus) {
|
||||||
int value = gpio_get_value(mach->gpio_vbus);
|
int value = gpio_get_value(mach->gpio_vbus);
|
||||||
return mach->gpio_vbus_inverted ? !value : value;
|
|
||||||
|
if (mach->gpio_vbus_inverted)
|
||||||
|
return !value;
|
||||||
|
else
|
||||||
|
return !!value;
|
||||||
}
|
}
|
||||||
if (mach->udc_is_connected)
|
if (mach->udc_is_connected)
|
||||||
return mach->udc_is_connected();
|
return mach->udc_is_connected();
|
||||||
@@ -982,7 +986,7 @@ static int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
|
|||||||
struct pxa25x_udc *udc;
|
struct pxa25x_udc *udc;
|
||||||
|
|
||||||
udc = container_of(_gadget, struct pxa25x_udc, gadget);
|
udc = container_of(_gadget, struct pxa25x_udc, gadget);
|
||||||
udc->vbus = (is_active != 0);
|
udc->vbus = is_active;
|
||||||
DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
|
DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
|
||||||
pullup(udc);
|
pullup(udc);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1399,12 +1403,8 @@ lubbock_vbus_irq(int irq, void *_dev)
|
|||||||
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
|
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
|
||||||
{
|
{
|
||||||
struct pxa25x_udc *dev = _dev;
|
struct pxa25x_udc *dev = _dev;
|
||||||
int vbus = gpio_get_value(dev->mach->gpio_vbus);
|
|
||||||
|
|
||||||
if (dev->mach->gpio_vbus_inverted)
|
pxa25x_udc_vbus_session(&dev->gadget, is_vbus_present());
|
||||||
vbus = !vbus;
|
|
||||||
|
|
||||||
pxa25x_udc_vbus_session(&dev->gadget, vbus);
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,6 @@ objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
|
|||||||
objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
|
objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
|
||||||
objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
|
objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
|
||||||
objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
|
objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
|
||||||
objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
|
|
||||||
|
|
||||||
omapfb-objs := $(objs-yy)
|
omapfb-objs := $(objs-yy)
|
||||||
|
|
||||||
|
@@ -1,327 +0,0 @@
|
|||||||
/*
|
|
||||||
* LCD panel support for the Siemens SX1 mobile phone
|
|
||||||
*
|
|
||||||
* Current version : Vovan888@gmail.com, great help from FCA00000
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
|
|
||||||
#include <mach/gpio.h>
|
|
||||||
#include <mach/omapfb.h>
|
|
||||||
#include <mach/mcbsp.h>
|
|
||||||
#include <mach/mux.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OMAP310 GPIO registers
|
|
||||||
*/
|
|
||||||
#define GPIO_DATA_INPUT 0xfffce000
|
|
||||||
#define GPIO_DATA_OUTPUT 0xfffce004
|
|
||||||
#define GPIO_DIR_CONTROL 0xfffce008
|
|
||||||
#define GPIO_INT_CONTROL 0xfffce00c
|
|
||||||
#define GPIO_INT_MASK 0xfffce010
|
|
||||||
#define GPIO_INT_STATUS 0xfffce014
|
|
||||||
#define GPIO_PIN_CONTROL 0xfffce018
|
|
||||||
|
|
||||||
|
|
||||||
#define A_LCD_SSC_RD 3
|
|
||||||
#define A_LCD_SSC_SD 7
|
|
||||||
#define _A_LCD_RESET 9
|
|
||||||
#define _A_LCD_SSC_CS 12
|
|
||||||
#define _A_LCD_SSC_A0 13
|
|
||||||
|
|
||||||
#define DSP_REG 0xE1017024
|
|
||||||
|
|
||||||
const unsigned char INIT_1[12] = {
|
|
||||||
0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char INIT_2[127] = {
|
|
||||||
0x15, 0x00, 0x29, 0x00, 0x3E, 0x00, 0x51, 0x00,
|
|
||||||
0x65, 0x00, 0x7A, 0x00, 0x8D, 0x00, 0xA1, 0x00,
|
|
||||||
0xB6, 0x00, 0xC7, 0x00, 0xD8, 0x00, 0xEB, 0x00,
|
|
||||||
0xFB, 0x00, 0x0B, 0x01, 0x1B, 0x01, 0x27, 0x01,
|
|
||||||
0x34, 0x01, 0x41, 0x01, 0x4C, 0x01, 0x55, 0x01,
|
|
||||||
0x5F, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01,
|
|
||||||
0x7E, 0x01, 0x86, 0x01, 0x8C, 0x01, 0x94, 0x01,
|
|
||||||
0x9B, 0x01, 0xA1, 0x01, 0xA4, 0x01, 0xA9, 0x01,
|
|
||||||
0xAD, 0x01, 0xB2, 0x01, 0xB7, 0x01, 0xBC, 0x01,
|
|
||||||
0xC0, 0x01, 0xC4, 0x01, 0xC8, 0x01, 0xCB, 0x01,
|
|
||||||
0xCF, 0x01, 0xD2, 0x01, 0xD5, 0x01, 0xD8, 0x01,
|
|
||||||
0xDB, 0x01, 0xE0, 0x01, 0xE3, 0x01, 0xE6, 0x01,
|
|
||||||
0xE8, 0x01, 0xEB, 0x01, 0xEE, 0x01, 0xF1, 0x01,
|
|
||||||
0xF3, 0x01, 0xF8, 0x01, 0xF9, 0x01, 0xFC, 0x01,
|
|
||||||
0x00, 0x02, 0x03, 0x02, 0x07, 0x02, 0x09, 0x02,
|
|
||||||
0x0E, 0x02, 0x13, 0x02, 0x1C, 0x02, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char INIT_3[15] = {
|
|
||||||
0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59,
|
|
||||||
0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
static void epson_sendbyte(int flag, unsigned char byte)
|
|
||||||
{
|
|
||||||
int i, shifter = 0x80;
|
|
||||||
|
|
||||||
if (!flag)
|
|
||||||
gpio_set_value(_A_LCD_SSC_A0, 0);
|
|
||||||
mdelay(2);
|
|
||||||
gpio_set_value(A_LCD_SSC_RD, 1);
|
|
||||||
|
|
||||||
gpio_set_value(A_LCD_SSC_SD, flag);
|
|
||||||
|
|
||||||
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
|
|
||||||
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
|
|
||||||
gpio_set_value(A_LCD_SSC_SD, shifter & byte);
|
|
||||||
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
|
|
||||||
shifter >>= 1;
|
|
||||||
}
|
|
||||||
gpio_set_value(_A_LCD_SSC_A0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_system(void)
|
|
||||||
{
|
|
||||||
omap_mcbsp_request(OMAP_MCBSP3);
|
|
||||||
omap_mcbsp_stop(OMAP_MCBSP3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_GPIO(void)
|
|
||||||
{
|
|
||||||
/* new wave */
|
|
||||||
gpio_request(A_LCD_SSC_RD, "lcd_ssc_rd");
|
|
||||||
gpio_request(A_LCD_SSC_SD, "lcd_ssc_sd");
|
|
||||||
gpio_request(_A_LCD_RESET, "lcd_reset");
|
|
||||||
gpio_request(_A_LCD_SSC_CS, "lcd_ssc_cs");
|
|
||||||
gpio_request(_A_LCD_SSC_A0, "lcd_ssc_a0");
|
|
||||||
|
|
||||||
/* set GPIOs to output, with initial data */
|
|
||||||
gpio_direction_output(A_LCD_SSC_RD, 1);
|
|
||||||
gpio_direction_output(A_LCD_SSC_SD, 0);
|
|
||||||
gpio_direction_output(_A_LCD_RESET, 0);
|
|
||||||
gpio_direction_output(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_direction_output(_A_LCD_SSC_A0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
omap_cfg_reg(MCBSP3_CLKX);
|
|
||||||
|
|
||||||
mdelay(2);
|
|
||||||
setup_GPIO();
|
|
||||||
mdelay(2);
|
|
||||||
|
|
||||||
/* reset LCD */
|
|
||||||
gpio_set_value(A_LCD_SSC_SD, 1);
|
|
||||||
epson_sendbyte(0, 0x25);
|
|
||||||
|
|
||||||
gpio_set_value(_A_LCD_RESET, 0);
|
|
||||||
mdelay(10);
|
|
||||||
gpio_set_value(_A_LCD_RESET, 1);
|
|
||||||
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
mdelay(2);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD, phase 1 */
|
|
||||||
epson_sendbyte(0, 0xCA);
|
|
||||||
for (i = 0; i < 10; i++)
|
|
||||||
epson_sendbyte(1, INIT_1[i]);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 2 */
|
|
||||||
epson_sendbyte(0, 0xCB);
|
|
||||||
for (i = 0; i < 125; i++)
|
|
||||||
epson_sendbyte(1, INIT_2[i]);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 2a */
|
|
||||||
epson_sendbyte(0, 0xCC);
|
|
||||||
for (i = 0; i < 14; i++)
|
|
||||||
epson_sendbyte(1, INIT_3[i]);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 3 */
|
|
||||||
epson_sendbyte(0, 0xBC);
|
|
||||||
epson_sendbyte(1, 0x08);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 4 */
|
|
||||||
epson_sendbyte(0, 0x07);
|
|
||||||
epson_sendbyte(1, 0x05);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 5 */
|
|
||||||
epson_sendbyte(0, 0x94);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 6 */
|
|
||||||
epson_sendbyte(0, 0xC6);
|
|
||||||
epson_sendbyte(1, 0x80);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
mdelay(100); /* used to be 1000 */
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 7 */
|
|
||||||
epson_sendbyte(0, 0x16);
|
|
||||||
epson_sendbyte(1, 0x02);
|
|
||||||
epson_sendbyte(1, 0x00);
|
|
||||||
epson_sendbyte(1, 0xB1);
|
|
||||||
epson_sendbyte(1, 0x00);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 8 */
|
|
||||||
epson_sendbyte(0, 0x76);
|
|
||||||
epson_sendbyte(1, 0x00);
|
|
||||||
epson_sendbyte(1, 0x00);
|
|
||||||
epson_sendbyte(1, 0xDB);
|
|
||||||
epson_sendbyte(1, 0x00);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
/* init LCD phase 9 */
|
|
||||||
epson_sendbyte(0, 0xAF);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sx1_panel_cleanup(struct lcd_panel *panel)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sx1_panel_disable(struct lcd_panel *panel)
|
|
||||||
{
|
|
||||||
printk(KERN_INFO "SX1: LCD panel disable\n");
|
|
||||||
sx1_setmmipower(0);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
|
|
||||||
epson_sendbyte(0, 0x25);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
epson_sendbyte(0, 0xAE);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
mdelay(100);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 0);
|
|
||||||
|
|
||||||
epson_sendbyte(0, 0x95);
|
|
||||||
gpio_set_value(_A_LCD_SSC_CS, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sx1_panel_enable(struct lcd_panel *panel)
|
|
||||||
{
|
|
||||||
printk(KERN_INFO "lcd_sx1: LCD panel enable\n");
|
|
||||||
init_system();
|
|
||||||
display_init();
|
|
||||||
|
|
||||||
sx1_setmmipower(1);
|
|
||||||
sx1_setbacklight(0x18);
|
|
||||||
sx1_setkeylight (0x06);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned long sx1_panel_get_caps(struct lcd_panel *panel)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct lcd_panel sx1_panel = {
|
|
||||||
.name = "sx1",
|
|
||||||
.config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
|
|
||||||
OMAP_LCDC_INV_HSYNC | OMAP_LCDC_INV_PIX_CLOCK |
|
|
||||||
OMAP_LCDC_INV_OUTPUT_EN,
|
|
||||||
|
|
||||||
.x_res = 176,
|
|
||||||
.y_res = 220,
|
|
||||||
.data_lines = 16,
|
|
||||||
.bpp = 16,
|
|
||||||
.hsw = 5,
|
|
||||||
.hfp = 5,
|
|
||||||
.hbp = 5,
|
|
||||||
.vsw = 2,
|
|
||||||
.vfp = 1,
|
|
||||||
.vbp = 1,
|
|
||||||
.pixel_clock = 1500,
|
|
||||||
|
|
||||||
.init = sx1_panel_init,
|
|
||||||
.cleanup = sx1_panel_cleanup,
|
|
||||||
.enable = sx1_panel_enable,
|
|
||||||
.disable = sx1_panel_disable,
|
|
||||||
.get_caps = sx1_panel_get_caps,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int sx1_panel_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
omapfb_register_panel(&sx1_panel);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sx1_panel_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sx1_panel_resume(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct platform_driver sx1_panel_driver = {
|
|
||||||
.probe = sx1_panel_probe,
|
|
||||||
.remove = sx1_panel_remove,
|
|
||||||
.suspend = sx1_panel_suspend,
|
|
||||||
.resume = sx1_panel_resume,
|
|
||||||
.driver = {
|
|
||||||
.name = "lcd_sx1",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int sx1_panel_drv_init(void)
|
|
||||||
{
|
|
||||||
return platform_driver_register(&sx1_panel_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sx1_panel_drv_cleanup(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&sx1_panel_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(sx1_panel_drv_init);
|
|
||||||
module_exit(sx1_panel_drv_cleanup);
|
|
@@ -63,12 +63,14 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx)
|
|||||||
#endif /* CONFIG_HIGHMEM */
|
#endif /* CONFIG_HIGHMEM */
|
||||||
|
|
||||||
/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
|
/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
|
||||||
|
#ifndef clear_user_highpage
|
||||||
static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
|
static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
|
||||||
{
|
{
|
||||||
void *addr = kmap_atomic(page, KM_USER0);
|
void *addr = kmap_atomic(page, KM_USER0);
|
||||||
clear_user_page(addr, vaddr, page);
|
clear_user_page(addr, vaddr, page);
|
||||||
kunmap_atomic(addr, KM_USER0);
|
kunmap_atomic(addr, KM_USER0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
|
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user