aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-31 19:13:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-31 19:13:44 -0400
commitb1c907f3b2675ecb01e340948fc62d6535ff5ac3 (patch)
tree978e7ba356ff57c4febe55f3ee0d0955ea721f14
parent91e67a996c60a347ad7b918a74efb0f6b3b274c3 (diff)
parent84ac218f0257a0cfd7689d9a44f53118dbf307b3 (diff)
Merge branch 'next' of git://git.monstr.eu/linux-2.6-microblaze
* 'next' of git://git.monstr.eu/linux-2.6-microblaze: microblaze: Remove __ARCH_WANT_INTERRUPTS_ON_CTXSW usage microblaze: Use delay slot in __strnlen_user, __strncpy_user microblaze: Remove NET_IP_ALIGN from system.h microblaze: Add __ucmpdi2() helper function microblaze: Raise SIGFPE/FPE_INTDIV for div by zero microblaze: Switch ELF_ARCH code to 189 microblaze: Added DMA sync operations microblaze: Moved __dma_sync() to dma-mapping.h microblaze: Add PVR for Microblaze v8.20.a microblaze: Fix access_ok macro microblaze: Add loop unrolling for PAGE in copy_tofrom_user microblaze: Simplify logic for unaligned byte copying microblaze: Change label names - copy_tofrom_user microblaze: Separate fixup section definition microblaze: Change label name in copy_tofrom_user microblaze: Clear top bit from cnt32_to_63
-rw-r--r--arch/microblaze/include/asm/dma-mapping.h20
-rw-r--r--arch/microblaze/include/asm/elf.h8
-rw-r--r--arch/microblaze/include/asm/system.h9
-rw-r--r--arch/microblaze/include/asm/uaccess.h2
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c1
-rw-r--r--arch/microblaze/kernel/dma.c82
-rw-r--r--arch/microblaze/kernel/exceptions.c2
-rw-r--r--arch/microblaze/kernel/process.c1
-rw-r--r--arch/microblaze/kernel/ptrace.c2
-rw-r--r--arch/microblaze/kernel/timer.c3
-rw-r--r--arch/microblaze/lib/Makefile1
-rw-r--r--arch/microblaze/lib/uaccess_old.S123
-rw-r--r--arch/microblaze/lib/ucmpdi2.c20
13 files changed, 220 insertions, 54 deletions
diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h
index a569514cf19f..3a3e5b886854 100644
--- a/arch/microblaze/include/asm/dma-mapping.h
+++ b/arch/microblaze/include/asm/dma-mapping.h
@@ -28,12 +28,12 @@
28#include <linux/dma-attrs.h> 28#include <linux/dma-attrs.h>
29#include <asm/io.h> 29#include <asm/io.h>
30#include <asm-generic/dma-coherent.h> 30#include <asm-generic/dma-coherent.h>
31#include <asm/cacheflush.h>
31 32
32#define DMA_ERROR_CODE (~(dma_addr_t)0x0) 33#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
33 34
34#define __dma_alloc_coherent(dev, gfp, size, handle) NULL 35#define __dma_alloc_coherent(dev, gfp, size, handle) NULL
35#define __dma_free_coherent(size, addr) ((void)0) 36#define __dma_free_coherent(size, addr) ((void)0)
36#define __dma_sync(addr, size, rw) ((void)0)
37 37
38static inline unsigned long device_to_mask(struct device *dev) 38static inline unsigned long device_to_mask(struct device *dev)
39{ 39{
@@ -95,6 +95,22 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
95 95
96#include <asm-generic/dma-mapping-common.h> 96#include <asm-generic/dma-mapping-common.h>
97 97
98static inline void __dma_sync(unsigned long paddr,
99 size_t size, enum dma_data_direction direction)
100{
101 switch (direction) {
102 case DMA_TO_DEVICE:
103 case DMA_BIDIRECTIONAL:
104 flush_dcache_range(paddr, paddr + size);
105 break;
106 case DMA_FROM_DEVICE:
107 invalidate_dcache_range(paddr, paddr + size);
108 break;
109 default:
110 BUG();
111 }
112}
113
98static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) 114static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
99{ 115{
100 struct dma_map_ops *ops = get_dma_ops(dev); 116 struct dma_map_ops *ops = get_dma_ops(dev);
@@ -135,7 +151,7 @@ static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
135 enum dma_data_direction direction) 151 enum dma_data_direction direction)
136{ 152{
137 BUG_ON(direction == DMA_NONE); 153 BUG_ON(direction == DMA_NONE);
138 __dma_sync(vaddr, size, (int)direction); 154 __dma_sync(virt_to_phys(vaddr), size, (int)direction);
139} 155}
140 156
141#endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */ 157#endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h
index 098dfdde4b06..834849f59ae8 100644
--- a/arch/microblaze/include/asm/elf.h
+++ b/arch/microblaze/include/asm/elf.h
@@ -16,13 +16,15 @@
16 * I've snaffled the value from the microblaze binutils source code 16 * I've snaffled the value from the microblaze binutils source code
17 * /binutils/microblaze/include/elf/microblaze.h 17 * /binutils/microblaze/include/elf/microblaze.h
18 */ 18 */
19#define EM_XILINX_MICROBLAZE 0xbaab 19#define EM_MICROBLAZE 189
20#define ELF_ARCH EM_XILINX_MICROBLAZE 20#define EM_MICROBLAZE_OLD 0xbaab
21#define ELF_ARCH EM_MICROBLAZE
21 22
22/* 23/*
23 * This is used to ensure we don't load something for the wrong architecture. 24 * This is used to ensure we don't load something for the wrong architecture.
24 */ 25 */
25#define elf_check_arch(x) ((x)->e_machine == EM_XILINX_MICROBLAZE) 26#define elf_check_arch(x) ((x)->e_machine == EM_MICROBLAZE \
27 || (x)->e_machine == EM_MICROBLAZE_OLD)
26 28
27/* 29/*
28 * These are used to set parameters in the core dumps. 30 * These are used to set parameters in the core dumps.
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
index e6a2284571dc..5a433cbaafb3 100644
--- a/arch/microblaze/include/asm/system.h
+++ b/arch/microblaze/include/asm/system.h
@@ -17,8 +17,6 @@
17#include <asm-generic/cmpxchg.h> 17#include <asm-generic/cmpxchg.h>
18#include <asm-generic/cmpxchg-local.h> 18#include <asm-generic/cmpxchg-local.h>
19 19
20#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
21
22struct task_struct; 20struct task_struct;
23struct thread_info; 21struct thread_info;
24 22
@@ -96,11 +94,4 @@ extern struct dentry *of_debugfs_root;
96 94
97#define arch_align_stack(x) (x) 95#define arch_align_stack(x) (x)
98 96
99/*
100 * MicroBlaze doesn't handle unaligned accesses in hardware.
101 *
102 * Based on this we force the IP header alignment in network drivers.
103 */
104#define NET_IP_ALIGN 2
105
106#endif /* _ASM_MICROBLAZE_SYSTEM_H */ 97#endif /* _ASM_MICROBLAZE_SYSTEM_H */
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 5bb95a11880d..072b0077abf9 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -95,7 +95,7 @@ static inline int ___range_ok(unsigned long addr, unsigned long size)
95 * - "addr", "addr + size" and "size" are all below the limit 95 * - "addr", "addr + size" and "size" are all below the limit
96 */ 96 */
97#define access_ok(type, addr, size) \ 97#define access_ok(type, addr, size) \
98 (get_fs().seg > (((unsigned long)(addr)) | \ 98 (get_fs().seg >= (((unsigned long)(addr)) | \
99 (size) | ((unsigned long)(addr) + (size)))) 99 (size) | ((unsigned long)(addr) + (size))))
100 100
101/* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n", 101/* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n",
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index 44394d80a683..54194b28574a 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -34,6 +34,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
34 {"8.00.a", 0x12}, 34 {"8.00.a", 0x12},
35 {"8.00.b", 0x13}, 35 {"8.00.b", 0x13},
36 {"8.10.a", 0x14}, 36 {"8.10.a", 0x14},
37 {"8.20.a", 0x15},
37 {NULL, 0}, 38 {NULL, 0},
38}; 39};
39 40
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c
index 393e6b2db688..dc6416d265d6 100644
--- a/arch/microblaze/kernel/dma.c
+++ b/arch/microblaze/kernel/dma.c
@@ -11,7 +11,6 @@
11#include <linux/gfp.h> 11#include <linux/gfp.h>
12#include <linux/dma-debug.h> 12#include <linux/dma-debug.h>
13#include <asm/bug.h> 13#include <asm/bug.h>
14#include <asm/cacheflush.h>
15 14
16/* 15/*
17 * Generic direct DMA implementation 16 * Generic direct DMA implementation
@@ -21,21 +20,6 @@
21 * can set archdata.dma_data to an unsigned long holding the offset. By 20 * can set archdata.dma_data to an unsigned long holding the offset. By
22 * default the offset is PCI_DRAM_OFFSET. 21 * default the offset is PCI_DRAM_OFFSET.
23 */ 22 */
24static inline void __dma_sync_page(unsigned long paddr, unsigned long offset,
25 size_t size, enum dma_data_direction direction)
26{
27 switch (direction) {
28 case DMA_TO_DEVICE:
29 case DMA_BIDIRECTIONAL:
30 flush_dcache_range(paddr + offset, paddr + offset + size);
31 break;
32 case DMA_FROM_DEVICE:
33 invalidate_dcache_range(paddr + offset, paddr + offset + size);
34 break;
35 default:
36 BUG();
37 }
38}
39 23
40static unsigned long get_dma_direct_offset(struct device *dev) 24static unsigned long get_dma_direct_offset(struct device *dev)
41{ 25{
@@ -91,7 +75,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
91 /* FIXME this part of code is untested */ 75 /* FIXME this part of code is untested */
92 for_each_sg(sgl, sg, nents, i) { 76 for_each_sg(sgl, sg, nents, i) {
93 sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev); 77 sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
94 __dma_sync_page(page_to_phys(sg_page(sg)), sg->offset, 78 __dma_sync(page_to_phys(sg_page(sg)) + sg->offset,
95 sg->length, direction); 79 sg->length, direction);
96 } 80 }
97 81
@@ -116,7 +100,7 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,
116 enum dma_data_direction direction, 100 enum dma_data_direction direction,
117 struct dma_attrs *attrs) 101 struct dma_attrs *attrs)
118{ 102{
119 __dma_sync_page(page_to_phys(page), offset, size, direction); 103 __dma_sync(page_to_phys(page) + offset, size, direction);
120 return page_to_phys(page) + offset + get_dma_direct_offset(dev); 104 return page_to_phys(page) + offset + get_dma_direct_offset(dev);
121} 105}
122 106
@@ -131,7 +115,63 @@ static inline void dma_direct_unmap_page(struct device *dev,
131 * phys_to_virt is here because in __dma_sync_page is __virt_to_phys and 115 * phys_to_virt is here because in __dma_sync_page is __virt_to_phys and
132 * dma_address is physical address 116 * dma_address is physical address
133 */ 117 */
134 __dma_sync_page(dma_address, 0 , size, direction); 118 __dma_sync(dma_address, size, direction);
119}
120
121static inline void
122dma_direct_sync_single_for_cpu(struct device *dev,
123 dma_addr_t dma_handle, size_t size,
124 enum dma_data_direction direction)
125{
126 /*
127 * It's pointless to flush the cache as the memory segment
128 * is given to the CPU
129 */
130
131 if (direction == DMA_FROM_DEVICE)
132 __dma_sync(dma_handle, size, direction);
133}
134
135static inline void
136dma_direct_sync_single_for_device(struct device *dev,
137 dma_addr_t dma_handle, size_t size,
138 enum dma_data_direction direction)
139{
140 /*
141 * It's pointless to invalidate the cache if the device isn't
142 * supposed to write to the relevant region
143 */
144
145 if (direction == DMA_TO_DEVICE)
146 __dma_sync(dma_handle, size, direction);
147}
148
149static inline void
150dma_direct_sync_sg_for_cpu(struct device *dev,
151 struct scatterlist *sgl, int nents,
152 enum dma_data_direction direction)
153{
154 struct scatterlist *sg;
155 int i;
156
157 /* FIXME this part of code is untested */
158 if (direction == DMA_FROM_DEVICE)
159 for_each_sg(sgl, sg, nents, i)
160 __dma_sync(sg->dma_address, sg->length, direction);
161}
162
163static inline void
164dma_direct_sync_sg_for_device(struct device *dev,
165 struct scatterlist *sgl, int nents,
166 enum dma_data_direction direction)
167{
168 struct scatterlist *sg;
169 int i;
170
171 /* FIXME this part of code is untested */
172 if (direction == DMA_TO_DEVICE)
173 for_each_sg(sgl, sg, nents, i)
174 __dma_sync(sg->dma_address, sg->length, direction);
135} 175}
136 176
137struct dma_map_ops dma_direct_ops = { 177struct dma_map_ops dma_direct_ops = {
@@ -142,6 +182,10 @@ struct dma_map_ops dma_direct_ops = {
142 .dma_supported = dma_direct_dma_supported, 182 .dma_supported = dma_direct_dma_supported,
143 .map_page = dma_direct_map_page, 183 .map_page = dma_direct_map_page,
144 .unmap_page = dma_direct_unmap_page, 184 .unmap_page = dma_direct_unmap_page,
185 .sync_single_for_cpu = dma_direct_sync_single_for_cpu,
186 .sync_single_for_device = dma_direct_sync_single_for_device,
187 .sync_sg_for_cpu = dma_direct_sync_sg_for_cpu,
188 .sync_sg_for_device = dma_direct_sync_sg_for_device,
145}; 189};
146EXPORT_SYMBOL(dma_direct_ops); 190EXPORT_SYMBOL(dma_direct_ops);
147 191
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
index 66fad2301221..6348dc82f428 100644
--- a/arch/microblaze/kernel/exceptions.c
+++ b/arch/microblaze/kernel/exceptions.c
@@ -119,7 +119,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
119 case MICROBLAZE_DIV_ZERO_EXCEPTION: 119 case MICROBLAZE_DIV_ZERO_EXCEPTION:
120 if (user_mode(regs)) { 120 if (user_mode(regs)) {
121 pr_debug("Divide by zero exception in user mode\n"); 121 pr_debug("Divide by zero exception in user mode\n");
122 _exception(SIGILL, regs, FPE_INTDIV, addr); 122 _exception(SIGFPE, regs, FPE_INTDIV, addr);
123 return; 123 return;
124 } 124 }
125 printk(KERN_WARNING "Divide by zero exception " \ 125 printk(KERN_WARNING "Divide by zero exception " \
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index dbb812421d8a..95cc295976a7 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -179,6 +179,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
179 179
180 ti->cpu_context.msr = (childregs->msr|MSR_VM); 180 ti->cpu_context.msr = (childregs->msr|MSR_VM);
181 ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */ 181 ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */
182 ti->cpu_context.msr &= ~MSR_IE;
182#endif 183#endif
183 ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8; 184 ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
184 185
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index 6a8e0cc5c57d..043cb58f9c44 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -148,7 +148,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
148 ret = -1L; 148 ret = -1L;
149 149
150 if (unlikely(current->audit_context)) 150 if (unlikely(current->audit_context))
151 audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12, 151 audit_syscall_entry(EM_MICROBLAZE, regs->r12,
152 regs->r5, regs->r6, 152 regs->r5, regs->r6,
153 regs->r7, regs->r8); 153 regs->r7, regs->r8);
154 154
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index e5550ce4e0eb..af74b1113aab 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -308,7 +308,8 @@ unsigned long long notrace sched_clock(void)
308{ 308{
309 if (timer_initialized) { 309 if (timer_initialized) {
310 struct clocksource *cs = &clocksource_microblaze; 310 struct clocksource *cs = &clocksource_microblaze;
311 cycle_t cyc = cnt32_to_63(cs->read(NULL)); 311
312 cycle_t cyc = cnt32_to_63(cs->read(NULL)) & LLONG_MAX;
312 return clocksource_cyc2ns(cyc, cs->mult, cs->shift); 313 return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
313 } 314 }
314 return 0; 315 return 0;
diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile
index 10c320aa908b..c13067b243c3 100644
--- a/arch/microblaze/lib/Makefile
+++ b/arch/microblaze/lib/Makefile
@@ -25,5 +25,6 @@ lib-y += lshrdi3.o
25lib-y += modsi3.o 25lib-y += modsi3.o
26lib-y += muldi3.o 26lib-y += muldi3.o
27lib-y += mulsi3.o 27lib-y += mulsi3.o
28lib-y += ucmpdi2.o
28lib-y += udivsi3.o 29lib-y += udivsi3.o
29lib-y += umodsi3.o 30lib-y += umodsi3.o
diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S
index 5810cec54a7a..f037266cdaf3 100644
--- a/arch/microblaze/lib/uaccess_old.S
+++ b/arch/microblaze/lib/uaccess_old.S
@@ -10,6 +10,7 @@
10 10
11#include <linux/errno.h> 11#include <linux/errno.h>
12#include <linux/linkage.h> 12#include <linux/linkage.h>
13#include <asm/page.h>
13 14
14/* 15/*
15 * int __strncpy_user(char *to, char *from, int len); 16 * int __strncpy_user(char *to, char *from, int len);
@@ -33,8 +34,8 @@ __strncpy_user:
33 * r3 - temp count 34 * r3 - temp count
34 * r4 - temp val 35 * r4 - temp val
35 */ 36 */
37 beqid r7,3f
36 addik r3,r7,0 /* temp_count = len */ 38 addik r3,r7,0 /* temp_count = len */
37 beqi r3,3f
381: 391:
39 lbu r4,r6,r0 40 lbu r4,r6,r0
40 sb r4,r5,r0 41 sb r4,r5,r0
@@ -76,8 +77,8 @@ __strncpy_user:
76.type __strnlen_user, @function 77.type __strnlen_user, @function
77.align 4; 78.align 4;
78__strnlen_user: 79__strnlen_user:
80 beqid r6,3f
79 addik r3,r6,0 81 addik r3,r6,0
80 beqi r3,3f
811: 821:
82 lbu r4,r5,r0 83 lbu r4,r5,r0
83 beqid r4,2f /* break on NUL */ 84 beqid r4,2f /* break on NUL */
@@ -102,6 +103,49 @@ __strnlen_user:
102 .section __ex_table,"a" 103 .section __ex_table,"a"
103 .word 1b,4b 104 .word 1b,4b
104 105
106/* Loop unrolling for __copy_tofrom_user */
107#define COPY(offset) \
1081: lwi r4 , r6, 0x0000 + offset; \
1092: lwi r19, r6, 0x0004 + offset; \
1103: lwi r20, r6, 0x0008 + offset; \
1114: lwi r21, r6, 0x000C + offset; \
1125: lwi r22, r6, 0x0010 + offset; \
1136: lwi r23, r6, 0x0014 + offset; \
1147: lwi r24, r6, 0x0018 + offset; \
1158: lwi r25, r6, 0x001C + offset; \
1169: swi r4 , r5, 0x0000 + offset; \
11710: swi r19, r5, 0x0004 + offset; \
11811: swi r20, r5, 0x0008 + offset; \
11912: swi r21, r5, 0x000C + offset; \
12013: swi r22, r5, 0x0010 + offset; \
12114: swi r23, r5, 0x0014 + offset; \
12215: swi r24, r5, 0x0018 + offset; \
12316: swi r25, r5, 0x001C + offset; \
124 .section __ex_table,"a"; \
125 .word 1b, 0f; \
126 .word 2b, 0f; \
127 .word 3b, 0f; \
128 .word 4b, 0f; \
129 .word 5b, 0f; \
130 .word 6b, 0f; \
131 .word 7b, 0f; \
132 .word 8b, 0f; \
133 .word 9b, 0f; \
134 .word 10b, 0f; \
135 .word 11b, 0f; \
136 .word 12b, 0f; \
137 .word 13b, 0f; \
138 .word 14b, 0f; \
139 .word 15b, 0f; \
140 .word 16b, 0f; \
141 .text
142
143#define COPY_80(offset) \
144 COPY(0x00 + offset);\
145 COPY(0x20 + offset);\
146 COPY(0x40 + offset);\
147 COPY(0x60 + offset);
148
105/* 149/*
106 * int __copy_tofrom_user(char *to, char *from, int len) 150 * int __copy_tofrom_user(char *to, char *from, int len)
107 * Return: 151 * Return:
@@ -119,34 +163,79 @@ __copy_tofrom_user:
119 * r7, r3 - count 163 * r7, r3 - count
120 * r4 - tempval 164 * r4 - tempval
121 */ 165 */
122 beqid r7, 3f /* zero size is not likely */ 166 beqid r7, 0f /* zero size is not likely */
123 andi r3, r7, 0x3 /* filter add count */
124 bneid r3, 4f /* if is odd value then byte copying */
125 or r3, r5, r6 /* find if is any to/from unaligned */ 167 or r3, r5, r6 /* find if is any to/from unaligned */
126 andi r3, r3, 0x3 /* mask unaligned */ 168 or r3, r3, r7 /* find if count is unaligned */
127 bneid r3, 1f /* it is unaligned -> then jump */ 169 andi r3, r3, 0x3 /* mask last 3 bits */
170 bneid r3, bu1 /* if r3 is not zero then byte copying */
171 or r3, r0, r0
172
173 rsubi r3, r7, PAGE_SIZE /* detect PAGE_SIZE */
174 beqid r3, page;
128 or r3, r0, r0 175 or r3, r0, r0
129 176
130/* at least one 4 byte copy */ 177w1: lw r4, r6, r3 /* at least one 4 byte copy */
1315: lw r4, r6, r3 178w2: sw r4, r5, r3
1326: sw r4, r5, r3
133 addik r7, r7, -4 179 addik r7, r7, -4
134 bneid r7, 5b 180 bneid r7, w1
135 addik r3, r3, 4 181 addik r3, r3, 4
136 addik r3, r7, 0 182 addik r3, r7, 0
137 rtsd r15, 8 183 rtsd r15, 8
138 nop 184 nop
1394: or r3, r0, r0 185
1401: lbu r4,r6,r3 186 .section __ex_table,"a"
1412: sb r4,r5,r3 187 .word w1, 0f;
188 .word w2, 0f;
189 .text
190
191.align 4 /* Alignment is important to keep icache happy */
192page: /* Create room on stack and save registers for storign values */
193 addik r1, r1, -32
194 swi r19, r1, 4
195 swi r20, r1, 8
196 swi r21, r1, 12
197 swi r22, r1, 16
198 swi r23, r1, 20
199 swi r24, r1, 24
200 swi r25, r1, 28
201loop: /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */
202 /* Loop unrolling to get performance boost */
203 COPY_80(0x000);
204 COPY_80(0x080);
205 COPY_80(0x100);
206 COPY_80(0x180);
207 /* copy loop */
208 addik r6, r6, 0x200
209 addik r7, r7, -0x200
210 bneid r7, loop
211 addik r5, r5, 0x200
212 /* Restore register content */
213 lwi r19, r1, 4
214 lwi r20, r1, 8
215 lwi r21, r1, 12
216 lwi r22, r1, 16
217 lwi r23, r1, 20
218 lwi r24, r1, 24
219 lwi r25, r1, 28
220 addik r1, r1, 32
221 /* return back */
222 addik r3, r7, 0
223 rtsd r15, 8
224 nop
225
226.align 4 /* Alignment is important to keep icache happy */
227bu1: lbu r4,r6,r3
228bu2: sb r4,r5,r3
142 addik r7,r7,-1 229 addik r7,r7,-1
143 bneid r7,1b 230 bneid r7,bu1
144 addik r3,r3,1 /* delay slot */ 231 addik r3,r3,1 /* delay slot */
1453: 2320:
146 addik r3,r7,0 233 addik r3,r7,0
147 rtsd r15,8 234 rtsd r15,8
148 nop 235 nop
149 .size __copy_tofrom_user, . - __copy_tofrom_user 236 .size __copy_tofrom_user, . - __copy_tofrom_user
150 237
151 .section __ex_table,"a" 238 .section __ex_table,"a"
152 .word 1b,3b,2b,3b,5b,3b,6b,3b 239 .word bu1, 0b;
240 .word bu2, 0b;
241 .text
diff --git a/arch/microblaze/lib/ucmpdi2.c b/arch/microblaze/lib/ucmpdi2.c
new file mode 100644
index 000000000000..63ca105b6713
--- /dev/null
+++ b/arch/microblaze/lib/ucmpdi2.c
@@ -0,0 +1,20 @@
1#include <linux/module.h>
2
3#include "libgcc.h"
4
5word_type __ucmpdi2(unsigned long long a, unsigned long long b)
6{
7 const DWunion au = {.ll = a};
8 const DWunion bu = {.ll = b};
9
10 if ((unsigned int) au.s.high < (unsigned int) bu.s.high)
11 return 0;
12 else if ((unsigned int) au.s.high > (unsigned int) bu.s.high)
13 return 2;
14 if ((unsigned int) au.s.low < (unsigned int) bu.s.low)
15 return 0;
16 else if ((unsigned int) au.s.low > (unsigned int) bu.s.low)
17 return 2;
18 return 1;
19}
20EXPORT_SYMBOL(__ucmpdi2);