Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+220 -54
+18 -2
arch/microblaze/include/asm/dma-mapping.h
··· 28 28 #include <linux/dma-attrs.h> 29 29 #include <asm/io.h> 30 30 #include <asm-generic/dma-coherent.h> 31 + #include <asm/cacheflush.h> 31 32 32 33 #define DMA_ERROR_CODE (~(dma_addr_t)0x0) 33 34 34 35 #define __dma_alloc_coherent(dev, gfp, size, handle) NULL 35 36 #define __dma_free_coherent(size, addr) ((void)0) 36 - #define __dma_sync(addr, size, rw) ((void)0) 37 37 38 38 static inline unsigned long device_to_mask(struct device *dev) 39 39 { ··· 95 95 96 96 #include <asm-generic/dma-mapping-common.h> 97 97 98 + static 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 + 98 114 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) 99 115 { 100 116 struct dma_map_ops *ops = get_dma_ops(dev); ··· 151 135 enum dma_data_direction direction) 152 136 { 153 137 BUG_ON(direction == DMA_NONE); 154 - __dma_sync(vaddr, size, (int)direction); 138 + __dma_sync(virt_to_phys(vaddr), size, (int)direction); 155 139 } 156 140 157 141 #endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
+5 -3
arch/microblaze/include/asm/elf.h
··· 16 16 * I've snaffled the value from the microblaze binutils source code 17 17 * /binutils/microblaze/include/elf/microblaze.h 18 18 */ 19 - #define EM_XILINX_MICROBLAZE 0xbaab 20 - #define ELF_ARCH EM_XILINX_MICROBLAZE 19 + #define EM_MICROBLAZE 189 20 + #define EM_MICROBLAZE_OLD 0xbaab 21 + #define ELF_ARCH EM_MICROBLAZE 21 22 22 23 /* 23 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 30 * These are used to set parameters in the core dumps.
-9
arch/microblaze/include/asm/system.h
··· 17 17 #include <asm-generic/cmpxchg.h> 18 18 #include <asm-generic/cmpxchg-local.h> 19 19 20 - #define __ARCH_WANT_INTERRUPTS_ON_CTXSW 21 - 22 20 struct task_struct; 23 21 struct thread_info; 24 22 ··· 93 95 #endif 94 96 95 97 #define arch_align_stack(x) (x) 96 - 97 - /* 98 - * MicroBlaze doesn't handle unaligned accesses in hardware. 99 - * 100 - * Based on this we force the IP header alignment in network drivers. 101 - */ 102 - #define NET_IP_ALIGN 2 103 98 104 99 #endif /* _ASM_MICROBLAZE_SYSTEM_H */
+1 -1
arch/microblaze/include/asm/uaccess.h
··· 95 95 * - "addr", "addr + size" and "size" are all below the limit 96 96 */ 97 97 #define access_ok(type, addr, size) \ 98 - (get_fs().seg > (((unsigned long)(addr)) | \ 98 + (get_fs().seg >= (((unsigned long)(addr)) | \ 99 99 (size) | ((unsigned long)(addr) + (size)))) 100 100 101 101 /* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n",
+1
arch/microblaze/kernel/cpu/cpuinfo.c
··· 34 34 {"8.00.a", 0x12}, 35 35 {"8.00.b", 0x13}, 36 36 {"8.10.a", 0x14}, 37 + {"8.20.a", 0x15}, 37 38 {NULL, 0}, 38 39 }; 39 40
+63 -19
arch/microblaze/kernel/dma.c
··· 11 11 #include <linux/gfp.h> 12 12 #include <linux/dma-debug.h> 13 13 #include <asm/bug.h> 14 - #include <asm/cacheflush.h> 15 14 16 15 /* 17 16 * Generic direct DMA implementation ··· 20 21 * can set archdata.dma_data to an unsigned long holding the offset. By 21 22 * default the offset is PCI_DRAM_OFFSET. 22 23 */ 23 - static inline void __dma_sync_page(unsigned long paddr, unsigned long offset, 24 - size_t size, enum dma_data_direction direction) 25 - { 26 - switch (direction) { 27 - case DMA_TO_DEVICE: 28 - case DMA_BIDIRECTIONAL: 29 - flush_dcache_range(paddr + offset, paddr + offset + size); 30 - break; 31 - case DMA_FROM_DEVICE: 32 - invalidate_dcache_range(paddr + offset, paddr + offset + size); 33 - break; 34 - default: 35 - BUG(); 36 - } 37 - } 38 24 39 25 static unsigned long get_dma_direct_offset(struct device *dev) 40 26 { ··· 75 91 /* FIXME this part of code is untested */ 76 92 for_each_sg(sgl, sg, nents, i) { 77 93 sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev); 78 - __dma_sync_page(page_to_phys(sg_page(sg)), sg->offset, 94 + __dma_sync(page_to_phys(sg_page(sg)) + sg->offset, 79 95 sg->length, direction); 80 96 } 81 97 ··· 100 116 enum dma_data_direction direction, 101 117 struct dma_attrs *attrs) 102 118 { 103 - __dma_sync_page(page_to_phys(page), offset, size, direction); 119 + __dma_sync(page_to_phys(page) + offset, size, direction); 104 120 return page_to_phys(page) + offset + get_dma_direct_offset(dev); 105 121 } 106 122 ··· 115 131 * phys_to_virt is here because in __dma_sync_page is __virt_to_phys and 116 132 * dma_address is physical address 117 133 */ 118 - __dma_sync_page(dma_address, 0 , size, direction); 134 + __dma_sync(dma_address, size, direction); 135 + } 136 + 137 + static inline void 138 + dma_direct_sync_single_for_cpu(struct device *dev, 139 + dma_addr_t dma_handle, size_t size, 140 + enum dma_data_direction direction) 141 + { 142 + /* 143 + * It's pointless to flush the cache as the memory segment 144 + * is given to the CPU 145 + */ 146 + 147 + if (direction == DMA_FROM_DEVICE) 148 + __dma_sync(dma_handle, size, direction); 149 + } 150 + 151 + static inline void 152 + dma_direct_sync_single_for_device(struct device *dev, 153 + dma_addr_t dma_handle, size_t size, 154 + enum dma_data_direction direction) 155 + { 156 + /* 157 + * It's pointless to invalidate the cache if the device isn't 158 + * supposed to write to the relevant region 159 + */ 160 + 161 + if (direction == DMA_TO_DEVICE) 162 + __dma_sync(dma_handle, size, direction); 163 + } 164 + 165 + static inline void 166 + dma_direct_sync_sg_for_cpu(struct device *dev, 167 + struct scatterlist *sgl, int nents, 168 + enum dma_data_direction direction) 169 + { 170 + struct scatterlist *sg; 171 + int i; 172 + 173 + /* FIXME this part of code is untested */ 174 + if (direction == DMA_FROM_DEVICE) 175 + for_each_sg(sgl, sg, nents, i) 176 + __dma_sync(sg->dma_address, sg->length, direction); 177 + } 178 + 179 + static inline void 180 + dma_direct_sync_sg_for_device(struct device *dev, 181 + struct scatterlist *sgl, int nents, 182 + enum dma_data_direction direction) 183 + { 184 + struct scatterlist *sg; 185 + int i; 186 + 187 + /* FIXME this part of code is untested */ 188 + if (direction == DMA_TO_DEVICE) 189 + for_each_sg(sgl, sg, nents, i) 190 + __dma_sync(sg->dma_address, sg->length, direction); 119 191 } 120 192 121 193 struct dma_map_ops dma_direct_ops = { ··· 182 142 .dma_supported = dma_direct_dma_supported, 183 143 .map_page = dma_direct_map_page, 184 144 .unmap_page = dma_direct_unmap_page, 145 + .sync_single_for_cpu = dma_direct_sync_single_for_cpu, 146 + .sync_single_for_device = dma_direct_sync_single_for_device, 147 + .sync_sg_for_cpu = dma_direct_sync_sg_for_cpu, 148 + .sync_sg_for_device = dma_direct_sync_sg_for_device, 185 149 }; 186 150 EXPORT_SYMBOL(dma_direct_ops); 187 151
+1 -1
arch/microblaze/kernel/exceptions.c
··· 119 119 case MICROBLAZE_DIV_ZERO_EXCEPTION: 120 120 if (user_mode(regs)) { 121 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 123 return; 124 124 } 125 125 printk(KERN_WARNING "Divide by zero exception " \
+1
arch/microblaze/kernel/process.c
··· 179 179 180 180 ti->cpu_context.msr = (childregs->msr|MSR_VM); 181 181 ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */ 182 + ti->cpu_context.msr &= ~MSR_IE; 182 183 #endif 183 184 ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8; 184 185
+1 -1
arch/microblaze/kernel/ptrace.c
··· 148 148 ret = -1L; 149 149 150 150 if (unlikely(current->audit_context)) 151 - audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12, 151 + audit_syscall_entry(EM_MICROBLAZE, regs->r12, 152 152 regs->r5, regs->r6, 153 153 regs->r7, regs->r8); 154 154
+2 -1
arch/microblaze/kernel/timer.c
··· 308 308 { 309 309 if (timer_initialized) { 310 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 313 return clocksource_cyc2ns(cyc, cs->mult, cs->shift); 313 314 } 314 315 return 0;
+1
arch/microblaze/lib/Makefile
··· 25 25 lib-y += modsi3.o 26 26 lib-y += muldi3.o 27 27 lib-y += mulsi3.o 28 + lib-y += ucmpdi2.o 28 29 lib-y += udivsi3.o 29 30 lib-y += umodsi3.o
+106 -17
arch/microblaze/lib/uaccess_old.S
··· 10 10 11 11 #include <linux/errno.h> 12 12 #include <linux/linkage.h> 13 + #include <asm/page.h> 13 14 14 15 /* 15 16 * int __strncpy_user(char *to, char *from, int len); ··· 34 33 * r3 - temp count 35 34 * r4 - temp val 36 35 */ 36 + beqid r7,3f 37 37 addik r3,r7,0 /* temp_count = len */ 38 - beqi r3,3f 39 38 1: 40 39 lbu r4,r6,r0 41 40 sb r4,r5,r0 ··· 77 76 .type __strnlen_user, @function 78 77 .align 4; 79 78 __strnlen_user: 79 + beqid r6,3f 80 80 addik r3,r6,0 81 - beqi r3,3f 82 81 1: 83 82 lbu r4,r5,r0 84 83 beqid r4,2f /* break on NUL */ ··· 103 102 .section __ex_table,"a" 104 103 .word 1b,4b 105 104 105 + /* Loop unrolling for __copy_tofrom_user */ 106 + #define COPY(offset) \ 107 + 1: lwi r4 , r6, 0x0000 + offset; \ 108 + 2: lwi r19, r6, 0x0004 + offset; \ 109 + 3: lwi r20, r6, 0x0008 + offset; \ 110 + 4: lwi r21, r6, 0x000C + offset; \ 111 + 5: lwi r22, r6, 0x0010 + offset; \ 112 + 6: lwi r23, r6, 0x0014 + offset; \ 113 + 7: lwi r24, r6, 0x0018 + offset; \ 114 + 8: lwi r25, r6, 0x001C + offset; \ 115 + 9: swi r4 , r5, 0x0000 + offset; \ 116 + 10: swi r19, r5, 0x0004 + offset; \ 117 + 11: swi r20, r5, 0x0008 + offset; \ 118 + 12: swi r21, r5, 0x000C + offset; \ 119 + 13: swi r22, r5, 0x0010 + offset; \ 120 + 14: swi r23, r5, 0x0014 + offset; \ 121 + 15: swi r24, r5, 0x0018 + offset; \ 122 + 16: swi r25, r5, 0x001C + offset; \ 123 + .section __ex_table,"a"; \ 124 + .word 1b, 0f; \ 125 + .word 2b, 0f; \ 126 + .word 3b, 0f; \ 127 + .word 4b, 0f; \ 128 + .word 5b, 0f; \ 129 + .word 6b, 0f; \ 130 + .word 7b, 0f; \ 131 + .word 8b, 0f; \ 132 + .word 9b, 0f; \ 133 + .word 10b, 0f; \ 134 + .word 11b, 0f; \ 135 + .word 12b, 0f; \ 136 + .word 13b, 0f; \ 137 + .word 14b, 0f; \ 138 + .word 15b, 0f; \ 139 + .word 16b, 0f; \ 140 + .text 141 + 142 + #define COPY_80(offset) \ 143 + COPY(0x00 + offset);\ 144 + COPY(0x20 + offset);\ 145 + COPY(0x40 + offset);\ 146 + COPY(0x60 + offset); 147 + 106 148 /* 107 149 * int __copy_tofrom_user(char *to, char *from, int len) 108 150 * Return: ··· 163 119 * r7, r3 - count 164 120 * r4 - tempval 165 121 */ 166 - beqid r7, 3f /* zero size is not likely */ 167 - andi r3, r7, 0x3 /* filter add count */ 168 - bneid r3, 4f /* if is odd value then byte copying */ 122 + beqid r7, 0f /* zero size is not likely */ 169 123 or r3, r5, r6 /* find if is any to/from unaligned */ 170 - andi r3, r3, 0x3 /* mask unaligned */ 171 - bneid r3, 1f /* it is unaligned -> then jump */ 124 + or r3, r3, r7 /* find if count is unaligned */ 125 + andi r3, r3, 0x3 /* mask last 3 bits */ 126 + bneid r3, bu1 /* if r3 is not zero then byte copying */ 172 127 or r3, r0, r0 173 128 174 - /* at least one 4 byte copy */ 175 - 5: lw r4, r6, r3 176 - 6: sw r4, r5, r3 129 + rsubi r3, r7, PAGE_SIZE /* detect PAGE_SIZE */ 130 + beqid r3, page; 131 + or r3, r0, r0 132 + 133 + w1: lw r4, r6, r3 /* at least one 4 byte copy */ 134 + w2: sw r4, r5, r3 177 135 addik r7, r7, -4 178 - bneid r7, 5b 136 + bneid r7, w1 179 137 addik r3, r3, 4 180 138 addik r3, r7, 0 181 139 rtsd r15, 8 182 140 nop 183 - 4: or r3, r0, r0 184 - 1: lbu r4,r6,r3 185 - 2: sb r4,r5,r3 141 + 142 + .section __ex_table,"a" 143 + .word w1, 0f; 144 + .word w2, 0f; 145 + .text 146 + 147 + .align 4 /* Alignment is important to keep icache happy */ 148 + page: /* Create room on stack and save registers for storign values */ 149 + addik r1, r1, -32 150 + swi r19, r1, 4 151 + swi r20, r1, 8 152 + swi r21, r1, 12 153 + swi r22, r1, 16 154 + swi r23, r1, 20 155 + swi r24, r1, 24 156 + swi r25, r1, 28 157 + loop: /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */ 158 + /* Loop unrolling to get performance boost */ 159 + COPY_80(0x000); 160 + COPY_80(0x080); 161 + COPY_80(0x100); 162 + COPY_80(0x180); 163 + /* copy loop */ 164 + addik r6, r6, 0x200 165 + addik r7, r7, -0x200 166 + bneid r7, loop 167 + addik r5, r5, 0x200 168 + /* Restore register content */ 169 + lwi r19, r1, 4 170 + lwi r20, r1, 8 171 + lwi r21, r1, 12 172 + lwi r22, r1, 16 173 + lwi r23, r1, 20 174 + lwi r24, r1, 24 175 + lwi r25, r1, 28 176 + addik r1, r1, 32 177 + /* return back */ 178 + addik r3, r7, 0 179 + rtsd r15, 8 180 + nop 181 + 182 + .align 4 /* Alignment is important to keep icache happy */ 183 + bu1: lbu r4,r6,r3 184 + bu2: sb r4,r5,r3 186 185 addik r7,r7,-1 187 - bneid r7,1b 186 + bneid r7,bu1 188 187 addik r3,r3,1 /* delay slot */ 189 - 3: 188 + 0: 190 189 addik r3,r7,0 191 190 rtsd r15,8 192 191 nop 193 192 .size __copy_tofrom_user, . - __copy_tofrom_user 194 193 195 194 .section __ex_table,"a" 196 - .word 1b,3b,2b,3b,5b,3b,6b,3b 195 + .word bu1, 0b; 196 + .word bu2, 0b; 197 + .text
+20
arch/microblaze/lib/ucmpdi2.c
··· 1 + #include <linux/module.h> 2 + 3 + #include "libgcc.h" 4 + 5 + word_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 + } 20 + EXPORT_SYMBOL(__ucmpdi2);