diff options
| -rw-r--r-- | arch/sparc/include/asm/pgtable_32.h | 20 | ||||
| -rw-r--r-- | arch/sparc/include/asm/pgtable_64.h | 20 | ||||
| -rw-r--r-- | arch/sparc/kernel/entry.h | 7 | ||||
| -rw-r--r-- | arch/sparc/kernel/module.c | 27 | ||||
| -rw-r--r-- | arch/sparc/kernel/setup_64.c | 48 | ||||
| -rw-r--r-- | arch/sparc/kernel/signal32.c | 18 | ||||
| -rw-r--r-- | arch/sparc/kernel/signal_32.c | 30 | ||||
| -rw-r--r-- | arch/sparc/kernel/signal_64.c | 42 | ||||
| -rw-r--r-- | arch/sparc/kernel/sigutil_64.c | 1 | ||||
| -rw-r--r-- | arch/sparc/mm/Makefile | 1 | ||||
| -rw-r--r-- | arch/sparc/mm/generic_32.c | 99 | ||||
| -rw-r--r-- | arch/sparc/mm/generic_64.c | 165 |
12 files changed, 159 insertions, 319 deletions
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 5b31a8e89823..a790cc657476 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h | |||
| @@ -431,10 +431,6 @@ extern unsigned long *sparc_valid_addr_bitmap; | |||
| 431 | #define kern_addr_valid(addr) \ | 431 | #define kern_addr_valid(addr) \ |
| 432 | (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) | 432 | (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) |
| 433 | 433 | ||
| 434 | extern int io_remap_pfn_range(struct vm_area_struct *vma, | ||
| 435 | unsigned long from, unsigned long pfn, | ||
| 436 | unsigned long size, pgprot_t prot); | ||
| 437 | |||
| 438 | /* | 434 | /* |
| 439 | * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in | 435 | * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in |
| 440 | * its high 4 bits. These macros/functions put it there or get it from there. | 436 | * its high 4 bits. These macros/functions put it there or get it from there. |
| @@ -443,6 +439,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, | |||
| 443 | #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) | 439 | #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) |
| 444 | #define GET_PFN(pfn) (pfn & 0x0fffffffUL) | 440 | #define GET_PFN(pfn) (pfn & 0x0fffffffUL) |
| 445 | 441 | ||
| 442 | extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, | ||
| 443 | unsigned long, pgprot_t); | ||
| 444 | |||
| 445 | static inline int io_remap_pfn_range(struct vm_area_struct *vma, | ||
| 446 | unsigned long from, unsigned long pfn, | ||
| 447 | unsigned long size, pgprot_t prot) | ||
| 448 | { | ||
| 449 | unsigned long long offset, space, phys_base; | ||
| 450 | |||
| 451 | offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT; | ||
| 452 | space = GET_IOSPACE(pfn); | ||
| 453 | phys_base = offset | (space << 32ULL); | ||
| 454 | |||
| 455 | return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot); | ||
| 456 | } | ||
| 457 | |||
| 446 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | 458 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS |
| 447 | #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ | 459 | #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ |
| 448 | ({ \ | 460 | ({ \ |
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index adf89329af59..38ebb2c60137 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h | |||
| @@ -757,10 +757,6 @@ static inline bool kern_addr_valid(unsigned long addr) | |||
| 757 | 757 | ||
| 758 | extern int page_in_phys_avail(unsigned long paddr); | 758 | extern int page_in_phys_avail(unsigned long paddr); |
| 759 | 759 | ||
| 760 | extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, | ||
| 761 | unsigned long pfn, | ||
| 762 | unsigned long size, pgprot_t prot); | ||
| 763 | |||
| 764 | /* | 760 | /* |
| 765 | * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in | 761 | * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in |
| 766 | * its high 4 bits. These macros/functions put it there or get it from there. | 762 | * its high 4 bits. These macros/functions put it there or get it from there. |
| @@ -769,6 +765,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, | |||
| 769 | #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) | 765 | #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) |
| 770 | #define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL) | 766 | #define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL) |
| 771 | 767 | ||
| 768 | extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, | ||
| 769 | unsigned long, pgprot_t); | ||
| 770 | |||
| 771 | static inline int io_remap_pfn_range(struct vm_area_struct *vma, | ||
| 772 | unsigned long from, unsigned long pfn, | ||
| 773 | unsigned long size, pgprot_t prot) | ||
| 774 | { | ||
| 775 | unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; | ||
| 776 | int space = GET_IOSPACE(pfn); | ||
| 777 | unsigned long phys_base; | ||
| 778 | |||
| 779 | phys_base = offset | (((unsigned long) space) << 32UL); | ||
| 780 | |||
| 781 | return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot); | ||
| 782 | } | ||
| 783 | |||
| 772 | #include <asm-generic/pgtable.h> | 784 | #include <asm-generic/pgtable.h> |
| 773 | 785 | ||
| 774 | /* We provide our own get_unmapped_area to cope with VA holes and | 786 | /* We provide our own get_unmapped_area to cope with VA holes and |
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h index e27f8ea8656e..0c218e4c0881 100644 --- a/arch/sparc/kernel/entry.h +++ b/arch/sparc/kernel/entry.h | |||
| @@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, | |||
| 42 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); | 42 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); |
| 43 | 43 | ||
| 44 | #else /* CONFIG_SPARC32 */ | 44 | #else /* CONFIG_SPARC32 */ |
| 45 | |||
| 46 | #include <asm/trap_block.h> | ||
| 47 | |||
| 45 | struct popc_3insn_patch_entry { | 48 | struct popc_3insn_patch_entry { |
| 46 | unsigned int addr; | 49 | unsigned int addr; |
| 47 | unsigned int insns[3]; | 50 | unsigned int insns[3]; |
| @@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch, | |||
| 57 | __popc_6insn_patch_end; | 60 | __popc_6insn_patch_end; |
| 58 | 61 | ||
| 59 | extern void __init per_cpu_patch(void); | 62 | extern void __init per_cpu_patch(void); |
| 63 | extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, | ||
| 64 | struct sun4v_1insn_patch_entry *); | ||
| 65 | extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, | ||
| 66 | struct sun4v_2insn_patch_entry *); | ||
| 60 | extern void __init sun4v_patch(void); | 67 | extern void __init sun4v_patch(void); |
| 61 | extern void __init boot_cpu_id_too_large(int cpu); | 68 | extern void __init boot_cpu_id_too_large(int cpu); |
| 62 | extern unsigned int dcache_parity_tl1_occurred; | 69 | extern unsigned int dcache_parity_tl1_occurred; |
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index da0c6c70ccb2..e5519870c3d9 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
| 18 | #include <asm/spitfire.h> | 18 | #include <asm/spitfire.h> |
| 19 | 19 | ||
| 20 | #include "entry.h" | ||
| 21 | |||
| 20 | #ifdef CONFIG_SPARC64 | 22 | #ifdef CONFIG_SPARC64 |
| 21 | 23 | ||
| 22 | #include <linux/jump_label.h> | 24 | #include <linux/jump_label.h> |
| @@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs, | |||
| 203 | } | 205 | } |
| 204 | 206 | ||
| 205 | #ifdef CONFIG_SPARC64 | 207 | #ifdef CONFIG_SPARC64 |
| 208 | static void do_patch_sections(const Elf_Ehdr *hdr, | ||
| 209 | const Elf_Shdr *sechdrs) | ||
| 210 | { | ||
| 211 | const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL; | ||
| 212 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
| 213 | |||
| 214 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | ||
| 215 | if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name)) | ||
| 216 | sun4v_1insn = s; | ||
| 217 | if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name)) | ||
| 218 | sun4v_2insn = s; | ||
| 219 | } | ||
| 220 | |||
| 221 | if (sun4v_1insn && tlb_type == hypervisor) { | ||
| 222 | void *p = (void *) sun4v_1insn->sh_addr; | ||
| 223 | sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size); | ||
| 224 | } | ||
| 225 | if (sun4v_2insn && tlb_type == hypervisor) { | ||
| 226 | void *p = (void *) sun4v_2insn->sh_addr; | ||
| 227 | sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 206 | int module_finalize(const Elf_Ehdr *hdr, | 231 | int module_finalize(const Elf_Ehdr *hdr, |
| 207 | const Elf_Shdr *sechdrs, | 232 | const Elf_Shdr *sechdrs, |
| 208 | struct module *me) | 233 | struct module *me) |
| @@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
| 210 | /* make jump label nops */ | 235 | /* make jump label nops */ |
| 211 | jump_label_apply_nops(me); | 236 | jump_label_apply_nops(me); |
| 212 | 237 | ||
| 238 | do_patch_sections(hdr, sechdrs); | ||
| 239 | |||
| 213 | /* Cheetah's I-cache is fully coherent. */ | 240 | /* Cheetah's I-cache is fully coherent. */ |
| 214 | if (tlb_type == spitfire) { | 241 | if (tlb_type == spitfire) { |
| 215 | unsigned long va; | 242 | unsigned long va; |
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index c965595aa7e9..a854a1c240ff 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c | |||
| @@ -234,40 +234,50 @@ void __init per_cpu_patch(void) | |||
| 234 | } | 234 | } |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | void __init sun4v_patch(void) | 237 | void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start, |
| 238 | struct sun4v_1insn_patch_entry *end) | ||
| 238 | { | 239 | { |
| 239 | extern void sun4v_hvapi_init(void); | 240 | while (start < end) { |
| 240 | struct sun4v_1insn_patch_entry *p1; | 241 | unsigned long addr = start->addr; |
| 241 | struct sun4v_2insn_patch_entry *p2; | ||
| 242 | |||
| 243 | if (tlb_type != hypervisor) | ||
| 244 | return; | ||
| 245 | 242 | ||
| 246 | p1 = &__sun4v_1insn_patch; | 243 | *(unsigned int *) (addr + 0) = start->insn; |
| 247 | while (p1 < &__sun4v_1insn_patch_end) { | ||
| 248 | unsigned long addr = p1->addr; | ||
| 249 | |||
| 250 | *(unsigned int *) (addr + 0) = p1->insn; | ||
| 251 | wmb(); | 244 | wmb(); |
| 252 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | 245 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); |
| 253 | 246 | ||
| 254 | p1++; | 247 | start++; |
| 255 | } | 248 | } |
| 249 | } | ||
| 256 | 250 | ||
| 257 | p2 = &__sun4v_2insn_patch; | 251 | void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start, |
| 258 | while (p2 < &__sun4v_2insn_patch_end) { | 252 | struct sun4v_2insn_patch_entry *end) |
| 259 | unsigned long addr = p2->addr; | 253 | { |
| 254 | while (start < end) { | ||
| 255 | unsigned long addr = start->addr; | ||
| 260 | 256 | ||
| 261 | *(unsigned int *) (addr + 0) = p2->insns[0]; | 257 | *(unsigned int *) (addr + 0) = start->insns[0]; |
| 262 | wmb(); | 258 | wmb(); |
| 263 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | 259 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); |
| 264 | 260 | ||
| 265 | *(unsigned int *) (addr + 4) = p2->insns[1]; | 261 | *(unsigned int *) (addr + 4) = start->insns[1]; |
| 266 | wmb(); | 262 | wmb(); |
| 267 | __asm__ __volatile__("flush %0" : : "r" (addr + 4)); | 263 | __asm__ __volatile__("flush %0" : : "r" (addr + 4)); |
| 268 | 264 | ||
| 269 | p2++; | 265 | start++; |
| 270 | } | 266 | } |
| 267 | } | ||
| 268 | |||
| 269 | void __init sun4v_patch(void) | ||
| 270 | { | ||
| 271 | extern void sun4v_hvapi_init(void); | ||
| 272 | |||
| 273 | if (tlb_type != hypervisor) | ||
| 274 | return; | ||
| 275 | |||
| 276 | sun4v_patch_1insn_range(&__sun4v_1insn_patch, | ||
| 277 | &__sun4v_1insn_patch_end); | ||
| 278 | |||
| 279 | sun4v_patch_2insn_range(&__sun4v_2insn_patch, | ||
| 280 | &__sun4v_2insn_patch_end); | ||
| 271 | 281 | ||
| 272 | sun4v_hvapi_init(); | 282 | sun4v_hvapi_init(); |
| 273 | } | 283 | } |
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 2caa556db86d..023b8860dc97 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c | |||
| @@ -822,21 +822,23 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs | |||
| 822 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 822 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 823 | * mistake. | 823 | * mistake. |
| 824 | */ | 824 | */ |
| 825 | void do_signal32(sigset_t *oldset, struct pt_regs * regs, | 825 | void do_signal32(sigset_t *oldset, struct pt_regs * regs) |
| 826 | int restart_syscall, unsigned long orig_i0) | ||
| 827 | { | 826 | { |
| 828 | struct k_sigaction ka; | 827 | struct k_sigaction ka; |
| 828 | unsigned long orig_i0; | ||
| 829 | int restart_syscall; | ||
| 829 | siginfo_t info; | 830 | siginfo_t info; |
| 830 | int signr; | 831 | int signr; |
| 831 | 832 | ||
| 832 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 833 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 833 | 834 | ||
| 834 | /* If the debugger messes with the program counter, it clears | 835 | restart_syscall = 0; |
| 835 | * the "in syscall" bit, directing us to not perform a syscall | 836 | orig_i0 = 0; |
| 836 | * restart. | 837 | if (pt_regs_is_syscall(regs) && |
| 837 | */ | 838 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { |
| 838 | if (restart_syscall && !pt_regs_is_syscall(regs)) | 839 | restart_syscall = 1; |
| 839 | restart_syscall = 0; | 840 | orig_i0 = regs->u_regs[UREG_G6]; |
| 841 | } | ||
| 840 | 842 | ||
| 841 | if (signr > 0) { | 843 | if (signr > 0) { |
| 842 | if (restart_syscall) | 844 | if (restart_syscall) |
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 8ce247ac04cc..d54c6e53aba0 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c | |||
| @@ -519,10 +519,26 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
| 519 | siginfo_t info; | 519 | siginfo_t info; |
| 520 | int signr; | 520 | int signr; |
| 521 | 521 | ||
| 522 | /* It's a lot of work and synchronization to add a new ptrace | ||
| 523 | * register for GDB to save and restore in order to get | ||
| 524 | * orig_i0 correct for syscall restarts when debugging. | ||
| 525 | * | ||
| 526 | * Although it should be the case that most of the global | ||
| 527 | * registers are volatile across a system call, glibc already | ||
| 528 | * depends upon that fact that we preserve them. So we can't | ||
| 529 | * just use any global register to save away the orig_i0 value. | ||
| 530 | * | ||
| 531 | * In particular %g2, %g3, %g4, and %g5 are all assumed to be | ||
| 532 | * preserved across a system call trap by various pieces of | ||
| 533 | * code in glibc. | ||
| 534 | * | ||
| 535 | * %g7 is used as the "thread register". %g6 is not used in | ||
| 536 | * any fixed manner. %g6 is used as a scratch register and | ||
| 537 | * a compiler temporary, but it's value is never used across | ||
| 538 | * a system call. Therefore %g6 is usable for orig_i0 storage. | ||
| 539 | */ | ||
| 522 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) | 540 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) |
| 523 | restart_syscall = 1; | 541 | regs->u_regs[UREG_G6] = orig_i0; |
| 524 | else | ||
| 525 | restart_syscall = 0; | ||
| 526 | 542 | ||
| 527 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 543 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 528 | oldset = ¤t->saved_sigmask; | 544 | oldset = ¤t->saved_sigmask; |
| @@ -535,8 +551,12 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
| 535 | * the software "in syscall" bit, directing us to not perform | 551 | * the software "in syscall" bit, directing us to not perform |
| 536 | * a syscall restart. | 552 | * a syscall restart. |
| 537 | */ | 553 | */ |
| 538 | if (restart_syscall && !pt_regs_is_syscall(regs)) | 554 | restart_syscall = 0; |
| 539 | restart_syscall = 0; | 555 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { |
| 556 | restart_syscall = 1; | ||
| 557 | orig_i0 = regs->u_regs[UREG_G6]; | ||
| 558 | } | ||
| 559 | |||
| 540 | 560 | ||
| 541 | if (signr > 0) { | 561 | if (signr > 0) { |
| 542 | if (restart_syscall) | 562 | if (restart_syscall) |
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index a2b81598d905..f0836cd0e2f2 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c | |||
| @@ -529,11 +529,27 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
| 529 | siginfo_t info; | 529 | siginfo_t info; |
| 530 | int signr; | 530 | int signr; |
| 531 | 531 | ||
| 532 | /* It's a lot of work and synchronization to add a new ptrace | ||
| 533 | * register for GDB to save and restore in order to get | ||
| 534 | * orig_i0 correct for syscall restarts when debugging. | ||
| 535 | * | ||
| 536 | * Although it should be the case that most of the global | ||
| 537 | * registers are volatile across a system call, glibc already | ||
| 538 | * depends upon that fact that we preserve them. So we can't | ||
| 539 | * just use any global register to save away the orig_i0 value. | ||
| 540 | * | ||
| 541 | * In particular %g2, %g3, %g4, and %g5 are all assumed to be | ||
| 542 | * preserved across a system call trap by various pieces of | ||
| 543 | * code in glibc. | ||
| 544 | * | ||
| 545 | * %g7 is used as the "thread register". %g6 is not used in | ||
| 546 | * any fixed manner. %g6 is used as a scratch register and | ||
| 547 | * a compiler temporary, but it's value is never used across | ||
| 548 | * a system call. Therefore %g6 is usable for orig_i0 storage. | ||
| 549 | */ | ||
| 532 | if (pt_regs_is_syscall(regs) && | 550 | if (pt_regs_is_syscall(regs) && |
| 533 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { | 551 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) |
| 534 | restart_syscall = 1; | 552 | regs->u_regs[UREG_G6] = orig_i0; |
| 535 | } else | ||
| 536 | restart_syscall = 0; | ||
| 537 | 553 | ||
| 538 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) | 554 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
| 539 | oldset = ¤t->saved_sigmask; | 555 | oldset = ¤t->saved_sigmask; |
| @@ -542,22 +558,20 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
| 542 | 558 | ||
| 543 | #ifdef CONFIG_COMPAT | 559 | #ifdef CONFIG_COMPAT |
| 544 | if (test_thread_flag(TIF_32BIT)) { | 560 | if (test_thread_flag(TIF_32BIT)) { |
| 545 | extern void do_signal32(sigset_t *, struct pt_regs *, | 561 | extern void do_signal32(sigset_t *, struct pt_regs *); |
| 546 | int restart_syscall, | 562 | do_signal32(oldset, regs); |
| 547 | unsigned long orig_i0); | ||
| 548 | do_signal32(oldset, regs, restart_syscall, orig_i0); | ||
| 549 | return; | 563 | return; |
| 550 | } | 564 | } |
| 551 | #endif | 565 | #endif |
| 552 | 566 | ||
| 553 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 567 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 554 | 568 | ||
| 555 | /* If the debugger messes with the program counter, it clears | 569 | restart_syscall = 0; |
| 556 | * the software "in syscall" bit, directing us to not perform | 570 | if (pt_regs_is_syscall(regs) && |
| 557 | * a syscall restart. | 571 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { |
| 558 | */ | 572 | restart_syscall = 1; |
| 559 | if (restart_syscall && !pt_regs_is_syscall(regs)) | 573 | orig_i0 = regs->u_regs[UREG_G6]; |
| 560 | restart_syscall = 0; | 574 | } |
| 561 | 575 | ||
| 562 | if (signr > 0) { | 576 | if (signr > 0) { |
| 563 | if (restart_syscall) | 577 | if (restart_syscall) |
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c index e7dc508c38eb..b19570d41a39 100644 --- a/arch/sparc/kernel/sigutil_64.c +++ b/arch/sparc/kernel/sigutil_64.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include <linux/types.h> | 2 | #include <linux/types.h> |
| 3 | #include <linux/thread_info.h> | 3 | #include <linux/thread_info.h> |
| 4 | #include <linux/uaccess.h> | 4 | #include <linux/uaccess.h> |
| 5 | #include <linux/errno.h> | ||
| 5 | 6 | ||
| 6 | #include <asm/sigcontext.h> | 7 | #include <asm/sigcontext.h> |
| 7 | #include <asm/fpumacro.h> | 8 | #include <asm/fpumacro.h> |
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index e3cda21b5ee9..301421c11291 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile | |||
| @@ -8,7 +8,6 @@ obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o | |||
| 8 | obj-y += fault_$(BITS).o | 8 | obj-y += fault_$(BITS).o |
| 9 | obj-y += init_$(BITS).o | 9 | obj-y += init_$(BITS).o |
| 10 | obj-$(CONFIG_SPARC32) += loadmmu.o | 10 | obj-$(CONFIG_SPARC32) += loadmmu.o |
| 11 | obj-y += generic_$(BITS).o | ||
| 12 | obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o | 11 | obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o |
| 13 | obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o | 12 | obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o |
| 14 | obj-$(CONFIG_SPARC_LEON)+= leon_mm.o | 13 | obj-$(CONFIG_SPARC_LEON)+= leon_mm.o |
diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c deleted file mode 100644 index 6ca39a60a196..000000000000 --- a/arch/sparc/mm/generic_32.c +++ /dev/null | |||
| @@ -1,99 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * generic.c: Generic Sparc mm routines that are not dependent upon | ||
| 3 | * MMU type but are Sparc specific. | ||
| 4 | * | ||
| 5 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/swap.h> | ||
| 11 | #include <linux/pagemap.h> | ||
| 12 | #include <linux/export.h> | ||
| 13 | |||
| 14 | #include <asm/pgalloc.h> | ||
| 15 | #include <asm/pgtable.h> | ||
| 16 | #include <asm/page.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include <asm/tlbflush.h> | ||
| 19 | |||
| 20 | /* Remap IO memory, the same way as remap_pfn_range(), but use | ||
| 21 | * the obio memory space. | ||
| 22 | * | ||
| 23 | * They use a pgprot that sets PAGE_IO and does not check the | ||
| 24 | * mem_map table as this is independent of normal memory. | ||
| 25 | */ | ||
| 26 | static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size, | ||
| 27 | unsigned long offset, pgprot_t prot, int space) | ||
| 28 | { | ||
| 29 | unsigned long end; | ||
| 30 | |||
| 31 | address &= ~PMD_MASK; | ||
| 32 | end = address + size; | ||
| 33 | if (end > PMD_SIZE) | ||
| 34 | end = PMD_SIZE; | ||
| 35 | do { | ||
| 36 | set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space)); | ||
| 37 | address += PAGE_SIZE; | ||
| 38 | offset += PAGE_SIZE; | ||
| 39 | pte++; | ||
| 40 | } while (address < end); | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, | ||
| 44 | unsigned long offset, pgprot_t prot, int space) | ||
| 45 | { | ||
| 46 | unsigned long end; | ||
| 47 | |||
| 48 | address &= ~PGDIR_MASK; | ||
| 49 | end = address + size; | ||
| 50 | if (end > PGDIR_SIZE) | ||
| 51 | end = PGDIR_SIZE; | ||
| 52 | offset -= address; | ||
| 53 | do { | ||
| 54 | pte_t *pte = pte_alloc_map(mm, NULL, pmd, address); | ||
| 55 | if (!pte) | ||
| 56 | return -ENOMEM; | ||
| 57 | io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space); | ||
| 58 | address = (address + PMD_SIZE) & PMD_MASK; | ||
| 59 | pmd++; | ||
| 60 | } while (address < end); | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, | ||
| 65 | unsigned long pfn, unsigned long size, pgprot_t prot) | ||
| 66 | { | ||
| 67 | int error = 0; | ||
| 68 | pgd_t * dir; | ||
| 69 | unsigned long beg = from; | ||
| 70 | unsigned long end = from + size; | ||
| 71 | struct mm_struct *mm = vma->vm_mm; | ||
| 72 | int space = GET_IOSPACE(pfn); | ||
| 73 | unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; | ||
| 74 | |||
| 75 | /* See comment in mm/memory.c remap_pfn_range */ | ||
| 76 | vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; | ||
| 77 | vma->vm_pgoff = (offset >> PAGE_SHIFT) | | ||
| 78 | ((unsigned long)space << 28UL); | ||
| 79 | |||
| 80 | offset -= from; | ||
| 81 | dir = pgd_offset(mm, from); | ||
| 82 | flush_cache_range(vma, beg, end); | ||
| 83 | |||
| 84 | while (from < end) { | ||
| 85 | pmd_t *pmd = pmd_alloc(mm, dir, from); | ||
| 86 | error = -ENOMEM; | ||
| 87 | if (!pmd) | ||
| 88 | break; | ||
| 89 | error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space); | ||
| 90 | if (error) | ||
| 91 | break; | ||
| 92 | from = (from + PGDIR_SIZE) & PGDIR_MASK; | ||
| 93 | dir++; | ||
| 94 | } | ||
| 95 | |||
| 96 | flush_tlb_range(vma, beg, end); | ||
| 97 | return error; | ||
| 98 | } | ||
| 99 | EXPORT_SYMBOL(io_remap_pfn_range); | ||
diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c deleted file mode 100644 index 9b357ddae39d..000000000000 --- a/arch/sparc/mm/generic_64.c +++ /dev/null | |||
| @@ -1,165 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * generic.c: Generic Sparc mm routines that are not dependent upon | ||
| 3 | * MMU type but are Sparc specific. | ||
| 4 | * | ||
| 5 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/swap.h> | ||
| 11 | #include <linux/export.h> | ||
| 12 | #include <linux/pagemap.h> | ||
| 13 | |||
| 14 | #include <asm/pgalloc.h> | ||
| 15 | #include <asm/pgtable.h> | ||
| 16 | #include <asm/page.h> | ||
| 17 | #include <asm/tlbflush.h> | ||
| 18 | |||
| 19 | /* Remap IO memory, the same way as remap_pfn_range(), but use | ||
| 20 | * the obio memory space. | ||
| 21 | * | ||
| 22 | * They use a pgprot that sets PAGE_IO and does not check the | ||
| 23 | * mem_map table as this is independent of normal memory. | ||
| 24 | */ | ||
| 25 | static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, | ||
| 26 | unsigned long address, | ||
| 27 | unsigned long size, | ||
| 28 | unsigned long offset, pgprot_t prot, | ||
| 29 | int space) | ||
| 30 | { | ||
| 31 | unsigned long end; | ||
| 32 | |||
| 33 | /* clear hack bit that was used as a write_combine side-effect flag */ | ||
| 34 | offset &= ~0x1UL; | ||
| 35 | address &= ~PMD_MASK; | ||
| 36 | end = address + size; | ||
| 37 | if (end > PMD_SIZE) | ||
| 38 | end = PMD_SIZE; | ||
| 39 | do { | ||
| 40 | pte_t entry; | ||
| 41 | unsigned long curend = address + PAGE_SIZE; | ||
| 42 | |||
| 43 | entry = mk_pte_io(offset, prot, space, PAGE_SIZE); | ||
| 44 | if (!(address & 0xffff)) { | ||
| 45 | if (PAGE_SIZE < (4 * 1024 * 1024) && | ||
| 46 | !(address & 0x3fffff) && | ||
| 47 | !(offset & 0x3ffffe) && | ||
| 48 | end >= address + 0x400000) { | ||
| 49 | entry = mk_pte_io(offset, prot, space, | ||
| 50 | 4 * 1024 * 1024); | ||
| 51 | curend = address + 0x400000; | ||
| 52 | offset += 0x400000; | ||
| 53 | } else if (PAGE_SIZE < (512 * 1024) && | ||
| 54 | !(address & 0x7ffff) && | ||
| 55 | !(offset & 0x7fffe) && | ||
| 56 | end >= address + 0x80000) { | ||
| 57 | entry = mk_pte_io(offset, prot, space, | ||
| 58 | 512 * 1024 * 1024); | ||
| 59 | curend = address + 0x80000; | ||
| 60 | offset += 0x80000; | ||
| 61 | } else if (PAGE_SIZE < (64 * 1024) && | ||
| 62 | !(offset & 0xfffe) && | ||
| 63 | end >= address + 0x10000) { | ||
| 64 | entry = mk_pte_io(offset, prot, space, | ||
| 65 | 64 * 1024); | ||
| 66 | curend = address + 0x10000; | ||
| 67 | offset += 0x10000; | ||
| 68 | } else | ||
| 69 | offset += PAGE_SIZE; | ||
| 70 | } else | ||
| 71 | offset += PAGE_SIZE; | ||
| 72 | |||
| 73 | if (pte_write(entry)) | ||
| 74 | entry = pte_mkdirty(entry); | ||
| 75 | do { | ||
| 76 | BUG_ON(!pte_none(*pte)); | ||
| 77 | set_pte_at(mm, address, pte, entry); | ||
| 78 | address += PAGE_SIZE; | ||
| 79 | pte_val(entry) += PAGE_SIZE; | ||
| 80 | pte++; | ||
| 81 | } while (address < curend); | ||
| 82 | } while (address < end); | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, | ||
| 86 | unsigned long offset, pgprot_t prot, int space) | ||
| 87 | { | ||
| 88 | unsigned long end; | ||
| 89 | |||
| 90 | address &= ~PGDIR_MASK; | ||
| 91 | end = address + size; | ||
| 92 | if (end > PGDIR_SIZE) | ||
| 93 | end = PGDIR_SIZE; | ||
| 94 | offset -= address; | ||
| 95 | do { | ||
| 96 | pte_t *pte = pte_alloc_map(mm, NULL, pmd, address); | ||
| 97 | if (!pte) | ||
| 98 | return -ENOMEM; | ||
| 99 | io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space); | ||
| 100 | pte_unmap(pte); | ||
| 101 | address = (address + PMD_SIZE) & PMD_MASK; | ||
| 102 | pmd++; | ||
| 103 | } while (address < end); | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size, | ||
| 108 | unsigned long offset, pgprot_t prot, int space) | ||
| 109 | { | ||
| 110 | unsigned long end; | ||
| 111 | |||
| 112 | address &= ~PUD_MASK; | ||
| 113 | end = address + size; | ||
| 114 | if (end > PUD_SIZE) | ||
| 115 | end = PUD_SIZE; | ||
| 116 | offset -= address; | ||
| 117 | do { | ||
| 118 | pmd_t *pmd = pmd_alloc(mm, pud, address); | ||
| 119 | if (!pud) | ||
| 120 | return -ENOMEM; | ||
| 121 | io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space); | ||
| 122 | address = (address + PUD_SIZE) & PUD_MASK; | ||
| 123 | pud++; | ||
| 124 | } while (address < end); | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, | ||
| 129 | unsigned long pfn, unsigned long size, pgprot_t prot) | ||
| 130 | { | ||
| 131 | int error = 0; | ||
| 132 | pgd_t * dir; | ||
| 133 | unsigned long beg = from; | ||
| 134 | unsigned long end = from + size; | ||
| 135 | struct mm_struct *mm = vma->vm_mm; | ||
| 136 | int space = GET_IOSPACE(pfn); | ||
| 137 | unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; | ||
| 138 | unsigned long phys_base; | ||
| 139 | |||
| 140 | phys_base = offset | (((unsigned long) space) << 32UL); | ||
| 141 | |||
| 142 | /* See comment in mm/memory.c remap_pfn_range */ | ||
| 143 | vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; | ||
| 144 | vma->vm_pgoff = phys_base >> PAGE_SHIFT; | ||
| 145 | |||
| 146 | offset -= from; | ||
| 147 | dir = pgd_offset(mm, from); | ||
| 148 | flush_cache_range(vma, beg, end); | ||
| 149 | |||
| 150 | while (from < end) { | ||
| 151 | pud_t *pud = pud_alloc(mm, dir, from); | ||
| 152 | error = -ENOMEM; | ||
| 153 | if (!pud) | ||
| 154 | break; | ||
| 155 | error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space); | ||
| 156 | if (error) | ||
| 157 | break; | ||
| 158 | from = (from + PGDIR_SIZE) & PGDIR_MASK; | ||
| 159 | dir++; | ||
| 160 | } | ||
| 161 | |||
| 162 | flush_tlb_range(vma, beg, end); | ||
| 163 | return error; | ||
| 164 | } | ||
| 165 | EXPORT_SYMBOL(io_remap_pfn_range); | ||
