diff options
125 files changed, 14175 insertions, 4007 deletions
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index d39c9f206271..460f72e640e6 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c | |||
| @@ -217,7 +217,7 @@ static void _sparc_free_io(struct resource *res) | |||
| 217 | unsigned long plen; | 217 | unsigned long plen; |
| 218 | 218 | ||
| 219 | plen = res->end - res->start + 1; | 219 | plen = res->end - res->start + 1; |
| 220 | if ((plen & (PAGE_SIZE-1)) != 0) BUG(); | 220 | BUG_ON((plen & (PAGE_SIZE-1)) != 0); |
| 221 | sparc_unmapiorange(res->start, plen); | 221 | sparc_unmapiorange(res->start, plen); |
| 222 | release_resource(res); | 222 | release_resource(res); |
| 223 | } | 223 | } |
| @@ -512,8 +512,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) | |||
| 512 | dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, | 512 | dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, |
| 513 | int direction) | 513 | int direction) |
| 514 | { | 514 | { |
| 515 | if (direction == PCI_DMA_NONE) | 515 | BUG_ON(direction == PCI_DMA_NONE); |
| 516 | BUG(); | ||
| 517 | /* IIep is write-through, not flushing. */ | 516 | /* IIep is write-through, not flushing. */ |
| 518 | return virt_to_phys(ptr); | 517 | return virt_to_phys(ptr); |
| 519 | } | 518 | } |
| @@ -528,8 +527,7 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, | |||
| 528 | void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, | 527 | void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, |
| 529 | int direction) | 528 | int direction) |
| 530 | { | 529 | { |
| 531 | if (direction == PCI_DMA_NONE) | 530 | BUG_ON(direction == PCI_DMA_NONE); |
| 532 | BUG(); | ||
| 533 | if (direction != PCI_DMA_TODEVICE) { | 531 | if (direction != PCI_DMA_TODEVICE) { |
| 534 | mmu_inval_dma_area((unsigned long)phys_to_virt(ba), | 532 | mmu_inval_dma_area((unsigned long)phys_to_virt(ba), |
| 535 | (size + PAGE_SIZE-1) & PAGE_MASK); | 533 | (size + PAGE_SIZE-1) & PAGE_MASK); |
| @@ -542,8 +540,7 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, | |||
| 542 | dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, | 540 | dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, |
| 543 | unsigned long offset, size_t size, int direction) | 541 | unsigned long offset, size_t size, int direction) |
| 544 | { | 542 | { |
| 545 | if (direction == PCI_DMA_NONE) | 543 | BUG_ON(direction == PCI_DMA_NONE); |
| 546 | BUG(); | ||
| 547 | /* IIep is write-through, not flushing. */ | 544 | /* IIep is write-through, not flushing. */ |
| 548 | return page_to_phys(page) + offset; | 545 | return page_to_phys(page) + offset; |
| 549 | } | 546 | } |
| @@ -551,8 +548,7 @@ dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, | |||
| 551 | void pci_unmap_page(struct pci_dev *hwdev, | 548 | void pci_unmap_page(struct pci_dev *hwdev, |
| 552 | dma_addr_t dma_address, size_t size, int direction) | 549 | dma_addr_t dma_address, size_t size, int direction) |
| 553 | { | 550 | { |
| 554 | if (direction == PCI_DMA_NONE) | 551 | BUG_ON(direction == PCI_DMA_NONE); |
| 555 | BUG(); | ||
| 556 | /* mmu_inval_dma_area XXX */ | 552 | /* mmu_inval_dma_area XXX */ |
| 557 | } | 553 | } |
| 558 | 554 | ||
| @@ -576,11 +572,10 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, | |||
| 576 | { | 572 | { |
| 577 | int n; | 573 | int n; |
| 578 | 574 | ||
| 579 | if (direction == PCI_DMA_NONE) | 575 | BUG_ON(direction == PCI_DMA_NONE); |
| 580 | BUG(); | ||
| 581 | /* IIep is write-through, not flushing. */ | 576 | /* IIep is write-through, not flushing. */ |
| 582 | for (n = 0; n < nents; n++) { | 577 | for (n = 0; n < nents; n++) { |
| 583 | if (page_address(sg->page) == NULL) BUG(); | 578 | BUG_ON(page_address(sg->page) == NULL); |
| 584 | sg->dvma_address = virt_to_phys(page_address(sg->page)); | 579 | sg->dvma_address = virt_to_phys(page_address(sg->page)); |
| 585 | sg->dvma_length = sg->length; | 580 | sg->dvma_length = sg->length; |
| 586 | sg++; | 581 | sg++; |
| @@ -597,11 +592,10 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, | |||
| 597 | { | 592 | { |
| 598 | int n; | 593 | int n; |
| 599 | 594 | ||
| 600 | if (direction == PCI_DMA_NONE) | 595 | BUG_ON(direction == PCI_DMA_NONE); |
| 601 | BUG(); | ||
| 602 | if (direction != PCI_DMA_TODEVICE) { | 596 | if (direction != PCI_DMA_TODEVICE) { |
| 603 | for (n = 0; n < nents; n++) { | 597 | for (n = 0; n < nents; n++) { |
| 604 | if (page_address(sg->page) == NULL) BUG(); | 598 | BUG_ON(page_address(sg->page) == NULL); |
| 605 | mmu_inval_dma_area( | 599 | mmu_inval_dma_area( |
| 606 | (unsigned long) page_address(sg->page), | 600 | (unsigned long) page_address(sg->page), |
| 607 | (sg->length + PAGE_SIZE-1) & PAGE_MASK); | 601 | (sg->length + PAGE_SIZE-1) & PAGE_MASK); |
| @@ -622,8 +616,7 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, | |||
| 622 | */ | 616 | */ |
| 623 | void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) | 617 | void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) |
| 624 | { | 618 | { |
| 625 | if (direction == PCI_DMA_NONE) | 619 | BUG_ON(direction == PCI_DMA_NONE); |
| 626 | BUG(); | ||
| 627 | if (direction != PCI_DMA_TODEVICE) { | 620 | if (direction != PCI_DMA_TODEVICE) { |
| 628 | mmu_inval_dma_area((unsigned long)phys_to_virt(ba), | 621 | mmu_inval_dma_area((unsigned long)phys_to_virt(ba), |
| 629 | (size + PAGE_SIZE-1) & PAGE_MASK); | 622 | (size + PAGE_SIZE-1) & PAGE_MASK); |
| @@ -632,8 +625,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t si | |||
| 632 | 625 | ||
| 633 | void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) | 626 | void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) |
| 634 | { | 627 | { |
| 635 | if (direction == PCI_DMA_NONE) | 628 | BUG_ON(direction == PCI_DMA_NONE); |
| 636 | BUG(); | ||
| 637 | if (direction != PCI_DMA_TODEVICE) { | 629 | if (direction != PCI_DMA_TODEVICE) { |
| 638 | mmu_inval_dma_area((unsigned long)phys_to_virt(ba), | 630 | mmu_inval_dma_area((unsigned long)phys_to_virt(ba), |
| 639 | (size + PAGE_SIZE-1) & PAGE_MASK); | 631 | (size + PAGE_SIZE-1) & PAGE_MASK); |
| @@ -650,11 +642,10 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int | |||
| 650 | { | 642 | { |
| 651 | int n; | 643 | int n; |
| 652 | 644 | ||
| 653 | if (direction == PCI_DMA_NONE) | 645 | BUG_ON(direction == PCI_DMA_NONE); |
| 654 | BUG(); | ||
| 655 | if (direction != PCI_DMA_TODEVICE) { | 646 | if (direction != PCI_DMA_TODEVICE) { |
| 656 | for (n = 0; n < nents; n++) { | 647 | for (n = 0; n < nents; n++) { |
| 657 | if (page_address(sg->page) == NULL) BUG(); | 648 | BUG_ON(page_address(sg->page) == NULL); |
| 658 | mmu_inval_dma_area( | 649 | mmu_inval_dma_area( |
| 659 | (unsigned long) page_address(sg->page), | 650 | (unsigned long) page_address(sg->page), |
| 660 | (sg->length + PAGE_SIZE-1) & PAGE_MASK); | 651 | (sg->length + PAGE_SIZE-1) & PAGE_MASK); |
| @@ -667,11 +658,10 @@ void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, i | |||
| 667 | { | 658 | { |
| 668 | int n; | 659 | int n; |
| 669 | 660 | ||
| 670 | if (direction == PCI_DMA_NONE) | 661 | BUG_ON(direction == PCI_DMA_NONE); |
| 671 | BUG(); | ||
| 672 | if (direction != PCI_DMA_TODEVICE) { | 662 | if (direction != PCI_DMA_TODEVICE) { |
| 673 | for (n = 0; n < nents; n++) { | 663 | for (n = 0; n < nents; n++) { |
| 674 | if (page_address(sg->page) == NULL) BUG(); | 664 | BUG_ON(page_address(sg->page) == NULL); |
| 675 | mmu_inval_dma_area( | 665 | mmu_inval_dma_area( |
| 676 | (unsigned long) page_address(sg->page), | 666 | (unsigned long) page_address(sg->page), |
| 677 | (sg->length + PAGE_SIZE-1) & PAGE_MASK); | 667 | (sg->length + PAGE_SIZE-1) & PAGE_MASK); |
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 4c0a50a76554..c3685b314d71 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig | |||
| @@ -186,6 +186,15 @@ endchoice | |||
| 186 | 186 | ||
| 187 | endmenu | 187 | endmenu |
| 188 | 188 | ||
| 189 | config ARCH_SPARSEMEM_ENABLE | ||
| 190 | def_bool y | ||
| 191 | |||
| 192 | config ARCH_SPARSEMEM_DEFAULT | ||
| 193 | def_bool y | ||
| 194 | |||
| 195 | config LARGE_ALLOCS | ||
| 196 | def_bool y | ||
| 197 | |||
| 189 | source "mm/Kconfig" | 198 | source "mm/Kconfig" |
| 190 | 199 | ||
| 191 | config GENERIC_ISA_DMA | 200 | config GENERIC_ISA_DMA |
| @@ -350,6 +359,15 @@ config SOLARIS_EMUL | |||
| 350 | 359 | ||
| 351 | endmenu | 360 | endmenu |
| 352 | 361 | ||
| 362 | config SCHED_SMT | ||
| 363 | bool "SMT (Hyperthreading) scheduler support" | ||
| 364 | depends on SMP | ||
| 365 | default y | ||
| 366 | help | ||
| 367 | SMT scheduler support improves the CPU scheduler's decision making | ||
| 368 | when dealing with UltraSPARC cpus at a cost of slightly increased | ||
| 369 | overhead in some places. If unsure say N here. | ||
| 370 | |||
| 353 | config CMDLINE_BOOL | 371 | config CMDLINE_BOOL |
| 354 | bool "Default bootloader kernel arguments" | 372 | bool "Default bootloader kernel arguments" |
| 355 | 373 | ||
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 069d49777b2a..f819a9663a8d 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | # | 1 | # |
| 2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
| 3 | # Linux kernel version: 2.6.16-rc2 | 3 | # Linux kernel version: 2.6.16 |
| 4 | # Tue Feb 7 17:47:18 2006 | 4 | # Mon Mar 20 01:23:21 2006 |
| 5 | # | 5 | # |
| 6 | CONFIG_SPARC=y | 6 | CONFIG_SPARC=y |
| 7 | CONFIG_SPARC64=y | 7 | CONFIG_SPARC64=y |
| @@ -115,14 +115,20 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y | |||
| 115 | CONFIG_HUGETLB_PAGE_SIZE_4MB=y | 115 | CONFIG_HUGETLB_PAGE_SIZE_4MB=y |
| 116 | # CONFIG_HUGETLB_PAGE_SIZE_512K is not set | 116 | # CONFIG_HUGETLB_PAGE_SIZE_512K is not set |
| 117 | # CONFIG_HUGETLB_PAGE_SIZE_64K is not set | 117 | # CONFIG_HUGETLB_PAGE_SIZE_64K is not set |
| 118 | CONFIG_ARCH_SPARSEMEM_ENABLE=y | ||
| 119 | CONFIG_ARCH_SPARSEMEM_DEFAULT=y | ||
| 120 | CONFIG_LARGE_ALLOCS=y | ||
| 118 | CONFIG_SELECT_MEMORY_MODEL=y | 121 | CONFIG_SELECT_MEMORY_MODEL=y |
| 119 | CONFIG_FLATMEM_MANUAL=y | 122 | # CONFIG_FLATMEM_MANUAL is not set |
| 120 | # CONFIG_DISCONTIGMEM_MANUAL is not set | 123 | # CONFIG_DISCONTIGMEM_MANUAL is not set |
| 121 | # CONFIG_SPARSEMEM_MANUAL is not set | 124 | CONFIG_SPARSEMEM_MANUAL=y |
| 122 | CONFIG_FLATMEM=y | 125 | CONFIG_SPARSEMEM=y |
| 123 | CONFIG_FLAT_NODE_MEM_MAP=y | 126 | CONFIG_HAVE_MEMORY_PRESENT=y |
| 124 | # CONFIG_SPARSEMEM_STATIC is not set | 127 | # CONFIG_SPARSEMEM_STATIC is not set |
| 128 | CONFIG_SPARSEMEM_EXTREME=y | ||
| 129 | CONFIG_MEMORY_HOTPLUG=y | ||
| 125 | CONFIG_SPLIT_PTLOCK_CPUS=4 | 130 | CONFIG_SPLIT_PTLOCK_CPUS=4 |
| 131 | CONFIG_MIGRATION=y | ||
| 126 | CONFIG_GENERIC_ISA_DMA=y | 132 | CONFIG_GENERIC_ISA_DMA=y |
| 127 | CONFIG_SBUS=y | 133 | CONFIG_SBUS=y |
| 128 | CONFIG_SBUSCHAR=y | 134 | CONFIG_SBUSCHAR=y |
| @@ -655,6 +661,7 @@ CONFIG_SERIAL_SUNCORE=y | |||
| 655 | CONFIG_SERIAL_SUNSU=y | 661 | CONFIG_SERIAL_SUNSU=y |
| 656 | CONFIG_SERIAL_SUNSU_CONSOLE=y | 662 | CONFIG_SERIAL_SUNSU_CONSOLE=y |
| 657 | CONFIG_SERIAL_SUNSAB=m | 663 | CONFIG_SERIAL_SUNSAB=m |
| 664 | CONFIG_SERIAL_SUNHV=y | ||
| 658 | CONFIG_SERIAL_CORE=y | 665 | CONFIG_SERIAL_CORE=y |
| 659 | CONFIG_SERIAL_CORE_CONSOLE=y | 666 | CONFIG_SERIAL_CORE_CONSOLE=y |
| 660 | # CONFIG_SERIAL_JSM is not set | 667 | # CONFIG_SERIAL_JSM is not set |
| @@ -1116,11 +1123,7 @@ CONFIG_USB_HIDDEV=y | |||
| 1116 | # CONFIG_INFINIBAND is not set | 1123 | # CONFIG_INFINIBAND is not set |
| 1117 | 1124 | ||
| 1118 | # | 1125 | # |
| 1119 | # SN Devices | 1126 | # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) |
| 1120 | # | ||
| 1121 | |||
| 1122 | # | ||
| 1123 | # EDAC - error detection and reporting (RAS) | ||
| 1124 | # | 1127 | # |
| 1125 | 1128 | ||
| 1126 | # | 1129 | # |
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 83d67eb18895..6f6816488b04 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile | |||
| @@ -11,10 +11,12 @@ obj-y := process.o setup.o cpu.o idprom.o \ | |||
| 11 | traps.o devices.o auxio.o una_asm.o \ | 11 | traps.o devices.o auxio.o una_asm.o \ |
| 12 | irq.o ptrace.o time.o sys_sparc.o signal.o \ | 12 | irq.o ptrace.o time.o sys_sparc.o signal.o \ |
| 13 | unaligned.o central.o pci.o starfire.o semaphore.o \ | 13 | unaligned.o central.o pci.o starfire.o semaphore.o \ |
| 14 | power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o | 14 | power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ |
| 15 | visemul.o | ||
| 15 | 16 | ||
| 16 | obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ | 17 | obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ |
| 17 | pci_psycho.o pci_sabre.o pci_schizo.o | 18 | pci_psycho.o pci_sabre.o pci_schizo.o \ |
| 19 | pci_sun4v.o pci_sun4v_asm.o | ||
| 18 | obj-$(CONFIG_SMP) += smp.o trampoline.o | 20 | obj-$(CONFIG_SMP) += smp.o trampoline.o |
| 19 | obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o | 21 | obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o |
| 20 | obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o | 22 | obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o |
| @@ -38,5 +40,5 @@ else | |||
| 38 | CMODEL_CFLAG := -m64 -mcmodel=medlow | 40 | CMODEL_CFLAG := -m64 -mcmodel=medlow |
| 39 | endif | 41 | endif |
| 40 | 42 | ||
| 41 | head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \ | 43 | head.o: head.S ttable.S itlb_miss.S dtlb_miss.S ktlb.S tsb.S \ |
| 42 | etrap.S rtrap.S winfixup.S entry.S | 44 | etrap.S rtrap.S winfixup.S entry.S |
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 202a80c24b6f..d7caa60a0074 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <asm/system.h> | 31 | #include <asm/system.h> |
| 32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 33 | #include <asm/pgalloc.h> | 33 | #include <asm/pgalloc.h> |
| 34 | #include <asm/mmu_context.h> | ||
| 34 | 35 | ||
| 35 | static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); | 36 | static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); |
| 36 | static int load_aout32_library(struct file*); | 37 | static int load_aout32_library(struct file*); |
| @@ -238,6 +239,8 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 238 | (current->mm->start_data = N_DATADDR(ex)); | 239 | (current->mm->start_data = N_DATADDR(ex)); |
| 239 | current->mm->brk = ex.a_bss + | 240 | current->mm->brk = ex.a_bss + |
| 240 | (current->mm->start_brk = N_BSSADDR(ex)); | 241 | (current->mm->start_brk = N_BSSADDR(ex)); |
| 242 | current->mm->free_area_cache = current->mm->mmap_base; | ||
| 243 | current->mm->cached_hole_size = 0; | ||
| 241 | 244 | ||
| 242 | current->mm->mmap = NULL; | 245 | current->mm->mmap = NULL; |
| 243 | compute_creds(bprm); | 246 | compute_creds(bprm); |
| @@ -329,15 +332,8 @@ beyond_if: | |||
| 329 | 332 | ||
| 330 | current->mm->start_stack = | 333 | current->mm->start_stack = |
| 331 | (unsigned long) create_aout32_tables((char __user *)bprm->p, bprm); | 334 | (unsigned long) create_aout32_tables((char __user *)bprm->p, bprm); |
| 332 | if (!(orig_thr_flags & _TIF_32BIT)) { | 335 | tsb_context_switch(current->mm); |
| 333 | unsigned long pgd_cache = get_pgd_cache(current->mm->pgd); | 336 | |
| 334 | |||
| 335 | __asm__ __volatile__("stxa\t%0, [%1] %2\n\t" | ||
| 336 | "membar #Sync" | ||
| 337 | : /* no outputs */ | ||
| 338 | : "r" (pgd_cache), | ||
| 339 | "r" (TSB_REG), "i" (ASI_DMMU)); | ||
| 340 | } | ||
| 341 | start_thread32(regs, ex.a_entry, current->mm->start_stack); | 337 | start_thread32(regs, ex.a_entry, current->mm->start_stack); |
| 342 | if (current->ptrace & PT_PTRACED) | 338 | if (current->ptrace & PT_PTRACED) |
| 343 | send_sig(SIGTRAP, current, 0); | 339 | send_sig(SIGTRAP, current, 0); |
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index a1a12d2aa353..8a2abcce2737 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c | |||
| @@ -153,7 +153,9 @@ MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); | |||
| 153 | #undef MODULE_DESCRIPTION | 153 | #undef MODULE_DESCRIPTION |
| 154 | #undef MODULE_AUTHOR | 154 | #undef MODULE_AUTHOR |
| 155 | 155 | ||
| 156 | #include <asm/a.out.h> | ||
| 157 | |||
| 156 | #undef TASK_SIZE | 158 | #undef TASK_SIZE |
| 157 | #define TASK_SIZE 0xf0000000 | 159 | #define TASK_SIZE STACK_TOP32 |
| 158 | 160 | ||
| 159 | #include "../../../fs/binfmt_elf.c" | 161 | #include "../../../fs/binfmt_elf.c" |
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c index 00eed88ef2e8..11cc0caef592 100644 --- a/arch/sparc64/kernel/cpu.c +++ b/arch/sparc64/kernel/cpu.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <asm/system.h> | 13 | #include <asm/system.h> |
| 14 | #include <asm/fpumacro.h> | 14 | #include <asm/fpumacro.h> |
| 15 | #include <asm/cpudata.h> | 15 | #include <asm/cpudata.h> |
| 16 | #include <asm/spitfire.h> | ||
| 16 | 17 | ||
| 17 | DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; | 18 | DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; |
| 18 | 19 | ||
| @@ -71,6 +72,12 @@ void __init cpu_probe(void) | |||
| 71 | unsigned long ver, fpu_vers, manuf, impl, fprs; | 72 | unsigned long ver, fpu_vers, manuf, impl, fprs; |
| 72 | int i; | 73 | int i; |
| 73 | 74 | ||
| 75 | if (tlb_type == hypervisor) { | ||
| 76 | sparc_cpu_type = "UltraSparc T1 (Niagara)"; | ||
| 77 | sparc_fpu_type = "UltraSparc T1 integrated FPU"; | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | |||
| 74 | fprs = fprs_read(); | 81 | fprs = fprs_read(); |
| 75 | fprs_write(FPRS_FEF); | 82 | fprs_write(FPRS_FEF); |
| 76 | __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" | 83 | __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" |
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index df9a1ca8fd77..007e8922cd16 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/string.h> | 12 | #include <linux/string.h> |
| 13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| 14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
| 15 | #include <linux/bootmem.h> | ||
| 15 | 16 | ||
| 16 | #include <asm/page.h> | 17 | #include <asm/page.h> |
| 17 | #include <asm/oplib.h> | 18 | #include <asm/oplib.h> |
| @@ -20,6 +21,8 @@ | |||
| 20 | #include <asm/spitfire.h> | 21 | #include <asm/spitfire.h> |
| 21 | #include <asm/timer.h> | 22 | #include <asm/timer.h> |
| 22 | #include <asm/cpudata.h> | 23 | #include <asm/cpudata.h> |
| 24 | #include <asm/vdev.h> | ||
| 25 | #include <asm/irq.h> | ||
| 23 | 26 | ||
| 24 | /* Used to synchronize acceses to NatSemi SUPER I/O chip configure | 27 | /* Used to synchronize acceses to NatSemi SUPER I/O chip configure |
| 25 | * operations in asm/ns87303.h | 28 | * operations in asm/ns87303.h |
| @@ -29,13 +32,158 @@ DEFINE_SPINLOCK(ns87303_lock); | |||
| 29 | extern void cpu_probe(void); | 32 | extern void cpu_probe(void); |
| 30 | extern void central_probe(void); | 33 | extern void central_probe(void); |
| 31 | 34 | ||
| 32 | static char *cpu_mid_prop(void) | 35 | u32 sun4v_vdev_devhandle; |
| 36 | int sun4v_vdev_root; | ||
| 37 | |||
| 38 | struct vdev_intmap { | ||
| 39 | unsigned int phys; | ||
| 40 | unsigned int irq; | ||
| 41 | unsigned int cnode; | ||
| 42 | unsigned int cinterrupt; | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct vdev_intmask { | ||
| 46 | unsigned int phys; | ||
| 47 | unsigned int interrupt; | ||
| 48 | unsigned int __unused; | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct vdev_intmap *vdev_intmap; | ||
| 52 | static int vdev_num_intmap; | ||
| 53 | static struct vdev_intmask vdev_intmask; | ||
| 54 | |||
| 55 | static void __init sun4v_virtual_device_probe(void) | ||
| 56 | { | ||
| 57 | struct linux_prom64_registers regs; | ||
| 58 | struct vdev_intmap *ip; | ||
| 59 | int node, sz, err; | ||
| 60 | |||
| 61 | if (tlb_type != hypervisor) | ||
| 62 | return; | ||
| 63 | |||
| 64 | node = prom_getchild(prom_root_node); | ||
| 65 | node = prom_searchsiblings(node, "virtual-devices"); | ||
| 66 | if (!node) { | ||
| 67 | prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); | ||
| 68 | prom_halt(); | ||
| 69 | } | ||
| 70 | |||
| 71 | sun4v_vdev_root = node; | ||
| 72 | |||
| 73 | prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); | ||
| 74 | sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; | ||
| 75 | |||
| 76 | sz = prom_getproplen(node, "interrupt-map"); | ||
| 77 | if (sz <= 0) { | ||
| 78 | prom_printf("SUN4V: Error, no vdev interrupt-map.\n"); | ||
| 79 | prom_halt(); | ||
| 80 | } | ||
| 81 | |||
| 82 | if ((sz % sizeof(*ip)) != 0) { | ||
| 83 | prom_printf("SUN4V: Bogus interrupt-map property size %d\n", | ||
| 84 | sz); | ||
| 85 | prom_halt(); | ||
| 86 | } | ||
| 87 | |||
| 88 | vdev_intmap = ip = alloc_bootmem_low_pages(sz); | ||
| 89 | if (!vdev_intmap) { | ||
| 90 | prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n"); | ||
| 91 | prom_halt(); | ||
| 92 | } | ||
| 93 | |||
| 94 | err = prom_getproperty(node, "interrupt-map", (char *) ip, sz); | ||
| 95 | if (err == -1) { | ||
| 96 | prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n"); | ||
| 97 | prom_halt(); | ||
| 98 | } | ||
| 99 | if (err != sz) { | ||
| 100 | prom_printf("SUN4V: Inconsistent interrupt-map size, " | ||
| 101 | "proplen(%d) vs getprop(%d).\n", sz,err); | ||
| 102 | prom_halt(); | ||
| 103 | } | ||
| 104 | |||
| 105 | vdev_num_intmap = err / sizeof(*ip); | ||
| 106 | |||
| 107 | err = prom_getproperty(node, "interrupt-map-mask", | ||
| 108 | (char *) &vdev_intmask, | ||
| 109 | sizeof(vdev_intmask)); | ||
| 110 | if (err <= 0) { | ||
| 111 | prom_printf("SUN4V: Fatal error, no vdev " | ||
| 112 | "interrupt-map-mask.\n"); | ||
| 113 | prom_halt(); | ||
| 114 | } | ||
| 115 | if (err % sizeof(vdev_intmask)) { | ||
| 116 | prom_printf("SUN4V: Bogus interrupt-map-mask " | ||
| 117 | "property size %d\n", err); | ||
| 118 | prom_halt(); | ||
| 119 | } | ||
| 120 | |||
| 121 | printk("SUN4V: virtual-devices devhandle[%x]\n", | ||
| 122 | sun4v_vdev_devhandle); | ||
| 123 | } | ||
| 124 | |||
| 125 | unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) | ||
| 126 | { | ||
| 127 | unsigned int irq, reg; | ||
| 128 | int err, i; | ||
| 129 | |||
| 130 | err = prom_getproperty(dev_node, "interrupts", | ||
| 131 | (char *) &irq, sizeof(irq)); | ||
| 132 | if (err <= 0) { | ||
| 133 | printk("VDEV: Cannot get \"interrupts\" " | ||
| 134 | "property for OBP node %x\n", dev_node); | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | err = prom_getproperty(dev_node, "reg", | ||
| 139 | (char *) ®, sizeof(reg)); | ||
| 140 | if (err <= 0) { | ||
| 141 | printk("VDEV: Cannot get \"reg\" " | ||
| 142 | "property for OBP node %x\n", dev_node); | ||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | for (i = 0; i < vdev_num_intmap; i++) { | ||
| 147 | if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) && | ||
| 148 | vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) { | ||
| 149 | irq = vdev_intmap[i].cinterrupt; | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | if (i == vdev_num_intmap) { | ||
| 155 | printk("VDEV: No matching interrupt map entry " | ||
| 156 | "for OBP node %x\n", dev_node); | ||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | return sun4v_build_irq(sun4v_vdev_devhandle, irq, 5, 0); | ||
| 161 | } | ||
| 162 | |||
| 163 | static const char *cpu_mid_prop(void) | ||
| 33 | { | 164 | { |
| 34 | if (tlb_type == spitfire) | 165 | if (tlb_type == spitfire) |
| 35 | return "upa-portid"; | 166 | return "upa-portid"; |
| 36 | return "portid"; | 167 | return "portid"; |
| 37 | } | 168 | } |
| 38 | 169 | ||
| 170 | static int get_cpu_mid(int prom_node) | ||
| 171 | { | ||
| 172 | if (tlb_type == hypervisor) { | ||
| 173 | struct linux_prom64_registers reg; | ||
| 174 | |||
| 175 | if (prom_getproplen(prom_node, "cpuid") == 4) | ||
| 176 | return prom_getintdefault(prom_node, "cpuid", 0); | ||
| 177 | |||
| 178 | prom_getproperty(prom_node, "reg", (char *) ®, sizeof(reg)); | ||
| 179 | return (reg.phys_addr >> 32) & 0x0fffffffUL; | ||
| 180 | } else { | ||
| 181 | const char *prop_name = cpu_mid_prop(); | ||
| 182 | |||
| 183 | return prom_getintdefault(prom_node, prop_name, 0); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 39 | static int check_cpu_node(int nd, int *cur_inst, | 187 | static int check_cpu_node(int nd, int *cur_inst, |
| 40 | int (*compare)(int, int, void *), void *compare_arg, | 188 | int (*compare)(int, int, void *), void *compare_arg, |
| 41 | int *prom_node, int *mid) | 189 | int *prom_node, int *mid) |
| @@ -50,7 +198,7 @@ static int check_cpu_node(int nd, int *cur_inst, | |||
| 50 | if (prom_node) | 198 | if (prom_node) |
| 51 | *prom_node = nd; | 199 | *prom_node = nd; |
| 52 | if (mid) | 200 | if (mid) |
| 53 | *mid = prom_getintdefault(nd, cpu_mid_prop(), 0); | 201 | *mid = get_cpu_mid(nd); |
| 54 | return 0; | 202 | return 0; |
| 55 | } | 203 | } |
| 56 | 204 | ||
| @@ -105,7 +253,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg) | |||
| 105 | int desired_mid = (int) (long) _arg; | 253 | int desired_mid = (int) (long) _arg; |
| 106 | int this_mid; | 254 | int this_mid; |
| 107 | 255 | ||
| 108 | this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0); | 256 | this_mid = get_cpu_mid(nd); |
| 109 | if (this_mid == desired_mid) | 257 | if (this_mid == desired_mid) |
| 110 | return 0; | 258 | return 0; |
| 111 | return -ENODEV; | 259 | return -ENODEV; |
| @@ -126,7 +274,8 @@ void __init device_scan(void) | |||
| 126 | 274 | ||
| 127 | #ifndef CONFIG_SMP | 275 | #ifndef CONFIG_SMP |
| 128 | { | 276 | { |
| 129 | int err, cpu_node; | 277 | int err, cpu_node, def; |
| 278 | |||
| 130 | err = cpu_find_by_instance(0, &cpu_node, NULL); | 279 | err = cpu_find_by_instance(0, &cpu_node, NULL); |
| 131 | if (err) { | 280 | if (err) { |
| 132 | prom_printf("No cpu nodes, cannot continue\n"); | 281 | prom_printf("No cpu nodes, cannot continue\n"); |
| @@ -135,21 +284,40 @@ void __init device_scan(void) | |||
| 135 | cpu_data(0).clock_tick = prom_getintdefault(cpu_node, | 284 | cpu_data(0).clock_tick = prom_getintdefault(cpu_node, |
| 136 | "clock-frequency", | 285 | "clock-frequency", |
| 137 | 0); | 286 | 0); |
| 287 | |||
| 288 | def = ((tlb_type == hypervisor) ? | ||
| 289 | (8 * 1024) : | ||
| 290 | (16 * 1024)); | ||
| 138 | cpu_data(0).dcache_size = prom_getintdefault(cpu_node, | 291 | cpu_data(0).dcache_size = prom_getintdefault(cpu_node, |
| 139 | "dcache-size", | 292 | "dcache-size", |
| 140 | 16 * 1024); | 293 | def); |
| 294 | |||
| 295 | def = 32; | ||
| 141 | cpu_data(0).dcache_line_size = | 296 | cpu_data(0).dcache_line_size = |
| 142 | prom_getintdefault(cpu_node, "dcache-line-size", 32); | 297 | prom_getintdefault(cpu_node, "dcache-line-size", |
| 298 | def); | ||
| 299 | |||
| 300 | def = 16 * 1024; | ||
| 143 | cpu_data(0).icache_size = prom_getintdefault(cpu_node, | 301 | cpu_data(0).icache_size = prom_getintdefault(cpu_node, |
| 144 | "icache-size", | 302 | "icache-size", |
| 145 | 16 * 1024); | 303 | def); |
| 304 | |||
| 305 | def = 32; | ||
| 146 | cpu_data(0).icache_line_size = | 306 | cpu_data(0).icache_line_size = |
| 147 | prom_getintdefault(cpu_node, "icache-line-size", 32); | 307 | prom_getintdefault(cpu_node, "icache-line-size", |
| 308 | def); | ||
| 309 | |||
| 310 | def = ((tlb_type == hypervisor) ? | ||
| 311 | (3 * 1024 * 1024) : | ||
| 312 | (4 * 1024 * 1024)); | ||
| 148 | cpu_data(0).ecache_size = prom_getintdefault(cpu_node, | 313 | cpu_data(0).ecache_size = prom_getintdefault(cpu_node, |
| 149 | "ecache-size", | 314 | "ecache-size", |
| 150 | 4 * 1024 * 1024); | 315 | def); |
| 316 | |||
| 317 | def = 64; | ||
| 151 | cpu_data(0).ecache_line_size = | 318 | cpu_data(0).ecache_line_size = |
| 152 | prom_getintdefault(cpu_node, "ecache-line-size", 64); | 319 | prom_getintdefault(cpu_node, "ecache-line-size", |
| 320 | def); | ||
| 153 | printk("CPU[0]: Caches " | 321 | printk("CPU[0]: Caches " |
| 154 | "D[sz(%d):line_sz(%d)] " | 322 | "D[sz(%d):line_sz(%d)] " |
| 155 | "I[sz(%d):line_sz(%d)] " | 323 | "I[sz(%d):line_sz(%d)] " |
| @@ -160,6 +328,7 @@ void __init device_scan(void) | |||
| 160 | } | 328 | } |
| 161 | #endif | 329 | #endif |
| 162 | 330 | ||
| 331 | sun4v_virtual_device_probe(); | ||
| 163 | central_probe(); | 332 | central_probe(); |
| 164 | 333 | ||
| 165 | cpu_probe(); | 334 | cpu_probe(); |
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S deleted file mode 100644 index acc889a7f9c1..000000000000 --- a/arch/sparc64/kernel/dtlb_backend.S +++ /dev/null | |||
| @@ -1,170 +0,0 @@ | |||
| 1 | /* $Id: dtlb_backend.S,v 1.16 2001/10/09 04:02:11 davem Exp $ | ||
| 2 | * dtlb_backend.S: Back end to DTLB miss replacement strategy. | ||
| 3 | * This is included directly into the trap table. | ||
| 4 | * | ||
| 5 | * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) | ||
| 6 | * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <asm/pgtable.h> | ||
| 10 | #include <asm/mmu.h> | ||
| 11 | |||
| 12 | #define VALID_SZ_BITS (_PAGE_VALID | _PAGE_SZBITS) | ||
| 13 | |||
| 14 | #define VPTE_BITS (_PAGE_CP | _PAGE_CV | _PAGE_P ) | ||
| 15 | #define VPTE_SHIFT (PAGE_SHIFT - 3) | ||
| 16 | |||
| 17 | /* Ways we can get here: | ||
| 18 | * | ||
| 19 | * 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1. | ||
| 20 | * 2) Nucleus loads and stores to/from user/kernel window save areas. | ||
| 21 | * 3) VPTE misses from dtlb_base and itlb_base. | ||
| 22 | * | ||
| 23 | * We need to extract out the PMD and PGDIR indexes from the | ||
| 24 | * linear virtual page table access address. The PTE index | ||
| 25 | * is at the bottom, but we are not concerned with it. Bits | ||
| 26 | * 0 to 2 are clear since each PTE is 8 bytes in size. Each | ||
| 27 | * PMD and PGDIR entry are 4 bytes in size. Thus, this | ||
| 28 | * address looks something like: | ||
| 29 | * | ||
| 30 | * |---------------------------------------------------------------| | ||
| 31 | * | ... | PGDIR index | PMD index | PTE index | | | ||
| 32 | * |---------------------------------------------------------------| | ||
| 33 | * 63 F E D C B A 3 2 0 <- bit nr | ||
| 34 | * | ||
| 35 | * The variable bits above are defined as: | ||
| 36 | * A --> 3 + (PAGE_SHIFT - log2(8)) | ||
| 37 | * --> 3 + (PAGE_SHIFT - 3) - 1 | ||
| 38 | * (ie. this is "bit 3" + PAGE_SIZE - size of PTE entry in bits - 1) | ||
| 39 | * B --> A + 1 | ||
| 40 | * C --> B + (PAGE_SHIFT - log2(4)) | ||
| 41 | * --> B + (PAGE_SHIFT - 2) - 1 | ||
| 42 | * (ie. this is "bit B" + PAGE_SIZE - size of PMD entry in bits - 1) | ||
| 43 | * D --> C + 1 | ||
| 44 | * E --> D + (PAGE_SHIFT - log2(4)) | ||
| 45 | * --> D + (PAGE_SHIFT - 2) - 1 | ||
| 46 | * (ie. this is "bit D" + PAGE_SIZE - size of PGDIR entry in bits - 1) | ||
| 47 | * F --> E + 1 | ||
| 48 | * | ||
| 49 | * (Note how "B" always evalutes to PAGE_SHIFT, all the other constants | ||
| 50 | * cancel out.) | ||
| 51 | * | ||
| 52 | * For 8K PAGE_SIZE (thus, PAGE_SHIFT of 13) the bit numbers are: | ||
| 53 | * A --> 12 | ||
| 54 | * B --> 13 | ||
| 55 | * C --> 23 | ||
| 56 | * D --> 24 | ||
| 57 | * E --> 34 | ||
| 58 | * F --> 35 | ||
| 59 | * | ||
| 60 | * For 64K PAGE_SIZE (thus, PAGE_SHIFT of 16) the bit numbers are: | ||
| 61 | * A --> 15 | ||
| 62 | * B --> 16 | ||
| 63 | * C --> 29 | ||
| 64 | * D --> 30 | ||
| 65 | * E --> 43 | ||
| 66 | * F --> 44 | ||
| 67 | * | ||
| 68 | * Because bits both above and below each PGDIR and PMD index need to | ||
| 69 | * be masked out, and the index can be as long as 14 bits (when using a | ||
| 70 | * 64K PAGE_SIZE, and thus a PAGE_SHIFT of 16), we need 3 instructions | ||
| 71 | * to extract each index out. | ||
| 72 | * | ||
| 73 | * Shifts do not pair very well on UltraSPARC-I, II, IIi, and IIe, so | ||
| 74 | * we try to avoid using them for the entire operation. We could setup | ||
| 75 | * a mask anywhere from bit 31 down to bit 10 using the sethi instruction. | ||
| 76 | * | ||
| 77 | * We need a mask covering bits B --> C and one covering D --> E. | ||
| 78 | * For 8K PAGE_SIZE these masks are 0x00ffe000 and 0x7ff000000. | ||
| 79 | * For 64K PAGE_SIZE these masks are 0x3fff0000 and 0xfffc0000000. | ||
| 80 | * The second in each set cannot be loaded with a single sethi | ||
| 81 | * instruction, because the upper bits are past bit 32. We would | ||
| 82 | * need to use a sethi + a shift. | ||
| 83 | * | ||
| 84 | * For the time being, we use 2 shifts and a simple "and" mask. | ||
| 85 | * We shift left to clear the bits above the index, we shift down | ||
| 86 | * to clear the bits below the index (sans the log2(4 or 8) bits) | ||
| 87 | * and a mask to clear the log2(4 or 8) bits. We need therefore | ||
| 88 | * define 4 shift counts, all of which are relative to PAGE_SHIFT. | ||
| 89 | * | ||
| 90 | * Although unsupportable for other reasons, this does mean that | ||
| 91 | * 512K and 4MB page sizes would be generaally supported by the | ||
| 92 | * kernel. (ELF binaries would break with > 64K PAGE_SIZE since | ||
| 93 | * the sections are only aligned that strongly). | ||
| 94 | * | ||
| 95 | * The operations performed for extraction are thus: | ||
| 96 | * | ||
| 97 | * ((X << FOO_SHIFT_LEFT) >> FOO_SHIFT_RIGHT) & ~0x3 | ||
| 98 | * | ||
| 99 | */ | ||
| 100 | |||
| 101 | #define A (3 + (PAGE_SHIFT - 3) - 1) | ||
| 102 | #define B (A + 1) | ||
| 103 | #define C (B + (PAGE_SHIFT - 2) - 1) | ||
| 104 | #define D (C + 1) | ||
| 105 | #define E (D + (PAGE_SHIFT - 2) - 1) | ||
| 106 | #define F (E + 1) | ||
| 107 | |||
| 108 | #define PMD_SHIFT_LEFT (64 - D) | ||
| 109 | #define PMD_SHIFT_RIGHT (64 - (D - B) - 2) | ||
| 110 | #define PGDIR_SHIFT_LEFT (64 - F) | ||
| 111 | #define PGDIR_SHIFT_RIGHT (64 - (F - D) - 2) | ||
| 112 | #define LOW_MASK_BITS 0x3 | ||
| 113 | |||
| 114 | /* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss */ | ||
| 115 | ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS | ||
| 116 | add %g3, %g3, %g5 ! Compute VPTE base | ||
| 117 | cmp %g4, %g5 ! VPTE miss? | ||
| 118 | bgeu,pt %xcc, 1f ! Continue here | ||
| 119 | andcc %g4, TAG_CONTEXT_BITS, %g5 ! tl0 miss Nucleus test | ||
| 120 | ba,a,pt %xcc, from_tl1_trap ! Fall to tl0 miss | ||
| 121 | 1: sllx %g6, VPTE_SHIFT, %g4 ! Position TAG_ACCESS | ||
| 122 | or %g4, %g5, %g4 ! Prepare TAG_ACCESS | ||
| 123 | |||
| 124 | /* TLB1 ** ICACHE line 2: Quick VPTE miss */ | ||
| 125 | mov TSB_REG, %g1 ! Grab TSB reg | ||
| 126 | ldxa [%g1] ASI_DMMU, %g5 ! Doing PGD caching? | ||
| 127 | sllx %g6, PMD_SHIFT_LEFT, %g1 ! Position PMD offset | ||
| 128 | be,pn %xcc, sparc64_vpte_nucleus ! Is it from Nucleus? | ||
| 129 | srlx %g1, PMD_SHIFT_RIGHT, %g1 ! Mask PMD offset bits | ||
| 130 | brnz,pt %g5, sparc64_vpte_continue ! Yep, go like smoke | ||
| 131 | andn %g1, LOW_MASK_BITS, %g1 ! Final PMD mask | ||
| 132 | sllx %g6, PGDIR_SHIFT_LEFT, %g5 ! Position PGD offset | ||
| 133 | |||
| 134 | /* TLB1 ** ICACHE line 3: Quick VPTE miss */ | ||
| 135 | srlx %g5, PGDIR_SHIFT_RIGHT, %g5 ! Mask PGD offset bits | ||
| 136 | andn %g5, LOW_MASK_BITS, %g5 ! Final PGD mask | ||
| 137 | lduwa [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD | ||
| 138 | brz,pn %g5, vpte_noent ! Valid? | ||
| 139 | sparc64_kpte_continue: | ||
| 140 | sllx %g5, 11, %g5 ! Shift into place | ||
| 141 | sparc64_vpte_continue: | ||
| 142 | lduwa [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD | ||
| 143 | sllx %g5, 11, %g5 ! Shift into place | ||
| 144 | brz,pn %g5, vpte_noent ! Valid? | ||
| 145 | |||
| 146 | /* TLB1 ** ICACHE line 4: Quick VPTE miss */ | ||
| 147 | mov (VALID_SZ_BITS >> 61), %g1 ! upper vpte into %g1 | ||
| 148 | sllx %g1, 61, %g1 ! finish calc | ||
| 149 | or %g5, VPTE_BITS, %g5 ! Prepare VPTE data | ||
| 150 | or %g5, %g1, %g5 ! ... | ||
| 151 | mov TLB_SFSR, %g1 ! Restore %g1 value | ||
| 152 | stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load VPTE into TLB | ||
| 153 | stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS | ||
| 154 | retry ! Load PTE once again | ||
| 155 | |||
| 156 | #undef VALID_SZ_BITS | ||
| 157 | #undef VPTE_SHIFT | ||
| 158 | #undef VPTE_BITS | ||
| 159 | #undef A | ||
| 160 | #undef B | ||
| 161 | #undef C | ||
| 162 | #undef D | ||
| 163 | #undef E | ||
| 164 | #undef F | ||
| 165 | #undef PMD_SHIFT_LEFT | ||
| 166 | #undef PMD_SHIFT_RIGHT | ||
| 167 | #undef PGDIR_SHIFT_LEFT | ||
| 168 | #undef PGDIR_SHIFT_RIGHT | ||
| 169 | #undef LOW_MASK_BITS | ||
| 170 | |||
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S deleted file mode 100644 index 6528786840c0..000000000000 --- a/arch/sparc64/kernel/dtlb_base.S +++ /dev/null | |||
| @@ -1,109 +0,0 @@ | |||
| 1 | /* $Id: dtlb_base.S,v 1.17 2001/10/11 22:33:52 davem Exp $ | ||
| 2 | * dtlb_base.S: Front end to DTLB miss replacement strategy. | ||
| 3 | * This is included directly into the trap table. | ||
| 4 | * | ||
| 5 | * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) | ||
| 6 | * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <asm/pgtable.h> | ||
| 10 | #include <asm/mmu.h> | ||
| 11 | |||
| 12 | /* %g1 TLB_SFSR (%g1 + %g1 == TLB_TAG_ACCESS) | ||
| 13 | * %g2 (KERN_HIGHBITS | KERN_LOWBITS) | ||
| 14 | * %g3 VPTE base (0xfffffffe00000000) Spitfire/Blackbird (44-bit VA space) | ||
| 15 | * (0xffe0000000000000) Cheetah (64-bit VA space) | ||
| 16 | * %g7 __pa(current->mm->pgd) | ||
| 17 | * | ||
| 18 | * The VPTE base value is completely magic, but note that | ||
| 19 | * few places in the kernel other than these TLB miss | ||
| 20 | * handlers know anything about the VPTE mechanism or | ||
| 21 | * how it works (see VPTE_SIZE, TASK_SIZE and PTRS_PER_PGD). | ||
| 22 | * Consider the 44-bit VADDR Ultra-I/II case as an example: | ||
| 23 | * | ||
| 24 | * VA[0 : (1<<43)] produce VPTE index [%g3 : 0] | ||
| 25 | * VA[0 : -(1<<43)] produce VPTE index [%g3-(1<<(43-PAGE_SHIFT+3)) : %g3] | ||
| 26 | * | ||
| 27 | * For Cheetah's 64-bit VADDR space this is: | ||
| 28 | * | ||
| 29 | * VA[0 : (1<<63)] produce VPTE index [%g3 : 0] | ||
| 30 | * VA[0 : -(1<<63)] produce VPTE index [%g3-(1<<(63-PAGE_SHIFT+3)) : %g3] | ||
| 31 | * | ||
| 32 | * If you're paying attention you'll notice that this means half of | ||
| 33 | * the VPTE table is above %g3 and half is below, low VA addresses | ||
| 34 | * map progressively upwards from %g3, and high VA addresses map | ||
| 35 | * progressively upwards towards %g3. This trick was needed to make | ||
| 36 | * the same 8 instruction handler work both for Spitfire/Blackbird's | ||
| 37 | * peculiar VA space hole configuration and the full 64-bit VA space | ||
| 38 | * one of Cheetah at the same time. | ||
| 39 | */ | ||
| 40 | |||
| 41 | /* Ways we can get here: | ||
| 42 | * | ||
| 43 | * 1) Nucleus loads and stores to/from PA-->VA direct mappings. | ||
| 44 | * 2) Nucleus loads and stores to/from vmalloc() areas. | ||
| 45 | * 3) User loads and stores. | ||
| 46 | * 4) User space accesses by nucleus at tl0 | ||
| 47 | */ | ||
| 48 | |||
| 49 | #if PAGE_SHIFT == 13 | ||
| 50 | /* | ||
| 51 | * To compute vpte offset, we need to do ((addr >> 13) << 3), | ||
| 52 | * which can be optimized to (addr >> 10) if bits 10/11/12 can | ||
| 53 | * be guaranteed to be 0 ... mmu_context.h does guarantee this | ||
| 54 | * by only using 10 bits in the hwcontext value. | ||
| 55 | */ | ||
| 56 | #define CREATE_VPTE_OFFSET1(r1, r2) nop | ||
| 57 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | ||
| 58 | srax r1, 10, r2 | ||
| 59 | #else | ||
| 60 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | ||
| 61 | srax r1, PAGE_SHIFT, r2 | ||
| 62 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | ||
| 63 | sllx r2, 3, r2 | ||
| 64 | #endif | ||
| 65 | |||
| 66 | /* DTLB ** ICACHE line 1: Quick user TLB misses */ | ||
| 67 | mov TLB_SFSR, %g1 | ||
| 68 | ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS | ||
| 69 | andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus? | ||
| 70 | from_tl1_trap: | ||
| 71 | rdpr %tl, %g5 ! For TL==3 test | ||
| 72 | CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset | ||
| 73 | be,pn %xcc, kvmap ! Yep, special processing | ||
| 74 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset | ||
| 75 | cmp %g5, 4 ! Last trap level? | ||
| 76 | |||
| 77 | /* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */ | ||
| 78 | be,pn %xcc, longpath ! Yep, cannot risk VPTE miss | ||
| 79 | nop ! delay slot | ||
| 80 | ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE | ||
| 81 | 1: brgez,pn %g5, longpath ! Invalid, branch out | ||
| 82 | nop ! Delay-slot | ||
| 83 | 9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB | ||
| 84 | retry ! Trap return | ||
| 85 | nop | ||
| 86 | |||
| 87 | /* DTLB ** ICACHE line 3: winfixups+real_faults */ | ||
| 88 | longpath: | ||
| 89 | rdpr %pstate, %g5 ! Move into alternate globals | ||
| 90 | wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate | ||
| 91 | rdpr %tl, %g4 ! See where we came from. | ||
| 92 | cmp %g4, 1 ! Is etrap/rtrap window fault? | ||
| 93 | mov TLB_TAG_ACCESS, %g4 ! Prepare for fault processing | ||
| 94 | ldxa [%g4] ASI_DMMU, %g5 ! Load faulting VA page | ||
| 95 | be,pt %xcc, sparc64_realfault_common ! Jump to normal fault handling | ||
| 96 | mov FAULT_CODE_DTLB, %g4 ! It was read from DTLB | ||
| 97 | |||
| 98 | /* DTLB ** ICACHE line 4: Unused... */ | ||
| 99 | ba,a,pt %xcc, winfix_trampoline ! Call window fixup code | ||
| 100 | nop | ||
| 101 | nop | ||
| 102 | nop | ||
| 103 | nop | ||
| 104 | nop | ||
| 105 | nop | ||
| 106 | nop | ||
| 107 | |||
| 108 | #undef CREATE_VPTE_OFFSET1 | ||
| 109 | #undef CREATE_VPTE_OFFSET2 | ||
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S new file mode 100644 index 000000000000..09a6a15a7105 --- /dev/null +++ b/arch/sparc64/kernel/dtlb_miss.S | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* DTLB ** ICACHE line 1: Context 0 check and TSB load */ | ||
| 2 | ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! Get TSB 8K pointer | ||
| 3 | ldxa [%g0] ASI_DMMU, %g6 ! Get TAG TARGET | ||
| 4 | srlx %g6, 48, %g5 ! Get context | ||
| 5 | sllx %g6, 22, %g6 ! Zero out context | ||
| 6 | brz,pn %g5, kvmap_dtlb ! Context 0 processing | ||
| 7 | srlx %g6, 22, %g6 ! Delay slot | ||
| 8 | TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry | ||
| 9 | cmp %g4, %g6 ! Compare TAG | ||
| 10 | |||
| 11 | /* DTLB ** ICACHE line 2: TSB compare and TLB load */ | ||
| 12 | bne,pn %xcc, tsb_miss_dtlb ! Miss | ||
| 13 | mov FAULT_CODE_DTLB, %g3 | ||
| 14 | stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load TLB | ||
| 15 | retry ! Trap done | ||
| 16 | nop | ||
| 17 | nop | ||
| 18 | nop | ||
| 19 | nop | ||
| 20 | |||
| 21 | /* DTLB ** ICACHE line 3: */ | ||
| 22 | nop | ||
| 23 | nop | ||
| 24 | nop | ||
| 25 | nop | ||
| 26 | nop | ||
| 27 | nop | ||
| 28 | nop | ||
| 29 | nop | ||
| 30 | |||
| 31 | /* DTLB ** ICACHE line 4: */ | ||
| 32 | nop | ||
| 33 | nop | ||
| 34 | nop | ||
| 35 | nop | ||
| 36 | nop | ||
| 37 | nop | ||
| 38 | nop | ||
| 39 | nop | ||
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 7991e919d8ab..c69504aa638f 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c | |||
| @@ -277,10 +277,9 @@ static inline void *ebus_alloc(size_t size) | |||
| 277 | { | 277 | { |
| 278 | void *mem; | 278 | void *mem; |
| 279 | 279 | ||
| 280 | mem = kmalloc(size, GFP_ATOMIC); | 280 | mem = kzalloc(size, GFP_ATOMIC); |
| 281 | if (!mem) | 281 | if (!mem) |
| 282 | panic("ebus_alloc: out of memory"); | 282 | panic("ebus_alloc: out of memory"); |
| 283 | memset((char *)mem, 0, size); | ||
| 284 | return mem; | 283 | return mem; |
| 285 | } | 284 | } |
| 286 | 285 | ||
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index a73553ae7e53..6d0b3ed77a02 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S | |||
| @@ -50,7 +50,8 @@ do_fpdis: | |||
| 50 | add %g0, %g0, %g0 | 50 | add %g0, %g0, %g0 |
| 51 | ba,a,pt %xcc, rtrap_clr_l6 | 51 | ba,a,pt %xcc, rtrap_clr_l6 |
| 52 | 52 | ||
| 53 | 1: ldub [%g6 + TI_FPSAVED], %g5 | 53 | 1: TRAP_LOAD_THREAD_REG(%g6, %g1) |
| 54 | ldub [%g6 + TI_FPSAVED], %g5 | ||
| 54 | wr %g0, FPRS_FEF, %fprs | 55 | wr %g0, FPRS_FEF, %fprs |
| 55 | andcc %g5, FPRS_FEF, %g0 | 56 | andcc %g5, FPRS_FEF, %g0 |
| 56 | be,a,pt %icc, 1f | 57 | be,a,pt %icc, 1f |
| @@ -96,10 +97,22 @@ do_fpdis: | |||
| 96 | add %g6, TI_FPREGS + 0x80, %g1 | 97 | add %g6, TI_FPREGS + 0x80, %g1 |
| 97 | faddd %f0, %f2, %f4 | 98 | faddd %f0, %f2, %f4 |
| 98 | fmuld %f0, %f2, %f6 | 99 | fmuld %f0, %f2, %f6 |
| 99 | ldxa [%g3] ASI_DMMU, %g5 | 100 | |
| 101 | 661: ldxa [%g3] ASI_DMMU, %g5 | ||
| 102 | .section .sun4v_1insn_patch, "ax" | ||
| 103 | .word 661b | ||
| 104 | ldxa [%g3] ASI_MMU, %g5 | ||
| 105 | .previous | ||
| 106 | |||
| 100 | sethi %hi(sparc64_kern_sec_context), %g2 | 107 | sethi %hi(sparc64_kern_sec_context), %g2 |
| 101 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 | 108 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 |
| 102 | stxa %g2, [%g3] ASI_DMMU | 109 | |
| 110 | 661: stxa %g2, [%g3] ASI_DMMU | ||
| 111 | .section .sun4v_1insn_patch, "ax" | ||
| 112 | .word 661b | ||
| 113 | stxa %g2, [%g3] ASI_MMU | ||
| 114 | .previous | ||
| 115 | |||
| 103 | membar #Sync | 116 | membar #Sync |
| 104 | add %g6, TI_FPREGS + 0xc0, %g2 | 117 | add %g6, TI_FPREGS + 0xc0, %g2 |
| 105 | faddd %f0, %f2, %f8 | 118 | faddd %f0, %f2, %f8 |
| @@ -125,11 +138,23 @@ do_fpdis: | |||
| 125 | fzero %f32 | 138 | fzero %f32 |
| 126 | mov SECONDARY_CONTEXT, %g3 | 139 | mov SECONDARY_CONTEXT, %g3 |
| 127 | fzero %f34 | 140 | fzero %f34 |
| 128 | ldxa [%g3] ASI_DMMU, %g5 | 141 | |
| 142 | 661: ldxa [%g3] ASI_DMMU, %g5 | ||
| 143 | .section .sun4v_1insn_patch, "ax" | ||
| 144 | .word 661b | ||
| 145 | ldxa [%g3] ASI_MMU, %g5 | ||
| 146 | .previous | ||
| 147 | |||
| 129 | add %g6, TI_FPREGS, %g1 | 148 | add %g6, TI_FPREGS, %g1 |
| 130 | sethi %hi(sparc64_kern_sec_context), %g2 | 149 | sethi %hi(sparc64_kern_sec_context), %g2 |
| 131 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 | 150 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 |
| 132 | stxa %g2, [%g3] ASI_DMMU | 151 | |
| 152 | 661: stxa %g2, [%g3] ASI_DMMU | ||
| 153 | .section .sun4v_1insn_patch, "ax" | ||
| 154 | .word 661b | ||
| 155 | stxa %g2, [%g3] ASI_MMU | ||
| 156 | .previous | ||
| 157 | |||
| 133 | membar #Sync | 158 | membar #Sync |
| 134 | add %g6, TI_FPREGS + 0x40, %g2 | 159 | add %g6, TI_FPREGS + 0x40, %g2 |
| 135 | faddd %f32, %f34, %f36 | 160 | faddd %f32, %f34, %f36 |
| @@ -154,10 +179,22 @@ do_fpdis: | |||
| 154 | nop | 179 | nop |
| 155 | 3: mov SECONDARY_CONTEXT, %g3 | 180 | 3: mov SECONDARY_CONTEXT, %g3 |
| 156 | add %g6, TI_FPREGS, %g1 | 181 | add %g6, TI_FPREGS, %g1 |
| 157 | ldxa [%g3] ASI_DMMU, %g5 | 182 | |
| 183 | 661: ldxa [%g3] ASI_DMMU, %g5 | ||
| 184 | .section .sun4v_1insn_patch, "ax" | ||
| 185 | .word 661b | ||
| 186 | ldxa [%g3] ASI_MMU, %g5 | ||
| 187 | .previous | ||
| 188 | |||
| 158 | sethi %hi(sparc64_kern_sec_context), %g2 | 189 | sethi %hi(sparc64_kern_sec_context), %g2 |
| 159 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 | 190 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 |
| 160 | stxa %g2, [%g3] ASI_DMMU | 191 | |
| 192 | 661: stxa %g2, [%g3] ASI_DMMU | ||
| 193 | .section .sun4v_1insn_patch, "ax" | ||
| 194 | .word 661b | ||
| 195 | stxa %g2, [%g3] ASI_MMU | ||
| 196 | .previous | ||
| 197 | |||
| 161 | membar #Sync | 198 | membar #Sync |
| 162 | mov 0x40, %g2 | 199 | mov 0x40, %g2 |
| 163 | membar #Sync | 200 | membar #Sync |
| @@ -168,7 +205,13 @@ do_fpdis: | |||
| 168 | ldda [%g1 + %g2] ASI_BLK_S, %f48 | 205 | ldda [%g1 + %g2] ASI_BLK_S, %f48 |
| 169 | membar #Sync | 206 | membar #Sync |
| 170 | fpdis_exit: | 207 | fpdis_exit: |
| 171 | stxa %g5, [%g3] ASI_DMMU | 208 | |
| 209 | 661: stxa %g5, [%g3] ASI_DMMU | ||
| 210 | .section .sun4v_1insn_patch, "ax" | ||
| 211 | .word 661b | ||
| 212 | stxa %g5, [%g3] ASI_MMU | ||
| 213 | .previous | ||
| 214 | |||
| 172 | membar #Sync | 215 | membar #Sync |
| 173 | fpdis_exit2: | 216 | fpdis_exit2: |
| 174 | wr %g7, 0, %gsr | 217 | wr %g7, 0, %gsr |
| @@ -189,6 +232,7 @@ fp_other_bounce: | |||
| 189 | .globl do_fpother_check_fitos | 232 | .globl do_fpother_check_fitos |
| 190 | .align 32 | 233 | .align 32 |
| 191 | do_fpother_check_fitos: | 234 | do_fpother_check_fitos: |
| 235 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
| 192 | sethi %hi(fp_other_bounce - 4), %g7 | 236 | sethi %hi(fp_other_bounce - 4), %g7 |
| 193 | or %g7, %lo(fp_other_bounce - 4), %g7 | 237 | or %g7, %lo(fp_other_bounce - 4), %g7 |
| 194 | 238 | ||
| @@ -312,6 +356,7 @@ fitos_emul_fini: | |||
| 312 | .globl do_fptrap | 356 | .globl do_fptrap |
| 313 | .align 32 | 357 | .align 32 |
| 314 | do_fptrap: | 358 | do_fptrap: |
| 359 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
| 315 | stx %fsr, [%g6 + TI_XFSR] | 360 | stx %fsr, [%g6 + TI_XFSR] |
| 316 | do_fptrap_after_fsr: | 361 | do_fptrap_after_fsr: |
| 317 | ldub [%g6 + TI_FPSAVED], %g3 | 362 | ldub [%g6 + TI_FPSAVED], %g3 |
| @@ -321,10 +366,22 @@ do_fptrap_after_fsr: | |||
| 321 | rd %gsr, %g3 | 366 | rd %gsr, %g3 |
| 322 | stx %g3, [%g6 + TI_GSR] | 367 | stx %g3, [%g6 + TI_GSR] |
| 323 | mov SECONDARY_CONTEXT, %g3 | 368 | mov SECONDARY_CONTEXT, %g3 |
| 324 | ldxa [%g3] ASI_DMMU, %g5 | 369 | |
| 370 | 661: ldxa [%g3] ASI_DMMU, %g5 | ||
| 371 | .section .sun4v_1insn_patch, "ax" | ||
| 372 | .word 661b | ||
| 373 | ldxa [%g3] ASI_MMU, %g5 | ||
| 374 | .previous | ||
| 375 | |||
| 325 | sethi %hi(sparc64_kern_sec_context), %g2 | 376 | sethi %hi(sparc64_kern_sec_context), %g2 |
| 326 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 | 377 | ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 |
| 327 | stxa %g2, [%g3] ASI_DMMU | 378 | |
| 379 | 661: stxa %g2, [%g3] ASI_DMMU | ||
| 380 | .section .sun4v_1insn_patch, "ax" | ||
| 381 | .word 661b | ||
| 382 | stxa %g2, [%g3] ASI_MMU | ||
| 383 | .previous | ||
| 384 | |||
| 328 | membar #Sync | 385 | membar #Sync |
| 329 | add %g6, TI_FPREGS, %g2 | 386 | add %g6, TI_FPREGS, %g2 |
| 330 | andcc %g1, FPRS_DL, %g0 | 387 | andcc %g1, FPRS_DL, %g0 |
| @@ -339,7 +396,13 @@ do_fptrap_after_fsr: | |||
| 339 | stda %f48, [%g2 + %g3] ASI_BLK_S | 396 | stda %f48, [%g2 + %g3] ASI_BLK_S |
| 340 | 5: mov SECONDARY_CONTEXT, %g1 | 397 | 5: mov SECONDARY_CONTEXT, %g1 |
| 341 | membar #Sync | 398 | membar #Sync |
| 342 | stxa %g5, [%g1] ASI_DMMU | 399 | |
| 400 | 661: stxa %g5, [%g1] ASI_DMMU | ||
| 401 | .section .sun4v_1insn_patch, "ax" | ||
| 402 | .word 661b | ||
| 403 | stxa %g5, [%g1] ASI_MMU | ||
| 404 | .previous | ||
| 405 | |||
| 343 | membar #Sync | 406 | membar #Sync |
| 344 | ba,pt %xcc, etrap | 407 | ba,pt %xcc, etrap |
| 345 | wr %g0, 0, %fprs | 408 | wr %g0, 0, %fprs |
| @@ -353,8 +416,6 @@ do_fptrap_after_fsr: | |||
| 353 | * | 416 | * |
| 354 | * With this method we can do most of the cross-call tlb/cache | 417 | * With this method we can do most of the cross-call tlb/cache |
| 355 | * flushing very quickly. | 418 | * flushing very quickly. |
| 356 | * | ||
| 357 | * Current CPU's IRQ worklist table is locked into %g6, don't touch. | ||
| 358 | */ | 419 | */ |
| 359 | .text | 420 | .text |
| 360 | .align 32 | 421 | .align 32 |
| @@ -378,6 +439,8 @@ do_ivec: | |||
| 378 | sllx %g2, %g4, %g2 | 439 | sllx %g2, %g4, %g2 |
| 379 | sllx %g4, 2, %g4 | 440 | sllx %g4, 2, %g4 |
| 380 | 441 | ||
| 442 | TRAP_LOAD_IRQ_WORK(%g6, %g1) | ||
| 443 | |||
| 381 | lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ | 444 | lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ |
| 382 | stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ | 445 | stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ |
| 383 | stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ | 446 | stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ |
| @@ -399,76 +462,6 @@ do_ivec_xcall: | |||
| 399 | 1: jmpl %g3, %g0 | 462 | 1: jmpl %g3, %g0 |
| 400 | nop | 463 | nop |
| 401 | 464 | ||
| 402 | .globl save_alternate_globals | ||
| 403 | save_alternate_globals: /* %o0 = save_area */ | ||
| 404 | rdpr %pstate, %o5 | ||
| 405 | andn %o5, PSTATE_IE, %o1 | ||
| 406 | wrpr %o1, PSTATE_AG, %pstate | ||
| 407 | stx %g0, [%o0 + 0x00] | ||
| 408 | stx %g1, [%o0 + 0x08] | ||
| 409 | stx %g2, [%o0 + 0x10] | ||
| 410 | stx %g3, [%o0 + 0x18] | ||
| 411 | stx %g4, [%o0 + 0x20] | ||
| 412 | stx %g5, [%o0 + 0x28] | ||
| 413 | stx %g6, [%o0 + 0x30] | ||
| 414 | stx %g7, [%o0 + 0x38] | ||
| 415 | wrpr %o1, PSTATE_IG, %pstate | ||
| 416 | stx %g0, [%o0 + 0x40] | ||
| 417 | stx %g1, [%o0 + 0x48] | ||
| 418 | stx %g2, [%o0 + 0x50] | ||
| 419 | stx %g3, [%o0 + 0x58] | ||
| 420 | stx %g4, [%o0 + 0x60] | ||
| 421 | stx %g5, [%o0 + 0x68] | ||
| 422 | stx %g6, [%o0 + 0x70] | ||
| 423 | stx %g7, [%o0 + 0x78] | ||
| 424 | wrpr %o1, PSTATE_MG, %pstate | ||
| 425 | stx %g0, [%o0 + 0x80] | ||
| 426 | stx %g1, [%o0 + 0x88] | ||
| 427 | stx %g2, [%o0 + 0x90] | ||
| 428 | stx %g3, [%o0 + 0x98] | ||
| 429 | stx %g4, [%o0 + 0xa0] | ||
| 430 | stx %g5, [%o0 + 0xa8] | ||
| 431 | stx %g6, [%o0 + 0xb0] | ||
| 432 | stx %g7, [%o0 + 0xb8] | ||
| 433 | wrpr %o5, 0x0, %pstate | ||
| 434 | retl | ||
| 435 | nop | ||
| 436 | |||
| 437 | .globl restore_alternate_globals | ||
| 438 | restore_alternate_globals: /* %o0 = save_area */ | ||
| 439 | rdpr %pstate, %o5 | ||
| 440 | andn %o5, PSTATE_IE, %o1 | ||
| 441 | wrpr %o1, PSTATE_AG, %pstate | ||
| 442 | ldx [%o0 + 0x00], %g0 | ||
| 443 | ldx [%o0 + 0x08], %g1 | ||
| 444 | ldx [%o0 + 0x10], %g2 | ||
| 445 | ldx [%o0 + 0x18], %g3 | ||
| 446 | ldx [%o0 + 0x20], %g4 | ||
| 447 | ldx [%o0 + 0x28], %g5 | ||
| 448 | ldx [%o0 + 0x30], %g6 | ||
| 449 | ldx [%o0 + 0x38], %g7 | ||
| 450 | wrpr %o1, PSTATE_IG, %pstate | ||
| 451 | ldx [%o0 + 0x40], %g0 | ||
| 452 | ldx [%o0 + 0x48], %g1 | ||
| 453 | ldx [%o0 + 0x50], %g2 | ||
| 454 | ldx [%o0 + 0x58], %g3 | ||
| 455 | ldx [%o0 + 0x60], %g4 | ||
| 456 | ldx [%o0 + 0x68], %g5 | ||
| 457 | ldx [%o0 + 0x70], %g6 | ||
| 458 | ldx [%o0 + 0x78], %g7 | ||
| 459 | wrpr %o1, PSTATE_MG, %pstate | ||
| 460 | ldx [%o0 + 0x80], %g0 | ||
| 461 | ldx [%o0 + 0x88], %g1 | ||
| 462 | ldx [%o0 + 0x90], %g2 | ||
| 463 | ldx [%o0 + 0x98], %g3 | ||
| 464 | ldx [%o0 + 0xa0], %g4 | ||
| 465 | ldx [%o0 + 0xa8], %g5 | ||
| 466 | ldx [%o0 + 0xb0], %g6 | ||
| 467 | ldx [%o0 + 0xb8], %g7 | ||
| 468 | wrpr %o5, 0x0, %pstate | ||
| 469 | retl | ||
| 470 | nop | ||
| 471 | |||
| 472 | .globl getcc, setcc | 465 | .globl getcc, setcc |
| 473 | getcc: | 466 | getcc: |
| 474 | ldx [%o0 + PT_V9_TSTATE], %o1 | 467 | ldx [%o0 + PT_V9_TSTATE], %o1 |
| @@ -488,9 +481,24 @@ setcc: | |||
| 488 | retl | 481 | retl |
| 489 | stx %o1, [%o0 + PT_V9_TSTATE] | 482 | stx %o1, [%o0 + PT_V9_TSTATE] |
| 490 | 483 | ||
| 491 | .globl utrap, utrap_ill | 484 | .globl utrap_trap |
| 492 | utrap: brz,pn %g1, etrap | 485 | utrap_trap: /* %g3=handler,%g4=level */ |
| 486 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
| 487 | ldx [%g6 + TI_UTRAPS], %g1 | ||
| 488 | brnz,pt %g1, invoke_utrap | ||
| 493 | nop | 489 | nop |
| 490 | |||
| 491 | ba,pt %xcc, etrap | ||
| 492 | rd %pc, %g7 | ||
| 493 | mov %l4, %o1 | ||
| 494 | call bad_trap | ||
| 495 | add %sp, PTREGS_OFF, %o0 | ||
| 496 | ba,pt %xcc, rtrap | ||
| 497 | clr %l6 | ||
| 498 | |||
| 499 | invoke_utrap: | ||
| 500 | sllx %g3, 3, %g3 | ||
| 501 | ldx [%g1 + %g3], %g1 | ||
| 494 | save %sp, -128, %sp | 502 | save %sp, -128, %sp |
| 495 | rdpr %tstate, %l6 | 503 | rdpr %tstate, %l6 |
| 496 | rdpr %cwp, %l7 | 504 | rdpr %cwp, %l7 |
| @@ -500,17 +508,6 @@ utrap: brz,pn %g1, etrap | |||
| 500 | rdpr %tnpc, %l7 | 508 | rdpr %tnpc, %l7 |
| 501 | wrpr %g1, 0, %tnpc | 509 | wrpr %g1, 0, %tnpc |
| 502 | done | 510 | done |
| 503 | utrap_ill: | ||
| 504 | call bad_trap | ||
| 505 | add %sp, PTREGS_OFF, %o0 | ||
| 506 | ba,pt %xcc, rtrap | ||
| 507 | clr %l6 | ||
| 508 | |||
| 509 | /* XXX Here is stuff we still need to write... -DaveM XXX */ | ||
| 510 | .globl netbsd_syscall | ||
| 511 | netbsd_syscall: | ||
| 512 | retl | ||
| 513 | nop | ||
| 514 | 511 | ||
| 515 | /* We need to carefully read the error status, ACK | 512 | /* We need to carefully read the error status, ACK |
| 516 | * the errors, prevent recursive traps, and pass the | 513 | * the errors, prevent recursive traps, and pass the |
| @@ -1001,7 +998,7 @@ dcpe_icpe_tl1_common: | |||
| 1001 | * %g3: scratch | 998 | * %g3: scratch |
| 1002 | * %g4: AFSR | 999 | * %g4: AFSR |
| 1003 | * %g5: AFAR | 1000 | * %g5: AFAR |
| 1004 | * %g6: current thread ptr | 1001 | * %g6: unused, will have current thread ptr after etrap |
| 1005 | * %g7: scratch | 1002 | * %g7: scratch |
| 1006 | */ | 1003 | */ |
| 1007 | __cheetah_log_error: | 1004 | __cheetah_log_error: |
| @@ -1539,13 +1536,14 @@ ret_from_syscall: | |||
| 1539 | 1536 | ||
| 1540 | 1: b,pt %xcc, ret_sys_call | 1537 | 1: b,pt %xcc, ret_sys_call |
| 1541 | ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 | 1538 | ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 |
| 1542 | sparc_exit: wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate | 1539 | sparc_exit: rdpr %pstate, %g2 |
| 1540 | wrpr %g2, PSTATE_IE, %pstate | ||
| 1543 | rdpr %otherwin, %g1 | 1541 | rdpr %otherwin, %g1 |
| 1544 | rdpr %cansave, %g3 | 1542 | rdpr %cansave, %g3 |
| 1545 | add %g3, %g1, %g3 | 1543 | add %g3, %g1, %g3 |
| 1546 | wrpr %g3, 0x0, %cansave | 1544 | wrpr %g3, 0x0, %cansave |
| 1547 | wrpr %g0, 0x0, %otherwin | 1545 | wrpr %g0, 0x0, %otherwin |
| 1548 | wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate | 1546 | wrpr %g2, 0x0, %pstate |
| 1549 | ba,pt %xcc, sys_exit | 1547 | ba,pt %xcc, sys_exit |
| 1550 | stb %g0, [%g6 + TI_WSAVED] | 1548 | stb %g0, [%g6 + TI_WSAVED] |
| 1551 | 1549 | ||
| @@ -1690,3 +1688,138 @@ __flushw_user: | |||
| 1690 | restore %g0, %g0, %g0 | 1688 | restore %g0, %g0, %g0 |
| 1691 | 2: retl | 1689 | 2: retl |
| 1692 | nop | 1690 | nop |
| 1691 | |||
| 1692 | #ifdef CONFIG_SMP | ||
| 1693 | .globl hard_smp_processor_id | ||
| 1694 | hard_smp_processor_id: | ||
| 1695 | #endif | ||
| 1696 | .globl real_hard_smp_processor_id | ||
| 1697 | real_hard_smp_processor_id: | ||
| 1698 | __GET_CPUID(%o0) | ||
| 1699 | retl | ||
| 1700 | nop | ||
| 1701 | |||
| 1702 | /* %o0: devhandle | ||
| 1703 | * %o1: devino | ||
| 1704 | * | ||
| 1705 | * returns %o0: sysino | ||
| 1706 | */ | ||
| 1707 | .globl sun4v_devino_to_sysino | ||
| 1708 | sun4v_devino_to_sysino: | ||
| 1709 | mov HV_FAST_INTR_DEVINO2SYSINO, %o5 | ||
| 1710 | ta HV_FAST_TRAP | ||
| 1711 | retl | ||
| 1712 | mov %o1, %o0 | ||
| 1713 | |||
| 1714 | /* %o0: sysino | ||
| 1715 | * | ||
| 1716 | * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED}) | ||
| 1717 | */ | ||
| 1718 | .globl sun4v_intr_getenabled | ||
| 1719 | sun4v_intr_getenabled: | ||
| 1720 | mov HV_FAST_INTR_GETENABLED, %o5 | ||
| 1721 | ta HV_FAST_TRAP | ||
| 1722 | retl | ||
| 1723 | mov %o1, %o0 | ||
| 1724 | |||
| 1725 | /* %o0: sysino | ||
| 1726 | * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) | ||
| 1727 | */ | ||
| 1728 | .globl sun4v_intr_setenabled | ||
| 1729 | sun4v_intr_setenabled: | ||
| 1730 | mov HV_FAST_INTR_SETENABLED, %o5 | ||
| 1731 | ta HV_FAST_TRAP | ||
| 1732 | retl | ||
| 1733 | nop | ||
| 1734 | |||
| 1735 | /* %o0: sysino | ||
| 1736 | * | ||
| 1737 | * returns %o0: intr_state (HV_INTR_STATE_*) | ||
| 1738 | */ | ||
| 1739 | .globl sun4v_intr_getstate | ||
| 1740 | sun4v_intr_getstate: | ||
| 1741 | mov HV_FAST_INTR_GETSTATE, %o5 | ||
| 1742 | ta HV_FAST_TRAP | ||
| 1743 | retl | ||
| 1744 | mov %o1, %o0 | ||
| 1745 | |||
| 1746 | /* %o0: sysino | ||
| 1747 | * %o1: intr_state (HV_INTR_STATE_*) | ||
| 1748 | */ | ||
| 1749 | .globl sun4v_intr_setstate | ||
| 1750 | sun4v_intr_setstate: | ||
| 1751 | mov HV_FAST_INTR_SETSTATE, %o5 | ||
| 1752 | ta HV_FAST_TRAP | ||
| 1753 | retl | ||
| 1754 | nop | ||
| 1755 | |||
| 1756 | /* %o0: sysino | ||
| 1757 | * | ||
| 1758 | * returns %o0: cpuid | ||
| 1759 | */ | ||
| 1760 | .globl sun4v_intr_gettarget | ||
| 1761 | sun4v_intr_gettarget: | ||
| 1762 | mov HV_FAST_INTR_GETTARGET, %o5 | ||
| 1763 | ta HV_FAST_TRAP | ||
| 1764 | retl | ||
| 1765 | mov %o1, %o0 | ||
| 1766 | |||
| 1767 | /* %o0: sysino | ||
| 1768 | * %o1: cpuid | ||
| 1769 | */ | ||
| 1770 | .globl sun4v_intr_settarget | ||
| 1771 | sun4v_intr_settarget: | ||
| 1772 | mov HV_FAST_INTR_SETTARGET, %o5 | ||
| 1773 | ta HV_FAST_TRAP | ||
| 1774 | retl | ||
| 1775 | nop | ||
| 1776 | |||
| 1777 | /* %o0: type | ||
| 1778 | * %o1: queue paddr | ||
| 1779 | * %o2: num queue entries | ||
| 1780 | * | ||
| 1781 | * returns %o0: status | ||
| 1782 | */ | ||
| 1783 | .globl sun4v_cpu_qconf | ||
| 1784 | sun4v_cpu_qconf: | ||
| 1785 | mov HV_FAST_CPU_QCONF, %o5 | ||
| 1786 | ta HV_FAST_TRAP | ||
| 1787 | retl | ||
| 1788 | nop | ||
| 1789 | |||
| 1790 | /* returns %o0: status | ||
| 1791 | */ | ||
| 1792 | .globl sun4v_cpu_yield | ||
| 1793 | sun4v_cpu_yield: | ||
| 1794 | mov HV_FAST_CPU_YIELD, %o5 | ||
| 1795 | ta HV_FAST_TRAP | ||
| 1796 | retl | ||
| 1797 | nop | ||
| 1798 | |||
| 1799 | /* %o0: num cpus in cpu list | ||
| 1800 | * %o1: cpu list paddr | ||
| 1801 | * %o2: mondo block paddr | ||
| 1802 | * | ||
| 1803 | * returns %o0: status | ||
| 1804 | */ | ||
| 1805 | .globl sun4v_cpu_mondo_send | ||
| 1806 | sun4v_cpu_mondo_send: | ||
| 1807 | mov HV_FAST_CPU_MONDO_SEND, %o5 | ||
| 1808 | ta HV_FAST_TRAP | ||
| 1809 | retl | ||
| 1810 | nop | ||
| 1811 | |||
| 1812 | /* %o0: CPU ID | ||
| 1813 | * | ||
| 1814 | * returns %o0: -status if status non-zero, else | ||
| 1815 | * %o0: cpu state as HV_CPU_STATE_* | ||
| 1816 | */ | ||
| 1817 | .globl sun4v_cpu_state | ||
| 1818 | sun4v_cpu_state: | ||
| 1819 | mov HV_FAST_CPU_STATE, %o5 | ||
| 1820 | ta HV_FAST_TRAP | ||
| 1821 | brnz,pn %o0, 1f | ||
| 1822 | sub %g0, %o0, %o0 | ||
| 1823 | mov %o1, %o0 | ||
| 1824 | 1: retl | ||
| 1825 | nop | ||
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 0d8eba21111b..149383835c25 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | .globl etrap, etrap_irq, etraptl1 | 31 | .globl etrap, etrap_irq, etraptl1 |
| 32 | etrap: rdpr %pil, %g2 | 32 | etrap: rdpr %pil, %g2 |
| 33 | etrap_irq: | 33 | etrap_irq: |
| 34 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
| 34 | rdpr %tstate, %g1 | 35 | rdpr %tstate, %g1 |
| 35 | sllx %g2, 20, %g3 | 36 | sllx %g2, 20, %g3 |
| 36 | andcc %g1, TSTATE_PRIV, %g0 | 37 | andcc %g1, TSTATE_PRIV, %g0 |
| @@ -54,7 +55,31 @@ etrap_irq: | |||
| 54 | rd %y, %g3 | 55 | rd %y, %g3 |
| 55 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] | 56 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] |
| 56 | st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] | 57 | st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] |
| 57 | save %g2, -STACK_BIAS, %sp ! Ordering here is critical | 58 | |
| 59 | rdpr %cansave, %g1 | ||
| 60 | brnz,pt %g1, etrap_save | ||
| 61 | nop | ||
| 62 | |||
| 63 | rdpr %cwp, %g1 | ||
| 64 | add %g1, 2, %g1 | ||
| 65 | wrpr %g1, %cwp | ||
| 66 | be,pt %xcc, etrap_user_spill | ||
| 67 | mov ASI_AIUP, %g3 | ||
| 68 | |||
| 69 | rdpr %otherwin, %g3 | ||
| 70 | brz %g3, etrap_kernel_spill | ||
| 71 | mov ASI_AIUS, %g3 | ||
| 72 | |||
| 73 | etrap_user_spill: | ||
| 74 | |||
| 75 | wr %g3, 0x0, %asi | ||
| 76 | ldx [%g6 + TI_FLAGS], %g3 | ||
| 77 | and %g3, _TIF_32BIT, %g3 | ||
| 78 | brnz,pt %g3, etrap_user_spill_32bit | ||
| 79 | nop | ||
| 80 | ba,a,pt %xcc, etrap_user_spill_64bit | ||
| 81 | |||
| 82 | etrap_save: save %g2, -STACK_BIAS, %sp | ||
| 58 | mov %g6, %l6 | 83 | mov %g6, %l6 |
| 59 | 84 | ||
| 60 | bne,pn %xcc, 3f | 85 | bne,pn %xcc, 3f |
| @@ -70,42 +95,56 @@ etrap_irq: | |||
| 70 | wrpr %g2, 0, %wstate | 95 | wrpr %g2, 0, %wstate |
| 71 | sethi %hi(sparc64_kern_pri_context), %g2 | 96 | sethi %hi(sparc64_kern_pri_context), %g2 |
| 72 | ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3 | 97 | ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3 |
| 73 | stxa %g3, [%l4] ASI_DMMU | 98 | |
| 74 | flush %l6 | 99 | 661: stxa %g3, [%l4] ASI_DMMU |
| 75 | wr %g0, ASI_AIUS, %asi | 100 | .section .sun4v_1insn_patch, "ax" |
| 76 | 2: wrpr %g0, 0x0, %tl | 101 | .word 661b |
| 77 | mov %g4, %l4 | 102 | stxa %g3, [%l4] ASI_MMU |
| 103 | .previous | ||
| 104 | |||
| 105 | sethi %hi(KERNBASE), %l4 | ||
| 106 | flush %l4 | ||
| 107 | mov ASI_AIUS, %l7 | ||
| 108 | 2: mov %g4, %l4 | ||
| 78 | mov %g5, %l5 | 109 | mov %g5, %l5 |
| 110 | add %g7, 4, %l2 | ||
| 111 | |||
| 112 | /* Go to trap time globals so we can save them. */ | ||
| 113 | 661: wrpr %g0, ETRAP_PSTATE1, %pstate | ||
| 114 | .section .sun4v_1insn_patch, "ax" | ||
| 115 | .word 661b | ||
| 116 | SET_GL(0) | ||
| 117 | .previous | ||
| 79 | 118 | ||
| 80 | mov %g7, %l2 | ||
| 81 | wrpr %g0, ETRAP_PSTATE1, %pstate | ||
| 82 | stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] | 119 | stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] |
| 83 | stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] | 120 | stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] |
| 121 | sllx %l7, 24, %l7 | ||
| 84 | stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] | 122 | stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] |
| 123 | rdpr %cwp, %l0 | ||
| 85 | stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] | 124 | stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] |
| 86 | stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] | 125 | stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] |
| 87 | stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] | 126 | stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] |
| 88 | |||
| 89 | stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] | 127 | stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] |
| 128 | or %l7, %l0, %l7 | ||
| 129 | sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 | ||
| 130 | or %l7, %l0, %l7 | ||
| 131 | wrpr %l2, %tnpc | ||
| 132 | wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate | ||
| 90 | stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] | 133 | stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] |
| 91 | stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] | 134 | stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] |
| 92 | stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] | 135 | stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] |
| 93 | stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] | 136 | stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] |
| 94 | stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] | 137 | stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] |
| 95 | stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] | 138 | stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] |
| 96 | |||
| 97 | stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] | 139 | stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] |
| 98 | stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] | ||
| 99 | wrpr %g0, ETRAP_PSTATE2, %pstate | ||
| 100 | mov %l6, %g6 | 140 | mov %l6, %g6 |
| 101 | #ifdef CONFIG_SMP | 141 | stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] |
| 102 | mov TSB_REG, %g3 | 142 | LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %l1) |
| 103 | ldxa [%g3] ASI_IMMU, %g5 | 143 | ldx [%g6 + TI_TASK], %g4 |
| 104 | #endif | 144 | done |
| 105 | jmpl %l2 + 0x4, %g0 | ||
| 106 | ldx [%g6 + TI_TASK], %g4 | ||
| 107 | 145 | ||
| 108 | 3: ldub [%l6 + TI_FPDEPTH], %l5 | 146 | 3: mov ASI_P, %l7 |
| 147 | ldub [%l6 + TI_FPDEPTH], %l5 | ||
| 109 | add %l6, TI_FPSAVED + 1, %l4 | 148 | add %l6, TI_FPSAVED + 1, %l4 |
| 110 | srl %l5, 1, %l3 | 149 | srl %l5, 1, %l3 |
| 111 | add %l5, 2, %l5 | 150 | add %l5, 2, %l5 |
| @@ -125,6 +164,7 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. | |||
| 125 | * 0x58 TL4's TT | 164 | * 0x58 TL4's TT |
| 126 | * 0x60 TL | 165 | * 0x60 TL |
| 127 | */ | 166 | */ |
| 167 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
| 128 | sub %sp, ((4 * 8) * 4) + 8, %g2 | 168 | sub %sp, ((4 * 8) * 4) + 8, %g2 |
| 129 | rdpr %tl, %g1 | 169 | rdpr %tl, %g1 |
| 130 | 170 | ||
| @@ -148,6 +188,11 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. | |||
| 148 | rdpr %tt, %g3 | 188 | rdpr %tt, %g3 |
| 149 | stx %g3, [%g2 + STACK_BIAS + 0x38] | 189 | stx %g3, [%g2 + STACK_BIAS + 0x38] |
| 150 | 190 | ||
| 191 | sethi %hi(is_sun4v), %g3 | ||
| 192 | lduw [%g3 + %lo(is_sun4v)], %g3 | ||
| 193 | brnz,pn %g3, finish_tl1_capture | ||
| 194 | nop | ||
| 195 | |||
| 151 | wrpr %g0, 3, %tl | 196 | wrpr %g0, 3, %tl |
| 152 | rdpr %tstate, %g3 | 197 | rdpr %tstate, %g3 |
| 153 | stx %g3, [%g2 + STACK_BIAS + 0x40] | 198 | stx %g3, [%g2 + STACK_BIAS + 0x40] |
| @@ -168,91 +213,20 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. | |||
| 168 | rdpr %tt, %g3 | 213 | rdpr %tt, %g3 |
| 169 | stx %g3, [%g2 + STACK_BIAS + 0x78] | 214 | stx %g3, [%g2 + STACK_BIAS + 0x78] |
| 170 | 215 | ||
| 171 | wrpr %g1, %tl | ||
| 172 | stx %g1, [%g2 + STACK_BIAS + 0x80] | 216 | stx %g1, [%g2 + STACK_BIAS + 0x80] |
| 173 | 217 | ||
| 218 | finish_tl1_capture: | ||
| 219 | wrpr %g0, 1, %tl | ||
| 220 | 661: nop | ||
| 221 | .section .sun4v_1insn_patch, "ax" | ||
| 222 | .word 661b | ||
| 223 | SET_GL(1) | ||
| 224 | .previous | ||
| 225 | |||
| 174 | rdpr %tstate, %g1 | 226 | rdpr %tstate, %g1 |
| 175 | sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 | 227 | sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 |
| 176 | ba,pt %xcc, 1b | 228 | ba,pt %xcc, 1b |
| 177 | andcc %g1, TSTATE_PRIV, %g0 | 229 | andcc %g1, TSTATE_PRIV, %g0 |
| 178 | 230 | ||
| 179 | .align 64 | ||
| 180 | .globl scetrap | ||
| 181 | scetrap: rdpr %pil, %g2 | ||
| 182 | rdpr %tstate, %g1 | ||
| 183 | sllx %g2, 20, %g3 | ||
| 184 | andcc %g1, TSTATE_PRIV, %g0 | ||
| 185 | or %g1, %g3, %g1 | ||
| 186 | bne,pn %xcc, 1f | ||
| 187 | sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2 | ||
| 188 | wrpr %g0, 7, %cleanwin | ||
| 189 | |||
| 190 | sllx %g1, 51, %g3 | ||
| 191 | sethi %hi(TASK_REGOFF), %g2 | ||
| 192 | or %g2, %lo(TASK_REGOFF), %g2 | ||
| 193 | brlz,pn %g3, 1f | ||
| 194 | add %g6, %g2, %g2 | ||
| 195 | wr %g0, 0, %fprs | ||
| 196 | 1: rdpr %tpc, %g3 | ||
| 197 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] | ||
| 198 | |||
| 199 | rdpr %tnpc, %g1 | ||
| 200 | stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] | ||
| 201 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] | ||
| 202 | save %g2, -STACK_BIAS, %sp ! Ordering here is critical | ||
| 203 | mov %g6, %l6 | ||
| 204 | bne,pn %xcc, 2f | ||
| 205 | mov ASI_P, %l7 | ||
| 206 | rdpr %canrestore, %g3 | ||
| 207 | |||
| 208 | rdpr %wstate, %g2 | ||
| 209 | wrpr %g0, 0, %canrestore | ||
| 210 | sll %g2, 3, %g2 | ||
| 211 | mov PRIMARY_CONTEXT, %l4 | ||
| 212 | wrpr %g3, 0, %otherwin | ||
| 213 | wrpr %g2, 0, %wstate | ||
| 214 | sethi %hi(sparc64_kern_pri_context), %g2 | ||
| 215 | ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3 | ||
| 216 | stxa %g3, [%l4] ASI_DMMU | ||
| 217 | flush %l6 | ||
| 218 | |||
| 219 | mov ASI_AIUS, %l7 | ||
| 220 | 2: mov %g4, %l4 | ||
| 221 | mov %g5, %l5 | ||
| 222 | add %g7, 0x4, %l2 | ||
| 223 | wrpr %g0, ETRAP_PSTATE1, %pstate | ||
| 224 | stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] | ||
| 225 | stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] | ||
| 226 | sllx %l7, 24, %l7 | ||
| 227 | |||
| 228 | stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] | ||
| 229 | rdpr %cwp, %l0 | ||
| 230 | stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] | ||
| 231 | stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] | ||
| 232 | stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] | ||
| 233 | stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] | ||
| 234 | or %l7, %l0, %l7 | ||
| 235 | sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 | ||
| 236 | |||
| 237 | or %l7, %l0, %l7 | ||
| 238 | wrpr %l2, %tnpc | ||
| 239 | wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate | ||
| 240 | stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] | ||
| 241 | stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] | ||
| 242 | stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] | ||
| 243 | stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] | ||
| 244 | stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] | ||
| 245 | |||
| 246 | stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] | ||
| 247 | stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] | ||
| 248 | mov %l6, %g6 | ||
| 249 | stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] | ||
| 250 | #ifdef CONFIG_SMP | ||
| 251 | mov TSB_REG, %g3 | ||
| 252 | ldxa [%g3] ASI_IMMU, %g5 | ||
| 253 | #endif | ||
| 254 | ldx [%g6 + TI_TASK], %g4 | ||
| 255 | done | ||
| 256 | |||
| 257 | #undef TASK_REGOFF | 231 | #undef TASK_REGOFF |
| 258 | #undef ETRAP_PSTATE1 | 232 | #undef ETRAP_PSTATE1 |
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index b49dcd4504b0..3eadac5e171e 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <asm/head.h> | 26 | #include <asm/head.h> |
| 27 | #include <asm/ttable.h> | 27 | #include <asm/ttable.h> |
| 28 | #include <asm/mmu.h> | 28 | #include <asm/mmu.h> |
| 29 | #include <asm/cpudata.h> | ||
| 29 | 30 | ||
| 30 | /* This section from from _start to sparc64_boot_end should fit into | 31 | /* This section from from _start to sparc64_boot_end should fit into |
| 31 | * 0x0000000000404000 to 0x0000000000408000. | 32 | * 0x0000000000404000 to 0x0000000000408000. |
| @@ -94,12 +95,17 @@ sparc64_boot: | |||
| 94 | wrpr %g1, 0x0, %pstate | 95 | wrpr %g1, 0x0, %pstate |
| 95 | ba,a,pt %xcc, 1f | 96 | ba,a,pt %xcc, 1f |
| 96 | 97 | ||
| 97 | .globl prom_finddev_name, prom_chosen_path | 98 | .globl prom_finddev_name, prom_chosen_path, prom_root_node |
| 98 | .globl prom_getprop_name, prom_mmu_name | 99 | .globl prom_getprop_name, prom_mmu_name, prom_peer_name |
| 99 | .globl prom_callmethod_name, prom_translate_name | 100 | .globl prom_callmethod_name, prom_translate_name, prom_root_compatible |
| 100 | .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache | 101 | .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache |
| 101 | .globl prom_boot_mapped_pc, prom_boot_mapping_mode | 102 | .globl prom_boot_mapped_pc, prom_boot_mapping_mode |
| 102 | .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low | 103 | .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low |
| 104 | .globl is_sun4v | ||
| 105 | prom_peer_name: | ||
| 106 | .asciz "peer" | ||
| 107 | prom_compatible_name: | ||
| 108 | .asciz "compatible" | ||
| 103 | prom_finddev_name: | 109 | prom_finddev_name: |
| 104 | .asciz "finddevice" | 110 | .asciz "finddevice" |
| 105 | prom_chosen_path: | 111 | prom_chosen_path: |
| @@ -116,7 +122,13 @@ prom_map_name: | |||
| 116 | .asciz "map" | 122 | .asciz "map" |
| 117 | prom_unmap_name: | 123 | prom_unmap_name: |
| 118 | .asciz "unmap" | 124 | .asciz "unmap" |
| 125 | prom_sun4v_name: | ||
| 126 | .asciz "sun4v" | ||
| 119 | .align 4 | 127 | .align 4 |
| 128 | prom_root_compatible: | ||
| 129 | .skip 64 | ||
| 130 | prom_root_node: | ||
| 131 | .word 0 | ||
| 120 | prom_mmu_ihandle_cache: | 132 | prom_mmu_ihandle_cache: |
| 121 | .word 0 | 133 | .word 0 |
| 122 | prom_boot_mapped_pc: | 134 | prom_boot_mapped_pc: |
| @@ -128,8 +140,54 @@ prom_boot_mapping_phys_high: | |||
| 128 | .xword 0 | 140 | .xword 0 |
| 129 | prom_boot_mapping_phys_low: | 141 | prom_boot_mapping_phys_low: |
| 130 | .xword 0 | 142 | .xword 0 |
| 143 | is_sun4v: | ||
| 144 | .word 0 | ||
| 131 | 1: | 145 | 1: |
| 132 | rd %pc, %l0 | 146 | rd %pc, %l0 |
| 147 | |||
| 148 | mov (1b - prom_peer_name), %l1 | ||
| 149 | sub %l0, %l1, %l1 | ||
| 150 | mov 0, %l2 | ||
| 151 | |||
| 152 | /* prom_root_node = prom_peer(0) */ | ||
| 153 | stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "peer" | ||
| 154 | mov 1, %l3 | ||
| 155 | stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1 | ||
| 156 | stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1 | ||
| 157 | stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, 0 | ||
| 158 | stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1 | ||
| 159 | call %l7 | ||
| 160 | add %sp, (2047 + 128), %o0 ! argument array | ||
| 161 | |||
| 162 | ldx [%sp + 2047 + 128 + 0x20], %l4 ! prom root node | ||
| 163 | mov (1b - prom_root_node), %l1 | ||
| 164 | sub %l0, %l1, %l1 | ||
| 165 | stw %l4, [%l1] | ||
| 166 | |||
| 167 | mov (1b - prom_getprop_name), %l1 | ||
| 168 | mov (1b - prom_compatible_name), %l2 | ||
| 169 | mov (1b - prom_root_compatible), %l5 | ||
| 170 | sub %l0, %l1, %l1 | ||
| 171 | sub %l0, %l2, %l2 | ||
| 172 | sub %l0, %l5, %l5 | ||
| 173 | |||
| 174 | /* prom_getproperty(prom_root_node, "compatible", | ||
| 175 | * &prom_root_compatible, 64) | ||
| 176 | */ | ||
| 177 | stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop" | ||
| 178 | mov 4, %l3 | ||
| 179 | stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4 | ||
| 180 | mov 1, %l3 | ||
| 181 | stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1 | ||
| 182 | stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, prom_root_node | ||
| 183 | stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible" | ||
| 184 | stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_root_compatible | ||
| 185 | mov 64, %l3 | ||
| 186 | stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size | ||
| 187 | stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1 | ||
| 188 | call %l7 | ||
| 189 | add %sp, (2047 + 128), %o0 ! argument array | ||
| 190 | |||
| 133 | mov (1b - prom_finddev_name), %l1 | 191 | mov (1b - prom_finddev_name), %l1 |
| 134 | mov (1b - prom_chosen_path), %l2 | 192 | mov (1b - prom_chosen_path), %l2 |
| 135 | mov (1b - prom_boot_mapped_pc), %l3 | 193 | mov (1b - prom_boot_mapped_pc), %l3 |
| @@ -238,6 +296,27 @@ prom_boot_mapping_phys_low: | |||
| 238 | add %sp, (192 + 128), %sp | 296 | add %sp, (192 + 128), %sp |
| 239 | 297 | ||
| 240 | sparc64_boot_after_remap: | 298 | sparc64_boot_after_remap: |
| 299 | sethi %hi(prom_root_compatible), %g1 | ||
| 300 | or %g1, %lo(prom_root_compatible), %g1 | ||
| 301 | sethi %hi(prom_sun4v_name), %g7 | ||
| 302 | or %g7, %lo(prom_sun4v_name), %g7 | ||
| 303 | mov 5, %g3 | ||
| 304 | 1: ldub [%g7], %g2 | ||
| 305 | ldub [%g1], %g4 | ||
| 306 | cmp %g2, %g4 | ||
| 307 | bne,pn %icc, 2f | ||
| 308 | add %g7, 1, %g7 | ||
| 309 | subcc %g3, 1, %g3 | ||
| 310 | bne,pt %xcc, 1b | ||
| 311 | add %g1, 1, %g1 | ||
| 312 | |||
| 313 | sethi %hi(is_sun4v), %g1 | ||
| 314 | or %g1, %lo(is_sun4v), %g1 | ||
| 315 | mov 1, %g7 | ||
| 316 | stw %g7, [%g1] | ||
| 317 | |||
| 318 | 2: | ||
| 319 | BRANCH_IF_SUN4V(g1, jump_to_sun4u_init) | ||
| 241 | BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot) | 320 | BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot) |
| 242 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot) | 321 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot) |
| 243 | ba,pt %xcc, spitfire_boot | 322 | ba,pt %xcc, spitfire_boot |
| @@ -301,20 +380,58 @@ jump_to_sun4u_init: | |||
| 301 | nop | 380 | nop |
| 302 | 381 | ||
| 303 | sun4u_init: | 382 | sun4u_init: |
| 383 | BRANCH_IF_SUN4V(g1, sun4v_init) | ||
| 384 | |||
| 304 | /* Set ctx 0 */ | 385 | /* Set ctx 0 */ |
| 305 | mov PRIMARY_CONTEXT, %g7 | 386 | mov PRIMARY_CONTEXT, %g7 |
| 306 | stxa %g0, [%g7] ASI_DMMU | 387 | stxa %g0, [%g7] ASI_DMMU |
| 307 | membar #Sync | 388 | membar #Sync |
| 308 | 389 | ||
| 309 | mov SECONDARY_CONTEXT, %g7 | 390 | mov SECONDARY_CONTEXT, %g7 |
| 310 | stxa %g0, [%g7] ASI_DMMU | 391 | stxa %g0, [%g7] ASI_DMMU |
| 311 | membar #Sync | 392 | membar #Sync |
| 312 | 393 | ||
| 313 | BRANCH_IF_ANY_CHEETAH(g1,g7,cheetah_tlb_fixup) | 394 | ba,pt %xcc, sun4u_continue |
| 395 | nop | ||
| 396 | |||
| 397 | sun4v_init: | ||
| 398 | /* Set ctx 0 */ | ||
| 399 | mov PRIMARY_CONTEXT, %g7 | ||
| 400 | stxa %g0, [%g7] ASI_MMU | ||
| 401 | membar #Sync | ||
| 402 | |||
| 403 | mov SECONDARY_CONTEXT, %g7 | ||
| 404 | stxa %g0, [%g7] ASI_MMU | ||
| 405 | membar #Sync | ||
| 406 | ba,pt %xcc, niagara_tlb_fixup | ||
| 407 | nop | ||
| 408 | |||
| 409 | sun4u_continue: | ||
| 410 | BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup) | ||
| 314 | 411 | ||
| 315 | ba,pt %xcc, spitfire_tlb_fixup | 412 | ba,pt %xcc, spitfire_tlb_fixup |
| 316 | nop | 413 | nop |
| 317 | 414 | ||
| 415 | niagara_tlb_fixup: | ||
| 416 | mov 3, %g2 /* Set TLB type to hypervisor. */ | ||
| 417 | sethi %hi(tlb_type), %g1 | ||
| 418 | stw %g2, [%g1 + %lo(tlb_type)] | ||
| 419 | |||
| 420 | /* Patch copy/clear ops. */ | ||
| 421 | call niagara_patch_copyops | ||
| 422 | nop | ||
| 423 | call niagara_patch_bzero | ||
| 424 | nop | ||
| 425 | call niagara_patch_pageops | ||
| 426 | nop | ||
| 427 | |||
| 428 | /* Patch TLB/cache ops. */ | ||
| 429 | call hypervisor_patch_cachetlbops | ||
| 430 | nop | ||
| 431 | |||
| 432 | ba,pt %xcc, tlb_fixup_done | ||
| 433 | nop | ||
| 434 | |||
| 318 | cheetah_tlb_fixup: | 435 | cheetah_tlb_fixup: |
| 319 | mov 2, %g2 /* Set TLB type to cheetah+. */ | 436 | mov 2, %g2 /* Set TLB type to cheetah+. */ |
| 320 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f) | 437 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f) |
| @@ -411,85 +528,55 @@ setup_trap_table: | |||
| 411 | wrpr %g0, 15, %pil | 528 | wrpr %g0, 15, %pil |
| 412 | 529 | ||
| 413 | /* Make the firmware call to jump over to the Linux trap table. */ | 530 | /* Make the firmware call to jump over to the Linux trap table. */ |
| 414 | call prom_set_trap_table | 531 | sethi %hi(is_sun4v), %o0 |
| 415 | sethi %hi(sparc64_ttable_tl0), %o0 | 532 | lduw [%o0 + %lo(is_sun4v)], %o0 |
| 533 | brz,pt %o0, 1f | ||
| 534 | nop | ||
| 416 | 535 | ||
| 417 | /* Start using proper page size encodings in ctx register. */ | 536 | TRAP_LOAD_TRAP_BLOCK(%g2, %g3) |
| 418 | sethi %hi(sparc64_kern_pri_context), %g3 | 537 | add %g2, TRAP_PER_CPU_FAULT_INFO, %g2 |
| 419 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 | 538 | stxa %g2, [%g0] ASI_SCRATCHPAD |
| 420 | mov PRIMARY_CONTEXT, %g1 | ||
| 421 | stxa %g2, [%g1] ASI_DMMU | ||
| 422 | membar #Sync | ||
| 423 | 539 | ||
| 424 | /* The Linux trap handlers expect various trap global registers | 540 | /* Compute physical address: |
| 425 | * to be setup with some fixed values. So here we set these | ||
| 426 | * up very carefully. These globals are: | ||
| 427 | * | ||
| 428 | * Alternate Globals (PSTATE_AG): | ||
| 429 | * | ||
| 430 | * %g6 --> current_thread_info() | ||
| 431 | * | ||
| 432 | * MMU Globals (PSTATE_MG): | ||
| 433 | * | ||
| 434 | * %g1 --> TLB_SFSR | ||
| 435 | * %g2 --> ((_PAGE_VALID | _PAGE_SZ4MB | | ||
| 436 | * _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | ||
| 437 | * ^ 0xfffff80000000000) | ||
| 438 | * (this %g2 value is used for computing the PAGE_OFFSET kernel | ||
| 439 | * TLB entries quickly, the virtual address of the fault XOR'd | ||
| 440 | * with this %g2 value is the PTE to load into the TLB) | ||
| 441 | * %g3 --> VPTE_BASE_CHEETAH or VPTE_BASE_SPITFIRE | ||
| 442 | * | 541 | * |
| 443 | * Interrupt Globals (PSTATE_IG, setup by init_irqwork_curcpu()): | 542 | * paddr = kern_base + (mmfsa_vaddr - KERNBASE) |
| 444 | * | ||
| 445 | * %g6 --> __irq_work[smp_processor_id()] | ||
| 446 | */ | 543 | */ |
| 544 | sethi %hi(KERNBASE), %g3 | ||
| 545 | sub %g2, %g3, %g2 | ||
| 546 | sethi %hi(kern_base), %g3 | ||
| 547 | ldx [%g3 + %lo(kern_base)], %g3 | ||
| 548 | add %g2, %g3, %o1 | ||
| 447 | 549 | ||
| 448 | rdpr %pstate, %o1 | 550 | call prom_set_trap_table_sun4v |
| 449 | mov %g6, %o2 | 551 | sethi %hi(sparc64_ttable_tl0), %o0 |
| 450 | wrpr %o1, PSTATE_AG, %pstate | 552 | |
| 451 | mov %o2, %g6 | 553 | ba,pt %xcc, 2f |
| 452 | |||
| 453 | #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) | ||
| 454 | #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | ||
| 455 | wrpr %o1, PSTATE_MG, %pstate | ||
| 456 | mov TSB_REG, %g1 | ||
| 457 | stxa %g0, [%g1] ASI_DMMU | ||
| 458 | membar #Sync | ||
| 459 | stxa %g0, [%g1] ASI_IMMU | ||
| 460 | membar #Sync | ||
| 461 | mov TLB_SFSR, %g1 | ||
| 462 | sethi %uhi(KERN_HIGHBITS), %g2 | ||
| 463 | or %g2, %ulo(KERN_HIGHBITS), %g2 | ||
| 464 | sllx %g2, 32, %g2 | ||
| 465 | or %g2, KERN_LOWBITS, %g2 | ||
| 466 | |||
| 467 | BRANCH_IF_ANY_CHEETAH(g3,g7,8f) | ||
| 468 | ba,pt %xcc, 9f | ||
| 469 | nop | 554 | nop |
| 470 | 555 | ||
| 471 | 8: | 556 | 1: call prom_set_trap_table |
| 472 | sethi %uhi(VPTE_BASE_CHEETAH), %g3 | 557 | sethi %hi(sparc64_ttable_tl0), %o0 |
| 473 | or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 | ||
| 474 | ba,pt %xcc, 2f | ||
| 475 | sllx %g3, 32, %g3 | ||
| 476 | 558 | ||
| 477 | 9: | 559 | /* Start using proper page size encodings in ctx register. */ |
| 478 | sethi %uhi(VPTE_BASE_SPITFIRE), %g3 | 560 | 2: sethi %hi(sparc64_kern_pri_context), %g3 |
| 479 | or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 | 561 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 |
| 480 | sllx %g3, 32, %g3 | ||
| 481 | 562 | ||
| 482 | 2: | 563 | mov PRIMARY_CONTEXT, %g1 |
| 483 | clr %g7 | 564 | |
| 484 | #undef KERN_HIGHBITS | 565 | 661: stxa %g2, [%g1] ASI_DMMU |
| 485 | #undef KERN_LOWBITS | 566 | .section .sun4v_1insn_patch, "ax" |
| 567 | .word 661b | ||
| 568 | stxa %g2, [%g1] ASI_MMU | ||
| 569 | .previous | ||
| 570 | |||
| 571 | membar #Sync | ||
| 486 | 572 | ||
| 487 | /* Kill PROM timer */ | 573 | /* Kill PROM timer */ |
| 488 | sethi %hi(0x80000000), %o2 | 574 | sethi %hi(0x80000000), %o2 |
| 489 | sllx %o2, 32, %o2 | 575 | sllx %o2, 32, %o2 |
| 490 | wr %o2, 0, %tick_cmpr | 576 | wr %o2, 0, %tick_cmpr |
| 491 | 577 | ||
| 492 | BRANCH_IF_ANY_CHEETAH(o2,o3,1f) | 578 | BRANCH_IF_SUN4V(o2, 1f) |
| 579 | BRANCH_IF_ANY_CHEETAH(o2, o3, 1f) | ||
| 493 | 580 | ||
| 494 | ba,pt %xcc, 2f | 581 | ba,pt %xcc, 2f |
| 495 | nop | 582 | nop |
| @@ -502,7 +589,6 @@ setup_trap_table: | |||
| 502 | 589 | ||
| 503 | 2: | 590 | 2: |
| 504 | wrpr %g0, %g0, %wstate | 591 | wrpr %g0, %g0, %wstate |
| 505 | wrpr %o1, 0x0, %pstate | ||
| 506 | 592 | ||
| 507 | call init_irqwork_curcpu | 593 | call init_irqwork_curcpu |
| 508 | nop | 594 | nop |
| @@ -517,7 +603,7 @@ setup_trap_table: | |||
| 517 | restore | 603 | restore |
| 518 | 604 | ||
| 519 | .globl setup_tba | 605 | .globl setup_tba |
| 520 | setup_tba: /* i0 = is_starfire */ | 606 | setup_tba: |
| 521 | save %sp, -192, %sp | 607 | save %sp, -192, %sp |
| 522 | 608 | ||
| 523 | /* The boot processor is the only cpu which invokes this | 609 | /* The boot processor is the only cpu which invokes this |
| @@ -536,31 +622,35 @@ setup_tba: /* i0 = is_starfire */ | |||
| 536 | restore | 622 | restore |
| 537 | sparc64_boot_end: | 623 | sparc64_boot_end: |
| 538 | 624 | ||
| 539 | #include "systbls.S" | ||
| 540 | #include "ktlb.S" | 625 | #include "ktlb.S" |
| 626 | #include "tsb.S" | ||
| 541 | #include "etrap.S" | 627 | #include "etrap.S" |
| 542 | #include "rtrap.S" | 628 | #include "rtrap.S" |
| 543 | #include "winfixup.S" | 629 | #include "winfixup.S" |
| 544 | #include "entry.S" | 630 | #include "entry.S" |
| 631 | #include "sun4v_tlb_miss.S" | ||
| 632 | #include "sun4v_ivec.S" | ||
| 545 | 633 | ||
| 546 | /* | 634 | /* |
| 547 | * The following skip makes sure the trap table in ttable.S is aligned | 635 | * The following skip makes sure the trap table in ttable.S is aligned |
| 548 | * on a 32K boundary as required by the v9 specs for TBA register. | 636 | * on a 32K boundary as required by the v9 specs for TBA register. |
| 637 | * | ||
| 638 | * We align to a 32K boundary, then we have the 32K kernel TSB, | ||
| 639 | * then the 32K aligned trap table. | ||
| 549 | */ | 640 | */ |
| 550 | 1: | 641 | 1: |
| 551 | .skip 0x4000 + _start - 1b | 642 | .skip 0x4000 + _start - 1b |
| 552 | 643 | ||
| 553 | #ifdef CONFIG_SBUS | 644 | .globl swapper_tsb |
| 554 | /* This is just a hack to fool make depend config.h discovering | 645 | swapper_tsb: |
| 555 | strategy: As the .S files below need config.h, but | 646 | .skip (32 * 1024) |
| 556 | make depend does not find it for them, we include config.h | ||
| 557 | in head.S */ | ||
| 558 | #endif | ||
| 559 | 647 | ||
| 560 | ! 0x0000000000408000 | 648 | ! 0x0000000000408000 |
| 561 | 649 | ||
| 562 | #include "ttable.S" | 650 | #include "ttable.S" |
| 563 | 651 | ||
| 652 | #include "systbls.S" | ||
| 653 | |||
| 564 | .data | 654 | .data |
| 565 | .align 8 | 655 | .align 8 |
| 566 | .globl prom_tba, tlb_type | 656 | .globl prom_tba, tlb_type |
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 233526ba3abe..8c93ba655b33 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/proc_fs.h> | 22 | #include <linux/proc_fs.h> |
| 23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
| 24 | #include <linux/bootmem.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/ptrace.h> | 26 | #include <asm/ptrace.h> |
| 26 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
| @@ -39,6 +40,7 @@ | |||
| 39 | #include <asm/cache.h> | 40 | #include <asm/cache.h> |
| 40 | #include <asm/cpudata.h> | 41 | #include <asm/cpudata.h> |
| 41 | #include <asm/auxio.h> | 42 | #include <asm/auxio.h> |
| 43 | #include <asm/head.h> | ||
| 42 | 44 | ||
| 43 | #ifdef CONFIG_SMP | 45 | #ifdef CONFIG_SMP |
| 44 | static void distribute_irqs(void); | 46 | static void distribute_irqs(void); |
| @@ -136,12 +138,48 @@ out_unlock: | |||
| 136 | return 0; | 138 | return 0; |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 141 | extern unsigned long real_hard_smp_processor_id(void); | ||
| 142 | |||
| 143 | static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) | ||
| 144 | { | ||
| 145 | unsigned int tid; | ||
| 146 | |||
| 147 | if (this_is_starfire) { | ||
| 148 | tid = starfire_translate(imap, cpuid); | ||
| 149 | tid <<= IMAP_TID_SHIFT; | ||
| 150 | tid &= IMAP_TID_UPA; | ||
| 151 | } else { | ||
| 152 | if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
| 153 | unsigned long ver; | ||
| 154 | |||
| 155 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | ||
| 156 | if ((ver >> 32UL) == __JALAPENO_ID || | ||
| 157 | (ver >> 32UL) == __SERRANO_ID) { | ||
| 158 | tid = cpuid << IMAP_TID_SHIFT; | ||
| 159 | tid &= IMAP_TID_JBUS; | ||
| 160 | } else { | ||
| 161 | unsigned int a = cpuid & 0x1f; | ||
| 162 | unsigned int n = (cpuid >> 5) & 0x1f; | ||
| 163 | |||
| 164 | tid = ((a << IMAP_AID_SHIFT) | | ||
| 165 | (n << IMAP_NID_SHIFT)); | ||
| 166 | tid &= (IMAP_AID_SAFARI | | ||
| 167 | IMAP_NID_SAFARI);; | ||
| 168 | } | ||
| 169 | } else { | ||
| 170 | tid = cpuid << IMAP_TID_SHIFT; | ||
| 171 | tid &= IMAP_TID_UPA; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | return tid; | ||
| 176 | } | ||
| 177 | |||
| 139 | /* Now these are always passed a true fully specified sun4u INO. */ | 178 | /* Now these are always passed a true fully specified sun4u INO. */ |
| 140 | void enable_irq(unsigned int irq) | 179 | void enable_irq(unsigned int irq) |
| 141 | { | 180 | { |
| 142 | struct ino_bucket *bucket = __bucket(irq); | 181 | struct ino_bucket *bucket = __bucket(irq); |
| 143 | unsigned long imap; | 182 | unsigned long imap, cpuid; |
| 144 | unsigned long tid; | ||
| 145 | 183 | ||
| 146 | imap = bucket->imap; | 184 | imap = bucket->imap; |
| 147 | if (imap == 0UL) | 185 | if (imap == 0UL) |
| @@ -149,47 +187,38 @@ void enable_irq(unsigned int irq) | |||
| 149 | 187 | ||
| 150 | preempt_disable(); | 188 | preempt_disable(); |
| 151 | 189 | ||
| 152 | if (tlb_type == cheetah || tlb_type == cheetah_plus) { | 190 | /* This gets the physical processor ID, even on uniprocessor, |
| 153 | unsigned long ver; | 191 | * so we can always program the interrupt target correctly. |
| 154 | 192 | */ | |
| 155 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | 193 | cpuid = real_hard_smp_processor_id(); |
| 156 | if ((ver >> 32) == 0x003e0016) { | 194 | |
| 157 | /* We set it to our JBUS ID. */ | 195 | if (tlb_type == hypervisor) { |
| 158 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | 196 | unsigned int ino = __irq_ino(irq); |
| 159 | : "=r" (tid) | 197 | int err; |
| 160 | : "i" (ASI_JBUS_CONFIG)); | 198 | |
| 161 | tid = ((tid & (0x1fUL<<17)) << 9); | 199 | err = sun4v_intr_settarget(ino, cpuid); |
| 162 | tid &= IMAP_TID_JBUS; | 200 | if (err != HV_EOK) |
| 163 | } else { | 201 | printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", |
| 164 | /* We set it to our Safari AID. */ | 202 | ino, cpuid, err); |
| 165 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | 203 | err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); |
| 166 | : "=r" (tid) | 204 | if (err != HV_EOK) |
| 167 | : "i" (ASI_SAFARI_CONFIG)); | 205 | printk("sun4v_intr_setenabled(%x): err(%d)\n", |
| 168 | tid = ((tid & (0x3ffUL<<17)) << 9); | 206 | ino, err); |
| 169 | tid &= IMAP_AID_SAFARI; | ||
| 170 | } | ||
| 171 | } else if (this_is_starfire == 0) { | ||
| 172 | /* We set it to our UPA MID. */ | ||
| 173 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | ||
| 174 | : "=r" (tid) | ||
| 175 | : "i" (ASI_UPA_CONFIG)); | ||
| 176 | tid = ((tid & UPA_CONFIG_MID) << 9); | ||
| 177 | tid &= IMAP_TID_UPA; | ||
| 178 | } else { | 207 | } else { |
| 179 | tid = (starfire_translate(imap, smp_processor_id()) << 26); | 208 | unsigned int tid = sun4u_compute_tid(imap, cpuid); |
| 180 | tid &= IMAP_TID_UPA; | 209 | |
| 210 | /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product | ||
| 211 | * of this SYSIO's preconfigured IGN in the SYSIO Control | ||
| 212 | * Register, the hardware just mirrors that value here. | ||
| 213 | * However for Graphics and UPA Slave devices the full | ||
| 214 | * IMAP_INR field can be set by the programmer here. | ||
| 215 | * | ||
| 216 | * Things like FFB can now be handled via the new IRQ | ||
| 217 | * mechanism. | ||
| 218 | */ | ||
| 219 | upa_writel(tid | IMAP_VALID, imap); | ||
| 181 | } | 220 | } |
| 182 | 221 | ||
| 183 | /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product | ||
| 184 | * of this SYSIO's preconfigured IGN in the SYSIO Control | ||
| 185 | * Register, the hardware just mirrors that value here. | ||
| 186 | * However for Graphics and UPA Slave devices the full | ||
| 187 | * IMAP_INR field can be set by the programmer here. | ||
| 188 | * | ||
| 189 | * Things like FFB can now be handled via the new IRQ mechanism. | ||
| 190 | */ | ||
| 191 | upa_writel(tid | IMAP_VALID, imap); | ||
| 192 | |||
| 193 | preempt_enable(); | 222 | preempt_enable(); |
| 194 | } | 223 | } |
| 195 | 224 | ||
| @@ -201,16 +230,26 @@ void disable_irq(unsigned int irq) | |||
| 201 | 230 | ||
| 202 | imap = bucket->imap; | 231 | imap = bucket->imap; |
| 203 | if (imap != 0UL) { | 232 | if (imap != 0UL) { |
| 204 | u32 tmp; | 233 | if (tlb_type == hypervisor) { |
| 234 | unsigned int ino = __irq_ino(irq); | ||
| 235 | int err; | ||
| 236 | |||
| 237 | err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); | ||
| 238 | if (err != HV_EOK) | ||
| 239 | printk("sun4v_intr_setenabled(%x): " | ||
| 240 | "err(%d)\n", ino, err); | ||
| 241 | } else { | ||
| 242 | u32 tmp; | ||
| 205 | 243 | ||
| 206 | /* NOTE: We do not want to futz with the IRQ clear registers | 244 | /* NOTE: We do not want to futz with the IRQ clear registers |
| 207 | * and move the state to IDLE, the SCSI code does call | 245 | * and move the state to IDLE, the SCSI code does call |
| 208 | * disable_irq() to assure atomicity in the queue cmd | 246 | * disable_irq() to assure atomicity in the queue cmd |
| 209 | * SCSI adapter driver code. Thus we'd lose interrupts. | 247 | * SCSI adapter driver code. Thus we'd lose interrupts. |
| 210 | */ | 248 | */ |
| 211 | tmp = upa_readl(imap); | 249 | tmp = upa_readl(imap); |
| 212 | tmp &= ~IMAP_VALID; | 250 | tmp &= ~IMAP_VALID; |
| 213 | upa_writel(tmp, imap); | 251 | upa_writel(tmp, imap); |
| 252 | } | ||
| 214 | } | 253 | } |
| 215 | } | 254 | } |
| 216 | 255 | ||
| @@ -248,6 +287,8 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long | |||
| 248 | return __irq(&pil0_dummy_bucket); | 287 | return __irq(&pil0_dummy_bucket); |
| 249 | } | 288 | } |
| 250 | 289 | ||
| 290 | BUG_ON(tlb_type == hypervisor); | ||
| 291 | |||
| 251 | /* RULE: Both must be specified in all other cases. */ | 292 | /* RULE: Both must be specified in all other cases. */ |
| 252 | if (iclr == 0UL || imap == 0UL) { | 293 | if (iclr == 0UL || imap == 0UL) { |
| 253 | prom_printf("Invalid build_irq %d %d %016lx %016lx\n", | 294 | prom_printf("Invalid build_irq %d %d %016lx %016lx\n", |
| @@ -275,12 +316,11 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long | |||
| 275 | goto out; | 316 | goto out; |
| 276 | } | 317 | } |
| 277 | 318 | ||
| 278 | bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC); | 319 | bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); |
| 279 | if (!bucket->irq_info) { | 320 | if (!bucket->irq_info) { |
| 280 | prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); | 321 | prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); |
| 281 | prom_halt(); | 322 | prom_halt(); |
| 282 | } | 323 | } |
| 283 | memset(bucket->irq_info, 0, sizeof(struct irq_desc)); | ||
| 284 | 324 | ||
| 285 | /* Ok, looks good, set it up. Don't touch the irq_chain or | 325 | /* Ok, looks good, set it up. Don't touch the irq_chain or |
| 286 | * the pending flag. | 326 | * the pending flag. |
| @@ -294,6 +334,37 @@ out: | |||
| 294 | return __irq(bucket); | 334 | return __irq(bucket); |
| 295 | } | 335 | } |
| 296 | 336 | ||
| 337 | unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags) | ||
| 338 | { | ||
| 339 | struct ino_bucket *bucket; | ||
| 340 | unsigned long sysino; | ||
| 341 | |||
| 342 | sysino = sun4v_devino_to_sysino(devhandle, devino); | ||
| 343 | |||
| 344 | bucket = &ivector_table[sysino]; | ||
| 345 | |||
| 346 | /* Catch accidental accesses to these things. IMAP/ICLR handling | ||
| 347 | * is done by hypervisor calls on sun4v platforms, not by direct | ||
| 348 | * register accesses. | ||
| 349 | * | ||
| 350 | * But we need to make them look unique for the disable_irq() logic | ||
| 351 | * in free_irq(). | ||
| 352 | */ | ||
| 353 | bucket->imap = ~0UL - sysino; | ||
| 354 | bucket->iclr = ~0UL - sysino; | ||
| 355 | |||
| 356 | bucket->pil = pil; | ||
| 357 | bucket->flags = flags; | ||
| 358 | |||
| 359 | bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); | ||
| 360 | if (!bucket->irq_info) { | ||
| 361 | prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); | ||
| 362 | prom_halt(); | ||
| 363 | } | ||
| 364 | |||
| 365 | return __irq(bucket); | ||
| 366 | } | ||
| 367 | |||
| 297 | static void atomic_bucket_insert(struct ino_bucket *bucket) | 368 | static void atomic_bucket_insert(struct ino_bucket *bucket) |
| 298 | { | 369 | { |
| 299 | unsigned long pstate; | 370 | unsigned long pstate; |
| @@ -482,7 +553,6 @@ void free_irq(unsigned int irq, void *dev_id) | |||
| 482 | bucket = __bucket(irq); | 553 | bucket = __bucket(irq); |
| 483 | if (bucket != &pil0_dummy_bucket) { | 554 | if (bucket != &pil0_dummy_bucket) { |
| 484 | struct irq_desc *desc = bucket->irq_info; | 555 | struct irq_desc *desc = bucket->irq_info; |
| 485 | unsigned long imap = bucket->imap; | ||
| 486 | int ent, i; | 556 | int ent, i; |
| 487 | 557 | ||
| 488 | for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { | 558 | for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { |
| @@ -495,6 +565,8 @@ void free_irq(unsigned int irq, void *dev_id) | |||
| 495 | } | 565 | } |
| 496 | 566 | ||
| 497 | if (!desc->action_active_mask) { | 567 | if (!desc->action_active_mask) { |
| 568 | unsigned long imap = bucket->imap; | ||
| 569 | |||
| 498 | /* This unique interrupt source is now inactive. */ | 570 | /* This unique interrupt source is now inactive. */ |
| 499 | bucket->flags &= ~IBF_ACTIVE; | 571 | bucket->flags &= ~IBF_ACTIVE; |
| 500 | 572 | ||
| @@ -592,7 +664,18 @@ static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) | |||
| 592 | break; | 664 | break; |
| 593 | } | 665 | } |
| 594 | if (bp->pil != 0) { | 666 | if (bp->pil != 0) { |
| 595 | upa_writel(ICLR_IDLE, bp->iclr); | 667 | if (tlb_type == hypervisor) { |
| 668 | unsigned int ino = __irq_ino(bp); | ||
| 669 | int err; | ||
| 670 | |||
| 671 | err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); | ||
| 672 | if (err != HV_EOK) | ||
| 673 | printk("sun4v_intr_setstate(%x): " | ||
| 674 | "err(%d)\n", ino, err); | ||
| 675 | } else { | ||
| 676 | upa_writel(ICLR_IDLE, bp->iclr); | ||
| 677 | } | ||
| 678 | |||
| 596 | /* Test and add entropy */ | 679 | /* Test and add entropy */ |
| 597 | if (random & SA_SAMPLE_RANDOM) | 680 | if (random & SA_SAMPLE_RANDOM) |
| 598 | add_interrupt_randomness(irq); | 681 | add_interrupt_randomness(irq); |
| @@ -694,7 +777,7 @@ irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) | |||
| 694 | val = readb(auxio_register); | 777 | val = readb(auxio_register); |
| 695 | val |= AUXIO_AUX1_FTCNT; | 778 | val |= AUXIO_AUX1_FTCNT; |
| 696 | writeb(val, auxio_register); | 779 | writeb(val, auxio_register); |
| 697 | val &= AUXIO_AUX1_FTCNT; | 780 | val &= ~AUXIO_AUX1_FTCNT; |
| 698 | writeb(val, auxio_register); | 781 | writeb(val, auxio_register); |
| 699 | 782 | ||
| 700 | doing_pdma = 0; | 783 | doing_pdma = 0; |
| @@ -727,25 +810,23 @@ EXPORT_SYMBOL(probe_irq_off); | |||
| 727 | static int retarget_one_irq(struct irqaction *p, int goal_cpu) | 810 | static int retarget_one_irq(struct irqaction *p, int goal_cpu) |
| 728 | { | 811 | { |
| 729 | struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table; | 812 | struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table; |
| 730 | unsigned long imap = bucket->imap; | ||
| 731 | unsigned int tid; | ||
| 732 | 813 | ||
| 733 | while (!cpu_online(goal_cpu)) { | 814 | while (!cpu_online(goal_cpu)) { |
| 734 | if (++goal_cpu >= NR_CPUS) | 815 | if (++goal_cpu >= NR_CPUS) |
| 735 | goal_cpu = 0; | 816 | goal_cpu = 0; |
| 736 | } | 817 | } |
| 737 | 818 | ||
| 738 | if (tlb_type == cheetah || tlb_type == cheetah_plus) { | 819 | if (tlb_type == hypervisor) { |
| 739 | tid = goal_cpu << 26; | 820 | unsigned int ino = __irq_ino(bucket); |
| 740 | tid &= IMAP_AID_SAFARI; | 821 | |
| 741 | } else if (this_is_starfire == 0) { | 822 | sun4v_intr_settarget(ino, goal_cpu); |
| 742 | tid = goal_cpu << 26; | 823 | sun4v_intr_setenabled(ino, HV_INTR_ENABLED); |
| 743 | tid &= IMAP_TID_UPA; | ||
| 744 | } else { | 824 | } else { |
| 745 | tid = (starfire_translate(imap, goal_cpu) << 26); | 825 | unsigned long imap = bucket->imap; |
| 746 | tid &= IMAP_TID_UPA; | 826 | unsigned int tid = sun4u_compute_tid(imap, goal_cpu); |
| 827 | |||
| 828 | upa_writel(tid | IMAP_VALID, imap); | ||
| 747 | } | 829 | } |
| 748 | upa_writel(tid | IMAP_VALID, imap); | ||
| 749 | 830 | ||
| 750 | do { | 831 | do { |
| 751 | if (++goal_cpu >= NR_CPUS) | 832 | if (++goal_cpu >= NR_CPUS) |
| @@ -848,33 +929,114 @@ static void kill_prom_timer(void) | |||
| 848 | 929 | ||
| 849 | void init_irqwork_curcpu(void) | 930 | void init_irqwork_curcpu(void) |
| 850 | { | 931 | { |
| 851 | register struct irq_work_struct *workp asm("o2"); | ||
| 852 | register unsigned long tmp asm("o3"); | ||
| 853 | int cpu = hard_smp_processor_id(); | 932 | int cpu = hard_smp_processor_id(); |
| 854 | 933 | ||
| 855 | memset(__irq_work + cpu, 0, sizeof(*workp)); | 934 | memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct)); |
| 856 | 935 | } | |
| 857 | /* Make sure we are called with PSTATE_IE disabled. */ | 936 | |
| 858 | __asm__ __volatile__("rdpr %%pstate, %0\n\t" | 937 | static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type) |
| 859 | : "=r" (tmp)); | 938 | { |
| 860 | if (tmp & PSTATE_IE) { | 939 | unsigned long num_entries = 128; |
| 861 | prom_printf("BUG: init_irqwork_curcpu() called with " | 940 | unsigned long status; |
| 862 | "PSTATE_IE enabled, bailing.\n"); | 941 | |
| 863 | __asm__ __volatile__("mov %%i7, %0\n\t" | 942 | status = sun4v_cpu_qconf(type, paddr, num_entries); |
| 864 | : "=r" (tmp)); | 943 | if (status != HV_EOK) { |
| 865 | prom_printf("BUG: Called from %lx\n", tmp); | 944 | prom_printf("SUN4V: sun4v_cpu_qconf(%lu:%lx:%lu) failed, " |
| 945 | "err %lu\n", type, paddr, num_entries, status); | ||
| 866 | prom_halt(); | 946 | prom_halt(); |
| 867 | } | 947 | } |
| 948 | } | ||
| 868 | 949 | ||
| 869 | /* Set interrupt globals. */ | 950 | static void __cpuinit sun4v_register_mondo_queues(int this_cpu) |
| 870 | workp = &__irq_work[cpu]; | 951 | { |
| 871 | __asm__ __volatile__( | 952 | struct trap_per_cpu *tb = &trap_block[this_cpu]; |
| 872 | "rdpr %%pstate, %0\n\t" | 953 | |
| 873 | "wrpr %0, %1, %%pstate\n\t" | 954 | register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO); |
| 874 | "mov %2, %%g6\n\t" | 955 | register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO); |
| 875 | "wrpr %0, 0x0, %%pstate\n\t" | 956 | register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR); |
| 876 | : "=&r" (tmp) | 957 | register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR); |
| 877 | : "i" (PSTATE_IG), "r" (workp)); | 958 | } |
| 959 | |||
| 960 | static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, int use_bootmem) | ||
| 961 | { | ||
| 962 | void *page; | ||
| 963 | |||
| 964 | if (use_bootmem) | ||
| 965 | page = alloc_bootmem_low_pages(PAGE_SIZE); | ||
| 966 | else | ||
| 967 | page = (void *) get_zeroed_page(GFP_ATOMIC); | ||
| 968 | |||
| 969 | if (!page) { | ||
| 970 | prom_printf("SUN4V: Error, cannot allocate mondo queue.\n"); | ||
| 971 | prom_halt(); | ||
| 972 | } | ||
| 973 | |||
| 974 | *pa_ptr = __pa(page); | ||
| 975 | } | ||
| 976 | |||
| 977 | static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, int use_bootmem) | ||
| 978 | { | ||
| 979 | void *page; | ||
| 980 | |||
| 981 | if (use_bootmem) | ||
| 982 | page = alloc_bootmem_low_pages(PAGE_SIZE); | ||
| 983 | else | ||
| 984 | page = (void *) get_zeroed_page(GFP_ATOMIC); | ||
| 985 | |||
| 986 | if (!page) { | ||
| 987 | prom_printf("SUN4V: Error, cannot allocate kbuf page.\n"); | ||
| 988 | prom_halt(); | ||
| 989 | } | ||
| 990 | |||
| 991 | *pa_ptr = __pa(page); | ||
| 992 | } | ||
| 993 | |||
| 994 | static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem) | ||
| 995 | { | ||
| 996 | #ifdef CONFIG_SMP | ||
| 997 | void *page; | ||
| 998 | |||
| 999 | BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); | ||
| 1000 | |||
| 1001 | if (use_bootmem) | ||
| 1002 | page = alloc_bootmem_low_pages(PAGE_SIZE); | ||
| 1003 | else | ||
| 1004 | page = (void *) get_zeroed_page(GFP_ATOMIC); | ||
| 1005 | |||
| 1006 | if (!page) { | ||
| 1007 | prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); | ||
| 1008 | prom_halt(); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | tb->cpu_mondo_block_pa = __pa(page); | ||
| 1012 | tb->cpu_list_pa = __pa(page + 64); | ||
| 1013 | #endif | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | /* Allocate and register the mondo and error queues for this cpu. */ | ||
| 1017 | void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load) | ||
| 1018 | { | ||
| 1019 | struct trap_per_cpu *tb = &trap_block[cpu]; | ||
| 1020 | |||
| 1021 | if (alloc) { | ||
| 1022 | alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem); | ||
| 1023 | alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem); | ||
| 1024 | alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem); | ||
| 1025 | alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem); | ||
| 1026 | alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem); | ||
| 1027 | alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem); | ||
| 1028 | |||
| 1029 | init_cpu_send_mondo_info(tb, use_bootmem); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | if (load) { | ||
| 1033 | if (cpu != hard_smp_processor_id()) { | ||
| 1034 | prom_printf("SUN4V: init mondo on cpu %d not %d\n", | ||
| 1035 | cpu, hard_smp_processor_id()); | ||
| 1036 | prom_halt(); | ||
| 1037 | } | ||
| 1038 | sun4v_register_mondo_queues(cpu); | ||
| 1039 | } | ||
| 878 | } | 1040 | } |
| 879 | 1041 | ||
| 880 | /* Only invoked on boot processor. */ | 1042 | /* Only invoked on boot processor. */ |
| @@ -884,6 +1046,9 @@ void __init init_IRQ(void) | |||
| 884 | kill_prom_timer(); | 1046 | kill_prom_timer(); |
| 885 | memset(&ivector_table[0], 0, sizeof(ivector_table)); | 1047 | memset(&ivector_table[0], 0, sizeof(ivector_table)); |
| 886 | 1048 | ||
| 1049 | if (tlb_type == hypervisor) | ||
| 1050 | sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1); | ||
| 1051 | |||
| 887 | /* We need to clear any IRQ's pending in the soft interrupt | 1052 | /* We need to clear any IRQ's pending in the soft interrupt |
| 888 | * registers, a spurious one could be left around from the | 1053 | * registers, a spurious one could be left around from the |
| 889 | * PROM timer which we just disabled. | 1054 | * PROM timer which we just disabled. |
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S deleted file mode 100644 index 4951ff8f6877..000000000000 --- a/arch/sparc64/kernel/itlb_base.S +++ /dev/null | |||
| @@ -1,79 +0,0 @@ | |||
| 1 | /* $Id: itlb_base.S,v 1.12 2002/02/09 19:49:30 davem Exp $ | ||
| 2 | * itlb_base.S: Front end to ITLB miss replacement strategy. | ||
| 3 | * This is included directly into the trap table. | ||
| 4 | * | ||
| 5 | * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) | ||
| 6 | * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) | ||
| 7 | */ | ||
| 8 | |||
| 9 | #if PAGE_SHIFT == 13 | ||
| 10 | /* | ||
| 11 | * To compute vpte offset, we need to do ((addr >> 13) << 3), | ||
| 12 | * which can be optimized to (addr >> 10) if bits 10/11/12 can | ||
| 13 | * be guaranteed to be 0 ... mmu_context.h does guarantee this | ||
| 14 | * by only using 10 bits in the hwcontext value. | ||
| 15 | */ | ||
| 16 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | ||
| 17 | srax r1, 10, r2 | ||
| 18 | #define CREATE_VPTE_OFFSET2(r1, r2) nop | ||
| 19 | #else /* PAGE_SHIFT */ | ||
| 20 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | ||
| 21 | srax r1, PAGE_SHIFT, r2 | ||
| 22 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | ||
| 23 | sllx r2, 3, r2 | ||
| 24 | #endif /* PAGE_SHIFT */ | ||
| 25 | |||
| 26 | |||
| 27 | /* Ways we can get here: | ||
| 28 | * | ||
| 29 | * 1) Nucleus instruction misses from module code. | ||
| 30 | * 2) All user instruction misses. | ||
| 31 | * | ||
| 32 | * All real page faults merge their code paths to the | ||
| 33 | * sparc64_realfault_common label below. | ||
| 34 | */ | ||
| 35 | |||
| 36 | /* ITLB ** ICACHE line 1: Quick user TLB misses */ | ||
| 37 | mov TLB_SFSR, %g1 | ||
| 38 | ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS | ||
| 39 | CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset | ||
| 40 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset | ||
| 41 | ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE | ||
| 42 | 1: brgez,pn %g5, 3f ! Not valid, branch out | ||
| 43 | sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot | ||
| 44 | andcc %g5, %g4, %g0 ! Executable? | ||
| 45 | |||
| 46 | /* ITLB ** ICACHE line 2: Real faults */ | ||
| 47 | be,pn %xcc, 3f ! Nope, branch. | ||
| 48 | nop ! Delay-slot | ||
| 49 | 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB | ||
| 50 | retry ! Trap return | ||
| 51 | 3: rdpr %pstate, %g4 ! Move into alt-globals | ||
| 52 | wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate | ||
| 53 | rdpr %tpc, %g5 ! And load faulting VA | ||
| 54 | mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB | ||
| 55 | |||
| 56 | /* ITLB ** ICACHE line 3: Finish faults */ | ||
| 57 | sparc64_realfault_common: ! Called by dtlb_miss | ||
| 58 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
| 59 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
| 60 | ba,pt %xcc, etrap ! Save state | ||
| 61 | 1: rd %pc, %g7 ! ... | ||
| 62 | call do_sparc64_fault ! Call fault handler | ||
| 63 | add %sp, PTREGS_OFF, %o0! Compute pt_regs arg | ||
| 64 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state | ||
| 65 | nop | ||
| 66 | |||
| 67 | /* ITLB ** ICACHE line 4: Window fixups */ | ||
| 68 | winfix_trampoline: | ||
| 69 | rdpr %tpc, %g3 ! Prepare winfixup TNPC | ||
| 70 | or %g3, 0x7c, %g3 ! Compute branch offset | ||
| 71 | wrpr %g3, %tnpc ! Write it into TNPC | ||
| 72 | done ! Do it to it | ||
| 73 | nop | ||
| 74 | nop | ||
| 75 | nop | ||
| 76 | nop | ||
| 77 | |||
| 78 | #undef CREATE_VPTE_OFFSET1 | ||
| 79 | #undef CREATE_VPTE_OFFSET2 | ||
diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S new file mode 100644 index 000000000000..ad46e2024f4b --- /dev/null +++ b/arch/sparc64/kernel/itlb_miss.S | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* ITLB ** ICACHE line 1: Context 0 check and TSB load */ | ||
| 2 | ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! Get TSB 8K pointer | ||
| 3 | ldxa [%g0] ASI_IMMU, %g6 ! Get TAG TARGET | ||
| 4 | srlx %g6, 48, %g5 ! Get context | ||
| 5 | sllx %g6, 22, %g6 ! Zero out context | ||
| 6 | brz,pn %g5, kvmap_itlb ! Context 0 processing | ||
| 7 | srlx %g6, 22, %g6 ! Delay slot | ||
| 8 | TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry | ||
| 9 | cmp %g4, %g6 ! Compare TAG | ||
| 10 | |||
| 11 | /* ITLB ** ICACHE line 2: TSB compare and TLB load */ | ||
| 12 | bne,pn %xcc, tsb_miss_itlb ! Miss | ||
| 13 | mov FAULT_CODE_ITLB, %g3 | ||
| 14 | andcc %g5, _PAGE_EXEC_4U, %g0 ! Executable? | ||
| 15 | be,pn %xcc, tsb_do_fault | ||
| 16 | nop ! Delay slot, fill me | ||
| 17 | stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB | ||
| 18 | retry ! Trap done | ||
| 19 | nop | ||
| 20 | |||
| 21 | /* ITLB ** ICACHE line 3: */ | ||
| 22 | nop | ||
| 23 | nop | ||
| 24 | nop | ||
| 25 | nop | ||
| 26 | nop | ||
| 27 | nop | ||
| 28 | nop | ||
| 29 | nop | ||
| 30 | |||
| 31 | /* ITLB ** ICACHE line 4: */ | ||
| 32 | nop | ||
| 33 | nop | ||
| 34 | nop | ||
| 35 | nop | ||
| 36 | nop | ||
| 37 | nop | ||
| 38 | nop | ||
| 39 | nop | ||
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S index d9244d3c9f73..31da1e564c95 100644 --- a/arch/sparc64/kernel/ktlb.S +++ b/arch/sparc64/kernel/ktlb.S | |||
| @@ -4,191 +4,276 @@ | |||
| 4 | * Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de) | 4 | * Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de) |
| 5 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) | 5 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) |
| 6 | * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 6 | * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
| 10 | #include <asm/head.h> | 10 | #include <asm/head.h> |
| 11 | #include <asm/asi.h> | 11 | #include <asm/asi.h> |
| 12 | #include <asm/page.h> | 12 | #include <asm/page.h> |
| 13 | #include <asm/pgtable.h> | 13 | #include <asm/pgtable.h> |
| 14 | #include <asm/tsb.h> | ||
| 14 | 15 | ||
| 15 | .text | 16 | .text |
| 16 | .align 32 | 17 | .align 32 |
| 17 | 18 | ||
| 18 | /* | 19 | kvmap_itlb: |
| 19 | * On a second level vpte miss, check whether the original fault is to the OBP | 20 | /* g6: TAG TARGET */ |
| 20 | * range (note that this is only possible for instruction miss, data misses to | 21 | mov TLB_TAG_ACCESS, %g4 |
| 21 | * obp range do not use vpte). If so, go back directly to the faulting address. | 22 | ldxa [%g4] ASI_IMMU, %g4 |
| 22 | * This is because we want to read the tpc, otherwise we have no way of knowing | 23 | |
| 23 | * the 8k aligned faulting address if we are using >8k kernel pagesize. This | 24 | /* sun4v_itlb_miss branches here with the missing virtual |
| 24 | * also ensures no vpte range addresses are dropped into tlb while obp is | 25 | * address already loaded into %g4 |
| 25 | * executing (see inherit_locked_prom_mappings() rant). | ||
| 26 | */ | ||
| 27 | sparc64_vpte_nucleus: | ||
| 28 | /* Note that kvmap below has verified that the address is | ||
| 29 | * in the range MODULES_VADDR --> VMALLOC_END already. So | ||
| 30 | * here we need only check if it is an OBP address or not. | ||
| 31 | */ | 26 | */ |
| 27 | kvmap_itlb_4v: | ||
| 28 | |||
| 29 | kvmap_itlb_nonlinear: | ||
| 30 | /* Catch kernel NULL pointer calls. */ | ||
| 31 | sethi %hi(PAGE_SIZE), %g5 | ||
| 32 | cmp %g4, %g5 | ||
| 33 | bleu,pn %xcc, kvmap_dtlb_longpath | ||
| 34 | nop | ||
| 35 | |||
| 36 | KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_itlb_load) | ||
| 37 | |||
| 38 | kvmap_itlb_tsb_miss: | ||
| 32 | sethi %hi(LOW_OBP_ADDRESS), %g5 | 39 | sethi %hi(LOW_OBP_ADDRESS), %g5 |
| 33 | cmp %g4, %g5 | 40 | cmp %g4, %g5 |
| 34 | blu,pn %xcc, kern_vpte | 41 | blu,pn %xcc, kvmap_itlb_vmalloc_addr |
| 35 | mov 0x1, %g5 | 42 | mov 0x1, %g5 |
| 36 | sllx %g5, 32, %g5 | 43 | sllx %g5, 32, %g5 |
| 37 | cmp %g4, %g5 | 44 | cmp %g4, %g5 |
| 38 | blu,pn %xcc, vpte_insn_obp | 45 | blu,pn %xcc, kvmap_itlb_obp |
| 39 | nop | 46 | nop |
| 40 | 47 | ||
| 41 | /* These two instructions are patched by paginig_init(). */ | 48 | kvmap_itlb_vmalloc_addr: |
| 42 | kern_vpte: | 49 | KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath) |
| 43 | sethi %hi(swapper_pgd_zero), %g5 | ||
| 44 | lduw [%g5 + %lo(swapper_pgd_zero)], %g5 | ||
| 45 | 50 | ||
| 46 | /* With kernel PGD in %g5, branch back into dtlb_backend. */ | 51 | KTSB_LOCK_TAG(%g1, %g2, %g7) |
| 47 | ba,pt %xcc, sparc64_kpte_continue | ||
| 48 | andn %g1, 0x3, %g1 /* Finish PMD offset adjustment. */ | ||
| 49 | 52 | ||
| 50 | vpte_noent: | 53 | /* Load and check PTE. */ |
| 51 | /* Restore previous TAG_ACCESS, %g5 is zero, and we will | 54 | ldxa [%g5] ASI_PHYS_USE_EC, %g5 |
| 52 | * skip over the trap instruction so that the top level | 55 | mov 1, %g7 |
| 53 | * TLB miss handler will thing this %g5 value is just an | 56 | sllx %g7, TSB_TAG_INVALID_BIT, %g7 |
| 54 | * invalid PTE, thus branching to full fault processing. | 57 | brgez,a,pn %g5, kvmap_itlb_longpath |
| 55 | */ | 58 | KTSB_STORE(%g1, %g7) |
| 56 | mov TLB_SFSR, %g1 | 59 | |
| 57 | stxa %g4, [%g1 + %g1] ASI_DMMU | 60 | KTSB_WRITE(%g1, %g5, %g6) |
| 58 | done | 61 | |
| 59 | 62 | /* fallthrough to TLB load */ | |
| 60 | vpte_insn_obp: | ||
| 61 | /* Behave as if we are at TL0. */ | ||
| 62 | wrpr %g0, 1, %tl | ||
| 63 | rdpr %tpc, %g4 /* Find original faulting iaddr */ | ||
| 64 | srlx %g4, 13, %g4 /* Throw out context bits */ | ||
| 65 | sllx %g4, 13, %g4 /* g4 has vpn + ctx0 now */ | ||
| 66 | |||
| 67 | /* Restore previous TAG_ACCESS. */ | ||
| 68 | mov TLB_SFSR, %g1 | ||
| 69 | stxa %g4, [%g1 + %g1] ASI_IMMU | ||
| 70 | |||
| 71 | sethi %hi(prom_trans), %g5 | ||
| 72 | or %g5, %lo(prom_trans), %g5 | ||
| 73 | |||
| 74 | 1: ldx [%g5 + 0x00], %g6 ! base | ||
| 75 | brz,a,pn %g6, longpath ! no more entries, fail | ||
| 76 | mov TLB_SFSR, %g1 ! and restore %g1 | ||
| 77 | ldx [%g5 + 0x08], %g1 ! len | ||
| 78 | add %g6, %g1, %g1 ! end | ||
| 79 | cmp %g6, %g4 | ||
| 80 | bgu,pt %xcc, 2f | ||
| 81 | cmp %g4, %g1 | ||
| 82 | bgeu,pt %xcc, 2f | ||
| 83 | ldx [%g5 + 0x10], %g1 ! PTE | ||
| 84 | |||
| 85 | /* TLB load, restore %g1, and return from trap. */ | ||
| 86 | sub %g4, %g6, %g6 | ||
| 87 | add %g1, %g6, %g5 | ||
| 88 | mov TLB_SFSR, %g1 | ||
| 89 | stxa %g5, [%g0] ASI_ITLB_DATA_IN | ||
| 90 | retry | ||
| 91 | 63 | ||
| 92 | 2: ba,pt %xcc, 1b | 64 | kvmap_itlb_load: |
| 93 | add %g5, (3 * 8), %g5 ! next entry | 65 | |
| 94 | 66 | 661: stxa %g5, [%g0] ASI_ITLB_DATA_IN | |
| 95 | kvmap_do_obp: | ||
| 96 | sethi %hi(prom_trans), %g5 | ||
| 97 | or %g5, %lo(prom_trans), %g5 | ||
| 98 | srlx %g4, 13, %g4 | ||
| 99 | sllx %g4, 13, %g4 | ||
| 100 | |||
| 101 | 1: ldx [%g5 + 0x00], %g6 ! base | ||
| 102 | brz,a,pn %g6, longpath ! no more entries, fail | ||
| 103 | mov TLB_SFSR, %g1 ! and restore %g1 | ||
| 104 | ldx [%g5 + 0x08], %g1 ! len | ||
| 105 | add %g6, %g1, %g1 ! end | ||
| 106 | cmp %g6, %g4 | ||
| 107 | bgu,pt %xcc, 2f | ||
| 108 | cmp %g4, %g1 | ||
| 109 | bgeu,pt %xcc, 2f | ||
| 110 | ldx [%g5 + 0x10], %g1 ! PTE | ||
| 111 | |||
| 112 | /* TLB load, restore %g1, and return from trap. */ | ||
| 113 | sub %g4, %g6, %g6 | ||
| 114 | add %g1, %g6, %g5 | ||
| 115 | mov TLB_SFSR, %g1 | ||
| 116 | stxa %g5, [%g0] ASI_DTLB_DATA_IN | ||
| 117 | retry | 67 | retry |
| 68 | .section .sun4v_2insn_patch, "ax" | ||
| 69 | .word 661b | ||
| 70 | nop | ||
| 71 | nop | ||
| 72 | .previous | ||
| 73 | |||
| 74 | /* For sun4v the ASI_ITLB_DATA_IN store and the retry | ||
| 75 | * instruction get nop'd out and we get here to branch | ||
| 76 | * to the sun4v tlb load code. The registers are setup | ||
| 77 | * as follows: | ||
| 78 | * | ||
| 79 | * %g4: vaddr | ||
| 80 | * %g5: PTE | ||
| 81 | * %g6: TAG | ||
| 82 | * | ||
| 83 | * The sun4v TLB load wants the PTE in %g3 so we fix that | ||
| 84 | * up here. | ||
| 85 | */ | ||
| 86 | ba,pt %xcc, sun4v_itlb_load | ||
| 87 | mov %g5, %g3 | ||
| 118 | 88 | ||
| 119 | 2: ba,pt %xcc, 1b | 89 | kvmap_itlb_longpath: |
| 120 | add %g5, (3 * 8), %g5 ! next entry | 90 | |
| 91 | 661: rdpr %pstate, %g5 | ||
| 92 | wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate | ||
| 93 | .section .sun4v_2insn_patch, "ax" | ||
| 94 | .word 661b | ||
| 95 | SET_GL(1) | ||
| 96 | nop | ||
| 97 | .previous | ||
| 98 | |||
| 99 | rdpr %tpc, %g5 | ||
| 100 | ba,pt %xcc, sparc64_realfault_common | ||
| 101 | mov FAULT_CODE_ITLB, %g4 | ||
| 102 | |||
| 103 | kvmap_itlb_obp: | ||
| 104 | OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath) | ||
| 105 | |||
| 106 | KTSB_LOCK_TAG(%g1, %g2, %g7) | ||
| 107 | |||
| 108 | KTSB_WRITE(%g1, %g5, %g6) | ||
| 109 | |||
| 110 | ba,pt %xcc, kvmap_itlb_load | ||
| 111 | nop | ||
| 112 | |||
| 113 | kvmap_dtlb_obp: | ||
| 114 | OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath) | ||
| 115 | |||
| 116 | KTSB_LOCK_TAG(%g1, %g2, %g7) | ||
| 117 | |||
| 118 | KTSB_WRITE(%g1, %g5, %g6) | ||
| 119 | |||
| 120 | ba,pt %xcc, kvmap_dtlb_load | ||
| 121 | nop | ||
| 121 | 122 | ||
| 122 | /* | ||
| 123 | * On a first level data miss, check whether this is to the OBP range (note | ||
| 124 | * that such accesses can be made by prom, as well as by kernel using | ||
| 125 | * prom_getproperty on "address"), and if so, do not use vpte access ... | ||
| 126 | * rather, use information saved during inherit_prom_mappings() using 8k | ||
| 127 | * pagesize. | ||
| 128 | */ | ||
| 129 | .align 32 | 123 | .align 32 |
| 130 | kvmap: | 124 | kvmap_dtlb_tsb4m_load: |
| 131 | brgez,pn %g4, kvmap_nonlinear | 125 | KTSB_LOCK_TAG(%g1, %g2, %g7) |
| 126 | KTSB_WRITE(%g1, %g5, %g6) | ||
| 127 | ba,pt %xcc, kvmap_dtlb_load | ||
| 132 | nop | 128 | nop |
| 133 | 129 | ||
| 134 | #ifdef CONFIG_DEBUG_PAGEALLOC | 130 | kvmap_dtlb: |
| 131 | /* %g6: TAG TARGET */ | ||
| 132 | mov TLB_TAG_ACCESS, %g4 | ||
| 133 | ldxa [%g4] ASI_DMMU, %g4 | ||
| 134 | |||
| 135 | /* sun4v_dtlb_miss branches here with the missing virtual | ||
| 136 | * address already loaded into %g4 | ||
| 137 | */ | ||
| 138 | kvmap_dtlb_4v: | ||
| 139 | brgez,pn %g4, kvmap_dtlb_nonlinear | ||
| 140 | nop | ||
| 141 | |||
| 142 | /* Correct TAG_TARGET is already in %g6, check 4mb TSB. */ | ||
| 143 | KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) | ||
| 144 | |||
| 145 | /* TSB entry address left in %g1, lookup linear PTE. | ||
| 146 | * Must preserve %g1 and %g6 (TAG). | ||
| 147 | */ | ||
| 148 | kvmap_dtlb_tsb4m_miss: | ||
| 149 | sethi %hi(kpte_linear_bitmap), %g2 | ||
| 150 | or %g2, %lo(kpte_linear_bitmap), %g2 | ||
| 151 | |||
| 152 | /* Clear the PAGE_OFFSET top virtual bits, then shift | ||
| 153 | * down to get a 256MB physical address index. | ||
| 154 | */ | ||
| 155 | sllx %g4, 21, %g5 | ||
| 156 | mov 1, %g7 | ||
| 157 | srlx %g5, 21 + 28, %g5 | ||
| 158 | |||
| 159 | /* Don't try this at home kids... this depends upon srlx | ||
| 160 | * only taking the low 6 bits of the shift count in %g5. | ||
| 161 | */ | ||
| 162 | sllx %g7, %g5, %g7 | ||
| 163 | |||
| 164 | /* Divide by 64 to get the offset into the bitmask. */ | ||
| 165 | srlx %g5, 6, %g5 | ||
| 166 | sllx %g5, 3, %g5 | ||
| 167 | |||
| 168 | /* kern_linear_pte_xor[((mask & bit) ? 1 : 0)] */ | ||
| 169 | ldx [%g2 + %g5], %g2 | ||
| 170 | andcc %g2, %g7, %g0 | ||
| 171 | sethi %hi(kern_linear_pte_xor), %g5 | ||
| 172 | or %g5, %lo(kern_linear_pte_xor), %g5 | ||
| 173 | bne,a,pt %xcc, 1f | ||
| 174 | add %g5, 8, %g5 | ||
| 175 | |||
| 176 | 1: ldx [%g5], %g2 | ||
| 177 | |||
| 135 | .globl kvmap_linear_patch | 178 | .globl kvmap_linear_patch |
| 136 | kvmap_linear_patch: | 179 | kvmap_linear_patch: |
| 137 | #endif | 180 | ba,pt %xcc, kvmap_dtlb_tsb4m_load |
| 138 | ba,pt %xcc, kvmap_load | ||
| 139 | xor %g2, %g4, %g5 | 181 | xor %g2, %g4, %g5 |
| 140 | 182 | ||
| 141 | #ifdef CONFIG_DEBUG_PAGEALLOC | 183 | kvmap_dtlb_vmalloc_addr: |
| 142 | sethi %hi(swapper_pg_dir), %g5 | 184 | KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath) |
| 143 | or %g5, %lo(swapper_pg_dir), %g5 | 185 | |
| 144 | sllx %g4, 64 - (PGDIR_SHIFT + PGDIR_BITS), %g6 | 186 | KTSB_LOCK_TAG(%g1, %g2, %g7) |
| 145 | srlx %g6, 64 - PAGE_SHIFT, %g6 | 187 | |
| 146 | andn %g6, 0x3, %g6 | 188 | /* Load and check PTE. */ |
| 147 | lduw [%g5 + %g6], %g5 | 189 | ldxa [%g5] ASI_PHYS_USE_EC, %g5 |
| 148 | brz,pn %g5, longpath | 190 | mov 1, %g7 |
| 149 | sllx %g4, 64 - (PMD_SHIFT + PMD_BITS), %g6 | 191 | sllx %g7, TSB_TAG_INVALID_BIT, %g7 |
| 150 | srlx %g6, 64 - PAGE_SHIFT, %g6 | 192 | brgez,a,pn %g5, kvmap_dtlb_longpath |
| 151 | sllx %g5, 11, %g5 | 193 | KTSB_STORE(%g1, %g7) |
| 152 | andn %g6, 0x3, %g6 | 194 | |
| 153 | lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 195 | KTSB_WRITE(%g1, %g5, %g6) |
| 154 | brz,pn %g5, longpath | 196 | |
| 155 | sllx %g4, 64 - PMD_SHIFT, %g6 | 197 | /* fallthrough to TLB load */ |
| 156 | srlx %g6, 64 - PAGE_SHIFT, %g6 | 198 | |
| 157 | sllx %g5, 11, %g5 | 199 | kvmap_dtlb_load: |
| 158 | andn %g6, 0x7, %g6 | 200 | |
| 159 | ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 201 | 661: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB |
| 160 | brz,pn %g5, longpath | 202 | retry |
| 203 | .section .sun4v_2insn_patch, "ax" | ||
| 204 | .word 661b | ||
| 205 | nop | ||
| 206 | nop | ||
| 207 | .previous | ||
| 208 | |||
| 209 | /* For sun4v the ASI_DTLB_DATA_IN store and the retry | ||
| 210 | * instruction get nop'd out and we get here to branch | ||
| 211 | * to the sun4v tlb load code. The registers are setup | ||
| 212 | * as follows: | ||
| 213 | * | ||
| 214 | * %g4: vaddr | ||
| 215 | * %g5: PTE | ||
| 216 | * %g6: TAG | ||
| 217 | * | ||
| 218 | * The sun4v TLB load wants the PTE in %g3 so we fix that | ||
| 219 | * up here. | ||
| 220 | */ | ||
| 221 | ba,pt %xcc, sun4v_dtlb_load | ||
| 222 | mov %g5, %g3 | ||
| 223 | |||
| 224 | kvmap_dtlb_nonlinear: | ||
| 225 | /* Catch kernel NULL pointer derefs. */ | ||
| 226 | sethi %hi(PAGE_SIZE), %g5 | ||
| 227 | cmp %g4, %g5 | ||
| 228 | bleu,pn %xcc, kvmap_dtlb_longpath | ||
| 161 | nop | 229 | nop |
| 162 | ba,a,pt %xcc, kvmap_load | ||
| 163 | #endif | ||
| 164 | 230 | ||
| 165 | kvmap_nonlinear: | 231 | KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) |
| 232 | |||
| 233 | kvmap_dtlb_tsbmiss: | ||
| 166 | sethi %hi(MODULES_VADDR), %g5 | 234 | sethi %hi(MODULES_VADDR), %g5 |
| 167 | cmp %g4, %g5 | 235 | cmp %g4, %g5 |
| 168 | blu,pn %xcc, longpath | 236 | blu,pn %xcc, kvmap_dtlb_longpath |
| 169 | mov (VMALLOC_END >> 24), %g5 | 237 | mov (VMALLOC_END >> 24), %g5 |
| 170 | sllx %g5, 24, %g5 | 238 | sllx %g5, 24, %g5 |
| 171 | cmp %g4, %g5 | 239 | cmp %g4, %g5 |
| 172 | bgeu,pn %xcc, longpath | 240 | bgeu,pn %xcc, kvmap_dtlb_longpath |
| 173 | nop | 241 | nop |
| 174 | 242 | ||
| 175 | kvmap_check_obp: | 243 | kvmap_check_obp: |
| 176 | sethi %hi(LOW_OBP_ADDRESS), %g5 | 244 | sethi %hi(LOW_OBP_ADDRESS), %g5 |
| 177 | cmp %g4, %g5 | 245 | cmp %g4, %g5 |
| 178 | blu,pn %xcc, kvmap_vmalloc_addr | 246 | blu,pn %xcc, kvmap_dtlb_vmalloc_addr |
| 179 | mov 0x1, %g5 | 247 | mov 0x1, %g5 |
| 180 | sllx %g5, 32, %g5 | 248 | sllx %g5, 32, %g5 |
| 181 | cmp %g4, %g5 | 249 | cmp %g4, %g5 |
| 182 | blu,pn %xcc, kvmap_do_obp | 250 | blu,pn %xcc, kvmap_dtlb_obp |
| 183 | nop | 251 | nop |
| 184 | 252 | ba,pt %xcc, kvmap_dtlb_vmalloc_addr | |
| 185 | kvmap_vmalloc_addr: | ||
| 186 | /* If we get here, a vmalloc addr was accessed, load kernel VPTE. */ | ||
| 187 | ldxa [%g3 + %g6] ASI_N, %g5 | ||
| 188 | brgez,pn %g5, longpath | ||
| 189 | nop | 253 | nop |
| 190 | 254 | ||
| 191 | kvmap_load: | 255 | kvmap_dtlb_longpath: |
| 192 | /* PTE is valid, load into TLB and return from trap. */ | 256 | |
| 193 | stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB | 257 | 661: rdpr %pstate, %g5 |
| 194 | retry | 258 | wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate |
| 259 | .section .sun4v_2insn_patch, "ax" | ||
| 260 | .word 661b | ||
| 261 | SET_GL(1) | ||
| 262 | ldxa [%g0] ASI_SCRATCHPAD, %g5 | ||
| 263 | .previous | ||
| 264 | |||
| 265 | rdpr %tl, %g3 | ||
| 266 | cmp %g3, 1 | ||
| 267 | |||
| 268 | 661: mov TLB_TAG_ACCESS, %g4 | ||
| 269 | ldxa [%g4] ASI_DMMU, %g5 | ||
| 270 | .section .sun4v_2insn_patch, "ax" | ||
| 271 | .word 661b | ||
| 272 | ldx [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5 | ||
| 273 | nop | ||
| 274 | .previous | ||
| 275 | |||
| 276 | be,pt %xcc, sparc64_realfault_common | ||
| 277 | mov FAULT_CODE_DTLB, %g4 | ||
| 278 | ba,pt %xcc, winfix_trampoline | ||
| 279 | nop | ||
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 2ff7c32ab0ce..95ffa9418620 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c | |||
| @@ -188,6 +188,7 @@ extern void psycho_init(int, char *); | |||
| 188 | extern void schizo_init(int, char *); | 188 | extern void schizo_init(int, char *); |
| 189 | extern void schizo_plus_init(int, char *); | 189 | extern void schizo_plus_init(int, char *); |
| 190 | extern void tomatillo_init(int, char *); | 190 | extern void tomatillo_init(int, char *); |
| 191 | extern void sun4v_pci_init(int, char *); | ||
| 191 | 192 | ||
| 192 | static struct { | 193 | static struct { |
| 193 | char *model_name; | 194 | char *model_name; |
| @@ -204,6 +205,7 @@ static struct { | |||
| 204 | { "pci108e,8002", schizo_plus_init }, | 205 | { "pci108e,8002", schizo_plus_init }, |
| 205 | { "SUNW,tomatillo", tomatillo_init }, | 206 | { "SUNW,tomatillo", tomatillo_init }, |
| 206 | { "pci108e,a801", tomatillo_init }, | 207 | { "pci108e,a801", tomatillo_init }, |
| 208 | { "SUNW,sun4v-pci", sun4v_pci_init }, | ||
| 207 | }; | 209 | }; |
| 208 | #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ | 210 | #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ |
| 209 | sizeof(pci_controller_table[0])) | 211 | sizeof(pci_controller_table[0])) |
| @@ -283,6 +285,12 @@ int __init pcic_present(void) | |||
| 283 | return pci_controller_scan(pci_is_controller); | 285 | return pci_controller_scan(pci_is_controller); |
| 284 | } | 286 | } |
| 285 | 287 | ||
| 288 | struct pci_iommu_ops *pci_iommu_ops; | ||
| 289 | EXPORT_SYMBOL(pci_iommu_ops); | ||
| 290 | |||
| 291 | extern struct pci_iommu_ops pci_sun4u_iommu_ops, | ||
| 292 | pci_sun4v_iommu_ops; | ||
| 293 | |||
| 286 | /* Find each controller in the system, attach and initialize | 294 | /* Find each controller in the system, attach and initialize |
| 287 | * software state structure for each and link into the | 295 | * software state structure for each and link into the |
| 288 | * pci_controller_root. Setup the controller enough such | 296 | * pci_controller_root. Setup the controller enough such |
| @@ -290,6 +298,11 @@ int __init pcic_present(void) | |||
| 290 | */ | 298 | */ |
| 291 | static void __init pci_controller_probe(void) | 299 | static void __init pci_controller_probe(void) |
| 292 | { | 300 | { |
| 301 | if (tlb_type == hypervisor) | ||
| 302 | pci_iommu_ops = &pci_sun4v_iommu_ops; | ||
| 303 | else | ||
| 304 | pci_iommu_ops = &pci_sun4u_iommu_ops; | ||
| 305 | |||
| 293 | printk("PCI: Probing for controllers.\n"); | 306 | printk("PCI: Probing for controllers.\n"); |
| 294 | 307 | ||
| 295 | pci_controller_scan(pci_controller_init); | 308 | pci_controller_scan(pci_controller_init); |
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 58310aacea28..33dedb1aacd4 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c | |||
| @@ -39,6 +39,8 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm, | |||
| 39 | { | 39 | { |
| 40 | int node; | 40 | int node; |
| 41 | 41 | ||
| 42 | *nregs = 0; | ||
| 43 | |||
| 42 | /* | 44 | /* |
| 43 | * Return the PBM's PROM node in case we are it's PCI device, | 45 | * Return the PBM's PROM node in case we are it's PCI device, |
| 44 | * as the PBM's reg property is different to standard PCI reg | 46 | * as the PBM's reg property is different to standard PCI reg |
| @@ -51,10 +53,8 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm, | |||
| 51 | pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || | 53 | pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || |
| 52 | pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || | 54 | pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || |
| 53 | pdev->device == PCI_DEVICE_ID_SUN_SABRE || | 55 | pdev->device == PCI_DEVICE_ID_SUN_SABRE || |
| 54 | pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) { | 56 | pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) |
| 55 | *nregs = 0; | ||
| 56 | return bus_prom_node; | 57 | return bus_prom_node; |
| 57 | } | ||
| 58 | 58 | ||
| 59 | node = prom_getchild(bus_prom_node); | 59 | node = prom_getchild(bus_prom_node); |
| 60 | while (node != 0) { | 60 | while (node != 0) { |
| @@ -541,135 +541,183 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, | |||
| 541 | pci_assign_unassigned(pbm, bus); | 541 | pci_assign_unassigned(pbm, bus); |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) | 544 | static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm, |
| 545 | struct pci_dev *toplevel_pdev, | ||
| 546 | struct pci_dev *pdev, | ||
| 547 | unsigned int interrupt) | ||
| 545 | { | 548 | { |
| 546 | struct linux_prom_pci_intmap bridge_local_intmap[PROM_PCIIMAP_MAX], *intmap; | 549 | unsigned int ret; |
| 547 | struct linux_prom_pci_intmask bridge_local_intmask, *intmask; | ||
| 548 | struct pcidev_cookie *dev_pcp = pdev->sysdata; | ||
| 549 | struct pci_pbm_info *pbm = dev_pcp->pbm; | ||
| 550 | struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs; | ||
| 551 | unsigned int hi, mid, lo, irq; | ||
| 552 | int i, num_intmap, map_slot; | ||
| 553 | 550 | ||
| 554 | intmap = &pbm->pbm_intmap[0]; | 551 | if (unlikely(interrupt < 1 || interrupt > 4)) { |
| 555 | intmask = &pbm->pbm_intmask; | 552 | printk("%s: Device %s interrupt value of %u is strange.\n", |
| 556 | num_intmap = pbm->num_pbm_intmap; | 553 | pbm->name, pci_name(pdev), interrupt); |
| 557 | map_slot = 0; | 554 | return interrupt; |
| 555 | } | ||
| 558 | 556 | ||
| 559 | /* If we are underneath a PCI bridge, use PROM register | 557 | ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1; |
| 560 | * property of the parent bridge which is closest to | 558 | |
| 561 | * the PBM. | 559 | printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n", |
| 562 | * | 560 | pbm->name, pci_name(toplevel_pdev), pci_name(pdev), |
| 563 | * However if that parent bridge has interrupt map/mask | 561 | interrupt, PCI_SLOT(pdev->devfn), ret); |
| 564 | * properties of its own we use the PROM register property | 562 | |
| 565 | * of the next child device on the path to PDEV. | 563 | return ret; |
| 566 | * | 564 | } |
| 567 | * In detail the two cases are (note that the 'X' below is the | 565 | |
| 568 | * 'next child on the path to PDEV' mentioned above): | 566 | static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm, |
| 569 | * | 567 | struct pci_dev *toplevel_pdev, |
| 570 | * 1) PBM --> PCI bus lacking int{map,mask} --> X ... PDEV | 568 | struct pci_dev *pbus, |
| 571 | * | 569 | struct pci_dev *pdev, |
| 572 | * Here we use regs of 'PCI bus' device. | 570 | unsigned int interrupt, |
| 573 | * | 571 | unsigned int *cnode) |
| 574 | * 2) PBM --> PCI bus with int{map,mask} --> X ... PDEV | 572 | { |
| 575 | * | 573 | struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX]; |
| 576 | * Here we use regs of 'X'. Note that X can be PDEV. | 574 | struct linux_prom_pci_intmask imask; |
| 577 | */ | 575 | struct pcidev_cookie *pbus_pcp = pbus->sysdata; |
| 578 | if (pdev->bus->number != pbm->pci_first_busno) { | 576 | struct pcidev_cookie *pdev_pcp = pdev->sysdata; |
| 579 | struct pcidev_cookie *bus_pcp, *regs_pcp; | 577 | struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs; |
| 580 | struct pci_dev *bus_dev, *regs_dev; | 578 | int plen, num_imap, i; |
| 581 | int plen; | 579 | unsigned int hi, mid, lo, irq, orig_interrupt; |
| 580 | |||
| 581 | *cnode = pbus_pcp->prom_node; | ||
| 582 | |||
| 583 | plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map", | ||
| 584 | (char *) &imap[0], sizeof(imap)); | ||
| 585 | if (plen <= 0 || | ||
| 586 | (plen % sizeof(struct linux_prom_pci_intmap)) != 0) { | ||
| 587 | printk("%s: Device %s interrupt-map has bad len %d\n", | ||
| 588 | pbm->name, pci_name(pbus), plen); | ||
| 589 | goto no_intmap; | ||
| 590 | } | ||
| 591 | num_imap = plen / sizeof(struct linux_prom_pci_intmap); | ||
| 592 | |||
| 593 | plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask", | ||
| 594 | (char *) &imask, sizeof(imask)); | ||
| 595 | if (plen <= 0 || | ||
| 596 | (plen % sizeof(struct linux_prom_pci_intmask)) != 0) { | ||
| 597 | printk("%s: Device %s interrupt-map-mask has bad len %d\n", | ||
| 598 | pbm->name, pci_name(pbus), plen); | ||
| 599 | goto no_intmap; | ||
| 600 | } | ||
| 601 | |||
| 602 | orig_interrupt = interrupt; | ||
| 582 | 603 | ||
| 583 | bus_dev = pdev->bus->self; | 604 | hi = pregs->phys_hi & imask.phys_hi; |
| 584 | regs_dev = pdev; | 605 | mid = pregs->phys_mid & imask.phys_mid; |
| 606 | lo = pregs->phys_lo & imask.phys_lo; | ||
| 607 | irq = interrupt & imask.interrupt; | ||
| 585 | 608 | ||
| 586 | while (bus_dev->bus && | 609 | for (i = 0; i < num_imap; i++) { |
| 587 | bus_dev->bus->number != pbm->pci_first_busno) { | 610 | if (imap[i].phys_hi == hi && |
| 588 | regs_dev = bus_dev; | 611 | imap[i].phys_mid == mid && |
| 589 | bus_dev = bus_dev->bus->self; | 612 | imap[i].phys_lo == lo && |
| 613 | imap[i].interrupt == irq) { | ||
| 614 | *cnode = imap[i].cnode; | ||
| 615 | interrupt = imap[i].cinterrupt; | ||
| 590 | } | 616 | } |
| 617 | } | ||
| 591 | 618 | ||
| 592 | regs_pcp = regs_dev->sysdata; | 619 | printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n", |
| 593 | pregs = regs_pcp->prom_regs; | 620 | pbm->name, pci_name(toplevel_pdev), |
| 621 | pci_name(pbus), pci_name(pdev), | ||
| 622 | orig_interrupt, interrupt); | ||
| 594 | 623 | ||
| 595 | bus_pcp = bus_dev->sysdata; | 624 | no_intmap: |
| 625 | return interrupt; | ||
| 626 | } | ||
| 596 | 627 | ||
| 597 | /* But if the PCI bridge has it's own interrupt map | 628 | /* For each PCI bus on the way to the root: |
| 598 | * and mask properties, use that and the regs of the | 629 | * 1) If it has an interrupt-map property, apply it. |
| 599 | * PCI entity at the next level down on the path to the | 630 | * 2) Else, swivel the interrupt number based upon the PCI device number. |
| 600 | * device. | 631 | * |
| 601 | */ | 632 | * Return the "IRQ controller" node. If this is the PBM's device node, |
| 602 | plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map", | 633 | * all interrupt translations are complete, else we should use that node's |
| 603 | (char *) &bridge_local_intmap[0], | 634 | * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt. |
| 604 | sizeof(bridge_local_intmap)); | 635 | */ |
| 605 | if (plen != -1) { | 636 | static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm, |
| 606 | intmap = &bridge_local_intmap[0]; | 637 | struct pci_dev *pdev, |
| 607 | num_intmap = plen / sizeof(struct linux_prom_pci_intmap); | 638 | unsigned int *interrupt) |
| 608 | plen = prom_getproperty(bus_pcp->prom_node, | 639 | { |
| 609 | "interrupt-map-mask", | 640 | struct pci_dev *toplevel_pdev = pdev; |
| 610 | (char *) &bridge_local_intmask, | 641 | struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata; |
| 611 | sizeof(bridge_local_intmask)); | 642 | unsigned int cnode = toplevel_pcp->prom_node; |
| 612 | if (plen == -1) { | 643 | |
| 613 | printk("pci_intmap_match: Warning! Bridge has intmap " | 644 | while (pdev->bus->number != pbm->pci_first_busno) { |
| 614 | "but no intmask.\n"); | 645 | struct pci_dev *pbus = pdev->bus->self; |
| 615 | printk("pci_intmap_match: Trying to recover.\n"); | 646 | struct pcidev_cookie *pcp = pbus->sysdata; |
| 616 | return 0; | 647 | int plen; |
| 617 | } | ||
| 618 | 648 | ||
| 619 | if (pdev->bus->self != bus_dev) | 649 | plen = prom_getproplen(pcp->prom_node, "interrupt-map"); |
| 620 | map_slot = 1; | 650 | if (plen <= 0) { |
| 651 | *interrupt = pci_slot_swivel(pbm, toplevel_pdev, | ||
| 652 | pdev, *interrupt); | ||
| 653 | cnode = pcp->prom_node; | ||
| 621 | } else { | 654 | } else { |
| 622 | pregs = bus_pcp->prom_regs; | 655 | *interrupt = pci_apply_intmap(pbm, toplevel_pdev, |
| 623 | map_slot = 1; | 656 | pbus, pdev, |
| 657 | *interrupt, &cnode); | ||
| 658 | |||
| 659 | while (pcp->prom_node != cnode && | ||
| 660 | pbus->bus->number != pbm->pci_first_busno) { | ||
| 661 | pbus = pbus->bus->self; | ||
| 662 | pcp = pbus->sysdata; | ||
| 663 | } | ||
| 624 | } | 664 | } |
| 625 | } | 665 | pdev = pbus; |
| 626 | 666 | ||
| 627 | if (map_slot) { | 667 | if (cnode == pbm->prom_node) |
| 628 | *interrupt = ((*interrupt | 668 | break; |
| 629 | - 1 | ||
| 630 | + PCI_SLOT(pdev->devfn)) & 0x3) + 1; | ||
| 631 | } | 669 | } |
| 632 | 670 | ||
| 633 | hi = pregs->phys_hi & intmask->phys_hi; | 671 | return cnode; |
| 634 | mid = pregs->phys_mid & intmask->phys_mid; | 672 | } |
| 635 | lo = pregs->phys_lo & intmask->phys_lo; | 673 | |
| 636 | irq = *interrupt & intmask->interrupt; | 674 | static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) |
| 637 | 675 | { | |
| 638 | for (i = 0; i < num_intmap; i++) { | 676 | struct pcidev_cookie *dev_pcp = pdev->sysdata; |
| 639 | if (intmap[i].phys_hi == hi && | 677 | struct pci_pbm_info *pbm = dev_pcp->pbm; |
| 640 | intmap[i].phys_mid == mid && | 678 | struct linux_prom_pci_registers reg[PROMREG_MAX]; |
| 641 | intmap[i].phys_lo == lo && | 679 | unsigned int hi, mid, lo, irq; |
| 642 | intmap[i].interrupt == irq) { | 680 | int i, cnode, plen; |
| 643 | *interrupt = intmap[i].cinterrupt; | 681 | |
| 644 | printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n", | 682 | cnode = pci_intmap_match_to_root(pbm, pdev, interrupt); |
| 645 | pdev->bus->number, PCI_SLOT(pdev->devfn), | 683 | if (cnode == pbm->prom_node) |
| 646 | map_slot, *interrupt); | 684 | goto success; |
| 647 | return 1; | 685 | |
| 648 | } | 686 | plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg)); |
| 687 | if (plen <= 0 || | ||
| 688 | (plen % sizeof(struct linux_prom_pci_registers)) != 0) { | ||
| 689 | printk("%s: OBP node %x reg property has bad len %d\n", | ||
| 690 | pbm->name, cnode, plen); | ||
| 691 | goto fail; | ||
| 649 | } | 692 | } |
| 650 | 693 | ||
| 651 | /* We will run this code even if pbm->num_pbm_intmap is zero, just so | 694 | hi = reg[0].phys_hi & pbm->pbm_intmask.phys_hi; |
| 652 | * we can apply the slot mapping to the PROM interrupt property value. | 695 | mid = reg[0].phys_mid & pbm->pbm_intmask.phys_mid; |
| 653 | * So do not spit out these warnings in that case. | 696 | lo = reg[0].phys_lo & pbm->pbm_intmask.phys_lo; |
| 654 | */ | 697 | irq = *interrupt & pbm->pbm_intmask.interrupt; |
| 655 | if (num_intmap != 0) { | 698 | |
| 656 | /* Print it both to OBP console and kernel one so that if bootup | 699 | for (i = 0; i < pbm->num_pbm_intmap; i++) { |
| 657 | * hangs here the user has the information to report. | 700 | struct linux_prom_pci_intmap *intmap; |
| 658 | */ | 701 | |
| 659 | prom_printf("pci_intmap_match: bus %02x, devfn %02x: ", | 702 | intmap = &pbm->pbm_intmap[i]; |
| 660 | pdev->bus->number, pdev->devfn); | 703 | |
| 661 | prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", | 704 | if (intmap->phys_hi == hi && |
| 662 | pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); | 705 | intmap->phys_mid == mid && |
| 663 | prom_printf("Please email this information to davem@redhat.com\n"); | 706 | intmap->phys_lo == lo && |
| 664 | 707 | intmap->interrupt == irq) { | |
| 665 | printk("pci_intmap_match: bus %02x, devfn %02x: ", | 708 | *interrupt = intmap->cinterrupt; |
| 666 | pdev->bus->number, pdev->devfn); | 709 | goto success; |
| 667 | printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", | 710 | } |
| 668 | pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); | ||
| 669 | printk("Please email this information to davem@redhat.com\n"); | ||
| 670 | } | 711 | } |
| 671 | 712 | ||
| 713 | fail: | ||
| 672 | return 0; | 714 | return 0; |
| 715 | |||
| 716 | success: | ||
| 717 | printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n", | ||
| 718 | pdev->bus->number, PCI_SLOT(pdev->devfn), | ||
| 719 | *interrupt); | ||
| 720 | return 1; | ||
| 673 | } | 721 | } |
| 674 | 722 | ||
| 675 | static void __init pdev_fixup_irq(struct pci_dev *pdev) | 723 | static void __init pdev_fixup_irq(struct pci_dev *pdev) |
| @@ -703,16 +751,18 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev) | |||
| 703 | return; | 751 | return; |
| 704 | } | 752 | } |
| 705 | 753 | ||
| 706 | /* Fully specified already? */ | 754 | if (tlb_type != hypervisor) { |
| 707 | if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { | 755 | /* Fully specified already? */ |
| 708 | pdev->irq = p->irq_build(pbm, pdev, prom_irq); | 756 | if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { |
| 709 | goto have_irq; | 757 | pdev->irq = p->irq_build(pbm, pdev, prom_irq); |
| 710 | } | 758 | goto have_irq; |
| 759 | } | ||
| 711 | 760 | ||
| 712 | /* An onboard device? (bit 5 set) */ | 761 | /* An onboard device? (bit 5 set) */ |
| 713 | if ((prom_irq & PCI_IRQ_INO) & 0x20) { | 762 | if ((prom_irq & PCI_IRQ_INO) & 0x20) { |
| 714 | pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); | 763 | pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); |
| 715 | goto have_irq; | 764 | goto have_irq; |
| 765 | } | ||
| 716 | } | 766 | } |
| 717 | 767 | ||
| 718 | /* Can we find a matching entry in the interrupt-map? */ | 768 | /* Can we find a matching entry in the interrupt-map? */ |
| @@ -927,33 +977,30 @@ void pci_register_legacy_regions(struct resource *io_res, | |||
| 927 | struct resource *p; | 977 | struct resource *p; |
| 928 | 978 | ||
| 929 | /* VGA Video RAM. */ | 979 | /* VGA Video RAM. */ |
| 930 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 980 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 931 | if (!p) | 981 | if (!p) |
| 932 | return; | 982 | return; |
| 933 | 983 | ||
| 934 | memset(p, 0, sizeof(*p)); | ||
| 935 | p->name = "Video RAM area"; | 984 | p->name = "Video RAM area"; |
| 936 | p->start = mem_res->start + 0xa0000UL; | 985 | p->start = mem_res->start + 0xa0000UL; |
| 937 | p->end = p->start + 0x1ffffUL; | 986 | p->end = p->start + 0x1ffffUL; |
| 938 | p->flags = IORESOURCE_BUSY; | 987 | p->flags = IORESOURCE_BUSY; |
| 939 | request_resource(mem_res, p); | 988 | request_resource(mem_res, p); |
| 940 | 989 | ||
| 941 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 990 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 942 | if (!p) | 991 | if (!p) |
| 943 | return; | 992 | return; |
| 944 | 993 | ||
| 945 | memset(p, 0, sizeof(*p)); | ||
| 946 | p->name = "System ROM"; | 994 | p->name = "System ROM"; |
| 947 | p->start = mem_res->start + 0xf0000UL; | 995 | p->start = mem_res->start + 0xf0000UL; |
| 948 | p->end = p->start + 0xffffUL; | 996 | p->end = p->start + 0xffffUL; |
| 949 | p->flags = IORESOURCE_BUSY; | 997 | p->flags = IORESOURCE_BUSY; |
| 950 | request_resource(mem_res, p); | 998 | request_resource(mem_res, p); |
| 951 | 999 | ||
| 952 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 1000 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 953 | if (!p) | 1001 | if (!p) |
| 954 | return; | 1002 | return; |
| 955 | 1003 | ||
| 956 | memset(p, 0, sizeof(*p)); | ||
| 957 | p->name = "Video ROM"; | 1004 | p->name = "Video ROM"; |
| 958 | p->start = mem_res->start + 0xc0000UL; | 1005 | p->start = mem_res->start + 0xc0000UL; |
| 959 | p->end = p->start + 0x7fffUL; | 1006 | p->end = p->start + 0x7fffUL; |
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index a11910be1013..8efbc139769d 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c | |||
| @@ -139,12 +139,11 @@ void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, | |||
| 139 | /* Allocate and initialize the free area map. */ | 139 | /* Allocate and initialize the free area map. */ |
| 140 | sz = num_tsb_entries / 8; | 140 | sz = num_tsb_entries / 8; |
| 141 | sz = (sz + 7UL) & ~7UL; | 141 | sz = (sz + 7UL) & ~7UL; |
| 142 | iommu->arena.map = kmalloc(sz, GFP_KERNEL); | 142 | iommu->arena.map = kzalloc(sz, GFP_KERNEL); |
| 143 | if (!iommu->arena.map) { | 143 | if (!iommu->arena.map) { |
| 144 | prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); | 144 | prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); |
| 145 | prom_halt(); | 145 | prom_halt(); |
| 146 | } | 146 | } |
| 147 | memset(iommu->arena.map, 0, sz); | ||
| 148 | iommu->arena.limit = num_tsb_entries; | 147 | iommu->arena.limit = num_tsb_entries; |
| 149 | 148 | ||
| 150 | /* Allocate and initialize the dummy page which we | 149 | /* Allocate and initialize the dummy page which we |
| @@ -219,7 +218,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) | |||
| 219 | * DMA for PCI device PDEV. Return non-NULL cpu-side address if | 218 | * DMA for PCI device PDEV. Return non-NULL cpu-side address if |
| 220 | * successful and set *DMA_ADDRP to the PCI side dma address. | 219 | * successful and set *DMA_ADDRP to the PCI side dma address. |
| 221 | */ | 220 | */ |
| 222 | void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) | 221 | static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) |
| 223 | { | 222 | { |
| 224 | struct pcidev_cookie *pcp; | 223 | struct pcidev_cookie *pcp; |
| 225 | struct pci_iommu *iommu; | 224 | struct pci_iommu *iommu; |
| @@ -267,7 +266,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad | |||
| 267 | } | 266 | } |
| 268 | 267 | ||
| 269 | /* Free and unmap a consistent DMA translation. */ | 268 | /* Free and unmap a consistent DMA translation. */ |
| 270 | void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) | 269 | static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) |
| 271 | { | 270 | { |
| 272 | struct pcidev_cookie *pcp; | 271 | struct pcidev_cookie *pcp; |
| 273 | struct pci_iommu *iommu; | 272 | struct pci_iommu *iommu; |
| @@ -294,7 +293,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ | |||
| 294 | /* Map a single buffer at PTR of SZ bytes for PCI DMA | 293 | /* Map a single buffer at PTR of SZ bytes for PCI DMA |
| 295 | * in streaming mode. | 294 | * in streaming mode. |
| 296 | */ | 295 | */ |
| 297 | dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) | 296 | static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) |
| 298 | { | 297 | { |
| 299 | struct pcidev_cookie *pcp; | 298 | struct pcidev_cookie *pcp; |
| 300 | struct pci_iommu *iommu; | 299 | struct pci_iommu *iommu; |
| @@ -415,7 +414,7 @@ do_flush_sync: | |||
| 415 | } | 414 | } |
| 416 | 415 | ||
| 417 | /* Unmap a single streaming mode DMA translation. */ | 416 | /* Unmap a single streaming mode DMA translation. */ |
| 418 | void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) | 417 | static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) |
| 419 | { | 418 | { |
| 420 | struct pcidev_cookie *pcp; | 419 | struct pcidev_cookie *pcp; |
| 421 | struct pci_iommu *iommu; | 420 | struct pci_iommu *iommu; |
| @@ -548,7 +547,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, | |||
| 548 | * When making changes here, inspect the assembly output. I was having | 547 | * When making changes here, inspect the assembly output. I was having |
| 549 | * hard time to kepp this routine out of using stack slots for holding variables. | 548 | * hard time to kepp this routine out of using stack slots for holding variables. |
| 550 | */ | 549 | */ |
| 551 | int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | 550 | static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) |
| 552 | { | 551 | { |
| 553 | struct pcidev_cookie *pcp; | 552 | struct pcidev_cookie *pcp; |
| 554 | struct pci_iommu *iommu; | 553 | struct pci_iommu *iommu; |
| @@ -562,9 +561,9 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int | |||
| 562 | /* Fast path single entry scatterlists. */ | 561 | /* Fast path single entry scatterlists. */ |
| 563 | if (nelems == 1) { | 562 | if (nelems == 1) { |
| 564 | sglist->dma_address = | 563 | sglist->dma_address = |
| 565 | pci_map_single(pdev, | 564 | pci_4u_map_single(pdev, |
| 566 | (page_address(sglist->page) + sglist->offset), | 565 | (page_address(sglist->page) + sglist->offset), |
| 567 | sglist->length, direction); | 566 | sglist->length, direction); |
| 568 | if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) | 567 | if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) |
| 569 | return 0; | 568 | return 0; |
| 570 | sglist->dma_length = sglist->length; | 569 | sglist->dma_length = sglist->length; |
| @@ -635,7 +634,7 @@ bad_no_ctx: | |||
| 635 | } | 634 | } |
| 636 | 635 | ||
| 637 | /* Unmap a set of streaming mode DMA translations. */ | 636 | /* Unmap a set of streaming mode DMA translations. */ |
| 638 | void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | 637 | static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) |
| 639 | { | 638 | { |
| 640 | struct pcidev_cookie *pcp; | 639 | struct pcidev_cookie *pcp; |
| 641 | struct pci_iommu *iommu; | 640 | struct pci_iommu *iommu; |
| @@ -695,7 +694,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, | |||
| 695 | /* Make physical memory consistent for a single | 694 | /* Make physical memory consistent for a single |
| 696 | * streaming mode DMA translation after a transfer. | 695 | * streaming mode DMA translation after a transfer. |
| 697 | */ | 696 | */ |
| 698 | void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) | 697 | static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) |
| 699 | { | 698 | { |
| 700 | struct pcidev_cookie *pcp; | 699 | struct pcidev_cookie *pcp; |
| 701 | struct pci_iommu *iommu; | 700 | struct pci_iommu *iommu; |
| @@ -735,7 +734,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size | |||
| 735 | /* Make physical memory consistent for a set of streaming | 734 | /* Make physical memory consistent for a set of streaming |
| 736 | * mode DMA translations after a transfer. | 735 | * mode DMA translations after a transfer. |
| 737 | */ | 736 | */ |
| 738 | void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | 737 | static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) |
| 739 | { | 738 | { |
| 740 | struct pcidev_cookie *pcp; | 739 | struct pcidev_cookie *pcp; |
| 741 | struct pci_iommu *iommu; | 740 | struct pci_iommu *iommu; |
| @@ -776,6 +775,17 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i | |||
| 776 | spin_unlock_irqrestore(&iommu->lock, flags); | 775 | spin_unlock_irqrestore(&iommu->lock, flags); |
| 777 | } | 776 | } |
| 778 | 777 | ||
| 778 | struct pci_iommu_ops pci_sun4u_iommu_ops = { | ||
| 779 | .alloc_consistent = pci_4u_alloc_consistent, | ||
| 780 | .free_consistent = pci_4u_free_consistent, | ||
| 781 | .map_single = pci_4u_map_single, | ||
| 782 | .unmap_single = pci_4u_unmap_single, | ||
| 783 | .map_sg = pci_4u_map_sg, | ||
| 784 | .unmap_sg = pci_4u_unmap_sg, | ||
| 785 | .dma_sync_single_for_cpu = pci_4u_dma_sync_single_for_cpu, | ||
| 786 | .dma_sync_sg_for_cpu = pci_4u_dma_sync_sg_for_cpu, | ||
| 787 | }; | ||
| 788 | |||
| 779 | static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) | 789 | static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) |
| 780 | { | 790 | { |
| 781 | struct pci_dev *ali_isa_bridge; | 791 | struct pci_dev *ali_isa_bridge; |
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index c03ed5f49d31..d17878b145c2 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c | |||
| @@ -286,17 +286,17 @@ static unsigned char psycho_pil_table[] = { | |||
| 286 | /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ | 286 | /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ |
| 287 | /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ | 287 | /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ |
| 288 | /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ | 288 | /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ |
| 289 | /*0x20*/4, /* SCSI */ | 289 | /*0x20*/5, /* SCSI */ |
| 290 | /*0x21*/5, /* Ethernet */ | 290 | /*0x21*/5, /* Ethernet */ |
| 291 | /*0x22*/8, /* Parallel Port */ | 291 | /*0x22*/8, /* Parallel Port */ |
| 292 | /*0x23*/13, /* Audio Record */ | 292 | /*0x23*/13, /* Audio Record */ |
| 293 | /*0x24*/14, /* Audio Playback */ | 293 | /*0x24*/14, /* Audio Playback */ |
| 294 | /*0x25*/15, /* PowerFail */ | 294 | /*0x25*/15, /* PowerFail */ |
| 295 | /*0x26*/4, /* second SCSI */ | 295 | /*0x26*/5, /* second SCSI */ |
| 296 | /*0x27*/11, /* Floppy */ | 296 | /*0x27*/11, /* Floppy */ |
| 297 | /*0x28*/4, /* Spare Hardware */ | 297 | /*0x28*/5, /* Spare Hardware */ |
| 298 | /*0x29*/9, /* Keyboard */ | 298 | /*0x29*/9, /* Keyboard */ |
| 299 | /*0x2a*/4, /* Mouse */ | 299 | /*0x2a*/5, /* Mouse */ |
| 300 | /*0x2b*/12, /* Serial */ | 300 | /*0x2b*/12, /* Serial */ |
| 301 | /*0x2c*/10, /* Timer 0 */ | 301 | /*0x2c*/10, /* Timer 0 */ |
| 302 | /*0x2d*/11, /* Timer 1 */ | 302 | /*0x2d*/11, /* Timer 1 */ |
| @@ -313,11 +313,11 @@ static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) | |||
| 313 | 313 | ||
| 314 | ret = psycho_pil_table[ino]; | 314 | ret = psycho_pil_table[ino]; |
| 315 | if (ret == 0 && pdev == NULL) { | 315 | if (ret == 0 && pdev == NULL) { |
| 316 | ret = 4; | 316 | ret = 5; |
| 317 | } else if (ret == 0) { | 317 | } else if (ret == 0) { |
| 318 | switch ((pdev->class >> 16) & 0xff) { | 318 | switch ((pdev->class >> 16) & 0xff) { |
| 319 | case PCI_BASE_CLASS_STORAGE: | 319 | case PCI_BASE_CLASS_STORAGE: |
| 320 | ret = 4; | 320 | ret = 5; |
| 321 | break; | 321 | break; |
| 322 | 322 | ||
| 323 | case PCI_BASE_CLASS_NETWORK: | 323 | case PCI_BASE_CLASS_NETWORK: |
| @@ -336,7 +336,7 @@ static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) | |||
| 336 | break; | 336 | break; |
| 337 | 337 | ||
| 338 | default: | 338 | default: |
| 339 | ret = 4; | 339 | ret = 5; |
| 340 | break; | 340 | break; |
| 341 | }; | 341 | }; |
| 342 | } | 342 | } |
| @@ -1164,7 +1164,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) | |||
| 1164 | static void pbm_scan_bus(struct pci_controller_info *p, | 1164 | static void pbm_scan_bus(struct pci_controller_info *p, |
| 1165 | struct pci_pbm_info *pbm) | 1165 | struct pci_pbm_info *pbm) |
| 1166 | { | 1166 | { |
| 1167 | struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); | 1167 | struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); |
| 1168 | 1168 | ||
| 1169 | if (!cookie) { | 1169 | if (!cookie) { |
| 1170 | prom_printf("PSYCHO: Critical allocation failure.\n"); | 1170 | prom_printf("PSYCHO: Critical allocation failure.\n"); |
| @@ -1172,7 +1172,6 @@ static void pbm_scan_bus(struct pci_controller_info *p, | |||
| 1172 | } | 1172 | } |
| 1173 | 1173 | ||
| 1174 | /* All we care about is the PBM. */ | 1174 | /* All we care about is the PBM. */ |
| 1175 | memset(cookie, 0, sizeof(*cookie)); | ||
| 1176 | cookie->pbm = pbm; | 1175 | cookie->pbm = pbm; |
| 1177 | 1176 | ||
| 1178 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, | 1177 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, |
| @@ -1465,18 +1464,16 @@ void psycho_init(int node, char *model_name) | |||
| 1465 | } | 1464 | } |
| 1466 | } | 1465 | } |
| 1467 | 1466 | ||
| 1468 | p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 1467 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); |
| 1469 | if (!p) { | 1468 | if (!p) { |
| 1470 | prom_printf("PSYCHO: Fatal memory allocation error.\n"); | 1469 | prom_printf("PSYCHO: Fatal memory allocation error.\n"); |
| 1471 | prom_halt(); | 1470 | prom_halt(); |
| 1472 | } | 1471 | } |
| 1473 | memset(p, 0, sizeof(*p)); | 1472 | iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); |
| 1474 | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | ||
| 1475 | if (!iommu) { | 1473 | if (!iommu) { |
| 1476 | prom_printf("PSYCHO: Fatal memory allocation error.\n"); | 1474 | prom_printf("PSYCHO: Fatal memory allocation error.\n"); |
| 1477 | prom_halt(); | 1475 | prom_halt(); |
| 1478 | } | 1476 | } |
| 1479 | memset(iommu, 0, sizeof(*iommu)); | ||
| 1480 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; | 1477 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; |
| 1481 | 1478 | ||
| 1482 | p->next = pci_controller_root; | 1479 | p->next = pci_controller_root; |
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index da8e1364194f..f67bb7f078cf 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c | |||
| @@ -533,17 +533,17 @@ static unsigned char sabre_pil_table[] = { | |||
| 533 | /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ | 533 | /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ |
| 534 | /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ | 534 | /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ |
| 535 | /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ | 535 | /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ |
| 536 | /*0x20*/4, /* SCSI */ | 536 | /*0x20*/5, /* SCSI */ |
| 537 | /*0x21*/5, /* Ethernet */ | 537 | /*0x21*/5, /* Ethernet */ |
| 538 | /*0x22*/8, /* Parallel Port */ | 538 | /*0x22*/8, /* Parallel Port */ |
| 539 | /*0x23*/13, /* Audio Record */ | 539 | /*0x23*/13, /* Audio Record */ |
| 540 | /*0x24*/14, /* Audio Playback */ | 540 | /*0x24*/14, /* Audio Playback */ |
| 541 | /*0x25*/15, /* PowerFail */ | 541 | /*0x25*/15, /* PowerFail */ |
| 542 | /*0x26*/4, /* second SCSI */ | 542 | /*0x26*/5, /* second SCSI */ |
| 543 | /*0x27*/11, /* Floppy */ | 543 | /*0x27*/11, /* Floppy */ |
| 544 | /*0x28*/4, /* Spare Hardware */ | 544 | /*0x28*/5, /* Spare Hardware */ |
| 545 | /*0x29*/9, /* Keyboard */ | 545 | /*0x29*/9, /* Keyboard */ |
| 546 | /*0x2a*/4, /* Mouse */ | 546 | /*0x2a*/5, /* Mouse */ |
| 547 | /*0x2b*/12, /* Serial */ | 547 | /*0x2b*/12, /* Serial */ |
| 548 | /*0x2c*/10, /* Timer 0 */ | 548 | /*0x2c*/10, /* Timer 0 */ |
| 549 | /*0x2d*/11, /* Timer 1 */ | 549 | /*0x2d*/11, /* Timer 1 */ |
| @@ -565,11 +565,11 @@ static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) | |||
| 565 | 565 | ||
| 566 | ret = sabre_pil_table[ino]; | 566 | ret = sabre_pil_table[ino]; |
| 567 | if (ret == 0 && pdev == NULL) { | 567 | if (ret == 0 && pdev == NULL) { |
| 568 | ret = 4; | 568 | ret = 5; |
| 569 | } else if (ret == 0) { | 569 | } else if (ret == 0) { |
| 570 | switch ((pdev->class >> 16) & 0xff) { | 570 | switch ((pdev->class >> 16) & 0xff) { |
| 571 | case PCI_BASE_CLASS_STORAGE: | 571 | case PCI_BASE_CLASS_STORAGE: |
| 572 | ret = 4; | 572 | ret = 5; |
| 573 | break; | 573 | break; |
| 574 | 574 | ||
| 575 | case PCI_BASE_CLASS_NETWORK: | 575 | case PCI_BASE_CLASS_NETWORK: |
| @@ -588,7 +588,7 @@ static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) | |||
| 588 | break; | 588 | break; |
| 589 | 589 | ||
| 590 | default: | 590 | default: |
| 591 | ret = 4; | 591 | ret = 5; |
| 592 | break; | 592 | break; |
| 593 | }; | 593 | }; |
| 594 | } | 594 | } |
| @@ -1167,7 +1167,7 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) | |||
| 1167 | 1167 | ||
| 1168 | static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) | 1168 | static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) |
| 1169 | { | 1169 | { |
| 1170 | struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); | 1170 | struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); |
| 1171 | 1171 | ||
| 1172 | if (!cookie) { | 1172 | if (!cookie) { |
| 1173 | prom_printf("SABRE: Critical allocation failure.\n"); | 1173 | prom_printf("SABRE: Critical allocation failure.\n"); |
| @@ -1175,7 +1175,6 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) | |||
| 1175 | } | 1175 | } |
| 1176 | 1176 | ||
| 1177 | /* All we care about is the PBM. */ | 1177 | /* All we care about is the PBM. */ |
| 1178 | memset(cookie, 0, sizeof(*cookie)); | ||
| 1179 | cookie->pbm = pbm; | 1178 | cookie->pbm = pbm; |
| 1180 | 1179 | ||
| 1181 | return cookie; | 1180 | return cookie; |
| @@ -1556,19 +1555,17 @@ void sabre_init(int pnode, char *model_name) | |||
| 1556 | } | 1555 | } |
| 1557 | } | 1556 | } |
| 1558 | 1557 | ||
| 1559 | p = kmalloc(sizeof(*p), GFP_ATOMIC); | 1558 | p = kzalloc(sizeof(*p), GFP_ATOMIC); |
| 1560 | if (!p) { | 1559 | if (!p) { |
| 1561 | prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); | 1560 | prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); |
| 1562 | prom_halt(); | 1561 | prom_halt(); |
| 1563 | } | 1562 | } |
| 1564 | memset(p, 0, sizeof(*p)); | ||
| 1565 | 1563 | ||
| 1566 | iommu = kmalloc(sizeof(*iommu), GFP_ATOMIC); | 1564 | iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); |
| 1567 | if (!iommu) { | 1565 | if (!iommu) { |
| 1568 | prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); | 1566 | prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); |
| 1569 | prom_halt(); | 1567 | prom_halt(); |
| 1570 | } | 1568 | } |
| 1571 | memset(iommu, 0, sizeof(*iommu)); | ||
| 1572 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; | 1569 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; |
| 1573 | 1570 | ||
| 1574 | upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); | 1571 | upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); |
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index d8c4e0919b4e..7fe4de03ac2e 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c | |||
| @@ -243,8 +243,8 @@ static unsigned char schizo_pil_table[] = { | |||
| 243 | /*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ | 243 | /*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ |
| 244 | /*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ | 244 | /*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ |
| 245 | /*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ | 245 | /*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ |
| 246 | /*0x18*/4, /* SCSI */ | 246 | /*0x18*/5, /* SCSI */ |
| 247 | /*0x19*/4, /* second SCSI */ | 247 | /*0x19*/5, /* second SCSI */ |
| 248 | /*0x1a*/0, /* UNKNOWN */ | 248 | /*0x1a*/0, /* UNKNOWN */ |
| 249 | /*0x1b*/0, /* UNKNOWN */ | 249 | /*0x1b*/0, /* UNKNOWN */ |
| 250 | /*0x1c*/8, /* Parallel */ | 250 | /*0x1c*/8, /* Parallel */ |
| @@ -254,7 +254,7 @@ static unsigned char schizo_pil_table[] = { | |||
| 254 | /*0x20*/13, /* Audio Record */ | 254 | /*0x20*/13, /* Audio Record */ |
| 255 | /*0x21*/14, /* Audio Playback */ | 255 | /*0x21*/14, /* Audio Playback */ |
| 256 | /*0x22*/12, /* Serial */ | 256 | /*0x22*/12, /* Serial */ |
| 257 | /*0x23*/4, /* EBUS I2C */ | 257 | /*0x23*/5, /* EBUS I2C */ |
| 258 | /*0x24*/10, /* RTC Clock */ | 258 | /*0x24*/10, /* RTC Clock */ |
| 259 | /*0x25*/11, /* Floppy */ | 259 | /*0x25*/11, /* Floppy */ |
| 260 | /*0x26*/0, /* UNKNOWN */ | 260 | /*0x26*/0, /* UNKNOWN */ |
| @@ -296,11 +296,11 @@ static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) | |||
| 296 | 296 | ||
| 297 | ret = schizo_pil_table[ino]; | 297 | ret = schizo_pil_table[ino]; |
| 298 | if (ret == 0 && pdev == NULL) { | 298 | if (ret == 0 && pdev == NULL) { |
| 299 | ret = 4; | 299 | ret = 5; |
| 300 | } else if (ret == 0) { | 300 | } else if (ret == 0) { |
| 301 | switch ((pdev->class >> 16) & 0xff) { | 301 | switch ((pdev->class >> 16) & 0xff) { |
| 302 | case PCI_BASE_CLASS_STORAGE: | 302 | case PCI_BASE_CLASS_STORAGE: |
| 303 | ret = 4; | 303 | ret = 5; |
| 304 | break; | 304 | break; |
| 305 | 305 | ||
| 306 | case PCI_BASE_CLASS_NETWORK: | 306 | case PCI_BASE_CLASS_NETWORK: |
| @@ -319,7 +319,7 @@ static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) | |||
| 319 | break; | 319 | break; |
| 320 | 320 | ||
| 321 | default: | 321 | default: |
| 322 | ret = 4; | 322 | ret = 5; |
| 323 | break; | 323 | break; |
| 324 | }; | 324 | }; |
| 325 | } | 325 | } |
| @@ -1525,7 +1525,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) | |||
| 1525 | static void pbm_scan_bus(struct pci_controller_info *p, | 1525 | static void pbm_scan_bus(struct pci_controller_info *p, |
| 1526 | struct pci_pbm_info *pbm) | 1526 | struct pci_pbm_info *pbm) |
| 1527 | { | 1527 | { |
| 1528 | struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); | 1528 | struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); |
| 1529 | 1529 | ||
| 1530 | if (!cookie) { | 1530 | if (!cookie) { |
| 1531 | prom_printf("%s: Critical allocation failure.\n", pbm->name); | 1531 | prom_printf("%s: Critical allocation failure.\n", pbm->name); |
| @@ -1533,7 +1533,6 @@ static void pbm_scan_bus(struct pci_controller_info *p, | |||
| 1533 | } | 1533 | } |
| 1534 | 1534 | ||
| 1535 | /* All we care about is the PBM. */ | 1535 | /* All we care about is the PBM. */ |
| 1536 | memset(cookie, 0, sizeof(*cookie)); | ||
| 1537 | cookie->pbm = pbm; | 1536 | cookie->pbm = pbm; |
| 1538 | 1537 | ||
| 1539 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, | 1538 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, |
| @@ -2120,27 +2119,24 @@ static void __schizo_init(int node, char *model_name, int chip_type) | |||
| 2120 | } | 2119 | } |
| 2121 | } | 2120 | } |
| 2122 | 2121 | ||
| 2123 | p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 2122 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); |
| 2124 | if (!p) { | 2123 | if (!p) { |
| 2125 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); | 2124 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); |
| 2126 | prom_halt(); | 2125 | prom_halt(); |
| 2127 | } | 2126 | } |
| 2128 | memset(p, 0, sizeof(*p)); | ||
| 2129 | 2127 | ||
| 2130 | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | 2128 | iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); |
| 2131 | if (!iommu) { | 2129 | if (!iommu) { |
| 2132 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); | 2130 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); |
| 2133 | prom_halt(); | 2131 | prom_halt(); |
| 2134 | } | 2132 | } |
| 2135 | memset(iommu, 0, sizeof(*iommu)); | ||
| 2136 | p->pbm_A.iommu = iommu; | 2133 | p->pbm_A.iommu = iommu; |
| 2137 | 2134 | ||
| 2138 | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | 2135 | iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); |
| 2139 | if (!iommu) { | 2136 | if (!iommu) { |
| 2140 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); | 2137 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); |
| 2141 | prom_halt(); | 2138 | prom_halt(); |
| 2142 | } | 2139 | } |
| 2143 | memset(iommu, 0, sizeof(*iommu)); | ||
| 2144 | p->pbm_B.iommu = iommu; | 2140 | p->pbm_B.iommu = iommu; |
| 2145 | 2141 | ||
| 2146 | p->next = pci_controller_root; | 2142 | p->next = pci_controller_root; |
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c new file mode 100644 index 000000000000..9372d4f376d5 --- /dev/null +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
| @@ -0,0 +1,1147 @@ | |||
| 1 | /* pci_sun4v.c: SUN4V specific PCI controller support. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <linux/types.h> | ||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/percpu.h> | ||
| 13 | |||
| 14 | #include <asm/pbm.h> | ||
| 15 | #include <asm/iommu.h> | ||
| 16 | #include <asm/irq.h> | ||
| 17 | #include <asm/upa.h> | ||
| 18 | #include <asm/pstate.h> | ||
| 19 | #include <asm/oplib.h> | ||
| 20 | #include <asm/hypervisor.h> | ||
| 21 | |||
| 22 | #include "pci_impl.h" | ||
| 23 | #include "iommu_common.h" | ||
| 24 | |||
| 25 | #include "pci_sun4v.h" | ||
| 26 | |||
| 27 | #define PGLIST_NENTS (PAGE_SIZE / sizeof(u64)) | ||
| 28 | |||
| 29 | struct pci_iommu_batch { | ||
| 30 | struct pci_dev *pdev; /* Device mapping is for. */ | ||
| 31 | unsigned long prot; /* IOMMU page protections */ | ||
| 32 | unsigned long entry; /* Index into IOTSB. */ | ||
| 33 | u64 *pglist; /* List of physical pages */ | ||
| 34 | unsigned long npages; /* Number of pages in list. */ | ||
| 35 | }; | ||
| 36 | |||
| 37 | static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch); | ||
| 38 | |||
| 39 | /* Interrupts must be disabled. */ | ||
| 40 | static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry) | ||
| 41 | { | ||
| 42 | struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); | ||
| 43 | |||
| 44 | p->pdev = pdev; | ||
| 45 | p->prot = prot; | ||
| 46 | p->entry = entry; | ||
| 47 | p->npages = 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | /* Interrupts must be disabled. */ | ||
| 51 | static long pci_iommu_batch_flush(struct pci_iommu_batch *p) | ||
| 52 | { | ||
| 53 | struct pcidev_cookie *pcp = p->pdev->sysdata; | ||
| 54 | unsigned long devhandle = pcp->pbm->devhandle; | ||
| 55 | unsigned long prot = p->prot; | ||
| 56 | unsigned long entry = p->entry; | ||
| 57 | u64 *pglist = p->pglist; | ||
| 58 | unsigned long npages = p->npages; | ||
| 59 | |||
| 60 | while (npages != 0) { | ||
| 61 | long num; | ||
| 62 | |||
| 63 | num = pci_sun4v_iommu_map(devhandle, HV_PCI_TSBID(0, entry), | ||
| 64 | npages, prot, __pa(pglist)); | ||
| 65 | if (unlikely(num < 0)) { | ||
| 66 | if (printk_ratelimit()) | ||
| 67 | printk("pci_iommu_batch_flush: IOMMU map of " | ||
| 68 | "[%08lx:%08lx:%lx:%lx:%lx] failed with " | ||
| 69 | "status %ld\n", | ||
| 70 | devhandle, HV_PCI_TSBID(0, entry), | ||
| 71 | npages, prot, __pa(pglist), num); | ||
| 72 | return -1; | ||
| 73 | } | ||
| 74 | |||
| 75 | entry += num; | ||
| 76 | npages -= num; | ||
| 77 | pglist += num; | ||
| 78 | } | ||
| 79 | |||
| 80 | p->entry = entry; | ||
| 81 | p->npages = 0; | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* Interrupts must be disabled. */ | ||
| 87 | static inline long pci_iommu_batch_add(u64 phys_page) | ||
| 88 | { | ||
| 89 | struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); | ||
| 90 | |||
| 91 | BUG_ON(p->npages >= PGLIST_NENTS); | ||
| 92 | |||
| 93 | p->pglist[p->npages++] = phys_page; | ||
| 94 | if (p->npages == PGLIST_NENTS) | ||
| 95 | return pci_iommu_batch_flush(p); | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | /* Interrupts must be disabled. */ | ||
| 101 | static inline long pci_iommu_batch_end(void) | ||
| 102 | { | ||
| 103 | struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); | ||
| 104 | |||
| 105 | BUG_ON(p->npages >= PGLIST_NENTS); | ||
| 106 | |||
| 107 | return pci_iommu_batch_flush(p); | ||
| 108 | } | ||
| 109 | |||
| 110 | static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages) | ||
| 111 | { | ||
| 112 | unsigned long n, i, start, end, limit; | ||
| 113 | int pass; | ||
| 114 | |||
| 115 | limit = arena->limit; | ||
| 116 | start = arena->hint; | ||
| 117 | pass = 0; | ||
| 118 | |||
| 119 | again: | ||
| 120 | n = find_next_zero_bit(arena->map, limit, start); | ||
| 121 | end = n + npages; | ||
| 122 | if (unlikely(end >= limit)) { | ||
| 123 | if (likely(pass < 1)) { | ||
| 124 | limit = start; | ||
| 125 | start = 0; | ||
| 126 | pass++; | ||
| 127 | goto again; | ||
| 128 | } else { | ||
| 129 | /* Scanned the whole thing, give up. */ | ||
| 130 | return -1; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | for (i = n; i < end; i++) { | ||
| 135 | if (test_bit(i, arena->map)) { | ||
| 136 | start = i + 1; | ||
| 137 | goto again; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | for (i = n; i < end; i++) | ||
| 142 | __set_bit(i, arena->map); | ||
| 143 | |||
| 144 | arena->hint = end; | ||
| 145 | |||
| 146 | return n; | ||
| 147 | } | ||
| 148 | |||
| 149 | static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) | ||
| 150 | { | ||
| 151 | unsigned long i; | ||
| 152 | |||
| 153 | for (i = base; i < (base + npages); i++) | ||
| 154 | __clear_bit(i, arena->map); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) | ||
| 158 | { | ||
| 159 | struct pcidev_cookie *pcp; | ||
| 160 | struct pci_iommu *iommu; | ||
| 161 | unsigned long flags, order, first_page, npages, n; | ||
| 162 | void *ret; | ||
| 163 | long entry; | ||
| 164 | |||
| 165 | size = IO_PAGE_ALIGN(size); | ||
| 166 | order = get_order(size); | ||
| 167 | if (unlikely(order >= MAX_ORDER)) | ||
| 168 | return NULL; | ||
| 169 | |||
| 170 | npages = size >> IO_PAGE_SHIFT; | ||
| 171 | |||
| 172 | first_page = __get_free_pages(GFP_ATOMIC, order); | ||
| 173 | if (unlikely(first_page == 0UL)) | ||
| 174 | return NULL; | ||
| 175 | |||
| 176 | memset((char *)first_page, 0, PAGE_SIZE << order); | ||
| 177 | |||
| 178 | pcp = pdev->sysdata; | ||
| 179 | iommu = pcp->pbm->iommu; | ||
| 180 | |||
| 181 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 182 | entry = pci_arena_alloc(&iommu->arena, npages); | ||
| 183 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 184 | |||
| 185 | if (unlikely(entry < 0L)) | ||
| 186 | goto arena_alloc_fail; | ||
| 187 | |||
| 188 | *dma_addrp = (iommu->page_table_map_base + | ||
| 189 | (entry << IO_PAGE_SHIFT)); | ||
| 190 | ret = (void *) first_page; | ||
| 191 | first_page = __pa(first_page); | ||
| 192 | |||
| 193 | local_irq_save(flags); | ||
| 194 | |||
| 195 | pci_iommu_batch_start(pdev, | ||
| 196 | (HV_PCI_MAP_ATTR_READ | | ||
| 197 | HV_PCI_MAP_ATTR_WRITE), | ||
| 198 | entry); | ||
| 199 | |||
| 200 | for (n = 0; n < npages; n++) { | ||
| 201 | long err = pci_iommu_batch_add(first_page + (n * PAGE_SIZE)); | ||
| 202 | if (unlikely(err < 0L)) | ||
| 203 | goto iommu_map_fail; | ||
| 204 | } | ||
| 205 | |||
| 206 | if (unlikely(pci_iommu_batch_end() < 0L)) | ||
| 207 | goto iommu_map_fail; | ||
| 208 | |||
| 209 | local_irq_restore(flags); | ||
| 210 | |||
| 211 | return ret; | ||
| 212 | |||
| 213 | iommu_map_fail: | ||
| 214 | /* Interrupts are disabled. */ | ||
| 215 | spin_lock(&iommu->lock); | ||
| 216 | pci_arena_free(&iommu->arena, entry, npages); | ||
| 217 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 218 | |||
| 219 | arena_alloc_fail: | ||
| 220 | free_pages(first_page, order); | ||
| 221 | return NULL; | ||
| 222 | } | ||
| 223 | |||
| 224 | static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) | ||
| 225 | { | ||
| 226 | struct pcidev_cookie *pcp; | ||
| 227 | struct pci_iommu *iommu; | ||
| 228 | unsigned long flags, order, npages, entry; | ||
| 229 | u32 devhandle; | ||
| 230 | |||
| 231 | npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; | ||
| 232 | pcp = pdev->sysdata; | ||
| 233 | iommu = pcp->pbm->iommu; | ||
| 234 | devhandle = pcp->pbm->devhandle; | ||
| 235 | entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); | ||
| 236 | |||
| 237 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 238 | |||
| 239 | pci_arena_free(&iommu->arena, entry, npages); | ||
| 240 | |||
| 241 | do { | ||
| 242 | unsigned long num; | ||
| 243 | |||
| 244 | num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), | ||
| 245 | npages); | ||
| 246 | entry += num; | ||
| 247 | npages -= num; | ||
| 248 | } while (npages != 0); | ||
| 249 | |||
| 250 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 251 | |||
| 252 | order = get_order(size); | ||
| 253 | if (order < 10) | ||
| 254 | free_pages((unsigned long)cpu, order); | ||
| 255 | } | ||
| 256 | |||
| 257 | static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) | ||
| 258 | { | ||
| 259 | struct pcidev_cookie *pcp; | ||
| 260 | struct pci_iommu *iommu; | ||
| 261 | unsigned long flags, npages, oaddr; | ||
| 262 | unsigned long i, base_paddr; | ||
| 263 | u32 bus_addr, ret; | ||
| 264 | unsigned long prot; | ||
| 265 | long entry; | ||
| 266 | |||
| 267 | pcp = pdev->sysdata; | ||
| 268 | iommu = pcp->pbm->iommu; | ||
| 269 | |||
| 270 | if (unlikely(direction == PCI_DMA_NONE)) | ||
| 271 | goto bad; | ||
| 272 | |||
| 273 | oaddr = (unsigned long)ptr; | ||
| 274 | npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); | ||
| 275 | npages >>= IO_PAGE_SHIFT; | ||
| 276 | |||
| 277 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 278 | entry = pci_arena_alloc(&iommu->arena, npages); | ||
| 279 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 280 | |||
| 281 | if (unlikely(entry < 0L)) | ||
| 282 | goto bad; | ||
| 283 | |||
| 284 | bus_addr = (iommu->page_table_map_base + | ||
| 285 | (entry << IO_PAGE_SHIFT)); | ||
| 286 | ret = bus_addr | (oaddr & ~IO_PAGE_MASK); | ||
| 287 | base_paddr = __pa(oaddr & IO_PAGE_MASK); | ||
| 288 | prot = HV_PCI_MAP_ATTR_READ; | ||
| 289 | if (direction != PCI_DMA_TODEVICE) | ||
| 290 | prot |= HV_PCI_MAP_ATTR_WRITE; | ||
| 291 | |||
| 292 | local_irq_save(flags); | ||
| 293 | |||
| 294 | pci_iommu_batch_start(pdev, prot, entry); | ||
| 295 | |||
| 296 | for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) { | ||
| 297 | long err = pci_iommu_batch_add(base_paddr); | ||
| 298 | if (unlikely(err < 0L)) | ||
| 299 | goto iommu_map_fail; | ||
| 300 | } | ||
| 301 | if (unlikely(pci_iommu_batch_end() < 0L)) | ||
| 302 | goto iommu_map_fail; | ||
| 303 | |||
| 304 | local_irq_restore(flags); | ||
| 305 | |||
| 306 | return ret; | ||
| 307 | |||
| 308 | bad: | ||
| 309 | if (printk_ratelimit()) | ||
| 310 | WARN_ON(1); | ||
| 311 | return PCI_DMA_ERROR_CODE; | ||
| 312 | |||
| 313 | iommu_map_fail: | ||
| 314 | /* Interrupts are disabled. */ | ||
| 315 | spin_lock(&iommu->lock); | ||
| 316 | pci_arena_free(&iommu->arena, entry, npages); | ||
| 317 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 318 | |||
| 319 | return PCI_DMA_ERROR_CODE; | ||
| 320 | } | ||
| 321 | |||
| 322 | static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) | ||
| 323 | { | ||
| 324 | struct pcidev_cookie *pcp; | ||
| 325 | struct pci_iommu *iommu; | ||
| 326 | unsigned long flags, npages; | ||
| 327 | long entry; | ||
| 328 | u32 devhandle; | ||
| 329 | |||
| 330 | if (unlikely(direction == PCI_DMA_NONE)) { | ||
| 331 | if (printk_ratelimit()) | ||
| 332 | WARN_ON(1); | ||
| 333 | return; | ||
| 334 | } | ||
| 335 | |||
| 336 | pcp = pdev->sysdata; | ||
| 337 | iommu = pcp->pbm->iommu; | ||
| 338 | devhandle = pcp->pbm->devhandle; | ||
| 339 | |||
| 340 | npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); | ||
| 341 | npages >>= IO_PAGE_SHIFT; | ||
| 342 | bus_addr &= IO_PAGE_MASK; | ||
| 343 | |||
| 344 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 345 | |||
| 346 | entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; | ||
| 347 | pci_arena_free(&iommu->arena, entry, npages); | ||
| 348 | |||
| 349 | do { | ||
| 350 | unsigned long num; | ||
| 351 | |||
| 352 | num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), | ||
| 353 | npages); | ||
| 354 | entry += num; | ||
| 355 | npages -= num; | ||
| 356 | } while (npages != 0); | ||
| 357 | |||
| 358 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 359 | } | ||
| 360 | |||
| 361 | #define SG_ENT_PHYS_ADDRESS(SG) \ | ||
| 362 | (__pa(page_address((SG)->page)) + (SG)->offset) | ||
| 363 | |||
| 364 | static inline long fill_sg(long entry, struct pci_dev *pdev, | ||
| 365 | struct scatterlist *sg, | ||
| 366 | int nused, int nelems, unsigned long prot) | ||
| 367 | { | ||
| 368 | struct scatterlist *dma_sg = sg; | ||
| 369 | struct scatterlist *sg_end = sg + nelems; | ||
| 370 | unsigned long flags; | ||
| 371 | int i; | ||
| 372 | |||
| 373 | local_irq_save(flags); | ||
| 374 | |||
| 375 | pci_iommu_batch_start(pdev, prot, entry); | ||
| 376 | |||
| 377 | for (i = 0; i < nused; i++) { | ||
| 378 | unsigned long pteval = ~0UL; | ||
| 379 | u32 dma_npages; | ||
| 380 | |||
| 381 | dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + | ||
| 382 | dma_sg->dma_length + | ||
| 383 | ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; | ||
| 384 | do { | ||
| 385 | unsigned long offset; | ||
| 386 | signed int len; | ||
| 387 | |||
| 388 | /* If we are here, we know we have at least one | ||
| 389 | * more page to map. So walk forward until we | ||
| 390 | * hit a page crossing, and begin creating new | ||
| 391 | * mappings from that spot. | ||
| 392 | */ | ||
| 393 | for (;;) { | ||
| 394 | unsigned long tmp; | ||
| 395 | |||
| 396 | tmp = SG_ENT_PHYS_ADDRESS(sg); | ||
| 397 | len = sg->length; | ||
| 398 | if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { | ||
| 399 | pteval = tmp & IO_PAGE_MASK; | ||
| 400 | offset = tmp & (IO_PAGE_SIZE - 1UL); | ||
| 401 | break; | ||
| 402 | } | ||
| 403 | if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { | ||
| 404 | pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; | ||
| 405 | offset = 0UL; | ||
| 406 | len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); | ||
| 407 | break; | ||
| 408 | } | ||
| 409 | sg++; | ||
| 410 | } | ||
| 411 | |||
| 412 | pteval = (pteval & IOPTE_PAGE); | ||
| 413 | while (len > 0) { | ||
| 414 | long err; | ||
| 415 | |||
| 416 | err = pci_iommu_batch_add(pteval); | ||
| 417 | if (unlikely(err < 0L)) | ||
| 418 | goto iommu_map_failed; | ||
| 419 | |||
| 420 | pteval += IO_PAGE_SIZE; | ||
| 421 | len -= (IO_PAGE_SIZE - offset); | ||
| 422 | offset = 0; | ||
| 423 | dma_npages--; | ||
| 424 | } | ||
| 425 | |||
| 426 | pteval = (pteval & IOPTE_PAGE) + len; | ||
| 427 | sg++; | ||
| 428 | |||
| 429 | /* Skip over any tail mappings we've fully mapped, | ||
| 430 | * adjusting pteval along the way. Stop when we | ||
| 431 | * detect a page crossing event. | ||
| 432 | */ | ||
| 433 | while (sg < sg_end && | ||
| 434 | (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && | ||
| 435 | (pteval == SG_ENT_PHYS_ADDRESS(sg)) && | ||
| 436 | ((pteval ^ | ||
| 437 | (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { | ||
| 438 | pteval += sg->length; | ||
| 439 | sg++; | ||
| 440 | } | ||
| 441 | if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) | ||
| 442 | pteval = ~0UL; | ||
| 443 | } while (dma_npages != 0); | ||
| 444 | dma_sg++; | ||
| 445 | } | ||
| 446 | |||
| 447 | if (unlikely(pci_iommu_batch_end() < 0L)) | ||
| 448 | goto iommu_map_failed; | ||
| 449 | |||
| 450 | local_irq_restore(flags); | ||
| 451 | return 0; | ||
| 452 | |||
| 453 | iommu_map_failed: | ||
| 454 | local_irq_restore(flags); | ||
| 455 | return -1L; | ||
| 456 | } | ||
| 457 | |||
| 458 | static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | ||
| 459 | { | ||
| 460 | struct pcidev_cookie *pcp; | ||
| 461 | struct pci_iommu *iommu; | ||
| 462 | unsigned long flags, npages, prot; | ||
| 463 | u32 dma_base; | ||
| 464 | struct scatterlist *sgtmp; | ||
| 465 | long entry, err; | ||
| 466 | int used; | ||
| 467 | |||
| 468 | /* Fast path single entry scatterlists. */ | ||
| 469 | if (nelems == 1) { | ||
| 470 | sglist->dma_address = | ||
| 471 | pci_4v_map_single(pdev, | ||
| 472 | (page_address(sglist->page) + sglist->offset), | ||
| 473 | sglist->length, direction); | ||
| 474 | if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) | ||
| 475 | return 0; | ||
| 476 | sglist->dma_length = sglist->length; | ||
| 477 | return 1; | ||
| 478 | } | ||
| 479 | |||
| 480 | pcp = pdev->sysdata; | ||
| 481 | iommu = pcp->pbm->iommu; | ||
| 482 | |||
| 483 | if (unlikely(direction == PCI_DMA_NONE)) | ||
| 484 | goto bad; | ||
| 485 | |||
| 486 | /* Step 1: Prepare scatter list. */ | ||
| 487 | npages = prepare_sg(sglist, nelems); | ||
| 488 | |||
| 489 | /* Step 2: Allocate a cluster and context, if necessary. */ | ||
| 490 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 491 | entry = pci_arena_alloc(&iommu->arena, npages); | ||
| 492 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 493 | |||
| 494 | if (unlikely(entry < 0L)) | ||
| 495 | goto bad; | ||
| 496 | |||
| 497 | dma_base = iommu->page_table_map_base + | ||
| 498 | (entry << IO_PAGE_SHIFT); | ||
| 499 | |||
| 500 | /* Step 3: Normalize DMA addresses. */ | ||
| 501 | used = nelems; | ||
| 502 | |||
| 503 | sgtmp = sglist; | ||
| 504 | while (used && sgtmp->dma_length) { | ||
| 505 | sgtmp->dma_address += dma_base; | ||
| 506 | sgtmp++; | ||
| 507 | used--; | ||
| 508 | } | ||
| 509 | used = nelems - used; | ||
| 510 | |||
| 511 | /* Step 4: Create the mappings. */ | ||
| 512 | prot = HV_PCI_MAP_ATTR_READ; | ||
| 513 | if (direction != PCI_DMA_TODEVICE) | ||
| 514 | prot |= HV_PCI_MAP_ATTR_WRITE; | ||
| 515 | |||
| 516 | err = fill_sg(entry, pdev, sglist, used, nelems, prot); | ||
| 517 | if (unlikely(err < 0L)) | ||
| 518 | goto iommu_map_failed; | ||
| 519 | |||
| 520 | return used; | ||
| 521 | |||
| 522 | bad: | ||
| 523 | if (printk_ratelimit()) | ||
| 524 | WARN_ON(1); | ||
| 525 | return 0; | ||
| 526 | |||
| 527 | iommu_map_failed: | ||
| 528 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 529 | pci_arena_free(&iommu->arena, entry, npages); | ||
| 530 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 531 | |||
| 532 | return 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | ||
| 536 | { | ||
| 537 | struct pcidev_cookie *pcp; | ||
| 538 | struct pci_iommu *iommu; | ||
| 539 | unsigned long flags, i, npages; | ||
| 540 | long entry; | ||
| 541 | u32 devhandle, bus_addr; | ||
| 542 | |||
| 543 | if (unlikely(direction == PCI_DMA_NONE)) { | ||
| 544 | if (printk_ratelimit()) | ||
| 545 | WARN_ON(1); | ||
| 546 | } | ||
| 547 | |||
| 548 | pcp = pdev->sysdata; | ||
| 549 | iommu = pcp->pbm->iommu; | ||
| 550 | devhandle = pcp->pbm->devhandle; | ||
| 551 | |||
| 552 | bus_addr = sglist->dma_address & IO_PAGE_MASK; | ||
| 553 | |||
| 554 | for (i = 1; i < nelems; i++) | ||
| 555 | if (sglist[i].dma_length == 0) | ||
| 556 | break; | ||
| 557 | i--; | ||
| 558 | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - | ||
| 559 | bus_addr) >> IO_PAGE_SHIFT; | ||
| 560 | |||
| 561 | entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); | ||
| 562 | |||
| 563 | spin_lock_irqsave(&iommu->lock, flags); | ||
| 564 | |||
| 565 | pci_arena_free(&iommu->arena, entry, npages); | ||
| 566 | |||
| 567 | do { | ||
| 568 | unsigned long num; | ||
| 569 | |||
| 570 | num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), | ||
| 571 | npages); | ||
| 572 | entry += num; | ||
| 573 | npages -= num; | ||
| 574 | } while (npages != 0); | ||
| 575 | |||
| 576 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
| 577 | } | ||
| 578 | |||
| 579 | static void pci_4v_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) | ||
| 580 | { | ||
| 581 | /* Nothing to do... */ | ||
| 582 | } | ||
| 583 | |||
| 584 | static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | ||
| 585 | { | ||
| 586 | /* Nothing to do... */ | ||
| 587 | } | ||
| 588 | |||
| 589 | struct pci_iommu_ops pci_sun4v_iommu_ops = { | ||
| 590 | .alloc_consistent = pci_4v_alloc_consistent, | ||
| 591 | .free_consistent = pci_4v_free_consistent, | ||
| 592 | .map_single = pci_4v_map_single, | ||
| 593 | .unmap_single = pci_4v_unmap_single, | ||
| 594 | .map_sg = pci_4v_map_sg, | ||
| 595 | .unmap_sg = pci_4v_unmap_sg, | ||
| 596 | .dma_sync_single_for_cpu = pci_4v_dma_sync_single_for_cpu, | ||
| 597 | .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu, | ||
| 598 | }; | ||
| 599 | |||
| 600 | /* SUN4V PCI configuration space accessors. */ | ||
| 601 | |||
| 602 | static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) | ||
| 603 | { | ||
| 604 | if (bus == pbm->pci_first_busno) { | ||
| 605 | if (device == 0 && func == 0) | ||
| 606 | return 0; | ||
| 607 | return 1; | ||
| 608 | } | ||
| 609 | |||
| 610 | if (bus < pbm->pci_first_busno || | ||
| 611 | bus > pbm->pci_last_busno) | ||
| 612 | return 1; | ||
| 613 | return 0; | ||
| 614 | } | ||
| 615 | |||
| 616 | static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | ||
| 617 | int where, int size, u32 *value) | ||
| 618 | { | ||
| 619 | struct pci_pbm_info *pbm = bus_dev->sysdata; | ||
| 620 | u32 devhandle = pbm->devhandle; | ||
| 621 | unsigned int bus = bus_dev->number; | ||
| 622 | unsigned int device = PCI_SLOT(devfn); | ||
| 623 | unsigned int func = PCI_FUNC(devfn); | ||
| 624 | unsigned long ret; | ||
| 625 | |||
| 626 | if (pci_sun4v_out_of_range(pbm, bus, device, func)) { | ||
| 627 | ret = ~0UL; | ||
| 628 | } else { | ||
| 629 | ret = pci_sun4v_config_get(devhandle, | ||
| 630 | HV_PCI_DEVICE_BUILD(bus, device, func), | ||
| 631 | where, size); | ||
| 632 | #if 0 | ||
| 633 | printk("rcfg: [%x:%x:%x:%d]=[%lx]\n", | ||
| 634 | devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), | ||
| 635 | where, size, ret); | ||
| 636 | #endif | ||
| 637 | } | ||
| 638 | switch (size) { | ||
| 639 | case 1: | ||
| 640 | *value = ret & 0xff; | ||
| 641 | break; | ||
| 642 | case 2: | ||
| 643 | *value = ret & 0xffff; | ||
| 644 | break; | ||
| 645 | case 4: | ||
| 646 | *value = ret & 0xffffffff; | ||
| 647 | break; | ||
| 648 | }; | ||
| 649 | |||
| 650 | |||
| 651 | return PCIBIOS_SUCCESSFUL; | ||
| 652 | } | ||
| 653 | |||
| 654 | static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | ||
| 655 | int where, int size, u32 value) | ||
| 656 | { | ||
| 657 | struct pci_pbm_info *pbm = bus_dev->sysdata; | ||
| 658 | u32 devhandle = pbm->devhandle; | ||
| 659 | unsigned int bus = bus_dev->number; | ||
| 660 | unsigned int device = PCI_SLOT(devfn); | ||
| 661 | unsigned int func = PCI_FUNC(devfn); | ||
| 662 | unsigned long ret; | ||
| 663 | |||
| 664 | if (pci_sun4v_out_of_range(pbm, bus, device, func)) { | ||
| 665 | /* Do nothing. */ | ||
| 666 | } else { | ||
| 667 | ret = pci_sun4v_config_put(devhandle, | ||
| 668 | HV_PCI_DEVICE_BUILD(bus, device, func), | ||
| 669 | where, size, value); | ||
| 670 | #if 0 | ||
| 671 | printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n", | ||
| 672 | devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), | ||
| 673 | where, size, value, ret); | ||
| 674 | #endif | ||
| 675 | } | ||
| 676 | return PCIBIOS_SUCCESSFUL; | ||
| 677 | } | ||
| 678 | |||
| 679 | static struct pci_ops pci_sun4v_ops = { | ||
| 680 | .read = pci_sun4v_read_pci_cfg, | ||
| 681 | .write = pci_sun4v_write_pci_cfg, | ||
| 682 | }; | ||
| 683 | |||
| 684 | |||
| 685 | static void pbm_scan_bus(struct pci_controller_info *p, | ||
| 686 | struct pci_pbm_info *pbm) | ||
| 687 | { | ||
| 688 | struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); | ||
| 689 | |||
| 690 | if (!cookie) { | ||
| 691 | prom_printf("%s: Critical allocation failure.\n", pbm->name); | ||
| 692 | prom_halt(); | ||
| 693 | } | ||
| 694 | |||
| 695 | /* All we care about is the PBM. */ | ||
| 696 | memset(cookie, 0, sizeof(*cookie)); | ||
| 697 | cookie->pbm = pbm; | ||
| 698 | |||
| 699 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); | ||
| 700 | #if 0 | ||
| 701 | pci_fixup_host_bridge_self(pbm->pci_bus); | ||
| 702 | pbm->pci_bus->self->sysdata = cookie; | ||
| 703 | #endif | ||
| 704 | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, | ||
| 705 | pbm->prom_node); | ||
| 706 | pci_record_assignments(pbm, pbm->pci_bus); | ||
| 707 | pci_assign_unassigned(pbm, pbm->pci_bus); | ||
| 708 | pci_fixup_irq(pbm, pbm->pci_bus); | ||
| 709 | pci_determine_66mhz_disposition(pbm, pbm->pci_bus); | ||
| 710 | pci_setup_busmastering(pbm, pbm->pci_bus); | ||
| 711 | } | ||
| 712 | |||
| 713 | static void pci_sun4v_scan_bus(struct pci_controller_info *p) | ||
| 714 | { | ||
| 715 | if (p->pbm_A.prom_node) { | ||
| 716 | p->pbm_A.is_66mhz_capable = | ||
| 717 | prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); | ||
| 718 | |||
| 719 | pbm_scan_bus(p, &p->pbm_A); | ||
| 720 | } | ||
| 721 | if (p->pbm_B.prom_node) { | ||
| 722 | p->pbm_B.is_66mhz_capable = | ||
| 723 | prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); | ||
| 724 | |||
| 725 | pbm_scan_bus(p, &p->pbm_B); | ||
| 726 | } | ||
| 727 | |||
| 728 | /* XXX register error interrupt handlers XXX */ | ||
| 729 | } | ||
| 730 | |||
| 731 | static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, | ||
| 732 | struct pci_dev *pdev, | ||
| 733 | unsigned int devino) | ||
| 734 | { | ||
| 735 | u32 devhandle = pbm->devhandle; | ||
| 736 | int pil; | ||
| 737 | |||
| 738 | pil = 5; | ||
| 739 | if (pdev) { | ||
| 740 | switch ((pdev->class >> 16) & 0xff) { | ||
| 741 | case PCI_BASE_CLASS_STORAGE: | ||
| 742 | pil = 5; | ||
| 743 | break; | ||
| 744 | |||
| 745 | case PCI_BASE_CLASS_NETWORK: | ||
| 746 | pil = 6; | ||
| 747 | break; | ||
| 748 | |||
| 749 | case PCI_BASE_CLASS_DISPLAY: | ||
| 750 | pil = 9; | ||
| 751 | break; | ||
| 752 | |||
| 753 | case PCI_BASE_CLASS_MULTIMEDIA: | ||
| 754 | case PCI_BASE_CLASS_MEMORY: | ||
| 755 | case PCI_BASE_CLASS_BRIDGE: | ||
| 756 | case PCI_BASE_CLASS_SERIAL: | ||
| 757 | pil = 10; | ||
| 758 | break; | ||
| 759 | |||
| 760 | default: | ||
| 761 | pil = 5; | ||
| 762 | break; | ||
| 763 | }; | ||
| 764 | } | ||
| 765 | BUG_ON(PIL_RESERVED(pil)); | ||
| 766 | |||
| 767 | return sun4v_build_irq(devhandle, devino, pil, IBF_PCI); | ||
| 768 | } | ||
| 769 | |||
| 770 | static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) | ||
| 771 | { | ||
| 772 | struct pcidev_cookie *pcp = pdev->sysdata; | ||
| 773 | struct pci_pbm_info *pbm = pcp->pbm; | ||
| 774 | struct resource *res, *root; | ||
| 775 | u32 reg; | ||
| 776 | int where, size, is_64bit; | ||
| 777 | |||
| 778 | res = &pdev->resource[resource]; | ||
| 779 | if (resource < 6) { | ||
| 780 | where = PCI_BASE_ADDRESS_0 + (resource * 4); | ||
| 781 | } else if (resource == PCI_ROM_RESOURCE) { | ||
| 782 | where = pdev->rom_base_reg; | ||
| 783 | } else { | ||
| 784 | /* Somebody might have asked allocation of a non-standard resource */ | ||
| 785 | return; | ||
| 786 | } | ||
| 787 | |||
| 788 | /* XXX 64-bit MEM handling is not %100 correct... XXX */ | ||
| 789 | is_64bit = 0; | ||
| 790 | if (res->flags & IORESOURCE_IO) | ||
| 791 | root = &pbm->io_space; | ||
| 792 | else { | ||
| 793 | root = &pbm->mem_space; | ||
| 794 | if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) | ||
| 795 | == PCI_BASE_ADDRESS_MEM_TYPE_64) | ||
| 796 | is_64bit = 1; | ||
| 797 | } | ||
| 798 | |||
| 799 | size = res->end - res->start; | ||
| 800 | pci_read_config_dword(pdev, where, ®); | ||
| 801 | reg = ((reg & size) | | ||
| 802 | (((u32)(res->start - root->start)) & ~size)); | ||
| 803 | if (resource == PCI_ROM_RESOURCE) { | ||
| 804 | reg |= PCI_ROM_ADDRESS_ENABLE; | ||
| 805 | res->flags |= IORESOURCE_ROM_ENABLE; | ||
| 806 | } | ||
| 807 | pci_write_config_dword(pdev, where, reg); | ||
| 808 | |||
| 809 | /* This knows that the upper 32-bits of the address | ||
| 810 | * must be zero. Our PCI common layer enforces this. | ||
| 811 | */ | ||
| 812 | if (is_64bit) | ||
| 813 | pci_write_config_dword(pdev, where + 4, 0); | ||
| 814 | } | ||
| 815 | |||
| 816 | static void pci_sun4v_resource_adjust(struct pci_dev *pdev, | ||
| 817 | struct resource *res, | ||
| 818 | struct resource *root) | ||
| 819 | { | ||
| 820 | res->start += root->start; | ||
| 821 | res->end += root->start; | ||
| 822 | } | ||
| 823 | |||
| 824 | /* Use ranges property to determine where PCI MEM, I/O, and Config | ||
| 825 | * space are for this PCI bus module. | ||
| 826 | */ | ||
| 827 | static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm) | ||
| 828 | { | ||
| 829 | int i, saw_mem, saw_io; | ||
| 830 | |||
| 831 | saw_mem = saw_io = 0; | ||
| 832 | for (i = 0; i < pbm->num_pbm_ranges; i++) { | ||
| 833 | struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; | ||
| 834 | unsigned long a; | ||
| 835 | int type; | ||
| 836 | |||
| 837 | type = (pr->child_phys_hi >> 24) & 0x3; | ||
| 838 | a = (((unsigned long)pr->parent_phys_hi << 32UL) | | ||
| 839 | ((unsigned long)pr->parent_phys_lo << 0UL)); | ||
| 840 | |||
| 841 | switch (type) { | ||
| 842 | case 1: | ||
| 843 | /* 16-bit IO space, 16MB */ | ||
| 844 | pbm->io_space.start = a; | ||
| 845 | pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); | ||
| 846 | pbm->io_space.flags = IORESOURCE_IO; | ||
| 847 | saw_io = 1; | ||
| 848 | break; | ||
| 849 | |||
| 850 | case 2: | ||
| 851 | /* 32-bit MEM space, 2GB */ | ||
| 852 | pbm->mem_space.start = a; | ||
| 853 | pbm->mem_space.end = a + (0x80000000UL - 1UL); | ||
| 854 | pbm->mem_space.flags = IORESOURCE_MEM; | ||
| 855 | saw_mem = 1; | ||
| 856 | break; | ||
| 857 | |||
| 858 | case 3: | ||
| 859 | /* XXX 64-bit MEM handling XXX */ | ||
| 860 | |||
| 861 | default: | ||
| 862 | break; | ||
| 863 | }; | ||
| 864 | } | ||
| 865 | |||
| 866 | if (!saw_io || !saw_mem) { | ||
| 867 | prom_printf("%s: Fatal error, missing %s PBM range.\n", | ||
| 868 | pbm->name, | ||
| 869 | (!saw_io ? "IO" : "MEM")); | ||
| 870 | prom_halt(); | ||
| 871 | } | ||
| 872 | |||
| 873 | printk("%s: PCI IO[%lx] MEM[%lx]\n", | ||
| 874 | pbm->name, | ||
| 875 | pbm->io_space.start, | ||
| 876 | pbm->mem_space.start); | ||
| 877 | } | ||
| 878 | |||
| 879 | static void pbm_register_toplevel_resources(struct pci_controller_info *p, | ||
| 880 | struct pci_pbm_info *pbm) | ||
| 881 | { | ||
| 882 | pbm->io_space.name = pbm->mem_space.name = pbm->name; | ||
| 883 | |||
| 884 | request_resource(&ioport_resource, &pbm->io_space); | ||
| 885 | request_resource(&iomem_resource, &pbm->mem_space); | ||
| 886 | pci_register_legacy_regions(&pbm->io_space, | ||
| 887 | &pbm->mem_space); | ||
| 888 | } | ||
| 889 | |||
| 890 | static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, | ||
| 891 | struct pci_iommu *iommu) | ||
| 892 | { | ||
| 893 | struct pci_iommu_arena *arena = &iommu->arena; | ||
| 894 | unsigned long i, cnt = 0; | ||
| 895 | u32 devhandle; | ||
| 896 | |||
| 897 | devhandle = pbm->devhandle; | ||
| 898 | for (i = 0; i < arena->limit; i++) { | ||
| 899 | unsigned long ret, io_attrs, ra; | ||
| 900 | |||
| 901 | ret = pci_sun4v_iommu_getmap(devhandle, | ||
| 902 | HV_PCI_TSBID(0, i), | ||
| 903 | &io_attrs, &ra); | ||
| 904 | if (ret == HV_EOK) { | ||
| 905 | cnt++; | ||
| 906 | __set_bit(i, arena->map); | ||
| 907 | } | ||
| 908 | } | ||
| 909 | |||
| 910 | return cnt; | ||
| 911 | } | ||
| 912 | |||
| 913 | static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | ||
| 914 | { | ||
| 915 | struct pci_iommu *iommu = pbm->iommu; | ||
| 916 | unsigned long num_tsb_entries, sz; | ||
| 917 | u32 vdma[2], dma_mask, dma_offset; | ||
| 918 | int err, tsbsize; | ||
| 919 | |||
| 920 | err = prom_getproperty(pbm->prom_node, "virtual-dma", | ||
| 921 | (char *)&vdma[0], sizeof(vdma)); | ||
| 922 | if (err == 0 || err == -1) { | ||
| 923 | /* No property, use default values. */ | ||
| 924 | vdma[0] = 0x80000000; | ||
| 925 | vdma[1] = 0x80000000; | ||
| 926 | } | ||
| 927 | |||
| 928 | dma_mask = vdma[0]; | ||
| 929 | switch (vdma[1]) { | ||
| 930 | case 0x20000000: | ||
| 931 | dma_mask |= 0x1fffffff; | ||
| 932 | tsbsize = 64; | ||
| 933 | break; | ||
| 934 | |||
| 935 | case 0x40000000: | ||
| 936 | dma_mask |= 0x3fffffff; | ||
| 937 | tsbsize = 128; | ||
| 938 | break; | ||
| 939 | |||
| 940 | case 0x80000000: | ||
| 941 | dma_mask |= 0x7fffffff; | ||
| 942 | tsbsize = 256; | ||
| 943 | break; | ||
| 944 | |||
| 945 | default: | ||
| 946 | prom_printf("PCI-SUN4V: strange virtual-dma size.\n"); | ||
| 947 | prom_halt(); | ||
| 948 | }; | ||
| 949 | |||
| 950 | tsbsize *= (8 * 1024); | ||
| 951 | |||
| 952 | num_tsb_entries = tsbsize / sizeof(iopte_t); | ||
| 953 | |||
| 954 | dma_offset = vdma[0]; | ||
| 955 | |||
| 956 | /* Setup initial software IOMMU state. */ | ||
| 957 | spin_lock_init(&iommu->lock); | ||
| 958 | iommu->ctx_lowest_free = 1; | ||
| 959 | iommu->page_table_map_base = dma_offset; | ||
| 960 | iommu->dma_addr_mask = dma_mask; | ||
| 961 | |||
| 962 | /* Allocate and initialize the free area map. */ | ||
| 963 | sz = num_tsb_entries / 8; | ||
| 964 | sz = (sz + 7UL) & ~7UL; | ||
| 965 | iommu->arena.map = kmalloc(sz, GFP_KERNEL); | ||
| 966 | if (!iommu->arena.map) { | ||
| 967 | prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); | ||
| 968 | prom_halt(); | ||
| 969 | } | ||
| 970 | memset(iommu->arena.map, 0, sz); | ||
| 971 | iommu->arena.limit = num_tsb_entries; | ||
| 972 | |||
| 973 | sz = probe_existing_entries(pbm, iommu); | ||
| 974 | |||
| 975 | printk("%s: TSB entries [%lu], existing mapings [%lu]\n", | ||
| 976 | pbm->name, num_tsb_entries, sz); | ||
| 977 | } | ||
| 978 | |||
| 979 | static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) | ||
| 980 | { | ||
| 981 | unsigned int busrange[2]; | ||
| 982 | int prom_node = pbm->prom_node; | ||
| 983 | int err; | ||
| 984 | |||
| 985 | err = prom_getproperty(prom_node, "bus-range", | ||
| 986 | (char *)&busrange[0], | ||
| 987 | sizeof(busrange)); | ||
| 988 | if (err == 0 || err == -1) { | ||
| 989 | prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); | ||
| 990 | prom_halt(); | ||
| 991 | } | ||
| 992 | |||
| 993 | pbm->pci_first_busno = busrange[0]; | ||
| 994 | pbm->pci_last_busno = busrange[1]; | ||
| 995 | |||
| 996 | } | ||
| 997 | |||
| 998 | static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle) | ||
| 999 | { | ||
| 1000 | struct pci_pbm_info *pbm; | ||
| 1001 | int err, i; | ||
| 1002 | |||
| 1003 | if (devhandle & 0x40) | ||
| 1004 | pbm = &p->pbm_B; | ||
| 1005 | else | ||
| 1006 | pbm = &p->pbm_A; | ||
| 1007 | |||
| 1008 | pbm->parent = p; | ||
| 1009 | pbm->prom_node = prom_node; | ||
| 1010 | pbm->pci_first_slot = 1; | ||
| 1011 | |||
| 1012 | pbm->devhandle = devhandle; | ||
| 1013 | |||
| 1014 | sprintf(pbm->name, "SUN4V-PCI%d PBM%c", | ||
| 1015 | p->index, (pbm == &p->pbm_A ? 'A' : 'B')); | ||
| 1016 | |||
| 1017 | printk("%s: devhandle[%x] prom_node[%x:%x]\n", | ||
| 1018 | pbm->name, pbm->devhandle, | ||
| 1019 | pbm->prom_node, prom_getchild(pbm->prom_node)); | ||
| 1020 | |||
| 1021 | prom_getstring(prom_node, "name", | ||
| 1022 | pbm->prom_name, sizeof(pbm->prom_name)); | ||
| 1023 | |||
| 1024 | err = prom_getproperty(prom_node, "ranges", | ||
| 1025 | (char *) pbm->pbm_ranges, | ||
| 1026 | sizeof(pbm->pbm_ranges)); | ||
| 1027 | if (err == 0 || err == -1) { | ||
| 1028 | prom_printf("%s: Fatal error, no ranges property.\n", | ||
| 1029 | pbm->name); | ||
| 1030 | prom_halt(); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | pbm->num_pbm_ranges = | ||
| 1034 | (err / sizeof(struct linux_prom_pci_ranges)); | ||
| 1035 | |||
| 1036 | /* Mask out the top 8 bits of the ranges, leaving the real | ||
| 1037 | * physical address. | ||
| 1038 | */ | ||
| 1039 | for (i = 0; i < pbm->num_pbm_ranges; i++) | ||
| 1040 | pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff; | ||
| 1041 | |||
| 1042 | pci_sun4v_determine_mem_io_space(pbm); | ||
| 1043 | pbm_register_toplevel_resources(p, pbm); | ||
| 1044 | |||
| 1045 | err = prom_getproperty(prom_node, "interrupt-map", | ||
| 1046 | (char *)pbm->pbm_intmap, | ||
| 1047 | sizeof(pbm->pbm_intmap)); | ||
| 1048 | if (err == 0 || err == -1) { | ||
| 1049 | prom_printf("%s: Fatal error, no interrupt-map property.\n", | ||
| 1050 | pbm->name); | ||
| 1051 | prom_halt(); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); | ||
| 1055 | err = prom_getproperty(prom_node, "interrupt-map-mask", | ||
| 1056 | (char *)&pbm->pbm_intmask, | ||
| 1057 | sizeof(pbm->pbm_intmask)); | ||
| 1058 | if (err == 0 || err == -1) { | ||
| 1059 | prom_printf("%s: Fatal error, no interrupt-map-mask.\n", | ||
| 1060 | pbm->name); | ||
| 1061 | prom_halt(); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | pci_sun4v_get_bus_range(pbm); | ||
| 1065 | pci_sun4v_iommu_init(pbm); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | void sun4v_pci_init(int node, char *model_name) | ||
| 1069 | { | ||
| 1070 | struct pci_controller_info *p; | ||
| 1071 | struct pci_iommu *iommu; | ||
| 1072 | struct linux_prom64_registers regs; | ||
| 1073 | u32 devhandle; | ||
| 1074 | int i; | ||
| 1075 | |||
| 1076 | prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); | ||
| 1077 | devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; | ||
| 1078 | |||
| 1079 | for (p = pci_controller_root; p; p = p->next) { | ||
| 1080 | struct pci_pbm_info *pbm; | ||
| 1081 | |||
| 1082 | if (p->pbm_A.prom_node && p->pbm_B.prom_node) | ||
| 1083 | continue; | ||
| 1084 | |||
| 1085 | pbm = (p->pbm_A.prom_node ? | ||
| 1086 | &p->pbm_A : | ||
| 1087 | &p->pbm_B); | ||
| 1088 | |||
| 1089 | if (pbm->devhandle == (devhandle ^ 0x40)) { | ||
| 1090 | pci_sun4v_pbm_init(p, node, devhandle); | ||
| 1091 | return; | ||
| 1092 | } | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | for_each_cpu(i) { | ||
| 1096 | unsigned long page = get_zeroed_page(GFP_ATOMIC); | ||
| 1097 | |||
| 1098 | if (!page) | ||
| 1099 | goto fatal_memory_error; | ||
| 1100 | |||
| 1101 | per_cpu(pci_iommu_batch, i).pglist = (u64 *) page; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | ||
| 1105 | if (!p) | ||
| 1106 | goto fatal_memory_error; | ||
| 1107 | |||
| 1108 | memset(p, 0, sizeof(*p)); | ||
| 1109 | |||
| 1110 | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | ||
| 1111 | if (!iommu) | ||
| 1112 | goto fatal_memory_error; | ||
| 1113 | |||
| 1114 | memset(iommu, 0, sizeof(*iommu)); | ||
| 1115 | p->pbm_A.iommu = iommu; | ||
| 1116 | |||
| 1117 | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | ||
| 1118 | if (!iommu) | ||
| 1119 | goto fatal_memory_error; | ||
| 1120 | |||
| 1121 | memset(iommu, 0, sizeof(*iommu)); | ||
| 1122 | p->pbm_B.iommu = iommu; | ||
| 1123 | |||
| 1124 | p->next = pci_controller_root; | ||
| 1125 | pci_controller_root = p; | ||
| 1126 | |||
| 1127 | p->index = pci_num_controllers++; | ||
| 1128 | p->pbms_same_domain = 0; | ||
| 1129 | |||
| 1130 | p->scan_bus = pci_sun4v_scan_bus; | ||
| 1131 | p->irq_build = pci_sun4v_irq_build; | ||
| 1132 | p->base_address_update = pci_sun4v_base_address_update; | ||
| 1133 | p->resource_adjust = pci_sun4v_resource_adjust; | ||
| 1134 | p->pci_ops = &pci_sun4v_ops; | ||
| 1135 | |||
| 1136 | /* Like PSYCHO and SCHIZO we have a 2GB aligned area | ||
| 1137 | * for memory space. | ||
| 1138 | */ | ||
| 1139 | pci_memspace_mask = 0x7fffffffUL; | ||
| 1140 | |||
| 1141 | pci_sun4v_pbm_init(p, node, devhandle); | ||
| 1142 | return; | ||
| 1143 | |||
| 1144 | fatal_memory_error: | ||
| 1145 | prom_printf("SUN4V_PCI: Fatal memory allocation error.\n"); | ||
| 1146 | prom_halt(); | ||
| 1147 | } | ||
diff --git a/arch/sparc64/kernel/pci_sun4v.h b/arch/sparc64/kernel/pci_sun4v.h new file mode 100644 index 000000000000..884d25f6158d --- /dev/null +++ b/arch/sparc64/kernel/pci_sun4v.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* pci_sun4v.h: SUN4V specific PCI controller support. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _PCI_SUN4V_H | ||
| 7 | #define _PCI_SUN4V_H | ||
| 8 | |||
| 9 | extern long pci_sun4v_iommu_map(unsigned long devhandle, | ||
| 10 | unsigned long tsbid, | ||
| 11 | unsigned long num_ttes, | ||
| 12 | unsigned long io_attributes, | ||
| 13 | unsigned long io_page_list_pa); | ||
| 14 | extern unsigned long pci_sun4v_iommu_demap(unsigned long devhandle, | ||
| 15 | unsigned long tsbid, | ||
| 16 | unsigned long num_ttes); | ||
| 17 | extern unsigned long pci_sun4v_iommu_getmap(unsigned long devhandle, | ||
| 18 | unsigned long tsbid, | ||
| 19 | unsigned long *io_attributes, | ||
| 20 | unsigned long *real_address); | ||
| 21 | extern unsigned long pci_sun4v_config_get(unsigned long devhandle, | ||
| 22 | unsigned long pci_device, | ||
| 23 | unsigned long config_offset, | ||
| 24 | unsigned long size); | ||
| 25 | extern int pci_sun4v_config_put(unsigned long devhandle, | ||
| 26 | unsigned long pci_device, | ||
| 27 | unsigned long config_offset, | ||
| 28 | unsigned long size, | ||
| 29 | unsigned long data); | ||
| 30 | |||
| 31 | #endif /* !(_PCI_SUN4V_H) */ | ||
diff --git a/arch/sparc64/kernel/pci_sun4v_asm.S b/arch/sparc64/kernel/pci_sun4v_asm.S new file mode 100644 index 000000000000..6604fdbf746c --- /dev/null +++ b/arch/sparc64/kernel/pci_sun4v_asm.S | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* pci_sun4v_asm: Hypervisor calls for PCI support. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <asm/hypervisor.h> | ||
| 7 | |||
| 8 | /* %o0: devhandle | ||
| 9 | * %o1: tsbid | ||
| 10 | * %o2: num ttes | ||
| 11 | * %o3: io_attributes | ||
| 12 | * %o4: io_page_list phys address | ||
| 13 | * | ||
| 14 | * returns %o0: -status if status was non-zero, else | ||
| 15 | * %o0: num pages mapped | ||
| 16 | */ | ||
| 17 | .globl pci_sun4v_iommu_map | ||
| 18 | pci_sun4v_iommu_map: | ||
| 19 | mov %o5, %g1 | ||
| 20 | mov HV_FAST_PCI_IOMMU_MAP, %o5 | ||
| 21 | ta HV_FAST_TRAP | ||
| 22 | brnz,pn %o0, 1f | ||
| 23 | sub %g0, %o0, %o0 | ||
| 24 | mov %o1, %o0 | ||
| 25 | 1: retl | ||
| 26 | nop | ||
| 27 | |||
| 28 | /* %o0: devhandle | ||
| 29 | * %o1: tsbid | ||
| 30 | * %o2: num ttes | ||
| 31 | * | ||
| 32 | * returns %o0: num ttes demapped | ||
| 33 | */ | ||
| 34 | .globl pci_sun4v_iommu_demap | ||
| 35 | pci_sun4v_iommu_demap: | ||
| 36 | mov HV_FAST_PCI_IOMMU_DEMAP, %o5 | ||
| 37 | ta HV_FAST_TRAP | ||
| 38 | retl | ||
| 39 | mov %o1, %o0 | ||
| 40 | |||
| 41 | /* %o0: devhandle | ||
| 42 | * %o1: tsbid | ||
| 43 | * %o2: &io_attributes | ||
| 44 | * %o3: &real_address | ||
| 45 | * | ||
| 46 | * returns %o0: status | ||
| 47 | */ | ||
| 48 | .globl pci_sun4v_iommu_getmap | ||
| 49 | pci_sun4v_iommu_getmap: | ||
| 50 | mov %o2, %o4 | ||
| 51 | mov HV_FAST_PCI_IOMMU_GETMAP, %o5 | ||
| 52 | ta HV_FAST_TRAP | ||
| 53 | stx %o1, [%o4] | ||
| 54 | stx %o2, [%o3] | ||
| 55 | retl | ||
| 56 | mov %o0, %o0 | ||
| 57 | |||
| 58 | /* %o0: devhandle | ||
| 59 | * %o1: pci_device | ||
| 60 | * %o2: pci_config_offset | ||
| 61 | * %o3: size | ||
| 62 | * | ||
| 63 | * returns %o0: data | ||
| 64 | * | ||
| 65 | * If there is an error, the data will be returned | ||
| 66 | * as all 1's. | ||
| 67 | */ | ||
| 68 | .globl pci_sun4v_config_get | ||
| 69 | pci_sun4v_config_get: | ||
| 70 | mov HV_FAST_PCI_CONFIG_GET, %o5 | ||
| 71 | ta HV_FAST_TRAP | ||
| 72 | brnz,a,pn %o1, 1f | ||
| 73 | mov -1, %o2 | ||
| 74 | 1: retl | ||
| 75 | mov %o2, %o0 | ||
| 76 | |||
| 77 | /* %o0: devhandle | ||
| 78 | * %o1: pci_device | ||
| 79 | * %o2: pci_config_offset | ||
| 80 | * %o3: size | ||
| 81 | * %o4: data | ||
| 82 | * | ||
| 83 | * returns %o0: status | ||
| 84 | * | ||
| 85 | * status will be zero if the operation completed | ||
| 86 | * successfully, else -1 if not | ||
| 87 | */ | ||
| 88 | .globl pci_sun4v_config_put | ||
| 89 | pci_sun4v_config_put: | ||
| 90 | mov HV_FAST_PCI_CONFIG_PUT, %o5 | ||
| 91 | ta HV_FAST_TRAP | ||
| 92 | brnz,a,pn %o1, 1f | ||
| 93 | mov -1, %o1 | ||
| 94 | 1: retl | ||
| 95 | mov %o1, %o0 | ||
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 059b0d025224..1c7ca2f712d9 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
| @@ -44,83 +44,61 @@ | |||
| 44 | #include <asm/fpumacro.h> | 44 | #include <asm/fpumacro.h> |
| 45 | #include <asm/head.h> | 45 | #include <asm/head.h> |
| 46 | #include <asm/cpudata.h> | 46 | #include <asm/cpudata.h> |
| 47 | #include <asm/mmu_context.h> | ||
| 47 | #include <asm/unistd.h> | 48 | #include <asm/unistd.h> |
| 49 | #include <asm/hypervisor.h> | ||
| 48 | 50 | ||
| 49 | /* #define VERBOSE_SHOWREGS */ | 51 | /* #define VERBOSE_SHOWREGS */ |
| 50 | 52 | ||
| 51 | /* | 53 | static void sparc64_yield(void) |
| 52 | * Nothing special yet... | ||
| 53 | */ | ||
| 54 | void default_idle(void) | ||
| 55 | { | ||
| 56 | } | ||
| 57 | |||
| 58 | #ifndef CONFIG_SMP | ||
| 59 | |||
| 60 | /* | ||
| 61 | * the idle loop on a Sparc... ;) | ||
| 62 | */ | ||
| 63 | void cpu_idle(void) | ||
| 64 | { | 54 | { |
| 65 | /* endless idle loop with no priority at all */ | 55 | if (tlb_type != hypervisor) |
| 66 | for (;;) { | 56 | return; |
| 67 | /* If current->work.need_resched is zero we should really | ||
| 68 | * setup for a system wakup event and execute a shutdown | ||
| 69 | * instruction. | ||
| 70 | * | ||
| 71 | * But this requires writing back the contents of the | ||
| 72 | * L2 cache etc. so implement this later. -DaveM | ||
| 73 | */ | ||
| 74 | while (!need_resched()) | ||
| 75 | barrier(); | ||
| 76 | 57 | ||
| 77 | preempt_enable_no_resched(); | 58 | clear_thread_flag(TIF_POLLING_NRFLAG); |
| 78 | schedule(); | 59 | smp_mb__after_clear_bit(); |
| 79 | preempt_disable(); | 60 | |
| 80 | check_pgt_cache(); | 61 | while (!need_resched()) { |
| 62 | unsigned long pstate; | ||
| 63 | |||
| 64 | /* Disable interrupts. */ | ||
| 65 | __asm__ __volatile__( | ||
| 66 | "rdpr %%pstate, %0\n\t" | ||
| 67 | "andn %0, %1, %0\n\t" | ||
| 68 | "wrpr %0, %%g0, %%pstate" | ||
| 69 | : "=&r" (pstate) | ||
| 70 | : "i" (PSTATE_IE)); | ||
| 71 | |||
| 72 | if (!need_resched()) | ||
| 73 | sun4v_cpu_yield(); | ||
| 74 | |||
| 75 | /* Re-enable interrupts. */ | ||
| 76 | __asm__ __volatile__( | ||
| 77 | "rdpr %%pstate, %0\n\t" | ||
| 78 | "or %0, %1, %0\n\t" | ||
| 79 | "wrpr %0, %%g0, %%pstate" | ||
| 80 | : "=&r" (pstate) | ||
| 81 | : "i" (PSTATE_IE)); | ||
| 81 | } | 82 | } |
| 82 | } | ||
| 83 | 83 | ||
| 84 | #else | 84 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 85 | } | ||
| 85 | 86 | ||
| 86 | /* | 87 | /* The idle loop on sparc64. */ |
| 87 | * the idle loop on a UltraMultiPenguin... | ||
| 88 | * | ||
| 89 | * TIF_POLLING_NRFLAG is set because we do not sleep the cpu | ||
| 90 | * inside of the idler task, so an interrupt is not needed | ||
| 91 | * to get a clean fast response. | ||
| 92 | * | ||
| 93 | * XXX Reverify this assumption... -DaveM | ||
| 94 | * | ||
| 95 | * Addendum: We do want it to do something for the signal | ||
| 96 | * delivery case, we detect that by just seeing | ||
| 97 | * if we are trying to send this to an idler or not. | ||
| 98 | */ | ||
| 99 | void cpu_idle(void) | 88 | void cpu_idle(void) |
| 100 | { | 89 | { |
| 101 | cpuinfo_sparc *cpuinfo = &local_cpu_data(); | ||
| 102 | set_thread_flag(TIF_POLLING_NRFLAG); | 90 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 103 | 91 | ||
| 104 | while(1) { | 92 | while(1) { |
| 105 | if (need_resched()) { | 93 | if (need_resched()) { |
| 106 | cpuinfo->idle_volume = 0; | ||
| 107 | preempt_enable_no_resched(); | 94 | preempt_enable_no_resched(); |
| 108 | schedule(); | 95 | schedule(); |
| 109 | preempt_disable(); | 96 | preempt_disable(); |
| 110 | check_pgt_cache(); | ||
| 111 | } | 97 | } |
| 112 | cpuinfo->idle_volume++; | 98 | sparc64_yield(); |
| 113 | |||
| 114 | /* The store ordering is so that IRQ handlers on | ||
| 115 | * other cpus see our increasing idleness for the buddy | ||
| 116 | * redistribution algorithm. -DaveM | ||
| 117 | */ | ||
| 118 | membar_storeload_storestore(); | ||
| 119 | } | 99 | } |
| 120 | } | 100 | } |
| 121 | 101 | ||
| 122 | #endif | ||
| 123 | |||
| 124 | extern char reboot_command []; | 102 | extern char reboot_command []; |
| 125 | 103 | ||
| 126 | extern void (*prom_palette)(int); | 104 | extern void (*prom_palette)(int); |
| @@ -354,6 +332,7 @@ void show_regs(struct pt_regs *regs) | |||
| 354 | extern long etrap, etraptl1; | 332 | extern long etrap, etraptl1; |
| 355 | #endif | 333 | #endif |
| 356 | __show_regs(regs); | 334 | __show_regs(regs); |
| 335 | #if 0 | ||
| 357 | #ifdef CONFIG_SMP | 336 | #ifdef CONFIG_SMP |
| 358 | { | 337 | { |
| 359 | extern void smp_report_regs(void); | 338 | extern void smp_report_regs(void); |
| @@ -361,6 +340,7 @@ void show_regs(struct pt_regs *regs) | |||
| 361 | smp_report_regs(); | 340 | smp_report_regs(); |
| 362 | } | 341 | } |
| 363 | #endif | 342 | #endif |
| 343 | #endif | ||
| 364 | 344 | ||
| 365 | #ifdef VERBOSE_SHOWREGS | 345 | #ifdef VERBOSE_SHOWREGS |
| 366 | if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && | 346 | if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && |
| @@ -433,30 +413,15 @@ void exit_thread(void) | |||
| 433 | void flush_thread(void) | 413 | void flush_thread(void) |
| 434 | { | 414 | { |
| 435 | struct thread_info *t = current_thread_info(); | 415 | struct thread_info *t = current_thread_info(); |
| 416 | struct mm_struct *mm; | ||
| 436 | 417 | ||
| 437 | if (t->flags & _TIF_ABI_PENDING) | 418 | if (t->flags & _TIF_ABI_PENDING) |
| 438 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); | 419 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); |
| 439 | 420 | ||
| 440 | if (t->task->mm) { | 421 | mm = t->task->mm; |
| 441 | unsigned long pgd_cache = 0UL; | 422 | if (mm) |
| 442 | if (test_thread_flag(TIF_32BIT)) { | 423 | tsb_context_switch(mm); |
| 443 | struct mm_struct *mm = t->task->mm; | ||
| 444 | pgd_t *pgd0 = &mm->pgd[0]; | ||
| 445 | pud_t *pud0 = pud_offset(pgd0, 0); | ||
| 446 | 424 | ||
| 447 | if (pud_none(*pud0)) { | ||
| 448 | pmd_t *page = pmd_alloc_one(mm, 0); | ||
| 449 | pud_set(pud0, page); | ||
| 450 | } | ||
| 451 | pgd_cache = get_pgd_cache(pgd0); | ||
| 452 | } | ||
| 453 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 454 | "membar #Sync" | ||
| 455 | : /* no outputs */ | ||
| 456 | : "r" (pgd_cache), | ||
| 457 | "r" (TSB_REG), | ||
| 458 | "i" (ASI_DMMU)); | ||
| 459 | } | ||
| 460 | set_thread_wsaved(0); | 425 | set_thread_wsaved(0); |
| 461 | 426 | ||
| 462 | /* Turn off performance counters if on. */ | 427 | /* Turn off performance counters if on. */ |
| @@ -555,6 +520,18 @@ void synchronize_user_stack(void) | |||
| 555 | } | 520 | } |
| 556 | } | 521 | } |
| 557 | 522 | ||
| 523 | static void stack_unaligned(unsigned long sp) | ||
| 524 | { | ||
| 525 | siginfo_t info; | ||
| 526 | |||
| 527 | info.si_signo = SIGBUS; | ||
| 528 | info.si_errno = 0; | ||
| 529 | info.si_code = BUS_ADRALN; | ||
| 530 | info.si_addr = (void __user *) sp; | ||
| 531 | info.si_trapno = 0; | ||
| 532 | force_sig_info(SIGBUS, &info, current); | ||
| 533 | } | ||
| 534 | |||
| 558 | void fault_in_user_windows(void) | 535 | void fault_in_user_windows(void) |
| 559 | { | 536 | { |
| 560 | struct thread_info *t = current_thread_info(); | 537 | struct thread_info *t = current_thread_info(); |
| @@ -570,13 +547,17 @@ void fault_in_user_windows(void) | |||
| 570 | flush_user_windows(); | 547 | flush_user_windows(); |
| 571 | window = get_thread_wsaved(); | 548 | window = get_thread_wsaved(); |
| 572 | 549 | ||
| 573 | if (window != 0) { | 550 | if (likely(window != 0)) { |
| 574 | window -= 1; | 551 | window -= 1; |
| 575 | do { | 552 | do { |
| 576 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); | 553 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); |
| 577 | struct reg_window *rwin = &t->reg_window[window]; | 554 | struct reg_window *rwin = &t->reg_window[window]; |
| 578 | 555 | ||
| 579 | if (copy_to_user((char __user *)sp, rwin, winsize)) | 556 | if (unlikely(sp & 0x7UL)) |
| 557 | stack_unaligned(sp); | ||
| 558 | |||
| 559 | if (unlikely(copy_to_user((char __user *)sp, | ||
| 560 | rwin, winsize))) | ||
| 580 | goto barf; | 561 | goto barf; |
| 581 | } while (window--); | 562 | } while (window--); |
| 582 | } | 563 | } |
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 3f9746f856d2..eb93e9c52846 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c | |||
| @@ -124,6 +124,9 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, | |||
| 124 | { | 124 | { |
| 125 | BUG_ON(len > PAGE_SIZE); | 125 | BUG_ON(len > PAGE_SIZE); |
| 126 | 126 | ||
| 127 | if (tlb_type == hypervisor) | ||
| 128 | return; | ||
| 129 | |||
| 127 | #ifdef DCACHE_ALIASING_POSSIBLE | 130 | #ifdef DCACHE_ALIASING_POSSIBLE |
| 128 | /* If bit 13 of the kernel address we used to access the | 131 | /* If bit 13 of the kernel address we used to access the |
| 129 | * user page is the same as the virtual address that page | 132 | * user page is the same as the virtual address that page |
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index b80eba0081ca..7130e866f935 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S | |||
| @@ -223,12 +223,26 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 | |||
| 223 | ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 | 223 | ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 |
| 224 | ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4 | 224 | ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4 |
| 225 | ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5 | 225 | ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5 |
| 226 | mov TSB_REG, %g6 | 226 | brz,pt %l3, 1f |
| 227 | brnz,a,pn %l3, 1f | 227 | mov %g6, %l2 |
| 228 | ldxa [%g6] ASI_IMMU, %g5 | 228 | |
| 229 | 1: ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6 | 229 | /* Must do this before thread reg is clobbered below. */ |
| 230 | LOAD_PER_CPU_BASE(%g5, %g6, %i0, %i1, %i2) | ||
| 231 | 1: | ||
| 232 | ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6 | ||
| 230 | ldx [%sp + PTREGS_OFF + PT_V9_G7], %g7 | 233 | ldx [%sp + PTREGS_OFF + PT_V9_G7], %g7 |
| 231 | wrpr %g0, RTRAP_PSTATE_AG_IRQOFF, %pstate | 234 | |
| 235 | /* Normal globals are restored, go to trap globals. */ | ||
| 236 | 661: wrpr %g0, RTRAP_PSTATE_AG_IRQOFF, %pstate | ||
| 237 | nop | ||
| 238 | .section .sun4v_2insn_patch, "ax" | ||
| 239 | .word 661b | ||
| 240 | wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate | ||
| 241 | SET_GL(1) | ||
| 242 | .previous | ||
| 243 | |||
| 244 | mov %l2, %g6 | ||
| 245 | |||
| 232 | ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 | 246 | ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 |
| 233 | ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 | 247 | ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 |
| 234 | 248 | ||
| @@ -252,27 +266,108 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 | |||
| 252 | 266 | ||
| 253 | brnz,pn %l3, kern_rtt | 267 | brnz,pn %l3, kern_rtt |
| 254 | mov PRIMARY_CONTEXT, %l7 | 268 | mov PRIMARY_CONTEXT, %l7 |
| 255 | ldxa [%l7 + %l7] ASI_DMMU, %l0 | 269 | |
| 270 | 661: ldxa [%l7 + %l7] ASI_DMMU, %l0 | ||
| 271 | .section .sun4v_1insn_patch, "ax" | ||
| 272 | .word 661b | ||
| 273 | ldxa [%l7 + %l7] ASI_MMU, %l0 | ||
| 274 | .previous | ||
| 275 | |||
| 256 | sethi %hi(sparc64_kern_pri_nuc_bits), %l1 | 276 | sethi %hi(sparc64_kern_pri_nuc_bits), %l1 |
| 257 | ldx [%l1 + %lo(sparc64_kern_pri_nuc_bits)], %l1 | 277 | ldx [%l1 + %lo(sparc64_kern_pri_nuc_bits)], %l1 |
| 258 | or %l0, %l1, %l0 | 278 | or %l0, %l1, %l0 |
| 259 | stxa %l0, [%l7] ASI_DMMU | 279 | |
| 260 | flush %g6 | 280 | 661: stxa %l0, [%l7] ASI_DMMU |
| 281 | .section .sun4v_1insn_patch, "ax" | ||
| 282 | .word 661b | ||
| 283 | stxa %l0, [%l7] ASI_MMU | ||
| 284 | .previous | ||
| 285 | |||
| 286 | sethi %hi(KERNBASE), %l7 | ||
| 287 | flush %l7 | ||
| 261 | rdpr %wstate, %l1 | 288 | rdpr %wstate, %l1 |
| 262 | rdpr %otherwin, %l2 | 289 | rdpr %otherwin, %l2 |
| 263 | srl %l1, 3, %l1 | 290 | srl %l1, 3, %l1 |
| 264 | 291 | ||
| 265 | wrpr %l2, %g0, %canrestore | 292 | wrpr %l2, %g0, %canrestore |
| 266 | wrpr %l1, %g0, %wstate | 293 | wrpr %l1, %g0, %wstate |
| 267 | wrpr %g0, %g0, %otherwin | 294 | brnz,pt %l2, user_rtt_restore |
| 295 | wrpr %g0, %g0, %otherwin | ||
| 296 | |||
| 297 | ldx [%g6 + TI_FLAGS], %g3 | ||
| 298 | wr %g0, ASI_AIUP, %asi | ||
| 299 | rdpr %cwp, %g1 | ||
| 300 | andcc %g3, _TIF_32BIT, %g0 | ||
| 301 | sub %g1, 1, %g1 | ||
| 302 | bne,pt %xcc, user_rtt_fill_32bit | ||
| 303 | wrpr %g1, %cwp | ||
| 304 | ba,a,pt %xcc, user_rtt_fill_64bit | ||
| 305 | |||
| 306 | user_rtt_fill_fixup: | ||
| 307 | rdpr %cwp, %g1 | ||
| 308 | add %g1, 1, %g1 | ||
| 309 | wrpr %g1, 0x0, %cwp | ||
| 310 | |||
| 311 | rdpr %wstate, %g2 | ||
| 312 | sll %g2, 3, %g2 | ||
| 313 | wrpr %g2, 0x0, %wstate | ||
| 314 | |||
| 315 | /* We know %canrestore and %otherwin are both zero. */ | ||
| 316 | |||
| 317 | sethi %hi(sparc64_kern_pri_context), %g2 | ||
| 318 | ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2 | ||
| 319 | mov PRIMARY_CONTEXT, %g1 | ||
| 320 | |||
| 321 | 661: stxa %g2, [%g1] ASI_DMMU | ||
| 322 | .section .sun4v_1insn_patch, "ax" | ||
| 323 | .word 661b | ||
| 324 | stxa %g2, [%g1] ASI_MMU | ||
| 325 | .previous | ||
| 326 | |||
| 327 | sethi %hi(KERNBASE), %g1 | ||
| 328 | flush %g1 | ||
| 329 | |||
| 330 | or %g4, FAULT_CODE_WINFIXUP, %g4 | ||
| 331 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
| 332 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
| 333 | |||
| 334 | mov %g6, %l1 | ||
| 335 | wrpr %g0, 0x0, %tl | ||
| 336 | |||
| 337 | 661: nop | ||
| 338 | .section .sun4v_1insn_patch, "ax" | ||
| 339 | .word 661b | ||
| 340 | SET_GL(0) | ||
| 341 | .previous | ||
| 342 | |||
| 343 | wrpr %g0, RTRAP_PSTATE, %pstate | ||
| 344 | |||
| 345 | mov %l1, %g6 | ||
| 346 | ldx [%g6 + TI_TASK], %g4 | ||
| 347 | LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) | ||
| 348 | call do_sparc64_fault | ||
| 349 | add %sp, PTREGS_OFF, %o0 | ||
| 350 | ba,pt %xcc, rtrap | ||
| 351 | nop | ||
| 352 | |||
| 353 | user_rtt_pre_restore: | ||
| 354 | add %g1, 1, %g1 | ||
| 355 | wrpr %g1, 0x0, %cwp | ||
| 356 | |||
| 357 | user_rtt_restore: | ||
| 268 | restore | 358 | restore |
| 269 | rdpr %canrestore, %g1 | 359 | rdpr %canrestore, %g1 |
| 270 | wrpr %g1, 0x0, %cleanwin | 360 | wrpr %g1, 0x0, %cleanwin |
| 271 | retry | 361 | retry |
| 272 | nop | 362 | nop |
| 273 | 363 | ||
| 274 | kern_rtt: restore | 364 | kern_rtt: rdpr %canrestore, %g1 |
| 365 | brz,pn %g1, kern_rtt_fill | ||
| 366 | nop | ||
| 367 | kern_rtt_restore: | ||
| 368 | restore | ||
| 275 | retry | 369 | retry |
| 370 | |||
| 276 | to_kernel: | 371 | to_kernel: |
| 277 | #ifdef CONFIG_PREEMPT | 372 | #ifdef CONFIG_PREEMPT |
| 278 | ldsw [%g6 + TI_PRE_COUNT], %l5 | 373 | ldsw [%g6 + TI_PRE_COUNT], %l5 |
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index d95a1bcf163d..1d6ffdeabd4c 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c | |||
| @@ -693,11 +693,11 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) | |||
| 693 | 693 | ||
| 694 | /* SBUS SYSIO INO number to Sparc PIL level. */ | 694 | /* SBUS SYSIO INO number to Sparc PIL level. */ |
| 695 | static unsigned char sysio_ino_to_pil[] = { | 695 | static unsigned char sysio_ino_to_pil[] = { |
| 696 | 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 0 */ | 696 | 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 0 */ |
| 697 | 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 1 */ | 697 | 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 1 */ |
| 698 | 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 2 */ | 698 | 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 2 */ |
| 699 | 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 3 */ | 699 | 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 3 */ |
| 700 | 4, /* Onboard SCSI */ | 700 | 5, /* Onboard SCSI */ |
| 701 | 5, /* Onboard Ethernet */ | 701 | 5, /* Onboard Ethernet */ |
| 702 | /*XXX*/ 8, /* Onboard BPP */ | 702 | /*XXX*/ 8, /* Onboard BPP */ |
| 703 | 0, /* Bogon */ | 703 | 0, /* Bogon */ |
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 158bd31e15b7..7d0e67c1ce50 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c | |||
| @@ -64,12 +64,6 @@ struct screen_info screen_info = { | |||
| 64 | 16 /* orig-video-points */ | 64 | 16 /* orig-video-points */ |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | /* Typing sync at the prom prompt calls the function pointed to by | ||
| 68 | * the sync callback which I set to the following function. | ||
| 69 | * This should sync all filesystems and return, for now it just | ||
| 70 | * prints out pretty messages and returns. | ||
| 71 | */ | ||
| 72 | |||
| 73 | void (*prom_palette)(int); | 67 | void (*prom_palette)(int); |
| 74 | void (*prom_keyboard)(void); | 68 | void (*prom_keyboard)(void); |
| 75 | 69 | ||
| @@ -79,259 +73,6 @@ prom_console_write(struct console *con, const char *s, unsigned n) | |||
| 79 | prom_write(s, n); | 73 | prom_write(s, n); |
| 80 | } | 74 | } |
| 81 | 75 | ||
| 82 | static struct console prom_console = { | ||
| 83 | .name = "prom", | ||
| 84 | .write = prom_console_write, | ||
| 85 | .flags = CON_CONSDEV | CON_ENABLED, | ||
| 86 | .index = -1, | ||
| 87 | }; | ||
| 88 | |||
| 89 | #define PROM_TRUE -1 | ||
| 90 | #define PROM_FALSE 0 | ||
| 91 | |||
| 92 | /* Pretty sick eh? */ | ||
| 93 | int prom_callback(long *args) | ||
| 94 | { | ||
| 95 | struct console *cons, *saved_console = NULL; | ||
| 96 | unsigned long flags; | ||
| 97 | char *cmd; | ||
| 98 | extern spinlock_t prom_entry_lock; | ||
| 99 | |||
| 100 | if (!args) | ||
| 101 | return -1; | ||
| 102 | if (!(cmd = (char *)args[0])) | ||
| 103 | return -1; | ||
| 104 | |||
| 105 | /* | ||
| 106 | * The callback can be invoked on the cpu that first dropped | ||
| 107 | * into prom_cmdline after taking the serial interrupt, or on | ||
| 108 | * a slave processor that was smp_captured() if the | ||
| 109 | * administrator has done a switch-cpu inside obp. In either | ||
| 110 | * case, the cpu is marked as in-interrupt. Drop IRQ locks. | ||
| 111 | */ | ||
| 112 | irq_exit(); | ||
| 113 | |||
| 114 | /* XXX Revisit the locking here someday. This is a debugging | ||
| 115 | * XXX feature so it isnt all that critical. -DaveM | ||
| 116 | */ | ||
| 117 | local_irq_save(flags); | ||
| 118 | |||
| 119 | spin_unlock(&prom_entry_lock); | ||
| 120 | cons = console_drivers; | ||
| 121 | while (cons) { | ||
| 122 | unregister_console(cons); | ||
| 123 | cons->flags &= ~(CON_PRINTBUFFER); | ||
| 124 | cons->next = saved_console; | ||
| 125 | saved_console = cons; | ||
| 126 | cons = console_drivers; | ||
| 127 | } | ||
| 128 | register_console(&prom_console); | ||
| 129 | if (!strcmp(cmd, "sync")) { | ||
| 130 | prom_printf("PROM `%s' command...\n", cmd); | ||
| 131 | show_free_areas(); | ||
| 132 | if (current->pid != 0) { | ||
| 133 | local_irq_enable(); | ||
| 134 | sys_sync(); | ||
| 135 | local_irq_disable(); | ||
| 136 | } | ||
| 137 | args[2] = 0; | ||
| 138 | args[args[1] + 3] = -1; | ||
| 139 | prom_printf("Returning to PROM\n"); | ||
| 140 | } else if (!strcmp(cmd, "va>tte-data")) { | ||
| 141 | unsigned long ctx, va; | ||
| 142 | unsigned long tte = 0; | ||
| 143 | long res = PROM_FALSE; | ||
| 144 | |||
| 145 | ctx = args[3]; | ||
| 146 | va = args[4]; | ||
| 147 | if (ctx) { | ||
| 148 | /* | ||
| 149 | * Find process owning ctx, lookup mapping. | ||
| 150 | */ | ||
| 151 | struct task_struct *p; | ||
| 152 | struct mm_struct *mm = NULL; | ||
| 153 | pgd_t *pgdp; | ||
| 154 | pud_t *pudp; | ||
| 155 | pmd_t *pmdp; | ||
| 156 | pte_t *ptep; | ||
| 157 | pte_t pte; | ||
| 158 | |||
| 159 | for_each_process(p) { | ||
| 160 | mm = p->mm; | ||
| 161 | if (CTX_NRBITS(mm->context) == ctx) | ||
| 162 | break; | ||
| 163 | } | ||
| 164 | if (!mm || | ||
| 165 | CTX_NRBITS(mm->context) != ctx) | ||
| 166 | goto done; | ||
| 167 | |||
| 168 | pgdp = pgd_offset(mm, va); | ||
| 169 | if (pgd_none(*pgdp)) | ||
| 170 | goto done; | ||
| 171 | pudp = pud_offset(pgdp, va); | ||
| 172 | if (pud_none(*pudp)) | ||
| 173 | goto done; | ||
| 174 | pmdp = pmd_offset(pudp, va); | ||
| 175 | if (pmd_none(*pmdp)) | ||
| 176 | goto done; | ||
| 177 | |||
| 178 | /* Preemption implicitly disabled by virtue of | ||
| 179 | * being called from inside OBP. | ||
| 180 | */ | ||
| 181 | ptep = pte_offset_map(pmdp, va); | ||
| 182 | pte = *ptep; | ||
| 183 | if (pte_present(pte)) { | ||
| 184 | tte = pte_val(pte); | ||
| 185 | res = PROM_TRUE; | ||
| 186 | } | ||
| 187 | pte_unmap(ptep); | ||
| 188 | goto done; | ||
| 189 | } | ||
| 190 | |||
| 191 | if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) { | ||
| 192 | extern unsigned long sparc64_kern_pri_context; | ||
| 193 | |||
| 194 | /* Spitfire Errata #32 workaround */ | ||
| 195 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 196 | "flush %%g6" | ||
| 197 | : /* No outputs */ | ||
| 198 | : "r" (sparc64_kern_pri_context), | ||
| 199 | "r" (PRIMARY_CONTEXT), | ||
| 200 | "i" (ASI_DMMU)); | ||
| 201 | |||
| 202 | /* | ||
| 203 | * Locked down tlb entry. | ||
| 204 | */ | ||
| 205 | |||
| 206 | if (tlb_type == spitfire) | ||
| 207 | tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT); | ||
| 208 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 209 | tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT); | ||
| 210 | |||
| 211 | res = PROM_TRUE; | ||
| 212 | goto done; | ||
| 213 | } | ||
| 214 | |||
| 215 | if (va < PGDIR_SIZE) { | ||
| 216 | /* | ||
| 217 | * vmalloc or prom_inherited mapping. | ||
| 218 | */ | ||
| 219 | pgd_t *pgdp; | ||
| 220 | pud_t *pudp; | ||
| 221 | pmd_t *pmdp; | ||
| 222 | pte_t *ptep; | ||
| 223 | pte_t pte; | ||
| 224 | int error; | ||
| 225 | |||
| 226 | if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) { | ||
| 227 | tte = prom_virt_to_phys(va, &error); | ||
| 228 | if (!error) | ||
| 229 | res = PROM_TRUE; | ||
| 230 | goto done; | ||
| 231 | } | ||
| 232 | pgdp = pgd_offset_k(va); | ||
| 233 | if (pgd_none(*pgdp)) | ||
| 234 | goto done; | ||
| 235 | pudp = pud_offset(pgdp, va); | ||
| 236 | if (pud_none(*pudp)) | ||
| 237 | goto done; | ||
| 238 | pmdp = pmd_offset(pudp, va); | ||
| 239 | if (pmd_none(*pmdp)) | ||
| 240 | goto done; | ||
| 241 | |||
| 242 | /* Preemption implicitly disabled by virtue of | ||
| 243 | * being called from inside OBP. | ||
| 244 | */ | ||
| 245 | ptep = pte_offset_kernel(pmdp, va); | ||
| 246 | pte = *ptep; | ||
| 247 | if (pte_present(pte)) { | ||
| 248 | tte = pte_val(pte); | ||
| 249 | res = PROM_TRUE; | ||
| 250 | } | ||
| 251 | goto done; | ||
| 252 | } | ||
| 253 | |||
| 254 | if (va < PAGE_OFFSET) { | ||
| 255 | /* | ||
| 256 | * No mappings here. | ||
| 257 | */ | ||
| 258 | goto done; | ||
| 259 | } | ||
| 260 | |||
| 261 | if (va & (1UL << 40)) { | ||
| 262 | /* | ||
| 263 | * I/O page. | ||
| 264 | */ | ||
| 265 | |||
| 266 | tte = (__pa(va) & _PAGE_PADDR) | | ||
| 267 | _PAGE_VALID | _PAGE_SZ4MB | | ||
| 268 | _PAGE_E | _PAGE_P | _PAGE_W; | ||
| 269 | res = PROM_TRUE; | ||
| 270 | goto done; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* | ||
| 274 | * Normal page. | ||
| 275 | */ | ||
| 276 | tte = (__pa(va) & _PAGE_PADDR) | | ||
| 277 | _PAGE_VALID | _PAGE_SZ4MB | | ||
| 278 | _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W; | ||
| 279 | res = PROM_TRUE; | ||
| 280 | |||
| 281 | done: | ||
| 282 | if (res == PROM_TRUE) { | ||
| 283 | args[2] = 3; | ||
| 284 | args[args[1] + 3] = 0; | ||
| 285 | args[args[1] + 4] = res; | ||
| 286 | args[args[1] + 5] = tte; | ||
| 287 | } else { | ||
| 288 | args[2] = 2; | ||
| 289 | args[args[1] + 3] = 0; | ||
| 290 | args[args[1] + 4] = res; | ||
| 291 | } | ||
| 292 | } else if (!strcmp(cmd, ".soft1")) { | ||
| 293 | unsigned long tte; | ||
| 294 | |||
| 295 | tte = args[3]; | ||
| 296 | prom_printf("%lx:\"%s%s%s%s%s\" ", | ||
| 297 | (tte & _PAGE_SOFT) >> 7, | ||
| 298 | tte & _PAGE_MODIFIED ? "M" : "-", | ||
| 299 | tte & _PAGE_ACCESSED ? "A" : "-", | ||
| 300 | tte & _PAGE_READ ? "W" : "-", | ||
| 301 | tte & _PAGE_WRITE ? "R" : "-", | ||
| 302 | tte & _PAGE_PRESENT ? "P" : "-"); | ||
| 303 | |||
| 304 | args[2] = 2; | ||
| 305 | args[args[1] + 3] = 0; | ||
| 306 | args[args[1] + 4] = PROM_TRUE; | ||
| 307 | } else if (!strcmp(cmd, ".soft2")) { | ||
| 308 | unsigned long tte; | ||
| 309 | |||
| 310 | tte = args[3]; | ||
| 311 | prom_printf("%lx ", (tte & 0x07FC000000000000UL) >> 50); | ||
| 312 | |||
| 313 | args[2] = 2; | ||
| 314 | args[args[1] + 3] = 0; | ||
| 315 | args[args[1] + 4] = PROM_TRUE; | ||
| 316 | } else { | ||
| 317 | prom_printf("unknown PROM `%s' command...\n", cmd); | ||
| 318 | } | ||
| 319 | unregister_console(&prom_console); | ||
| 320 | while (saved_console) { | ||
| 321 | cons = saved_console; | ||
| 322 | saved_console = cons->next; | ||
| 323 | register_console(cons); | ||
| 324 | } | ||
| 325 | spin_lock(&prom_entry_lock); | ||
| 326 | local_irq_restore(flags); | ||
| 327 | |||
| 328 | /* | ||
| 329 | * Restore in-interrupt status for a resume from obp. | ||
| 330 | */ | ||
| 331 | irq_enter(); | ||
| 332 | return 0; | ||
| 333 | } | ||
| 334 | |||
| 335 | unsigned int boot_flags = 0; | 76 | unsigned int boot_flags = 0; |
| 336 | #define BOOTME_DEBUG 0x1 | 77 | #define BOOTME_DEBUG 0x1 |
| 337 | #define BOOTME_SINGLE 0x2 | 78 | #define BOOTME_SINGLE 0x2 |
| @@ -479,15 +220,99 @@ char reboot_command[COMMAND_LINE_SIZE]; | |||
| 479 | 220 | ||
| 480 | static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; | 221 | static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; |
| 481 | 222 | ||
| 482 | void register_prom_callbacks(void) | 223 | static void __init per_cpu_patch(void) |
| 483 | { | 224 | { |
| 484 | prom_setcallback(prom_callback); | 225 | struct cpuid_patch_entry *p; |
| 485 | prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; " | 226 | unsigned long ver; |
| 486 | "' linux-va>tte-data to va>tte-data"); | 227 | int is_jbus; |
| 487 | prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; " | 228 | |
| 488 | "' linux-.soft1 to .soft1"); | 229 | if (tlb_type == spitfire && !this_is_starfire) |
| 489 | prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; " | 230 | return; |
| 490 | "' linux-.soft2 to .soft2"); | 231 | |
| 232 | is_jbus = 0; | ||
| 233 | if (tlb_type != hypervisor) { | ||
| 234 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | ||
| 235 | is_jbus = ((ver >> 32UL) == __JALAPENO_ID || | ||
| 236 | (ver >> 32UL) == __SERRANO_ID); | ||
| 237 | } | ||
| 238 | |||
| 239 | p = &__cpuid_patch; | ||
| 240 | while (p < &__cpuid_patch_end) { | ||
| 241 | unsigned long addr = p->addr; | ||
| 242 | unsigned int *insns; | ||
| 243 | |||
| 244 | switch (tlb_type) { | ||
| 245 | case spitfire: | ||
| 246 | insns = &p->starfire[0]; | ||
| 247 | break; | ||
| 248 | case cheetah: | ||
| 249 | case cheetah_plus: | ||
| 250 | if (is_jbus) | ||
| 251 | insns = &p->cheetah_jbus[0]; | ||
| 252 | else | ||
| 253 | insns = &p->cheetah_safari[0]; | ||
| 254 | break; | ||
| 255 | case hypervisor: | ||
| 256 | insns = &p->sun4v[0]; | ||
| 257 | break; | ||
| 258 | default: | ||
| 259 | prom_printf("Unknown cpu type, halting.\n"); | ||
| 260 | prom_halt(); | ||
| 261 | }; | ||
| 262 | |||
| 263 | *(unsigned int *) (addr + 0) = insns[0]; | ||
| 264 | wmb(); | ||
| 265 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | ||
| 266 | |||
| 267 | *(unsigned int *) (addr + 4) = insns[1]; | ||
| 268 | wmb(); | ||
| 269 | __asm__ __volatile__("flush %0" : : "r" (addr + 4)); | ||
| 270 | |||
| 271 | *(unsigned int *) (addr + 8) = insns[2]; | ||
| 272 | wmb(); | ||
| 273 | __asm__ __volatile__("flush %0" : : "r" (addr + 8)); | ||
| 274 | |||
| 275 | *(unsigned int *) (addr + 12) = insns[3]; | ||
| 276 | wmb(); | ||
| 277 | __asm__ __volatile__("flush %0" : : "r" (addr + 12)); | ||
| 278 | |||
| 279 | p++; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | static void __init sun4v_patch(void) | ||
| 284 | { | ||
| 285 | struct sun4v_1insn_patch_entry *p1; | ||
| 286 | struct sun4v_2insn_patch_entry *p2; | ||
| 287 | |||
| 288 | if (tlb_type != hypervisor) | ||
| 289 | return; | ||
| 290 | |||
| 291 | p1 = &__sun4v_1insn_patch; | ||
| 292 | while (p1 < &__sun4v_1insn_patch_end) { | ||
| 293 | unsigned long addr = p1->addr; | ||
| 294 | |||
| 295 | *(unsigned int *) (addr + 0) = p1->insn; | ||
| 296 | wmb(); | ||
| 297 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | ||
| 298 | |||
| 299 | p1++; | ||
| 300 | } | ||
| 301 | |||
| 302 | p2 = &__sun4v_2insn_patch; | ||
| 303 | while (p2 < &__sun4v_2insn_patch_end) { | ||
| 304 | unsigned long addr = p2->addr; | ||
| 305 | |||
| 306 | *(unsigned int *) (addr + 0) = p2->insns[0]; | ||
| 307 | wmb(); | ||
| 308 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | ||
| 309 | |||
| 310 | *(unsigned int *) (addr + 4) = p2->insns[1]; | ||
| 311 | wmb(); | ||
| 312 | __asm__ __volatile__("flush %0" : : "r" (addr + 4)); | ||
| 313 | |||
| 314 | p2++; | ||
| 315 | } | ||
| 491 | } | 316 | } |
| 492 | 317 | ||
| 493 | void __init setup_arch(char **cmdline_p) | 318 | void __init setup_arch(char **cmdline_p) |
| @@ -496,7 +321,10 @@ void __init setup_arch(char **cmdline_p) | |||
| 496 | *cmdline_p = prom_getbootargs(); | 321 | *cmdline_p = prom_getbootargs(); |
| 497 | strcpy(saved_command_line, *cmdline_p); | 322 | strcpy(saved_command_line, *cmdline_p); |
| 498 | 323 | ||
| 499 | printk("ARCH: SUN4U\n"); | 324 | if (tlb_type == hypervisor) |
| 325 | printk("ARCH: SUN4V\n"); | ||
| 326 | else | ||
| 327 | printk("ARCH: SUN4U\n"); | ||
| 500 | 328 | ||
| 501 | #ifdef CONFIG_DUMMY_CONSOLE | 329 | #ifdef CONFIG_DUMMY_CONSOLE |
| 502 | conswitchp = &dummy_con; | 330 | conswitchp = &dummy_con; |
| @@ -507,6 +335,13 @@ void __init setup_arch(char **cmdline_p) | |||
| 507 | /* Work out if we are starfire early on */ | 335 | /* Work out if we are starfire early on */ |
| 508 | check_if_starfire(); | 336 | check_if_starfire(); |
| 509 | 337 | ||
| 338 | /* Now we know enough to patch the get_cpuid sequences | ||
| 339 | * used by trap code. | ||
| 340 | */ | ||
| 341 | per_cpu_patch(); | ||
| 342 | |||
| 343 | sun4v_patch(); | ||
| 344 | |||
| 510 | boot_flags_init(*cmdline_p); | 345 | boot_flags_init(*cmdline_p); |
| 511 | 346 | ||
| 512 | idprom_init(); | 347 | idprom_init(); |
| @@ -514,7 +349,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 514 | if (!root_flags) | 349 | if (!root_flags) |
| 515 | root_mountflags &= ~MS_RDONLY; | 350 | root_mountflags &= ~MS_RDONLY; |
| 516 | ROOT_DEV = old_decode_dev(root_dev); | 351 | ROOT_DEV = old_decode_dev(root_dev); |
| 517 | #ifdef CONFIG_BLK_DEV_INITRD | 352 | #ifdef CONFIG_BLK_DEV_RAM |
| 518 | rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; | 353 | rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; |
| 519 | rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); | 354 | rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); |
| 520 | rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); | 355 | rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); |
| @@ -544,6 +379,9 @@ void __init setup_arch(char **cmdline_p) | |||
| 544 | 379 | ||
| 545 | smp_setup_cpu_possible_map(); | 380 | smp_setup_cpu_possible_map(); |
| 546 | 381 | ||
| 382 | /* Get boot processor trap_block[] setup. */ | ||
| 383 | init_cur_cpu_trap(current_thread_info()); | ||
| 384 | |||
| 547 | paging_init(); | 385 | paging_init(); |
| 548 | } | 386 | } |
| 549 | 387 | ||
| @@ -565,6 +403,12 @@ static int __init set_preferred_console(void) | |||
| 565 | serial_console = 2; | 403 | serial_console = 2; |
| 566 | } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) { | 404 | } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) { |
| 567 | serial_console = 3; | 405 | serial_console = 3; |
| 406 | } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) { | ||
| 407 | /* sunhv_console_init() doesn't check the serial_console | ||
| 408 | * value anyways... | ||
| 409 | */ | ||
| 410 | serial_console = 4; | ||
| 411 | return add_preferred_console("ttyHV", 0, NULL); | ||
| 568 | } else { | 412 | } else { |
| 569 | prom_printf("Inconsistent console: " | 413 | prom_printf("Inconsistent console: " |
| 570 | "input %d, output %d\n", | 414 | "input %d, output %d\n", |
| @@ -598,9 +442,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) | |||
| 598 | seq_printf(m, | 442 | seq_printf(m, |
| 599 | "cpu\t\t: %s\n" | 443 | "cpu\t\t: %s\n" |
| 600 | "fpu\t\t: %s\n" | 444 | "fpu\t\t: %s\n" |
| 601 | "promlib\t\t: Version 3 Revision %d\n" | 445 | "prom\t\t: %s\n" |
| 602 | "prom\t\t: %d.%d.%d\n" | 446 | "type\t\t: %s\n" |
| 603 | "type\t\t: sun4u\n" | ||
| 604 | "ncpus probed\t: %d\n" | 447 | "ncpus probed\t: %d\n" |
| 605 | "ncpus active\t: %d\n" | 448 | "ncpus active\t: %d\n" |
| 606 | "D$ parity tl1\t: %u\n" | 449 | "D$ parity tl1\t: %u\n" |
| @@ -612,10 +455,10 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) | |||
| 612 | , | 455 | , |
| 613 | sparc_cpu_type, | 456 | sparc_cpu_type, |
| 614 | sparc_fpu_type, | 457 | sparc_fpu_type, |
| 615 | prom_rev, | 458 | prom_version, |
| 616 | prom_prev >> 16, | 459 | ((tlb_type == hypervisor) ? |
| 617 | (prom_prev >> 8) & 0xff, | 460 | "sun4v" : |
| 618 | prom_prev & 0xff, | 461 | "sun4u"), |
| 619 | ncpus_probed, | 462 | ncpus_probed, |
| 620 | num_online_cpus(), | 463 | num_online_cpus(), |
| 621 | dcache_parity_tl1_occurred, | 464 | dcache_parity_tl1_occurred, |
| @@ -692,15 +535,11 @@ static int __init topology_init(void) | |||
| 692 | while (!cpu_find_by_instance(ncpus_probed, NULL, NULL)) | 535 | while (!cpu_find_by_instance(ncpus_probed, NULL, NULL)) |
| 693 | ncpus_probed++; | 536 | ncpus_probed++; |
| 694 | 537 | ||
| 695 | for (i = 0; i < NR_CPUS; i++) { | 538 | for_each_cpu(i) { |
| 696 | if (cpu_possible(i)) { | 539 | struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 697 | struct cpu *p = kmalloc(sizeof(*p), GFP_KERNEL); | 540 | if (p) { |
| 698 | 541 | register_cpu(p, i, NULL); | |
| 699 | if (p) { | 542 | err = 0; |
| 700 | memset(p, 0, sizeof(*p)); | ||
| 701 | register_cpu(p, i, NULL); | ||
| 702 | err = 0; | ||
| 703 | } | ||
| 704 | } | 543 | } |
| 705 | } | 544 | } |
| 706 | 545 | ||
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 1f7ad8a69052..373a701c90a5 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <asm/timer.h> | 38 | #include <asm/timer.h> |
| 39 | #include <asm/starfire.h> | 39 | #include <asm/starfire.h> |
| 40 | #include <asm/tlb.h> | 40 | #include <asm/tlb.h> |
| 41 | #include <asm/sections.h> | ||
| 41 | 42 | ||
| 42 | extern void calibrate_delay(void); | 43 | extern void calibrate_delay(void); |
| 43 | 44 | ||
| @@ -46,6 +47,8 @@ static unsigned char boot_cpu_id; | |||
| 46 | 47 | ||
| 47 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; | 48 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; |
| 48 | cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; | 49 | cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; |
| 50 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = | ||
| 51 | { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; | ||
| 49 | static cpumask_t smp_commenced_mask; | 52 | static cpumask_t smp_commenced_mask; |
| 50 | static cpumask_t cpu_callout_map; | 53 | static cpumask_t cpu_callout_map; |
| 51 | 54 | ||
| @@ -77,7 +80,7 @@ void smp_bogo(struct seq_file *m) | |||
| 77 | 80 | ||
| 78 | void __init smp_store_cpu_info(int id) | 81 | void __init smp_store_cpu_info(int id) |
| 79 | { | 82 | { |
| 80 | int cpu_node; | 83 | int cpu_node, def; |
| 81 | 84 | ||
| 82 | /* multiplier and counter set by | 85 | /* multiplier and counter set by |
| 83 | smp_setup_percpu_timer() */ | 86 | smp_setup_percpu_timer() */ |
| @@ -87,24 +90,32 @@ void __init smp_store_cpu_info(int id) | |||
| 87 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, | 90 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, |
| 88 | "clock-frequency", 0); | 91 | "clock-frequency", 0); |
| 89 | 92 | ||
| 90 | cpu_data(id).pgcache_size = 0; | 93 | def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024)); |
| 91 | cpu_data(id).pte_cache[0] = NULL; | ||
| 92 | cpu_data(id).pte_cache[1] = NULL; | ||
| 93 | cpu_data(id).pgd_cache = NULL; | ||
| 94 | cpu_data(id).idle_volume = 1; | ||
| 95 | |||
| 96 | cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size", | 94 | cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size", |
| 97 | 16 * 1024); | 95 | def); |
| 96 | |||
| 97 | def = 32; | ||
| 98 | cpu_data(id).dcache_line_size = | 98 | cpu_data(id).dcache_line_size = |
| 99 | prom_getintdefault(cpu_node, "dcache-line-size", 32); | 99 | prom_getintdefault(cpu_node, "dcache-line-size", def); |
| 100 | |||
| 101 | def = 16 * 1024; | ||
| 100 | cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", | 102 | cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", |
| 101 | 16 * 1024); | 103 | def); |
| 104 | |||
| 105 | def = 32; | ||
| 102 | cpu_data(id).icache_line_size = | 106 | cpu_data(id).icache_line_size = |
| 103 | prom_getintdefault(cpu_node, "icache-line-size", 32); | 107 | prom_getintdefault(cpu_node, "icache-line-size", def); |
| 108 | |||
| 109 | def = ((tlb_type == hypervisor) ? | ||
| 110 | (3 * 1024 * 1024) : | ||
| 111 | (4 * 1024 * 1024)); | ||
| 104 | cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", | 112 | cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", |
| 105 | 4 * 1024 * 1024); | 113 | def); |
| 114 | |||
| 115 | def = 64; | ||
| 106 | cpu_data(id).ecache_line_size = | 116 | cpu_data(id).ecache_line_size = |
| 107 | prom_getintdefault(cpu_node, "ecache-line-size", 64); | 117 | prom_getintdefault(cpu_node, "ecache-line-size", def); |
| 118 | |||
| 108 | printk("CPU[%d]: Caches " | 119 | printk("CPU[%d]: Caches " |
| 109 | "D[sz(%d):line_sz(%d)] " | 120 | "D[sz(%d):line_sz(%d)] " |
| 110 | "I[sz(%d):line_sz(%d)] " | 121 | "I[sz(%d):line_sz(%d)] " |
| @@ -119,27 +130,16 @@ static void smp_setup_percpu_timer(void); | |||
| 119 | 130 | ||
| 120 | static volatile unsigned long callin_flag = 0; | 131 | static volatile unsigned long callin_flag = 0; |
| 121 | 132 | ||
| 122 | extern void inherit_locked_prom_mappings(int save_p); | ||
| 123 | |||
| 124 | static inline void cpu_setup_percpu_base(unsigned long cpu_id) | ||
| 125 | { | ||
| 126 | __asm__ __volatile__("mov %0, %%g5\n\t" | ||
| 127 | "stxa %0, [%1] %2\n\t" | ||
| 128 | "membar #Sync" | ||
| 129 | : /* no outputs */ | ||
| 130 | : "r" (__per_cpu_offset(cpu_id)), | ||
| 131 | "r" (TSB_REG), "i" (ASI_IMMU)); | ||
| 132 | } | ||
| 133 | |||
| 134 | void __init smp_callin(void) | 133 | void __init smp_callin(void) |
| 135 | { | 134 | { |
| 136 | int cpuid = hard_smp_processor_id(); | 135 | int cpuid = hard_smp_processor_id(); |
| 137 | 136 | ||
| 138 | inherit_locked_prom_mappings(0); | 137 | __local_per_cpu_offset = __per_cpu_offset(cpuid); |
| 139 | 138 | ||
| 140 | __flush_tlb_all(); | 139 | if (tlb_type == hypervisor) |
| 140 | sun4v_ktsb_register(); | ||
| 141 | 141 | ||
| 142 | cpu_setup_percpu_base(cpuid); | 142 | __flush_tlb_all(); |
| 143 | 143 | ||
| 144 | smp_setup_percpu_timer(); | 144 | smp_setup_percpu_timer(); |
| 145 | 145 | ||
| @@ -316,6 +316,8 @@ static void smp_synchronize_one_tick(int cpu) | |||
| 316 | spin_unlock_irqrestore(&itc_sync_lock, flags); | 316 | spin_unlock_irqrestore(&itc_sync_lock, flags); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load); | ||
| 320 | |||
| 319 | extern unsigned long sparc64_cpu_startup; | 321 | extern unsigned long sparc64_cpu_startup; |
| 320 | 322 | ||
| 321 | /* The OBP cpu startup callback truncates the 3rd arg cookie to | 323 | /* The OBP cpu startup callback truncates the 3rd arg cookie to |
| @@ -331,21 +333,31 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) | |||
| 331 | unsigned long cookie = | 333 | unsigned long cookie = |
| 332 | (unsigned long)(&cpu_new_thread); | 334 | (unsigned long)(&cpu_new_thread); |
| 333 | struct task_struct *p; | 335 | struct task_struct *p; |
| 334 | int timeout, ret, cpu_node; | 336 | int timeout, ret; |
| 335 | 337 | ||
| 336 | p = fork_idle(cpu); | 338 | p = fork_idle(cpu); |
| 337 | callin_flag = 0; | 339 | callin_flag = 0; |
| 338 | cpu_new_thread = task_thread_info(p); | 340 | cpu_new_thread = task_thread_info(p); |
| 339 | cpu_set(cpu, cpu_callout_map); | 341 | cpu_set(cpu, cpu_callout_map); |
| 340 | 342 | ||
| 341 | cpu_find_by_mid(cpu, &cpu_node); | 343 | if (tlb_type == hypervisor) { |
| 342 | prom_startcpu(cpu_node, entry, cookie); | 344 | /* Alloc the mondo queues, cpu will load them. */ |
| 345 | sun4v_init_mondo_queues(0, cpu, 1, 0); | ||
| 346 | |||
| 347 | prom_startcpu_cpuid(cpu, entry, cookie); | ||
| 348 | } else { | ||
| 349 | int cpu_node; | ||
| 350 | |||
| 351 | cpu_find_by_mid(cpu, &cpu_node); | ||
| 352 | prom_startcpu(cpu_node, entry, cookie); | ||
| 353 | } | ||
| 343 | 354 | ||
| 344 | for (timeout = 0; timeout < 5000000; timeout++) { | 355 | for (timeout = 0; timeout < 5000000; timeout++) { |
| 345 | if (callin_flag) | 356 | if (callin_flag) |
| 346 | break; | 357 | break; |
| 347 | udelay(100); | 358 | udelay(100); |
| 348 | } | 359 | } |
| 360 | |||
| 349 | if (callin_flag) { | 361 | if (callin_flag) { |
| 350 | ret = 0; | 362 | ret = 0; |
| 351 | } else { | 363 | } else { |
| @@ -441,7 +453,7 @@ static __inline__ void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, c | |||
| 441 | static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | 453 | static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) |
| 442 | { | 454 | { |
| 443 | u64 pstate, ver; | 455 | u64 pstate, ver; |
| 444 | int nack_busy_id, is_jalapeno; | 456 | int nack_busy_id, is_jbus; |
| 445 | 457 | ||
| 446 | if (cpus_empty(mask)) | 458 | if (cpus_empty(mask)) |
| 447 | return; | 459 | return; |
| @@ -451,7 +463,8 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas | |||
| 451 | * derivative processor. | 463 | * derivative processor. |
| 452 | */ | 464 | */ |
| 453 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | 465 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); |
| 454 | is_jalapeno = ((ver >> 32) == 0x003e0016); | 466 | is_jbus = ((ver >> 32) == __JALAPENO_ID || |
| 467 | (ver >> 32) == __SERRANO_ID); | ||
| 455 | 468 | ||
| 456 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); | 469 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); |
| 457 | 470 | ||
| @@ -476,7 +489,7 @@ retry: | |||
| 476 | for_each_cpu_mask(i, mask) { | 489 | for_each_cpu_mask(i, mask) { |
| 477 | u64 target = (i << 14) | 0x70; | 490 | u64 target = (i << 14) | 0x70; |
| 478 | 491 | ||
| 479 | if (!is_jalapeno) | 492 | if (!is_jbus) |
| 480 | target |= (nack_busy_id << 24); | 493 | target |= (nack_busy_id << 24); |
| 481 | __asm__ __volatile__( | 494 | __asm__ __volatile__( |
| 482 | "stxa %%g0, [%0] %1\n\t" | 495 | "stxa %%g0, [%0] %1\n\t" |
| @@ -529,7 +542,7 @@ retry: | |||
| 529 | for_each_cpu_mask(i, mask) { | 542 | for_each_cpu_mask(i, mask) { |
| 530 | u64 check_mask; | 543 | u64 check_mask; |
| 531 | 544 | ||
| 532 | if (is_jalapeno) | 545 | if (is_jbus) |
| 533 | check_mask = (0x2UL << (2*i)); | 546 | check_mask = (0x2UL << (2*i)); |
| 534 | else | 547 | else |
| 535 | check_mask = (0x2UL << | 548 | check_mask = (0x2UL << |
| @@ -544,6 +557,155 @@ retry: | |||
| 544 | } | 557 | } |
| 545 | } | 558 | } |
| 546 | 559 | ||
| 560 | /* Multi-cpu list version. */ | ||
| 561 | static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | ||
| 562 | { | ||
| 563 | struct trap_per_cpu *tb; | ||
| 564 | u16 *cpu_list; | ||
| 565 | u64 *mondo; | ||
| 566 | cpumask_t error_mask; | ||
| 567 | unsigned long flags, status; | ||
| 568 | int cnt, retries, this_cpu, prev_sent, i; | ||
| 569 | |||
| 570 | /* We have to do this whole thing with interrupts fully disabled. | ||
| 571 | * Otherwise if we send an xcall from interrupt context it will | ||
| 572 | * corrupt both our mondo block and cpu list state. | ||
| 573 | * | ||
| 574 | * One consequence of this is that we cannot use timeout mechanisms | ||
| 575 | * that depend upon interrupts being delivered locally. So, for | ||
| 576 | * example, we cannot sample jiffies and expect it to advance. | ||
| 577 | * | ||
| 578 | * Fortunately, udelay() uses %stick/%tick so we can use that. | ||
| 579 | */ | ||
| 580 | local_irq_save(flags); | ||
| 581 | |||
| 582 | this_cpu = smp_processor_id(); | ||
| 583 | tb = &trap_block[this_cpu]; | ||
| 584 | |||
| 585 | mondo = __va(tb->cpu_mondo_block_pa); | ||
| 586 | mondo[0] = data0; | ||
| 587 | mondo[1] = data1; | ||
| 588 | mondo[2] = data2; | ||
| 589 | wmb(); | ||
| 590 | |||
| 591 | cpu_list = __va(tb->cpu_list_pa); | ||
| 592 | |||
| 593 | /* Setup the initial cpu list. */ | ||
| 594 | cnt = 0; | ||
| 595 | for_each_cpu_mask(i, mask) | ||
| 596 | cpu_list[cnt++] = i; | ||
| 597 | |||
| 598 | cpus_clear(error_mask); | ||
| 599 | retries = 0; | ||
| 600 | prev_sent = 0; | ||
| 601 | do { | ||
| 602 | int forward_progress, n_sent; | ||
| 603 | |||
| 604 | status = sun4v_cpu_mondo_send(cnt, | ||
| 605 | tb->cpu_list_pa, | ||
| 606 | tb->cpu_mondo_block_pa); | ||
| 607 | |||
| 608 | /* HV_EOK means all cpus received the xcall, we're done. */ | ||
| 609 | if (likely(status == HV_EOK)) | ||
| 610 | break; | ||
| 611 | |||
| 612 | /* First, see if we made any forward progress. | ||
| 613 | * | ||
| 614 | * The hypervisor indicates successful sends by setting | ||
| 615 | * cpu list entries to the value 0xffff. | ||
| 616 | */ | ||
| 617 | n_sent = 0; | ||
| 618 | for (i = 0; i < cnt; i++) { | ||
| 619 | if (likely(cpu_list[i] == 0xffff)) | ||
| 620 | n_sent++; | ||
| 621 | } | ||
| 622 | |||
| 623 | forward_progress = 0; | ||
| 624 | if (n_sent > prev_sent) | ||
| 625 | forward_progress = 1; | ||
| 626 | |||
| 627 | prev_sent = n_sent; | ||
| 628 | |||
| 629 | /* If we get a HV_ECPUERROR, then one or more of the cpus | ||
| 630 | * in the list are in error state. Use the cpu_state() | ||
| 631 | * hypervisor call to find out which cpus are in error state. | ||
| 632 | */ | ||
| 633 | if (unlikely(status == HV_ECPUERROR)) { | ||
| 634 | for (i = 0; i < cnt; i++) { | ||
| 635 | long err; | ||
| 636 | u16 cpu; | ||
| 637 | |||
| 638 | cpu = cpu_list[i]; | ||
| 639 | if (cpu == 0xffff) | ||
| 640 | continue; | ||
| 641 | |||
| 642 | err = sun4v_cpu_state(cpu); | ||
| 643 | if (err >= 0 && | ||
| 644 | err == HV_CPU_STATE_ERROR) { | ||
| 645 | cpu_list[i] = 0xffff; | ||
| 646 | cpu_set(cpu, error_mask); | ||
| 647 | } | ||
| 648 | } | ||
| 649 | } else if (unlikely(status != HV_EWOULDBLOCK)) | ||
| 650 | goto fatal_mondo_error; | ||
| 651 | |||
| 652 | /* Don't bother rewriting the CPU list, just leave the | ||
| 653 | * 0xffff and non-0xffff entries in there and the | ||
| 654 | * hypervisor will do the right thing. | ||
| 655 | * | ||
| 656 | * Only advance timeout state if we didn't make any | ||
| 657 | * forward progress. | ||
| 658 | */ | ||
| 659 | if (unlikely(!forward_progress)) { | ||
| 660 | if (unlikely(++retries > 10000)) | ||
| 661 | goto fatal_mondo_timeout; | ||
| 662 | |||
| 663 | /* Delay a little bit to let other cpus catch up | ||
| 664 | * on their cpu mondo queue work. | ||
| 665 | */ | ||
| 666 | udelay(2 * cnt); | ||
| 667 | } | ||
| 668 | } while (1); | ||
| 669 | |||
| 670 | local_irq_restore(flags); | ||
| 671 | |||
| 672 | if (unlikely(!cpus_empty(error_mask))) | ||
| 673 | goto fatal_mondo_cpu_error; | ||
| 674 | |||
| 675 | return; | ||
| 676 | |||
| 677 | fatal_mondo_cpu_error: | ||
| 678 | printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " | ||
| 679 | "were in error state\n", | ||
| 680 | this_cpu); | ||
| 681 | printk(KERN_CRIT "CPU[%d]: Error mask [ ", this_cpu); | ||
| 682 | for_each_cpu_mask(i, error_mask) | ||
| 683 | printk("%d ", i); | ||
| 684 | printk("]\n"); | ||
| 685 | return; | ||
| 686 | |||
| 687 | fatal_mondo_timeout: | ||
| 688 | local_irq_restore(flags); | ||
| 689 | printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " | ||
| 690 | " progress after %d retries.\n", | ||
| 691 | this_cpu, retries); | ||
| 692 | goto dump_cpu_list_and_out; | ||
| 693 | |||
| 694 | fatal_mondo_error: | ||
| 695 | local_irq_restore(flags); | ||
| 696 | printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", | ||
| 697 | this_cpu, status); | ||
| 698 | printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " | ||
| 699 | "mondo_block_pa(%lx)\n", | ||
| 700 | this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa); | ||
| 701 | |||
| 702 | dump_cpu_list_and_out: | ||
| 703 | printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu); | ||
| 704 | for (i = 0; i < cnt; i++) | ||
| 705 | printk("%u ", cpu_list[i]); | ||
| 706 | printk("]\n"); | ||
| 707 | } | ||
| 708 | |||
| 547 | /* Send cross call to all processors mentioned in MASK | 709 | /* Send cross call to all processors mentioned in MASK |
| 548 | * except self. | 710 | * except self. |
| 549 | */ | 711 | */ |
| @@ -557,8 +719,10 @@ static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 d | |||
| 557 | 719 | ||
| 558 | if (tlb_type == spitfire) | 720 | if (tlb_type == spitfire) |
| 559 | spitfire_xcall_deliver(data0, data1, data2, mask); | 721 | spitfire_xcall_deliver(data0, data1, data2, mask); |
| 560 | else | 722 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) |
| 561 | cheetah_xcall_deliver(data0, data1, data2, mask); | 723 | cheetah_xcall_deliver(data0, data1, data2, mask); |
| 724 | else | ||
| 725 | hypervisor_xcall_deliver(data0, data1, data2, mask); | ||
| 562 | /* NOTE: Caller runs local copy on master. */ | 726 | /* NOTE: Caller runs local copy on master. */ |
| 563 | 727 | ||
| 564 | put_cpu(); | 728 | put_cpu(); |
| @@ -594,16 +758,13 @@ extern unsigned long xcall_call_function; | |||
| 594 | * You must not call this function with disabled interrupts or from a | 758 | * You must not call this function with disabled interrupts or from a |
| 595 | * hardware interrupt handler or from a bottom half handler. | 759 | * hardware interrupt handler or from a bottom half handler. |
| 596 | */ | 760 | */ |
| 597 | int smp_call_function(void (*func)(void *info), void *info, | 761 | static int smp_call_function_mask(void (*func)(void *info), void *info, |
| 598 | int nonatomic, int wait) | 762 | int nonatomic, int wait, cpumask_t mask) |
| 599 | { | 763 | { |
| 600 | struct call_data_struct data; | 764 | struct call_data_struct data; |
| 601 | int cpus = num_online_cpus() - 1; | 765 | int cpus; |
| 602 | long timeout; | 766 | long timeout; |
| 603 | 767 | ||
| 604 | if (!cpus) | ||
| 605 | return 0; | ||
| 606 | |||
| 607 | /* Can deadlock when called with interrupts disabled */ | 768 | /* Can deadlock when called with interrupts disabled */ |
| 608 | WARN_ON(irqs_disabled()); | 769 | WARN_ON(irqs_disabled()); |
| 609 | 770 | ||
| @@ -614,9 +775,14 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
| 614 | 775 | ||
| 615 | spin_lock(&call_lock); | 776 | spin_lock(&call_lock); |
| 616 | 777 | ||
| 778 | cpu_clear(smp_processor_id(), mask); | ||
| 779 | cpus = cpus_weight(mask); | ||
| 780 | if (!cpus) | ||
| 781 | goto out_unlock; | ||
| 782 | |||
| 617 | call_data = &data; | 783 | call_data = &data; |
| 618 | 784 | ||
| 619 | smp_cross_call(&xcall_call_function, 0, 0, 0); | 785 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); |
| 620 | 786 | ||
| 621 | /* | 787 | /* |
| 622 | * Wait for other cpus to complete function or at | 788 | * Wait for other cpus to complete function or at |
| @@ -630,18 +796,25 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
| 630 | udelay(1); | 796 | udelay(1); |
| 631 | } | 797 | } |
| 632 | 798 | ||
| 799 | out_unlock: | ||
| 633 | spin_unlock(&call_lock); | 800 | spin_unlock(&call_lock); |
| 634 | 801 | ||
| 635 | return 0; | 802 | return 0; |
| 636 | 803 | ||
| 637 | out_timeout: | 804 | out_timeout: |
| 638 | spin_unlock(&call_lock); | 805 | spin_unlock(&call_lock); |
| 639 | printk("XCALL: Remote cpus not responding, ncpus=%ld finished=%ld\n", | 806 | printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n", |
| 640 | (long) num_online_cpus() - 1L, | 807 | cpus, atomic_read(&data.finished)); |
| 641 | (long) atomic_read(&data.finished)); | ||
| 642 | return 0; | 808 | return 0; |
| 643 | } | 809 | } |
| 644 | 810 | ||
| 811 | int smp_call_function(void (*func)(void *info), void *info, | ||
| 812 | int nonatomic, int wait) | ||
| 813 | { | ||
| 814 | return smp_call_function_mask(func, info, nonatomic, wait, | ||
| 815 | cpu_online_map); | ||
| 816 | } | ||
| 817 | |||
| 645 | void smp_call_function_client(int irq, struct pt_regs *regs) | 818 | void smp_call_function_client(int irq, struct pt_regs *regs) |
| 646 | { | 819 | { |
| 647 | void (*func) (void *info) = call_data->func; | 820 | void (*func) (void *info) = call_data->func; |
| @@ -659,13 +832,25 @@ void smp_call_function_client(int irq, struct pt_regs *regs) | |||
| 659 | } | 832 | } |
| 660 | } | 833 | } |
| 661 | 834 | ||
| 835 | static void tsb_sync(void *info) | ||
| 836 | { | ||
| 837 | struct mm_struct *mm = info; | ||
| 838 | |||
| 839 | if (current->active_mm == mm) | ||
| 840 | tsb_context_switch(mm); | ||
| 841 | } | ||
| 842 | |||
| 843 | void smp_tsb_sync(struct mm_struct *mm) | ||
| 844 | { | ||
| 845 | smp_call_function_mask(tsb_sync, mm, 0, 1, mm->cpu_vm_mask); | ||
| 846 | } | ||
| 847 | |||
| 662 | extern unsigned long xcall_flush_tlb_mm; | 848 | extern unsigned long xcall_flush_tlb_mm; |
| 663 | extern unsigned long xcall_flush_tlb_pending; | 849 | extern unsigned long xcall_flush_tlb_pending; |
| 664 | extern unsigned long xcall_flush_tlb_kernel_range; | 850 | extern unsigned long xcall_flush_tlb_kernel_range; |
| 665 | extern unsigned long xcall_flush_tlb_all_spitfire; | ||
| 666 | extern unsigned long xcall_flush_tlb_all_cheetah; | ||
| 667 | extern unsigned long xcall_report_regs; | 851 | extern unsigned long xcall_report_regs; |
| 668 | extern unsigned long xcall_receive_signal; | 852 | extern unsigned long xcall_receive_signal; |
| 853 | extern unsigned long xcall_new_mmu_context_version; | ||
| 669 | 854 | ||
| 670 | #ifdef DCACHE_ALIASING_POSSIBLE | 855 | #ifdef DCACHE_ALIASING_POSSIBLE |
| 671 | extern unsigned long xcall_flush_dcache_page_cheetah; | 856 | extern unsigned long xcall_flush_dcache_page_cheetah; |
| @@ -693,11 +878,17 @@ static __inline__ void __local_flush_dcache_page(struct page *page) | |||
| 693 | void smp_flush_dcache_page_impl(struct page *page, int cpu) | 878 | void smp_flush_dcache_page_impl(struct page *page, int cpu) |
| 694 | { | 879 | { |
| 695 | cpumask_t mask = cpumask_of_cpu(cpu); | 880 | cpumask_t mask = cpumask_of_cpu(cpu); |
| 696 | int this_cpu = get_cpu(); | 881 | int this_cpu; |
| 882 | |||
| 883 | if (tlb_type == hypervisor) | ||
| 884 | return; | ||
| 697 | 885 | ||
| 698 | #ifdef CONFIG_DEBUG_DCFLUSH | 886 | #ifdef CONFIG_DEBUG_DCFLUSH |
| 699 | atomic_inc(&dcpage_flushes); | 887 | atomic_inc(&dcpage_flushes); |
| 700 | #endif | 888 | #endif |
| 889 | |||
| 890 | this_cpu = get_cpu(); | ||
| 891 | |||
| 701 | if (cpu == this_cpu) { | 892 | if (cpu == this_cpu) { |
| 702 | __local_flush_dcache_page(page); | 893 | __local_flush_dcache_page(page); |
| 703 | } else if (cpu_online(cpu)) { | 894 | } else if (cpu_online(cpu)) { |
| @@ -713,7 +904,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) | |||
| 713 | __pa(pg_addr), | 904 | __pa(pg_addr), |
| 714 | (u64) pg_addr, | 905 | (u64) pg_addr, |
| 715 | mask); | 906 | mask); |
| 716 | } else { | 907 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
| 717 | #ifdef DCACHE_ALIASING_POSSIBLE | 908 | #ifdef DCACHE_ALIASING_POSSIBLE |
| 718 | data0 = | 909 | data0 = |
| 719 | ((u64)&xcall_flush_dcache_page_cheetah); | 910 | ((u64)&xcall_flush_dcache_page_cheetah); |
| @@ -735,7 +926,12 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
| 735 | void *pg_addr = page_address(page); | 926 | void *pg_addr = page_address(page); |
| 736 | cpumask_t mask = cpu_online_map; | 927 | cpumask_t mask = cpu_online_map; |
| 737 | u64 data0; | 928 | u64 data0; |
| 738 | int this_cpu = get_cpu(); | 929 | int this_cpu; |
| 930 | |||
| 931 | if (tlb_type == hypervisor) | ||
| 932 | return; | ||
| 933 | |||
| 934 | this_cpu = get_cpu(); | ||
| 739 | 935 | ||
| 740 | cpu_clear(this_cpu, mask); | 936 | cpu_clear(this_cpu, mask); |
| 741 | 937 | ||
| @@ -752,7 +948,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
| 752 | __pa(pg_addr), | 948 | __pa(pg_addr), |
| 753 | (u64) pg_addr, | 949 | (u64) pg_addr, |
| 754 | mask); | 950 | mask); |
| 755 | } else { | 951 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
| 756 | #ifdef DCACHE_ALIASING_POSSIBLE | 952 | #ifdef DCACHE_ALIASING_POSSIBLE |
| 757 | data0 = ((u64)&xcall_flush_dcache_page_cheetah); | 953 | data0 = ((u64)&xcall_flush_dcache_page_cheetah); |
| 758 | cheetah_xcall_deliver(data0, | 954 | cheetah_xcall_deliver(data0, |
| @@ -769,38 +965,58 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
| 769 | put_cpu(); | 965 | put_cpu(); |
| 770 | } | 966 | } |
| 771 | 967 | ||
| 968 | static void __smp_receive_signal_mask(cpumask_t mask) | ||
| 969 | { | ||
| 970 | smp_cross_call_masked(&xcall_receive_signal, 0, 0, 0, mask); | ||
| 971 | } | ||
| 972 | |||
| 772 | void smp_receive_signal(int cpu) | 973 | void smp_receive_signal(int cpu) |
| 773 | { | 974 | { |
| 774 | cpumask_t mask = cpumask_of_cpu(cpu); | 975 | cpumask_t mask = cpumask_of_cpu(cpu); |
| 775 | 976 | ||
| 776 | if (cpu_online(cpu)) { | 977 | if (cpu_online(cpu)) |
| 777 | u64 data0 = (((u64)&xcall_receive_signal) & 0xffffffff); | 978 | __smp_receive_signal_mask(mask); |
| 778 | |||
| 779 | if (tlb_type == spitfire) | ||
| 780 | spitfire_xcall_deliver(data0, 0, 0, mask); | ||
| 781 | else | ||
| 782 | cheetah_xcall_deliver(data0, 0, 0, mask); | ||
| 783 | } | ||
| 784 | } | 979 | } |
| 785 | 980 | ||
| 786 | void smp_receive_signal_client(int irq, struct pt_regs *regs) | 981 | void smp_receive_signal_client(int irq, struct pt_regs *regs) |
| 787 | { | 982 | { |
| 788 | /* Just return, rtrap takes care of the rest. */ | ||
| 789 | clear_softint(1 << irq); | 983 | clear_softint(1 << irq); |
| 790 | } | 984 | } |
| 791 | 985 | ||
| 792 | void smp_report_regs(void) | 986 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) |
| 793 | { | 987 | { |
| 794 | smp_cross_call(&xcall_report_regs, 0, 0, 0); | 988 | struct mm_struct *mm; |
| 989 | unsigned long flags; | ||
| 990 | |||
| 991 | clear_softint(1 << irq); | ||
| 992 | |||
| 993 | /* See if we need to allocate a new TLB context because | ||
| 994 | * the version of the one we are using is now out of date. | ||
| 995 | */ | ||
| 996 | mm = current->active_mm; | ||
| 997 | if (unlikely(!mm || (mm == &init_mm))) | ||
| 998 | return; | ||
| 999 | |||
| 1000 | spin_lock_irqsave(&mm->context.lock, flags); | ||
| 1001 | |||
| 1002 | if (unlikely(!CTX_VALID(mm->context))) | ||
| 1003 | get_new_mmu_context(mm); | ||
| 1004 | |||
| 1005 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 1006 | |||
| 1007 | load_secondary_context(mm); | ||
| 1008 | __flush_tlb_mm(CTX_HWBITS(mm->context), | ||
| 1009 | SECONDARY_CONTEXT); | ||
| 795 | } | 1010 | } |
| 796 | 1011 | ||
| 797 | void smp_flush_tlb_all(void) | 1012 | void smp_new_mmu_context_version(void) |
| 798 | { | 1013 | { |
| 799 | if (tlb_type == spitfire) | 1014 | smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); |
| 800 | smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0); | 1015 | } |
| 801 | else | 1016 | |
| 802 | smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0); | 1017 | void smp_report_regs(void) |
| 803 | __flush_tlb_all(); | 1018 | { |
| 1019 | smp_cross_call(&xcall_report_regs, 0, 0, 0); | ||
| 804 | } | 1020 | } |
| 805 | 1021 | ||
| 806 | /* We know that the window frames of the user have been flushed | 1022 | /* We know that the window frames of the user have been flushed |
| @@ -944,24 +1160,19 @@ void smp_release(void) | |||
| 944 | * can service tlb flush xcalls... | 1160 | * can service tlb flush xcalls... |
| 945 | */ | 1161 | */ |
| 946 | extern void prom_world(int); | 1162 | extern void prom_world(int); |
| 947 | extern void save_alternate_globals(unsigned long *); | 1163 | |
| 948 | extern void restore_alternate_globals(unsigned long *); | ||
| 949 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) | 1164 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) |
| 950 | { | 1165 | { |
| 951 | unsigned long global_save[24]; | ||
| 952 | |||
| 953 | clear_softint(1 << irq); | 1166 | clear_softint(1 << irq); |
| 954 | 1167 | ||
| 955 | preempt_disable(); | 1168 | preempt_disable(); |
| 956 | 1169 | ||
| 957 | __asm__ __volatile__("flushw"); | 1170 | __asm__ __volatile__("flushw"); |
| 958 | save_alternate_globals(global_save); | ||
| 959 | prom_world(1); | 1171 | prom_world(1); |
| 960 | atomic_inc(&smp_capture_registry); | 1172 | atomic_inc(&smp_capture_registry); |
| 961 | membar_storeload_storestore(); | 1173 | membar_storeload_storestore(); |
| 962 | while (penguins_are_doing_time) | 1174 | while (penguins_are_doing_time) |
| 963 | rmb(); | 1175 | rmb(); |
| 964 | restore_alternate_globals(global_save); | ||
| 965 | atomic_dec(&smp_capture_registry); | 1176 | atomic_dec(&smp_capture_registry); |
| 966 | prom_world(0); | 1177 | prom_world(0); |
| 967 | 1178 | ||
| @@ -1082,6 +1293,8 @@ int setup_profiling_timer(unsigned int multiplier) | |||
| 1082 | /* Constrain the number of cpus to max_cpus. */ | 1293 | /* Constrain the number of cpus to max_cpus. */ |
| 1083 | void __init smp_prepare_cpus(unsigned int max_cpus) | 1294 | void __init smp_prepare_cpus(unsigned int max_cpus) |
| 1084 | { | 1295 | { |
| 1296 | int i; | ||
| 1297 | |||
| 1085 | if (num_possible_cpus() > max_cpus) { | 1298 | if (num_possible_cpus() > max_cpus) { |
| 1086 | int instance, mid; | 1299 | int instance, mid; |
| 1087 | 1300 | ||
| @@ -1096,6 +1309,20 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
| 1096 | } | 1309 | } |
| 1097 | } | 1310 | } |
| 1098 | 1311 | ||
| 1312 | for_each_cpu(i) { | ||
| 1313 | if (tlb_type == hypervisor) { | ||
| 1314 | int j; | ||
| 1315 | |||
| 1316 | /* XXX get this mapping from machine description */ | ||
| 1317 | for_each_cpu(j) { | ||
| 1318 | if ((j >> 2) == (i >> 2)) | ||
| 1319 | cpu_set(j, cpu_sibling_map[i]); | ||
| 1320 | } | ||
| 1321 | } else { | ||
| 1322 | cpu_set(i, cpu_sibling_map[i]); | ||
| 1323 | } | ||
| 1324 | } | ||
| 1325 | |||
| 1099 | smp_store_cpu_info(boot_cpu_id); | 1326 | smp_store_cpu_info(boot_cpu_id); |
| 1100 | } | 1327 | } |
| 1101 | 1328 | ||
| @@ -1117,12 +1344,15 @@ void __init smp_setup_cpu_possible_map(void) | |||
| 1117 | 1344 | ||
| 1118 | void __devinit smp_prepare_boot_cpu(void) | 1345 | void __devinit smp_prepare_boot_cpu(void) |
| 1119 | { | 1346 | { |
| 1120 | if (hard_smp_processor_id() >= NR_CPUS) { | 1347 | int cpu = hard_smp_processor_id(); |
| 1348 | |||
| 1349 | if (cpu >= NR_CPUS) { | ||
| 1121 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); | 1350 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); |
| 1122 | prom_halt(); | 1351 | prom_halt(); |
| 1123 | } | 1352 | } |
| 1124 | 1353 | ||
| 1125 | current_thread_info()->cpu = hard_smp_processor_id(); | 1354 | current_thread_info()->cpu = cpu; |
| 1355 | __local_per_cpu_offset = __per_cpu_offset(cpu); | ||
| 1126 | 1356 | ||
| 1127 | cpu_set(smp_processor_id(), cpu_online_map); | 1357 | cpu_set(smp_processor_id(), cpu_online_map); |
| 1128 | cpu_set(smp_processor_id(), phys_cpu_present_map); | 1358 | cpu_set(smp_processor_id(), phys_cpu_present_map); |
| @@ -1139,7 +1369,11 @@ int __devinit __cpu_up(unsigned int cpu) | |||
| 1139 | if (!cpu_isset(cpu, cpu_online_map)) { | 1369 | if (!cpu_isset(cpu, cpu_online_map)) { |
| 1140 | ret = -ENODEV; | 1370 | ret = -ENODEV; |
| 1141 | } else { | 1371 | } else { |
| 1142 | smp_synchronize_one_tick(cpu); | 1372 | /* On SUN4V, writes to %tick and %stick are |
| 1373 | * not allowed. | ||
| 1374 | */ | ||
| 1375 | if (tlb_type != hypervisor) | ||
| 1376 | smp_synchronize_one_tick(cpu); | ||
| 1143 | } | 1377 | } |
| 1144 | } | 1378 | } |
| 1145 | return ret; | 1379 | return ret; |
| @@ -1183,12 +1417,9 @@ void __init setup_per_cpu_areas(void) | |||
| 1183 | { | 1417 | { |
| 1184 | unsigned long goal, size, i; | 1418 | unsigned long goal, size, i; |
| 1185 | char *ptr; | 1419 | char *ptr; |
| 1186 | /* Created by linker magic */ | ||
| 1187 | extern char __per_cpu_start[], __per_cpu_end[]; | ||
| 1188 | 1420 | ||
| 1189 | /* Copy section for each CPU (we discard the original) */ | 1421 | /* Copy section for each CPU (we discard the original) */ |
| 1190 | goal = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE); | 1422 | goal = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); |
| 1191 | |||
| 1192 | #ifdef CONFIG_MODULES | 1423 | #ifdef CONFIG_MODULES |
| 1193 | if (goal < PERCPU_ENOUGH_ROOM) | 1424 | if (goal < PERCPU_ENOUGH_ROOM) |
| 1194 | goal = PERCPU_ENOUGH_ROOM; | 1425 | goal = PERCPU_ENOUGH_ROOM; |
| @@ -1197,31 +1428,10 @@ void __init setup_per_cpu_areas(void) | |||
| 1197 | for (size = 1UL; size < goal; size <<= 1UL) | 1428 | for (size = 1UL; size < goal; size <<= 1UL) |
| 1198 | __per_cpu_shift++; | 1429 | __per_cpu_shift++; |
| 1199 | 1430 | ||
| 1200 | /* Make sure the resulting __per_cpu_base value | 1431 | ptr = alloc_bootmem(size * NR_CPUS); |
| 1201 | * will fit in the 43-bit sign extended IMMU | ||
| 1202 | * TSB register. | ||
| 1203 | */ | ||
| 1204 | ptr = __alloc_bootmem(size * NR_CPUS, PAGE_SIZE, | ||
| 1205 | (unsigned long) __per_cpu_start); | ||
| 1206 | 1432 | ||
| 1207 | __per_cpu_base = ptr - __per_cpu_start; | 1433 | __per_cpu_base = ptr - __per_cpu_start; |
| 1208 | 1434 | ||
| 1209 | if ((__per_cpu_shift < PAGE_SHIFT) || | ||
| 1210 | (__per_cpu_base & ~PAGE_MASK) || | ||
| 1211 | (__per_cpu_base != (((long) __per_cpu_base << 20) >> 20))) { | ||
| 1212 | prom_printf("PER_CPU: Invalid layout, " | ||
| 1213 | "ptr[%p] shift[%lx] base[%lx]\n", | ||
| 1214 | ptr, __per_cpu_shift, __per_cpu_base); | ||
| 1215 | prom_halt(); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | for (i = 0; i < NR_CPUS; i++, ptr += size) | 1435 | for (i = 0; i < NR_CPUS; i++, ptr += size) |
| 1219 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | 1436 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); |
| 1220 | |||
| 1221 | /* Finally, load in the boot cpu's base value. | ||
| 1222 | * We abuse the IMMU TSB register for trap handler | ||
| 1223 | * entry and exit loading of %g5. That is why it | ||
| 1224 | * has to be page aligned. | ||
| 1225 | */ | ||
| 1226 | cpu_setup_percpu_base(hard_smp_processor_id()); | ||
| 1227 | } | 1437 | } |
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 3c06bfb92a8c..9914a17651b4 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c | |||
| @@ -95,9 +95,6 @@ extern int __ashrdi3(int, int); | |||
| 95 | 95 | ||
| 96 | extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs); | 96 | extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs); |
| 97 | 97 | ||
| 98 | extern unsigned long phys_base; | ||
| 99 | extern unsigned long pfn_base; | ||
| 100 | |||
| 101 | extern unsigned int sys_call_table[]; | 98 | extern unsigned int sys_call_table[]; |
| 102 | 99 | ||
| 103 | extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); | 100 | extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); |
| @@ -108,6 +105,14 @@ extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, | |||
| 108 | extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, | 105 | extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, |
| 109 | unsigned long *, unsigned long *, unsigned long *); | 106 | unsigned long *, unsigned long *, unsigned long *); |
| 110 | 107 | ||
| 108 | extern void xor_niagara_2(unsigned long, unsigned long *, unsigned long *); | ||
| 109 | extern void xor_niagara_3(unsigned long, unsigned long *, unsigned long *, | ||
| 110 | unsigned long *); | ||
| 111 | extern void xor_niagara_4(unsigned long, unsigned long *, unsigned long *, | ||
| 112 | unsigned long *, unsigned long *); | ||
| 113 | extern void xor_niagara_5(unsigned long, unsigned long *, unsigned long *, | ||
| 114 | unsigned long *, unsigned long *, unsigned long *); | ||
| 115 | |||
| 111 | /* Per-CPU information table */ | 116 | /* Per-CPU information table */ |
| 112 | EXPORT_PER_CPU_SYMBOL(__cpu_data); | 117 | EXPORT_PER_CPU_SYMBOL(__cpu_data); |
| 113 | 118 | ||
| @@ -241,10 +246,6 @@ EXPORT_SYMBOL(verify_compat_iovec); | |||
| 241 | #endif | 246 | #endif |
| 242 | 247 | ||
| 243 | EXPORT_SYMBOL(dump_fpu); | 248 | EXPORT_SYMBOL(dump_fpu); |
| 244 | EXPORT_SYMBOL(pte_alloc_one_kernel); | ||
| 245 | #ifndef CONFIG_SMP | ||
| 246 | EXPORT_SYMBOL(pgt_quicklists); | ||
| 247 | #endif | ||
| 248 | EXPORT_SYMBOL(put_fs_struct); | 249 | EXPORT_SYMBOL(put_fs_struct); |
| 249 | 250 | ||
| 250 | /* math-emu wants this */ | 251 | /* math-emu wants this */ |
| @@ -339,14 +340,10 @@ EXPORT_SYMBOL(copy_to_user_fixup); | |||
| 339 | EXPORT_SYMBOL(copy_from_user_fixup); | 340 | EXPORT_SYMBOL(copy_from_user_fixup); |
| 340 | EXPORT_SYMBOL(copy_in_user_fixup); | 341 | EXPORT_SYMBOL(copy_in_user_fixup); |
| 341 | EXPORT_SYMBOL(__strncpy_from_user); | 342 | EXPORT_SYMBOL(__strncpy_from_user); |
| 342 | EXPORT_SYMBOL(__bzero_noasi); | 343 | EXPORT_SYMBOL(__clear_user); |
| 343 | 344 | ||
| 344 | /* Various address conversion macros use this. */ | 345 | /* Various address conversion macros use this. */ |
| 345 | EXPORT_SYMBOL(phys_base); | ||
| 346 | EXPORT_SYMBOL(pfn_base); | ||
| 347 | EXPORT_SYMBOL(sparc64_valid_addr_bitmap); | 346 | EXPORT_SYMBOL(sparc64_valid_addr_bitmap); |
| 348 | EXPORT_SYMBOL(page_to_pfn); | ||
| 349 | EXPORT_SYMBOL(pfn_to_page); | ||
| 350 | 347 | ||
| 351 | /* No version information on this, heavily used in inline asm, | 348 | /* No version information on this, heavily used in inline asm, |
| 352 | * and will always be 'void __ret_efault(void)'. | 349 | * and will always be 'void __ret_efault(void)'. |
| @@ -392,4 +389,9 @@ EXPORT_SYMBOL(xor_vis_3); | |||
| 392 | EXPORT_SYMBOL(xor_vis_4); | 389 | EXPORT_SYMBOL(xor_vis_4); |
| 393 | EXPORT_SYMBOL(xor_vis_5); | 390 | EXPORT_SYMBOL(xor_vis_5); |
| 394 | 391 | ||
| 392 | EXPORT_SYMBOL(xor_niagara_2); | ||
| 393 | EXPORT_SYMBOL(xor_niagara_3); | ||
| 394 | EXPORT_SYMBOL(xor_niagara_4); | ||
| 395 | EXPORT_SYMBOL(xor_niagara_5); | ||
| 396 | |||
| 395 | EXPORT_SYMBOL(prom_palette); | 397 | EXPORT_SYMBOL(prom_palette); |
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S new file mode 100644 index 000000000000..b49a68bdda43 --- /dev/null +++ b/arch/sparc64/kernel/sun4v_ivec.S | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | /* sun4v_ivec.S: Sun4v interrupt vector handling. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <asm/cpudata.h> | ||
| 7 | #include <asm/intr_queue.h> | ||
| 8 | |||
| 9 | .text | ||
| 10 | .align 32 | ||
| 11 | |||
| 12 | sun4v_cpu_mondo: | ||
| 13 | /* Head offset in %g2, tail offset in %g4. | ||
| 14 | * If they are the same, no work. | ||
| 15 | */ | ||
| 16 | mov INTRQ_CPU_MONDO_HEAD, %g2 | ||
| 17 | ldxa [%g2] ASI_QUEUE, %g2 | ||
| 18 | mov INTRQ_CPU_MONDO_TAIL, %g4 | ||
| 19 | ldxa [%g4] ASI_QUEUE, %g4 | ||
| 20 | cmp %g2, %g4 | ||
| 21 | be,pn %xcc, sun4v_cpu_mondo_queue_empty | ||
| 22 | nop | ||
| 23 | |||
| 24 | /* Get &trap_block[smp_processor_id()] into %g3. */ | ||
| 25 | ldxa [%g0] ASI_SCRATCHPAD, %g3 | ||
| 26 | sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 | ||
| 27 | |||
| 28 | /* Get CPU mondo queue base phys address into %g7. */ | ||
| 29 | ldx [%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 | ||
| 30 | |||
| 31 | /* Now get the cross-call arguments and handler PC, same | ||
| 32 | * layout as sun4u: | ||
| 33 | * | ||
| 34 | * 1st 64-bit word: low half is 32-bit PC, put into %g3 and jmpl to it | ||
| 35 | * high half is context arg to MMU flushes, into %g5 | ||
| 36 | * 2nd 64-bit word: 64-bit arg, load into %g1 | ||
| 37 | * 3rd 64-bit word: 64-bit arg, load into %g7 | ||
| 38 | */ | ||
| 39 | ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 40 | add %g2, 0x8, %g2 | ||
| 41 | srlx %g3, 32, %g5 | ||
| 42 | ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g1 | ||
| 43 | add %g2, 0x8, %g2 | ||
| 44 | srl %g3, 0, %g3 | ||
| 45 | ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g7 | ||
| 46 | add %g2, 0x40 - 0x8 - 0x8, %g2 | ||
| 47 | |||
| 48 | /* Update queue head pointer. */ | ||
| 49 | sethi %hi(8192 - 1), %g4 | ||
| 50 | or %g4, %lo(8192 - 1), %g4 | ||
| 51 | and %g2, %g4, %g2 | ||
| 52 | |||
| 53 | mov INTRQ_CPU_MONDO_HEAD, %g4 | ||
| 54 | stxa %g2, [%g4] ASI_QUEUE | ||
| 55 | membar #Sync | ||
| 56 | |||
| 57 | jmpl %g3, %g0 | ||
| 58 | nop | ||
| 59 | |||
| 60 | sun4v_cpu_mondo_queue_empty: | ||
| 61 | retry | ||
| 62 | |||
| 63 | sun4v_dev_mondo: | ||
| 64 | /* Head offset in %g2, tail offset in %g4. */ | ||
| 65 | mov INTRQ_DEVICE_MONDO_HEAD, %g2 | ||
| 66 | ldxa [%g2] ASI_QUEUE, %g2 | ||
| 67 | mov INTRQ_DEVICE_MONDO_TAIL, %g4 | ||
| 68 | ldxa [%g4] ASI_QUEUE, %g4 | ||
| 69 | cmp %g2, %g4 | ||
| 70 | be,pn %xcc, sun4v_dev_mondo_queue_empty | ||
| 71 | nop | ||
| 72 | |||
| 73 | /* Get &trap_block[smp_processor_id()] into %g3. */ | ||
| 74 | ldxa [%g0] ASI_SCRATCHPAD, %g3 | ||
| 75 | sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 | ||
| 76 | |||
| 77 | /* Get DEV mondo queue base phys address into %g5. */ | ||
| 78 | ldx [%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5 | ||
| 79 | |||
| 80 | /* Load IVEC into %g3. */ | ||
| 81 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 82 | add %g2, 0x40, %g2 | ||
| 83 | |||
| 84 | /* XXX There can be a full 64-byte block of data here. | ||
| 85 | * XXX This is how we can get at MSI vector data. | ||
| 86 | * XXX Current we do not capture this, but when we do we'll | ||
| 87 | * XXX need to add a 64-byte storage area in the struct ino_bucket | ||
| 88 | * XXX or the struct irq_desc. | ||
| 89 | */ | ||
| 90 | |||
| 91 | /* Update queue head pointer, this frees up some registers. */ | ||
| 92 | sethi %hi(8192 - 1), %g4 | ||
| 93 | or %g4, %lo(8192 - 1), %g4 | ||
| 94 | and %g2, %g4, %g2 | ||
| 95 | |||
| 96 | mov INTRQ_DEVICE_MONDO_HEAD, %g4 | ||
| 97 | stxa %g2, [%g4] ASI_QUEUE | ||
| 98 | membar #Sync | ||
| 99 | |||
| 100 | /* Get &__irq_work[smp_processor_id()] into %g1. */ | ||
| 101 | TRAP_LOAD_IRQ_WORK(%g1, %g4) | ||
| 102 | |||
| 103 | /* Get &ivector_table[IVEC] into %g4. */ | ||
| 104 | sethi %hi(ivector_table), %g4 | ||
| 105 | sllx %g3, 5, %g3 | ||
| 106 | or %g4, %lo(ivector_table), %g4 | ||
| 107 | add %g4, %g3, %g4 | ||
| 108 | |||
| 109 | /* Load IRQ %pil into %g5. */ | ||
| 110 | ldub [%g4 + 0x04], %g5 | ||
| 111 | |||
| 112 | /* Insert ivector_table[] entry into __irq_work[] queue. */ | ||
| 113 | sllx %g5, 2, %g3 | ||
| 114 | lduw [%g1 + %g3], %g2 /* g2 = irq_work(cpu, pil) */ | ||
| 115 | stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */ | ||
| 116 | stw %g4, [%g1 + %g3] /* irq_work(cpu, pil) = bucket */ | ||
| 117 | |||
| 118 | /* Signal the interrupt by setting (1 << pil) in %softint. */ | ||
| 119 | mov 1, %g2 | ||
| 120 | sllx %g2, %g5, %g2 | ||
| 121 | wr %g2, 0x0, %set_softint | ||
| 122 | |||
| 123 | sun4v_dev_mondo_queue_empty: | ||
| 124 | retry | ||
| 125 | |||
| 126 | sun4v_res_mondo: | ||
| 127 | /* Head offset in %g2, tail offset in %g4. */ | ||
| 128 | mov INTRQ_RESUM_MONDO_HEAD, %g2 | ||
| 129 | ldxa [%g2] ASI_QUEUE, %g2 | ||
| 130 | mov INTRQ_RESUM_MONDO_TAIL, %g4 | ||
| 131 | ldxa [%g4] ASI_QUEUE, %g4 | ||
| 132 | cmp %g2, %g4 | ||
| 133 | be,pn %xcc, sun4v_res_mondo_queue_empty | ||
| 134 | nop | ||
| 135 | |||
| 136 | /* Get &trap_block[smp_processor_id()] into %g3. */ | ||
| 137 | ldxa [%g0] ASI_SCRATCHPAD, %g3 | ||
| 138 | sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 | ||
| 139 | |||
| 140 | /* Get RES mondo queue base phys address into %g5. */ | ||
| 141 | ldx [%g3 + TRAP_PER_CPU_RESUM_MONDO_PA], %g5 | ||
| 142 | |||
| 143 | /* Get RES kernel buffer base phys address into %g7. */ | ||
| 144 | ldx [%g3 + TRAP_PER_CPU_RESUM_KBUF_PA], %g7 | ||
| 145 | |||
| 146 | /* If the first word is non-zero, queue is full. */ | ||
| 147 | ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g1 | ||
| 148 | brnz,pn %g1, sun4v_res_mondo_queue_full | ||
| 149 | nop | ||
| 150 | |||
| 151 | /* Remember this entry's offset in %g1. */ | ||
| 152 | mov %g2, %g1 | ||
| 153 | |||
| 154 | /* Copy 64-byte queue entry into kernel buffer. */ | ||
| 155 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 156 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 157 | add %g2, 0x08, %g2 | ||
| 158 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 159 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 160 | add %g2, 0x08, %g2 | ||
| 161 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 162 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 163 | add %g2, 0x08, %g2 | ||
| 164 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 165 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 166 | add %g2, 0x08, %g2 | ||
| 167 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 168 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 169 | add %g2, 0x08, %g2 | ||
| 170 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 171 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 172 | add %g2, 0x08, %g2 | ||
| 173 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 174 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 175 | add %g2, 0x08, %g2 | ||
| 176 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 177 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 178 | add %g2, 0x08, %g2 | ||
| 179 | |||
| 180 | /* Update queue head pointer. */ | ||
| 181 | sethi %hi(8192 - 1), %g4 | ||
| 182 | or %g4, %lo(8192 - 1), %g4 | ||
| 183 | and %g2, %g4, %g2 | ||
| 184 | |||
| 185 | mov INTRQ_RESUM_MONDO_HEAD, %g4 | ||
| 186 | stxa %g2, [%g4] ASI_QUEUE | ||
| 187 | membar #Sync | ||
| 188 | |||
| 189 | /* Disable interrupts and save register state so we can call | ||
| 190 | * C code. The etrap handling will leave %g4 in %l4 for us | ||
| 191 | * when it's done. | ||
| 192 | */ | ||
| 193 | rdpr %pil, %g2 | ||
| 194 | wrpr %g0, 15, %pil | ||
| 195 | mov %g1, %g4 | ||
| 196 | ba,pt %xcc, etrap_irq | ||
| 197 | rd %pc, %g7 | ||
| 198 | |||
| 199 | /* Log the event. */ | ||
| 200 | add %sp, PTREGS_OFF, %o0 | ||
| 201 | call sun4v_resum_error | ||
| 202 | mov %l4, %o1 | ||
| 203 | |||
| 204 | /* Return from trap. */ | ||
| 205 | ba,pt %xcc, rtrap_irq | ||
| 206 | nop | ||
| 207 | |||
| 208 | sun4v_res_mondo_queue_empty: | ||
| 209 | retry | ||
| 210 | |||
| 211 | sun4v_res_mondo_queue_full: | ||
| 212 | /* The queue is full, consolidate our damage by setting | ||
| 213 | * the head equal to the tail. We'll just trap again otherwise. | ||
| 214 | * Call C code to log the event. | ||
| 215 | */ | ||
| 216 | mov INTRQ_RESUM_MONDO_HEAD, %g2 | ||
| 217 | stxa %g4, [%g2] ASI_QUEUE | ||
| 218 | membar #Sync | ||
| 219 | |||
| 220 | rdpr %pil, %g2 | ||
| 221 | wrpr %g0, 15, %pil | ||
| 222 | ba,pt %xcc, etrap_irq | ||
| 223 | rd %pc, %g7 | ||
| 224 | |||
| 225 | call sun4v_resum_overflow | ||
| 226 | add %sp, PTREGS_OFF, %o0 | ||
| 227 | |||
| 228 | ba,pt %xcc, rtrap_irq | ||
| 229 | nop | ||
| 230 | |||
| 231 | sun4v_nonres_mondo: | ||
| 232 | /* Head offset in %g2, tail offset in %g4. */ | ||
| 233 | mov INTRQ_NONRESUM_MONDO_HEAD, %g2 | ||
| 234 | ldxa [%g2] ASI_QUEUE, %g2 | ||
| 235 | mov INTRQ_NONRESUM_MONDO_TAIL, %g4 | ||
| 236 | ldxa [%g4] ASI_QUEUE, %g4 | ||
| 237 | cmp %g2, %g4 | ||
| 238 | be,pn %xcc, sun4v_nonres_mondo_queue_empty | ||
| 239 | nop | ||
| 240 | |||
| 241 | /* Get &trap_block[smp_processor_id()] into %g3. */ | ||
| 242 | ldxa [%g0] ASI_SCRATCHPAD, %g3 | ||
| 243 | sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 | ||
| 244 | |||
| 245 | /* Get RES mondo queue base phys address into %g5. */ | ||
| 246 | ldx [%g3 + TRAP_PER_CPU_NONRESUM_MONDO_PA], %g5 | ||
| 247 | |||
| 248 | /* Get RES kernel buffer base phys address into %g7. */ | ||
| 249 | ldx [%g3 + TRAP_PER_CPU_NONRESUM_KBUF_PA], %g7 | ||
| 250 | |||
| 251 | /* If the first word is non-zero, queue is full. */ | ||
| 252 | ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g1 | ||
| 253 | brnz,pn %g1, sun4v_nonres_mondo_queue_full | ||
| 254 | nop | ||
| 255 | |||
| 256 | /* Remember this entry's offset in %g1. */ | ||
| 257 | mov %g2, %g1 | ||
| 258 | |||
| 259 | /* Copy 64-byte queue entry into kernel buffer. */ | ||
| 260 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 261 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 262 | add %g2, 0x08, %g2 | ||
| 263 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 264 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 265 | add %g2, 0x08, %g2 | ||
| 266 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 267 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 268 | add %g2, 0x08, %g2 | ||
| 269 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 270 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 271 | add %g2, 0x08, %g2 | ||
| 272 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 273 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 274 | add %g2, 0x08, %g2 | ||
| 275 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 276 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 277 | add %g2, 0x08, %g2 | ||
| 278 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 279 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 280 | add %g2, 0x08, %g2 | ||
| 281 | ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 | ||
| 282 | stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC | ||
| 283 | add %g2, 0x08, %g2 | ||
| 284 | |||
| 285 | /* Update queue head pointer. */ | ||
| 286 | sethi %hi(8192 - 1), %g4 | ||
| 287 | or %g4, %lo(8192 - 1), %g4 | ||
| 288 | and %g2, %g4, %g2 | ||
| 289 | |||
| 290 | mov INTRQ_NONRESUM_MONDO_HEAD, %g4 | ||
| 291 | stxa %g2, [%g4] ASI_QUEUE | ||
| 292 | membar #Sync | ||
| 293 | |||
| 294 | /* Disable interrupts and save register state so we can call | ||
| 295 | * C code. The etrap handling will leave %g4 in %l4 for us | ||
| 296 | * when it's done. | ||
| 297 | */ | ||
| 298 | rdpr %pil, %g2 | ||
| 299 | wrpr %g0, 15, %pil | ||
| 300 | mov %g1, %g4 | ||
| 301 | ba,pt %xcc, etrap_irq | ||
| 302 | rd %pc, %g7 | ||
| 303 | |||
| 304 | /* Log the event. */ | ||
| 305 | add %sp, PTREGS_OFF, %o0 | ||
| 306 | call sun4v_nonresum_error | ||
| 307 | mov %l4, %o1 | ||
| 308 | |||
| 309 | /* Return from trap. */ | ||
| 310 | ba,pt %xcc, rtrap_irq | ||
| 311 | nop | ||
| 312 | |||
| 313 | sun4v_nonres_mondo_queue_empty: | ||
| 314 | retry | ||
| 315 | |||
| 316 | sun4v_nonres_mondo_queue_full: | ||
| 317 | /* The queue is full, consolidate our damage by setting | ||
| 318 | * the head equal to the tail. We'll just trap again otherwise. | ||
| 319 | * Call C code to log the event. | ||
| 320 | */ | ||
| 321 | mov INTRQ_NONRESUM_MONDO_HEAD, %g2 | ||
| 322 | stxa %g4, [%g2] ASI_QUEUE | ||
| 323 | membar #Sync | ||
| 324 | |||
| 325 | rdpr %pil, %g2 | ||
| 326 | wrpr %g0, 15, %pil | ||
| 327 | ba,pt %xcc, etrap_irq | ||
| 328 | rd %pc, %g7 | ||
| 329 | |||
| 330 | call sun4v_nonresum_overflow | ||
| 331 | add %sp, PTREGS_OFF, %o0 | ||
| 332 | |||
| 333 | ba,pt %xcc, rtrap_irq | ||
| 334 | nop | ||
diff --git a/arch/sparc64/kernel/sun4v_tlb_miss.S b/arch/sparc64/kernel/sun4v_tlb_miss.S new file mode 100644 index 000000000000..ab23ddb7116e --- /dev/null +++ b/arch/sparc64/kernel/sun4v_tlb_miss.S | |||
| @@ -0,0 +1,421 @@ | |||
| 1 | /* sun4v_tlb_miss.S: Sun4v TLB miss handlers. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | .text | ||
| 7 | .align 32 | ||
| 8 | |||
| 9 | /* Load ITLB fault information into VADDR and CTX, using BASE. */ | ||
| 10 | #define LOAD_ITLB_INFO(BASE, VADDR, CTX) \ | ||
| 11 | ldx [BASE + HV_FAULT_I_ADDR_OFFSET], VADDR; \ | ||
| 12 | ldx [BASE + HV_FAULT_I_CTX_OFFSET], CTX; | ||
| 13 | |||
| 14 | /* Load DTLB fault information into VADDR and CTX, using BASE. */ | ||
| 15 | #define LOAD_DTLB_INFO(BASE, VADDR, CTX) \ | ||
| 16 | ldx [BASE + HV_FAULT_D_ADDR_OFFSET], VADDR; \ | ||
| 17 | ldx [BASE + HV_FAULT_D_CTX_OFFSET], CTX; | ||
| 18 | |||
| 19 | /* DEST = (VADDR >> 22) | ||
| 20 | * | ||
| 21 | * Branch to ZERO_CTX_LABEL if context is zero. | ||
| 22 | */ | ||
| 23 | #define COMPUTE_TAG_TARGET(DEST, VADDR, CTX, ZERO_CTX_LABEL) \ | ||
| 24 | srlx VADDR, 22, DEST; \ | ||
| 25 | brz,pn CTX, ZERO_CTX_LABEL; \ | ||
| 26 | nop; | ||
| 27 | |||
| 28 | /* Create TSB pointer. This is something like: | ||
| 29 | * | ||
| 30 | * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL; | ||
| 31 | * tsb_base = tsb_reg & ~0x7UL; | ||
| 32 | * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask); | ||
| 33 | * tsb_ptr = tsb_base + (tsb_index * 16); | ||
| 34 | */ | ||
| 35 | #define COMPUTE_TSB_PTR(TSB_PTR, VADDR, TMP1, TMP2) \ | ||
| 36 | and TSB_PTR, 0x7, TMP1; \ | ||
| 37 | mov 512, TMP2; \ | ||
| 38 | andn TSB_PTR, 0x7, TSB_PTR; \ | ||
| 39 | sllx TMP2, TMP1, TMP2; \ | ||
| 40 | srlx VADDR, PAGE_SHIFT, TMP1; \ | ||
| 41 | sub TMP2, 1, TMP2; \ | ||
| 42 | and TMP1, TMP2, TMP1; \ | ||
| 43 | sllx TMP1, 4, TMP1; \ | ||
| 44 | add TSB_PTR, TMP1, TSB_PTR; | ||
| 45 | |||
| 46 | sun4v_itlb_miss: | ||
| 47 | /* Load MMU Miss base into %g2. */ | ||
| 48 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 49 | |||
| 50 | /* Load UTSB reg into %g1. */ | ||
| 51 | mov SCRATCHPAD_UTSBREG1, %g1 | ||
| 52 | ldxa [%g1] ASI_SCRATCHPAD, %g1 | ||
| 53 | |||
| 54 | LOAD_ITLB_INFO(%g2, %g4, %g5) | ||
| 55 | COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_itlb_4v) | ||
| 56 | COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7) | ||
| 57 | |||
| 58 | /* Load TSB tag/pte into %g2/%g3 and compare the tag. */ | ||
| 59 | ldda [%g1] ASI_QUAD_LDD_PHYS_4V, %g2 | ||
| 60 | cmp %g2, %g6 | ||
| 61 | bne,a,pn %xcc, tsb_miss_page_table_walk | ||
| 62 | mov FAULT_CODE_ITLB, %g3 | ||
| 63 | andcc %g3, _PAGE_EXEC_4V, %g0 | ||
| 64 | be,a,pn %xcc, tsb_do_fault | ||
| 65 | mov FAULT_CODE_ITLB, %g3 | ||
| 66 | |||
| 67 | /* We have a valid entry, make hypervisor call to load | ||
| 68 | * I-TLB and return from trap. | ||
| 69 | * | ||
| 70 | * %g3: PTE | ||
| 71 | * %g4: vaddr | ||
| 72 | */ | ||
| 73 | sun4v_itlb_load: | ||
| 74 | ldxa [%g0] ASI_SCRATCHPAD, %g6 | ||
| 75 | mov %o0, %g1 ! save %o0 | ||
| 76 | mov %o1, %g2 ! save %o1 | ||
| 77 | mov %o2, %g5 ! save %o2 | ||
| 78 | mov %o3, %g7 ! save %o3 | ||
| 79 | mov %g4, %o0 ! vaddr | ||
| 80 | ldx [%g6 + HV_FAULT_I_CTX_OFFSET], %o1 ! ctx | ||
| 81 | mov %g3, %o2 ! PTE | ||
| 82 | mov HV_MMU_IMMU, %o3 ! flags | ||
| 83 | ta HV_MMU_MAP_ADDR_TRAP | ||
| 84 | brnz,pn %o0, sun4v_itlb_error | ||
| 85 | mov %g2, %o1 ! restore %o1 | ||
| 86 | mov %g1, %o0 ! restore %o0 | ||
| 87 | mov %g5, %o2 ! restore %o2 | ||
| 88 | mov %g7, %o3 ! restore %o3 | ||
| 89 | |||
| 90 | retry | ||
| 91 | |||
| 92 | sun4v_dtlb_miss: | ||
| 93 | /* Load MMU Miss base into %g2. */ | ||
| 94 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 95 | |||
| 96 | /* Load UTSB reg into %g1. */ | ||
| 97 | mov SCRATCHPAD_UTSBREG1, %g1 | ||
| 98 | ldxa [%g1] ASI_SCRATCHPAD, %g1 | ||
| 99 | |||
| 100 | LOAD_DTLB_INFO(%g2, %g4, %g5) | ||
| 101 | COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_dtlb_4v) | ||
| 102 | COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7) | ||
| 103 | |||
| 104 | /* Load TSB tag/pte into %g2/%g3 and compare the tag. */ | ||
| 105 | ldda [%g1] ASI_QUAD_LDD_PHYS_4V, %g2 | ||
| 106 | cmp %g2, %g6 | ||
| 107 | bne,a,pn %xcc, tsb_miss_page_table_walk | ||
| 108 | mov FAULT_CODE_DTLB, %g3 | ||
| 109 | |||
| 110 | /* We have a valid entry, make hypervisor call to load | ||
| 111 | * D-TLB and return from trap. | ||
| 112 | * | ||
| 113 | * %g3: PTE | ||
| 114 | * %g4: vaddr | ||
| 115 | */ | ||
| 116 | sun4v_dtlb_load: | ||
| 117 | ldxa [%g0] ASI_SCRATCHPAD, %g6 | ||
| 118 | mov %o0, %g1 ! save %o0 | ||
| 119 | mov %o1, %g2 ! save %o1 | ||
| 120 | mov %o2, %g5 ! save %o2 | ||
| 121 | mov %o3, %g7 ! save %o3 | ||
| 122 | mov %g4, %o0 ! vaddr | ||
| 123 | ldx [%g6 + HV_FAULT_D_CTX_OFFSET], %o1 ! ctx | ||
| 124 | mov %g3, %o2 ! PTE | ||
| 125 | mov HV_MMU_DMMU, %o3 ! flags | ||
| 126 | ta HV_MMU_MAP_ADDR_TRAP | ||
| 127 | brnz,pn %o0, sun4v_dtlb_error | ||
| 128 | mov %g2, %o1 ! restore %o1 | ||
| 129 | mov %g1, %o0 ! restore %o0 | ||
| 130 | mov %g5, %o2 ! restore %o2 | ||
| 131 | mov %g7, %o3 ! restore %o3 | ||
| 132 | |||
| 133 | retry | ||
| 134 | |||
| 135 | sun4v_dtlb_prot: | ||
| 136 | SET_GL(1) | ||
| 137 | |||
| 138 | /* Load MMU Miss base into %g5. */ | ||
| 139 | ldxa [%g0] ASI_SCRATCHPAD, %g5 | ||
| 140 | |||
| 141 | ldx [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5 | ||
| 142 | rdpr %tl, %g1 | ||
| 143 | cmp %g1, 1 | ||
| 144 | bgu,pn %xcc, winfix_trampoline | ||
| 145 | nop | ||
| 146 | ba,pt %xcc, sparc64_realfault_common | ||
| 147 | mov FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4 | ||
| 148 | |||
| 149 | /* Called from trap table: | ||
| 150 | * %g4: vaddr | ||
| 151 | * %g5: context | ||
| 152 | * %g6: TAG TARGET | ||
| 153 | */ | ||
| 154 | sun4v_itsb_miss: | ||
| 155 | mov SCRATCHPAD_UTSBREG1, %g1 | ||
| 156 | ldxa [%g1] ASI_SCRATCHPAD, %g1 | ||
| 157 | brz,pn %g5, kvmap_itlb_4v | ||
| 158 | mov FAULT_CODE_ITLB, %g3 | ||
| 159 | ba,a,pt %xcc, sun4v_tsb_miss_common | ||
| 160 | |||
| 161 | /* Called from trap table: | ||
| 162 | * %g4: vaddr | ||
| 163 | * %g5: context | ||
| 164 | * %g6: TAG TARGET | ||
| 165 | */ | ||
| 166 | sun4v_dtsb_miss: | ||
| 167 | mov SCRATCHPAD_UTSBREG1, %g1 | ||
| 168 | ldxa [%g1] ASI_SCRATCHPAD, %g1 | ||
| 169 | brz,pn %g5, kvmap_dtlb_4v | ||
| 170 | mov FAULT_CODE_DTLB, %g3 | ||
| 171 | |||
| 172 | /* fallthrough */ | ||
| 173 | |||
| 174 | /* Create TSB pointer into %g1. This is something like: | ||
| 175 | * | ||
| 176 | * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL; | ||
| 177 | * tsb_base = tsb_reg & ~0x7UL; | ||
| 178 | * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask); | ||
| 179 | * tsb_ptr = tsb_base + (tsb_index * 16); | ||
| 180 | */ | ||
| 181 | sun4v_tsb_miss_common: | ||
| 182 | COMPUTE_TSB_PTR(%g1, %g4, %g5, %g7) | ||
| 183 | |||
| 184 | /* Branch directly to page table lookup. We have SCRATCHPAD_MMU_MISS | ||
| 185 | * still in %g2, so it's quite trivial to get at the PGD PHYS value | ||
| 186 | * so we can preload it into %g7. | ||
| 187 | */ | ||
| 188 | sub %g2, TRAP_PER_CPU_FAULT_INFO, %g2 | ||
| 189 | ba,pt %xcc, tsb_miss_page_table_walk_sun4v_fastpath | ||
| 190 | ldx [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7 | ||
| 191 | |||
| 192 | sun4v_itlb_error: | ||
| 193 | sethi %hi(sun4v_err_itlb_vaddr), %g1 | ||
| 194 | stx %g4, [%g1 + %lo(sun4v_err_itlb_vaddr)] | ||
| 195 | sethi %hi(sun4v_err_itlb_ctx), %g1 | ||
| 196 | ldxa [%g0] ASI_SCRATCHPAD, %g6 | ||
| 197 | ldx [%g6 + HV_FAULT_I_CTX_OFFSET], %o1 | ||
| 198 | stx %o1, [%g1 + %lo(sun4v_err_itlb_ctx)] | ||
| 199 | sethi %hi(sun4v_err_itlb_pte), %g1 | ||
| 200 | stx %g3, [%g1 + %lo(sun4v_err_itlb_pte)] | ||
| 201 | sethi %hi(sun4v_err_itlb_error), %g1 | ||
| 202 | stx %o0, [%g1 + %lo(sun4v_err_itlb_error)] | ||
| 203 | |||
| 204 | rdpr %tl, %g4 | ||
| 205 | cmp %g4, 1 | ||
| 206 | ble,pt %icc, 1f | ||
| 207 | sethi %hi(2f), %g7 | ||
| 208 | ba,pt %xcc, etraptl1 | ||
| 209 | or %g7, %lo(2f), %g7 | ||
| 210 | |||
| 211 | 1: ba,pt %xcc, etrap | ||
| 212 | 2: or %g7, %lo(2b), %g7 | ||
| 213 | call sun4v_itlb_error_report | ||
| 214 | add %sp, PTREGS_OFF, %o0 | ||
| 215 | |||
| 216 | /* NOTREACHED */ | ||
| 217 | |||
| 218 | sun4v_dtlb_error: | ||
| 219 | sethi %hi(sun4v_err_dtlb_vaddr), %g1 | ||
| 220 | stx %g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)] | ||
| 221 | sethi %hi(sun4v_err_dtlb_ctx), %g1 | ||
| 222 | ldxa [%g0] ASI_SCRATCHPAD, %g6 | ||
| 223 | ldx [%g6 + HV_FAULT_D_CTX_OFFSET], %o1 | ||
| 224 | stx %o1, [%g1 + %lo(sun4v_err_dtlb_ctx)] | ||
| 225 | sethi %hi(sun4v_err_dtlb_pte), %g1 | ||
| 226 | stx %g3, [%g1 + %lo(sun4v_err_dtlb_pte)] | ||
| 227 | sethi %hi(sun4v_err_dtlb_error), %g1 | ||
| 228 | stx %o0, [%g1 + %lo(sun4v_err_dtlb_error)] | ||
| 229 | |||
| 230 | rdpr %tl, %g4 | ||
| 231 | cmp %g4, 1 | ||
| 232 | ble,pt %icc, 1f | ||
| 233 | sethi %hi(2f), %g7 | ||
| 234 | ba,pt %xcc, etraptl1 | ||
| 235 | or %g7, %lo(2f), %g7 | ||
| 236 | |||
| 237 | 1: ba,pt %xcc, etrap | ||
| 238 | 2: or %g7, %lo(2b), %g7 | ||
| 239 | call sun4v_dtlb_error_report | ||
| 240 | add %sp, PTREGS_OFF, %o0 | ||
| 241 | |||
| 242 | /* NOTREACHED */ | ||
| 243 | |||
| 244 | /* Instruction Access Exception, tl0. */ | ||
| 245 | sun4v_iacc: | ||
| 246 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 247 | ldx [%g2 + HV_FAULT_I_TYPE_OFFSET], %g3 | ||
| 248 | ldx [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4 | ||
| 249 | ldx [%g2 + HV_FAULT_I_CTX_OFFSET], %g5 | ||
| 250 | sllx %g3, 16, %g3 | ||
| 251 | or %g5, %g3, %g5 | ||
| 252 | ba,pt %xcc, etrap | ||
| 253 | rd %pc, %g7 | ||
| 254 | mov %l4, %o1 | ||
| 255 | mov %l5, %o2 | ||
| 256 | call sun4v_insn_access_exception | ||
| 257 | add %sp, PTREGS_OFF, %o0 | ||
| 258 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 259 | |||
| 260 | /* Instruction Access Exception, tl1. */ | ||
| 261 | sun4v_iacc_tl1: | ||
| 262 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 263 | ldx [%g2 + HV_FAULT_I_TYPE_OFFSET], %g3 | ||
| 264 | ldx [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4 | ||
| 265 | ldx [%g2 + HV_FAULT_I_CTX_OFFSET], %g5 | ||
| 266 | sllx %g3, 16, %g3 | ||
| 267 | or %g5, %g3, %g5 | ||
| 268 | ba,pt %xcc, etraptl1 | ||
| 269 | rd %pc, %g7 | ||
| 270 | mov %l4, %o1 | ||
| 271 | mov %l5, %o2 | ||
| 272 | call sun4v_insn_access_exception_tl1 | ||
| 273 | add %sp, PTREGS_OFF, %o0 | ||
| 274 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 275 | |||
| 276 | /* Data Access Exception, tl0. */ | ||
| 277 | sun4v_dacc: | ||
| 278 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 279 | ldx [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
| 280 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
| 281 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5 | ||
| 282 | sllx %g3, 16, %g3 | ||
| 283 | or %g5, %g3, %g5 | ||
| 284 | ba,pt %xcc, etrap | ||
| 285 | rd %pc, %g7 | ||
| 286 | mov %l4, %o1 | ||
| 287 | mov %l5, %o2 | ||
| 288 | call sun4v_data_access_exception | ||
| 289 | add %sp, PTREGS_OFF, %o0 | ||
| 290 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 291 | |||
| 292 | /* Data Access Exception, tl1. */ | ||
| 293 | sun4v_dacc_tl1: | ||
| 294 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 295 | ldx [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
| 296 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
| 297 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5 | ||
| 298 | sllx %g3, 16, %g3 | ||
| 299 | or %g5, %g3, %g5 | ||
| 300 | ba,pt %xcc, etraptl1 | ||
| 301 | rd %pc, %g7 | ||
| 302 | mov %l4, %o1 | ||
| 303 | mov %l5, %o2 | ||
| 304 | call sun4v_data_access_exception_tl1 | ||
| 305 | add %sp, PTREGS_OFF, %o0 | ||
| 306 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 307 | |||
| 308 | /* Memory Address Unaligned. */ | ||
| 309 | sun4v_mna: | ||
| 310 | /* Window fixup? */ | ||
| 311 | rdpr %tl, %g2 | ||
| 312 | cmp %g2, 1 | ||
| 313 | ble,pt %icc, 1f | ||
| 314 | nop | ||
| 315 | |||
| 316 | SET_GL(1) | ||
| 317 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 318 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g5 | ||
| 319 | mov HV_FAULT_TYPE_UNALIGNED, %g3 | ||
| 320 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g4 | ||
| 321 | sllx %g3, 16, %g3 | ||
| 322 | or %g4, %g3, %g4 | ||
| 323 | ba,pt %xcc, winfix_mna | ||
| 324 | rdpr %tpc, %g3 | ||
| 325 | /* not reached */ | ||
| 326 | |||
| 327 | 1: ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 328 | mov HV_FAULT_TYPE_UNALIGNED, %g3 | ||
| 329 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
| 330 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5 | ||
| 331 | sllx %g3, 16, %g3 | ||
| 332 | or %g5, %g3, %g5 | ||
| 333 | |||
| 334 | ba,pt %xcc, etrap | ||
| 335 | rd %pc, %g7 | ||
| 336 | mov %l4, %o1 | ||
| 337 | mov %l5, %o2 | ||
| 338 | call sun4v_do_mna | ||
| 339 | add %sp, PTREGS_OFF, %o0 | ||
| 340 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 341 | |||
| 342 | /* Privileged Action. */ | ||
| 343 | sun4v_privact: | ||
| 344 | ba,pt %xcc, etrap | ||
| 345 | rd %pc, %g7 | ||
| 346 | call do_privact | ||
| 347 | add %sp, PTREGS_OFF, %o0 | ||
| 348 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 349 | |||
| 350 | /* Unaligned ldd float, tl0. */ | ||
| 351 | sun4v_lddfmna: | ||
| 352 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 353 | ldx [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
| 354 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
| 355 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5 | ||
| 356 | sllx %g3, 16, %g3 | ||
| 357 | or %g5, %g3, %g5 | ||
| 358 | ba,pt %xcc, etrap | ||
| 359 | rd %pc, %g7 | ||
| 360 | mov %l4, %o1 | ||
| 361 | mov %l5, %o2 | ||
| 362 | call handle_lddfmna | ||
| 363 | add %sp, PTREGS_OFF, %o0 | ||
| 364 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 365 | |||
| 366 | /* Unaligned std float, tl0. */ | ||
| 367 | sun4v_stdfmna: | ||
| 368 | ldxa [%g0] ASI_SCRATCHPAD, %g2 | ||
| 369 | ldx [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
| 370 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
| 371 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5 | ||
| 372 | sllx %g3, 16, %g3 | ||
| 373 | or %g5, %g3, %g5 | ||
| 374 | ba,pt %xcc, etrap | ||
| 375 | rd %pc, %g7 | ||
| 376 | mov %l4, %o1 | ||
| 377 | mov %l5, %o2 | ||
| 378 | call handle_stdfmna | ||
| 379 | add %sp, PTREGS_OFF, %o0 | ||
| 380 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 381 | |||
| 382 | #define BRANCH_ALWAYS 0x10680000 | ||
| 383 | #define NOP 0x01000000 | ||
| 384 | #define SUN4V_DO_PATCH(OLD, NEW) \ | ||
| 385 | sethi %hi(NEW), %g1; \ | ||
| 386 | or %g1, %lo(NEW), %g1; \ | ||
| 387 | sethi %hi(OLD), %g2; \ | ||
| 388 | or %g2, %lo(OLD), %g2; \ | ||
| 389 | sub %g1, %g2, %g1; \ | ||
| 390 | sethi %hi(BRANCH_ALWAYS), %g3; \ | ||
| 391 | sll %g1, 11, %g1; \ | ||
| 392 | srl %g1, 11 + 2, %g1; \ | ||
| 393 | or %g3, %lo(BRANCH_ALWAYS), %g3; \ | ||
| 394 | or %g3, %g1, %g3; \ | ||
| 395 | stw %g3, [%g2]; \ | ||
| 396 | sethi %hi(NOP), %g3; \ | ||
| 397 | or %g3, %lo(NOP), %g3; \ | ||
| 398 | stw %g3, [%g2 + 0x4]; \ | ||
| 399 | flush %g2; | ||
| 400 | |||
| 401 | .globl sun4v_patch_tlb_handlers | ||
| 402 | .type sun4v_patch_tlb_handlers,#function | ||
| 403 | sun4v_patch_tlb_handlers: | ||
| 404 | SUN4V_DO_PATCH(tl0_iamiss, sun4v_itlb_miss) | ||
| 405 | SUN4V_DO_PATCH(tl1_iamiss, sun4v_itlb_miss) | ||
| 406 | SUN4V_DO_PATCH(tl0_damiss, sun4v_dtlb_miss) | ||
| 407 | SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss) | ||
| 408 | SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot) | ||
| 409 | SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot) | ||
| 410 | SUN4V_DO_PATCH(tl0_iax, sun4v_iacc) | ||
| 411 | SUN4V_DO_PATCH(tl1_iax, sun4v_iacc_tl1) | ||
| 412 | SUN4V_DO_PATCH(tl0_dax, sun4v_dacc) | ||
| 413 | SUN4V_DO_PATCH(tl1_dax, sun4v_dacc_tl1) | ||
| 414 | SUN4V_DO_PATCH(tl0_mna, sun4v_mna) | ||
| 415 | SUN4V_DO_PATCH(tl1_mna, sun4v_mna) | ||
| 416 | SUN4V_DO_PATCH(tl0_lddfmna, sun4v_lddfmna) | ||
| 417 | SUN4V_DO_PATCH(tl0_stdfmna, sun4v_stdfmna) | ||
| 418 | SUN4V_DO_PATCH(tl0_privact, sun4v_privact) | ||
| 419 | retl | ||
| 420 | nop | ||
| 421 | .size sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers | ||
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 5f8c822a2b4a..7a869138c37f 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c | |||
| @@ -25,25 +25,93 @@ | |||
| 25 | #include <linux/syscalls.h> | 25 | #include <linux/syscalls.h> |
| 26 | #include <linux/ipc.h> | 26 | #include <linux/ipc.h> |
| 27 | #include <linux/personality.h> | 27 | #include <linux/personality.h> |
| 28 | #include <linux/random.h> | ||
| 28 | 29 | ||
| 29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
| 30 | #include <asm/ipc.h> | 31 | #include <asm/ipc.h> |
| 31 | #include <asm/utrap.h> | 32 | #include <asm/utrap.h> |
| 32 | #include <asm/perfctr.h> | 33 | #include <asm/perfctr.h> |
| 34 | #include <asm/a.out.h> | ||
| 33 | 35 | ||
| 34 | /* #define DEBUG_UNIMP_SYSCALL */ | 36 | /* #define DEBUG_UNIMP_SYSCALL */ |
| 35 | 37 | ||
| 36 | /* XXX Make this per-binary type, this way we can detect the type of | ||
| 37 | * XXX a binary. Every Sparc executable calls this very early on. | ||
| 38 | */ | ||
| 39 | asmlinkage unsigned long sys_getpagesize(void) | 38 | asmlinkage unsigned long sys_getpagesize(void) |
| 40 | { | 39 | { |
| 41 | return PAGE_SIZE; | 40 | return PAGE_SIZE; |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | #define COLOUR_ALIGN(addr,pgoff) \ | 43 | #define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL)) |
| 45 | ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ | 44 | #define VA_EXCLUDE_END (0xfffff80000000000UL + (1UL << 32UL)) |
| 46 | (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) | 45 | |
| 46 | /* Does addr --> addr+len fall within 4GB of the VA-space hole or | ||
| 47 | * overflow past the end of the 64-bit address space? | ||
| 48 | */ | ||
| 49 | static inline int invalid_64bit_range(unsigned long addr, unsigned long len) | ||
| 50 | { | ||
| 51 | unsigned long va_exclude_start, va_exclude_end; | ||
| 52 | |||
| 53 | va_exclude_start = VA_EXCLUDE_START; | ||
| 54 | va_exclude_end = VA_EXCLUDE_END; | ||
| 55 | |||
| 56 | if (unlikely(len >= va_exclude_start)) | ||
| 57 | return 1; | ||
| 58 | |||
| 59 | if (unlikely((addr + len) < addr)) | ||
| 60 | return 1; | ||
| 61 | |||
| 62 | if (unlikely((addr >= va_exclude_start && addr < va_exclude_end) || | ||
| 63 | ((addr + len) >= va_exclude_start && | ||
| 64 | (addr + len) < va_exclude_end))) | ||
| 65 | return 1; | ||
| 66 | |||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* Does start,end straddle the VA-space hole? */ | ||
| 71 | static inline int straddles_64bit_va_hole(unsigned long start, unsigned long end) | ||
| 72 | { | ||
| 73 | unsigned long va_exclude_start, va_exclude_end; | ||
| 74 | |||
| 75 | va_exclude_start = VA_EXCLUDE_START; | ||
| 76 | va_exclude_end = VA_EXCLUDE_END; | ||
| 77 | |||
| 78 | if (likely(start < va_exclude_start && end < va_exclude_start)) | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | if (likely(start >= va_exclude_end && end >= va_exclude_end)) | ||
| 82 | return 0; | ||
| 83 | |||
| 84 | return 1; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* These functions differ from the default implementations in | ||
| 88 | * mm/mmap.c in two ways: | ||
| 89 | * | ||
| 90 | * 1) For file backed MAP_SHARED mmap()'s we D-cache color align, | ||
| 91 | * for fixed such mappings we just validate what the user gave us. | ||
| 92 | * 2) For 64-bit tasks we avoid mapping anything within 4GB of | ||
| 93 | * the spitfire/niagara VA-hole. | ||
| 94 | */ | ||
| 95 | |||
| 96 | static inline unsigned long COLOUR_ALIGN(unsigned long addr, | ||
| 97 | unsigned long pgoff) | ||
| 98 | { | ||
| 99 | unsigned long base = (addr+SHMLBA-1)&~(SHMLBA-1); | ||
| 100 | unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1); | ||
| 101 | |||
| 102 | return base + off; | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr, | ||
| 106 | unsigned long pgoff) | ||
| 107 | { | ||
| 108 | unsigned long base = addr & ~(SHMLBA-1); | ||
| 109 | unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1); | ||
| 110 | |||
| 111 | if (base + off <= addr) | ||
| 112 | return base + off; | ||
| 113 | return base - off; | ||
| 114 | } | ||
| 47 | 115 | ||
| 48 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) | 116 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) |
| 49 | { | 117 | { |
| @@ -64,8 +132,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
| 64 | } | 132 | } |
| 65 | 133 | ||
| 66 | if (test_thread_flag(TIF_32BIT)) | 134 | if (test_thread_flag(TIF_32BIT)) |
| 67 | task_size = 0xf0000000UL; | 135 | task_size = STACK_TOP32; |
| 68 | if (len > task_size || len > -PAGE_OFFSET) | 136 | if (unlikely(len > task_size || len >= VA_EXCLUDE_START)) |
| 69 | return -ENOMEM; | 137 | return -ENOMEM; |
| 70 | 138 | ||
| 71 | do_color_align = 0; | 139 | do_color_align = 0; |
| @@ -84,11 +152,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
| 84 | return addr; | 152 | return addr; |
| 85 | } | 153 | } |
| 86 | 154 | ||
| 87 | if (len <= mm->cached_hole_size) { | 155 | if (len > mm->cached_hole_size) { |
| 156 | start_addr = addr = mm->free_area_cache; | ||
| 157 | } else { | ||
| 158 | start_addr = addr = TASK_UNMAPPED_BASE; | ||
| 88 | mm->cached_hole_size = 0; | 159 | mm->cached_hole_size = 0; |
| 89 | mm->free_area_cache = TASK_UNMAPPED_BASE; | ||
| 90 | } | 160 | } |
| 91 | start_addr = addr = mm->free_area_cache; | ||
| 92 | 161 | ||
| 93 | task_size -= len; | 162 | task_size -= len; |
| 94 | 163 | ||
| @@ -100,11 +169,12 @@ full_search: | |||
| 100 | 169 | ||
| 101 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | 170 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { |
| 102 | /* At this point: (!vma || addr < vma->vm_end). */ | 171 | /* At this point: (!vma || addr < vma->vm_end). */ |
| 103 | if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) { | 172 | if (addr < VA_EXCLUDE_START && |
| 104 | addr = PAGE_OFFSET; | 173 | (addr + len) >= VA_EXCLUDE_START) { |
| 105 | vma = find_vma(mm, PAGE_OFFSET); | 174 | addr = VA_EXCLUDE_END; |
| 175 | vma = find_vma(mm, VA_EXCLUDE_END); | ||
| 106 | } | 176 | } |
| 107 | if (task_size < addr) { | 177 | if (unlikely(task_size < addr)) { |
| 108 | if (start_addr != TASK_UNMAPPED_BASE) { | 178 | if (start_addr != TASK_UNMAPPED_BASE) { |
| 109 | start_addr = addr = TASK_UNMAPPED_BASE; | 179 | start_addr = addr = TASK_UNMAPPED_BASE; |
| 110 | mm->cached_hole_size = 0; | 180 | mm->cached_hole_size = 0; |
| @@ -112,7 +182,7 @@ full_search: | |||
| 112 | } | 182 | } |
| 113 | return -ENOMEM; | 183 | return -ENOMEM; |
| 114 | } | 184 | } |
| 115 | if (!vma || addr + len <= vma->vm_start) { | 185 | if (likely(!vma || addr + len <= vma->vm_start)) { |
| 116 | /* | 186 | /* |
| 117 | * Remember the place where we stopped the search: | 187 | * Remember the place where we stopped the search: |
| 118 | */ | 188 | */ |
| @@ -128,6 +198,121 @@ full_search: | |||
| 128 | } | 198 | } |
| 129 | } | 199 | } |
| 130 | 200 | ||
| 201 | unsigned long | ||
| 202 | arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | ||
| 203 | const unsigned long len, const unsigned long pgoff, | ||
| 204 | const unsigned long flags) | ||
| 205 | { | ||
| 206 | struct vm_area_struct *vma; | ||
| 207 | struct mm_struct *mm = current->mm; | ||
| 208 | unsigned long task_size = STACK_TOP32; | ||
| 209 | unsigned long addr = addr0; | ||
| 210 | int do_color_align; | ||
| 211 | |||
| 212 | /* This should only ever run for 32-bit processes. */ | ||
| 213 | BUG_ON(!test_thread_flag(TIF_32BIT)); | ||
| 214 | |||
| 215 | if (flags & MAP_FIXED) { | ||
| 216 | /* We do not accept a shared mapping if it would violate | ||
| 217 | * cache aliasing constraints. | ||
| 218 | */ | ||
| 219 | if ((flags & MAP_SHARED) && | ||
| 220 | ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) | ||
| 221 | return -EINVAL; | ||
| 222 | return addr; | ||
| 223 | } | ||
| 224 | |||
| 225 | if (unlikely(len > task_size)) | ||
| 226 | return -ENOMEM; | ||
| 227 | |||
| 228 | do_color_align = 0; | ||
| 229 | if (filp || (flags & MAP_SHARED)) | ||
| 230 | do_color_align = 1; | ||
| 231 | |||
| 232 | /* requesting a specific address */ | ||
| 233 | if (addr) { | ||
| 234 | if (do_color_align) | ||
| 235 | addr = COLOUR_ALIGN(addr, pgoff); | ||
| 236 | else | ||
| 237 | addr = PAGE_ALIGN(addr); | ||
| 238 | |||
| 239 | vma = find_vma(mm, addr); | ||
| 240 | if (task_size - len >= addr && | ||
| 241 | (!vma || addr + len <= vma->vm_start)) | ||
| 242 | return addr; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* check if free_area_cache is useful for us */ | ||
| 246 | if (len <= mm->cached_hole_size) { | ||
| 247 | mm->cached_hole_size = 0; | ||
| 248 | mm->free_area_cache = mm->mmap_base; | ||
| 249 | } | ||
| 250 | |||
| 251 | /* either no address requested or can't fit in requested address hole */ | ||
| 252 | addr = mm->free_area_cache; | ||
| 253 | if (do_color_align) { | ||
| 254 | unsigned long base = COLOUR_ALIGN_DOWN(addr-len, pgoff); | ||
| 255 | |||
| 256 | addr = base + len; | ||
| 257 | } | ||
| 258 | |||
| 259 | /* make sure it can fit in the remaining address space */ | ||
| 260 | if (likely(addr > len)) { | ||
| 261 | vma = find_vma(mm, addr-len); | ||
| 262 | if (!vma || addr <= vma->vm_start) { | ||
| 263 | /* remember the address as a hint for next time */ | ||
| 264 | return (mm->free_area_cache = addr-len); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | if (unlikely(mm->mmap_base < len)) | ||
| 269 | goto bottomup; | ||
| 270 | |||
| 271 | addr = mm->mmap_base-len; | ||
| 272 | if (do_color_align) | ||
| 273 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
| 274 | |||
| 275 | do { | ||
| 276 | /* | ||
| 277 | * Lookup failure means no vma is above this address, | ||
| 278 | * else if new region fits below vma->vm_start, | ||
| 279 | * return with success: | ||
| 280 | */ | ||
| 281 | vma = find_vma(mm, addr); | ||
| 282 | if (likely(!vma || addr+len <= vma->vm_start)) { | ||
| 283 | /* remember the address as a hint for next time */ | ||
| 284 | return (mm->free_area_cache = addr); | ||
| 285 | } | ||
| 286 | |||
| 287 | /* remember the largest hole we saw so far */ | ||
| 288 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
| 289 | mm->cached_hole_size = vma->vm_start - addr; | ||
| 290 | |||
| 291 | /* try just below the current vma->vm_start */ | ||
| 292 | addr = vma->vm_start-len; | ||
| 293 | if (do_color_align) | ||
| 294 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
| 295 | } while (likely(len < vma->vm_start)); | ||
| 296 | |||
| 297 | bottomup: | ||
| 298 | /* | ||
| 299 | * A failed mmap() very likely causes application failure, | ||
| 300 | * so fall back to the bottom-up function here. This scenario | ||
| 301 | * can happen with large stack limits and large mmap() | ||
| 302 | * allocations. | ||
| 303 | */ | ||
| 304 | mm->cached_hole_size = ~0UL; | ||
| 305 | mm->free_area_cache = TASK_UNMAPPED_BASE; | ||
| 306 | addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); | ||
| 307 | /* | ||
| 308 | * Restore the topdown base: | ||
| 309 | */ | ||
| 310 | mm->free_area_cache = mm->mmap_base; | ||
| 311 | mm->cached_hole_size = ~0UL; | ||
| 312 | |||
| 313 | return addr; | ||
| 314 | } | ||
| 315 | |||
| 131 | /* Try to align mapping such that we align it as much as possible. */ | 316 | /* Try to align mapping such that we align it as much as possible. */ |
| 132 | unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) | 317 | unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) |
| 133 | { | 318 | { |
| @@ -171,15 +356,57 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u | |||
| 171 | return addr; | 356 | return addr; |
| 172 | } | 357 | } |
| 173 | 358 | ||
| 359 | /* Essentially the same as PowerPC... */ | ||
| 360 | void arch_pick_mmap_layout(struct mm_struct *mm) | ||
| 361 | { | ||
| 362 | unsigned long random_factor = 0UL; | ||
| 363 | |||
| 364 | if (current->flags & PF_RANDOMIZE) { | ||
| 365 | random_factor = get_random_int(); | ||
| 366 | if (test_thread_flag(TIF_32BIT)) | ||
| 367 | random_factor &= ((1 * 1024 * 1024) - 1); | ||
| 368 | else | ||
| 369 | random_factor = ((random_factor << PAGE_SHIFT) & | ||
| 370 | 0xffffffffUL); | ||
| 371 | } | ||
| 372 | |||
| 373 | /* | ||
| 374 | * Fall back to the standard layout if the personality | ||
| 375 | * bit is set, or if the expected stack growth is unlimited: | ||
| 376 | */ | ||
| 377 | if (!test_thread_flag(TIF_32BIT) || | ||
| 378 | (current->personality & ADDR_COMPAT_LAYOUT) || | ||
| 379 | current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY || | ||
| 380 | sysctl_legacy_va_layout) { | ||
| 381 | mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; | ||
| 382 | mm->get_unmapped_area = arch_get_unmapped_area; | ||
| 383 | mm->unmap_area = arch_unmap_area; | ||
| 384 | } else { | ||
| 385 | /* We know it's 32-bit */ | ||
| 386 | unsigned long task_size = STACK_TOP32; | ||
| 387 | unsigned long gap; | ||
| 388 | |||
| 389 | gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; | ||
| 390 | if (gap < 128 * 1024 * 1024) | ||
| 391 | gap = 128 * 1024 * 1024; | ||
| 392 | if (gap > (task_size / 6 * 5)) | ||
| 393 | gap = (task_size / 6 * 5); | ||
| 394 | |||
| 395 | mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor); | ||
| 396 | mm->get_unmapped_area = arch_get_unmapped_area_topdown; | ||
| 397 | mm->unmap_area = arch_unmap_area_topdown; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 174 | asmlinkage unsigned long sparc_brk(unsigned long brk) | 401 | asmlinkage unsigned long sparc_brk(unsigned long brk) |
| 175 | { | 402 | { |
| 176 | /* People could try to be nasty and use ta 0x6d in 32bit programs */ | 403 | /* People could try to be nasty and use ta 0x6d in 32bit programs */ |
| 177 | if (test_thread_flag(TIF_32BIT) && | 404 | if (test_thread_flag(TIF_32BIT) && brk >= STACK_TOP32) |
| 178 | brk >= 0xf0000000UL) | ||
| 179 | return current->mm->brk; | 405 | return current->mm->brk; |
| 180 | 406 | ||
| 181 | if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET)) | 407 | if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk))) |
| 182 | return current->mm->brk; | 408 | return current->mm->brk; |
| 409 | |||
| 183 | return sys_brk(brk); | 410 | return sys_brk(brk); |
| 184 | } | 411 | } |
| 185 | 412 | ||
| @@ -340,13 +567,16 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, | |||
| 340 | retval = -EINVAL; | 567 | retval = -EINVAL; |
| 341 | 568 | ||
| 342 | if (test_thread_flag(TIF_32BIT)) { | 569 | if (test_thread_flag(TIF_32BIT)) { |
| 343 | if (len > 0xf0000000UL || | 570 | if (len >= STACK_TOP32) |
| 344 | ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) | 571 | goto out_putf; |
| 572 | |||
| 573 | if ((flags & MAP_FIXED) && addr > STACK_TOP32 - len) | ||
| 345 | goto out_putf; | 574 | goto out_putf; |
| 346 | } else { | 575 | } else { |
| 347 | if (len > -PAGE_OFFSET || | 576 | if (len >= VA_EXCLUDE_START) |
| 348 | ((flags & MAP_FIXED) && | 577 | goto out_putf; |
| 349 | addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) | 578 | |
| 579 | if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len)) | ||
| 350 | goto out_putf; | 580 | goto out_putf; |
| 351 | } | 581 | } |
| 352 | 582 | ||
| @@ -365,9 +595,9 @@ asmlinkage long sys64_munmap(unsigned long addr, size_t len) | |||
| 365 | { | 595 | { |
| 366 | long ret; | 596 | long ret; |
| 367 | 597 | ||
| 368 | if (len > -PAGE_OFFSET || | 598 | if (invalid_64bit_range(addr, len)) |
| 369 | (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) | ||
| 370 | return -EINVAL; | 599 | return -EINVAL; |
| 600 | |||
| 371 | down_write(¤t->mm->mmap_sem); | 601 | down_write(¤t->mm->mmap_sem); |
| 372 | ret = do_munmap(current->mm, addr, len); | 602 | ret = do_munmap(current->mm, addr, len); |
| 373 | up_write(¤t->mm->mmap_sem); | 603 | up_write(¤t->mm->mmap_sem); |
| @@ -384,18 +614,19 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, | |||
| 384 | { | 614 | { |
| 385 | struct vm_area_struct *vma; | 615 | struct vm_area_struct *vma; |
| 386 | unsigned long ret = -EINVAL; | 616 | unsigned long ret = -EINVAL; |
| 617 | |||
| 387 | if (test_thread_flag(TIF_32BIT)) | 618 | if (test_thread_flag(TIF_32BIT)) |
| 388 | goto out; | 619 | goto out; |
| 389 | if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET) | 620 | if (unlikely(new_len >= VA_EXCLUDE_START)) |
| 390 | goto out; | 621 | goto out; |
| 391 | if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) | 622 | if (unlikely(invalid_64bit_range(addr, old_len))) |
| 392 | goto out; | 623 | goto out; |
| 624 | |||
| 393 | down_write(¤t->mm->mmap_sem); | 625 | down_write(¤t->mm->mmap_sem); |
| 394 | if (flags & MREMAP_FIXED) { | 626 | if (flags & MREMAP_FIXED) { |
| 395 | if (new_addr < PAGE_OFFSET && | 627 | if (invalid_64bit_range(new_addr, new_len)) |
| 396 | new_addr + new_len > -PAGE_OFFSET) | ||
| 397 | goto out_sem; | 628 | goto out_sem; |
| 398 | } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { | 629 | } else if (invalid_64bit_range(addr, new_len)) { |
| 399 | unsigned long map_flags = 0; | 630 | unsigned long map_flags = 0; |
| 400 | struct file *file = NULL; | 631 | struct file *file = NULL; |
| 401 | 632 | ||
| @@ -554,12 +785,10 @@ asmlinkage long sys_utrap_install(utrap_entry_t type, | |||
| 554 | } | 785 | } |
| 555 | if (!current_thread_info()->utraps) { | 786 | if (!current_thread_info()->utraps) { |
| 556 | current_thread_info()->utraps = | 787 | current_thread_info()->utraps = |
| 557 | kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); | 788 | kzalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); |
| 558 | if (!current_thread_info()->utraps) | 789 | if (!current_thread_info()->utraps) |
| 559 | return -ENOMEM; | 790 | return -ENOMEM; |
| 560 | current_thread_info()->utraps[0] = 1; | 791 | current_thread_info()->utraps[0] = 1; |
| 561 | memset(current_thread_info()->utraps+1, 0, | ||
| 562 | UT_TRAP_INSTRUCTION_31*sizeof(long)); | ||
| 563 | } else { | 792 | } else { |
| 564 | if ((utrap_handler_t)current_thread_info()->utraps[type] != new_p && | 793 | if ((utrap_handler_t)current_thread_info()->utraps[type] != new_p && |
| 565 | current_thread_info()->utraps[0] > 1) { | 794 | current_thread_info()->utraps[0] > 1) { |
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 417727bd87ba..0e41df024489 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c | |||
| @@ -62,6 +62,7 @@ | |||
| 62 | #include <asm/fpumacro.h> | 62 | #include <asm/fpumacro.h> |
| 63 | #include <asm/semaphore.h> | 63 | #include <asm/semaphore.h> |
| 64 | #include <asm/mmu_context.h> | 64 | #include <asm/mmu_context.h> |
| 65 | #include <asm/a.out.h> | ||
| 65 | 66 | ||
| 66 | asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group) | 67 | asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group) |
| 67 | { | 68 | { |
| @@ -1039,15 +1040,15 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr, | |||
| 1039 | unsigned long ret = -EINVAL; | 1040 | unsigned long ret = -EINVAL; |
| 1040 | unsigned long new_addr = __new_addr; | 1041 | unsigned long new_addr = __new_addr; |
| 1041 | 1042 | ||
| 1042 | if (old_len > 0xf0000000UL || new_len > 0xf0000000UL) | 1043 | if (old_len > STACK_TOP32 || new_len > STACK_TOP32) |
| 1043 | goto out; | 1044 | goto out; |
| 1044 | if (addr > 0xf0000000UL - old_len) | 1045 | if (addr > STACK_TOP32 - old_len) |
| 1045 | goto out; | 1046 | goto out; |
| 1046 | down_write(¤t->mm->mmap_sem); | 1047 | down_write(¤t->mm->mmap_sem); |
| 1047 | if (flags & MREMAP_FIXED) { | 1048 | if (flags & MREMAP_FIXED) { |
| 1048 | if (new_addr > 0xf0000000UL - new_len) | 1049 | if (new_addr > STACK_TOP32 - new_len) |
| 1049 | goto out_sem; | 1050 | goto out_sem; |
| 1050 | } else if (addr > 0xf0000000UL - new_len) { | 1051 | } else if (addr > STACK_TOP32 - new_len) { |
| 1051 | unsigned long map_flags = 0; | 1052 | unsigned long map_flags = 0; |
| 1052 | struct file *file = NULL; | 1053 | struct file *file = NULL; |
| 1053 | 1054 | ||
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index a22930d62adf..7d61f1bfd3d3 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #include <linux/cpufreq.h> | 30 | #include <linux/cpufreq.h> |
| 31 | #include <linux/percpu.h> | 31 | #include <linux/percpu.h> |
| 32 | #include <linux/profile.h> | 32 | #include <linux/profile.h> |
| 33 | #include <linux/miscdevice.h> | ||
| 34 | #include <linux/rtc.h> | ||
| 33 | 35 | ||
| 34 | #include <asm/oplib.h> | 36 | #include <asm/oplib.h> |
| 35 | #include <asm/mostek.h> | 37 | #include <asm/mostek.h> |
| @@ -45,6 +47,7 @@ | |||
| 45 | #include <asm/smp.h> | 47 | #include <asm/smp.h> |
| 46 | #include <asm/sections.h> | 48 | #include <asm/sections.h> |
| 47 | #include <asm/cpudata.h> | 49 | #include <asm/cpudata.h> |
| 50 | #include <asm/uaccess.h> | ||
| 48 | 51 | ||
| 49 | DEFINE_SPINLOCK(mostek_lock); | 52 | DEFINE_SPINLOCK(mostek_lock); |
| 50 | DEFINE_SPINLOCK(rtc_lock); | 53 | DEFINE_SPINLOCK(rtc_lock); |
| @@ -193,16 +196,22 @@ struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations; | |||
| 193 | 196 | ||
| 194 | static void stick_init_tick(unsigned long offset) | 197 | static void stick_init_tick(unsigned long offset) |
| 195 | { | 198 | { |
| 196 | tick_disable_protection(); | 199 | /* Writes to the %tick and %stick register are not |
| 197 | 200 | * allowed on sun4v. The Hypervisor controls that | |
| 198 | /* Let the user get at STICK too. */ | 201 | * bit, per-strand. |
| 199 | __asm__ __volatile__( | 202 | */ |
| 200 | " rd %%asr24, %%g2\n" | 203 | if (tlb_type != hypervisor) { |
| 201 | " andn %%g2, %0, %%g2\n" | 204 | tick_disable_protection(); |
| 202 | " wr %%g2, 0, %%asr24" | 205 | |
| 203 | : /* no outputs */ | 206 | /* Let the user get at STICK too. */ |
| 204 | : "r" (TICK_PRIV_BIT) | 207 | __asm__ __volatile__( |
| 205 | : "g1", "g2"); | 208 | " rd %%asr24, %%g2\n" |
| 209 | " andn %%g2, %0, %%g2\n" | ||
| 210 | " wr %%g2, 0, %%asr24" | ||
| 211 | : /* no outputs */ | ||
| 212 | : "r" (TICK_PRIV_BIT) | ||
| 213 | : "g1", "g2"); | ||
| 214 | } | ||
| 206 | 215 | ||
| 207 | __asm__ __volatile__( | 216 | __asm__ __volatile__( |
| 208 | " rd %%asr24, %%g1\n" | 217 | " rd %%asr24, %%g1\n" |
| @@ -683,6 +692,83 @@ static void __init set_system_time(void) | |||
| 683 | } | 692 | } |
| 684 | } | 693 | } |
| 685 | 694 | ||
| 695 | /* davem suggests we keep this within the 4M locked kernel image */ | ||
| 696 | static u32 starfire_get_time(void) | ||
| 697 | { | ||
| 698 | static char obp_gettod[32]; | ||
| 699 | static u32 unix_tod; | ||
| 700 | |||
| 701 | sprintf(obp_gettod, "h# %08x unix-gettod", | ||
| 702 | (unsigned int) (long) &unix_tod); | ||
| 703 | prom_feval(obp_gettod); | ||
| 704 | |||
| 705 | return unix_tod; | ||
| 706 | } | ||
| 707 | |||
| 708 | static int starfire_set_time(u32 val) | ||
| 709 | { | ||
| 710 | /* Do nothing, time is set using the service processor | ||
| 711 | * console on this platform. | ||
| 712 | */ | ||
| 713 | return 0; | ||
| 714 | } | ||
| 715 | |||
| 716 | static u32 hypervisor_get_time(void) | ||
| 717 | { | ||
| 718 | register unsigned long func asm("%o5"); | ||
| 719 | register unsigned long arg0 asm("%o0"); | ||
| 720 | register unsigned long arg1 asm("%o1"); | ||
| 721 | int retries = 10000; | ||
| 722 | |||
| 723 | retry: | ||
| 724 | func = HV_FAST_TOD_GET; | ||
| 725 | arg0 = 0; | ||
| 726 | arg1 = 0; | ||
| 727 | __asm__ __volatile__("ta %6" | ||
| 728 | : "=&r" (func), "=&r" (arg0), "=&r" (arg1) | ||
| 729 | : "0" (func), "1" (arg0), "2" (arg1), | ||
| 730 | "i" (HV_FAST_TRAP)); | ||
| 731 | if (arg0 == HV_EOK) | ||
| 732 | return arg1; | ||
| 733 | if (arg0 == HV_EWOULDBLOCK) { | ||
| 734 | if (--retries > 0) { | ||
| 735 | udelay(100); | ||
| 736 | goto retry; | ||
| 737 | } | ||
| 738 | printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); | ||
| 739 | return 0; | ||
| 740 | } | ||
| 741 | printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); | ||
| 742 | return 0; | ||
| 743 | } | ||
| 744 | |||
| 745 | static int hypervisor_set_time(u32 secs) | ||
| 746 | { | ||
| 747 | register unsigned long func asm("%o5"); | ||
| 748 | register unsigned long arg0 asm("%o0"); | ||
| 749 | int retries = 10000; | ||
| 750 | |||
| 751 | retry: | ||
| 752 | func = HV_FAST_TOD_SET; | ||
| 753 | arg0 = secs; | ||
| 754 | __asm__ __volatile__("ta %4" | ||
| 755 | : "=&r" (func), "=&r" (arg0) | ||
| 756 | : "0" (func), "1" (arg0), | ||
| 757 | "i" (HV_FAST_TRAP)); | ||
| 758 | if (arg0 == HV_EOK) | ||
| 759 | return 0; | ||
| 760 | if (arg0 == HV_EWOULDBLOCK) { | ||
| 761 | if (--retries > 0) { | ||
| 762 | udelay(100); | ||
| 763 | goto retry; | ||
| 764 | } | ||
| 765 | printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); | ||
| 766 | return -EAGAIN; | ||
| 767 | } | ||
| 768 | printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); | ||
| 769 | return -EOPNOTSUPP; | ||
| 770 | } | ||
| 771 | |||
| 686 | void __init clock_probe(void) | 772 | void __init clock_probe(void) |
| 687 | { | 773 | { |
| 688 | struct linux_prom_registers clk_reg[2]; | 774 | struct linux_prom_registers clk_reg[2]; |
| @@ -702,14 +788,14 @@ void __init clock_probe(void) | |||
| 702 | 788 | ||
| 703 | 789 | ||
| 704 | if (this_is_starfire) { | 790 | if (this_is_starfire) { |
| 705 | /* davem suggests we keep this within the 4M locked kernel image */ | 791 | xtime.tv_sec = starfire_get_time(); |
| 706 | static char obp_gettod[256]; | 792 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
| 707 | static u32 unix_tod; | 793 | set_normalized_timespec(&wall_to_monotonic, |
| 708 | 794 | -xtime.tv_sec, -xtime.tv_nsec); | |
| 709 | sprintf(obp_gettod, "h# %08x unix-gettod", | 795 | return; |
| 710 | (unsigned int) (long) &unix_tod); | 796 | } |
| 711 | prom_feval(obp_gettod); | 797 | if (tlb_type == hypervisor) { |
| 712 | xtime.tv_sec = unix_tod; | 798 | xtime.tv_sec = hypervisor_get_time(); |
| 713 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 799 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
| 714 | set_normalized_timespec(&wall_to_monotonic, | 800 | set_normalized_timespec(&wall_to_monotonic, |
| 715 | -xtime.tv_sec, -xtime.tv_nsec); | 801 | -xtime.tv_sec, -xtime.tv_nsec); |
| @@ -981,11 +1067,10 @@ static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_reg | |||
| 981 | } | 1067 | } |
| 982 | 1068 | ||
| 983 | struct freq_table { | 1069 | struct freq_table { |
| 984 | unsigned long udelay_val_ref; | ||
| 985 | unsigned long clock_tick_ref; | 1070 | unsigned long clock_tick_ref; |
| 986 | unsigned int ref_freq; | 1071 | unsigned int ref_freq; |
| 987 | }; | 1072 | }; |
| 988 | static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 }; | 1073 | static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0 }; |
| 989 | 1074 | ||
| 990 | unsigned long sparc64_get_clock_tick(unsigned int cpu) | 1075 | unsigned long sparc64_get_clock_tick(unsigned int cpu) |
| 991 | { | 1076 | { |
| @@ -1007,16 +1092,11 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val | |||
| 1007 | 1092 | ||
| 1008 | if (!ft->ref_freq) { | 1093 | if (!ft->ref_freq) { |
| 1009 | ft->ref_freq = freq->old; | 1094 | ft->ref_freq = freq->old; |
| 1010 | ft->udelay_val_ref = cpu_data(cpu).udelay_val; | ||
| 1011 | ft->clock_tick_ref = cpu_data(cpu).clock_tick; | 1095 | ft->clock_tick_ref = cpu_data(cpu).clock_tick; |
| 1012 | } | 1096 | } |
| 1013 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || | 1097 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || |
| 1014 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || | 1098 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || |
| 1015 | (val == CPUFREQ_RESUMECHANGE)) { | 1099 | (val == CPUFREQ_RESUMECHANGE)) { |
| 1016 | cpu_data(cpu).udelay_val = | ||
| 1017 | cpufreq_scale(ft->udelay_val_ref, | ||
| 1018 | ft->ref_freq, | ||
| 1019 | freq->new); | ||
| 1020 | cpu_data(cpu).clock_tick = | 1100 | cpu_data(cpu).clock_tick = |
| 1021 | cpufreq_scale(ft->clock_tick_ref, | 1101 | cpufreq_scale(ft->clock_tick_ref, |
| 1022 | ft->ref_freq, | 1102 | ft->ref_freq, |
| @@ -1179,3 +1259,246 @@ static int set_rtc_mmss(unsigned long nowtime) | |||
| 1179 | return retval; | 1259 | return retval; |
| 1180 | } | 1260 | } |
| 1181 | } | 1261 | } |
| 1262 | |||
| 1263 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | ||
| 1264 | static unsigned char mini_rtc_status; /* bitmapped status byte. */ | ||
| 1265 | |||
| 1266 | /* months start at 0 now */ | ||
| 1267 | static unsigned char days_in_mo[] = | ||
| 1268 | {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
| 1269 | |||
| 1270 | #define FEBRUARY 2 | ||
| 1271 | #define STARTOFTIME 1970 | ||
| 1272 | #define SECDAY 86400L | ||
| 1273 | #define SECYR (SECDAY * 365) | ||
| 1274 | #define leapyear(year) ((year) % 4 == 0 && \ | ||
| 1275 | ((year) % 100 != 0 || (year) % 400 == 0)) | ||
| 1276 | #define days_in_year(a) (leapyear(a) ? 366 : 365) | ||
| 1277 | #define days_in_month(a) (month_days[(a) - 1]) | ||
| 1278 | |||
| 1279 | static int month_days[12] = { | ||
| 1280 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | ||
| 1281 | }; | ||
| 1282 | |||
| 1283 | /* | ||
| 1284 | * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) | ||
| 1285 | */ | ||
| 1286 | static void GregorianDay(struct rtc_time * tm) | ||
| 1287 | { | ||
| 1288 | int leapsToDate; | ||
| 1289 | int lastYear; | ||
| 1290 | int day; | ||
| 1291 | int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; | ||
| 1292 | |||
| 1293 | lastYear = tm->tm_year - 1; | ||
| 1294 | |||
| 1295 | /* | ||
| 1296 | * Number of leap corrections to apply up to end of last year | ||
| 1297 | */ | ||
| 1298 | leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; | ||
| 1299 | |||
| 1300 | /* | ||
| 1301 | * This year is a leap year if it is divisible by 4 except when it is | ||
| 1302 | * divisible by 100 unless it is divisible by 400 | ||
| 1303 | * | ||
| 1304 | * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was | ||
| 1305 | */ | ||
| 1306 | day = tm->tm_mon > 2 && leapyear(tm->tm_year); | ||
| 1307 | |||
| 1308 | day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + | ||
| 1309 | tm->tm_mday; | ||
| 1310 | |||
| 1311 | tm->tm_wday = day % 7; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | static void to_tm(int tim, struct rtc_time *tm) | ||
| 1315 | { | ||
| 1316 | register int i; | ||
| 1317 | register long hms, day; | ||
| 1318 | |||
| 1319 | day = tim / SECDAY; | ||
| 1320 | hms = tim % SECDAY; | ||
| 1321 | |||
| 1322 | /* Hours, minutes, seconds are easy */ | ||
| 1323 | tm->tm_hour = hms / 3600; | ||
| 1324 | tm->tm_min = (hms % 3600) / 60; | ||
| 1325 | tm->tm_sec = (hms % 3600) % 60; | ||
| 1326 | |||
| 1327 | /* Number of years in days */ | ||
| 1328 | for (i = STARTOFTIME; day >= days_in_year(i); i++) | ||
| 1329 | day -= days_in_year(i); | ||
| 1330 | tm->tm_year = i; | ||
| 1331 | |||
| 1332 | /* Number of months in days left */ | ||
| 1333 | if (leapyear(tm->tm_year)) | ||
| 1334 | days_in_month(FEBRUARY) = 29; | ||
| 1335 | for (i = 1; day >= days_in_month(i); i++) | ||
| 1336 | day -= days_in_month(i); | ||
| 1337 | days_in_month(FEBRUARY) = 28; | ||
| 1338 | tm->tm_mon = i; | ||
| 1339 | |||
| 1340 | /* Days are what is left over (+1) from all that. */ | ||
| 1341 | tm->tm_mday = day + 1; | ||
| 1342 | |||
| 1343 | /* | ||
| 1344 | * Determine the day of week | ||
| 1345 | */ | ||
| 1346 | GregorianDay(tm); | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | /* Both Starfire and SUN4V give us seconds since Jan 1st, 1970, | ||
| 1350 | * aka Unix time. So we have to convert to/from rtc_time. | ||
| 1351 | */ | ||
| 1352 | static inline void mini_get_rtc_time(struct rtc_time *time) | ||
| 1353 | { | ||
| 1354 | unsigned long flags; | ||
| 1355 | u32 seconds; | ||
| 1356 | |||
| 1357 | spin_lock_irqsave(&rtc_lock, flags); | ||
| 1358 | seconds = 0; | ||
| 1359 | if (this_is_starfire) | ||
| 1360 | seconds = starfire_get_time(); | ||
| 1361 | else if (tlb_type == hypervisor) | ||
| 1362 | seconds = hypervisor_get_time(); | ||
| 1363 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
| 1364 | |||
| 1365 | to_tm(seconds, time); | ||
| 1366 | time->tm_year -= 1900; | ||
| 1367 | time->tm_mon -= 1; | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | static inline int mini_set_rtc_time(struct rtc_time *time) | ||
| 1371 | { | ||
| 1372 | u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1, | ||
| 1373 | time->tm_mday, time->tm_hour, | ||
| 1374 | time->tm_min, time->tm_sec); | ||
| 1375 | unsigned long flags; | ||
| 1376 | int err; | ||
| 1377 | |||
| 1378 | spin_lock_irqsave(&rtc_lock, flags); | ||
| 1379 | err = -ENODEV; | ||
| 1380 | if (this_is_starfire) | ||
| 1381 | err = starfire_set_time(seconds); | ||
| 1382 | else if (tlb_type == hypervisor) | ||
| 1383 | err = hypervisor_set_time(seconds); | ||
| 1384 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
| 1385 | |||
| 1386 | return err; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | static int mini_rtc_ioctl(struct inode *inode, struct file *file, | ||
| 1390 | unsigned int cmd, unsigned long arg) | ||
| 1391 | { | ||
| 1392 | struct rtc_time wtime; | ||
| 1393 | void __user *argp = (void __user *)arg; | ||
| 1394 | |||
| 1395 | switch (cmd) { | ||
| 1396 | |||
| 1397 | case RTC_PLL_GET: | ||
| 1398 | return -EINVAL; | ||
| 1399 | |||
| 1400 | case RTC_PLL_SET: | ||
| 1401 | return -EINVAL; | ||
| 1402 | |||
| 1403 | case RTC_UIE_OFF: /* disable ints from RTC updates. */ | ||
| 1404 | return 0; | ||
| 1405 | |||
| 1406 | case RTC_UIE_ON: /* enable ints for RTC updates. */ | ||
| 1407 | return -EINVAL; | ||
| 1408 | |||
| 1409 | case RTC_RD_TIME: /* Read the time/date from RTC */ | ||
| 1410 | /* this doesn't get week-day, who cares */ | ||
| 1411 | memset(&wtime, 0, sizeof(wtime)); | ||
| 1412 | mini_get_rtc_time(&wtime); | ||
| 1413 | |||
| 1414 | return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0; | ||
| 1415 | |||
| 1416 | case RTC_SET_TIME: /* Set the RTC */ | ||
| 1417 | { | ||
| 1418 | int year; | ||
| 1419 | unsigned char leap_yr; | ||
| 1420 | |||
| 1421 | if (!capable(CAP_SYS_TIME)) | ||
| 1422 | return -EACCES; | ||
| 1423 | |||
| 1424 | if (copy_from_user(&wtime, argp, sizeof(wtime))) | ||
| 1425 | return -EFAULT; | ||
| 1426 | |||
| 1427 | year = wtime.tm_year + 1900; | ||
| 1428 | leap_yr = ((!(year % 4) && (year % 100)) || | ||
| 1429 | !(year % 400)); | ||
| 1430 | |||
| 1431 | if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1)) | ||
| 1432 | return -EINVAL; | ||
| 1433 | |||
| 1434 | if (wtime.tm_mday < 0 || wtime.tm_mday > | ||
| 1435 | (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr))) | ||
| 1436 | return -EINVAL; | ||
| 1437 | |||
| 1438 | if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || | ||
| 1439 | wtime.tm_min < 0 || wtime.tm_min >= 60 || | ||
| 1440 | wtime.tm_sec < 0 || wtime.tm_sec >= 60) | ||
| 1441 | return -EINVAL; | ||
| 1442 | |||
| 1443 | return mini_set_rtc_time(&wtime); | ||
| 1444 | } | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | return -EINVAL; | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | static int mini_rtc_open(struct inode *inode, struct file *file) | ||
| 1451 | { | ||
| 1452 | if (mini_rtc_status & RTC_IS_OPEN) | ||
| 1453 | return -EBUSY; | ||
| 1454 | |||
| 1455 | mini_rtc_status |= RTC_IS_OPEN; | ||
| 1456 | |||
| 1457 | return 0; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | static int mini_rtc_release(struct inode *inode, struct file *file) | ||
| 1461 | { | ||
| 1462 | mini_rtc_status &= ~RTC_IS_OPEN; | ||
| 1463 | return 0; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | |||
| 1467 | static struct file_operations mini_rtc_fops = { | ||
| 1468 | .owner = THIS_MODULE, | ||
| 1469 | .ioctl = mini_rtc_ioctl, | ||
| 1470 | .open = mini_rtc_open, | ||
| 1471 | .release = mini_rtc_release, | ||
| 1472 | }; | ||
| 1473 | |||
| 1474 | static struct miscdevice rtc_mini_dev = | ||
| 1475 | { | ||
| 1476 | .minor = RTC_MINOR, | ||
| 1477 | .name = "rtc", | ||
| 1478 | .fops = &mini_rtc_fops, | ||
| 1479 | }; | ||
| 1480 | |||
| 1481 | static int __init rtc_mini_init(void) | ||
| 1482 | { | ||
| 1483 | int retval; | ||
| 1484 | |||
| 1485 | if (tlb_type != hypervisor && !this_is_starfire) | ||
| 1486 | return -ENODEV; | ||
| 1487 | |||
| 1488 | printk(KERN_INFO "Mini RTC Driver\n"); | ||
| 1489 | |||
| 1490 | retval = misc_register(&rtc_mini_dev); | ||
| 1491 | if (retval < 0) | ||
| 1492 | return retval; | ||
| 1493 | |||
| 1494 | return 0; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static void __exit rtc_mini_exit(void) | ||
| 1498 | { | ||
| 1499 | misc_deregister(&rtc_mini_dev); | ||
| 1500 | } | ||
| 1501 | |||
| 1502 | |||
| 1503 | module_init(rtc_mini_init); | ||
| 1504 | module_exit(rtc_mini_exit); | ||
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index 9478551cb020..a4dc01a3d238 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
| 17 | #include <asm/thread_info.h> | 17 | #include <asm/thread_info.h> |
| 18 | #include <asm/mmu.h> | 18 | #include <asm/mmu.h> |
| 19 | #include <asm/hypervisor.h> | ||
| 20 | #include <asm/cpudata.h> | ||
| 19 | 21 | ||
| 20 | .data | 22 | .data |
| 21 | .align 8 | 23 | .align 8 |
| @@ -28,14 +30,19 @@ itlb_load: | |||
| 28 | dtlb_load: | 30 | dtlb_load: |
| 29 | .asciz "SUNW,dtlb-load" | 31 | .asciz "SUNW,dtlb-load" |
| 30 | 32 | ||
| 33 | /* XXX __cpuinit this thing XXX */ | ||
| 34 | #define TRAMP_STACK_SIZE 1024 | ||
| 35 | .align 16 | ||
| 36 | tramp_stack: | ||
| 37 | .skip TRAMP_STACK_SIZE | ||
| 38 | |||
| 31 | .text | 39 | .text |
| 32 | .align 8 | 40 | .align 8 |
| 33 | .globl sparc64_cpu_startup, sparc64_cpu_startup_end | 41 | .globl sparc64_cpu_startup, sparc64_cpu_startup_end |
| 34 | sparc64_cpu_startup: | 42 | sparc64_cpu_startup: |
| 35 | flushw | 43 | BRANCH_IF_SUN4V(g1, niagara_startup) |
| 36 | 44 | BRANCH_IF_CHEETAH_BASE(g1, g5, cheetah_startup) | |
| 37 | BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_startup) | 45 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1, g5, cheetah_plus_startup) |
| 38 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_startup) | ||
| 39 | 46 | ||
| 40 | ba,pt %xcc, spitfire_startup | 47 | ba,pt %xcc, spitfire_startup |
| 41 | nop | 48 | nop |
| @@ -55,6 +62,7 @@ cheetah_startup: | |||
| 55 | or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 | 62 | or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 |
| 56 | stxa %g5, [%g0] ASI_DCU_CONTROL_REG | 63 | stxa %g5, [%g0] ASI_DCU_CONTROL_REG |
| 57 | membar #Sync | 64 | membar #Sync |
| 65 | /* fallthru */ | ||
| 58 | 66 | ||
| 59 | cheetah_generic_startup: | 67 | cheetah_generic_startup: |
| 60 | mov TSB_EXTENSION_P, %g3 | 68 | mov TSB_EXTENSION_P, %g3 |
| @@ -70,7 +78,9 @@ cheetah_generic_startup: | |||
| 70 | stxa %g0, [%g3] ASI_DMMU | 78 | stxa %g0, [%g3] ASI_DMMU |
| 71 | stxa %g0, [%g3] ASI_IMMU | 79 | stxa %g0, [%g3] ASI_IMMU |
| 72 | membar #Sync | 80 | membar #Sync |
| 81 | /* fallthru */ | ||
| 73 | 82 | ||
| 83 | niagara_startup: | ||
| 74 | /* Disable STICK_INT interrupts. */ | 84 | /* Disable STICK_INT interrupts. */ |
| 75 | sethi %hi(0x80000000), %g5 | 85 | sethi %hi(0x80000000), %g5 |
| 76 | sllx %g5, 32, %g5 | 86 | sllx %g5, 32, %g5 |
| @@ -85,17 +95,17 @@ spitfire_startup: | |||
| 85 | membar #Sync | 95 | membar #Sync |
| 86 | 96 | ||
| 87 | startup_continue: | 97 | startup_continue: |
| 88 | wrpr %g0, 15, %pil | ||
| 89 | |||
| 90 | sethi %hi(0x80000000), %g2 | 98 | sethi %hi(0x80000000), %g2 |
| 91 | sllx %g2, 32, %g2 | 99 | sllx %g2, 32, %g2 |
| 92 | wr %g2, 0, %tick_cmpr | 100 | wr %g2, 0, %tick_cmpr |
| 93 | 101 | ||
| 102 | mov %o0, %l0 | ||
| 103 | |||
| 104 | BRANCH_IF_SUN4V(g1, niagara_lock_tlb) | ||
| 105 | |||
| 94 | /* Call OBP by hand to lock KERNBASE into i/d tlbs. | 106 | /* Call OBP by hand to lock KERNBASE into i/d tlbs. |
| 95 | * We lock 2 consequetive entries if we are 'bigkernel'. | 107 | * We lock 2 consequetive entries if we are 'bigkernel'. |
| 96 | */ | 108 | */ |
| 97 | mov %o0, %l0 | ||
| 98 | |||
| 99 | sethi %hi(prom_entry_lock), %g2 | 109 | sethi %hi(prom_entry_lock), %g2 |
| 100 | 1: ldstub [%g2 + %lo(prom_entry_lock)], %g1 | 110 | 1: ldstub [%g2 + %lo(prom_entry_lock)], %g1 |
| 101 | membar #StoreLoad | #StoreStore | 111 | membar #StoreLoad | #StoreStore |
| @@ -105,7 +115,6 @@ startup_continue: | |||
| 105 | sethi %hi(p1275buf), %g2 | 115 | sethi %hi(p1275buf), %g2 |
| 106 | or %g2, %lo(p1275buf), %g2 | 116 | or %g2, %lo(p1275buf), %g2 |
| 107 | ldx [%g2 + 0x10], %l2 | 117 | ldx [%g2 + 0x10], %l2 |
| 108 | mov %sp, %l1 | ||
| 109 | add %l2, -(192 + 128), %sp | 118 | add %l2, -(192 + 128), %sp |
| 110 | flushw | 119 | flushw |
| 111 | 120 | ||
| @@ -142,8 +151,7 @@ startup_continue: | |||
| 142 | 151 | ||
| 143 | sethi %hi(bigkernel), %g2 | 152 | sethi %hi(bigkernel), %g2 |
| 144 | lduw [%g2 + %lo(bigkernel)], %g2 | 153 | lduw [%g2 + %lo(bigkernel)], %g2 |
| 145 | cmp %g2, 0 | 154 | brz,pt %g2, do_dtlb |
| 146 | be,pt %icc, do_dtlb | ||
| 147 | nop | 155 | nop |
| 148 | 156 | ||
| 149 | sethi %hi(call_method), %g2 | 157 | sethi %hi(call_method), %g2 |
| @@ -214,8 +222,7 @@ do_dtlb: | |||
| 214 | 222 | ||
| 215 | sethi %hi(bigkernel), %g2 | 223 | sethi %hi(bigkernel), %g2 |
| 216 | lduw [%g2 + %lo(bigkernel)], %g2 | 224 | lduw [%g2 + %lo(bigkernel)], %g2 |
| 217 | cmp %g2, 0 | 225 | brz,pt %g2, do_unlock |
| 218 | be,pt %icc, do_unlock | ||
| 219 | nop | 226 | nop |
| 220 | 227 | ||
| 221 | sethi %hi(call_method), %g2 | 228 | sethi %hi(call_method), %g2 |
| @@ -257,99 +264,180 @@ do_unlock: | |||
| 257 | stb %g0, [%g2 + %lo(prom_entry_lock)] | 264 | stb %g0, [%g2 + %lo(prom_entry_lock)] |
| 258 | membar #StoreStore | #StoreLoad | 265 | membar #StoreStore | #StoreLoad |
| 259 | 266 | ||
| 260 | mov %l1, %sp | 267 | ba,pt %xcc, after_lock_tlb |
| 261 | flushw | 268 | nop |
| 269 | |||
| 270 | niagara_lock_tlb: | ||
| 271 | mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 | ||
| 272 | sethi %hi(KERNBASE), %o0 | ||
| 273 | clr %o1 | ||
| 274 | sethi %hi(kern_locked_tte_data), %o2 | ||
| 275 | ldx [%o2 + %lo(kern_locked_tte_data)], %o2 | ||
| 276 | mov HV_MMU_IMMU, %o3 | ||
| 277 | ta HV_FAST_TRAP | ||
| 278 | |||
| 279 | mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 | ||
| 280 | sethi %hi(KERNBASE), %o0 | ||
| 281 | clr %o1 | ||
| 282 | sethi %hi(kern_locked_tte_data), %o2 | ||
| 283 | ldx [%o2 + %lo(kern_locked_tte_data)], %o2 | ||
| 284 | mov HV_MMU_DMMU, %o3 | ||
| 285 | ta HV_FAST_TRAP | ||
| 262 | 286 | ||
| 263 | mov %l0, %o0 | 287 | sethi %hi(bigkernel), %g2 |
| 288 | lduw [%g2 + %lo(bigkernel)], %g2 | ||
| 289 | brz,pt %g2, after_lock_tlb | ||
| 290 | nop | ||
| 264 | 291 | ||
| 292 | mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 | ||
| 293 | sethi %hi(KERNBASE + 0x400000), %o0 | ||
| 294 | clr %o1 | ||
| 295 | sethi %hi(kern_locked_tte_data), %o2 | ||
| 296 | ldx [%o2 + %lo(kern_locked_tte_data)], %o2 | ||
| 297 | sethi %hi(0x400000), %o3 | ||
| 298 | add %o2, %o3, %o2 | ||
| 299 | mov HV_MMU_IMMU, %o3 | ||
| 300 | ta HV_FAST_TRAP | ||
| 301 | |||
| 302 | mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 | ||
| 303 | sethi %hi(KERNBASE + 0x400000), %o0 | ||
| 304 | clr %o1 | ||
| 305 | sethi %hi(kern_locked_tte_data), %o2 | ||
| 306 | ldx [%o2 + %lo(kern_locked_tte_data)], %o2 | ||
| 307 | sethi %hi(0x400000), %o3 | ||
| 308 | add %o2, %o3, %o2 | ||
| 309 | mov HV_MMU_DMMU, %o3 | ||
| 310 | ta HV_FAST_TRAP | ||
| 311 | |||
| 312 | after_lock_tlb: | ||
| 265 | wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate | 313 | wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate |
| 266 | wr %g0, 0, %fprs | 314 | wr %g0, 0, %fprs |
| 267 | 315 | ||
| 268 | /* XXX Buggy PROM... */ | ||
| 269 | srl %o0, 0, %o0 | ||
| 270 | ldx [%o0], %g6 | ||
| 271 | |||
| 272 | wr %g0, ASI_P, %asi | 316 | wr %g0, ASI_P, %asi |
| 273 | 317 | ||
| 274 | mov PRIMARY_CONTEXT, %g7 | 318 | mov PRIMARY_CONTEXT, %g7 |
| 275 | stxa %g0, [%g7] ASI_DMMU | 319 | |
| 320 | 661: stxa %g0, [%g7] ASI_DMMU | ||
| 321 | .section .sun4v_1insn_patch, "ax" | ||
| 322 | .word 661b | ||
| 323 | stxa %g0, [%g7] ASI_MMU | ||
| 324 | .previous | ||
| 325 | |||
| 276 | membar #Sync | 326 | membar #Sync |
| 277 | mov SECONDARY_CONTEXT, %g7 | 327 | mov SECONDARY_CONTEXT, %g7 |
| 278 | stxa %g0, [%g7] ASI_DMMU | 328 | |
| 329 | 661: stxa %g0, [%g7] ASI_DMMU | ||
| 330 | .section .sun4v_1insn_patch, "ax" | ||
| 331 | .word 661b | ||
| 332 | stxa %g0, [%g7] ASI_MMU | ||
| 333 | .previous | ||
| 334 | |||
| 279 | membar #Sync | 335 | membar #Sync |
| 280 | 336 | ||
| 281 | mov 1, %g5 | 337 | /* Everything we do here, until we properly take over the |
| 282 | sllx %g5, THREAD_SHIFT, %g5 | 338 | * trap table, must be done with extreme care. We cannot |
| 283 | sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5 | 339 | * make any references to %g6 (current thread pointer), |
| 284 | add %g6, %g5, %sp | 340 | * %g4 (current task pointer), or %g5 (base of current cpu's |
| 341 | * per-cpu area) until we properly take over the trap table | ||
| 342 | * from the firmware and hypervisor. | ||
| 343 | * | ||
| 344 | * Get onto temporary stack which is in the locked kernel image. | ||
| 345 | */ | ||
| 346 | sethi %hi(tramp_stack), %g1 | ||
| 347 | or %g1, %lo(tramp_stack), %g1 | ||
| 348 | add %g1, TRAMP_STACK_SIZE, %g1 | ||
| 349 | sub %g1, STACKFRAME_SZ + STACK_BIAS, %sp | ||
| 285 | mov 0, %fp | 350 | mov 0, %fp |
| 286 | 351 | ||
| 287 | wrpr %g0, 0, %wstate | 352 | /* Put garbage in these registers to trap any access to them. */ |
| 288 | wrpr %g0, 0, %tl | 353 | set 0xdeadbeef, %g4 |
| 354 | set 0xdeadbeef, %g5 | ||
| 355 | set 0xdeadbeef, %g6 | ||
| 289 | 356 | ||
| 290 | /* Setup the trap globals, then we can resurface. */ | 357 | call init_irqwork_curcpu |
| 291 | rdpr %pstate, %o1 | 358 | nop |
| 292 | mov %g6, %o2 | ||
| 293 | wrpr %o1, PSTATE_AG, %pstate | ||
| 294 | sethi %hi(sparc64_ttable_tl0), %g5 | ||
| 295 | wrpr %g5, %tba | ||
| 296 | mov %o2, %g6 | ||
| 297 | |||
| 298 | wrpr %o1, PSTATE_MG, %pstate | ||
| 299 | #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) | ||
| 300 | #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | ||
| 301 | |||
| 302 | mov TSB_REG, %g1 | ||
| 303 | stxa %g0, [%g1] ASI_DMMU | ||
| 304 | membar #Sync | ||
| 305 | mov TLB_SFSR, %g1 | ||
| 306 | sethi %uhi(KERN_HIGHBITS), %g2 | ||
| 307 | or %g2, %ulo(KERN_HIGHBITS), %g2 | ||
| 308 | sllx %g2, 32, %g2 | ||
| 309 | or %g2, KERN_LOWBITS, %g2 | ||
| 310 | 359 | ||
| 311 | BRANCH_IF_ANY_CHEETAH(g3,g7,9f) | 360 | sethi %hi(tlb_type), %g3 |
| 361 | lduw [%g3 + %lo(tlb_type)], %g2 | ||
| 362 | cmp %g2, 3 | ||
| 363 | bne,pt %icc, 1f | ||
| 364 | nop | ||
| 312 | 365 | ||
| 313 | ba,pt %xcc, 1f | 366 | call hard_smp_processor_id |
| 314 | nop | 367 | nop |
| 368 | |||
| 369 | mov %o0, %o1 | ||
| 370 | mov 0, %o0 | ||
| 371 | mov 0, %o2 | ||
| 372 | call sun4v_init_mondo_queues | ||
| 373 | mov 1, %o3 | ||
| 315 | 374 | ||
| 316 | 9: | 375 | 1: call init_cur_cpu_trap |
| 317 | sethi %uhi(VPTE_BASE_CHEETAH), %g3 | 376 | ldx [%l0], %o0 |
| 318 | or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 | 377 | |
| 319 | ba,pt %xcc, 2f | 378 | /* Start using proper page size encodings in ctx register. */ |
| 320 | sllx %g3, 32, %g3 | 379 | sethi %hi(sparc64_kern_pri_context), %g3 |
| 321 | 1: | 380 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 |
| 322 | sethi %uhi(VPTE_BASE_SPITFIRE), %g3 | 381 | mov PRIMARY_CONTEXT, %g1 |
| 323 | or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 | ||
| 324 | sllx %g3, 32, %g3 | ||
| 325 | 382 | ||
| 326 | 2: | 383 | 661: stxa %g2, [%g1] ASI_DMMU |
| 327 | clr %g7 | 384 | .section .sun4v_1insn_patch, "ax" |
| 328 | #undef KERN_HIGHBITS | 385 | .word 661b |
| 329 | #undef KERN_LOWBITS | 386 | stxa %g2, [%g1] ASI_MMU |
| 387 | .previous | ||
| 330 | 388 | ||
| 331 | wrpr %o1, 0x0, %pstate | 389 | membar #Sync |
| 332 | ldx [%g6 + TI_TASK], %g4 | ||
| 333 | 390 | ||
| 334 | wrpr %g0, 0, %wstate | 391 | wrpr %g0, 0, %wstate |
| 335 | 392 | ||
| 336 | call init_irqwork_curcpu | 393 | /* As a hack, put &init_thread_union into %g6. |
| 394 | * prom_world() loads from here to restore the %asi | ||
| 395 | * register. | ||
| 396 | */ | ||
| 397 | sethi %hi(init_thread_union), %g6 | ||
| 398 | or %g6, %lo(init_thread_union), %g6 | ||
| 399 | |||
| 400 | sethi %hi(is_sun4v), %o0 | ||
| 401 | lduw [%o0 + %lo(is_sun4v)], %o0 | ||
| 402 | brz,pt %o0, 1f | ||
| 337 | nop | 403 | nop |
| 338 | 404 | ||
| 339 | /* Start using proper page size encodings in ctx register. */ | 405 | TRAP_LOAD_TRAP_BLOCK(%g2, %g3) |
| 340 | sethi %hi(sparc64_kern_pri_context), %g3 | 406 | add %g2, TRAP_PER_CPU_FAULT_INFO, %g2 |
| 341 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 | 407 | stxa %g2, [%g0] ASI_SCRATCHPAD |
| 342 | mov PRIMARY_CONTEXT, %g1 | 408 | |
| 343 | stxa %g2, [%g1] ASI_DMMU | 409 | /* Compute physical address: |
| 344 | membar #Sync | 410 | * |
| 411 | * paddr = kern_base + (mmfsa_vaddr - KERNBASE) | ||
| 412 | */ | ||
| 413 | sethi %hi(KERNBASE), %g3 | ||
| 414 | sub %g2, %g3, %g2 | ||
| 415 | sethi %hi(kern_base), %g3 | ||
| 416 | ldx [%g3 + %lo(kern_base)], %g3 | ||
| 417 | add %g2, %g3, %o1 | ||
| 418 | |||
| 419 | call prom_set_trap_table_sun4v | ||
| 420 | sethi %hi(sparc64_ttable_tl0), %o0 | ||
| 421 | |||
| 422 | ba,pt %xcc, 2f | ||
| 423 | nop | ||
| 424 | |||
| 425 | 1: call prom_set_trap_table | ||
| 426 | sethi %hi(sparc64_ttable_tl0), %o0 | ||
| 427 | |||
| 428 | 2: ldx [%l0], %g6 | ||
| 429 | ldx [%g6 + TI_TASK], %g4 | ||
| 430 | |||
| 431 | mov 1, %g5 | ||
| 432 | sllx %g5, THREAD_SHIFT, %g5 | ||
| 433 | sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5 | ||
| 434 | add %g6, %g5, %sp | ||
| 435 | mov 0, %fp | ||
| 345 | 436 | ||
| 346 | rdpr %pstate, %o1 | 437 | rdpr %pstate, %o1 |
| 347 | or %o1, PSTATE_IE, %o1 | 438 | or %o1, PSTATE_IE, %o1 |
| 348 | wrpr %o1, 0, %pstate | 439 | wrpr %o1, 0, %pstate |
| 349 | 440 | ||
| 350 | call prom_set_trap_table | ||
| 351 | sethi %hi(sparc64_ttable_tl0), %o0 | ||
| 352 | |||
| 353 | call smp_callin | 441 | call smp_callin |
| 354 | nop | 442 | nop |
| 355 | call cpu_idle | 443 | call cpu_idle |
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 8d44ae5a15e3..7f7dba0ca96a 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
| 39 | #include <asm/timer.h> | 39 | #include <asm/timer.h> |
| 40 | #include <asm/kdebug.h> | 40 | #include <asm/kdebug.h> |
| 41 | #include <asm/head.h> | ||
| 41 | #ifdef CONFIG_KMOD | 42 | #ifdef CONFIG_KMOD |
| 42 | #include <linux/kmod.h> | 43 | #include <linux/kmod.h> |
| 43 | #endif | 44 | #endif |
| @@ -72,12 +73,14 @@ struct tl1_traplog { | |||
| 72 | 73 | ||
| 73 | static void dump_tl1_traplog(struct tl1_traplog *p) | 74 | static void dump_tl1_traplog(struct tl1_traplog *p) |
| 74 | { | 75 | { |
| 75 | int i; | 76 | int i, limit; |
| 77 | |||
| 78 | printk(KERN_EMERG "TRAPLOG: Error at trap level 0x%lx, " | ||
| 79 | "dumping track stack.\n", p->tl); | ||
| 76 | 80 | ||
| 77 | printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n", | 81 | limit = (tlb_type == hypervisor) ? 2 : 4; |
| 78 | p->tl); | 82 | for (i = 0; i < limit; i++) { |
| 79 | for (i = 0; i < 4; i++) { | 83 | printk(KERN_EMERG |
| 80 | printk(KERN_CRIT | ||
| 81 | "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] " | 84 | "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] " |
| 82 | "TNPC[%016lx] TT[%lx]\n", | 85 | "TNPC[%016lx] TT[%lx]\n", |
| 83 | i + 1, | 86 | i + 1, |
| @@ -179,6 +182,45 @@ void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr | |||
| 179 | spitfire_insn_access_exception(regs, sfsr, sfar); | 182 | spitfire_insn_access_exception(regs, sfsr, sfar); |
| 180 | } | 183 | } |
| 181 | 184 | ||
| 185 | void sun4v_insn_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
| 186 | { | ||
| 187 | unsigned short type = (type_ctx >> 16); | ||
| 188 | unsigned short ctx = (type_ctx & 0xffff); | ||
| 189 | siginfo_t info; | ||
| 190 | |||
| 191 | if (notify_die(DIE_TRAP, "instruction access exception", regs, | ||
| 192 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
| 193 | return; | ||
| 194 | |||
| 195 | if (regs->tstate & TSTATE_PRIV) { | ||
| 196 | printk("sun4v_insn_access_exception: ADDR[%016lx] " | ||
| 197 | "CTX[%04x] TYPE[%04x], going.\n", | ||
| 198 | addr, ctx, type); | ||
| 199 | die_if_kernel("Iax", regs); | ||
| 200 | } | ||
| 201 | |||
| 202 | if (test_thread_flag(TIF_32BIT)) { | ||
| 203 | regs->tpc &= 0xffffffff; | ||
| 204 | regs->tnpc &= 0xffffffff; | ||
| 205 | } | ||
| 206 | info.si_signo = SIGSEGV; | ||
| 207 | info.si_errno = 0; | ||
| 208 | info.si_code = SEGV_MAPERR; | ||
| 209 | info.si_addr = (void __user *) addr; | ||
| 210 | info.si_trapno = 0; | ||
| 211 | force_sig_info(SIGSEGV, &info, current); | ||
| 212 | } | ||
| 213 | |||
| 214 | void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
| 215 | { | ||
| 216 | if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs, | ||
| 217 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
| 218 | return; | ||
| 219 | |||
| 220 | dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); | ||
| 221 | sun4v_insn_access_exception(regs, addr, type_ctx); | ||
| 222 | } | ||
| 223 | |||
| 182 | void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) | 224 | void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) |
| 183 | { | 225 | { |
| 184 | siginfo_t info; | 226 | siginfo_t info; |
| @@ -227,6 +269,45 @@ void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr | |||
| 227 | spitfire_data_access_exception(regs, sfsr, sfar); | 269 | spitfire_data_access_exception(regs, sfsr, sfar); |
| 228 | } | 270 | } |
| 229 | 271 | ||
| 272 | void sun4v_data_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
| 273 | { | ||
| 274 | unsigned short type = (type_ctx >> 16); | ||
| 275 | unsigned short ctx = (type_ctx & 0xffff); | ||
| 276 | siginfo_t info; | ||
| 277 | |||
| 278 | if (notify_die(DIE_TRAP, "data access exception", regs, | ||
| 279 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
| 280 | return; | ||
| 281 | |||
| 282 | if (regs->tstate & TSTATE_PRIV) { | ||
| 283 | printk("sun4v_data_access_exception: ADDR[%016lx] " | ||
| 284 | "CTX[%04x] TYPE[%04x], going.\n", | ||
| 285 | addr, ctx, type); | ||
| 286 | die_if_kernel("Dax", regs); | ||
| 287 | } | ||
| 288 | |||
| 289 | if (test_thread_flag(TIF_32BIT)) { | ||
| 290 | regs->tpc &= 0xffffffff; | ||
| 291 | regs->tnpc &= 0xffffffff; | ||
| 292 | } | ||
| 293 | info.si_signo = SIGSEGV; | ||
| 294 | info.si_errno = 0; | ||
| 295 | info.si_code = SEGV_MAPERR; | ||
| 296 | info.si_addr = (void __user *) addr; | ||
| 297 | info.si_trapno = 0; | ||
| 298 | force_sig_info(SIGSEGV, &info, current); | ||
| 299 | } | ||
| 300 | |||
| 301 | void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
| 302 | { | ||
| 303 | if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs, | ||
| 304 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
| 305 | return; | ||
| 306 | |||
| 307 | dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); | ||
| 308 | sun4v_data_access_exception(regs, addr, type_ctx); | ||
| 309 | } | ||
| 310 | |||
| 230 | #ifdef CONFIG_PCI | 311 | #ifdef CONFIG_PCI |
| 231 | /* This is really pathetic... */ | 312 | /* This is really pathetic... */ |
| 232 | extern volatile int pci_poke_in_progress; | 313 | extern volatile int pci_poke_in_progress; |
| @@ -788,7 +869,8 @@ void __init cheetah_ecache_flush_init(void) | |||
| 788 | cheetah_error_log[i].afsr = CHAFSR_INVALID; | 869 | cheetah_error_log[i].afsr = CHAFSR_INVALID; |
| 789 | 870 | ||
| 790 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | 871 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); |
| 791 | if ((ver >> 32) == 0x003e0016) { | 872 | if ((ver >> 32) == __JALAPENO_ID || |
| 873 | (ver >> 32) == __SERRANO_ID) { | ||
| 792 | cheetah_error_table = &__jalapeno_error_table[0]; | 874 | cheetah_error_table = &__jalapeno_error_table[0]; |
| 793 | cheetah_afsr_errors = JPAFSR_ERRORS; | 875 | cheetah_afsr_errors = JPAFSR_ERRORS; |
| 794 | } else if ((ver >> 32) == 0x003e0015) { | 876 | } else if ((ver >> 32) == 0x003e0015) { |
| @@ -1666,6 +1748,238 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs) | |||
| 1666 | regs->tpc); | 1748 | regs->tpc); |
| 1667 | } | 1749 | } |
| 1668 | 1750 | ||
| 1751 | struct sun4v_error_entry { | ||
| 1752 | u64 err_handle; | ||
| 1753 | u64 err_stick; | ||
| 1754 | |||
| 1755 | u32 err_type; | ||
| 1756 | #define SUN4V_ERR_TYPE_UNDEFINED 0 | ||
| 1757 | #define SUN4V_ERR_TYPE_UNCORRECTED_RES 1 | ||
| 1758 | #define SUN4V_ERR_TYPE_PRECISE_NONRES 2 | ||
| 1759 | #define SUN4V_ERR_TYPE_DEFERRED_NONRES 3 | ||
| 1760 | #define SUN4V_ERR_TYPE_WARNING_RES 4 | ||
| 1761 | |||
| 1762 | u32 err_attrs; | ||
| 1763 | #define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001 | ||
| 1764 | #define SUN4V_ERR_ATTRS_MEMORY 0x00000002 | ||
| 1765 | #define SUN4V_ERR_ATTRS_PIO 0x00000004 | ||
| 1766 | #define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008 | ||
| 1767 | #define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010 | ||
| 1768 | #define SUN4V_ERR_ATTRS_USER_MODE 0x01000000 | ||
| 1769 | #define SUN4V_ERR_ATTRS_PRIV_MODE 0x02000000 | ||
| 1770 | #define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000 | ||
| 1771 | |||
| 1772 | u64 err_raddr; | ||
| 1773 | u32 err_size; | ||
| 1774 | u16 err_cpu; | ||
| 1775 | u16 err_pad; | ||
| 1776 | }; | ||
| 1777 | |||
| 1778 | static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0); | ||
| 1779 | static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0); | ||
| 1780 | |||
| 1781 | static const char *sun4v_err_type_to_str(u32 type) | ||
| 1782 | { | ||
| 1783 | switch (type) { | ||
| 1784 | case SUN4V_ERR_TYPE_UNDEFINED: | ||
| 1785 | return "undefined"; | ||
| 1786 | case SUN4V_ERR_TYPE_UNCORRECTED_RES: | ||
| 1787 | return "uncorrected resumable"; | ||
| 1788 | case SUN4V_ERR_TYPE_PRECISE_NONRES: | ||
| 1789 | return "precise nonresumable"; | ||
| 1790 | case SUN4V_ERR_TYPE_DEFERRED_NONRES: | ||
| 1791 | return "deferred nonresumable"; | ||
| 1792 | case SUN4V_ERR_TYPE_WARNING_RES: | ||
| 1793 | return "warning resumable"; | ||
| 1794 | default: | ||
| 1795 | return "unknown"; | ||
| 1796 | }; | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | static void sun4v_log_error(struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt) | ||
| 1800 | { | ||
| 1801 | int cnt; | ||
| 1802 | |||
| 1803 | printk("%s: Reporting on cpu %d\n", pfx, cpu); | ||
| 1804 | printk("%s: err_handle[%lx] err_stick[%lx] err_type[%08x:%s]\n", | ||
| 1805 | pfx, | ||
| 1806 | ent->err_handle, ent->err_stick, | ||
| 1807 | ent->err_type, | ||
| 1808 | sun4v_err_type_to_str(ent->err_type)); | ||
| 1809 | printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n", | ||
| 1810 | pfx, | ||
| 1811 | ent->err_attrs, | ||
| 1812 | ((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ? | ||
| 1813 | "processor" : ""), | ||
| 1814 | ((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ? | ||
| 1815 | "memory" : ""), | ||
| 1816 | ((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ? | ||
| 1817 | "pio" : ""), | ||
| 1818 | ((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ? | ||
| 1819 | "integer-regs" : ""), | ||
| 1820 | ((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ? | ||
| 1821 | "fpu-regs" : ""), | ||
| 1822 | ((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ? | ||
| 1823 | "user" : ""), | ||
| 1824 | ((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ? | ||
| 1825 | "privileged" : ""), | ||
| 1826 | ((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ? | ||
| 1827 | "queue-full" : "")); | ||
| 1828 | printk("%s: err_raddr[%016lx] err_size[%u] err_cpu[%u]\n", | ||
| 1829 | pfx, | ||
| 1830 | ent->err_raddr, ent->err_size, ent->err_cpu); | ||
| 1831 | |||
| 1832 | if ((cnt = atomic_read(ocnt)) != 0) { | ||
| 1833 | atomic_set(ocnt, 0); | ||
| 1834 | wmb(); | ||
| 1835 | printk("%s: Queue overflowed %d times.\n", | ||
| 1836 | pfx, cnt); | ||
| 1837 | } | ||
| 1838 | } | ||
| 1839 | |||
| 1840 | /* We run with %pil set to 15 and PSTATE_IE enabled in %pstate. | ||
| 1841 | * Log the event and clear the first word of the entry. | ||
| 1842 | */ | ||
| 1843 | void sun4v_resum_error(struct pt_regs *regs, unsigned long offset) | ||
| 1844 | { | ||
| 1845 | struct sun4v_error_entry *ent, local_copy; | ||
| 1846 | struct trap_per_cpu *tb; | ||
| 1847 | unsigned long paddr; | ||
| 1848 | int cpu; | ||
| 1849 | |||
| 1850 | cpu = get_cpu(); | ||
| 1851 | |||
| 1852 | tb = &trap_block[cpu]; | ||
| 1853 | paddr = tb->resum_kernel_buf_pa + offset; | ||
| 1854 | ent = __va(paddr); | ||
| 1855 | |||
| 1856 | memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry)); | ||
| 1857 | |||
| 1858 | /* We have a local copy now, so release the entry. */ | ||
| 1859 | ent->err_handle = 0; | ||
| 1860 | wmb(); | ||
| 1861 | |||
| 1862 | put_cpu(); | ||
| 1863 | |||
| 1864 | sun4v_log_error(&local_copy, cpu, | ||
| 1865 | KERN_ERR "RESUMABLE ERROR", | ||
| 1866 | &sun4v_resum_oflow_cnt); | ||
| 1867 | } | ||
| 1868 | |||
| 1869 | /* If we try to printk() we'll probably make matters worse, by trying | ||
| 1870 | * to retake locks this cpu already holds or causing more errors. So | ||
| 1871 | * just bump a counter, and we'll report these counter bumps above. | ||
| 1872 | */ | ||
| 1873 | void sun4v_resum_overflow(struct pt_regs *regs) | ||
| 1874 | { | ||
| 1875 | atomic_inc(&sun4v_resum_oflow_cnt); | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | /* We run with %pil set to 15 and PSTATE_IE enabled in %pstate. | ||
| 1879 | * Log the event, clear the first word of the entry, and die. | ||
| 1880 | */ | ||
| 1881 | void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset) | ||
| 1882 | { | ||
| 1883 | struct sun4v_error_entry *ent, local_copy; | ||
| 1884 | struct trap_per_cpu *tb; | ||
| 1885 | unsigned long paddr; | ||
| 1886 | int cpu; | ||
| 1887 | |||
| 1888 | cpu = get_cpu(); | ||
| 1889 | |||
| 1890 | tb = &trap_block[cpu]; | ||
| 1891 | paddr = tb->nonresum_kernel_buf_pa + offset; | ||
| 1892 | ent = __va(paddr); | ||
| 1893 | |||
| 1894 | memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry)); | ||
| 1895 | |||
| 1896 | /* We have a local copy now, so release the entry. */ | ||
| 1897 | ent->err_handle = 0; | ||
| 1898 | wmb(); | ||
| 1899 | |||
| 1900 | put_cpu(); | ||
| 1901 | |||
| 1902 | #ifdef CONFIG_PCI | ||
| 1903 | /* Check for the special PCI poke sequence. */ | ||
| 1904 | if (pci_poke_in_progress && pci_poke_cpu == cpu) { | ||
| 1905 | pci_poke_faulted = 1; | ||
| 1906 | regs->tpc += 4; | ||
| 1907 | regs->tnpc = regs->tpc + 4; | ||
| 1908 | return; | ||
| 1909 | } | ||
| 1910 | #endif | ||
| 1911 | |||
| 1912 | sun4v_log_error(&local_copy, cpu, | ||
| 1913 | KERN_EMERG "NON-RESUMABLE ERROR", | ||
| 1914 | &sun4v_nonresum_oflow_cnt); | ||
| 1915 | |||
| 1916 | panic("Non-resumable error."); | ||
| 1917 | } | ||
| 1918 | |||
| 1919 | /* If we try to printk() we'll probably make matters worse, by trying | ||
| 1920 | * to retake locks this cpu already holds or causing more errors. So | ||
| 1921 | * just bump a counter, and we'll report these counter bumps above. | ||
| 1922 | */ | ||
| 1923 | void sun4v_nonresum_overflow(struct pt_regs *regs) | ||
| 1924 | { | ||
| 1925 | /* XXX Actually even this can make not that much sense. Perhaps | ||
| 1926 | * XXX we should just pull the plug and panic directly from here? | ||
| 1927 | */ | ||
| 1928 | atomic_inc(&sun4v_nonresum_oflow_cnt); | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | unsigned long sun4v_err_itlb_vaddr; | ||
| 1932 | unsigned long sun4v_err_itlb_ctx; | ||
| 1933 | unsigned long sun4v_err_itlb_pte; | ||
| 1934 | unsigned long sun4v_err_itlb_error; | ||
| 1935 | |||
| 1936 | void sun4v_itlb_error_report(struct pt_regs *regs, int tl) | ||
| 1937 | { | ||
| 1938 | if (tl > 1) | ||
| 1939 | dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); | ||
| 1940 | |||
| 1941 | printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n", | ||
| 1942 | regs->tpc, tl); | ||
| 1943 | printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] " | ||
| 1944 | "pte[%lx] error[%lx]\n", | ||
| 1945 | sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx, | ||
| 1946 | sun4v_err_itlb_pte, sun4v_err_itlb_error); | ||
| 1947 | |||
| 1948 | prom_halt(); | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | unsigned long sun4v_err_dtlb_vaddr; | ||
| 1952 | unsigned long sun4v_err_dtlb_ctx; | ||
| 1953 | unsigned long sun4v_err_dtlb_pte; | ||
| 1954 | unsigned long sun4v_err_dtlb_error; | ||
| 1955 | |||
| 1956 | void sun4v_dtlb_error_report(struct pt_regs *regs, int tl) | ||
| 1957 | { | ||
| 1958 | if (tl > 1) | ||
| 1959 | dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); | ||
| 1960 | |||
| 1961 | printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n", | ||
| 1962 | regs->tpc, tl); | ||
| 1963 | printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] " | ||
| 1964 | "pte[%lx] error[%lx]\n", | ||
| 1965 | sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx, | ||
| 1966 | sun4v_err_dtlb_pte, sun4v_err_dtlb_error); | ||
| 1967 | |||
| 1968 | prom_halt(); | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | void hypervisor_tlbop_error(unsigned long err, unsigned long op) | ||
| 1972 | { | ||
| 1973 | printk(KERN_CRIT "SUN4V: TLB hv call error %lu for op %lu\n", | ||
| 1974 | err, op); | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | void hypervisor_tlbop_error_xcall(unsigned long err, unsigned long op) | ||
| 1978 | { | ||
| 1979 | printk(KERN_CRIT "SUN4V: XCALL TLB hv call error %lu for op %lu\n", | ||
| 1980 | err, op); | ||
| 1981 | } | ||
| 1982 | |||
| 1669 | void do_fpe_common(struct pt_regs *regs) | 1983 | void do_fpe_common(struct pt_regs *regs) |
| 1670 | { | 1984 | { |
| 1671 | if (regs->tstate & TSTATE_PRIV) { | 1985 | if (regs->tstate & TSTATE_PRIV) { |
| @@ -1924,10 +2238,11 @@ void die_if_kernel(char *str, struct pt_regs *regs) | |||
| 1924 | } | 2238 | } |
| 1925 | user_instruction_dump ((unsigned int __user *) regs->tpc); | 2239 | user_instruction_dump ((unsigned int __user *) regs->tpc); |
| 1926 | } | 2240 | } |
| 2241 | #if 0 | ||
| 1927 | #ifdef CONFIG_SMP | 2242 | #ifdef CONFIG_SMP |
| 1928 | smp_report_regs(); | 2243 | smp_report_regs(); |
| 1929 | #endif | 2244 | #endif |
| 1930 | 2245 | #endif | |
| 1931 | if (regs->tstate & TSTATE_PRIV) | 2246 | if (regs->tstate & TSTATE_PRIV) |
| 1932 | do_exit(SIGKILL); | 2247 | do_exit(SIGKILL); |
| 1933 | do_exit(SIGSEGV); | 2248 | do_exit(SIGSEGV); |
| @@ -1958,6 +2273,11 @@ void do_illegal_instruction(struct pt_regs *regs) | |||
| 1958 | } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ { | 2273 | } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ { |
| 1959 | if (handle_ldf_stq(insn, regs)) | 2274 | if (handle_ldf_stq(insn, regs)) |
| 1960 | return; | 2275 | return; |
| 2276 | } else if (tlb_type == hypervisor) { | ||
| 2277 | extern int vis_emul(struct pt_regs *, unsigned int); | ||
| 2278 | |||
| 2279 | if (!vis_emul(regs, insn)) | ||
| 2280 | return; | ||
| 1961 | } | 2281 | } |
| 1962 | } | 2282 | } |
| 1963 | info.si_signo = SIGILL; | 2283 | info.si_signo = SIGILL; |
| @@ -1968,6 +2288,8 @@ void do_illegal_instruction(struct pt_regs *regs) | |||
| 1968 | force_sig_info(SIGILL, &info, current); | 2288 | force_sig_info(SIGILL, &info, current); |
| 1969 | } | 2289 | } |
| 1970 | 2290 | ||
| 2291 | extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn); | ||
| 2292 | |||
| 1971 | void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) | 2293 | void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) |
| 1972 | { | 2294 | { |
| 1973 | siginfo_t info; | 2295 | siginfo_t info; |
| @@ -1977,13 +2299,7 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo | |||
| 1977 | return; | 2299 | return; |
| 1978 | 2300 | ||
| 1979 | if (regs->tstate & TSTATE_PRIV) { | 2301 | if (regs->tstate & TSTATE_PRIV) { |
| 1980 | extern void kernel_unaligned_trap(struct pt_regs *regs, | 2302 | kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); |
| 1981 | unsigned int insn, | ||
| 1982 | unsigned long sfar, | ||
| 1983 | unsigned long sfsr); | ||
| 1984 | |||
| 1985 | kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), | ||
| 1986 | sfar, sfsr); | ||
| 1987 | return; | 2303 | return; |
| 1988 | } | 2304 | } |
| 1989 | info.si_signo = SIGBUS; | 2305 | info.si_signo = SIGBUS; |
| @@ -1994,6 +2310,26 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo | |||
| 1994 | force_sig_info(SIGBUS, &info, current); | 2310 | force_sig_info(SIGBUS, &info, current); |
| 1995 | } | 2311 | } |
| 1996 | 2312 | ||
| 2313 | void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
| 2314 | { | ||
| 2315 | siginfo_t info; | ||
| 2316 | |||
| 2317 | if (notify_die(DIE_TRAP, "memory address unaligned", regs, | ||
| 2318 | 0, 0x34, SIGSEGV) == NOTIFY_STOP) | ||
| 2319 | return; | ||
| 2320 | |||
| 2321 | if (regs->tstate & TSTATE_PRIV) { | ||
| 2322 | kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); | ||
| 2323 | return; | ||
| 2324 | } | ||
| 2325 | info.si_signo = SIGBUS; | ||
| 2326 | info.si_errno = 0; | ||
| 2327 | info.si_code = BUS_ADRALN; | ||
| 2328 | info.si_addr = (void __user *) addr; | ||
| 2329 | info.si_trapno = 0; | ||
| 2330 | force_sig_info(SIGBUS, &info, current); | ||
| 2331 | } | ||
| 2332 | |||
| 1997 | void do_privop(struct pt_regs *regs) | 2333 | void do_privop(struct pt_regs *regs) |
| 1998 | { | 2334 | { |
| 1999 | siginfo_t info; | 2335 | siginfo_t info; |
| @@ -2130,7 +2466,22 @@ void do_getpsr(struct pt_regs *regs) | |||
| 2130 | } | 2466 | } |
| 2131 | } | 2467 | } |
| 2132 | 2468 | ||
| 2469 | struct trap_per_cpu trap_block[NR_CPUS]; | ||
| 2470 | |||
| 2471 | /* This can get invoked before sched_init() so play it super safe | ||
| 2472 | * and use hard_smp_processor_id(). | ||
| 2473 | */ | ||
| 2474 | void init_cur_cpu_trap(struct thread_info *t) | ||
| 2475 | { | ||
| 2476 | int cpu = hard_smp_processor_id(); | ||
| 2477 | struct trap_per_cpu *p = &trap_block[cpu]; | ||
| 2478 | |||
| 2479 | p->thread = t; | ||
| 2480 | p->pgd_paddr = 0; | ||
| 2481 | } | ||
| 2482 | |||
| 2133 | extern void thread_info_offsets_are_bolixed_dave(void); | 2483 | extern void thread_info_offsets_are_bolixed_dave(void); |
| 2484 | extern void trap_per_cpu_offsets_are_bolixed_dave(void); | ||
| 2134 | 2485 | ||
| 2135 | /* Only invoked on boot processor. */ | 2486 | /* Only invoked on boot processor. */ |
| 2136 | void __init trap_init(void) | 2487 | void __init trap_init(void) |
| @@ -2154,7 +2505,6 @@ void __init trap_init(void) | |||
| 2154 | TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) || | 2505 | TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) || |
| 2155 | TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) || | 2506 | TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) || |
| 2156 | TI_PCR != offsetof(struct thread_info, pcr_reg) || | 2507 | TI_PCR != offsetof(struct thread_info, pcr_reg) || |
| 2157 | TI_CEE_STUFF != offsetof(struct thread_info, cee_stuff) || | ||
| 2158 | TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || | 2508 | TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || |
| 2159 | TI_NEW_CHILD != offsetof(struct thread_info, new_child) || | 2509 | TI_NEW_CHILD != offsetof(struct thread_info, new_child) || |
| 2160 | TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || | 2510 | TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || |
| @@ -2165,6 +2515,29 @@ void __init trap_init(void) | |||
| 2165 | (TI_FPREGS & (64 - 1))) | 2515 | (TI_FPREGS & (64 - 1))) |
| 2166 | thread_info_offsets_are_bolixed_dave(); | 2516 | thread_info_offsets_are_bolixed_dave(); |
| 2167 | 2517 | ||
| 2518 | if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) || | ||
| 2519 | (TRAP_PER_CPU_PGD_PADDR != | ||
| 2520 | offsetof(struct trap_per_cpu, pgd_paddr)) || | ||
| 2521 | (TRAP_PER_CPU_CPU_MONDO_PA != | ||
| 2522 | offsetof(struct trap_per_cpu, cpu_mondo_pa)) || | ||
| 2523 | (TRAP_PER_CPU_DEV_MONDO_PA != | ||
| 2524 | offsetof(struct trap_per_cpu, dev_mondo_pa)) || | ||
| 2525 | (TRAP_PER_CPU_RESUM_MONDO_PA != | ||
| 2526 | offsetof(struct trap_per_cpu, resum_mondo_pa)) || | ||
| 2527 | (TRAP_PER_CPU_RESUM_KBUF_PA != | ||
| 2528 | offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) || | ||
| 2529 | (TRAP_PER_CPU_NONRESUM_MONDO_PA != | ||
| 2530 | offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || | ||
| 2531 | (TRAP_PER_CPU_NONRESUM_KBUF_PA != | ||
| 2532 | offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) || | ||
| 2533 | (TRAP_PER_CPU_FAULT_INFO != | ||
| 2534 | offsetof(struct trap_per_cpu, fault_info)) || | ||
| 2535 | (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != | ||
| 2536 | offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) || | ||
| 2537 | (TRAP_PER_CPU_CPU_LIST_PA != | ||
| 2538 | offsetof(struct trap_per_cpu, cpu_list_pa))) | ||
| 2539 | trap_per_cpu_offsets_are_bolixed_dave(); | ||
| 2540 | |||
| 2168 | /* Attach to the address space of init_task. On SMP we | 2541 | /* Attach to the address space of init_task. On SMP we |
| 2169 | * do this in smp.c:smp_callin for other cpus. | 2542 | * do this in smp.c:smp_callin for other cpus. |
| 2170 | */ | 2543 | */ |
diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S new file mode 100644 index 000000000000..118baea44f69 --- /dev/null +++ b/arch/sparc64/kernel/tsb.S | |||
| @@ -0,0 +1,442 @@ | |||
| 1 | /* tsb.S: Sparc64 TSB table handling. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <asm/tsb.h> | ||
| 7 | #include <asm/hypervisor.h> | ||
| 8 | |||
| 9 | .text | ||
| 10 | .align 32 | ||
| 11 | |||
| 12 | /* Invoked from TLB miss handler, we are in the | ||
| 13 | * MMU global registers and they are setup like | ||
| 14 | * this: | ||
| 15 | * | ||
| 16 | * %g1: TSB entry pointer | ||
| 17 | * %g2: available temporary | ||
| 18 | * %g3: FAULT_CODE_{D,I}TLB | ||
| 19 | * %g4: available temporary | ||
| 20 | * %g5: available temporary | ||
| 21 | * %g6: TAG TARGET | ||
| 22 | * %g7: available temporary, will be loaded by us with | ||
| 23 | * the physical address base of the linux page | ||
| 24 | * tables for the current address space | ||
| 25 | */ | ||
| 26 | tsb_miss_dtlb: | ||
| 27 | mov TLB_TAG_ACCESS, %g4 | ||
| 28 | ba,pt %xcc, tsb_miss_page_table_walk | ||
| 29 | ldxa [%g4] ASI_DMMU, %g4 | ||
| 30 | |||
| 31 | tsb_miss_itlb: | ||
| 32 | mov TLB_TAG_ACCESS, %g4 | ||
| 33 | ba,pt %xcc, tsb_miss_page_table_walk | ||
| 34 | ldxa [%g4] ASI_IMMU, %g4 | ||
| 35 | |||
| 36 | /* At this point we have: | ||
| 37 | * %g1 -- TSB entry address | ||
| 38 | * %g3 -- FAULT_CODE_{D,I}TLB | ||
| 39 | * %g4 -- missing virtual address | ||
| 40 | * %g6 -- TAG TARGET (vaddr >> 22) | ||
| 41 | */ | ||
| 42 | tsb_miss_page_table_walk: | ||
| 43 | TRAP_LOAD_PGD_PHYS(%g7, %g5) | ||
| 44 | |||
| 45 | /* And now we have the PGD base physical address in %g7. */ | ||
| 46 | tsb_miss_page_table_walk_sun4v_fastpath: | ||
| 47 | USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault) | ||
| 48 | |||
| 49 | /* At this point we have: | ||
| 50 | * %g1 -- TSB entry address | ||
| 51 | * %g3 -- FAULT_CODE_{D,I}TLB | ||
| 52 | * %g5 -- physical address of PTE in Linux page tables | ||
| 53 | * %g6 -- TAG TARGET (vaddr >> 22) | ||
| 54 | */ | ||
| 55 | tsb_reload: | ||
| 56 | TSB_LOCK_TAG(%g1, %g2, %g7) | ||
| 57 | |||
| 58 | /* Load and check PTE. */ | ||
| 59 | ldxa [%g5] ASI_PHYS_USE_EC, %g5 | ||
| 60 | mov 1, %g7 | ||
| 61 | sllx %g7, TSB_TAG_INVALID_BIT, %g7 | ||
| 62 | brgez,a,pn %g5, tsb_do_fault | ||
| 63 | TSB_STORE(%g1, %g7) | ||
| 64 | |||
| 65 | TSB_WRITE(%g1, %g5, %g6) | ||
| 66 | |||
| 67 | /* Finally, load TLB and return from trap. */ | ||
| 68 | tsb_tlb_reload: | ||
| 69 | cmp %g3, FAULT_CODE_DTLB | ||
| 70 | bne,pn %xcc, tsb_itlb_load | ||
| 71 | nop | ||
| 72 | |||
| 73 | tsb_dtlb_load: | ||
| 74 | |||
| 75 | 661: stxa %g5, [%g0] ASI_DTLB_DATA_IN | ||
| 76 | retry | ||
| 77 | .section .sun4v_2insn_patch, "ax" | ||
| 78 | .word 661b | ||
| 79 | nop | ||
| 80 | nop | ||
| 81 | .previous | ||
| 82 | |||
| 83 | /* For sun4v the ASI_DTLB_DATA_IN store and the retry | ||
| 84 | * instruction get nop'd out and we get here to branch | ||
| 85 | * to the sun4v tlb load code. The registers are setup | ||
| 86 | * as follows: | ||
| 87 | * | ||
| 88 | * %g4: vaddr | ||
| 89 | * %g5: PTE | ||
| 90 | * %g6: TAG | ||
| 91 | * | ||
| 92 | * The sun4v TLB load wants the PTE in %g3 so we fix that | ||
| 93 | * up here. | ||
| 94 | */ | ||
| 95 | ba,pt %xcc, sun4v_dtlb_load | ||
| 96 | mov %g5, %g3 | ||
| 97 | |||
| 98 | tsb_itlb_load: | ||
| 99 | /* Executable bit must be set. */ | ||
| 100 | 661: andcc %g5, _PAGE_EXEC_4U, %g0 | ||
| 101 | .section .sun4v_1insn_patch, "ax" | ||
| 102 | .word 661b | ||
| 103 | andcc %g5, _PAGE_EXEC_4V, %g0 | ||
| 104 | .previous | ||
| 105 | |||
| 106 | be,pn %xcc, tsb_do_fault | ||
| 107 | nop | ||
| 108 | |||
| 109 | 661: stxa %g5, [%g0] ASI_ITLB_DATA_IN | ||
| 110 | retry | ||
| 111 | .section .sun4v_2insn_patch, "ax" | ||
| 112 | .word 661b | ||
| 113 | nop | ||
| 114 | nop | ||
| 115 | .previous | ||
| 116 | |||
| 117 | /* For sun4v the ASI_ITLB_DATA_IN store and the retry | ||
| 118 | * instruction get nop'd out and we get here to branch | ||
| 119 | * to the sun4v tlb load code. The registers are setup | ||
| 120 | * as follows: | ||
| 121 | * | ||
| 122 | * %g4: vaddr | ||
| 123 | * %g5: PTE | ||
| 124 | * %g6: TAG | ||
| 125 | * | ||
| 126 | * The sun4v TLB load wants the PTE in %g3 so we fix that | ||
| 127 | * up here. | ||
| 128 | */ | ||
| 129 | ba,pt %xcc, sun4v_itlb_load | ||
| 130 | mov %g5, %g3 | ||
| 131 | |||
| 132 | /* No valid entry in the page tables, do full fault | ||
| 133 | * processing. | ||
| 134 | */ | ||
| 135 | |||
| 136 | .globl tsb_do_fault | ||
| 137 | tsb_do_fault: | ||
| 138 | cmp %g3, FAULT_CODE_DTLB | ||
| 139 | |||
| 140 | 661: rdpr %pstate, %g5 | ||
| 141 | wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate | ||
| 142 | .section .sun4v_2insn_patch, "ax" | ||
| 143 | .word 661b | ||
| 144 | SET_GL(1) | ||
| 145 | ldxa [%g0] ASI_SCRATCHPAD, %g4 | ||
| 146 | .previous | ||
| 147 | |||
| 148 | bne,pn %xcc, tsb_do_itlb_fault | ||
| 149 | nop | ||
| 150 | |||
| 151 | tsb_do_dtlb_fault: | ||
| 152 | rdpr %tl, %g3 | ||
| 153 | cmp %g3, 1 | ||
| 154 | |||
| 155 | 661: mov TLB_TAG_ACCESS, %g4 | ||
| 156 | ldxa [%g4] ASI_DMMU, %g5 | ||
| 157 | .section .sun4v_2insn_patch, "ax" | ||
| 158 | .word 661b | ||
| 159 | ldx [%g4 + HV_FAULT_D_ADDR_OFFSET], %g5 | ||
| 160 | nop | ||
| 161 | .previous | ||
| 162 | |||
| 163 | be,pt %xcc, sparc64_realfault_common | ||
| 164 | mov FAULT_CODE_DTLB, %g4 | ||
| 165 | ba,pt %xcc, winfix_trampoline | ||
| 166 | nop | ||
| 167 | |||
| 168 | tsb_do_itlb_fault: | ||
| 169 | rdpr %tpc, %g5 | ||
| 170 | ba,pt %xcc, sparc64_realfault_common | ||
| 171 | mov FAULT_CODE_ITLB, %g4 | ||
| 172 | |||
| 173 | .globl sparc64_realfault_common | ||
| 174 | sparc64_realfault_common: | ||
| 175 | /* fault code in %g4, fault address in %g5, etrap will | ||
| 176 | * preserve these two values in %l4 and %l5 respectively | ||
| 177 | */ | ||
| 178 | ba,pt %xcc, etrap ! Save trap state | ||
| 179 | 1: rd %pc, %g7 ! ... | ||
| 180 | stb %l4, [%g6 + TI_FAULT_CODE] ! Save fault code | ||
| 181 | stx %l5, [%g6 + TI_FAULT_ADDR] ! Save fault address | ||
| 182 | call do_sparc64_fault ! Call fault handler | ||
| 183 | add %sp, PTREGS_OFF, %o0 ! Compute pt_regs arg | ||
| 184 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state | ||
| 185 | nop ! Delay slot (fill me) | ||
| 186 | |||
| 187 | winfix_trampoline: | ||
| 188 | rdpr %tpc, %g3 ! Prepare winfixup TNPC | ||
| 189 | or %g3, 0x7c, %g3 ! Compute branch offset | ||
| 190 | wrpr %g3, %tnpc ! Write it into TNPC | ||
| 191 | done ! Trap return | ||
| 192 | |||
| 193 | /* Insert an entry into the TSB. | ||
| 194 | * | ||
| 195 | * %o0: TSB entry pointer (virt or phys address) | ||
| 196 | * %o1: tag | ||
| 197 | * %o2: pte | ||
| 198 | */ | ||
| 199 | .align 32 | ||
| 200 | .globl __tsb_insert | ||
| 201 | __tsb_insert: | ||
| 202 | rdpr %pstate, %o5 | ||
| 203 | wrpr %o5, PSTATE_IE, %pstate | ||
| 204 | TSB_LOCK_TAG(%o0, %g2, %g3) | ||
| 205 | TSB_WRITE(%o0, %o2, %o1) | ||
| 206 | wrpr %o5, %pstate | ||
| 207 | retl | ||
| 208 | nop | ||
| 209 | .size __tsb_insert, .-__tsb_insert | ||
| 210 | |||
| 211 | /* Flush the given TSB entry if it has the matching | ||
| 212 | * tag. | ||
| 213 | * | ||
| 214 | * %o0: TSB entry pointer (virt or phys address) | ||
| 215 | * %o1: tag | ||
| 216 | */ | ||
| 217 | .align 32 | ||
| 218 | .globl tsb_flush | ||
| 219 | .type tsb_flush,#function | ||
| 220 | tsb_flush: | ||
| 221 | sethi %hi(TSB_TAG_LOCK_HIGH), %g2 | ||
| 222 | 1: TSB_LOAD_TAG(%o0, %g1) | ||
| 223 | srlx %g1, 32, %o3 | ||
| 224 | andcc %o3, %g2, %g0 | ||
| 225 | bne,pn %icc, 1b | ||
| 226 | membar #LoadLoad | ||
| 227 | cmp %g1, %o1 | ||
| 228 | mov 1, %o3 | ||
| 229 | bne,pt %xcc, 2f | ||
| 230 | sllx %o3, TSB_TAG_INVALID_BIT, %o3 | ||
| 231 | TSB_CAS_TAG(%o0, %g1, %o3) | ||
| 232 | cmp %g1, %o3 | ||
| 233 | bne,pn %xcc, 1b | ||
| 234 | nop | ||
| 235 | 2: retl | ||
| 236 | TSB_MEMBAR | ||
| 237 | .size tsb_flush, .-tsb_flush | ||
| 238 | |||
| 239 | /* Reload MMU related context switch state at | ||
| 240 | * schedule() time. | ||
| 241 | * | ||
| 242 | * %o0: page table physical address | ||
| 243 | * %o1: TSB register value | ||
| 244 | * %o2: TSB virtual address | ||
| 245 | * %o3: TSB mapping locked PTE | ||
| 246 | * %o4: Hypervisor TSB descriptor physical address | ||
| 247 | * | ||
| 248 | * We have to run this whole thing with interrupts | ||
| 249 | * disabled so that the current cpu doesn't change | ||
| 250 | * due to preemption. | ||
| 251 | */ | ||
| 252 | .align 32 | ||
| 253 | .globl __tsb_context_switch | ||
| 254 | .type __tsb_context_switch,#function | ||
| 255 | __tsb_context_switch: | ||
| 256 | rdpr %pstate, %o5 | ||
| 257 | wrpr %o5, PSTATE_IE, %pstate | ||
| 258 | |||
| 259 | ldub [%g6 + TI_CPU], %g1 | ||
| 260 | sethi %hi(trap_block), %g2 | ||
| 261 | sllx %g1, TRAP_BLOCK_SZ_SHIFT, %g1 | ||
| 262 | or %g2, %lo(trap_block), %g2 | ||
| 263 | add %g2, %g1, %g2 | ||
| 264 | stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR] | ||
| 265 | |||
| 266 | sethi %hi(tlb_type), %g1 | ||
| 267 | lduw [%g1 + %lo(tlb_type)], %g1 | ||
| 268 | cmp %g1, 3 | ||
| 269 | bne,pt %icc, 1f | ||
| 270 | nop | ||
| 271 | |||
| 272 | /* Hypervisor TSB switch. */ | ||
| 273 | mov SCRATCHPAD_UTSBREG1, %g1 | ||
| 274 | stxa %o1, [%g1] ASI_SCRATCHPAD | ||
| 275 | mov -1, %g2 | ||
| 276 | mov SCRATCHPAD_UTSBREG2, %g1 | ||
| 277 | stxa %g2, [%g1] ASI_SCRATCHPAD | ||
| 278 | |||
| 279 | /* Save away %o5's %pstate, we have to use %o5 for | ||
| 280 | * the hypervisor call. | ||
| 281 | */ | ||
| 282 | mov %o5, %g1 | ||
| 283 | |||
| 284 | mov HV_FAST_MMU_TSB_CTXNON0, %o5 | ||
| 285 | mov 1, %o0 | ||
| 286 | mov %o4, %o1 | ||
| 287 | ta HV_FAST_TRAP | ||
| 288 | |||
| 289 | /* Finish up and restore %o5. */ | ||
| 290 | ba,pt %xcc, 9f | ||
| 291 | mov %g1, %o5 | ||
| 292 | |||
| 293 | /* SUN4U TSB switch. */ | ||
| 294 | 1: mov TSB_REG, %g1 | ||
| 295 | stxa %o1, [%g1] ASI_DMMU | ||
| 296 | membar #Sync | ||
| 297 | stxa %o1, [%g1] ASI_IMMU | ||
| 298 | membar #Sync | ||
| 299 | |||
| 300 | 2: brz %o2, 9f | ||
| 301 | nop | ||
| 302 | |||
| 303 | sethi %hi(sparc64_highest_unlocked_tlb_ent), %g2 | ||
| 304 | mov TLB_TAG_ACCESS, %g1 | ||
| 305 | lduw [%g2 + %lo(sparc64_highest_unlocked_tlb_ent)], %g2 | ||
| 306 | stxa %o2, [%g1] ASI_DMMU | ||
| 307 | membar #Sync | ||
| 308 | sllx %g2, 3, %g2 | ||
| 309 | stxa %o3, [%g2] ASI_DTLB_DATA_ACCESS | ||
| 310 | membar #Sync | ||
| 311 | 9: | ||
| 312 | wrpr %o5, %pstate | ||
| 313 | |||
| 314 | retl | ||
| 315 | nop | ||
| 316 | .size __tsb_context_switch, .-__tsb_context_switch | ||
| 317 | |||
| 318 | #define TSB_PASS_BITS ((1 << TSB_TAG_LOCK_BIT) | \ | ||
| 319 | (1 << TSB_TAG_INVALID_BIT)) | ||
| 320 | |||
| 321 | .align 32 | ||
| 322 | .globl copy_tsb | ||
| 323 | .type copy_tsb,#function | ||
| 324 | copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size | ||
| 325 | * %o2=new_tsb_base, %o3=new_tsb_size | ||
| 326 | */ | ||
| 327 | sethi %uhi(TSB_PASS_BITS), %g7 | ||
| 328 | srlx %o3, 4, %o3 | ||
| 329 | add %o0, %o1, %g1 /* end of old tsb */ | ||
| 330 | sllx %g7, 32, %g7 | ||
| 331 | sub %o3, 1, %o3 /* %o3 == new tsb hash mask */ | ||
| 332 | |||
| 333 | 661: prefetcha [%o0] ASI_N, #one_read | ||
| 334 | .section .tsb_phys_patch, "ax" | ||
| 335 | .word 661b | ||
| 336 | prefetcha [%o0] ASI_PHYS_USE_EC, #one_read | ||
| 337 | .previous | ||
| 338 | |||
| 339 | 90: andcc %o0, (64 - 1), %g0 | ||
| 340 | bne 1f | ||
| 341 | add %o0, 64, %o5 | ||
| 342 | |||
| 343 | 661: prefetcha [%o5] ASI_N, #one_read | ||
| 344 | .section .tsb_phys_patch, "ax" | ||
| 345 | .word 661b | ||
| 346 | prefetcha [%o5] ASI_PHYS_USE_EC, #one_read | ||
| 347 | .previous | ||
| 348 | |||
| 349 | 1: TSB_LOAD_QUAD(%o0, %g2) /* %g2/%g3 == TSB entry */ | ||
| 350 | andcc %g2, %g7, %g0 /* LOCK or INVALID set? */ | ||
| 351 | bne,pn %xcc, 80f /* Skip it */ | ||
| 352 | sllx %g2, 22, %o4 /* TAG --> VADDR */ | ||
| 353 | |||
| 354 | /* This can definitely be computed faster... */ | ||
| 355 | srlx %o0, 4, %o5 /* Build index */ | ||
| 356 | and %o5, 511, %o5 /* Mask index */ | ||
| 357 | sllx %o5, PAGE_SHIFT, %o5 /* Put into vaddr position */ | ||
| 358 | or %o4, %o5, %o4 /* Full VADDR. */ | ||
| 359 | srlx %o4, PAGE_SHIFT, %o4 /* Shift down to create index */ | ||
| 360 | and %o4, %o3, %o4 /* Mask with new_tsb_nents-1 */ | ||
| 361 | sllx %o4, 4, %o4 /* Shift back up into tsb ent offset */ | ||
| 362 | TSB_STORE(%o2 + %o4, %g2) /* Store TAG */ | ||
| 363 | add %o4, 0x8, %o4 /* Advance to TTE */ | ||
| 364 | TSB_STORE(%o2 + %o4, %g3) /* Store TTE */ | ||
| 365 | |||
| 366 | 80: add %o0, 16, %o0 | ||
| 367 | cmp %o0, %g1 | ||
| 368 | bne,pt %xcc, 90b | ||
| 369 | nop | ||
| 370 | |||
| 371 | retl | ||
| 372 | TSB_MEMBAR | ||
| 373 | .size copy_tsb, .-copy_tsb | ||
| 374 | |||
| 375 | /* Set the invalid bit in all TSB entries. */ | ||
| 376 | .align 32 | ||
| 377 | .globl tsb_init | ||
| 378 | .type tsb_init,#function | ||
| 379 | tsb_init: /* %o0 = TSB vaddr, %o1 = size in bytes */ | ||
| 380 | prefetch [%o0 + 0x000], #n_writes | ||
| 381 | mov 1, %g1 | ||
| 382 | prefetch [%o0 + 0x040], #n_writes | ||
| 383 | sllx %g1, TSB_TAG_INVALID_BIT, %g1 | ||
| 384 | prefetch [%o0 + 0x080], #n_writes | ||
| 385 | 1: prefetch [%o0 + 0x0c0], #n_writes | ||
| 386 | stx %g1, [%o0 + 0x00] | ||
| 387 | stx %g1, [%o0 + 0x10] | ||
| 388 | stx %g1, [%o0 + 0x20] | ||
| 389 | stx %g1, [%o0 + 0x30] | ||
| 390 | prefetch [%o0 + 0x100], #n_writes | ||
| 391 | stx %g1, [%o0 + 0x40] | ||
| 392 | stx %g1, [%o0 + 0x50] | ||
| 393 | stx %g1, [%o0 + 0x60] | ||
| 394 | stx %g1, [%o0 + 0x70] | ||
| 395 | prefetch [%o0 + 0x140], #n_writes | ||
| 396 | stx %g1, [%o0 + 0x80] | ||
| 397 | stx %g1, [%o0 + 0x90] | ||
| 398 | stx %g1, [%o0 + 0xa0] | ||
| 399 | stx %g1, [%o0 + 0xb0] | ||
| 400 | prefetch [%o0 + 0x180], #n_writes | ||
| 401 | stx %g1, [%o0 + 0xc0] | ||
| 402 | stx %g1, [%o0 + 0xd0] | ||
| 403 | stx %g1, [%o0 + 0xe0] | ||
| 404 | stx %g1, [%o0 + 0xf0] | ||
| 405 | subcc %o1, 0x100, %o1 | ||
| 406 | bne,pt %xcc, 1b | ||
| 407 | add %o0, 0x100, %o0 | ||
| 408 | retl | ||
| 409 | nop | ||
| 410 | nop | ||
| 411 | nop | ||
| 412 | .size tsb_init, .-tsb_init | ||
| 413 | |||
| 414 | .globl NGtsb_init | ||
| 415 | .type NGtsb_init,#function | ||
| 416 | NGtsb_init: | ||
| 417 | rd %asi, %g2 | ||
| 418 | mov 1, %g1 | ||
| 419 | wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi | ||
| 420 | sllx %g1, TSB_TAG_INVALID_BIT, %g1 | ||
| 421 | 1: stxa %g1, [%o0 + 0x00] %asi | ||
| 422 | stxa %g1, [%o0 + 0x10] %asi | ||
| 423 | stxa %g1, [%o0 + 0x20] %asi | ||
| 424 | stxa %g1, [%o0 + 0x30] %asi | ||
| 425 | stxa %g1, [%o0 + 0x40] %asi | ||
| 426 | stxa %g1, [%o0 + 0x50] %asi | ||
| 427 | stxa %g1, [%o0 + 0x60] %asi | ||
| 428 | stxa %g1, [%o0 + 0x70] %asi | ||
| 429 | stxa %g1, [%o0 + 0x80] %asi | ||
| 430 | stxa %g1, [%o0 + 0x90] %asi | ||
| 431 | stxa %g1, [%o0 + 0xa0] %asi | ||
| 432 | stxa %g1, [%o0 + 0xb0] %asi | ||
| 433 | stxa %g1, [%o0 + 0xc0] %asi | ||
| 434 | stxa %g1, [%o0 + 0xd0] %asi | ||
| 435 | stxa %g1, [%o0 + 0xe0] %asi | ||
| 436 | stxa %g1, [%o0 + 0xf0] %asi | ||
| 437 | subcc %o1, 0x100, %o1 | ||
| 438 | bne,pt %xcc, 1b | ||
| 439 | add %o0, 0x100, %o0 | ||
| 440 | retl | ||
| 441 | wr %g2, 0x0, %asi | ||
| 442 | .size NGtsb_init, .-NGtsb_init | ||
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 8365bc1f81f3..5d901519db55 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* $Id: ttable.S,v 1.38 2002/02/09 19:49:30 davem Exp $ | 1 | /* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah/SUN4V extensions. |
| 2 | * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions. | ||
| 3 | * | 2 | * |
| 4 | * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu) | 3 | * Copyright (C) 1996, 2001, 2006 David S. Miller (davem@davemloft.net) |
| 5 | */ | 4 | */ |
| 6 | 5 | ||
| 7 | #include <linux/config.h> | 6 | #include <linux/config.h> |
| @@ -19,7 +18,7 @@ tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) | |||
| 19 | tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) | 18 | tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) |
| 20 | tl0_iax: membar #Sync | 19 | tl0_iax: membar #Sync |
| 21 | TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception) | 20 | TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception) |
| 22 | tl0_resv009: BTRAP(0x9) | 21 | tl0_itsb_4v: SUN4V_ITSB_MISS |
| 23 | tl0_iae: membar #Sync | 22 | tl0_iae: membar #Sync |
| 24 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | 23 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) |
| 25 | tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) | 24 | tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) |
| @@ -38,7 +37,7 @@ tl0_div0: TRAP(do_div0) | |||
| 38 | tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) | 37 | tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) |
| 39 | tl0_resv02f: BTRAP(0x2f) | 38 | tl0_resv02f: BTRAP(0x2f) |
| 40 | tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception) | 39 | tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception) |
| 41 | tl0_resv031: BTRAP(0x31) | 40 | tl0_dtsb_4v: SUN4V_DTSB_MISS |
| 42 | tl0_dae: membar #Sync | 41 | tl0_dae: membar #Sync |
| 43 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | 42 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) |
| 44 | tl0_resv033: BTRAP(0x33) | 43 | tl0_resv033: BTRAP(0x33) |
| @@ -52,12 +51,13 @@ tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) | |||
| 52 | tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) | 51 | tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) |
| 53 | tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) | 52 | tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) |
| 54 | tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) | 53 | tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) |
| 54 | tl0_irq4: TRAP_IRQ(smp_new_mmu_context_version_client, 4) | ||
| 55 | #else | 55 | #else |
| 56 | tl0_irq1: BTRAP(0x41) | 56 | tl0_irq1: BTRAP(0x41) |
| 57 | tl0_irq2: BTRAP(0x42) | 57 | tl0_irq2: BTRAP(0x42) |
| 58 | tl0_irq3: BTRAP(0x43) | 58 | tl0_irq3: BTRAP(0x43) |
| 59 | tl0_irq4: BTRAP(0x44) | ||
| 59 | #endif | 60 | #endif |
| 60 | tl0_irq4: TRAP_IRQ(handler_irq, 4) | ||
| 61 | tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) | 61 | tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) |
| 62 | tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) | 62 | tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) |
| 63 | tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) | 63 | tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) |
| @@ -78,9 +78,9 @@ tl0_vaw: TRAP(do_vaw) | |||
| 78 | tl0_cee: membar #Sync | 78 | tl0_cee: membar #Sync |
| 79 | TRAP_NOSAVE_7INSNS(__spitfire_cee_trap) | 79 | TRAP_NOSAVE_7INSNS(__spitfire_cee_trap) |
| 80 | tl0_iamiss: | 80 | tl0_iamiss: |
| 81 | #include "itlb_base.S" | 81 | #include "itlb_miss.S" |
| 82 | tl0_damiss: | 82 | tl0_damiss: |
| 83 | #include "dtlb_base.S" | 83 | #include "dtlb_miss.S" |
| 84 | tl0_daprot: | 84 | tl0_daprot: |
| 85 | #include "dtlb_prot.S" | 85 | #include "dtlb_prot.S" |
| 86 | tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ | 86 | tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ |
| @@ -88,15 +88,18 @@ tl0_dcpe: BTRAP(0x71) /* D-cache Parity Error on Cheetah+ */ | |||
| 88 | tl0_icpe: BTRAP(0x72) /* I-cache Parity Error on Cheetah+ */ | 88 | tl0_icpe: BTRAP(0x72) /* I-cache Parity Error on Cheetah+ */ |
| 89 | tl0_resv073: BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) | 89 | tl0_resv073: BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) |
| 90 | tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) | 90 | tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) |
| 91 | tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f) | 91 | tl0_cpu_mondo: TRAP_NOSAVE(sun4v_cpu_mondo) |
| 92 | tl0_dev_mondo: TRAP_NOSAVE(sun4v_dev_mondo) | ||
| 93 | tl0_res_mondo: TRAP_NOSAVE(sun4v_res_mondo) | ||
| 94 | tl0_nres_mondo: TRAP_NOSAVE(sun4v_nonres_mondo) | ||
| 92 | tl0_s0n: SPILL_0_NORMAL | 95 | tl0_s0n: SPILL_0_NORMAL |
| 93 | tl0_s1n: SPILL_1_NORMAL | 96 | tl0_s1n: SPILL_1_NORMAL |
| 94 | tl0_s2n: SPILL_2_NORMAL | 97 | tl0_s2n: SPILL_2_NORMAL |
| 95 | tl0_s3n: SPILL_3_NORMAL | 98 | tl0_s3n: SPILL_0_NORMAL_ETRAP |
| 96 | tl0_s4n: SPILL_4_NORMAL | 99 | tl0_s4n: SPILL_1_GENERIC_ETRAP |
| 97 | tl0_s5n: SPILL_5_NORMAL | 100 | tl0_s5n: SPILL_1_GENERIC_ETRAP_FIXUP |
| 98 | tl0_s6n: SPILL_6_NORMAL | 101 | tl0_s6n: SPILL_2_GENERIC_ETRAP |
| 99 | tl0_s7n: SPILL_7_NORMAL | 102 | tl0_s7n: SPILL_2_GENERIC_ETRAP_FIXUP |
| 100 | tl0_s0o: SPILL_0_OTHER | 103 | tl0_s0o: SPILL_0_OTHER |
| 101 | tl0_s1o: SPILL_1_OTHER | 104 | tl0_s1o: SPILL_1_OTHER |
| 102 | tl0_s2o: SPILL_2_OTHER | 105 | tl0_s2o: SPILL_2_OTHER |
| @@ -110,9 +113,9 @@ tl0_f1n: FILL_1_NORMAL | |||
| 110 | tl0_f2n: FILL_2_NORMAL | 113 | tl0_f2n: FILL_2_NORMAL |
| 111 | tl0_f3n: FILL_3_NORMAL | 114 | tl0_f3n: FILL_3_NORMAL |
| 112 | tl0_f4n: FILL_4_NORMAL | 115 | tl0_f4n: FILL_4_NORMAL |
| 113 | tl0_f5n: FILL_5_NORMAL | 116 | tl0_f5n: FILL_0_NORMAL_RTRAP |
| 114 | tl0_f6n: FILL_6_NORMAL | 117 | tl0_f6n: FILL_1_GENERIC_RTRAP |
| 115 | tl0_f7n: FILL_7_NORMAL | 118 | tl0_f7n: FILL_2_GENERIC_RTRAP |
| 116 | tl0_f0o: FILL_0_OTHER | 119 | tl0_f0o: FILL_0_OTHER |
| 117 | tl0_f1o: FILL_1_OTHER | 120 | tl0_f1o: FILL_1_OTHER |
| 118 | tl0_f2o: FILL_2_OTHER | 121 | tl0_f2o: FILL_2_OTHER |
| @@ -128,7 +131,7 @@ tl0_flushw: FLUSH_WINDOW_TRAP | |||
| 128 | tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) | 131 | tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) |
| 129 | .globl tl0_solaris | 132 | .globl tl0_solaris |
| 130 | tl0_solaris: SOLARIS_SYSCALL_TRAP | 133 | tl0_solaris: SOLARIS_SYSCALL_TRAP |
| 131 | tl0_netbsd: NETBSD_SYSCALL_TRAP | 134 | tl0_resv109: BTRAP(0x109) |
| 132 | tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e) | 135 | tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e) |
| 133 | tl0_resv10f: BTRAP(0x10f) | 136 | tl0_resv10f: BTRAP(0x10f) |
| 134 | tl0_linux32: LINUX_32BIT_SYSCALL_TRAP | 137 | tl0_linux32: LINUX_32BIT_SYSCALL_TRAP |
| @@ -179,7 +182,7 @@ sparc64_ttable_tl1: | |||
| 179 | tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) | 182 | tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) |
| 180 | tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) | 183 | tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) |
| 181 | tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1) | 184 | tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1) |
| 182 | tl1_resv009: BTRAPTL1(0x9) | 185 | tl1_itsb_4v: SUN4V_ITSB_MISS |
| 183 | tl1_iae: membar #Sync | 186 | tl1_iae: membar #Sync |
| 184 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | 187 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) |
| 185 | tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) | 188 | tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) |
| @@ -198,7 +201,7 @@ tl1_div0: TRAPTL1(do_div0_tl1) | |||
| 198 | tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) | 201 | tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) |
| 199 | tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) | 202 | tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) |
| 200 | tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1) | 203 | tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1) |
| 201 | tl1_resv031: BTRAPTL1(0x31) | 204 | tl1_dtsb_4v: SUN4V_DTSB_MISS |
| 202 | tl1_dae: membar #Sync | 205 | tl1_dae: membar #Sync |
| 203 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | 206 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) |
| 204 | tl1_resv033: BTRAPTL1(0x33) | 207 | tl1_resv033: BTRAPTL1(0x33) |
| @@ -222,26 +225,10 @@ tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f) | |||
| 222 | tl1_ivec: TRAP_IVEC | 225 | tl1_ivec: TRAP_IVEC |
| 223 | tl1_paw: TRAPTL1(do_paw_tl1) | 226 | tl1_paw: TRAPTL1(do_paw_tl1) |
| 224 | tl1_vaw: TRAPTL1(do_vaw_tl1) | 227 | tl1_vaw: TRAPTL1(do_vaw_tl1) |
| 225 | 228 | tl1_cee: BTRAPTL1(0x63) | |
| 226 | /* The grotty trick to save %g1 into current->thread.cee_stuff | ||
| 227 | * is because when we take this trap we could be interrupting | ||
| 228 | * trap code already using the trap alternate global registers. | ||
| 229 | * | ||
| 230 | * We cross our fingers and pray that this store/load does | ||
| 231 | * not cause yet another CEE trap. | ||
| 232 | */ | ||
| 233 | tl1_cee: membar #Sync | ||
| 234 | stx %g1, [%g6 + TI_CEE_STUFF] | ||
| 235 | ldxa [%g0] ASI_AFSR, %g1 | ||
| 236 | membar #Sync | ||
| 237 | stxa %g1, [%g0] ASI_AFSR | ||
| 238 | membar #Sync | ||
| 239 | ldx [%g6 + TI_CEE_STUFF], %g1 | ||
| 240 | retry | ||
| 241 | |||
| 242 | tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) | 229 | tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) |
| 243 | tl1_damiss: | 230 | tl1_damiss: |
| 244 | #include "dtlb_backend.S" | 231 | #include "dtlb_miss.S" |
| 245 | tl1_daprot: | 232 | tl1_daprot: |
| 246 | #include "dtlb_prot.S" | 233 | #include "dtlb_prot.S" |
| 247 | tl1_fecc: BTRAPTL1(0x70) /* Fast-ECC on Cheetah */ | 234 | tl1_fecc: BTRAPTL1(0x70) /* Fast-ECC on Cheetah */ |
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 70faf630603b..001e8518331f 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
| @@ -277,7 +277,7 @@ static void kernel_mna_trap_fault(void) | |||
| 277 | regs->tstate |= (ASI_AIUS << 24UL); | 277 | regs->tstate |= (ASI_AIUS << 24UL); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) | 280 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) |
| 281 | { | 281 | { |
| 282 | enum direction dir = decode_direction(insn); | 282 | enum direction dir = decode_direction(insn); |
| 283 | int size = decode_access_size(insn); | 283 | int size = decode_access_size(insn); |
| @@ -405,6 +405,9 @@ extern void do_privact(struct pt_regs *regs); | |||
| 405 | extern void spitfire_data_access_exception(struct pt_regs *regs, | 405 | extern void spitfire_data_access_exception(struct pt_regs *regs, |
| 406 | unsigned long sfsr, | 406 | unsigned long sfsr, |
| 407 | unsigned long sfar); | 407 | unsigned long sfar); |
| 408 | extern void sun4v_data_access_exception(struct pt_regs *regs, | ||
| 409 | unsigned long addr, | ||
| 410 | unsigned long type_ctx); | ||
| 408 | 411 | ||
| 409 | int handle_ldf_stq(u32 insn, struct pt_regs *regs) | 412 | int handle_ldf_stq(u32 insn, struct pt_regs *regs) |
| 410 | { | 413 | { |
| @@ -447,14 +450,20 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) | |||
| 447 | break; | 450 | break; |
| 448 | } | 451 | } |
| 449 | default: | 452 | default: |
| 450 | spitfire_data_access_exception(regs, 0, addr); | 453 | if (tlb_type == hypervisor) |
| 454 | sun4v_data_access_exception(regs, addr, 0); | ||
| 455 | else | ||
| 456 | spitfire_data_access_exception(regs, 0, addr); | ||
| 451 | return 1; | 457 | return 1; |
| 452 | } | 458 | } |
| 453 | if (put_user (first >> 32, (u32 __user *)addr) || | 459 | if (put_user (first >> 32, (u32 __user *)addr) || |
| 454 | __put_user ((u32)first, (u32 __user *)(addr + 4)) || | 460 | __put_user ((u32)first, (u32 __user *)(addr + 4)) || |
| 455 | __put_user (second >> 32, (u32 __user *)(addr + 8)) || | 461 | __put_user (second >> 32, (u32 __user *)(addr + 8)) || |
| 456 | __put_user ((u32)second, (u32 __user *)(addr + 12))) { | 462 | __put_user ((u32)second, (u32 __user *)(addr + 12))) { |
| 457 | spitfire_data_access_exception(regs, 0, addr); | 463 | if (tlb_type == hypervisor) |
| 464 | sun4v_data_access_exception(regs, addr, 0); | ||
| 465 | else | ||
| 466 | spitfire_data_access_exception(regs, 0, addr); | ||
| 458 | return 1; | 467 | return 1; |
| 459 | } | 468 | } |
| 460 | } else { | 469 | } else { |
| @@ -467,7 +476,10 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) | |||
| 467 | do_privact(regs); | 476 | do_privact(regs); |
| 468 | return 1; | 477 | return 1; |
| 469 | } else if (asi > ASI_SNFL) { | 478 | } else if (asi > ASI_SNFL) { |
| 470 | spitfire_data_access_exception(regs, 0, addr); | 479 | if (tlb_type == hypervisor) |
| 480 | sun4v_data_access_exception(regs, addr, 0); | ||
| 481 | else | ||
| 482 | spitfire_data_access_exception(regs, 0, addr); | ||
| 471 | return 1; | 483 | return 1; |
| 472 | } | 484 | } |
| 473 | switch (insn & 0x180000) { | 485 | switch (insn & 0x180000) { |
| @@ -484,7 +496,10 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) | |||
| 484 | err |= __get_user (data[i], (u32 __user *)(addr + 4*i)); | 496 | err |= __get_user (data[i], (u32 __user *)(addr + 4*i)); |
| 485 | } | 497 | } |
| 486 | if (err && !(asi & 0x2 /* NF */)) { | 498 | if (err && !(asi & 0x2 /* NF */)) { |
| 487 | spitfire_data_access_exception(regs, 0, addr); | 499 | if (tlb_type == hypervisor) |
| 500 | sun4v_data_access_exception(regs, addr, 0); | ||
| 501 | else | ||
| 502 | spitfire_data_access_exception(regs, 0, addr); | ||
| 488 | return 1; | 503 | return 1; |
| 489 | } | 504 | } |
| 490 | if (asi & 0x8) /* Little */ { | 505 | if (asi & 0x8) /* Little */ { |
| @@ -548,7 +563,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
| 548 | u32 insn; | 563 | u32 insn; |
| 549 | u32 first, second; | 564 | u32 first, second; |
| 550 | u64 value; | 565 | u64 value; |
| 551 | u8 asi, freg; | 566 | u8 freg; |
| 552 | int flag; | 567 | int flag; |
| 553 | struct fpustate *f = FPUSTATE; | 568 | struct fpustate *f = FPUSTATE; |
| 554 | 569 | ||
| @@ -557,7 +572,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
| 557 | if (test_thread_flag(TIF_32BIT)) | 572 | if (test_thread_flag(TIF_32BIT)) |
| 558 | pc = (u32)pc; | 573 | pc = (u32)pc; |
| 559 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { | 574 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { |
| 560 | asi = sfsr >> 16; | 575 | int asi = decode_asi(insn, regs); |
| 561 | if ((asi > ASI_SNFL) || | 576 | if ((asi > ASI_SNFL) || |
| 562 | (asi < ASI_P)) | 577 | (asi < ASI_P)) |
| 563 | goto daex; | 578 | goto daex; |
| @@ -587,7 +602,11 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
| 587 | *(u64 *)(f->regs + freg) = value; | 602 | *(u64 *)(f->regs + freg) = value; |
| 588 | current_thread_info()->fpsaved[0] |= flag; | 603 | current_thread_info()->fpsaved[0] |= flag; |
| 589 | } else { | 604 | } else { |
| 590 | daex: spitfire_data_access_exception(regs, sfsr, sfar); | 605 | daex: |
| 606 | if (tlb_type == hypervisor) | ||
| 607 | sun4v_data_access_exception(regs, sfar, sfsr); | ||
| 608 | else | ||
| 609 | spitfire_data_access_exception(regs, sfsr, sfar); | ||
| 591 | return; | 610 | return; |
| 592 | } | 611 | } |
| 593 | advance(regs); | 612 | advance(regs); |
| @@ -600,7 +619,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
| 600 | unsigned long tstate = regs->tstate; | 619 | unsigned long tstate = regs->tstate; |
| 601 | u32 insn; | 620 | u32 insn; |
| 602 | u64 value; | 621 | u64 value; |
| 603 | u8 asi, freg; | 622 | u8 freg; |
| 604 | int flag; | 623 | int flag; |
| 605 | struct fpustate *f = FPUSTATE; | 624 | struct fpustate *f = FPUSTATE; |
| 606 | 625 | ||
| @@ -609,8 +628,8 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
| 609 | if (test_thread_flag(TIF_32BIT)) | 628 | if (test_thread_flag(TIF_32BIT)) |
| 610 | pc = (u32)pc; | 629 | pc = (u32)pc; |
| 611 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { | 630 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { |
| 631 | int asi = decode_asi(insn, regs); | ||
| 612 | freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); | 632 | freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); |
| 613 | asi = sfsr >> 16; | ||
| 614 | value = 0; | 633 | value = 0; |
| 615 | flag = (freg < 32) ? FPRS_DL : FPRS_DU; | 634 | flag = (freg < 32) ? FPRS_DL : FPRS_DU; |
| 616 | if ((asi > ASI_SNFL) || | 635 | if ((asi > ASI_SNFL) || |
| @@ -631,7 +650,11 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
| 631 | __put_user ((u32)value, (u32 __user *)(sfar + 4))) | 650 | __put_user ((u32)value, (u32 __user *)(sfar + 4))) |
| 632 | goto daex; | 651 | goto daex; |
| 633 | } else { | 652 | } else { |
| 634 | daex: spitfire_data_access_exception(regs, sfsr, sfar); | 653 | daex: |
| 654 | if (tlb_type == hypervisor) | ||
| 655 | sun4v_data_access_exception(regs, sfar, sfsr); | ||
| 656 | else | ||
| 657 | spitfire_data_access_exception(regs, sfsr, sfar); | ||
| 635 | return; | 658 | return; |
| 636 | } | 659 | } |
| 637 | advance(regs); | 660 | advance(regs); |
diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c index b35dc8dc995a..1f83fe6a82d6 100644 --- a/arch/sparc64/kernel/us2e_cpufreq.c +++ b/arch/sparc64/kernel/us2e_cpufreq.c | |||
| @@ -346,6 +346,9 @@ static int __init us2e_freq_init(void) | |||
| 346 | unsigned long manuf, impl, ver; | 346 | unsigned long manuf, impl, ver; |
| 347 | int ret; | 347 | int ret; |
| 348 | 348 | ||
| 349 | if (tlb_type != spitfire) | ||
| 350 | return -ENODEV; | ||
| 351 | |||
| 349 | __asm__("rdpr %%ver, %0" : "=r" (ver)); | 352 | __asm__("rdpr %%ver, %0" : "=r" (ver)); |
| 350 | manuf = ((ver >> 48) & 0xffff); | 353 | manuf = ((ver >> 48) & 0xffff); |
| 351 | impl = ((ver >> 32) & 0xffff); | 354 | impl = ((ver >> 32) & 0xffff); |
| @@ -354,20 +357,16 @@ static int __init us2e_freq_init(void) | |||
| 354 | struct cpufreq_driver *driver; | 357 | struct cpufreq_driver *driver; |
| 355 | 358 | ||
| 356 | ret = -ENOMEM; | 359 | ret = -ENOMEM; |
| 357 | driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); | 360 | driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); |
| 358 | if (!driver) | 361 | if (!driver) |
| 359 | goto err_out; | 362 | goto err_out; |
| 360 | memset(driver, 0, sizeof(*driver)); | ||
| 361 | 363 | ||
| 362 | us2e_freq_table = kmalloc( | 364 | us2e_freq_table = kzalloc( |
| 363 | (NR_CPUS * sizeof(struct us2e_freq_percpu_info)), | 365 | (NR_CPUS * sizeof(struct us2e_freq_percpu_info)), |
| 364 | GFP_KERNEL); | 366 | GFP_KERNEL); |
| 365 | if (!us2e_freq_table) | 367 | if (!us2e_freq_table) |
| 366 | goto err_out; | 368 | goto err_out; |
| 367 | 369 | ||
| 368 | memset(us2e_freq_table, 0, | ||
| 369 | (NR_CPUS * sizeof(struct us2e_freq_percpu_info))); | ||
| 370 | |||
| 371 | driver->init = us2e_freq_cpu_init; | 370 | driver->init = us2e_freq_cpu_init; |
| 372 | driver->verify = us2e_freq_verify; | 371 | driver->verify = us2e_freq_verify; |
| 373 | driver->target = us2e_freq_target; | 372 | driver->target = us2e_freq_target; |
diff --git a/arch/sparc64/kernel/us3_cpufreq.c b/arch/sparc64/kernel/us3_cpufreq.c index 6d1f9a3c464f..47e3acafb5be 100644 --- a/arch/sparc64/kernel/us3_cpufreq.c +++ b/arch/sparc64/kernel/us3_cpufreq.c | |||
| @@ -203,6 +203,9 @@ static int __init us3_freq_init(void) | |||
| 203 | unsigned long manuf, impl, ver; | 203 | unsigned long manuf, impl, ver; |
| 204 | int ret; | 204 | int ret; |
| 205 | 205 | ||
| 206 | if (tlb_type != cheetah && tlb_type != cheetah_plus) | ||
| 207 | return -ENODEV; | ||
| 208 | |||
| 206 | __asm__("rdpr %%ver, %0" : "=r" (ver)); | 209 | __asm__("rdpr %%ver, %0" : "=r" (ver)); |
| 207 | manuf = ((ver >> 48) & 0xffff); | 210 | manuf = ((ver >> 48) & 0xffff); |
| 208 | impl = ((ver >> 32) & 0xffff); | 211 | impl = ((ver >> 32) & 0xffff); |
| @@ -215,20 +218,16 @@ static int __init us3_freq_init(void) | |||
| 215 | struct cpufreq_driver *driver; | 218 | struct cpufreq_driver *driver; |
| 216 | 219 | ||
| 217 | ret = -ENOMEM; | 220 | ret = -ENOMEM; |
| 218 | driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); | 221 | driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); |
| 219 | if (!driver) | 222 | if (!driver) |
| 220 | goto err_out; | 223 | goto err_out; |
| 221 | memset(driver, 0, sizeof(*driver)); | ||
| 222 | 224 | ||
| 223 | us3_freq_table = kmalloc( | 225 | us3_freq_table = kzalloc( |
| 224 | (NR_CPUS * sizeof(struct us3_freq_percpu_info)), | 226 | (NR_CPUS * sizeof(struct us3_freq_percpu_info)), |
| 225 | GFP_KERNEL); | 227 | GFP_KERNEL); |
| 226 | if (!us3_freq_table) | 228 | if (!us3_freq_table) |
| 227 | goto err_out; | 229 | goto err_out; |
| 228 | 230 | ||
| 229 | memset(us3_freq_table, 0, | ||
| 230 | (NR_CPUS * sizeof(struct us3_freq_percpu_info))); | ||
| 231 | |||
| 232 | driver->init = us3_freq_cpu_init; | 231 | driver->init = us3_freq_cpu_init; |
| 233 | driver->verify = us3_freq_verify; | 232 | driver->verify = us3_freq_verify; |
| 234 | driver->target = us3_freq_target; | 233 | driver->target = us3_freq_target; |
diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c new file mode 100644 index 000000000000..84fedaa38aae --- /dev/null +++ b/arch/sparc64/kernel/visemul.c | |||
| @@ -0,0 +1,894 @@ | |||
| 1 | /* visemul.c: Emulation of VIS instructions. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/errno.h> | ||
| 7 | #include <linux/thread_info.h> | ||
| 8 | |||
| 9 | #include <asm/ptrace.h> | ||
| 10 | #include <asm/pstate.h> | ||
| 11 | #include <asm/system.h> | ||
| 12 | #include <asm/fpumacro.h> | ||
| 13 | #include <asm/uaccess.h> | ||
| 14 | |||
| 15 | /* OPF field of various VIS instructions. */ | ||
| 16 | |||
| 17 | /* 000111011 - four 16-bit packs */ | ||
| 18 | #define FPACK16_OPF 0x03b | ||
| 19 | |||
| 20 | /* 000111010 - two 32-bit packs */ | ||
| 21 | #define FPACK32_OPF 0x03a | ||
| 22 | |||
| 23 | /* 000111101 - four 16-bit packs */ | ||
| 24 | #define FPACKFIX_OPF 0x03d | ||
| 25 | |||
| 26 | /* 001001101 - four 16-bit expands */ | ||
| 27 | #define FEXPAND_OPF 0x04d | ||
| 28 | |||
| 29 | /* 001001011 - two 32-bit merges */ | ||
| 30 | #define FPMERGE_OPF 0x04b | ||
| 31 | |||
| 32 | /* 000110001 - 8-by-16-bit partitoned product */ | ||
| 33 | #define FMUL8x16_OPF 0x031 | ||
| 34 | |||
| 35 | /* 000110011 - 8-by-16-bit upper alpha partitioned product */ | ||
| 36 | #define FMUL8x16AU_OPF 0x033 | ||
| 37 | |||
| 38 | /* 000110101 - 8-by-16-bit lower alpha partitioned product */ | ||
| 39 | #define FMUL8x16AL_OPF 0x035 | ||
| 40 | |||
| 41 | /* 000110110 - upper 8-by-16-bit partitioned product */ | ||
| 42 | #define FMUL8SUx16_OPF 0x036 | ||
| 43 | |||
| 44 | /* 000110111 - lower 8-by-16-bit partitioned product */ | ||
| 45 | #define FMUL8ULx16_OPF 0x037 | ||
| 46 | |||
| 47 | /* 000111000 - upper 8-by-16-bit partitioned product */ | ||
| 48 | #define FMULD8SUx16_OPF 0x038 | ||
| 49 | |||
| 50 | /* 000111001 - lower unsigned 8-by-16-bit partitioned product */ | ||
| 51 | #define FMULD8ULx16_OPF 0x039 | ||
| 52 | |||
| 53 | /* 000101000 - four 16-bit compare; set rd if src1 > src2 */ | ||
| 54 | #define FCMPGT16_OPF 0x028 | ||
| 55 | |||
| 56 | /* 000101100 - two 32-bit compare; set rd if src1 > src2 */ | ||
| 57 | #define FCMPGT32_OPF 0x02c | ||
| 58 | |||
| 59 | /* 000100000 - four 16-bit compare; set rd if src1 <= src2 */ | ||
| 60 | #define FCMPLE16_OPF 0x020 | ||
| 61 | |||
| 62 | /* 000100100 - two 32-bit compare; set rd if src1 <= src2 */ | ||
| 63 | #define FCMPLE32_OPF 0x024 | ||
| 64 | |||
| 65 | /* 000100010 - four 16-bit compare; set rd if src1 != src2 */ | ||
| 66 | #define FCMPNE16_OPF 0x022 | ||
| 67 | |||
| 68 | /* 000100110 - two 32-bit compare; set rd if src1 != src2 */ | ||
| 69 | #define FCMPNE32_OPF 0x026 | ||
| 70 | |||
| 71 | /* 000101010 - four 16-bit compare; set rd if src1 == src2 */ | ||
| 72 | #define FCMPEQ16_OPF 0x02a | ||
| 73 | |||
| 74 | /* 000101110 - two 32-bit compare; set rd if src1 == src2 */ | ||
| 75 | #define FCMPEQ32_OPF 0x02e | ||
| 76 | |||
| 77 | /* 000000000 - Eight 8-bit edge boundary processing */ | ||
| 78 | #define EDGE8_OPF 0x000 | ||
| 79 | |||
| 80 | /* 000000001 - Eight 8-bit edge boundary processing, no CC */ | ||
| 81 | #define EDGE8N_OPF 0x001 | ||
| 82 | |||
| 83 | /* 000000010 - Eight 8-bit edge boundary processing, little-endian */ | ||
| 84 | #define EDGE8L_OPF 0x002 | ||
| 85 | |||
| 86 | /* 000000011 - Eight 8-bit edge boundary processing, little-endian, no CC */ | ||
| 87 | #define EDGE8LN_OPF 0x003 | ||
| 88 | |||
| 89 | /* 000000100 - Four 16-bit edge boundary processing */ | ||
| 90 | #define EDGE16_OPF 0x004 | ||
| 91 | |||
| 92 | /* 000000101 - Four 16-bit edge boundary processing, no CC */ | ||
| 93 | #define EDGE16N_OPF 0x005 | ||
| 94 | |||
| 95 | /* 000000110 - Four 16-bit edge boundary processing, little-endian */ | ||
| 96 | #define EDGE16L_OPF 0x006 | ||
| 97 | |||
| 98 | /* 000000111 - Four 16-bit edge boundary processing, little-endian, no CC */ | ||
| 99 | #define EDGE16LN_OPF 0x007 | ||
| 100 | |||
| 101 | /* 000001000 - Two 32-bit edge boundary processing */ | ||
| 102 | #define EDGE32_OPF 0x008 | ||
| 103 | |||
| 104 | /* 000001001 - Two 32-bit edge boundary processing, no CC */ | ||
| 105 | #define EDGE32N_OPF 0x009 | ||
| 106 | |||
| 107 | /* 000001010 - Two 32-bit edge boundary processing, little-endian */ | ||
| 108 | #define EDGE32L_OPF 0x00a | ||
| 109 | |||
| 110 | /* 000001011 - Two 32-bit edge boundary processing, little-endian, no CC */ | ||
| 111 | #define EDGE32LN_OPF 0x00b | ||
| 112 | |||
| 113 | /* 000111110 - distance between 8 8-bit components */ | ||
| 114 | #define PDIST_OPF 0x03e | ||
| 115 | |||
| 116 | /* 000010000 - convert 8-bit 3-D address to blocked byte address */ | ||
| 117 | #define ARRAY8_OPF 0x010 | ||
| 118 | |||
| 119 | /* 000010010 - convert 16-bit 3-D address to blocked byte address */ | ||
| 120 | #define ARRAY16_OPF 0x012 | ||
| 121 | |||
| 122 | /* 000010100 - convert 32-bit 3-D address to blocked byte address */ | ||
| 123 | #define ARRAY32_OPF 0x014 | ||
| 124 | |||
| 125 | /* 000011001 - Set the GSR.MASK field in preparation for a BSHUFFLE */ | ||
| 126 | #define BMASK_OPF 0x019 | ||
| 127 | |||
| 128 | /* 001001100 - Permute bytes as specified by GSR.MASK */ | ||
| 129 | #define BSHUFFLE_OPF 0x04c | ||
| 130 | |||
| 131 | #define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19)) | ||
| 132 | #define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19)) | ||
| 133 | |||
| 134 | #define VIS_OPF_SHIFT 5 | ||
| 135 | #define VIS_OPF_MASK (0x1ff << VIS_OPF_SHIFT) | ||
| 136 | |||
| 137 | #define RS1(INSN) (((INSN) >> 24) & 0x1f) | ||
| 138 | #define RS2(INSN) (((INSN) >> 0) & 0x1f) | ||
| 139 | #define RD(INSN) (((INSN) >> 25) & 0x1f) | ||
| 140 | |||
| 141 | static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, | ||
| 142 | unsigned int rd, int from_kernel) | ||
| 143 | { | ||
| 144 | if (rs2 >= 16 || rs1 >= 16 || rd >= 16) { | ||
| 145 | if (from_kernel != 0) | ||
| 146 | __asm__ __volatile__("flushw"); | ||
| 147 | else | ||
| 148 | flushw_user(); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) | ||
| 153 | { | ||
| 154 | unsigned long value; | ||
| 155 | |||
| 156 | if (reg < 16) | ||
| 157 | return (!reg ? 0 : regs->u_regs[reg]); | ||
| 158 | if (regs->tstate & TSTATE_PRIV) { | ||
| 159 | struct reg_window *win; | ||
| 160 | win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); | ||
| 161 | value = win->locals[reg - 16]; | ||
| 162 | } else if (test_thread_flag(TIF_32BIT)) { | ||
| 163 | struct reg_window32 __user *win32; | ||
| 164 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | ||
| 165 | get_user(value, &win32->locals[reg - 16]); | ||
| 166 | } else { | ||
| 167 | struct reg_window __user *win; | ||
| 168 | win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); | ||
| 169 | get_user(value, &win->locals[reg - 16]); | ||
| 170 | } | ||
| 171 | return value; | ||
| 172 | } | ||
| 173 | |||
| 174 | static inline unsigned long __user *__fetch_reg_addr_user(unsigned int reg, | ||
| 175 | struct pt_regs *regs) | ||
| 176 | { | ||
| 177 | BUG_ON(reg < 16); | ||
| 178 | BUG_ON(regs->tstate & TSTATE_PRIV); | ||
| 179 | |||
| 180 | if (test_thread_flag(TIF_32BIT)) { | ||
| 181 | struct reg_window32 __user *win32; | ||
| 182 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | ||
| 183 | return (unsigned long __user *)&win32->locals[reg - 16]; | ||
| 184 | } else { | ||
| 185 | struct reg_window __user *win; | ||
| 186 | win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); | ||
| 187 | return &win->locals[reg - 16]; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | static inline unsigned long *__fetch_reg_addr_kern(unsigned int reg, | ||
| 192 | struct pt_regs *regs) | ||
| 193 | { | ||
| 194 | BUG_ON(reg >= 16); | ||
| 195 | BUG_ON(regs->tstate & TSTATE_PRIV); | ||
| 196 | |||
| 197 | return ®s->u_regs[reg]; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void store_reg(struct pt_regs *regs, unsigned long val, unsigned long rd) | ||
| 201 | { | ||
| 202 | if (rd < 16) { | ||
| 203 | unsigned long *rd_kern = __fetch_reg_addr_kern(rd, regs); | ||
| 204 | |||
| 205 | *rd_kern = val; | ||
| 206 | } else { | ||
| 207 | unsigned long __user *rd_user = __fetch_reg_addr_user(rd, regs); | ||
| 208 | |||
| 209 | if (test_thread_flag(TIF_32BIT)) | ||
| 210 | __put_user((u32)val, (u32 __user *)rd_user); | ||
| 211 | else | ||
| 212 | __put_user(val, rd_user); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | static inline unsigned long fpd_regval(struct fpustate *f, | ||
| 217 | unsigned int insn_regnum) | ||
| 218 | { | ||
| 219 | insn_regnum = (((insn_regnum & 1) << 5) | | ||
| 220 | (insn_regnum & 0x1e)); | ||
| 221 | |||
| 222 | return *(unsigned long *) &f->regs[insn_regnum]; | ||
| 223 | } | ||
| 224 | |||
| 225 | static inline unsigned long *fpd_regaddr(struct fpustate *f, | ||
| 226 | unsigned int insn_regnum) | ||
| 227 | { | ||
| 228 | insn_regnum = (((insn_regnum & 1) << 5) | | ||
| 229 | (insn_regnum & 0x1e)); | ||
| 230 | |||
| 231 | return (unsigned long *) &f->regs[insn_regnum]; | ||
| 232 | } | ||
| 233 | |||
| 234 | static inline unsigned int fps_regval(struct fpustate *f, | ||
| 235 | unsigned int insn_regnum) | ||
| 236 | { | ||
| 237 | return f->regs[insn_regnum]; | ||
| 238 | } | ||
| 239 | |||
| 240 | static inline unsigned int *fps_regaddr(struct fpustate *f, | ||
| 241 | unsigned int insn_regnum) | ||
| 242 | { | ||
| 243 | return &f->regs[insn_regnum]; | ||
| 244 | } | ||
| 245 | |||
| 246 | struct edge_tab { | ||
| 247 | u16 left, right; | ||
| 248 | }; | ||
| 249 | struct edge_tab edge8_tab[8] = { | ||
| 250 | { 0xff, 0x80 }, | ||
| 251 | { 0x7f, 0xc0 }, | ||
| 252 | { 0x3f, 0xe0 }, | ||
| 253 | { 0x1f, 0xf0 }, | ||
| 254 | { 0x0f, 0xf8 }, | ||
| 255 | { 0x07, 0xfc }, | ||
| 256 | { 0x03, 0xfe }, | ||
| 257 | { 0x01, 0xff }, | ||
| 258 | }; | ||
| 259 | struct edge_tab edge8_tab_l[8] = { | ||
| 260 | { 0xff, 0x01 }, | ||
| 261 | { 0xfe, 0x03 }, | ||
| 262 | { 0xfc, 0x07 }, | ||
| 263 | { 0xf8, 0x0f }, | ||
| 264 | { 0xf0, 0x1f }, | ||
| 265 | { 0xe0, 0x3f }, | ||
| 266 | { 0xc0, 0x7f }, | ||
| 267 | { 0x80, 0xff }, | ||
| 268 | }; | ||
| 269 | struct edge_tab edge16_tab[4] = { | ||
| 270 | { 0xf, 0x8 }, | ||
| 271 | { 0x7, 0xc }, | ||
| 272 | { 0x3, 0xe }, | ||
| 273 | { 0x1, 0xf }, | ||
| 274 | }; | ||
| 275 | struct edge_tab edge16_tab_l[4] = { | ||
| 276 | { 0xf, 0x1 }, | ||
| 277 | { 0xe, 0x3 }, | ||
| 278 | { 0xc, 0x7 }, | ||
| 279 | { 0x8, 0xf }, | ||
| 280 | }; | ||
| 281 | struct edge_tab edge32_tab[2] = { | ||
| 282 | { 0x3, 0x2 }, | ||
| 283 | { 0x1, 0x3 }, | ||
| 284 | }; | ||
| 285 | struct edge_tab edge32_tab_l[2] = { | ||
| 286 | { 0x3, 0x1 }, | ||
| 287 | { 0x2, 0x3 }, | ||
| 288 | }; | ||
| 289 | |||
| 290 | static void edge(struct pt_regs *regs, unsigned int insn, unsigned int opf) | ||
| 291 | { | ||
| 292 | unsigned long orig_rs1, rs1, orig_rs2, rs2, rd_val; | ||
| 293 | u16 left, right; | ||
| 294 | |||
| 295 | maybe_flush_windows(RS1(insn), RS2(insn), RD(insn), 0); | ||
| 296 | orig_rs1 = rs1 = fetch_reg(RS1(insn), regs); | ||
| 297 | orig_rs2 = rs2 = fetch_reg(RS2(insn), regs); | ||
| 298 | |||
| 299 | if (test_thread_flag(TIF_32BIT)) { | ||
| 300 | rs1 = rs1 & 0xffffffff; | ||
| 301 | rs2 = rs2 & 0xffffffff; | ||
| 302 | } | ||
| 303 | switch (opf) { | ||
| 304 | default: | ||
| 305 | case EDGE8_OPF: | ||
| 306 | case EDGE8N_OPF: | ||
| 307 | left = edge8_tab[rs1 & 0x7].left; | ||
| 308 | right = edge8_tab[rs2 & 0x7].right; | ||
| 309 | break; | ||
| 310 | case EDGE8L_OPF: | ||
| 311 | case EDGE8LN_OPF: | ||
| 312 | left = edge8_tab_l[rs1 & 0x7].left; | ||
| 313 | right = edge8_tab_l[rs2 & 0x7].right; | ||
| 314 | break; | ||
| 315 | |||
| 316 | case EDGE16_OPF: | ||
| 317 | case EDGE16N_OPF: | ||
| 318 | left = edge16_tab[(rs1 >> 1) & 0x3].left; | ||
| 319 | right = edge16_tab[(rs2 >> 1) & 0x3].right; | ||
| 320 | break; | ||
| 321 | |||
| 322 | case EDGE16L_OPF: | ||
| 323 | case EDGE16LN_OPF: | ||
| 324 | left = edge16_tab_l[(rs1 >> 1) & 0x3].left; | ||
| 325 | right = edge16_tab_l[(rs2 >> 1) & 0x3].right; | ||
| 326 | break; | ||
| 327 | |||
| 328 | case EDGE32_OPF: | ||
| 329 | case EDGE32N_OPF: | ||
| 330 | left = edge32_tab[(rs1 >> 2) & 0x1].left; | ||
| 331 | right = edge32_tab[(rs2 >> 2) & 0x1].right; | ||
| 332 | break; | ||
| 333 | |||
| 334 | case EDGE32L_OPF: | ||
| 335 | case EDGE32LN_OPF: | ||
| 336 | left = edge32_tab_l[(rs1 >> 2) & 0x1].left; | ||
| 337 | right = edge32_tab_l[(rs2 >> 2) & 0x1].right; | ||
| 338 | break; | ||
| 339 | }; | ||
| 340 | |||
| 341 | if ((rs1 & ~0x7UL) == (rs2 & ~0x7UL)) | ||
| 342 | rd_val = right & left; | ||
| 343 | else | ||
| 344 | rd_val = left; | ||
| 345 | |||
| 346 | store_reg(regs, rd_val, RD(insn)); | ||
| 347 | |||
| 348 | switch (opf) { | ||
| 349 | case EDGE8_OPF: | ||
| 350 | case EDGE8L_OPF: | ||
| 351 | case EDGE16_OPF: | ||
| 352 | case EDGE16L_OPF: | ||
| 353 | case EDGE32_OPF: | ||
| 354 | case EDGE32L_OPF: { | ||
| 355 | unsigned long ccr, tstate; | ||
| 356 | |||
| 357 | __asm__ __volatile__("subcc %1, %2, %%g0\n\t" | ||
| 358 | "rd %%ccr, %0" | ||
| 359 | : "=r" (ccr) | ||
| 360 | : "r" (orig_rs1), "r" (orig_rs2) | ||
| 361 | : "cc"); | ||
| 362 | tstate = regs->tstate & ~(TSTATE_XCC | TSTATE_ICC); | ||
| 363 | regs->tstate = tstate | (ccr << 32UL); | ||
| 364 | } | ||
| 365 | }; | ||
| 366 | } | ||
| 367 | |||
| 368 | static void array(struct pt_regs *regs, unsigned int insn, unsigned int opf) | ||
| 369 | { | ||
| 370 | unsigned long rs1, rs2, rd_val; | ||
| 371 | unsigned int bits, bits_mask; | ||
| 372 | |||
| 373 | maybe_flush_windows(RS1(insn), RS2(insn), RD(insn), 0); | ||
| 374 | rs1 = fetch_reg(RS1(insn), regs); | ||
| 375 | rs2 = fetch_reg(RS2(insn), regs); | ||
| 376 | |||
| 377 | bits = (rs2 > 5 ? 5 : rs2); | ||
| 378 | bits_mask = (1UL << bits) - 1UL; | ||
| 379 | |||
| 380 | rd_val = ((((rs1 >> 11) & 0x3) << 0) | | ||
| 381 | (((rs1 >> 33) & 0x3) << 2) | | ||
| 382 | (((rs1 >> 55) & 0x1) << 4) | | ||
| 383 | (((rs1 >> 13) & 0xf) << 5) | | ||
| 384 | (((rs1 >> 35) & 0xf) << 9) | | ||
| 385 | (((rs1 >> 56) & 0xf) << 13) | | ||
| 386 | (((rs1 >> 17) & bits_mask) << 17) | | ||
| 387 | (((rs1 >> 39) & bits_mask) << (17 + bits)) | | ||
| 388 | (((rs1 >> 60) & 0xf) << (17 + (2*bits)))); | ||
| 389 | |||
| 390 | switch (opf) { | ||
| 391 | case ARRAY16_OPF: | ||
| 392 | rd_val <<= 1; | ||
| 393 | break; | ||
| 394 | |||
| 395 | case ARRAY32_OPF: | ||
| 396 | rd_val <<= 2; | ||
| 397 | }; | ||
| 398 | |||
| 399 | store_reg(regs, rd_val, RD(insn)); | ||
| 400 | } | ||
| 401 | |||
| 402 | static void bmask(struct pt_regs *regs, unsigned int insn) | ||
| 403 | { | ||
| 404 | unsigned long rs1, rs2, rd_val, gsr; | ||
| 405 | |||
| 406 | maybe_flush_windows(RS1(insn), RS2(insn), RD(insn), 0); | ||
| 407 | rs1 = fetch_reg(RS1(insn), regs); | ||
| 408 | rs2 = fetch_reg(RS2(insn), regs); | ||
| 409 | rd_val = rs1 + rs2; | ||
| 410 | |||
| 411 | store_reg(regs, rd_val, RD(insn)); | ||
| 412 | |||
| 413 | gsr = current_thread_info()->gsr[0] & 0xffffffff; | ||
| 414 | gsr |= rd_val << 32UL; | ||
| 415 | current_thread_info()->gsr[0] = gsr; | ||
| 416 | } | ||
| 417 | |||
| 418 | static void bshuffle(struct pt_regs *regs, unsigned int insn) | ||
| 419 | { | ||
| 420 | struct fpustate *f = FPUSTATE; | ||
| 421 | unsigned long rs1, rs2, rd_val; | ||
| 422 | unsigned long bmask, i; | ||
| 423 | |||
| 424 | bmask = current_thread_info()->gsr[0] >> 32UL; | ||
| 425 | |||
| 426 | rs1 = fpd_regval(f, RS1(insn)); | ||
| 427 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 428 | |||
| 429 | rd_val = 0UL; | ||
| 430 | for (i = 0; i < 8; i++) { | ||
| 431 | unsigned long which = (bmask >> (i * 4)) & 0xf; | ||
| 432 | unsigned long byte; | ||
| 433 | |||
| 434 | if (which < 8) | ||
| 435 | byte = (rs1 >> (which * 8)) & 0xff; | ||
| 436 | else | ||
| 437 | byte = (rs2 >> ((which-8)*8)) & 0xff; | ||
| 438 | rd_val |= (byte << (i * 8)); | ||
| 439 | } | ||
| 440 | |||
| 441 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 442 | } | ||
| 443 | |||
| 444 | static void pdist(struct pt_regs *regs, unsigned int insn) | ||
| 445 | { | ||
| 446 | struct fpustate *f = FPUSTATE; | ||
| 447 | unsigned long rs1, rs2, *rd, rd_val; | ||
| 448 | unsigned long i; | ||
| 449 | |||
| 450 | rs1 = fpd_regval(f, RS1(insn)); | ||
| 451 | rs2 = fpd_regval(f, RS1(insn)); | ||
| 452 | rd = fpd_regaddr(f, RD(insn)); | ||
| 453 | |||
| 454 | rd_val = *rd; | ||
| 455 | |||
| 456 | for (i = 0; i < 8; i++) { | ||
| 457 | s16 s1, s2; | ||
| 458 | |||
| 459 | s1 = (rs1 >> (56 - (i * 8))) & 0xff; | ||
| 460 | s2 = (rs2 >> (56 - (i * 8))) & 0xff; | ||
| 461 | |||
| 462 | /* Absolute value of difference. */ | ||
| 463 | s1 -= s2; | ||
| 464 | if (s1 < 0) | ||
| 465 | s1 = ~s1 + 1; | ||
| 466 | |||
| 467 | rd_val += s1; | ||
| 468 | } | ||
| 469 | |||
| 470 | *rd = rd_val; | ||
| 471 | } | ||
| 472 | |||
| 473 | static void pformat(struct pt_regs *regs, unsigned int insn, unsigned int opf) | ||
| 474 | { | ||
| 475 | struct fpustate *f = FPUSTATE; | ||
| 476 | unsigned long rs1, rs2, gsr, scale, rd_val; | ||
| 477 | |||
| 478 | gsr = current_thread_info()->gsr[0]; | ||
| 479 | scale = (gsr >> 3) & (opf == FPACK16_OPF ? 0xf : 0x1f); | ||
| 480 | switch (opf) { | ||
| 481 | case FPACK16_OPF: { | ||
| 482 | unsigned long byte; | ||
| 483 | |||
| 484 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 485 | rd_val = 0; | ||
| 486 | for (byte = 0; byte < 4; byte++) { | ||
| 487 | unsigned int val; | ||
| 488 | s16 src = (rs2 >> (byte * 16UL)) & 0xffffUL; | ||
| 489 | int scaled = src << scale; | ||
| 490 | int from_fixed = scaled >> 7; | ||
| 491 | |||
| 492 | val = ((from_fixed < 0) ? | ||
| 493 | 0 : | ||
| 494 | (from_fixed > 255) ? | ||
| 495 | 255 : from_fixed); | ||
| 496 | |||
| 497 | rd_val |= (val << (8 * byte)); | ||
| 498 | } | ||
| 499 | *fps_regaddr(f, RD(insn)) = rd_val; | ||
| 500 | break; | ||
| 501 | } | ||
| 502 | |||
| 503 | case FPACK32_OPF: { | ||
| 504 | unsigned long word; | ||
| 505 | |||
| 506 | rs1 = fpd_regval(f, RS1(insn)); | ||
| 507 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 508 | rd_val = (rs1 << 8) & ~(0x000000ff000000ffUL); | ||
| 509 | for (word = 0; word < 2; word++) { | ||
| 510 | unsigned long val; | ||
| 511 | s32 src = (rs2 >> (word * 32UL)); | ||
| 512 | s64 scaled = src << scale; | ||
| 513 | s64 from_fixed = scaled >> 23; | ||
| 514 | |||
| 515 | val = ((from_fixed < 0) ? | ||
| 516 | 0 : | ||
| 517 | (from_fixed > 255) ? | ||
| 518 | 255 : from_fixed); | ||
| 519 | |||
| 520 | rd_val |= (val << (32 * word)); | ||
| 521 | } | ||
| 522 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 523 | break; | ||
| 524 | } | ||
| 525 | |||
| 526 | case FPACKFIX_OPF: { | ||
| 527 | unsigned long word; | ||
| 528 | |||
| 529 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 530 | |||
| 531 | rd_val = 0; | ||
| 532 | for (word = 0; word < 2; word++) { | ||
| 533 | long val; | ||
| 534 | s32 src = (rs2 >> (word * 32UL)); | ||
| 535 | s64 scaled = src << scale; | ||
| 536 | s64 from_fixed = scaled >> 16; | ||
| 537 | |||
| 538 | val = ((from_fixed < -32768) ? | ||
| 539 | -32768 : | ||
| 540 | (from_fixed > 32767) ? | ||
| 541 | 32767 : from_fixed); | ||
| 542 | |||
| 543 | rd_val |= ((val & 0xffff) << (word * 16)); | ||
| 544 | } | ||
| 545 | *fps_regaddr(f, RD(insn)) = rd_val; | ||
| 546 | break; | ||
| 547 | } | ||
| 548 | |||
| 549 | case FEXPAND_OPF: { | ||
| 550 | unsigned long byte; | ||
| 551 | |||
| 552 | rs2 = fps_regval(f, RS2(insn)); | ||
| 553 | |||
| 554 | rd_val = 0; | ||
| 555 | for (byte = 0; byte < 4; byte++) { | ||
| 556 | unsigned long val; | ||
| 557 | u8 src = (rs2 >> (byte * 8)) & 0xff; | ||
| 558 | |||
| 559 | val = src << 4; | ||
| 560 | |||
| 561 | rd_val |= (val << (byte * 16)); | ||
| 562 | } | ||
| 563 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 564 | break; | ||
| 565 | } | ||
| 566 | |||
| 567 | case FPMERGE_OPF: { | ||
| 568 | rs1 = fps_regval(f, RS1(insn)); | ||
| 569 | rs2 = fps_regval(f, RS2(insn)); | ||
| 570 | |||
| 571 | rd_val = (((rs2 & 0x000000ff) << 0) | | ||
| 572 | ((rs1 & 0x000000ff) << 8) | | ||
| 573 | ((rs2 & 0x0000ff00) << 8) | | ||
| 574 | ((rs1 & 0x0000ff00) << 16) | | ||
| 575 | ((rs2 & 0x00ff0000) << 16) | | ||
| 576 | ((rs1 & 0x00ff0000) << 24) | | ||
| 577 | ((rs2 & 0xff000000) << 24) | | ||
| 578 | ((rs1 & 0xff000000) << 32)); | ||
| 579 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 580 | break; | ||
| 581 | } | ||
| 582 | }; | ||
| 583 | } | ||
| 584 | |||
| 585 | static void pmul(struct pt_regs *regs, unsigned int insn, unsigned int opf) | ||
| 586 | { | ||
| 587 | struct fpustate *f = FPUSTATE; | ||
| 588 | unsigned long rs1, rs2, rd_val; | ||
| 589 | |||
| 590 | switch (opf) { | ||
| 591 | case FMUL8x16_OPF: { | ||
| 592 | unsigned long byte; | ||
| 593 | |||
| 594 | rs1 = fps_regval(f, RS1(insn)); | ||
| 595 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 596 | |||
| 597 | rd_val = 0; | ||
| 598 | for (byte = 0; byte < 4; byte++) { | ||
| 599 | u16 src1 = (rs1 >> (byte * 8)) & 0x00ff; | ||
| 600 | s16 src2 = (rs2 >> (byte * 16)) & 0xffff; | ||
| 601 | u32 prod = src1 * src2; | ||
| 602 | u16 scaled = ((prod & 0x00ffff00) >> 8); | ||
| 603 | |||
| 604 | /* Round up. */ | ||
| 605 | if (prod & 0x80) | ||
| 606 | scaled++; | ||
| 607 | rd_val |= ((scaled & 0xffffUL) << (byte * 16UL)); | ||
| 608 | } | ||
| 609 | |||
| 610 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 611 | break; | ||
| 612 | } | ||
| 613 | |||
| 614 | case FMUL8x16AU_OPF: | ||
| 615 | case FMUL8x16AL_OPF: { | ||
| 616 | unsigned long byte; | ||
| 617 | s16 src2; | ||
| 618 | |||
| 619 | rs1 = fps_regval(f, RS1(insn)); | ||
| 620 | rs2 = fps_regval(f, RS2(insn)); | ||
| 621 | |||
| 622 | rd_val = 0; | ||
| 623 | src2 = (rs2 >> (opf == FMUL8x16AU_OPF) ? 16 : 0); | ||
| 624 | for (byte = 0; byte < 4; byte++) { | ||
| 625 | u16 src1 = (rs1 >> (byte * 8)) & 0x00ff; | ||
| 626 | u32 prod = src1 * src2; | ||
| 627 | u16 scaled = ((prod & 0x00ffff00) >> 8); | ||
| 628 | |||
| 629 | /* Round up. */ | ||
| 630 | if (prod & 0x80) | ||
| 631 | scaled++; | ||
| 632 | rd_val |= ((scaled & 0xffffUL) << (byte * 16UL)); | ||
| 633 | } | ||
| 634 | |||
| 635 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 636 | break; | ||
| 637 | } | ||
| 638 | |||
| 639 | case FMUL8SUx16_OPF: | ||
| 640 | case FMUL8ULx16_OPF: { | ||
| 641 | unsigned long byte, ushift; | ||
| 642 | |||
| 643 | rs1 = fpd_regval(f, RS1(insn)); | ||
| 644 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 645 | |||
| 646 | rd_val = 0; | ||
| 647 | ushift = (opf == FMUL8SUx16_OPF) ? 8 : 0; | ||
| 648 | for (byte = 0; byte < 4; byte++) { | ||
| 649 | u16 src1; | ||
| 650 | s16 src2; | ||
| 651 | u32 prod; | ||
| 652 | u16 scaled; | ||
| 653 | |||
| 654 | src1 = ((rs1 >> ((16 * byte) + ushift)) & 0x00ff); | ||
| 655 | src2 = ((rs2 >> (16 * byte)) & 0xffff); | ||
| 656 | prod = src1 * src2; | ||
| 657 | scaled = ((prod & 0x00ffff00) >> 8); | ||
| 658 | |||
| 659 | /* Round up. */ | ||
| 660 | if (prod & 0x80) | ||
| 661 | scaled++; | ||
| 662 | rd_val |= ((scaled & 0xffffUL) << (byte * 16UL)); | ||
| 663 | } | ||
| 664 | |||
| 665 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 666 | break; | ||
| 667 | } | ||
| 668 | |||
| 669 | case FMULD8SUx16_OPF: | ||
| 670 | case FMULD8ULx16_OPF: { | ||
| 671 | unsigned long byte, ushift; | ||
| 672 | |||
| 673 | rs1 = fps_regval(f, RS1(insn)); | ||
| 674 | rs2 = fps_regval(f, RS2(insn)); | ||
| 675 | |||
| 676 | rd_val = 0; | ||
| 677 | ushift = (opf == FMULD8SUx16_OPF) ? 8 : 0; | ||
| 678 | for (byte = 0; byte < 2; byte++) { | ||
| 679 | u16 src1; | ||
| 680 | s16 src2; | ||
| 681 | u32 prod; | ||
| 682 | u16 scaled; | ||
| 683 | |||
| 684 | src1 = ((rs1 >> ((16 * byte) + ushift)) & 0x00ff); | ||
| 685 | src2 = ((rs2 >> (16 * byte)) & 0xffff); | ||
| 686 | prod = src1 * src2; | ||
| 687 | scaled = ((prod & 0x00ffff00) >> 8); | ||
| 688 | |||
| 689 | /* Round up. */ | ||
| 690 | if (prod & 0x80) | ||
| 691 | scaled++; | ||
| 692 | rd_val |= ((scaled & 0xffffUL) << | ||
| 693 | ((byte * 32UL) + 7UL)); | ||
| 694 | } | ||
| 695 | *fpd_regaddr(f, RD(insn)) = rd_val; | ||
| 696 | break; | ||
| 697 | } | ||
| 698 | }; | ||
| 699 | } | ||
| 700 | |||
| 701 | static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf) | ||
| 702 | { | ||
| 703 | struct fpustate *f = FPUSTATE; | ||
| 704 | unsigned long rs1, rs2, rd_val, i; | ||
| 705 | |||
| 706 | rs1 = fpd_regval(f, RS1(insn)); | ||
| 707 | rs2 = fpd_regval(f, RS2(insn)); | ||
| 708 | |||
| 709 | rd_val = 0; | ||
| 710 | |||
| 711 | switch (opf) { | ||
| 712 | case FCMPGT16_OPF: | ||
| 713 | for (i = 0; i < 4; i++) { | ||
| 714 | s16 a = (rs1 >> (i * 16)) & 0xffff; | ||
| 715 | s16 b = (rs2 >> (i * 16)) & 0xffff; | ||
| 716 | |||
| 717 | if (a > b) | ||
| 718 | rd_val |= 1 << i; | ||
| 719 | } | ||
| 720 | break; | ||
| 721 | |||
| 722 | case FCMPGT32_OPF: | ||
| 723 | for (i = 0; i < 2; i++) { | ||
| 724 | s32 a = (rs1 >> (i * 32)) & 0xffff; | ||
| 725 | s32 b = (rs2 >> (i * 32)) & 0xffff; | ||
| 726 | |||
| 727 | if (a > b) | ||
| 728 | rd_val |= 1 << i; | ||
| 729 | } | ||
| 730 | break; | ||
| 731 | |||
| 732 | case FCMPLE16_OPF: | ||
| 733 | for (i = 0; i < 4; i++) { | ||
| 734 | s16 a = (rs1 >> (i * 16)) & 0xffff; | ||
| 735 | s16 b = (rs2 >> (i * 16)) & 0xffff; | ||
| 736 | |||
| 737 | if (a <= b) | ||
| 738 | rd_val |= 1 << i; | ||
| 739 | } | ||
| 740 | break; | ||
| 741 | |||
| 742 | case FCMPLE32_OPF: | ||
| 743 | for (i = 0; i < 2; i++) { | ||
| 744 | s32 a = (rs1 >> (i * 32)) & 0xffff; | ||
| 745 | s32 b = (rs2 >> (i * 32)) & 0xffff; | ||
| 746 | |||
| 747 | if (a <= b) | ||
| 748 | rd_val |= 1 << i; | ||
| 749 | } | ||
| 750 | break; | ||
| 751 | |||
| 752 | case FCMPNE16_OPF: | ||
| 753 | for (i = 0; i < 4; i++) { | ||
| 754 | s16 a = (rs1 >> (i * 16)) & 0xffff; | ||
| 755 | s16 b = (rs2 >> (i * 16)) & 0xffff; | ||
| 756 | |||
| 757 | if (a != b) | ||
| 758 | rd_val |= 1 << i; | ||
| 759 | } | ||
| 760 | break; | ||
| 761 | |||
| 762 | case FCMPNE32_OPF: | ||
| 763 | for (i = 0; i < 2; i++) { | ||
| 764 | s32 a = (rs1 >> (i * 32)) & 0xffff; | ||
| 765 | s32 b = (rs2 >> (i * 32)) & 0xffff; | ||
| 766 | |||
| 767 | if (a != b) | ||
| 768 | rd_val |= 1 << i; | ||
| 769 | } | ||
| 770 | break; | ||
| 771 | |||
| 772 | case FCMPEQ16_OPF: | ||
| 773 | for (i = 0; i < 4; i++) { | ||
| 774 | s16 a = (rs1 >> (i * 16)) & 0xffff; | ||
| 775 | s16 b = (rs2 >> (i * 16)) & 0xffff; | ||
| 776 | |||
| 777 | if (a == b) | ||
| 778 | rd_val |= 1 << i; | ||
| 779 | } | ||
| 780 | break; | ||
| 781 | |||
| 782 | case FCMPEQ32_OPF: | ||
| 783 | for (i = 0; i < 2; i++) { | ||
| 784 | s32 a = (rs1 >> (i * 32)) & 0xffff; | ||
| 785 | s32 b = (rs2 >> (i * 32)) & 0xffff; | ||
| 786 | |||
| 787 | if (a == b) | ||
| 788 | rd_val |= 1 << i; | ||
| 789 | } | ||
| 790 | break; | ||
| 791 | }; | ||
| 792 | |||
| 793 | maybe_flush_windows(0, 0, RD(insn), 0); | ||
| 794 | store_reg(regs, rd_val, RD(insn)); | ||
| 795 | } | ||
| 796 | |||
| 797 | /* Emulate the VIS instructions which are not implemented in | ||
| 798 | * hardware on Niagara. | ||
| 799 | */ | ||
| 800 | int vis_emul(struct pt_regs *regs, unsigned int insn) | ||
| 801 | { | ||
| 802 | unsigned long pc = regs->tpc; | ||
| 803 | unsigned int opf; | ||
| 804 | |||
| 805 | BUG_ON(regs->tstate & TSTATE_PRIV); | ||
| 806 | |||
| 807 | if (test_thread_flag(TIF_32BIT)) | ||
| 808 | pc = (u32)pc; | ||
| 809 | |||
| 810 | if (get_user(insn, (u32 __user *) pc)) | ||
| 811 | return -EFAULT; | ||
| 812 | |||
| 813 | if ((insn & VIS_OPCODE_MASK) != VIS_OPCODE_VAL) | ||
| 814 | return -EINVAL; | ||
| 815 | |||
| 816 | opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT; | ||
| 817 | switch (opf) { | ||
| 818 | default: | ||
| 819 | return -EINVAL; | ||
| 820 | |||
| 821 | /* Pixel Formatting Instructions. */ | ||
| 822 | case FPACK16_OPF: | ||
| 823 | case FPACK32_OPF: | ||
| 824 | case FPACKFIX_OPF: | ||
| 825 | case FEXPAND_OPF: | ||
| 826 | case FPMERGE_OPF: | ||
| 827 | pformat(regs, insn, opf); | ||
| 828 | break; | ||
| 829 | |||
| 830 | /* Partitioned Multiply Instructions */ | ||
| 831 | case FMUL8x16_OPF: | ||
| 832 | case FMUL8x16AU_OPF: | ||
| 833 | case FMUL8x16AL_OPF: | ||
| 834 | case FMUL8SUx16_OPF: | ||
| 835 | case FMUL8ULx16_OPF: | ||
| 836 | case FMULD8SUx16_OPF: | ||
| 837 | case FMULD8ULx16_OPF: | ||
| 838 | pmul(regs, insn, opf); | ||
| 839 | break; | ||
| 840 | |||
| 841 | /* Pixel Compare Instructions */ | ||
| 842 | case FCMPGT16_OPF: | ||
| 843 | case FCMPGT32_OPF: | ||
| 844 | case FCMPLE16_OPF: | ||
| 845 | case FCMPLE32_OPF: | ||
| 846 | case FCMPNE16_OPF: | ||
| 847 | case FCMPNE32_OPF: | ||
| 848 | case FCMPEQ16_OPF: | ||
| 849 | case FCMPEQ32_OPF: | ||
| 850 | pcmp(regs, insn, opf); | ||
| 851 | break; | ||
| 852 | |||
| 853 | /* Edge Handling Instructions */ | ||
| 854 | case EDGE8_OPF: | ||
| 855 | case EDGE8N_OPF: | ||
| 856 | case EDGE8L_OPF: | ||
| 857 | case EDGE8LN_OPF: | ||
| 858 | case EDGE16_OPF: | ||
| 859 | case EDGE16N_OPF: | ||
| 860 | case EDGE16L_OPF: | ||
| 861 | case EDGE16LN_OPF: | ||
| 862 | case EDGE32_OPF: | ||
| 863 | case EDGE32N_OPF: | ||
| 864 | case EDGE32L_OPF: | ||
| 865 | case EDGE32LN_OPF: | ||
| 866 | edge(regs, insn, opf); | ||
| 867 | break; | ||
| 868 | |||
| 869 | /* Pixel Component Distance */ | ||
| 870 | case PDIST_OPF: | ||
| 871 | pdist(regs, insn); | ||
| 872 | break; | ||
| 873 | |||
| 874 | /* Three-Dimensional Array Addressing Instructions */ | ||
| 875 | case ARRAY8_OPF: | ||
| 876 | case ARRAY16_OPF: | ||
| 877 | case ARRAY32_OPF: | ||
| 878 | array(regs, insn, opf); | ||
| 879 | break; | ||
| 880 | |||
| 881 | /* Byte Mask and Shuffle Instructions */ | ||
| 882 | case BMASK_OPF: | ||
| 883 | bmask(regs, insn); | ||
| 884 | break; | ||
| 885 | |||
| 886 | case BSHUFFLE_OPF: | ||
| 887 | bshuffle(regs, insn); | ||
| 888 | break; | ||
| 889 | }; | ||
| 890 | |||
| 891 | regs->tpc = regs->tnpc; | ||
| 892 | regs->tnpc += 4; | ||
| 893 | return 0; | ||
| 894 | } | ||
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S index 467d13a0d5c1..b097379a49a8 100644 --- a/arch/sparc64/kernel/vmlinux.lds.S +++ b/arch/sparc64/kernel/vmlinux.lds.S | |||
| @@ -70,6 +70,22 @@ SECTIONS | |||
| 70 | .con_initcall.init : { *(.con_initcall.init) } | 70 | .con_initcall.init : { *(.con_initcall.init) } |
| 71 | __con_initcall_end = .; | 71 | __con_initcall_end = .; |
| 72 | SECURITY_INIT | 72 | SECURITY_INIT |
| 73 | . = ALIGN(4); | ||
| 74 | __tsb_ldquad_phys_patch = .; | ||
| 75 | .tsb_ldquad_phys_patch : { *(.tsb_ldquad_phys_patch) } | ||
| 76 | __tsb_ldquad_phys_patch_end = .; | ||
| 77 | __tsb_phys_patch = .; | ||
| 78 | .tsb_phys_patch : { *(.tsb_phys_patch) } | ||
| 79 | __tsb_phys_patch_end = .; | ||
| 80 | __cpuid_patch = .; | ||
| 81 | .cpuid_patch : { *(.cpuid_patch) } | ||
| 82 | __cpuid_patch_end = .; | ||
| 83 | __sun4v_1insn_patch = .; | ||
| 84 | .sun4v_1insn_patch : { *(.sun4v_1insn_patch) } | ||
| 85 | __sun4v_1insn_patch_end = .; | ||
| 86 | __sun4v_2insn_patch = .; | ||
| 87 | .sun4v_2insn_patch : { *(.sun4v_2insn_patch) } | ||
| 88 | __sun4v_2insn_patch_end = .; | ||
| 73 | . = ALIGN(8192); | 89 | . = ALIGN(8192); |
| 74 | __initramfs_start = .; | 90 | __initramfs_start = .; |
| 75 | .init.ramfs : { *(.init.ramfs) } | 91 | .init.ramfs : { *(.init.ramfs) } |
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index 39160926267b..c4aa110a10e5 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* $Id: winfixup.S,v 1.30 2002/02/09 19:49:30 davem Exp $ | 1 | /* winfixup.S: Handle cases where user stack pointer is found to be bogus. |
| 2 | * | 2 | * |
| 3 | * winfixup.S: Handle cases where user stack pointer is found to be bogus. | 3 | * Copyright (C) 1997, 2006 David S. Miller (davem@davemloft.net) |
| 4 | * | ||
| 5 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | ||
| 6 | */ | 4 | */ |
| 7 | 5 | ||
| 8 | #include <asm/asi.h> | 6 | #include <asm/asi.h> |
| @@ -15,374 +13,144 @@ | |||
| 15 | 13 | ||
| 16 | .text | 14 | .text |
| 17 | 15 | ||
| 18 | set_pcontext: | 16 | /* It used to be the case that these register window fault |
| 19 | sethi %hi(sparc64_kern_pri_context), %l1 | 17 | * handlers could run via the save and restore instructions |
| 20 | ldx [%l1 + %lo(sparc64_kern_pri_context)], %l1 | 18 | * done by the trap entry and exit code. They now do the |
| 21 | mov PRIMARY_CONTEXT, %g1 | 19 | * window spill/fill by hand, so that case no longer can occur. |
| 22 | stxa %l1, [%g1] ASI_DMMU | 20 | */ |
| 23 | flush %g6 | ||
| 24 | retl | ||
| 25 | nop | ||
| 26 | 21 | ||
| 27 | .align 32 | 22 | .align 32 |
| 28 | |||
| 29 | /* Here are the rules, pay attention. | ||
| 30 | * | ||
| 31 | * The kernel is disallowed from touching user space while | ||
| 32 | * the trap level is greater than zero, except for from within | ||
| 33 | * the window spill/fill handlers. This must be followed | ||
| 34 | * so that we can easily detect the case where we tried to | ||
| 35 | * spill/fill with a bogus (or unmapped) user stack pointer. | ||
| 36 | * | ||
| 37 | * These are layed out in a special way for cache reasons, | ||
| 38 | * don't touch... | ||
| 39 | */ | ||
| 40 | .globl fill_fixup, spill_fixup | ||
| 41 | fill_fixup: | 23 | fill_fixup: |
| 42 | rdpr %tstate, %g1 | 24 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
| 43 | andcc %g1, TSTATE_PRIV, %g0 | 25 | rdpr %tstate, %g1 |
| 44 | or %g4, FAULT_CODE_WINFIXUP, %g4 | 26 | and %g1, TSTATE_CWP, %g1 |
| 45 | be,pt %xcc, window_scheisse_from_user_common | 27 | or %g4, FAULT_CODE_WINFIXUP, %g4 |
| 46 | and %g1, TSTATE_CWP, %g1 | 28 | stb %g4, [%g6 + TI_FAULT_CODE] |
| 47 | 29 | stx %g5, [%g6 + TI_FAULT_ADDR] | |
| 48 | /* This is the extremely complex case, but it does happen from | 30 | wrpr %g1, %cwp |
| 49 | * time to time if things are just right. Essentially the restore | 31 | ba,pt %xcc, etrap |
| 50 | * done in rtrap right before going back to user mode, with tl=1 | 32 | rd %pc, %g7 |
| 51 | * and that levels trap stack registers all setup, took a fill trap, | 33 | call do_sparc64_fault |
| 52 | * the user stack was not mapped in the tlb, and tlb miss occurred, | 34 | add %sp, PTREGS_OFF, %o0 |
| 53 | * the pte found was not valid, and a simple ref bit watch update | 35 | ba,pt %xcc, rtrap_clr_l6 |
| 54 | * could not satisfy the miss, so we got here. | ||
| 55 | * | ||
| 56 | * We must carefully unwind the state so we get back to tl=0, preserve | ||
| 57 | * all the register values we were going to give to the user. Luckily | ||
| 58 | * most things are where they need to be, we also have the address | ||
| 59 | * which triggered the fault handy as well. | ||
| 60 | * | ||
| 61 | * Also note that we must preserve %l5 and %l6. If the user was | ||
| 62 | * returning from a system call, we must make it look this way | ||
| 63 | * after we process the fill fault on the users stack. | ||
| 64 | * | ||
| 65 | * First, get into the window where the original restore was executed. | ||
| 66 | */ | ||
| 67 | |||
| 68 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
| 69 | wrpr %g1, %cwp ! Get into the right window. | ||
| 70 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
| 71 | |||
| 72 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
| 73 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
| 74 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
| 75 | call set_pcontext ! Change contexts... | ||
| 76 | nop | 36 | nop |
| 77 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
| 78 | mov %g6, %o7 ! Get current. | ||
| 79 | |||
| 80 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
| 81 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
| 82 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
| 83 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
| 84 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
| 85 | mov %o7, %g6 | ||
| 86 | ldx [%g6 + TI_TASK], %g4 | ||
| 87 | #ifdef CONFIG_SMP | ||
| 88 | mov TSB_REG, %g1 | ||
| 89 | ldxa [%g1] ASI_IMMU, %g5 | ||
| 90 | #endif | ||
| 91 | 37 | ||
| 92 | /* This is the same as below, except we handle this a bit special | 38 | /* Be very careful about usage of the trap globals here. |
| 93 | * since we must preserve %l5 and %l6, see comment above. | 39 | * You cannot touch %g5 as that has the fault information. |
| 94 | */ | ||
| 95 | call do_sparc64_fault | ||
| 96 | add %sp, PTREGS_OFF, %o0 | ||
| 97 | ba,pt %xcc, rtrap | ||
| 98 | nop ! yes, nop is correct | ||
| 99 | |||
| 100 | /* Be very careful about usage of the alternate globals here. | ||
| 101 | * You cannot touch %g4/%g5 as that has the fault information | ||
| 102 | * should this be from usermode. Also be careful for the case | ||
| 103 | * where we get here from the save instruction in etrap.S when | ||
| 104 | * coming from either user or kernel (does not matter which, it | ||
| 105 | * is the same problem in both cases). Essentially this means | ||
| 106 | * do not touch %g7 or %g2 so we handle the two cases fine. | ||
| 107 | */ | 40 | */ |
| 108 | spill_fixup: | 41 | spill_fixup: |
| 109 | ldx [%g6 + TI_FLAGS], %g1 | 42 | spill_fixup_mna: |
| 110 | andcc %g1, _TIF_32BIT, %g0 | 43 | spill_fixup_dax: |
| 111 | ldub [%g6 + TI_WSAVED], %g1 | 44 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
| 112 | 45 | ldx [%g6 + TI_FLAGS], %g1 | |
| 113 | sll %g1, 3, %g3 | 46 | andcc %g1, _TIF_32BIT, %g0 |
| 114 | add %g6, %g3, %g3 | 47 | ldub [%g6 + TI_WSAVED], %g1 |
| 115 | stx %sp, [%g3 + TI_RWIN_SPTRS] | 48 | sll %g1, 3, %g3 |
| 116 | sll %g1, 7, %g3 | 49 | add %g6, %g3, %g3 |
| 117 | bne,pt %xcc, 1f | 50 | stx %sp, [%g3 + TI_RWIN_SPTRS] |
| 118 | add %g6, %g3, %g3 | 51 | sll %g1, 7, %g3 |
| 119 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | 52 | bne,pt %xcc, 1f |
| 120 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | 53 | add %g6, %g3, %g3 |
| 121 | 54 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | |
| 122 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | 55 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] |
| 123 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | 56 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] |
| 124 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | 57 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] |
| 125 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | 58 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] |
| 126 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | 59 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] |
| 127 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | 60 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] |
| 128 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | 61 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] |
| 129 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | 62 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] |
| 130 | 63 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | |
| 131 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | 64 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] |
| 132 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | 65 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] |
| 133 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | 66 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] |
| 134 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | 67 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] |
| 135 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | 68 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] |
| 136 | b,pt %xcc, 2f | 69 | ba,pt %xcc, 2f |
| 137 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | 70 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] |
| 138 | 1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] | 71 | 1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] |
| 139 | 72 | stw %l1, [%g3 + TI_REG_WINDOW + 0x04] | |
| 140 | stw %l1, [%g3 + TI_REG_WINDOW + 0x04] | 73 | stw %l2, [%g3 + TI_REG_WINDOW + 0x08] |
| 141 | stw %l2, [%g3 + TI_REG_WINDOW + 0x08] | 74 | stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] |
| 142 | stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] | 75 | stw %l4, [%g3 + TI_REG_WINDOW + 0x10] |
| 143 | stw %l4, [%g3 + TI_REG_WINDOW + 0x10] | 76 | stw %l5, [%g3 + TI_REG_WINDOW + 0x14] |
| 144 | stw %l5, [%g3 + TI_REG_WINDOW + 0x14] | 77 | stw %l6, [%g3 + TI_REG_WINDOW + 0x18] |
| 145 | stw %l6, [%g3 + TI_REG_WINDOW + 0x18] | 78 | stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] |
| 146 | stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] | 79 | stw %i0, [%g3 + TI_REG_WINDOW + 0x20] |
| 147 | stw %i0, [%g3 + TI_REG_WINDOW + 0x20] | 80 | stw %i1, [%g3 + TI_REG_WINDOW + 0x24] |
| 148 | 81 | stw %i2, [%g3 + TI_REG_WINDOW + 0x28] | |
| 149 | stw %i1, [%g3 + TI_REG_WINDOW + 0x24] | 82 | stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] |
| 150 | stw %i2, [%g3 + TI_REG_WINDOW + 0x28] | 83 | stw %i4, [%g3 + TI_REG_WINDOW + 0x30] |
| 151 | stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] | 84 | stw %i5, [%g3 + TI_REG_WINDOW + 0x34] |
| 152 | stw %i4, [%g3 + TI_REG_WINDOW + 0x30] | 85 | stw %i6, [%g3 + TI_REG_WINDOW + 0x38] |
| 153 | stw %i5, [%g3 + TI_REG_WINDOW + 0x34] | 86 | stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] |
| 154 | stw %i6, [%g3 + TI_REG_WINDOW + 0x38] | 87 | 2: add %g1, 1, %g1 |
| 155 | stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] | 88 | stb %g1, [%g6 + TI_WSAVED] |
| 156 | 2: add %g1, 1, %g1 | 89 | rdpr %tstate, %g1 |
| 157 | 90 | andcc %g1, TSTATE_PRIV, %g0 | |
| 158 | stb %g1, [%g6 + TI_WSAVED] | ||
| 159 | rdpr %tstate, %g1 | ||
| 160 | andcc %g1, TSTATE_PRIV, %g0 | ||
| 161 | saved | 91 | saved |
| 162 | and %g1, TSTATE_CWP, %g1 | 92 | be,pn %xcc, 1f |
| 163 | be,pn %xcc, window_scheisse_from_user_common | 93 | and %g1, TSTATE_CWP, %g1 |
| 164 | mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 | ||
| 165 | retry | 94 | retry |
| 95 | 1: mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 | ||
| 96 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
| 97 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
| 98 | wrpr %g1, %cwp | ||
| 99 | ba,pt %xcc, etrap | ||
| 100 | rd %pc, %g7 | ||
| 101 | call do_sparc64_fault | ||
| 102 | add %sp, PTREGS_OFF, %o0 | ||
| 103 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 166 | 104 | ||
| 167 | window_scheisse_from_user_common: | ||
| 168 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
| 169 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
| 170 | wrpr %g1, %cwp | ||
| 171 | ba,pt %xcc, etrap | ||
| 172 | rd %pc, %g7 | ||
| 173 | call do_sparc64_fault | ||
| 174 | add %sp, PTREGS_OFF, %o0 | ||
| 175 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 176 | |||
| 177 | .globl winfix_mna, fill_fixup_mna, spill_fixup_mna | ||
| 178 | winfix_mna: | 105 | winfix_mna: |
| 179 | andn %g3, 0x7f, %g3 | 106 | andn %g3, 0x7f, %g3 |
| 180 | add %g3, 0x78, %g3 | 107 | add %g3, 0x78, %g3 |
| 181 | wrpr %g3, %tnpc | 108 | wrpr %g3, %tnpc |
| 182 | done | 109 | done |
| 183 | fill_fixup_mna: | ||
| 184 | rdpr %tstate, %g1 | ||
| 185 | andcc %g1, TSTATE_PRIV, %g0 | ||
| 186 | be,pt %xcc, window_mna_from_user_common | ||
| 187 | and %g1, TSTATE_CWP, %g1 | ||
| 188 | 110 | ||
| 189 | /* Please, see fill_fixup commentary about why we must preserve | 111 | fill_fixup_mna: |
| 190 | * %l5 and %l6 to preserve absolute correct semantics. | 112 | rdpr %tstate, %g1 |
| 191 | */ | 113 | and %g1, TSTATE_CWP, %g1 |
| 192 | rdpr %wstate, %g2 ! Grab user mode wstate. | 114 | wrpr %g1, %cwp |
| 193 | wrpr %g1, %cwp ! Get into the right window. | 115 | ba,pt %xcc, etrap |
| 194 | sll %g2, 3, %g2 ! NORMAL-->OTHER | 116 | rd %pc, %g7 |
| 195 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | 117 | sethi %hi(tlb_type), %g1 |
| 196 | 118 | lduw [%g1 + %lo(tlb_type)], %g1 | |
| 197 | wrpr %g2, 0x0, %wstate ! This must be consistent. | 119 | cmp %g1, 3 |
| 198 | wrpr %g0, 0x0, %otherwin ! We know this. | 120 | bne,pt %icc, 1f |
| 199 | call set_pcontext ! Change contexts... | 121 | add %sp, PTREGS_OFF, %o0 |
| 122 | mov %l4, %o2 | ||
| 123 | call sun4v_do_mna | ||
| 124 | mov %l5, %o1 | ||
| 125 | ba,a,pt %xcc, rtrap_clr_l6 | ||
| 126 | 1: mov %l4, %o1 | ||
| 127 | mov %l5, %o2 | ||
| 128 | call mem_address_unaligned | ||
| 200 | nop | 129 | nop |
| 201 | rdpr %pstate, %l1 ! Prepare to change globals. | 130 | ba,a,pt %xcc, rtrap_clr_l6 |
| 202 | mov %g4, %o2 ! Setup args for | ||
| 203 | mov %g5, %o1 ! final call to mem_address_unaligned. | ||
| 204 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
| 205 | 131 | ||
| 206 | mov %g6, %o7 ! Stash away current. | ||
| 207 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
| 208 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
| 209 | mov %o7, %g6 ! Get current back. | ||
| 210 | ldx [%g6 + TI_TASK], %g4 ! Finish it. | ||
| 211 | #ifdef CONFIG_SMP | ||
| 212 | mov TSB_REG, %g1 | ||
| 213 | ldxa [%g1] ASI_IMMU, %g5 | ||
| 214 | #endif | ||
| 215 | call mem_address_unaligned | ||
| 216 | add %sp, PTREGS_OFF, %o0 | ||
| 217 | |||
| 218 | b,pt %xcc, rtrap | ||
| 219 | nop ! yes, the nop is correct | ||
| 220 | spill_fixup_mna: | ||
| 221 | ldx [%g6 + TI_FLAGS], %g1 | ||
| 222 | andcc %g1, _TIF_32BIT, %g0 | ||
| 223 | ldub [%g6 + TI_WSAVED], %g1 | ||
| 224 | sll %g1, 3, %g3 | ||
| 225 | add %g6, %g3, %g3 | ||
| 226 | stx %sp, [%g3 + TI_RWIN_SPTRS] | ||
| 227 | |||
| 228 | sll %g1, 7, %g3 | ||
| 229 | bne,pt %xcc, 1f | ||
| 230 | add %g6, %g3, %g3 | ||
| 231 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
| 232 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
| 233 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
| 234 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
| 235 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
| 236 | |||
| 237 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
| 238 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
| 239 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
| 240 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
| 241 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
| 242 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
| 243 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
| 244 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
| 245 | |||
| 246 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
| 247 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
| 248 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
| 249 | b,pt %xcc, 2f | ||
| 250 | add %g1, 1, %g1 | ||
| 251 | 1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
| 252 | std %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
| 253 | std %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
| 254 | |||
| 255 | std %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
| 256 | std %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
| 257 | std %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
| 258 | std %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
| 259 | std %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
| 260 | add %g1, 1, %g1 | ||
| 261 | 2: stb %g1, [%g6 + TI_WSAVED] | ||
| 262 | rdpr %tstate, %g1 | ||
| 263 | |||
| 264 | andcc %g1, TSTATE_PRIV, %g0 | ||
| 265 | saved | ||
| 266 | be,pn %xcc, window_mna_from_user_common | ||
| 267 | and %g1, TSTATE_CWP, %g1 | ||
| 268 | retry | ||
| 269 | window_mna_from_user_common: | ||
| 270 | wrpr %g1, %cwp | ||
| 271 | sethi %hi(109f), %g7 | ||
| 272 | ba,pt %xcc, etrap | ||
| 273 | 109: or %g7, %lo(109b), %g7 | ||
| 274 | mov %l4, %o2 | ||
| 275 | mov %l5, %o1 | ||
| 276 | call mem_address_unaligned | ||
| 277 | add %sp, PTREGS_OFF, %o0 | ||
| 278 | ba,pt %xcc, rtrap | ||
| 279 | clr %l6 | ||
| 280 | |||
| 281 | /* These are only needed for 64-bit mode processes which | ||
| 282 | * put their stack pointer into the VPTE area and there | ||
| 283 | * happens to be a VPTE tlb entry mapped there during | ||
| 284 | * a spill/fill trap to that stack frame. | ||
| 285 | */ | ||
| 286 | .globl winfix_dax, fill_fixup_dax, spill_fixup_dax | ||
| 287 | winfix_dax: | 132 | winfix_dax: |
| 288 | andn %g3, 0x7f, %g3 | 133 | andn %g3, 0x7f, %g3 |
| 289 | add %g3, 0x74, %g3 | 134 | add %g3, 0x74, %g3 |
| 290 | wrpr %g3, %tnpc | 135 | wrpr %g3, %tnpc |
| 291 | done | 136 | done |
| 292 | fill_fixup_dax: | ||
| 293 | rdpr %tstate, %g1 | ||
| 294 | andcc %g1, TSTATE_PRIV, %g0 | ||
| 295 | be,pt %xcc, window_dax_from_user_common | ||
| 296 | and %g1, TSTATE_CWP, %g1 | ||
| 297 | |||
| 298 | /* Please, see fill_fixup commentary about why we must preserve | ||
| 299 | * %l5 and %l6 to preserve absolute correct semantics. | ||
| 300 | */ | ||
| 301 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
| 302 | wrpr %g1, %cwp ! Get into the right window. | ||
| 303 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
| 304 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
| 305 | 137 | ||
| 306 | wrpr %g2, 0x0, %wstate ! This must be consistent. | 138 | fill_fixup_dax: |
| 307 | wrpr %g0, 0x0, %otherwin ! We know this. | 139 | rdpr %tstate, %g1 |
| 308 | call set_pcontext ! Change contexts... | 140 | and %g1, TSTATE_CWP, %g1 |
| 141 | wrpr %g1, %cwp | ||
| 142 | ba,pt %xcc, etrap | ||
| 143 | rd %pc, %g7 | ||
| 144 | sethi %hi(tlb_type), %g1 | ||
| 145 | mov %l4, %o1 | ||
| 146 | lduw [%g1 + %lo(tlb_type)], %g1 | ||
| 147 | mov %l5, %o2 | ||
| 148 | cmp %g1, 3 | ||
| 149 | bne,pt %icc, 1f | ||
| 150 | add %sp, PTREGS_OFF, %o0 | ||
| 151 | call sun4v_data_access_exception | ||
| 309 | nop | 152 | nop |
| 310 | rdpr %pstate, %l1 ! Prepare to change globals. | 153 | ba,a,pt %xcc, rtrap_clr_l6 |
| 311 | mov %g4, %o1 ! Setup args for | 154 | 1: call spitfire_data_access_exception |
| 312 | mov %g5, %o2 ! final call to spitfire_data_access_exception. | 155 | nop |
| 313 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | 156 | ba,a,pt %xcc, rtrap_clr_l6 |
| 314 | |||
| 315 | mov %g6, %o7 ! Stash away current. | ||
| 316 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
| 317 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
| 318 | mov %o7, %g6 ! Get current back. | ||
| 319 | ldx [%g6 + TI_TASK], %g4 ! Finish it. | ||
| 320 | #ifdef CONFIG_SMP | ||
| 321 | mov TSB_REG, %g1 | ||
| 322 | ldxa [%g1] ASI_IMMU, %g5 | ||
| 323 | #endif | ||
| 324 | call spitfire_data_access_exception | ||
| 325 | add %sp, PTREGS_OFF, %o0 | ||
| 326 | |||
| 327 | b,pt %xcc, rtrap | ||
| 328 | nop ! yes, the nop is correct | ||
| 329 | spill_fixup_dax: | ||
| 330 | ldx [%g6 + TI_FLAGS], %g1 | ||
| 331 | andcc %g1, _TIF_32BIT, %g0 | ||
| 332 | ldub [%g6 + TI_WSAVED], %g1 | ||
| 333 | sll %g1, 3, %g3 | ||
| 334 | add %g6, %g3, %g3 | ||
| 335 | stx %sp, [%g3 + TI_RWIN_SPTRS] | ||
| 336 | |||
| 337 | sll %g1, 7, %g3 | ||
| 338 | bne,pt %xcc, 1f | ||
| 339 | add %g6, %g3, %g3 | ||
| 340 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
| 341 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
| 342 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
| 343 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
| 344 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
| 345 | |||
| 346 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
| 347 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
| 348 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
| 349 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
| 350 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
| 351 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
| 352 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
| 353 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
| 354 | |||
| 355 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
| 356 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
| 357 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
| 358 | b,pt %xcc, 2f | ||
| 359 | add %g1, 1, %g1 | ||
| 360 | 1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
| 361 | std %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
| 362 | std %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
| 363 | |||
| 364 | std %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
| 365 | std %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
| 366 | std %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
| 367 | std %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
| 368 | std %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
| 369 | add %g1, 1, %g1 | ||
| 370 | 2: stb %g1, [%g6 + TI_WSAVED] | ||
| 371 | rdpr %tstate, %g1 | ||
| 372 | |||
| 373 | andcc %g1, TSTATE_PRIV, %g0 | ||
| 374 | saved | ||
| 375 | be,pn %xcc, window_dax_from_user_common | ||
| 376 | and %g1, TSTATE_CWP, %g1 | ||
| 377 | retry | ||
| 378 | window_dax_from_user_common: | ||
| 379 | wrpr %g1, %cwp | ||
| 380 | sethi %hi(109f), %g7 | ||
| 381 | ba,pt %xcc, etrap | ||
| 382 | 109: or %g7, %lo(109b), %g7 | ||
| 383 | mov %l4, %o1 | ||
| 384 | mov %l5, %o2 | ||
| 385 | call spitfire_data_access_exception | ||
| 386 | add %sp, PTREGS_OFF, %o0 | ||
| 387 | ba,pt %xcc, rtrap | ||
| 388 | clr %l6 | ||
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index c295806500f7..8812ded19f01 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile | |||
| @@ -11,6 +11,8 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \ | |||
| 11 | VISsave.o atomic.o bitops.o \ | 11 | VISsave.o atomic.o bitops.o \ |
| 12 | U1memcpy.o U1copy_from_user.o U1copy_to_user.o \ | 12 | U1memcpy.o U1copy_from_user.o U1copy_to_user.o \ |
| 13 | U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ | 13 | U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ |
| 14 | NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \ | ||
| 15 | NGpage.o NGbzero.o \ | ||
| 14 | copy_in_user.o user_fixup.o memmove.o \ | 16 | copy_in_user.o user_fixup.o memmove.o \ |
| 15 | mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o | 17 | mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o |
| 16 | 18 | ||
diff --git a/arch/sparc64/lib/NGbzero.S b/arch/sparc64/lib/NGbzero.S new file mode 100644 index 000000000000..e86baece5cc8 --- /dev/null +++ b/arch/sparc64/lib/NGbzero.S | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | /* NGbzero.S: Niagara optimized memset/clear_user. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | #include <asm/asi.h> | ||
| 6 | |||
| 7 | #define EX_ST(x,y) \ | ||
| 8 | 98: x,y; \ | ||
| 9 | .section .fixup; \ | ||
| 10 | .align 4; \ | ||
| 11 | 99: retl; \ | ||
| 12 | mov %o1, %o0; \ | ||
| 13 | .section __ex_table; \ | ||
| 14 | .align 4; \ | ||
| 15 | .word 98b, 99b; \ | ||
| 16 | .text; \ | ||
| 17 | .align 4; | ||
| 18 | |||
| 19 | .text | ||
| 20 | |||
| 21 | .globl NGmemset | ||
| 22 | .type NGmemset, #function | ||
| 23 | NGmemset: /* %o0=buf, %o1=pat, %o2=len */ | ||
| 24 | and %o1, 0xff, %o3 | ||
| 25 | mov %o2, %o1 | ||
| 26 | sllx %o3, 8, %g1 | ||
| 27 | or %g1, %o3, %o2 | ||
| 28 | sllx %o2, 16, %g1 | ||
| 29 | or %g1, %o2, %o2 | ||
| 30 | sllx %o2, 32, %g1 | ||
| 31 | ba,pt %xcc, 1f | ||
| 32 | or %g1, %o2, %o2 | ||
| 33 | |||
| 34 | .globl NGbzero | ||
| 35 | .type NGbzero, #function | ||
| 36 | NGbzero: | ||
| 37 | clr %o2 | ||
| 38 | 1: brz,pn %o1, NGbzero_return | ||
| 39 | mov %o0, %o3 | ||
| 40 | |||
| 41 | /* %o5: saved %asi, restored at NGbzero_done | ||
| 42 | * %g7: store-init %asi to use | ||
| 43 | * %o4: non-store-init %asi to use | ||
| 44 | */ | ||
| 45 | rd %asi, %o5 | ||
| 46 | mov ASI_BLK_INIT_QUAD_LDD_P, %g7 | ||
| 47 | mov ASI_P, %o4 | ||
| 48 | wr %o4, 0x0, %asi | ||
| 49 | |||
| 50 | NGbzero_from_clear_user: | ||
| 51 | cmp %o1, 15 | ||
| 52 | bl,pn %icc, NGbzero_tiny | ||
| 53 | andcc %o0, 0x7, %g1 | ||
| 54 | be,pt %xcc, 2f | ||
| 55 | mov 8, %g2 | ||
| 56 | sub %g2, %g1, %g1 | ||
| 57 | sub %o1, %g1, %o1 | ||
| 58 | 1: EX_ST(stba %o2, [%o0 + 0x00] %asi) | ||
| 59 | subcc %g1, 1, %g1 | ||
| 60 | bne,pt %xcc, 1b | ||
| 61 | add %o0, 1, %o0 | ||
| 62 | 2: cmp %o1, 128 | ||
| 63 | bl,pn %icc, NGbzero_medium | ||
| 64 | andcc %o0, (64 - 1), %g1 | ||
| 65 | be,pt %xcc, NGbzero_pre_loop | ||
| 66 | mov 64, %g2 | ||
| 67 | sub %g2, %g1, %g1 | ||
| 68 | sub %o1, %g1, %o1 | ||
| 69 | 1: EX_ST(stxa %o2, [%o0 + 0x00] %asi) | ||
| 70 | subcc %g1, 8, %g1 | ||
| 71 | bne,pt %xcc, 1b | ||
| 72 | add %o0, 8, %o0 | ||
| 73 | |||
| 74 | NGbzero_pre_loop: | ||
| 75 | wr %g7, 0x0, %asi | ||
| 76 | andn %o1, (64 - 1), %g1 | ||
| 77 | sub %o1, %g1, %o1 | ||
| 78 | NGbzero_loop: | ||
| 79 | EX_ST(stxa %o2, [%o0 + 0x00] %asi) | ||
| 80 | EX_ST(stxa %o2, [%o0 + 0x08] %asi) | ||
| 81 | EX_ST(stxa %o2, [%o0 + 0x10] %asi) | ||
| 82 | EX_ST(stxa %o2, [%o0 + 0x18] %asi) | ||
| 83 | EX_ST(stxa %o2, [%o0 + 0x20] %asi) | ||
| 84 | EX_ST(stxa %o2, [%o0 + 0x28] %asi) | ||
| 85 | EX_ST(stxa %o2, [%o0 + 0x30] %asi) | ||
| 86 | EX_ST(stxa %o2, [%o0 + 0x38] %asi) | ||
| 87 | subcc %g1, 64, %g1 | ||
| 88 | bne,pt %xcc, NGbzero_loop | ||
| 89 | add %o0, 64, %o0 | ||
| 90 | |||
| 91 | wr %o4, 0x0, %asi | ||
| 92 | brz,pn %o1, NGbzero_done | ||
| 93 | NGbzero_medium: | ||
| 94 | andncc %o1, 0x7, %g1 | ||
| 95 | be,pn %xcc, 2f | ||
| 96 | sub %o1, %g1, %o1 | ||
| 97 | 1: EX_ST(stxa %o2, [%o0 + 0x00] %asi) | ||
| 98 | subcc %g1, 8, %g1 | ||
| 99 | bne,pt %xcc, 1b | ||
| 100 | add %o0, 8, %o0 | ||
| 101 | 2: brz,pt %o1, NGbzero_done | ||
| 102 | nop | ||
| 103 | |||
| 104 | NGbzero_tiny: | ||
| 105 | 1: EX_ST(stba %o2, [%o0 + 0x00] %asi) | ||
| 106 | subcc %o1, 1, %o1 | ||
| 107 | bne,pt %icc, 1b | ||
| 108 | add %o0, 1, %o0 | ||
| 109 | |||
| 110 | /* fallthrough */ | ||
| 111 | |||
| 112 | NGbzero_done: | ||
| 113 | wr %o5, 0x0, %asi | ||
| 114 | |||
| 115 | NGbzero_return: | ||
| 116 | retl | ||
| 117 | mov %o3, %o0 | ||
| 118 | .size NGbzero, .-NGbzero | ||
| 119 | .size NGmemset, .-NGmemset | ||
| 120 | |||
| 121 | .globl NGclear_user | ||
| 122 | .type NGclear_user, #function | ||
| 123 | NGclear_user: /* %o0=buf, %o1=len */ | ||
| 124 | rd %asi, %o5 | ||
| 125 | brz,pn %o1, NGbzero_done | ||
| 126 | clr %o3 | ||
| 127 | cmp %o5, ASI_AIUS | ||
| 128 | bne,pn %icc, NGbzero | ||
| 129 | clr %o2 | ||
| 130 | mov ASI_BLK_INIT_QUAD_LDD_AIUS, %g7 | ||
| 131 | ba,pt %xcc, NGbzero_from_clear_user | ||
| 132 | mov ASI_AIUS, %o4 | ||
| 133 | .size NGclear_user, .-NGclear_user | ||
| 134 | |||
| 135 | #define BRANCH_ALWAYS 0x10680000 | ||
| 136 | #define NOP 0x01000000 | ||
| 137 | #define NG_DO_PATCH(OLD, NEW) \ | ||
| 138 | sethi %hi(NEW), %g1; \ | ||
| 139 | or %g1, %lo(NEW), %g1; \ | ||
| 140 | sethi %hi(OLD), %g2; \ | ||
| 141 | or %g2, %lo(OLD), %g2; \ | ||
| 142 | sub %g1, %g2, %g1; \ | ||
| 143 | sethi %hi(BRANCH_ALWAYS), %g3; \ | ||
| 144 | sll %g1, 11, %g1; \ | ||
| 145 | srl %g1, 11 + 2, %g1; \ | ||
| 146 | or %g3, %lo(BRANCH_ALWAYS), %g3; \ | ||
| 147 | or %g3, %g1, %g3; \ | ||
| 148 | stw %g3, [%g2]; \ | ||
| 149 | sethi %hi(NOP), %g3; \ | ||
| 150 | or %g3, %lo(NOP), %g3; \ | ||
| 151 | stw %g3, [%g2 + 0x4]; \ | ||
| 152 | flush %g2; | ||
| 153 | |||
| 154 | .globl niagara_patch_bzero | ||
| 155 | .type niagara_patch_bzero,#function | ||
| 156 | niagara_patch_bzero: | ||
| 157 | NG_DO_PATCH(memset, NGmemset) | ||
| 158 | NG_DO_PATCH(__bzero, NGbzero) | ||
| 159 | NG_DO_PATCH(__clear_user, NGclear_user) | ||
| 160 | NG_DO_PATCH(tsb_init, NGtsb_init) | ||
| 161 | retl | ||
| 162 | nop | ||
| 163 | .size niagara_patch_bzero,.-niagara_patch_bzero | ||
diff --git a/arch/sparc64/lib/NGcopy_from_user.S b/arch/sparc64/lib/NGcopy_from_user.S new file mode 100644 index 000000000000..2d93456f76dd --- /dev/null +++ b/arch/sparc64/lib/NGcopy_from_user.S | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* NGcopy_from_user.S: Niagara optimized copy from userspace. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #define EX_LD(x) \ | ||
| 7 | 98: x; \ | ||
| 8 | .section .fixup; \ | ||
| 9 | .align 4; \ | ||
| 10 | 99: wr %g0, ASI_AIUS, %asi;\ | ||
| 11 | retl; \ | ||
| 12 | mov 1, %o0; \ | ||
| 13 | .section __ex_table,"a";\ | ||
| 14 | .align 4; \ | ||
| 15 | .word 98b, 99b; \ | ||
| 16 | .text; \ | ||
| 17 | .align 4; | ||
| 18 | |||
| 19 | #ifndef ASI_AIUS | ||
| 20 | #define ASI_AIUS 0x11 | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #define FUNC_NAME NGcopy_from_user | ||
| 24 | #define LOAD(type,addr,dest) type##a [addr] ASI_AIUS, dest | ||
| 25 | #define LOAD_TWIN(addr_reg,dest0,dest1) \ | ||
| 26 | ldda [addr_reg] ASI_BLK_INIT_QUAD_LDD_AIUS, dest0 | ||
| 27 | #define EX_RETVAL(x) 0 | ||
| 28 | |||
| 29 | #ifdef __KERNEL__ | ||
| 30 | #define PREAMBLE \ | ||
| 31 | rd %asi, %g1; \ | ||
| 32 | cmp %g1, ASI_AIUS; \ | ||
| 33 | bne,pn %icc, memcpy_user_stub; \ | ||
| 34 | nop | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #include "NGmemcpy.S" | ||
diff --git a/arch/sparc64/lib/NGcopy_to_user.S b/arch/sparc64/lib/NGcopy_to_user.S new file mode 100644 index 000000000000..34112d5054ef --- /dev/null +++ b/arch/sparc64/lib/NGcopy_to_user.S | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* NGcopy_to_user.S: Niagara optimized copy to userspace. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #define EX_ST(x) \ | ||
| 7 | 98: x; \ | ||
| 8 | .section .fixup; \ | ||
| 9 | .align 4; \ | ||
| 10 | 99: wr %g0, ASI_AIUS, %asi;\ | ||
| 11 | retl; \ | ||
| 12 | mov 1, %o0; \ | ||
| 13 | .section __ex_table,"a";\ | ||
| 14 | .align 4; \ | ||
| 15 | .word 98b, 99b; \ | ||
| 16 | .text; \ | ||
| 17 | .align 4; | ||
| 18 | |||
| 19 | #ifndef ASI_AIUS | ||
| 20 | #define ASI_AIUS 0x11 | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #define FUNC_NAME NGcopy_to_user | ||
| 24 | #define STORE(type,src,addr) type##a src, [addr] ASI_AIUS | ||
| 25 | #define STORE_ASI ASI_BLK_INIT_QUAD_LDD_AIUS | ||
| 26 | #define EX_RETVAL(x) 0 | ||
| 27 | |||
| 28 | #ifdef __KERNEL__ | ||
| 29 | /* Writing to %asi is _expensive_ so we hardcode it. | ||
| 30 | * Reading %asi to check for KERNEL_DS is comparatively | ||
| 31 | * cheap. | ||
| 32 | */ | ||
| 33 | #define PREAMBLE \ | ||
| 34 | rd %asi, %g1; \ | ||
| 35 | cmp %g1, ASI_AIUS; \ | ||
| 36 | bne,pn %icc, memcpy_user_stub; \ | ||
| 37 | nop | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #include "NGmemcpy.S" | ||
diff --git a/arch/sparc64/lib/NGmemcpy.S b/arch/sparc64/lib/NGmemcpy.S new file mode 100644 index 000000000000..8e522b3dc095 --- /dev/null +++ b/arch/sparc64/lib/NGmemcpy.S | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /* NGmemcpy.S: Niagara optimized memcpy. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifdef __KERNEL__ | ||
| 7 | #include <asm/asi.h> | ||
| 8 | #include <asm/thread_info.h> | ||
| 9 | #define GLOBAL_SPARE %g7 | ||
| 10 | #define RESTORE_ASI(TMP) \ | ||
| 11 | ldub [%g6 + TI_CURRENT_DS], TMP; \ | ||
| 12 | wr TMP, 0x0, %asi; | ||
| 13 | #else | ||
| 14 | #define GLOBAL_SPARE %g5 | ||
| 15 | #define RESTORE_ASI(TMP) \ | ||
| 16 | wr %g0, ASI_PNF, %asi | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #ifndef STORE_ASI | ||
| 20 | #define STORE_ASI ASI_BLK_INIT_QUAD_LDD_P | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #ifndef EX_LD | ||
| 24 | #define EX_LD(x) x | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #ifndef EX_ST | ||
| 28 | #define EX_ST(x) x | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #ifndef EX_RETVAL | ||
| 32 | #define EX_RETVAL(x) x | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #ifndef LOAD | ||
| 36 | #ifndef MEMCPY_DEBUG | ||
| 37 | #define LOAD(type,addr,dest) type [addr], dest | ||
| 38 | #else | ||
| 39 | #define LOAD(type,addr,dest) type##a [addr] 0x80, dest | ||
| 40 | #endif | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #ifndef LOAD_TWIN | ||
| 44 | #define LOAD_TWIN(addr_reg,dest0,dest1) \ | ||
| 45 | ldda [addr_reg] ASI_BLK_INIT_QUAD_LDD_P, dest0 | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #ifndef STORE | ||
| 49 | #define STORE(type,src,addr) type src, [addr] | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #ifndef STORE_INIT | ||
| 53 | #define STORE_INIT(src,addr) stxa src, [addr] %asi | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #ifndef FUNC_NAME | ||
| 57 | #define FUNC_NAME NGmemcpy | ||
| 58 | #endif | ||
| 59 | |||
| 60 | #ifndef PREAMBLE | ||
| 61 | #define PREAMBLE | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #ifndef XCC | ||
| 65 | #define XCC xcc | ||
| 66 | #endif | ||
| 67 | |||
| 68 | .register %g2,#scratch | ||
| 69 | .register %g3,#scratch | ||
| 70 | |||
| 71 | .text | ||
| 72 | .align 64 | ||
| 73 | |||
| 74 | .globl FUNC_NAME | ||
| 75 | .type FUNC_NAME,#function | ||
| 76 | FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ | ||
| 77 | srlx %o2, 31, %g2 | ||
| 78 | cmp %g2, 0 | ||
| 79 | tne %xcc, 5 | ||
| 80 | PREAMBLE | ||
| 81 | mov %o0, GLOBAL_SPARE | ||
| 82 | cmp %o2, 0 | ||
| 83 | be,pn %XCC, 85f | ||
| 84 | or %o0, %o1, %o3 | ||
| 85 | cmp %o2, 16 | ||
| 86 | blu,a,pn %XCC, 80f | ||
| 87 | or %o3, %o2, %o3 | ||
| 88 | |||
| 89 | /* 2 blocks (128 bytes) is the minimum we can do the block | ||
| 90 | * copy with. We need to ensure that we'll iterate at least | ||
| 91 | * once in the block copy loop. At worst we'll need to align | ||
| 92 | * the destination to a 64-byte boundary which can chew up | ||
| 93 | * to (64 - 1) bytes from the length before we perform the | ||
| 94 | * block copy loop. | ||
| 95 | */ | ||
| 96 | cmp %o2, (2 * 64) | ||
| 97 | blu,pt %XCC, 70f | ||
| 98 | andcc %o3, 0x7, %g0 | ||
| 99 | |||
| 100 | /* %o0: dst | ||
| 101 | * %o1: src | ||
| 102 | * %o2: len (known to be >= 128) | ||
| 103 | * | ||
| 104 | * The block copy loops will use %o4/%o5,%g2/%g3 as | ||
| 105 | * temporaries while copying the data. | ||
| 106 | */ | ||
| 107 | |||
| 108 | LOAD(prefetch, %o1, #one_read) | ||
| 109 | wr %g0, STORE_ASI, %asi | ||
| 110 | |||
| 111 | /* Align destination on 64-byte boundary. */ | ||
| 112 | andcc %o0, (64 - 1), %o4 | ||
| 113 | be,pt %XCC, 2f | ||
| 114 | sub %o4, 64, %o4 | ||
| 115 | sub %g0, %o4, %o4 ! bytes to align dst | ||
| 116 | sub %o2, %o4, %o2 | ||
| 117 | 1: subcc %o4, 1, %o4 | ||
| 118 | EX_LD(LOAD(ldub, %o1, %g1)) | ||
| 119 | EX_ST(STORE(stb, %g1, %o0)) | ||
| 120 | add %o1, 1, %o1 | ||
| 121 | bne,pt %XCC, 1b | ||
| 122 | add %o0, 1, %o0 | ||
| 123 | |||
| 124 | /* If the source is on a 16-byte boundary we can do | ||
| 125 | * the direct block copy loop. If it is 8-byte aligned | ||
| 126 | * we can do the 16-byte loads offset by -8 bytes and the | ||
| 127 | * init stores offset by one register. | ||
| 128 | * | ||
| 129 | * If the source is not even 8-byte aligned, we need to do | ||
| 130 | * shifting and masking (basically integer faligndata). | ||
| 131 | * | ||
| 132 | * The careful bit with init stores is that if we store | ||
| 133 | * to any part of the cache line we have to store the whole | ||
| 134 | * cacheline else we can end up with corrupt L2 cache line | ||
| 135 | * contents. Since the loop works on 64-bytes of 64-byte | ||
| 136 | * aligned store data at a time, this is easy to ensure. | ||
| 137 | */ | ||
| 138 | 2: | ||
| 139 | andcc %o1, (16 - 1), %o4 | ||
| 140 | andn %o2, (64 - 1), %g1 ! block copy loop iterator | ||
| 141 | sub %o2, %g1, %o2 ! final sub-block copy bytes | ||
| 142 | be,pt %XCC, 50f | ||
| 143 | cmp %o4, 8 | ||
| 144 | be,a,pt %XCC, 10f | ||
| 145 | sub %o1, 0x8, %o1 | ||
| 146 | |||
| 147 | /* Neither 8-byte nor 16-byte aligned, shift and mask. */ | ||
| 148 | mov %g1, %o4 | ||
| 149 | and %o1, 0x7, %g1 | ||
| 150 | sll %g1, 3, %g1 | ||
| 151 | mov 64, %o3 | ||
| 152 | andn %o1, 0x7, %o1 | ||
| 153 | EX_LD(LOAD(ldx, %o1, %g2)) | ||
| 154 | sub %o3, %g1, %o3 | ||
| 155 | sllx %g2, %g1, %g2 | ||
| 156 | |||
| 157 | #define SWIVEL_ONE_DWORD(SRC, TMP1, TMP2, PRE_VAL, PRE_SHIFT, POST_SHIFT, DST)\ | ||
| 158 | EX_LD(LOAD(ldx, SRC, TMP1)); \ | ||
| 159 | srlx TMP1, PRE_SHIFT, TMP2; \ | ||
| 160 | or TMP2, PRE_VAL, TMP2; \ | ||
| 161 | EX_ST(STORE_INIT(TMP2, DST)); \ | ||
| 162 | sllx TMP1, POST_SHIFT, PRE_VAL; | ||
| 163 | |||
| 164 | 1: add %o1, 0x8, %o1 | ||
| 165 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x00) | ||
| 166 | add %o1, 0x8, %o1 | ||
| 167 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x08) | ||
| 168 | add %o1, 0x8, %o1 | ||
| 169 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x10) | ||
| 170 | add %o1, 0x8, %o1 | ||
| 171 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x18) | ||
| 172 | add %o1, 32, %o1 | ||
| 173 | LOAD(prefetch, %o1, #one_read) | ||
| 174 | sub %o1, 32 - 8, %o1 | ||
| 175 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x20) | ||
| 176 | add %o1, 8, %o1 | ||
| 177 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x28) | ||
| 178 | add %o1, 8, %o1 | ||
| 179 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x30) | ||
| 180 | add %o1, 8, %o1 | ||
| 181 | SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x38) | ||
| 182 | subcc %o4, 64, %o4 | ||
| 183 | bne,pt %XCC, 1b | ||
| 184 | add %o0, 64, %o0 | ||
| 185 | |||
| 186 | #undef SWIVEL_ONE_DWORD | ||
| 187 | |||
| 188 | srl %g1, 3, %g1 | ||
| 189 | ba,pt %XCC, 60f | ||
| 190 | add %o1, %g1, %o1 | ||
| 191 | |||
| 192 | 10: /* Destination is 64-byte aligned, source was only 8-byte | ||
| 193 | * aligned but it has been subtracted by 8 and we perform | ||
| 194 | * one twin load ahead, then add 8 back into source when | ||
| 195 | * we finish the loop. | ||
| 196 | */ | ||
| 197 | EX_LD(LOAD_TWIN(%o1, %o4, %o5)) | ||
| 198 | 1: add %o1, 16, %o1 | ||
| 199 | EX_LD(LOAD_TWIN(%o1, %g2, %g3)) | ||
| 200 | add %o1, 16 + 32, %o1 | ||
| 201 | LOAD(prefetch, %o1, #one_read) | ||
| 202 | sub %o1, 32, %o1 | ||
| 203 | EX_ST(STORE_INIT(%o5, %o0 + 0x00)) ! initializes cache line | ||
| 204 | EX_ST(STORE_INIT(%g2, %o0 + 0x08)) | ||
| 205 | EX_LD(LOAD_TWIN(%o1, %o4, %o5)) | ||
| 206 | add %o1, 16, %o1 | ||
| 207 | EX_ST(STORE_INIT(%g3, %o0 + 0x10)) | ||
| 208 | EX_ST(STORE_INIT(%o4, %o0 + 0x18)) | ||
| 209 | EX_LD(LOAD_TWIN(%o1, %g2, %g3)) | ||
| 210 | add %o1, 16, %o1 | ||
| 211 | EX_ST(STORE_INIT(%o5, %o0 + 0x20)) | ||
| 212 | EX_ST(STORE_INIT(%g2, %o0 + 0x28)) | ||
| 213 | EX_LD(LOAD_TWIN(%o1, %o4, %o5)) | ||
| 214 | EX_ST(STORE_INIT(%g3, %o0 + 0x30)) | ||
| 215 | EX_ST(STORE_INIT(%o4, %o0 + 0x38)) | ||
| 216 | subcc %g1, 64, %g1 | ||
| 217 | bne,pt %XCC, 1b | ||
| 218 | add %o0, 64, %o0 | ||
| 219 | |||
| 220 | ba,pt %XCC, 60f | ||
| 221 | add %o1, 0x8, %o1 | ||
| 222 | |||
| 223 | 50: /* Destination is 64-byte aligned, and source is 16-byte | ||
| 224 | * aligned. | ||
| 225 | */ | ||
| 226 | 1: EX_LD(LOAD_TWIN(%o1, %o4, %o5)) | ||
| 227 | add %o1, 16, %o1 | ||
| 228 | EX_LD(LOAD_TWIN(%o1, %g2, %g3)) | ||
| 229 | add %o1, 16 + 32, %o1 | ||
| 230 | LOAD(prefetch, %o1, #one_read) | ||
| 231 | sub %o1, 32, %o1 | ||
| 232 | EX_ST(STORE_INIT(%o4, %o0 + 0x00)) ! initializes cache line | ||
| 233 | EX_ST(STORE_INIT(%o5, %o0 + 0x08)) | ||
| 234 | EX_LD(LOAD_TWIN(%o1, %o4, %o5)) | ||
| 235 | add %o1, 16, %o1 | ||
| 236 | EX_ST(STORE_INIT(%g2, %o0 + 0x10)) | ||
| 237 | EX_ST(STORE_INIT(%g3, %o0 + 0x18)) | ||
| 238 | EX_LD(LOAD_TWIN(%o1, %g2, %g3)) | ||
| 239 | add %o1, 16, %o1 | ||
| 240 | EX_ST(STORE_INIT(%o4, %o0 + 0x20)) | ||
| 241 | EX_ST(STORE_INIT(%o5, %o0 + 0x28)) | ||
| 242 | EX_ST(STORE_INIT(%g2, %o0 + 0x30)) | ||
| 243 | EX_ST(STORE_INIT(%g3, %o0 + 0x38)) | ||
| 244 | subcc %g1, 64, %g1 | ||
| 245 | bne,pt %XCC, 1b | ||
| 246 | add %o0, 64, %o0 | ||
| 247 | /* fall through */ | ||
| 248 | |||
| 249 | 60: | ||
| 250 | /* %o2 contains any final bytes still needed to be copied | ||
| 251 | * over. If anything is left, we copy it one byte at a time. | ||
| 252 | */ | ||
| 253 | RESTORE_ASI(%o3) | ||
| 254 | brz,pt %o2, 85f | ||
| 255 | sub %o0, %o1, %o3 | ||
| 256 | ba,a,pt %XCC, 90f | ||
| 257 | |||
| 258 | .align 64 | ||
| 259 | 70: /* 16 < len <= 64 */ | ||
| 260 | bne,pn %XCC, 75f | ||
| 261 | sub %o0, %o1, %o3 | ||
| 262 | |||
| 263 | 72: | ||
| 264 | andn %o2, 0xf, %o4 | ||
| 265 | and %o2, 0xf, %o2 | ||
| 266 | 1: subcc %o4, 0x10, %o4 | ||
| 267 | EX_LD(LOAD(ldx, %o1, %o5)) | ||
| 268 | add %o1, 0x08, %o1 | ||
| 269 | EX_LD(LOAD(ldx, %o1, %g1)) | ||
| 270 | sub %o1, 0x08, %o1 | ||
| 271 | EX_ST(STORE(stx, %o5, %o1 + %o3)) | ||
| 272 | add %o1, 0x8, %o1 | ||
| 273 | EX_ST(STORE(stx, %g1, %o1 + %o3)) | ||
| 274 | bgu,pt %XCC, 1b | ||
| 275 | add %o1, 0x8, %o1 | ||
| 276 | 73: andcc %o2, 0x8, %g0 | ||
| 277 | be,pt %XCC, 1f | ||
| 278 | nop | ||
| 279 | sub %o2, 0x8, %o2 | ||
| 280 | EX_LD(LOAD(ldx, %o1, %o5)) | ||
| 281 | EX_ST(STORE(stx, %o5, %o1 + %o3)) | ||
| 282 | add %o1, 0x8, %o1 | ||
| 283 | 1: andcc %o2, 0x4, %g0 | ||
| 284 | be,pt %XCC, 1f | ||
| 285 | nop | ||
| 286 | sub %o2, 0x4, %o2 | ||
| 287 | EX_LD(LOAD(lduw, %o1, %o5)) | ||
| 288 | EX_ST(STORE(stw, %o5, %o1 + %o3)) | ||
| 289 | add %o1, 0x4, %o1 | ||
| 290 | 1: cmp %o2, 0 | ||
| 291 | be,pt %XCC, 85f | ||
| 292 | nop | ||
| 293 | ba,pt %xcc, 90f | ||
| 294 | nop | ||
| 295 | |||
| 296 | 75: | ||
| 297 | andcc %o0, 0x7, %g1 | ||
| 298 | sub %g1, 0x8, %g1 | ||
| 299 | be,pn %icc, 2f | ||
| 300 | sub %g0, %g1, %g1 | ||
| 301 | sub %o2, %g1, %o2 | ||
| 302 | |||
| 303 | 1: subcc %g1, 1, %g1 | ||
| 304 | EX_LD(LOAD(ldub, %o1, %o5)) | ||
| 305 | EX_ST(STORE(stb, %o5, %o1 + %o3)) | ||
| 306 | bgu,pt %icc, 1b | ||
| 307 | add %o1, 1, %o1 | ||
| 308 | |||
| 309 | 2: add %o1, %o3, %o0 | ||
| 310 | andcc %o1, 0x7, %g1 | ||
| 311 | bne,pt %icc, 8f | ||
| 312 | sll %g1, 3, %g1 | ||
| 313 | |||
| 314 | cmp %o2, 16 | ||
| 315 | bgeu,pt %icc, 72b | ||
| 316 | nop | ||
| 317 | ba,a,pt %xcc, 73b | ||
| 318 | |||
| 319 | 8: mov 64, %o3 | ||
| 320 | andn %o1, 0x7, %o1 | ||
| 321 | EX_LD(LOAD(ldx, %o1, %g2)) | ||
| 322 | sub %o3, %g1, %o3 | ||
| 323 | andn %o2, 0x7, %o4 | ||
| 324 | sllx %g2, %g1, %g2 | ||
| 325 | 1: add %o1, 0x8, %o1 | ||
| 326 | EX_LD(LOAD(ldx, %o1, %g3)) | ||
| 327 | subcc %o4, 0x8, %o4 | ||
| 328 | srlx %g3, %o3, %o5 | ||
| 329 | or %o5, %g2, %o5 | ||
| 330 | EX_ST(STORE(stx, %o5, %o0)) | ||
| 331 | add %o0, 0x8, %o0 | ||
| 332 | bgu,pt %icc, 1b | ||
| 333 | sllx %g3, %g1, %g2 | ||
| 334 | |||
| 335 | srl %g1, 3, %g1 | ||
| 336 | andcc %o2, 0x7, %o2 | ||
| 337 | be,pn %icc, 85f | ||
| 338 | add %o1, %g1, %o1 | ||
| 339 | ba,pt %xcc, 90f | ||
| 340 | sub %o0, %o1, %o3 | ||
| 341 | |||
| 342 | .align 64 | ||
| 343 | 80: /* 0 < len <= 16 */ | ||
| 344 | andcc %o3, 0x3, %g0 | ||
| 345 | bne,pn %XCC, 90f | ||
| 346 | sub %o0, %o1, %o3 | ||
| 347 | |||
| 348 | 1: | ||
| 349 | subcc %o2, 4, %o2 | ||
| 350 | EX_LD(LOAD(lduw, %o1, %g1)) | ||
| 351 | EX_ST(STORE(stw, %g1, %o1 + %o3)) | ||
| 352 | bgu,pt %XCC, 1b | ||
| 353 | add %o1, 4, %o1 | ||
| 354 | |||
| 355 | 85: retl | ||
| 356 | mov EX_RETVAL(GLOBAL_SPARE), %o0 | ||
| 357 | |||
| 358 | .align 32 | ||
| 359 | 90: | ||
| 360 | subcc %o2, 1, %o2 | ||
| 361 | EX_LD(LOAD(ldub, %o1, %g1)) | ||
| 362 | EX_ST(STORE(stb, %g1, %o1 + %o3)) | ||
| 363 | bgu,pt %XCC, 90b | ||
| 364 | add %o1, 1, %o1 | ||
| 365 | retl | ||
| 366 | mov EX_RETVAL(GLOBAL_SPARE), %o0 | ||
| 367 | |||
| 368 | .size FUNC_NAME, .-FUNC_NAME | ||
diff --git a/arch/sparc64/lib/NGpage.S b/arch/sparc64/lib/NGpage.S new file mode 100644 index 000000000000..7d7c3bb8dcbf --- /dev/null +++ b/arch/sparc64/lib/NGpage.S | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /* NGpage.S: Niagara optimize clear and copy page. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <asm/asi.h> | ||
| 7 | #include <asm/page.h> | ||
| 8 | |||
| 9 | .text | ||
| 10 | .align 32 | ||
| 11 | |||
| 12 | /* This is heavily simplified from the sun4u variants | ||
| 13 | * because Niagara does not have any D-cache aliasing issues | ||
| 14 | * and also we don't need to use the FPU in order to implement | ||
| 15 | * an optimal page copy/clear. | ||
| 16 | */ | ||
| 17 | |||
| 18 | NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ | ||
| 19 | prefetch [%o1 + 0x00], #one_read | ||
| 20 | mov 8, %g1 | ||
| 21 | mov 16, %g2 | ||
| 22 | mov 24, %g3 | ||
| 23 | set PAGE_SIZE, %g7 | ||
| 24 | |||
| 25 | 1: ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2 | ||
| 26 | ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4 | ||
| 27 | prefetch [%o1 + 0x40], #one_read | ||
| 28 | add %o1, 32, %o1 | ||
| 29 | stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P | ||
| 30 | stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P | ||
| 31 | ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2 | ||
| 32 | stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P | ||
| 33 | stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P | ||
| 34 | ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4 | ||
| 35 | add %o1, 32, %o1 | ||
| 36 | add %o0, 32, %o0 | ||
| 37 | stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P | ||
| 38 | stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P | ||
| 39 | stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P | ||
| 40 | stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P | ||
| 41 | subcc %g7, 64, %g7 | ||
| 42 | bne,pt %xcc, 1b | ||
| 43 | add %o0, 32, %o0 | ||
| 44 | retl | ||
| 45 | nop | ||
| 46 | |||
| 47 | NGclear_page: /* %o0=dest */ | ||
| 48 | NGclear_user_page: /* %o0=dest, %o1=vaddr */ | ||
| 49 | mov 8, %g1 | ||
| 50 | mov 16, %g2 | ||
| 51 | mov 24, %g3 | ||
| 52 | set PAGE_SIZE, %g7 | ||
| 53 | |||
| 54 | 1: stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P | ||
| 55 | stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P | ||
| 56 | stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P | ||
| 57 | stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P | ||
| 58 | add %o0, 32, %o0 | ||
| 59 | stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P | ||
| 60 | stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P | ||
| 61 | stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P | ||
| 62 | stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P | ||
| 63 | subcc %g7, 64, %g7 | ||
| 64 | bne,pt %xcc, 1b | ||
| 65 | add %o0, 32, %o0 | ||
| 66 | retl | ||
| 67 | nop | ||
| 68 | |||
| 69 | #define BRANCH_ALWAYS 0x10680000 | ||
| 70 | #define NOP 0x01000000 | ||
| 71 | #define NG_DO_PATCH(OLD, NEW) \ | ||
| 72 | sethi %hi(NEW), %g1; \ | ||
| 73 | or %g1, %lo(NEW), %g1; \ | ||
| 74 | sethi %hi(OLD), %g2; \ | ||
| 75 | or %g2, %lo(OLD), %g2; \ | ||
| 76 | sub %g1, %g2, %g1; \ | ||
| 77 | sethi %hi(BRANCH_ALWAYS), %g3; \ | ||
| 78 | sll %g1, 11, %g1; \ | ||
| 79 | srl %g1, 11 + 2, %g1; \ | ||
| 80 | or %g3, %lo(BRANCH_ALWAYS), %g3; \ | ||
| 81 | or %g3, %g1, %g3; \ | ||
| 82 | stw %g3, [%g2]; \ | ||
| 83 | sethi %hi(NOP), %g3; \ | ||
| 84 | or %g3, %lo(NOP), %g3; \ | ||
| 85 | stw %g3, [%g2 + 0x4]; \ | ||
| 86 | flush %g2; | ||
| 87 | |||
| 88 | .globl niagara_patch_pageops | ||
| 89 | .type niagara_patch_pageops,#function | ||
| 90 | niagara_patch_pageops: | ||
| 91 | NG_DO_PATCH(copy_user_page, NGcopy_user_page) | ||
| 92 | NG_DO_PATCH(_clear_page, NGclear_page) | ||
| 93 | NG_DO_PATCH(clear_user_page, NGclear_user_page) | ||
| 94 | retl | ||
| 95 | nop | ||
| 96 | .size niagara_patch_pageops,.-niagara_patch_pageops | ||
diff --git a/arch/sparc64/lib/NGpatch.S b/arch/sparc64/lib/NGpatch.S new file mode 100644 index 000000000000..3b0674fc3366 --- /dev/null +++ b/arch/sparc64/lib/NGpatch.S | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* NGpatch.S: Patch Ultra-I routines with Niagara variant. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #define BRANCH_ALWAYS 0x10680000 | ||
| 7 | #define NOP 0x01000000 | ||
| 8 | #define NG_DO_PATCH(OLD, NEW) \ | ||
| 9 | sethi %hi(NEW), %g1; \ | ||
| 10 | or %g1, %lo(NEW), %g1; \ | ||
| 11 | sethi %hi(OLD), %g2; \ | ||
| 12 | or %g2, %lo(OLD), %g2; \ | ||
| 13 | sub %g1, %g2, %g1; \ | ||
| 14 | sethi %hi(BRANCH_ALWAYS), %g3; \ | ||
| 15 | sll %g1, 11, %g1; \ | ||
| 16 | srl %g1, 11 + 2, %g1; \ | ||
| 17 | or %g3, %lo(BRANCH_ALWAYS), %g3; \ | ||
| 18 | or %g3, %g1, %g3; \ | ||
| 19 | stw %g3, [%g2]; \ | ||
| 20 | sethi %hi(NOP), %g3; \ | ||
| 21 | or %g3, %lo(NOP), %g3; \ | ||
| 22 | stw %g3, [%g2 + 0x4]; \ | ||
| 23 | flush %g2; | ||
| 24 | |||
| 25 | .globl niagara_patch_copyops | ||
| 26 | .type niagara_patch_copyops,#function | ||
| 27 | niagara_patch_copyops: | ||
| 28 | NG_DO_PATCH(memcpy, NGmemcpy) | ||
| 29 | NG_DO_PATCH(___copy_from_user, NGcopy_from_user) | ||
| 30 | NG_DO_PATCH(___copy_to_user, NGcopy_to_user) | ||
| 31 | retl | ||
| 32 | nop | ||
| 33 | .size niagara_patch_copyops,.-niagara_patch_copyops | ||
diff --git a/arch/sparc64/lib/U3patch.S b/arch/sparc64/lib/U3patch.S index e2b6c5e4b95a..ecc302619a6e 100644 --- a/arch/sparc64/lib/U3patch.S +++ b/arch/sparc64/lib/U3patch.S | |||
| @@ -12,7 +12,8 @@ | |||
| 12 | or %g2, %lo(OLD), %g2; \ | 12 | or %g2, %lo(OLD), %g2; \ |
| 13 | sub %g1, %g2, %g1; \ | 13 | sub %g1, %g2, %g1; \ |
| 14 | sethi %hi(BRANCH_ALWAYS), %g3; \ | 14 | sethi %hi(BRANCH_ALWAYS), %g3; \ |
| 15 | srl %g1, 2, %g1; \ | 15 | sll %g1, 11, %g1; \ |
| 16 | srl %g1, 11 + 2, %g1; \ | ||
| 16 | or %g3, %lo(BRANCH_ALWAYS), %g3; \ | 17 | or %g3, %lo(BRANCH_ALWAYS), %g3; \ |
| 17 | or %g3, %g1, %g3; \ | 18 | or %g3, %g1, %g3; \ |
| 18 | stw %g3, [%g2]; \ | 19 | stw %g3, [%g2]; \ |
diff --git a/arch/sparc64/lib/bzero.S b/arch/sparc64/lib/bzero.S index 1d2abcfa4e52..c7bbae8c590f 100644 --- a/arch/sparc64/lib/bzero.S +++ b/arch/sparc64/lib/bzero.S | |||
| @@ -98,12 +98,12 @@ __bzero_done: | |||
| 98 | .text; \ | 98 | .text; \ |
| 99 | .align 4; | 99 | .align 4; |
| 100 | 100 | ||
| 101 | .globl __bzero_noasi | 101 | .globl __clear_user |
| 102 | .type __bzero_noasi, #function | 102 | .type __clear_user, #function |
| 103 | __bzero_noasi: /* %o0=buf, %o1=len */ | 103 | __clear_user: /* %o0=buf, %o1=len */ |
| 104 | brz,pn %o1, __bzero_noasi_done | 104 | brz,pn %o1, __clear_user_done |
| 105 | cmp %o1, 16 | 105 | cmp %o1, 16 |
| 106 | bl,pn %icc, __bzero_noasi_tiny | 106 | bl,pn %icc, __clear_user_tiny |
| 107 | EX_ST(prefetcha [%o0 + 0x00] %asi, #n_writes) | 107 | EX_ST(prefetcha [%o0 + 0x00] %asi, #n_writes) |
| 108 | andcc %o0, 0x3, %g0 | 108 | andcc %o0, 0x3, %g0 |
| 109 | be,pt %icc, 2f | 109 | be,pt %icc, 2f |
| @@ -145,14 +145,14 @@ __bzero_noasi: /* %o0=buf, %o1=len */ | |||
| 145 | subcc %g1, 8, %g1 | 145 | subcc %g1, 8, %g1 |
| 146 | bne,pt %icc, 5b | 146 | bne,pt %icc, 5b |
| 147 | add %o0, 0x8, %o0 | 147 | add %o0, 0x8, %o0 |
| 148 | 6: brz,pt %o1, __bzero_noasi_done | 148 | 6: brz,pt %o1, __clear_user_done |
| 149 | nop | 149 | nop |
| 150 | __bzero_noasi_tiny: | 150 | __clear_user_tiny: |
| 151 | 1: EX_ST(stba %g0, [%o0 + 0x00] %asi) | 151 | 1: EX_ST(stba %g0, [%o0 + 0x00] %asi) |
| 152 | subcc %o1, 1, %o1 | 152 | subcc %o1, 1, %o1 |
| 153 | bne,pt %icc, 1b | 153 | bne,pt %icc, 1b |
| 154 | add %o0, 1, %o0 | 154 | add %o0, 1, %o0 |
| 155 | __bzero_noasi_done: | 155 | __clear_user_done: |
| 156 | retl | 156 | retl |
| 157 | clr %o0 | 157 | clr %o0 |
| 158 | .size __bzero_noasi, .-__bzero_noasi | 158 | .size __clear_user, .-__clear_user |
diff --git a/arch/sparc64/lib/clear_page.S b/arch/sparc64/lib/clear_page.S index b59884ef051d..77e531f6c2a7 100644 --- a/arch/sparc64/lib/clear_page.S +++ b/arch/sparc64/lib/clear_page.S | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <asm/page.h> | 9 | #include <asm/page.h> |
| 10 | #include <asm/pgtable.h> | 10 | #include <asm/pgtable.h> |
| 11 | #include <asm/spitfire.h> | 11 | #include <asm/spitfire.h> |
| 12 | #include <asm/head.h> | ||
| 12 | 13 | ||
| 13 | /* What we used to do was lock a TLB entry into a specific | 14 | /* What we used to do was lock a TLB entry into a specific |
| 14 | * TLB slot, clear the page with interrupts disabled, then | 15 | * TLB slot, clear the page with interrupts disabled, then |
| @@ -22,9 +23,6 @@ | |||
| 22 | * disable preemption during the clear. | 23 | * disable preemption during the clear. |
| 23 | */ | 24 | */ |
| 24 | 25 | ||
| 25 | #define TTE_BITS_TOP (_PAGE_VALID | _PAGE_SZBITS) | ||
| 26 | #define TTE_BITS_BOTTOM (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W) | ||
| 27 | |||
| 28 | .text | 26 | .text |
| 29 | 27 | ||
| 30 | .globl _clear_page | 28 | .globl _clear_page |
| @@ -43,12 +41,11 @@ clear_user_page: /* %o0=dest, %o1=vaddr */ | |||
| 43 | sethi %hi(PAGE_SIZE), %o4 | 41 | sethi %hi(PAGE_SIZE), %o4 |
| 44 | 42 | ||
| 45 | sllx %g2, 32, %g2 | 43 | sllx %g2, 32, %g2 |
| 46 | sethi %uhi(TTE_BITS_TOP), %g3 | 44 | sethi %hi(PAGE_KERNEL_LOCKED), %g3 |
| 47 | 45 | ||
| 48 | sllx %g3, 32, %g3 | 46 | ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3 |
| 49 | sub %o0, %g2, %g1 ! paddr | 47 | sub %o0, %g2, %g1 ! paddr |
| 50 | 48 | ||
| 51 | or %g3, TTE_BITS_BOTTOM, %g3 | ||
| 52 | and %o1, %o4, %o0 ! vaddr D-cache alias bit | 49 | and %o1, %o4, %o0 ! vaddr D-cache alias bit |
| 53 | 50 | ||
| 54 | or %g1, %g3, %g1 ! TTE data | 51 | or %g1, %g3, %g1 ! TTE data |
| @@ -66,7 +63,8 @@ clear_user_page: /* %o0=dest, %o1=vaddr */ | |||
| 66 | wrpr %o4, PSTATE_IE, %pstate | 63 | wrpr %o4, PSTATE_IE, %pstate |
| 67 | stxa %o0, [%g3] ASI_DMMU | 64 | stxa %o0, [%g3] ASI_DMMU |
| 68 | stxa %g1, [%g0] ASI_DTLB_DATA_IN | 65 | stxa %g1, [%g0] ASI_DTLB_DATA_IN |
| 69 | flush %g6 | 66 | sethi %hi(KERNBASE), %g1 |
| 67 | flush %g1 | ||
| 70 | wrpr %o4, 0x0, %pstate | 68 | wrpr %o4, 0x0, %pstate |
| 71 | 69 | ||
| 72 | mov 1, %o4 | 70 | mov 1, %o4 |
diff --git a/arch/sparc64/lib/copy_page.S b/arch/sparc64/lib/copy_page.S index feebb14fd27a..37460666a5c3 100644 --- a/arch/sparc64/lib/copy_page.S +++ b/arch/sparc64/lib/copy_page.S | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | * disable preemption during the clear. | 23 | * disable preemption during the clear. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #define TTE_BITS_TOP (_PAGE_VALID | _PAGE_SZBITS) | ||
| 27 | #define TTE_BITS_BOTTOM (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W) | ||
| 28 | #define DCACHE_SIZE (PAGE_SIZE * 2) | 26 | #define DCACHE_SIZE (PAGE_SIZE * 2) |
| 29 | 27 | ||
| 30 | #if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19) | 28 | #if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19) |
| @@ -52,13 +50,12 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ | |||
| 52 | sethi %hi(PAGE_SIZE), %o3 | 50 | sethi %hi(PAGE_SIZE), %o3 |
| 53 | 51 | ||
| 54 | sllx %g2, 32, %g2 | 52 | sllx %g2, 32, %g2 |
| 55 | sethi %uhi(TTE_BITS_TOP), %g3 | 53 | sethi %hi(PAGE_KERNEL_LOCKED), %g3 |
| 56 | 54 | ||
| 57 | sllx %g3, 32, %g3 | 55 | ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3 |
| 58 | sub %o0, %g2, %g1 ! dest paddr | 56 | sub %o0, %g2, %g1 ! dest paddr |
| 59 | 57 | ||
| 60 | sub %o1, %g2, %g2 ! src paddr | 58 | sub %o1, %g2, %g2 ! src paddr |
| 61 | or %g3, TTE_BITS_BOTTOM, %g3 | ||
| 62 | 59 | ||
| 63 | and %o2, %o3, %o0 ! vaddr D-cache alias bit | 60 | and %o2, %o3, %o0 ! vaddr D-cache alias bit |
| 64 | or %g1, %g3, %g1 ! dest TTE data | 61 | or %g1, %g3, %g1 ! dest TTE data |
diff --git a/arch/sparc64/lib/delay.c b/arch/sparc64/lib/delay.c index e8808727617a..fb27e54a03ee 100644 --- a/arch/sparc64/lib/delay.c +++ b/arch/sparc64/lib/delay.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* delay.c: Delay loops for sparc64 | 1 | /* delay.c: Delay loops for sparc64 |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004 David S. Miller <davem@redhat.com> | 3 | * Copyright (C) 2004, 2006 David S. Miller <davem@davemloft.net> |
| 4 | * | 4 | * |
| 5 | * Based heavily upon x86 variant which is: | 5 | * Based heavily upon x86 variant which is: |
| 6 | * Copyright (C) 1993 Linus Torvalds | 6 | * Copyright (C) 1993 Linus Torvalds |
| @@ -8,19 +8,16 @@ | |||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
| 11 | #include <asm/timer.h> | ||
| 11 | 12 | ||
| 12 | void __delay(unsigned long loops) | 13 | void __delay(unsigned long loops) |
| 13 | { | 14 | { |
| 14 | __asm__ __volatile__( | 15 | unsigned long bclock, now; |
| 15 | " b,pt %%xcc, 1f\n" | 16 | |
| 16 | " cmp %0, 0\n" | 17 | bclock = tick_ops->get_tick(); |
| 17 | " .align 32\n" | 18 | do { |
| 18 | "1:\n" | 19 | now = tick_ops->get_tick(); |
| 19 | " bne,pt %%xcc, 1b\n" | 20 | } while ((now-bclock) < loops); |
| 20 | " subcc %0, 1, %0\n" | ||
| 21 | : "=&r" (loops) | ||
| 22 | : "0" (loops) | ||
| 23 | : "cc"); | ||
| 24 | } | 21 | } |
| 25 | 22 | ||
| 26 | /* We used to multiply by HZ after shifting down by 32 bits | 23 | /* We used to multiply by HZ after shifting down by 32 bits |
diff --git a/arch/sparc64/lib/xor.S b/arch/sparc64/lib/xor.S index 4cd5d2be1ae1..a79c8888170d 100644 --- a/arch/sparc64/lib/xor.S +++ b/arch/sparc64/lib/xor.S | |||
| @@ -2,9 +2,10 @@ | |||
| 2 | * arch/sparc64/lib/xor.S | 2 | * arch/sparc64/lib/xor.S |
| 3 | * | 3 | * |
| 4 | * High speed xor_block operation for RAID4/5 utilizing the | 4 | * High speed xor_block operation for RAID4/5 utilizing the |
| 5 | * UltraSparc Visual Instruction Set. | 5 | * UltraSparc Visual Instruction Set and Niagara store-init/twin-load. |
| 6 | * | 6 | * |
| 7 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) | 7 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) |
| 8 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 8 | */ | 9 | */ |
| 9 | 10 | ||
| 10 | #include <asm/visasm.h> | 11 | #include <asm/visasm.h> |
| @@ -19,6 +20,8 @@ | |||
| 19 | */ | 20 | */ |
| 20 | .text | 21 | .text |
| 21 | .align 32 | 22 | .align 32 |
| 23 | |||
| 24 | /* VIS versions. */ | ||
| 22 | .globl xor_vis_2 | 25 | .globl xor_vis_2 |
| 23 | .type xor_vis_2,#function | 26 | .type xor_vis_2,#function |
| 24 | xor_vis_2: | 27 | xor_vis_2: |
| @@ -352,3 +355,298 @@ xor_vis_5: | |||
| 352 | ret | 355 | ret |
| 353 | restore | 356 | restore |
| 354 | .size xor_vis_5, .-xor_vis_5 | 357 | .size xor_vis_5, .-xor_vis_5 |
| 358 | |||
| 359 | /* Niagara versions. */ | ||
| 360 | .globl xor_niagara_2 | ||
| 361 | .type xor_niagara_2,#function | ||
| 362 | xor_niagara_2: /* %o0=bytes, %o1=dest, %o2=src */ | ||
| 363 | save %sp, -192, %sp | ||
| 364 | prefetch [%i1], #n_writes | ||
| 365 | prefetch [%i2], #one_read | ||
| 366 | rd %asi, %g7 | ||
| 367 | wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi | ||
| 368 | srlx %i0, 6, %g1 | ||
| 369 | mov %i1, %i0 | ||
| 370 | mov %i2, %i1 | ||
| 371 | 1: ldda [%i1 + 0x00] %asi, %i2 /* %i2/%i3 = src + 0x00 */ | ||
| 372 | ldda [%i1 + 0x10] %asi, %i4 /* %i4/%i5 = src + 0x10 */ | ||
| 373 | ldda [%i1 + 0x20] %asi, %g2 /* %g2/%g3 = src + 0x20 */ | ||
| 374 | ldda [%i1 + 0x30] %asi, %l0 /* %l0/%l1 = src + 0x30 */ | ||
| 375 | prefetch [%i1 + 0x40], #one_read | ||
| 376 | ldda [%i0 + 0x00] %asi, %o0 /* %o0/%o1 = dest + 0x00 */ | ||
| 377 | ldda [%i0 + 0x10] %asi, %o2 /* %o2/%o3 = dest + 0x10 */ | ||
| 378 | ldda [%i0 + 0x20] %asi, %o4 /* %o4/%o5 = dest + 0x20 */ | ||
| 379 | ldda [%i0 + 0x30] %asi, %l2 /* %l2/%l3 = dest + 0x30 */ | ||
| 380 | prefetch [%i0 + 0x40], #n_writes | ||
| 381 | xor %o0, %i2, %o0 | ||
| 382 | xor %o1, %i3, %o1 | ||
| 383 | stxa %o0, [%i0 + 0x00] %asi | ||
| 384 | stxa %o1, [%i0 + 0x08] %asi | ||
| 385 | xor %o2, %i4, %o2 | ||
| 386 | xor %o3, %i5, %o3 | ||
| 387 | stxa %o2, [%i0 + 0x10] %asi | ||
| 388 | stxa %o3, [%i0 + 0x18] %asi | ||
| 389 | xor %o4, %g2, %o4 | ||
| 390 | xor %o5, %g3, %o5 | ||
| 391 | stxa %o4, [%i0 + 0x20] %asi | ||
| 392 | stxa %o5, [%i0 + 0x28] %asi | ||
| 393 | xor %l2, %l0, %l2 | ||
| 394 | xor %l3, %l1, %l3 | ||
| 395 | stxa %l2, [%i0 + 0x30] %asi | ||
| 396 | stxa %l3, [%i0 + 0x38] %asi | ||
| 397 | add %i0, 0x40, %i0 | ||
| 398 | subcc %g1, 1, %g1 | ||
| 399 | bne,pt %xcc, 1b | ||
| 400 | add %i1, 0x40, %i1 | ||
| 401 | membar #Sync | ||
| 402 | wr %g7, 0x0, %asi | ||
| 403 | ret | ||
| 404 | restore | ||
| 405 | .size xor_niagara_2, .-xor_niagara_2 | ||
| 406 | |||
| 407 | .globl xor_niagara_3 | ||
| 408 | .type xor_niagara_3,#function | ||
| 409 | xor_niagara_3: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2 */ | ||
| 410 | save %sp, -192, %sp | ||
| 411 | prefetch [%i1], #n_writes | ||
| 412 | prefetch [%i2], #one_read | ||
| 413 | prefetch [%i3], #one_read | ||
| 414 | rd %asi, %g7 | ||
| 415 | wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi | ||
| 416 | srlx %i0, 6, %g1 | ||
| 417 | mov %i1, %i0 | ||
| 418 | mov %i2, %i1 | ||
| 419 | mov %i3, %l7 | ||
| 420 | 1: ldda [%i1 + 0x00] %asi, %i2 /* %i2/%i3 = src1 + 0x00 */ | ||
| 421 | ldda [%i1 + 0x10] %asi, %i4 /* %i4/%i5 = src1 + 0x10 */ | ||
| 422 | ldda [%l7 + 0x00] %asi, %g2 /* %g2/%g3 = src2 + 0x00 */ | ||
| 423 | ldda [%l7 + 0x10] %asi, %l0 /* %l0/%l1 = src2 + 0x10 */ | ||
| 424 | ldda [%i0 + 0x00] %asi, %o0 /* %o0/%o1 = dest + 0x00 */ | ||
| 425 | ldda [%i0 + 0x10] %asi, %o2 /* %o2/%o3 = dest + 0x10 */ | ||
| 426 | xor %g2, %i2, %g2 | ||
| 427 | xor %g3, %i3, %g3 | ||
| 428 | xor %o0, %g2, %o0 | ||
| 429 | xor %o1, %g3, %o1 | ||
| 430 | stxa %o0, [%i0 + 0x00] %asi | ||
| 431 | stxa %o1, [%i0 + 0x08] %asi | ||
| 432 | ldda [%i1 + 0x20] %asi, %i2 /* %i2/%i3 = src1 + 0x20 */ | ||
| 433 | ldda [%l7 + 0x20] %asi, %g2 /* %g2/%g3 = src2 + 0x20 */ | ||
| 434 | ldda [%i0 + 0x20] %asi, %o0 /* %o0/%o1 = dest + 0x20 */ | ||
| 435 | xor %l0, %i4, %l0 | ||
| 436 | xor %l1, %i5, %l1 | ||
| 437 | xor %o2, %l0, %o2 | ||
| 438 | xor %o3, %l1, %o3 | ||
| 439 | stxa %o2, [%i0 + 0x10] %asi | ||
| 440 | stxa %o3, [%i0 + 0x18] %asi | ||
| 441 | ldda [%i1 + 0x30] %asi, %i4 /* %i4/%i5 = src1 + 0x30 */ | ||
| 442 | ldda [%l7 + 0x30] %asi, %l0 /* %l0/%l1 = src2 + 0x30 */ | ||
| 443 | ldda [%i0 + 0x30] %asi, %o2 /* %o2/%o3 = dest + 0x30 */ | ||
| 444 | prefetch [%i1 + 0x40], #one_read | ||
| 445 | prefetch [%l7 + 0x40], #one_read | ||
| 446 | prefetch [%i0 + 0x40], #n_writes | ||
| 447 | xor %g2, %i2, %g2 | ||
| 448 | xor %g3, %i3, %g3 | ||
| 449 | xor %o0, %g2, %o0 | ||
| 450 | xor %o1, %g3, %o1 | ||
| 451 | stxa %o0, [%i0 + 0x20] %asi | ||
| 452 | stxa %o1, [%i0 + 0x28] %asi | ||
| 453 | xor %l0, %i4, %l0 | ||
| 454 | xor %l1, %i5, %l1 | ||
| 455 | xor %o2, %l0, %o2 | ||
| 456 | xor %o3, %l1, %o3 | ||
| 457 | stxa %o2, [%i0 + 0x30] %asi | ||
| 458 | stxa %o3, [%i0 + 0x38] %asi | ||
| 459 | add %i0, 0x40, %i0 | ||
| 460 | add %i1, 0x40, %i1 | ||
| 461 | subcc %g1, 1, %g1 | ||
| 462 | bne,pt %xcc, 1b | ||
| 463 | add %l7, 0x40, %l7 | ||
| 464 | membar #Sync | ||
| 465 | wr %g7, 0x0, %asi | ||
| 466 | ret | ||
| 467 | restore | ||
| 468 | .size xor_niagara_3, .-xor_niagara_3 | ||
| 469 | |||
| 470 | .globl xor_niagara_4 | ||
| 471 | .type xor_niagara_4,#function | ||
| 472 | xor_niagara_4: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */ | ||
| 473 | save %sp, -192, %sp | ||
| 474 | prefetch [%i1], #n_writes | ||
| 475 | prefetch [%i2], #one_read | ||
| 476 | prefetch [%i3], #one_read | ||
| 477 | prefetch [%i4], #one_read | ||
| 478 | rd %asi, %g7 | ||
| 479 | wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi | ||
| 480 | srlx %i0, 6, %g1 | ||
| 481 | mov %i1, %i0 | ||
| 482 | mov %i2, %i1 | ||
| 483 | mov %i3, %l7 | ||
| 484 | mov %i4, %l6 | ||
| 485 | 1: ldda [%i1 + 0x00] %asi, %i2 /* %i2/%i3 = src1 + 0x00 */ | ||
| 486 | ldda [%l7 + 0x00] %asi, %i4 /* %i4/%i5 = src2 + 0x00 */ | ||
| 487 | ldda [%l6 + 0x00] %asi, %g2 /* %g2/%g3 = src3 + 0x00 */ | ||
| 488 | ldda [%i0 + 0x00] %asi, %l0 /* %l0/%l1 = dest + 0x00 */ | ||
| 489 | xor %i4, %i2, %i4 | ||
| 490 | xor %i5, %i3, %i5 | ||
| 491 | ldda [%i1 + 0x10] %asi, %i2 /* %i2/%i3 = src1 + 0x10 */ | ||
| 492 | xor %g2, %i4, %g2 | ||
| 493 | xor %g3, %i5, %g3 | ||
| 494 | ldda [%i7 + 0x10] %asi, %i4 /* %i4/%i5 = src2 + 0x10 */ | ||
| 495 | xor %l0, %g2, %l0 | ||
| 496 | xor %l1, %g3, %l1 | ||
| 497 | stxa %l0, [%i0 + 0x00] %asi | ||
| 498 | stxa %l1, [%i0 + 0x08] %asi | ||
| 499 | ldda [%i6 + 0x10] %asi, %g2 /* %g2/%g3 = src3 + 0x10 */ | ||
| 500 | ldda [%i0 + 0x10] %asi, %l0 /* %l0/%l1 = dest + 0x10 */ | ||
| 501 | |||
| 502 | xor %i4, %i2, %i4 | ||
| 503 | xor %i5, %i3, %i5 | ||
| 504 | ldda [%i1 + 0x20] %asi, %i2 /* %i2/%i3 = src1 + 0x20 */ | ||
| 505 | xor %g2, %i4, %g2 | ||
| 506 | xor %g3, %i5, %g3 | ||
| 507 | ldda [%i7 + 0x20] %asi, %i4 /* %i4/%i5 = src2 + 0x20 */ | ||
| 508 | xor %l0, %g2, %l0 | ||
| 509 | xor %l1, %g3, %l1 | ||
| 510 | stxa %l0, [%i0 + 0x10] %asi | ||
| 511 | stxa %l1, [%i0 + 0x18] %asi | ||
| 512 | ldda [%i6 + 0x20] %asi, %g2 /* %g2/%g3 = src3 + 0x20 */ | ||
| 513 | ldda [%i0 + 0x20] %asi, %l0 /* %l0/%l1 = dest + 0x20 */ | ||
| 514 | |||
| 515 | xor %i4, %i2, %i4 | ||
| 516 | xor %i5, %i3, %i5 | ||
| 517 | ldda [%i1 + 0x30] %asi, %i2 /* %i2/%i3 = src1 + 0x30 */ | ||
| 518 | xor %g2, %i4, %g2 | ||
| 519 | xor %g3, %i5, %g3 | ||
| 520 | ldda [%i7 + 0x30] %asi, %i4 /* %i4/%i5 = src2 + 0x30 */ | ||
| 521 | xor %l0, %g2, %l0 | ||
| 522 | xor %l1, %g3, %l1 | ||
| 523 | stxa %l0, [%i0 + 0x20] %asi | ||
| 524 | stxa %l1, [%i0 + 0x28] %asi | ||
| 525 | ldda [%i6 + 0x30] %asi, %g2 /* %g2/%g3 = src3 + 0x30 */ | ||
| 526 | ldda [%i0 + 0x30] %asi, %l0 /* %l0/%l1 = dest + 0x30 */ | ||
| 527 | |||
| 528 | prefetch [%i1 + 0x40], #one_read | ||
| 529 | prefetch [%l7 + 0x40], #one_read | ||
| 530 | prefetch [%l6 + 0x40], #one_read | ||
| 531 | prefetch [%i0 + 0x40], #n_writes | ||
| 532 | |||
| 533 | xor %i4, %i2, %i4 | ||
| 534 | xor %i5, %i3, %i5 | ||
| 535 | xor %g2, %i4, %g2 | ||
| 536 | xor %g3, %i5, %g3 | ||
| 537 | xor %l0, %g2, %l0 | ||
| 538 | xor %l1, %g3, %l1 | ||
| 539 | stxa %l0, [%i0 + 0x30] %asi | ||
| 540 | stxa %l1, [%i0 + 0x38] %asi | ||
| 541 | |||
| 542 | add %i0, 0x40, %i0 | ||
| 543 | add %i1, 0x40, %i1 | ||
| 544 | add %l7, 0x40, %l7 | ||
| 545 | subcc %g1, 1, %g1 | ||
| 546 | bne,pt %xcc, 1b | ||
| 547 | add %l6, 0x40, %l6 | ||
| 548 | membar #Sync | ||
| 549 | wr %g7, 0x0, %asi | ||
| 550 | ret | ||
| 551 | restore | ||
| 552 | .size xor_niagara_4, .-xor_niagara_4 | ||
| 553 | |||
| 554 | .globl xor_niagara_5 | ||
| 555 | .type xor_niagara_5,#function | ||
| 556 | xor_niagara_5: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3, %o5=src4 */ | ||
| 557 | save %sp, -192, %sp | ||
| 558 | prefetch [%i1], #n_writes | ||
| 559 | prefetch [%i2], #one_read | ||
| 560 | prefetch [%i3], #one_read | ||
| 561 | prefetch [%i4], #one_read | ||
| 562 | prefetch [%i5], #one_read | ||
| 563 | rd %asi, %g7 | ||
| 564 | wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi | ||
| 565 | srlx %i0, 6, %g1 | ||
| 566 | mov %i1, %i0 | ||
| 567 | mov %i2, %i1 | ||
| 568 | mov %i3, %l7 | ||
| 569 | mov %i4, %l6 | ||
| 570 | mov %i5, %l5 | ||
| 571 | 1: ldda [%i1 + 0x00] %asi, %i2 /* %i2/%i3 = src1 + 0x00 */ | ||
| 572 | ldda [%l7 + 0x00] %asi, %i4 /* %i4/%i5 = src2 + 0x00 */ | ||
| 573 | ldda [%l6 + 0x00] %asi, %g2 /* %g2/%g3 = src3 + 0x00 */ | ||
| 574 | ldda [%l5 + 0x00] %asi, %l0 /* %l0/%l1 = src4 + 0x00 */ | ||
| 575 | ldda [%i0 + 0x00] %asi, %l2 /* %l2/%l3 = dest + 0x00 */ | ||
| 576 | xor %i4, %i2, %i4 | ||
| 577 | xor %i5, %i3, %i5 | ||
| 578 | ldda [%i1 + 0x10] %asi, %i2 /* %i2/%i3 = src1 + 0x10 */ | ||
| 579 | xor %g2, %i4, %g2 | ||
| 580 | xor %g3, %i5, %g3 | ||
| 581 | ldda [%l7 + 0x10] %asi, %i4 /* %i4/%i5 = src2 + 0x10 */ | ||
| 582 | xor %l0, %g2, %l0 | ||
| 583 | xor %l1, %g3, %l1 | ||
| 584 | ldda [%l6 + 0x10] %asi, %g2 /* %g2/%g3 = src3 + 0x10 */ | ||
| 585 | xor %l2, %l0, %l2 | ||
| 586 | xor %l3, %l1, %l3 | ||
| 587 | stxa %l2, [%i0 + 0x00] %asi | ||
| 588 | stxa %l3, [%i0 + 0x08] %asi | ||
| 589 | ldda [%l5 + 0x10] %asi, %l0 /* %l0/%l1 = src4 + 0x10 */ | ||
| 590 | ldda [%i0 + 0x10] %asi, %l2 /* %l2/%l3 = dest + 0x10 */ | ||
| 591 | |||
| 592 | xor %i4, %i2, %i4 | ||
| 593 | xor %i5, %i3, %i5 | ||
| 594 | ldda [%i1 + 0x20] %asi, %i2 /* %i2/%i3 = src1 + 0x20 */ | ||
| 595 | xor %g2, %i4, %g2 | ||
| 596 | xor %g3, %i5, %g3 | ||
| 597 | ldda [%l7 + 0x20] %asi, %i4 /* %i4/%i5 = src2 + 0x20 */ | ||
| 598 | xor %l0, %g2, %l0 | ||
| 599 | xor %l1, %g3, %l1 | ||
| 600 | ldda [%l6 + 0x20] %asi, %g2 /* %g2/%g3 = src3 + 0x20 */ | ||
| 601 | xor %l2, %l0, %l2 | ||
| 602 | xor %l3, %l1, %l3 | ||
| 603 | stxa %l2, [%i0 + 0x10] %asi | ||
| 604 | stxa %l3, [%i0 + 0x18] %asi | ||
| 605 | ldda [%l5 + 0x20] %asi, %l0 /* %l0/%l1 = src4 + 0x20 */ | ||
| 606 | ldda [%i0 + 0x20] %asi, %l2 /* %l2/%l3 = dest + 0x20 */ | ||
| 607 | |||
| 608 | xor %i4, %i2, %i4 | ||
| 609 | xor %i5, %i3, %i5 | ||
| 610 | ldda [%i1 + 0x30] %asi, %i2 /* %i2/%i3 = src1 + 0x30 */ | ||
| 611 | xor %g2, %i4, %g2 | ||
| 612 | xor %g3, %i5, %g3 | ||
| 613 | ldda [%l7 + 0x30] %asi, %i4 /* %i4/%i5 = src2 + 0x30 */ | ||
| 614 | xor %l0, %g2, %l0 | ||
| 615 | xor %l1, %g3, %l1 | ||
| 616 | ldda [%l6 + 0x30] %asi, %g2 /* %g2/%g3 = src3 + 0x30 */ | ||
| 617 | xor %l2, %l0, %l2 | ||
| 618 | xor %l3, %l1, %l3 | ||
| 619 | stxa %l2, [%i0 + 0x20] %asi | ||
| 620 | stxa %l3, [%i0 + 0x28] %asi | ||
| 621 | ldda [%l5 + 0x30] %asi, %l0 /* %l0/%l1 = src4 + 0x30 */ | ||
| 622 | ldda [%i0 + 0x30] %asi, %l2 /* %l2/%l3 = dest + 0x30 */ | ||
| 623 | |||
| 624 | prefetch [%i1 + 0x40], #one_read | ||
| 625 | prefetch [%l7 + 0x40], #one_read | ||
| 626 | prefetch [%l6 + 0x40], #one_read | ||
| 627 | prefetch [%l5 + 0x40], #one_read | ||
| 628 | prefetch [%i0 + 0x40], #n_writes | ||
| 629 | |||
| 630 | xor %i4, %i2, %i4 | ||
| 631 | xor %i5, %i3, %i5 | ||
| 632 | xor %g2, %i4, %g2 | ||
| 633 | xor %g3, %i5, %g3 | ||
| 634 | xor %l0, %g2, %l0 | ||
| 635 | xor %l1, %g3, %l1 | ||
| 636 | xor %l2, %l0, %l2 | ||
| 637 | xor %l3, %l1, %l3 | ||
| 638 | stxa %l2, [%i0 + 0x30] %asi | ||
| 639 | stxa %l3, [%i0 + 0x38] %asi | ||
| 640 | |||
| 641 | add %i0, 0x40, %i0 | ||
| 642 | add %i1, 0x40, %i1 | ||
| 643 | add %l7, 0x40, %l7 | ||
| 644 | add %l6, 0x40, %l6 | ||
| 645 | subcc %g1, 1, %g1 | ||
| 646 | bne,pt %xcc, 1b | ||
| 647 | add %l5, 0x40, %l5 | ||
| 648 | membar #Sync | ||
| 649 | wr %g7, 0x0, %asi | ||
| 650 | ret | ||
| 651 | restore | ||
| 652 | .size xor_niagara_5, .-xor_niagara_5 | ||
diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c index 2ae05cd7b773..6ee496c2864a 100644 --- a/arch/sparc64/math-emu/math.c +++ b/arch/sparc64/math-emu/math.c | |||
| @@ -206,9 +206,29 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f) | |||
| 206 | case FSTOQ: TYPE(3,3,1,1,1,0,0); break; | 206 | case FSTOQ: TYPE(3,3,1,1,1,0,0); break; |
| 207 | case FDTOQ: TYPE(3,3,1,2,1,0,0); break; | 207 | case FDTOQ: TYPE(3,3,1,2,1,0,0); break; |
| 208 | case FQTOI: TYPE(3,1,0,3,1,0,0); break; | 208 | case FQTOI: TYPE(3,1,0,3,1,0,0); break; |
| 209 | |||
| 210 | /* We can get either unimplemented or unfinished | ||
| 211 | * for these cases. Pre-Niagara systems generate | ||
| 212 | * unfinished fpop for SUBNORMAL cases, and Niagara | ||
| 213 | * always gives unimplemented fpop for fsqrt{s,d}. | ||
| 214 | */ | ||
| 215 | case FSQRTS: { | ||
| 216 | unsigned long x = current_thread_info()->xfsr[0]; | ||
| 217 | |||
| 218 | x = (x >> 14) & 0xf; | ||
| 219 | TYPE(x,1,1,1,1,0,0); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | |||
| 223 | case FSQRTD: { | ||
| 224 | unsigned long x = current_thread_info()->xfsr[0]; | ||
| 225 | |||
| 226 | x = (x >> 14) & 0xf; | ||
| 227 | TYPE(x,2,1,2,1,0,0); | ||
| 228 | break; | ||
| 229 | } | ||
| 230 | |||
| 209 | /* SUBNORMAL - ftt == 2 */ | 231 | /* SUBNORMAL - ftt == 2 */ |
| 210 | case FSQRTS: TYPE(2,1,1,1,1,0,0); break; | ||
| 211 | case FSQRTD: TYPE(2,2,1,2,1,0,0); break; | ||
| 212 | case FADDD: | 232 | case FADDD: |
| 213 | case FSUBD: | 233 | case FSUBD: |
| 214 | case FMULD: | 234 | case FMULD: |
diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile index 9d0960e69f48..e415bf942bcd 100644 --- a/arch/sparc64/mm/Makefile +++ b/arch/sparc64/mm/Makefile | |||
| @@ -5,6 +5,6 @@ | |||
| 5 | EXTRA_AFLAGS := -ansi | 5 | EXTRA_AFLAGS := -ansi |
| 6 | EXTRA_CFLAGS := -Werror | 6 | EXTRA_CFLAGS := -Werror |
| 7 | 7 | ||
| 8 | obj-y := ultra.o tlb.o fault.o init.o generic.o | 8 | obj-y := ultra.o tlb.o tsb.o fault.o init.o generic.o |
| 9 | 9 | ||
| 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 6f0539aa44d0..63b6cc0cd5d5 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <asm/lsu.h> | 29 | #include <asm/lsu.h> |
| 30 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
| 31 | #include <asm/kdebug.h> | 31 | #include <asm/kdebug.h> |
| 32 | #include <asm/mmu_context.h> | ||
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * To debug kernel to catch accesses to certain virtual/physical addresses. | 35 | * To debug kernel to catch accesses to certain virtual/physical addresses. |
| @@ -91,12 +92,13 @@ static void __kprobes unhandled_fault(unsigned long address, | |||
| 91 | die_if_kernel("Oops", regs); | 92 | die_if_kernel("Oops", regs); |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 94 | static void bad_kernel_pc(struct pt_regs *regs) | 95 | static void bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) |
| 95 | { | 96 | { |
| 96 | unsigned long *ksp; | 97 | unsigned long *ksp; |
| 97 | 98 | ||
| 98 | printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", | 99 | printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", |
| 99 | regs->tpc); | 100 | regs->tpc); |
| 101 | printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); | ||
| 100 | __asm__("mov %%sp, %0" : "=r" (ksp)); | 102 | __asm__("mov %%sp, %0" : "=r" (ksp)); |
| 101 | show_stack(current, ksp); | 103 | show_stack(current, ksp); |
| 102 | unhandled_fault(regs->tpc, current, regs); | 104 | unhandled_fault(regs->tpc, current, regs); |
| @@ -137,7 +139,7 @@ static unsigned int get_user_insn(unsigned long tpc) | |||
| 137 | if (!pte_present(pte)) | 139 | if (!pte_present(pte)) |
| 138 | goto out; | 140 | goto out; |
| 139 | 141 | ||
| 140 | pa = (pte_val(pte) & _PAGE_PADDR); | 142 | pa = (pte_pfn(pte) << PAGE_SHIFT); |
| 141 | pa += (tpc & ~PAGE_MASK); | 143 | pa += (tpc & ~PAGE_MASK); |
| 142 | 144 | ||
| 143 | /* Use phys bypass so we don't pollute dtlb/dcache. */ | 145 | /* Use phys bypass so we don't pollute dtlb/dcache. */ |
| @@ -257,7 +259,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | |||
| 257 | struct vm_area_struct *vma; | 259 | struct vm_area_struct *vma; |
| 258 | unsigned int insn = 0; | 260 | unsigned int insn = 0; |
| 259 | int si_code, fault_code; | 261 | int si_code, fault_code; |
| 260 | unsigned long address; | 262 | unsigned long address, mm_rss; |
| 261 | 263 | ||
| 262 | fault_code = get_thread_fault_code(); | 264 | fault_code = get_thread_fault_code(); |
| 263 | 265 | ||
| @@ -280,7 +282,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | |||
| 280 | (tpc >= MODULES_VADDR && tpc < MODULES_END)) { | 282 | (tpc >= MODULES_VADDR && tpc < MODULES_END)) { |
| 281 | /* Valid, no problems... */ | 283 | /* Valid, no problems... */ |
| 282 | } else { | 284 | } else { |
| 283 | bad_kernel_pc(regs); | 285 | bad_kernel_pc(regs, address); |
| 284 | return; | 286 | return; |
| 285 | } | 287 | } |
| 286 | } | 288 | } |
| @@ -406,6 +408,11 @@ good_area: | |||
| 406 | } | 408 | } |
| 407 | 409 | ||
| 408 | up_read(&mm->mmap_sem); | 410 | up_read(&mm->mmap_sem); |
| 411 | |||
| 412 | mm_rss = get_mm_rss(mm); | ||
| 413 | if (unlikely(mm_rss >= mm->context.tsb_rss_limit)) | ||
| 414 | tsb_grow(mm, mm_rss); | ||
| 415 | |||
| 409 | return; | 416 | return; |
| 410 | 417 | ||
| 411 | /* | 418 | /* |
diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c index 580b63da836b..5fc5c579e35e 100644 --- a/arch/sparc64/mm/generic.c +++ b/arch/sparc64/mm/generic.c | |||
| @@ -15,15 +15,6 @@ | |||
| 15 | #include <asm/page.h> | 15 | #include <asm/page.h> |
| 16 | #include <asm/tlbflush.h> | 16 | #include <asm/tlbflush.h> |
| 17 | 17 | ||
| 18 | static inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space) | ||
| 19 | { | ||
| 20 | pte_t pte; | ||
| 21 | pte_val(pte) = (((page) | pgprot_val(prot) | _PAGE_E) & | ||
| 22 | ~(unsigned long)_PAGE_CACHE); | ||
| 23 | pte_val(pte) |= (((unsigned long)space) << 32); | ||
| 24 | return pte; | ||
| 25 | } | ||
| 26 | |||
| 27 | /* Remap IO memory, the same way as remap_pfn_range(), but use | 18 | /* Remap IO memory, the same way as remap_pfn_range(), but use |
| 28 | * the obio memory space. | 19 | * the obio memory space. |
| 29 | * | 20 | * |
| @@ -48,24 +39,29 @@ static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, | |||
| 48 | pte_t entry; | 39 | pte_t entry; |
| 49 | unsigned long curend = address + PAGE_SIZE; | 40 | unsigned long curend = address + PAGE_SIZE; |
| 50 | 41 | ||
| 51 | entry = mk_pte_io(offset, prot, space); | 42 | entry = mk_pte_io(offset, prot, space, PAGE_SIZE); |
| 52 | if (!(address & 0xffff)) { | 43 | if (!(address & 0xffff)) { |
| 53 | if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) { | 44 | if (PAGE_SIZE < (4 * 1024 * 1024) && |
| 54 | entry = mk_pte_io(offset, | 45 | !(address & 0x3fffff) && |
| 55 | __pgprot(pgprot_val (prot) | _PAGE_SZ4MB), | 46 | !(offset & 0x3ffffe) && |
| 56 | space); | 47 | end >= address + 0x400000) { |
| 48 | entry = mk_pte_io(offset, prot, space, | ||
| 49 | 4 * 1024 * 1024); | ||
| 57 | curend = address + 0x400000; | 50 | curend = address + 0x400000; |
| 58 | offset += 0x400000; | 51 | offset += 0x400000; |
| 59 | } else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) { | 52 | } else if (PAGE_SIZE < (512 * 1024) && |
| 60 | entry = mk_pte_io(offset, | 53 | !(address & 0x7ffff) && |
| 61 | __pgprot(pgprot_val (prot) | _PAGE_SZ512K), | 54 | !(offset & 0x7fffe) && |
| 62 | space); | 55 | end >= address + 0x80000) { |
| 56 | entry = mk_pte_io(offset, prot, space, | ||
| 57 | 512 * 1024 * 1024); | ||
| 63 | curend = address + 0x80000; | 58 | curend = address + 0x80000; |
| 64 | offset += 0x80000; | 59 | offset += 0x80000; |
| 65 | } else if (!(offset & 0xfffe) && end >= address + 0x10000) { | 60 | } else if (PAGE_SIZE < (64 * 1024) && |
| 66 | entry = mk_pte_io(offset, | 61 | !(offset & 0xfffe) && |
| 67 | __pgprot(pgprot_val (prot) | _PAGE_SZ64K), | 62 | end >= address + 0x10000) { |
| 68 | space); | 63 | entry = mk_pte_io(offset, prot, space, |
| 64 | 64 * 1024); | ||
| 69 | curend = address + 0x10000; | 65 | curend = address + 0x10000; |
| 70 | offset += 0x10000; | 66 | offset += 0x10000; |
| 71 | } else | 67 | } else |
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 625cbb336a23..a7a24869d045 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * SPARC64 Huge TLB page support. | 2 | * SPARC64 Huge TLB page support. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2002, 2003 David S. Miller (davem@redhat.com) | 4 | * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net) |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <linux/config.h> | 7 | #include <linux/config.h> |
| @@ -22,6 +22,175 @@ | |||
| 22 | #include <asm/cacheflush.h> | 22 | #include <asm/cacheflush.h> |
| 23 | #include <asm/mmu_context.h> | 23 | #include <asm/mmu_context.h> |
| 24 | 24 | ||
| 25 | /* Slightly simplified from the non-hugepage variant because by | ||
| 26 | * definition we don't have to worry about any page coloring stuff | ||
| 27 | */ | ||
| 28 | #define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL)) | ||
| 29 | #define VA_EXCLUDE_END (0xfffff80000000000UL + (1UL << 32UL)) | ||
| 30 | |||
| 31 | static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp, | ||
| 32 | unsigned long addr, | ||
| 33 | unsigned long len, | ||
| 34 | unsigned long pgoff, | ||
| 35 | unsigned long flags) | ||
| 36 | { | ||
| 37 | struct mm_struct *mm = current->mm; | ||
| 38 | struct vm_area_struct * vma; | ||
| 39 | unsigned long task_size = TASK_SIZE; | ||
| 40 | unsigned long start_addr; | ||
| 41 | |||
| 42 | if (test_thread_flag(TIF_32BIT)) | ||
| 43 | task_size = STACK_TOP32; | ||
| 44 | if (unlikely(len >= VA_EXCLUDE_START)) | ||
| 45 | return -ENOMEM; | ||
| 46 | |||
| 47 | if (len > mm->cached_hole_size) { | ||
| 48 | start_addr = addr = mm->free_area_cache; | ||
| 49 | } else { | ||
| 50 | start_addr = addr = TASK_UNMAPPED_BASE; | ||
| 51 | mm->cached_hole_size = 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | task_size -= len; | ||
| 55 | |||
| 56 | full_search: | ||
| 57 | addr = ALIGN(addr, HPAGE_SIZE); | ||
| 58 | |||
| 59 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | ||
| 60 | /* At this point: (!vma || addr < vma->vm_end). */ | ||
| 61 | if (addr < VA_EXCLUDE_START && | ||
| 62 | (addr + len) >= VA_EXCLUDE_START) { | ||
| 63 | addr = VA_EXCLUDE_END; | ||
| 64 | vma = find_vma(mm, VA_EXCLUDE_END); | ||
| 65 | } | ||
| 66 | if (unlikely(task_size < addr)) { | ||
| 67 | if (start_addr != TASK_UNMAPPED_BASE) { | ||
| 68 | start_addr = addr = TASK_UNMAPPED_BASE; | ||
| 69 | mm->cached_hole_size = 0; | ||
| 70 | goto full_search; | ||
| 71 | } | ||
| 72 | return -ENOMEM; | ||
| 73 | } | ||
| 74 | if (likely(!vma || addr + len <= vma->vm_start)) { | ||
| 75 | /* | ||
| 76 | * Remember the place where we stopped the search: | ||
| 77 | */ | ||
| 78 | mm->free_area_cache = addr + len; | ||
| 79 | return addr; | ||
| 80 | } | ||
| 81 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
| 82 | mm->cached_hole_size = vma->vm_start - addr; | ||
| 83 | |||
| 84 | addr = ALIGN(vma->vm_end, HPAGE_SIZE); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | static unsigned long | ||
| 89 | hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | ||
| 90 | const unsigned long len, | ||
| 91 | const unsigned long pgoff, | ||
| 92 | const unsigned long flags) | ||
| 93 | { | ||
| 94 | struct vm_area_struct *vma; | ||
| 95 | struct mm_struct *mm = current->mm; | ||
| 96 | unsigned long addr = addr0; | ||
| 97 | |||
| 98 | /* This should only ever run for 32-bit processes. */ | ||
| 99 | BUG_ON(!test_thread_flag(TIF_32BIT)); | ||
| 100 | |||
| 101 | /* check if free_area_cache is useful for us */ | ||
| 102 | if (len <= mm->cached_hole_size) { | ||
| 103 | mm->cached_hole_size = 0; | ||
| 104 | mm->free_area_cache = mm->mmap_base; | ||
| 105 | } | ||
| 106 | |||
| 107 | /* either no address requested or can't fit in requested address hole */ | ||
| 108 | addr = mm->free_area_cache & HPAGE_MASK; | ||
| 109 | |||
| 110 | /* make sure it can fit in the remaining address space */ | ||
| 111 | if (likely(addr > len)) { | ||
| 112 | vma = find_vma(mm, addr-len); | ||
| 113 | if (!vma || addr <= vma->vm_start) { | ||
| 114 | /* remember the address as a hint for next time */ | ||
| 115 | return (mm->free_area_cache = addr-len); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | if (unlikely(mm->mmap_base < len)) | ||
| 120 | goto bottomup; | ||
| 121 | |||
| 122 | addr = (mm->mmap_base-len) & HPAGE_MASK; | ||
| 123 | |||
| 124 | do { | ||
| 125 | /* | ||
| 126 | * Lookup failure means no vma is above this address, | ||
| 127 | * else if new region fits below vma->vm_start, | ||
| 128 | * return with success: | ||
| 129 | */ | ||
| 130 | vma = find_vma(mm, addr); | ||
| 131 | if (likely(!vma || addr+len <= vma->vm_start)) { | ||
| 132 | /* remember the address as a hint for next time */ | ||
| 133 | return (mm->free_area_cache = addr); | ||
| 134 | } | ||
| 135 | |||
| 136 | /* remember the largest hole we saw so far */ | ||
| 137 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
| 138 | mm->cached_hole_size = vma->vm_start - addr; | ||
| 139 | |||
| 140 | /* try just below the current vma->vm_start */ | ||
| 141 | addr = (vma->vm_start-len) & HPAGE_MASK; | ||
| 142 | } while (likely(len < vma->vm_start)); | ||
| 143 | |||
| 144 | bottomup: | ||
| 145 | /* | ||
| 146 | * A failed mmap() very likely causes application failure, | ||
| 147 | * so fall back to the bottom-up function here. This scenario | ||
| 148 | * can happen with large stack limits and large mmap() | ||
| 149 | * allocations. | ||
| 150 | */ | ||
| 151 | mm->cached_hole_size = ~0UL; | ||
| 152 | mm->free_area_cache = TASK_UNMAPPED_BASE; | ||
| 153 | addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); | ||
| 154 | /* | ||
| 155 | * Restore the topdown base: | ||
| 156 | */ | ||
| 157 | mm->free_area_cache = mm->mmap_base; | ||
| 158 | mm->cached_hole_size = ~0UL; | ||
| 159 | |||
| 160 | return addr; | ||
| 161 | } | ||
| 162 | |||
| 163 | unsigned long | ||
| 164 | hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | ||
| 165 | unsigned long len, unsigned long pgoff, unsigned long flags) | ||
| 166 | { | ||
| 167 | struct mm_struct *mm = current->mm; | ||
| 168 | struct vm_area_struct *vma; | ||
| 169 | unsigned long task_size = TASK_SIZE; | ||
| 170 | |||
| 171 | if (test_thread_flag(TIF_32BIT)) | ||
| 172 | task_size = STACK_TOP32; | ||
| 173 | |||
| 174 | if (len & ~HPAGE_MASK) | ||
| 175 | return -EINVAL; | ||
| 176 | if (len > task_size) | ||
| 177 | return -ENOMEM; | ||
| 178 | |||
| 179 | if (addr) { | ||
| 180 | addr = ALIGN(addr, HPAGE_SIZE); | ||
| 181 | vma = find_vma(mm, addr); | ||
| 182 | if (task_size - len >= addr && | ||
| 183 | (!vma || addr + len <= vma->vm_start)) | ||
| 184 | return addr; | ||
| 185 | } | ||
| 186 | if (mm->get_unmapped_area == arch_get_unmapped_area) | ||
| 187 | return hugetlb_get_unmapped_area_bottomup(file, addr, len, | ||
| 188 | pgoff, flags); | ||
| 189 | else | ||
| 190 | return hugetlb_get_unmapped_area_topdown(file, addr, len, | ||
| 191 | pgoff, flags); | ||
| 192 | } | ||
| 193 | |||
| 25 | pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) | 194 | pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) |
| 26 | { | 195 | { |
| 27 | pgd_t *pgd; | 196 | pgd_t *pgd; |
| @@ -48,12 +217,14 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | |||
| 48 | pmd_t *pmd; | 217 | pmd_t *pmd; |
| 49 | pte_t *pte = NULL; | 218 | pte_t *pte = NULL; |
| 50 | 219 | ||
| 220 | addr &= HPAGE_MASK; | ||
| 221 | |||
| 51 | pgd = pgd_offset(mm, addr); | 222 | pgd = pgd_offset(mm, addr); |
| 52 | if (pgd) { | 223 | if (!pgd_none(*pgd)) { |
| 53 | pud = pud_offset(pgd, addr); | 224 | pud = pud_offset(pgd, addr); |
| 54 | if (pud) { | 225 | if (!pud_none(*pud)) { |
| 55 | pmd = pmd_offset(pud, addr); | 226 | pmd = pmd_offset(pud, addr); |
| 56 | if (pmd) | 227 | if (!pmd_none(*pmd)) |
| 57 | pte = pte_offset_map(pmd, addr); | 228 | pte = pte_offset_map(pmd, addr); |
| 58 | } | 229 | } |
| 59 | } | 230 | } |
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 1e44ee26cee8..c2b556106fc1 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
| 9 | #include <linux/module.h> | ||
| 9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 10 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
| 11 | #include <linux/string.h> | 12 | #include <linux/string.h> |
| @@ -39,9 +40,27 @@ | |||
| 39 | #include <asm/tlb.h> | 40 | #include <asm/tlb.h> |
| 40 | #include <asm/spitfire.h> | 41 | #include <asm/spitfire.h> |
| 41 | #include <asm/sections.h> | 42 | #include <asm/sections.h> |
| 43 | #include <asm/tsb.h> | ||
| 44 | #include <asm/hypervisor.h> | ||
| 42 | 45 | ||
| 43 | extern void device_scan(void); | 46 | extern void device_scan(void); |
| 44 | 47 | ||
| 48 | #define MAX_PHYS_ADDRESS (1UL << 42UL) | ||
| 49 | #define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) | ||
| 50 | #define KPTE_BITMAP_BYTES \ | ||
| 51 | ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8) | ||
| 52 | |||
| 53 | unsigned long kern_linear_pte_xor[2] __read_mostly; | ||
| 54 | |||
| 55 | /* A bitmap, one bit for every 256MB of physical memory. If the bit | ||
| 56 | * is clear, we should use a 4MB page (via kern_linear_pte_xor[0]) else | ||
| 57 | * if set we should use a 256MB page (via kern_linear_pte_xor[1]). | ||
| 58 | */ | ||
| 59 | unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)]; | ||
| 60 | |||
| 61 | /* A special kernel TSB for 4MB and 256MB linear mappings. */ | ||
| 62 | struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; | ||
| 63 | |||
| 45 | #define MAX_BANKS 32 | 64 | #define MAX_BANKS 32 |
| 46 | 65 | ||
| 47 | static struct linux_prom64_registers pavail[MAX_BANKS] __initdata; | 66 | static struct linux_prom64_registers pavail[MAX_BANKS] __initdata; |
| @@ -111,11 +130,9 @@ static void __init read_obp_memory(const char *property, | |||
| 111 | 130 | ||
| 112 | unsigned long *sparc64_valid_addr_bitmap __read_mostly; | 131 | unsigned long *sparc64_valid_addr_bitmap __read_mostly; |
| 113 | 132 | ||
| 114 | /* Ugly, but necessary... -DaveM */ | 133 | /* Kernel physical address base and size in bytes. */ |
| 115 | unsigned long phys_base __read_mostly; | ||
| 116 | unsigned long kern_base __read_mostly; | 134 | unsigned long kern_base __read_mostly; |
| 117 | unsigned long kern_size __read_mostly; | 135 | unsigned long kern_size __read_mostly; |
| 118 | unsigned long pfn_base __read_mostly; | ||
| 119 | 136 | ||
| 120 | /* get_new_mmu_context() uses "cache + 1". */ | 137 | /* get_new_mmu_context() uses "cache + 1". */ |
| 121 | DEFINE_SPINLOCK(ctx_alloc_lock); | 138 | DEFINE_SPINLOCK(ctx_alloc_lock); |
| @@ -141,24 +158,28 @@ unsigned long sparc64_kern_sec_context __read_mostly; | |||
| 141 | 158 | ||
| 142 | int bigkernel = 0; | 159 | int bigkernel = 0; |
| 143 | 160 | ||
| 144 | /* XXX Tune this... */ | 161 | kmem_cache_t *pgtable_cache __read_mostly; |
| 145 | #define PGT_CACHE_LOW 25 | 162 | |
| 146 | #define PGT_CACHE_HIGH 50 | 163 | static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) |
| 164 | { | ||
| 165 | clear_page(addr); | ||
| 166 | } | ||
| 167 | |||
| 168 | extern void tsb_cache_init(void); | ||
| 147 | 169 | ||
| 148 | void check_pgt_cache(void) | 170 | void pgtable_cache_init(void) |
| 149 | { | 171 | { |
| 150 | preempt_disable(); | 172 | pgtable_cache = kmem_cache_create("pgtable_cache", |
| 151 | if (pgtable_cache_size > PGT_CACHE_HIGH) { | 173 | PAGE_SIZE, PAGE_SIZE, |
| 152 | do { | 174 | SLAB_HWCACHE_ALIGN | |
| 153 | if (pgd_quicklist) | 175 | SLAB_MUST_HWCACHE_ALIGN, |
| 154 | free_pgd_slow(get_pgd_fast()); | 176 | zero_ctor, |
| 155 | if (pte_quicklist[0]) | 177 | NULL); |
| 156 | free_pte_slow(pte_alloc_one_fast(NULL, 0)); | 178 | if (!pgtable_cache) { |
| 157 | if (pte_quicklist[1]) | 179 | prom_printf("Could not create pgtable_cache\n"); |
| 158 | free_pte_slow(pte_alloc_one_fast(NULL, 1 << (PAGE_SHIFT + 10))); | 180 | prom_halt(); |
| 159 | } while (pgtable_cache_size > PGT_CACHE_LOW); | ||
| 160 | } | 181 | } |
| 161 | preempt_enable(); | 182 | tsb_cache_init(); |
| 162 | } | 183 | } |
| 163 | 184 | ||
| 164 | #ifdef CONFIG_DEBUG_DCFLUSH | 185 | #ifdef CONFIG_DEBUG_DCFLUSH |
| @@ -168,8 +189,9 @@ atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0); | |||
| 168 | #endif | 189 | #endif |
| 169 | #endif | 190 | #endif |
| 170 | 191 | ||
| 171 | __inline__ void flush_dcache_page_impl(struct page *page) | 192 | inline void flush_dcache_page_impl(struct page *page) |
| 172 | { | 193 | { |
| 194 | BUG_ON(tlb_type == hypervisor); | ||
| 173 | #ifdef CONFIG_DEBUG_DCFLUSH | 195 | #ifdef CONFIG_DEBUG_DCFLUSH |
| 174 | atomic_inc(&dcpage_flushes); | 196 | atomic_inc(&dcpage_flushes); |
| 175 | #endif | 197 | #endif |
| @@ -186,8 +208,8 @@ __inline__ void flush_dcache_page_impl(struct page *page) | |||
| 186 | } | 208 | } |
| 187 | 209 | ||
| 188 | #define PG_dcache_dirty PG_arch_1 | 210 | #define PG_dcache_dirty PG_arch_1 |
| 189 | #define PG_dcache_cpu_shift 24 | 211 | #define PG_dcache_cpu_shift 24UL |
| 190 | #define PG_dcache_cpu_mask (256 - 1) | 212 | #define PG_dcache_cpu_mask (256UL - 1UL) |
| 191 | 213 | ||
| 192 | #if NR_CPUS > 256 | 214 | #if NR_CPUS > 256 |
| 193 | #error D-cache dirty tracking and thread_info->cpu need fixing for > 256 cpus | 215 | #error D-cache dirty tracking and thread_info->cpu need fixing for > 256 cpus |
| @@ -243,32 +265,61 @@ static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long c | |||
| 243 | : "g1", "g7"); | 265 | : "g1", "g7"); |
| 244 | } | 266 | } |
| 245 | 267 | ||
| 268 | static inline void tsb_insert(struct tsb *ent, unsigned long tag, unsigned long pte) | ||
| 269 | { | ||
| 270 | unsigned long tsb_addr = (unsigned long) ent; | ||
| 271 | |||
| 272 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) | ||
| 273 | tsb_addr = __pa(tsb_addr); | ||
| 274 | |||
| 275 | __tsb_insert(tsb_addr, tag, pte); | ||
| 276 | } | ||
| 277 | |||
| 278 | unsigned long _PAGE_ALL_SZ_BITS __read_mostly; | ||
| 279 | unsigned long _PAGE_SZBITS __read_mostly; | ||
| 280 | |||
| 246 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) | 281 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) |
| 247 | { | 282 | { |
| 248 | struct page *page; | 283 | struct mm_struct *mm; |
| 249 | unsigned long pfn; | 284 | struct tsb *tsb; |
| 250 | unsigned long pg_flags; | 285 | unsigned long tag, flags; |
| 251 | 286 | ||
| 252 | pfn = pte_pfn(pte); | 287 | if (tlb_type != hypervisor) { |
| 253 | if (pfn_valid(pfn) && | 288 | unsigned long pfn = pte_pfn(pte); |
| 254 | (page = pfn_to_page(pfn), page_mapping(page)) && | 289 | unsigned long pg_flags; |
| 255 | ((pg_flags = page->flags) & (1UL << PG_dcache_dirty))) { | 290 | struct page *page; |
| 256 | int cpu = ((pg_flags >> PG_dcache_cpu_shift) & | 291 | |
| 257 | PG_dcache_cpu_mask); | 292 | if (pfn_valid(pfn) && |
| 258 | int this_cpu = get_cpu(); | 293 | (page = pfn_to_page(pfn), page_mapping(page)) && |
| 259 | 294 | ((pg_flags = page->flags) & (1UL << PG_dcache_dirty))) { | |
| 260 | /* This is just to optimize away some function calls | 295 | int cpu = ((pg_flags >> PG_dcache_cpu_shift) & |
| 261 | * in the SMP case. | 296 | PG_dcache_cpu_mask); |
| 262 | */ | 297 | int this_cpu = get_cpu(); |
| 263 | if (cpu == this_cpu) | 298 | |
| 264 | flush_dcache_page_impl(page); | 299 | /* This is just to optimize away some function calls |
| 265 | else | 300 | * in the SMP case. |
| 266 | smp_flush_dcache_page_impl(page, cpu); | 301 | */ |
| 302 | if (cpu == this_cpu) | ||
| 303 | flush_dcache_page_impl(page); | ||
| 304 | else | ||
| 305 | smp_flush_dcache_page_impl(page, cpu); | ||
| 267 | 306 | ||
| 268 | clear_dcache_dirty_cpu(page, cpu); | 307 | clear_dcache_dirty_cpu(page, cpu); |
| 269 | 308 | ||
| 270 | put_cpu(); | 309 | put_cpu(); |
| 310 | } | ||
| 271 | } | 311 | } |
| 312 | |||
| 313 | mm = vma->vm_mm; | ||
| 314 | |||
| 315 | spin_lock_irqsave(&mm->context.lock, flags); | ||
| 316 | |||
| 317 | tsb = &mm->context.tsb[(address >> PAGE_SHIFT) & | ||
| 318 | (mm->context.tsb_nentries - 1UL)]; | ||
| 319 | tag = (address >> 22UL); | ||
| 320 | tsb_insert(tsb, tag, pte_val(pte)); | ||
| 321 | |||
| 322 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 272 | } | 323 | } |
| 273 | 324 | ||
| 274 | void flush_dcache_page(struct page *page) | 325 | void flush_dcache_page(struct page *page) |
| @@ -276,6 +327,9 @@ void flush_dcache_page(struct page *page) | |||
| 276 | struct address_space *mapping; | 327 | struct address_space *mapping; |
| 277 | int this_cpu; | 328 | int this_cpu; |
| 278 | 329 | ||
| 330 | if (tlb_type == hypervisor) | ||
| 331 | return; | ||
| 332 | |||
| 279 | /* Do not bother with the expensive D-cache flush if it | 333 | /* Do not bother with the expensive D-cache flush if it |
| 280 | * is merely the zero page. The 'bigcore' testcase in GDB | 334 | * is merely the zero page. The 'bigcore' testcase in GDB |
| 281 | * causes this case to run millions of times. | 335 | * causes this case to run millions of times. |
| @@ -311,7 +365,7 @@ out: | |||
| 311 | 365 | ||
| 312 | void __kprobes flush_icache_range(unsigned long start, unsigned long end) | 366 | void __kprobes flush_icache_range(unsigned long start, unsigned long end) |
| 313 | { | 367 | { |
| 314 | /* Cheetah has coherent I-cache. */ | 368 | /* Cheetah and Hypervisor platform cpus have coherent I-cache. */ |
| 315 | if (tlb_type == spitfire) { | 369 | if (tlb_type == spitfire) { |
| 316 | unsigned long kaddr; | 370 | unsigned long kaddr; |
| 317 | 371 | ||
| @@ -320,16 +374,6 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end) | |||
| 320 | } | 374 | } |
| 321 | } | 375 | } |
| 322 | 376 | ||
| 323 | unsigned long page_to_pfn(struct page *page) | ||
| 324 | { | ||
| 325 | return (unsigned long) ((page - mem_map) + pfn_base); | ||
| 326 | } | ||
| 327 | |||
| 328 | struct page *pfn_to_page(unsigned long pfn) | ||
| 329 | { | ||
| 330 | return (mem_map + (pfn - pfn_base)); | ||
| 331 | } | ||
| 332 | |||
| 333 | void show_mem(void) | 377 | void show_mem(void) |
| 334 | { | 378 | { |
| 335 | printk("Mem-info:\n"); | 379 | printk("Mem-info:\n"); |
| @@ -338,7 +382,6 @@ void show_mem(void) | |||
| 338 | nr_swap_pages << (PAGE_SHIFT-10)); | 382 | nr_swap_pages << (PAGE_SHIFT-10)); |
| 339 | printk("%ld pages of RAM\n", num_physpages); | 383 | printk("%ld pages of RAM\n", num_physpages); |
| 340 | printk("%d free pages\n", nr_free_pages()); | 384 | printk("%d free pages\n", nr_free_pages()); |
| 341 | printk("%d pages in page table cache\n",pgtable_cache_size); | ||
| 342 | } | 385 | } |
| 343 | 386 | ||
| 344 | void mmu_info(struct seq_file *m) | 387 | void mmu_info(struct seq_file *m) |
| @@ -349,6 +392,8 @@ void mmu_info(struct seq_file *m) | |||
| 349 | seq_printf(m, "MMU Type\t: Cheetah+\n"); | 392 | seq_printf(m, "MMU Type\t: Cheetah+\n"); |
| 350 | else if (tlb_type == spitfire) | 393 | else if (tlb_type == spitfire) |
| 351 | seq_printf(m, "MMU Type\t: Spitfire\n"); | 394 | seq_printf(m, "MMU Type\t: Spitfire\n"); |
| 395 | else if (tlb_type == hypervisor) | ||
| 396 | seq_printf(m, "MMU Type\t: Hypervisor (sun4v)\n"); | ||
| 352 | else | 397 | else |
| 353 | seq_printf(m, "MMU Type\t: ???\n"); | 398 | seq_printf(m, "MMU Type\t: ???\n"); |
| 354 | 399 | ||
| @@ -371,45 +416,13 @@ struct linux_prom_translation { | |||
| 371 | /* Exported for kernel TLB miss handling in ktlb.S */ | 416 | /* Exported for kernel TLB miss handling in ktlb.S */ |
| 372 | struct linux_prom_translation prom_trans[512] __read_mostly; | 417 | struct linux_prom_translation prom_trans[512] __read_mostly; |
| 373 | unsigned int prom_trans_ents __read_mostly; | 418 | unsigned int prom_trans_ents __read_mostly; |
| 374 | unsigned int swapper_pgd_zero __read_mostly; | ||
| 375 | |||
| 376 | extern unsigned long prom_boot_page; | ||
| 377 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); | ||
| 378 | extern int prom_get_mmu_ihandle(void); | ||
| 379 | extern void register_prom_callbacks(void); | ||
| 380 | 419 | ||
| 381 | /* Exported for SMP bootup purposes. */ | 420 | /* Exported for SMP bootup purposes. */ |
| 382 | unsigned long kern_locked_tte_data; | 421 | unsigned long kern_locked_tte_data; |
| 383 | 422 | ||
| 384 | /* | ||
| 385 | * Translate PROM's mapping we capture at boot time into physical address. | ||
| 386 | * The second parameter is only set from prom_callback() invocations. | ||
| 387 | */ | ||
| 388 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) | ||
| 389 | { | ||
| 390 | int i; | ||
| 391 | |||
| 392 | for (i = 0; i < prom_trans_ents; i++) { | ||
| 393 | struct linux_prom_translation *p = &prom_trans[i]; | ||
| 394 | |||
| 395 | if (promva >= p->virt && | ||
| 396 | promva < (p->virt + p->size)) { | ||
| 397 | unsigned long base = p->data & _PAGE_PADDR; | ||
| 398 | |||
| 399 | if (error) | ||
| 400 | *error = 0; | ||
| 401 | return base + (promva & (8192 - 1)); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | if (error) | ||
| 405 | *error = 1; | ||
| 406 | return 0UL; | ||
| 407 | } | ||
| 408 | |||
| 409 | /* The obp translations are saved based on 8k pagesize, since obp can | 423 | /* The obp translations are saved based on 8k pagesize, since obp can |
| 410 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> | 424 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> |
| 411 | * HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte | 425 | * HI_OBP_ADDRESS range are handled in ktlb.S. |
| 412 | * scheme (also, see rant in inherit_locked_prom_mappings()). | ||
| 413 | */ | 426 | */ |
| 414 | static inline int in_obp_range(unsigned long vaddr) | 427 | static inline int in_obp_range(unsigned long vaddr) |
| 415 | { | 428 | { |
| @@ -490,6 +503,36 @@ static void __init read_obp_translations(void) | |||
| 490 | } | 503 | } |
| 491 | } | 504 | } |
| 492 | 505 | ||
| 506 | static void __init hypervisor_tlb_lock(unsigned long vaddr, | ||
| 507 | unsigned long pte, | ||
| 508 | unsigned long mmu) | ||
| 509 | { | ||
| 510 | register unsigned long func asm("%o5"); | ||
| 511 | register unsigned long arg0 asm("%o0"); | ||
| 512 | register unsigned long arg1 asm("%o1"); | ||
| 513 | register unsigned long arg2 asm("%o2"); | ||
| 514 | register unsigned long arg3 asm("%o3"); | ||
| 515 | |||
| 516 | func = HV_FAST_MMU_MAP_PERM_ADDR; | ||
| 517 | arg0 = vaddr; | ||
| 518 | arg1 = 0; | ||
| 519 | arg2 = pte; | ||
| 520 | arg3 = mmu; | ||
| 521 | __asm__ __volatile__("ta 0x80" | ||
| 522 | : "=&r" (func), "=&r" (arg0), | ||
| 523 | "=&r" (arg1), "=&r" (arg2), | ||
| 524 | "=&r" (arg3) | ||
| 525 | : "0" (func), "1" (arg0), "2" (arg1), | ||
| 526 | "3" (arg2), "4" (arg3)); | ||
| 527 | if (arg0 != 0) { | ||
| 528 | prom_printf("hypervisor_tlb_lock[%lx:%lx:%lx:%lx]: " | ||
| 529 | "errors with %lx\n", vaddr, 0, pte, mmu, arg0); | ||
| 530 | prom_halt(); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | static unsigned long kern_large_tte(unsigned long paddr); | ||
| 535 | |||
| 493 | static void __init remap_kernel(void) | 536 | static void __init remap_kernel(void) |
| 494 | { | 537 | { |
| 495 | unsigned long phys_page, tte_vaddr, tte_data; | 538 | unsigned long phys_page, tte_vaddr, tte_data; |
| @@ -497,25 +540,34 @@ static void __init remap_kernel(void) | |||
| 497 | 540 | ||
| 498 | tte_vaddr = (unsigned long) KERNBASE; | 541 | tte_vaddr = (unsigned long) KERNBASE; |
| 499 | phys_page = (prom_boot_mapping_phys_low >> 22UL) << 22UL; | 542 | phys_page = (prom_boot_mapping_phys_low >> 22UL) << 22UL; |
| 500 | tte_data = (phys_page | (_PAGE_VALID | _PAGE_SZ4MB | | 543 | tte_data = kern_large_tte(phys_page); |
| 501 | _PAGE_CP | _PAGE_CV | _PAGE_P | | ||
| 502 | _PAGE_L | _PAGE_W)); | ||
| 503 | 544 | ||
| 504 | kern_locked_tte_data = tte_data; | 545 | kern_locked_tte_data = tte_data; |
| 505 | 546 | ||
| 506 | /* Now lock us into the TLBs via OBP. */ | 547 | /* Now lock us into the TLBs via Hypervisor or OBP. */ |
| 507 | prom_dtlb_load(tlb_ent, tte_data, tte_vaddr); | 548 | if (tlb_type == hypervisor) { |
| 508 | prom_itlb_load(tlb_ent, tte_data, tte_vaddr); | 549 | hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_DMMU); |
| 509 | if (bigkernel) { | 550 | hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_IMMU); |
| 510 | tlb_ent -= 1; | 551 | if (bigkernel) { |
| 511 | prom_dtlb_load(tlb_ent, | 552 | tte_vaddr += 0x400000; |
| 512 | tte_data + 0x400000, | 553 | tte_data += 0x400000; |
| 513 | tte_vaddr + 0x400000); | 554 | hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_DMMU); |
| 514 | prom_itlb_load(tlb_ent, | 555 | hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_IMMU); |
| 515 | tte_data + 0x400000, | 556 | } |
| 516 | tte_vaddr + 0x400000); | 557 | } else { |
| 558 | prom_dtlb_load(tlb_ent, tte_data, tte_vaddr); | ||
| 559 | prom_itlb_load(tlb_ent, tte_data, tte_vaddr); | ||
| 560 | if (bigkernel) { | ||
| 561 | tlb_ent -= 1; | ||
| 562 | prom_dtlb_load(tlb_ent, | ||
| 563 | tte_data + 0x400000, | ||
| 564 | tte_vaddr + 0x400000); | ||
| 565 | prom_itlb_load(tlb_ent, | ||
| 566 | tte_data + 0x400000, | ||
| 567 | tte_vaddr + 0x400000); | ||
| 568 | } | ||
| 569 | sparc64_highest_unlocked_tlb_ent = tlb_ent - 1; | ||
| 517 | } | 570 | } |
| 518 | sparc64_highest_unlocked_tlb_ent = tlb_ent - 1; | ||
| 519 | if (tlb_type == cheetah_plus) { | 571 | if (tlb_type == cheetah_plus) { |
| 520 | sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 | | 572 | sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 | |
| 521 | CTX_CHEETAH_PLUS_NUC); | 573 | CTX_CHEETAH_PLUS_NUC); |
| @@ -533,372 +585,14 @@ static void __init inherit_prom_mappings(void) | |||
| 533 | prom_printf("Remapping the kernel... "); | 585 | prom_printf("Remapping the kernel... "); |
| 534 | remap_kernel(); | 586 | remap_kernel(); |
| 535 | prom_printf("done.\n"); | 587 | prom_printf("done.\n"); |
| 536 | |||
| 537 | prom_printf("Registering callbacks... "); | ||
| 538 | register_prom_callbacks(); | ||
| 539 | prom_printf("done.\n"); | ||
| 540 | } | ||
| 541 | |||
| 542 | /* The OBP specifications for sun4u mark 0xfffffffc00000000 and | ||
| 543 | * upwards as reserved for use by the firmware (I wonder if this | ||
| 544 | * will be the same on Cheetah...). We use this virtual address | ||
| 545 | * range for the VPTE table mappings of the nucleus so we need | ||
| 546 | * to zap them when we enter the PROM. -DaveM | ||
| 547 | */ | ||
| 548 | static void __flush_nucleus_vptes(void) | ||
| 549 | { | ||
| 550 | unsigned long prom_reserved_base = 0xfffffffc00000000UL; | ||
| 551 | int i; | ||
| 552 | |||
| 553 | /* Only DTLB must be checked for VPTE entries. */ | ||
| 554 | if (tlb_type == spitfire) { | ||
| 555 | for (i = 0; i < 63; i++) { | ||
| 556 | unsigned long tag; | ||
| 557 | |||
| 558 | /* Spitfire Errata #32 workaround */ | ||
| 559 | /* NOTE: Always runs on spitfire, so no cheetah+ | ||
| 560 | * page size encodings. | ||
| 561 | */ | ||
| 562 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 563 | "flush %%g6" | ||
| 564 | : /* No outputs */ | ||
| 565 | : "r" (0), | ||
| 566 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 567 | |||
| 568 | tag = spitfire_get_dtlb_tag(i); | ||
| 569 | if (((tag & ~(PAGE_MASK)) == 0) && | ||
| 570 | ((tag & (PAGE_MASK)) >= prom_reserved_base)) { | ||
| 571 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 572 | "membar #Sync" | ||
| 573 | : /* no outputs */ | ||
| 574 | : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 575 | spitfire_put_dtlb_data(i, 0x0UL); | ||
| 576 | } | ||
| 577 | } | ||
| 578 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
| 579 | for (i = 0; i < 512; i++) { | ||
| 580 | unsigned long tag = cheetah_get_dtlb_tag(i, 2); | ||
| 581 | |||
| 582 | if ((tag & ~PAGE_MASK) == 0 && | ||
| 583 | (tag & PAGE_MASK) >= prom_reserved_base) { | ||
| 584 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 585 | "membar #Sync" | ||
| 586 | : /* no outputs */ | ||
| 587 | : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 588 | cheetah_put_dtlb_data(i, 0x0UL, 2); | ||
| 589 | } | ||
| 590 | |||
| 591 | if (tlb_type != cheetah_plus) | ||
| 592 | continue; | ||
| 593 | |||
| 594 | tag = cheetah_get_dtlb_tag(i, 3); | ||
| 595 | |||
| 596 | if ((tag & ~PAGE_MASK) == 0 && | ||
| 597 | (tag & PAGE_MASK) >= prom_reserved_base) { | ||
| 598 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 599 | "membar #Sync" | ||
| 600 | : /* no outputs */ | ||
| 601 | : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 602 | cheetah_put_dtlb_data(i, 0x0UL, 3); | ||
| 603 | } | ||
| 604 | } | ||
| 605 | } else { | ||
| 606 | /* Implement me :-) */ | ||
| 607 | BUG(); | ||
| 608 | } | ||
| 609 | } | 588 | } |
| 610 | 589 | ||
| 611 | static int prom_ditlb_set; | ||
| 612 | struct prom_tlb_entry { | ||
| 613 | int tlb_ent; | ||
| 614 | unsigned long tlb_tag; | ||
| 615 | unsigned long tlb_data; | ||
| 616 | }; | ||
| 617 | struct prom_tlb_entry prom_itlb[16], prom_dtlb[16]; | ||
| 618 | |||
| 619 | void prom_world(int enter) | 590 | void prom_world(int enter) |
| 620 | { | 591 | { |
| 621 | unsigned long pstate; | ||
| 622 | int i; | ||
| 623 | |||
| 624 | if (!enter) | 592 | if (!enter) |
| 625 | set_fs((mm_segment_t) { get_thread_current_ds() }); | 593 | set_fs((mm_segment_t) { get_thread_current_ds() }); |
| 626 | 594 | ||
| 627 | if (!prom_ditlb_set) | 595 | __asm__ __volatile__("flushw"); |
| 628 | return; | ||
| 629 | |||
| 630 | /* Make sure the following runs atomically. */ | ||
| 631 | __asm__ __volatile__("flushw\n\t" | ||
| 632 | "rdpr %%pstate, %0\n\t" | ||
| 633 | "wrpr %0, %1, %%pstate" | ||
| 634 | : "=r" (pstate) | ||
| 635 | : "i" (PSTATE_IE)); | ||
| 636 | |||
| 637 | if (enter) { | ||
| 638 | /* Kick out nucleus VPTEs. */ | ||
| 639 | __flush_nucleus_vptes(); | ||
| 640 | |||
| 641 | /* Install PROM world. */ | ||
| 642 | for (i = 0; i < 16; i++) { | ||
| 643 | if (prom_dtlb[i].tlb_ent != -1) { | ||
| 644 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 645 | "membar #Sync" | ||
| 646 | : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), | ||
| 647 | "i" (ASI_DMMU)); | ||
| 648 | if (tlb_type == spitfire) | ||
| 649 | spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, | ||
| 650 | prom_dtlb[i].tlb_data); | ||
| 651 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 652 | cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, | ||
| 653 | prom_dtlb[i].tlb_data); | ||
| 654 | } | ||
| 655 | if (prom_itlb[i].tlb_ent != -1) { | ||
| 656 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 657 | "membar #Sync" | ||
| 658 | : : "r" (prom_itlb[i].tlb_tag), | ||
| 659 | "r" (TLB_TAG_ACCESS), | ||
| 660 | "i" (ASI_IMMU)); | ||
| 661 | if (tlb_type == spitfire) | ||
| 662 | spitfire_put_itlb_data(prom_itlb[i].tlb_ent, | ||
| 663 | prom_itlb[i].tlb_data); | ||
| 664 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 665 | cheetah_put_litlb_data(prom_itlb[i].tlb_ent, | ||
| 666 | prom_itlb[i].tlb_data); | ||
| 667 | } | ||
| 668 | } | ||
| 669 | } else { | ||
| 670 | for (i = 0; i < 16; i++) { | ||
| 671 | if (prom_dtlb[i].tlb_ent != -1) { | ||
| 672 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 673 | "membar #Sync" | ||
| 674 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 675 | if (tlb_type == spitfire) | ||
| 676 | spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); | ||
| 677 | else | ||
| 678 | cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); | ||
| 679 | } | ||
| 680 | if (prom_itlb[i].tlb_ent != -1) { | ||
| 681 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 682 | "membar #Sync" | ||
| 683 | : : "r" (TLB_TAG_ACCESS), | ||
| 684 | "i" (ASI_IMMU)); | ||
| 685 | if (tlb_type == spitfire) | ||
| 686 | spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); | ||
| 687 | else | ||
| 688 | cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL); | ||
| 689 | } | ||
| 690 | } | ||
| 691 | } | ||
| 692 | __asm__ __volatile__("wrpr %0, 0, %%pstate" | ||
| 693 | : : "r" (pstate)); | ||
| 694 | } | ||
| 695 | |||
| 696 | void inherit_locked_prom_mappings(int save_p) | ||
| 697 | { | ||
| 698 | int i; | ||
| 699 | int dtlb_seen = 0; | ||
| 700 | int itlb_seen = 0; | ||
| 701 | |||
| 702 | /* Fucking losing PROM has more mappings in the TLB, but | ||
| 703 | * it (conveniently) fails to mention any of these in the | ||
| 704 | * translations property. The only ones that matter are | ||
| 705 | * the locked PROM tlb entries, so we impose the following | ||
| 706 | * irrecovable rule on the PROM, it is allowed 8 locked | ||
| 707 | * entries in the ITLB and 8 in the DTLB. | ||
| 708 | * | ||
| 709 | * Supposedly the upper 16GB of the address space is | ||
| 710 | * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED | ||
| 711 | * SOMEWHERE!!!!!!!!!!!!!!!!! Furthermore the entire interface | ||
| 712 | * used between the client program and the firmware on sun5 | ||
| 713 | * systems to coordinate mmu mappings is also COMPLETELY | ||
| 714 | * UNDOCUMENTED!!!!!! Thanks S(t)un! | ||
| 715 | */ | ||
| 716 | if (save_p) { | ||
| 717 | for (i = 0; i < 16; i++) { | ||
| 718 | prom_itlb[i].tlb_ent = -1; | ||
| 719 | prom_dtlb[i].tlb_ent = -1; | ||
| 720 | } | ||
| 721 | } | ||
| 722 | if (tlb_type == spitfire) { | ||
| 723 | int high = sparc64_highest_unlocked_tlb_ent; | ||
| 724 | for (i = 0; i <= high; i++) { | ||
| 725 | unsigned long data; | ||
| 726 | |||
| 727 | /* Spitfire Errata #32 workaround */ | ||
| 728 | /* NOTE: Always runs on spitfire, so no cheetah+ | ||
| 729 | * page size encodings. | ||
| 730 | */ | ||
| 731 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 732 | "flush %%g6" | ||
| 733 | : /* No outputs */ | ||
| 734 | : "r" (0), | ||
| 735 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 736 | |||
| 737 | data = spitfire_get_dtlb_data(i); | ||
| 738 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
| 739 | unsigned long tag; | ||
| 740 | |||
| 741 | /* Spitfire Errata #32 workaround */ | ||
| 742 | /* NOTE: Always runs on spitfire, so no | ||
| 743 | * cheetah+ page size encodings. | ||
| 744 | */ | ||
| 745 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 746 | "flush %%g6" | ||
| 747 | : /* No outputs */ | ||
| 748 | : "r" (0), | ||
| 749 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 750 | |||
| 751 | tag = spitfire_get_dtlb_tag(i); | ||
| 752 | if (save_p) { | ||
| 753 | prom_dtlb[dtlb_seen].tlb_ent = i; | ||
| 754 | prom_dtlb[dtlb_seen].tlb_tag = tag; | ||
| 755 | prom_dtlb[dtlb_seen].tlb_data = data; | ||
| 756 | } | ||
| 757 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 758 | "membar #Sync" | ||
| 759 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 760 | spitfire_put_dtlb_data(i, 0x0UL); | ||
| 761 | |||
| 762 | dtlb_seen++; | ||
| 763 | if (dtlb_seen > 15) | ||
| 764 | break; | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | for (i = 0; i < high; i++) { | ||
| 769 | unsigned long data; | ||
| 770 | |||
| 771 | /* Spitfire Errata #32 workaround */ | ||
| 772 | /* NOTE: Always runs on spitfire, so no | ||
| 773 | * cheetah+ page size encodings. | ||
| 774 | */ | ||
| 775 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 776 | "flush %%g6" | ||
| 777 | : /* No outputs */ | ||
| 778 | : "r" (0), | ||
| 779 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 780 | |||
| 781 | data = spitfire_get_itlb_data(i); | ||
| 782 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
| 783 | unsigned long tag; | ||
| 784 | |||
| 785 | /* Spitfire Errata #32 workaround */ | ||
| 786 | /* NOTE: Always runs on spitfire, so no | ||
| 787 | * cheetah+ page size encodings. | ||
| 788 | */ | ||
| 789 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 790 | "flush %%g6" | ||
| 791 | : /* No outputs */ | ||
| 792 | : "r" (0), | ||
| 793 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 794 | |||
| 795 | tag = spitfire_get_itlb_tag(i); | ||
| 796 | if (save_p) { | ||
| 797 | prom_itlb[itlb_seen].tlb_ent = i; | ||
| 798 | prom_itlb[itlb_seen].tlb_tag = tag; | ||
| 799 | prom_itlb[itlb_seen].tlb_data = data; | ||
| 800 | } | ||
| 801 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 802 | "membar #Sync" | ||
| 803 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); | ||
| 804 | spitfire_put_itlb_data(i, 0x0UL); | ||
| 805 | |||
| 806 | itlb_seen++; | ||
| 807 | if (itlb_seen > 15) | ||
| 808 | break; | ||
| 809 | } | ||
| 810 | } | ||
| 811 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
| 812 | int high = sparc64_highest_unlocked_tlb_ent; | ||
| 813 | |||
| 814 | for (i = 0; i <= high; i++) { | ||
| 815 | unsigned long data; | ||
| 816 | |||
| 817 | data = cheetah_get_ldtlb_data(i); | ||
| 818 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
| 819 | unsigned long tag; | ||
| 820 | |||
| 821 | tag = cheetah_get_ldtlb_tag(i); | ||
| 822 | if (save_p) { | ||
| 823 | prom_dtlb[dtlb_seen].tlb_ent = i; | ||
| 824 | prom_dtlb[dtlb_seen].tlb_tag = tag; | ||
| 825 | prom_dtlb[dtlb_seen].tlb_data = data; | ||
| 826 | } | ||
| 827 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 828 | "membar #Sync" | ||
| 829 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 830 | cheetah_put_ldtlb_data(i, 0x0UL); | ||
| 831 | |||
| 832 | dtlb_seen++; | ||
| 833 | if (dtlb_seen > 15) | ||
| 834 | break; | ||
| 835 | } | ||
| 836 | } | ||
| 837 | |||
| 838 | for (i = 0; i < high; i++) { | ||
| 839 | unsigned long data; | ||
| 840 | |||
| 841 | data = cheetah_get_litlb_data(i); | ||
| 842 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
| 843 | unsigned long tag; | ||
| 844 | |||
| 845 | tag = cheetah_get_litlb_tag(i); | ||
| 846 | if (save_p) { | ||
| 847 | prom_itlb[itlb_seen].tlb_ent = i; | ||
| 848 | prom_itlb[itlb_seen].tlb_tag = tag; | ||
| 849 | prom_itlb[itlb_seen].tlb_data = data; | ||
| 850 | } | ||
| 851 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 852 | "membar #Sync" | ||
| 853 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); | ||
| 854 | cheetah_put_litlb_data(i, 0x0UL); | ||
| 855 | |||
| 856 | itlb_seen++; | ||
| 857 | if (itlb_seen > 15) | ||
| 858 | break; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | } else { | ||
| 862 | /* Implement me :-) */ | ||
| 863 | BUG(); | ||
| 864 | } | ||
| 865 | if (save_p) | ||
| 866 | prom_ditlb_set = 1; | ||
| 867 | } | ||
| 868 | |||
| 869 | /* Give PROM back his world, done during reboots... */ | ||
| 870 | void prom_reload_locked(void) | ||
| 871 | { | ||
| 872 | int i; | ||
| 873 | |||
| 874 | for (i = 0; i < 16; i++) { | ||
| 875 | if (prom_dtlb[i].tlb_ent != -1) { | ||
| 876 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 877 | "membar #Sync" | ||
| 878 | : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), | ||
| 879 | "i" (ASI_DMMU)); | ||
| 880 | if (tlb_type == spitfire) | ||
| 881 | spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, | ||
| 882 | prom_dtlb[i].tlb_data); | ||
| 883 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 884 | cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, | ||
| 885 | prom_dtlb[i].tlb_data); | ||
| 886 | } | ||
| 887 | |||
| 888 | if (prom_itlb[i].tlb_ent != -1) { | ||
| 889 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 890 | "membar #Sync" | ||
| 891 | : : "r" (prom_itlb[i].tlb_tag), | ||
| 892 | "r" (TLB_TAG_ACCESS), | ||
| 893 | "i" (ASI_IMMU)); | ||
| 894 | if (tlb_type == spitfire) | ||
| 895 | spitfire_put_itlb_data(prom_itlb[i].tlb_ent, | ||
| 896 | prom_itlb[i].tlb_data); | ||
| 897 | else | ||
| 898 | cheetah_put_litlb_data(prom_itlb[i].tlb_ent, | ||
| 899 | prom_itlb[i].tlb_data); | ||
| 900 | } | ||
| 901 | } | ||
| 902 | } | 596 | } |
| 903 | 597 | ||
| 904 | #ifdef DCACHE_ALIASING_POSSIBLE | 598 | #ifdef DCACHE_ALIASING_POSSIBLE |
| @@ -914,7 +608,7 @@ void __flush_dcache_range(unsigned long start, unsigned long end) | |||
| 914 | if (++n >= 512) | 608 | if (++n >= 512) |
| 915 | break; | 609 | break; |
| 916 | } | 610 | } |
| 917 | } else { | 611 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
| 918 | start = __pa(start); | 612 | start = __pa(start); |
| 919 | end = __pa(end); | 613 | end = __pa(end); |
| 920 | for (va = start; va < end; va += 32) | 614 | for (va = start; va < end; va += 32) |
| @@ -927,63 +621,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end) | |||
| 927 | } | 621 | } |
| 928 | #endif /* DCACHE_ALIASING_POSSIBLE */ | 622 | #endif /* DCACHE_ALIASING_POSSIBLE */ |
| 929 | 623 | ||
| 930 | /* If not locked, zap it. */ | ||
| 931 | void __flush_tlb_all(void) | ||
| 932 | { | ||
| 933 | unsigned long pstate; | ||
| 934 | int i; | ||
| 935 | |||
| 936 | __asm__ __volatile__("flushw\n\t" | ||
| 937 | "rdpr %%pstate, %0\n\t" | ||
| 938 | "wrpr %0, %1, %%pstate" | ||
| 939 | : "=r" (pstate) | ||
| 940 | : "i" (PSTATE_IE)); | ||
| 941 | if (tlb_type == spitfire) { | ||
| 942 | for (i = 0; i < 64; i++) { | ||
| 943 | /* Spitfire Errata #32 workaround */ | ||
| 944 | /* NOTE: Always runs on spitfire, so no | ||
| 945 | * cheetah+ page size encodings. | ||
| 946 | */ | ||
| 947 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 948 | "flush %%g6" | ||
| 949 | : /* No outputs */ | ||
| 950 | : "r" (0), | ||
| 951 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 952 | |||
| 953 | if (!(spitfire_get_dtlb_data(i) & _PAGE_L)) { | ||
| 954 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 955 | "membar #Sync" | ||
| 956 | : /* no outputs */ | ||
| 957 | : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 958 | spitfire_put_dtlb_data(i, 0x0UL); | ||
| 959 | } | ||
| 960 | |||
| 961 | /* Spitfire Errata #32 workaround */ | ||
| 962 | /* NOTE: Always runs on spitfire, so no | ||
| 963 | * cheetah+ page size encodings. | ||
| 964 | */ | ||
| 965 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 966 | "flush %%g6" | ||
| 967 | : /* No outputs */ | ||
| 968 | : "r" (0), | ||
| 969 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 970 | |||
| 971 | if (!(spitfire_get_itlb_data(i) & _PAGE_L)) { | ||
| 972 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 973 | "membar #Sync" | ||
| 974 | : /* no outputs */ | ||
| 975 | : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); | ||
| 976 | spitfire_put_itlb_data(i, 0x0UL); | ||
| 977 | } | ||
| 978 | } | ||
| 979 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
| 980 | cheetah_flush_dtlb_all(); | ||
| 981 | cheetah_flush_itlb_all(); | ||
| 982 | } | ||
| 983 | __asm__ __volatile__("wrpr %0, 0, %%pstate" | ||
| 984 | : : "r" (pstate)); | ||
| 985 | } | ||
| 986 | |||
| 987 | /* Caller does TLB context flushing on local CPU if necessary. | 624 | /* Caller does TLB context flushing on local CPU if necessary. |
| 988 | * The caller also ensures that CTX_VALID(mm->context) is false. | 625 | * The caller also ensures that CTX_VALID(mm->context) is false. |
| 989 | * | 626 | * |
| @@ -991,17 +628,21 @@ void __flush_tlb_all(void) | |||
| 991 | * let the user have CTX 0 (nucleus) or we ever use a CTX | 628 | * let the user have CTX 0 (nucleus) or we ever use a CTX |
| 992 | * version of zero (and thus NO_CONTEXT would not be caught | 629 | * version of zero (and thus NO_CONTEXT would not be caught |
| 993 | * by version mis-match tests in mmu_context.h). | 630 | * by version mis-match tests in mmu_context.h). |
| 631 | * | ||
| 632 | * Always invoked with interrupts disabled. | ||
| 994 | */ | 633 | */ |
| 995 | void get_new_mmu_context(struct mm_struct *mm) | 634 | void get_new_mmu_context(struct mm_struct *mm) |
| 996 | { | 635 | { |
| 997 | unsigned long ctx, new_ctx; | 636 | unsigned long ctx, new_ctx; |
| 998 | unsigned long orig_pgsz_bits; | 637 | unsigned long orig_pgsz_bits; |
| 999 | 638 | unsigned long flags; | |
| 639 | int new_version; | ||
| 1000 | 640 | ||
| 1001 | spin_lock(&ctx_alloc_lock); | 641 | spin_lock_irqsave(&ctx_alloc_lock, flags); |
| 1002 | orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); | 642 | orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); |
| 1003 | ctx = (tlb_context_cache + 1) & CTX_NR_MASK; | 643 | ctx = (tlb_context_cache + 1) & CTX_NR_MASK; |
| 1004 | new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); | 644 | new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); |
| 645 | new_version = 0; | ||
| 1005 | if (new_ctx >= (1 << CTX_NR_BITS)) { | 646 | if (new_ctx >= (1 << CTX_NR_BITS)) { |
| 1006 | new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1); | 647 | new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1); |
| 1007 | if (new_ctx >= ctx) { | 648 | if (new_ctx >= ctx) { |
| @@ -1024,6 +665,7 @@ void get_new_mmu_context(struct mm_struct *mm) | |||
| 1024 | mmu_context_bmap[i + 2] = 0; | 665 | mmu_context_bmap[i + 2] = 0; |
| 1025 | mmu_context_bmap[i + 3] = 0; | 666 | mmu_context_bmap[i + 3] = 0; |
| 1026 | } | 667 | } |
| 668 | new_version = 1; | ||
| 1027 | goto out; | 669 | goto out; |
| 1028 | } | 670 | } |
| 1029 | } | 671 | } |
| @@ -1032,79 +674,10 @@ void get_new_mmu_context(struct mm_struct *mm) | |||
| 1032 | out: | 674 | out: |
| 1033 | tlb_context_cache = new_ctx; | 675 | tlb_context_cache = new_ctx; |
| 1034 | mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; | 676 | mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; |
| 1035 | spin_unlock(&ctx_alloc_lock); | 677 | spin_unlock_irqrestore(&ctx_alloc_lock, flags); |
| 1036 | } | ||
| 1037 | |||
| 1038 | #ifndef CONFIG_SMP | ||
| 1039 | struct pgtable_cache_struct pgt_quicklists; | ||
| 1040 | #endif | ||
| 1041 | |||
| 1042 | /* OK, we have to color these pages. The page tables are accessed | ||
| 1043 | * by non-Dcache enabled mapping in the VPTE area by the dtlb_backend.S | ||
| 1044 | * code, as well as by PAGE_OFFSET range direct-mapped addresses by | ||
| 1045 | * other parts of the kernel. By coloring, we make sure that the tlbmiss | ||
| 1046 | * fast handlers do not get data from old/garbage dcache lines that | ||
| 1047 | * correspond to an old/stale virtual address (user/kernel) that | ||
| 1048 | * previously mapped the pagetable page while accessing vpte range | ||
| 1049 | * addresses. The idea is that if the vpte color and PAGE_OFFSET range | ||
| 1050 | * color is the same, then when the kernel initializes the pagetable | ||
| 1051 | * using the later address range, accesses with the first address | ||
| 1052 | * range will see the newly initialized data rather than the garbage. | ||
| 1053 | */ | ||
| 1054 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 1055 | #define DC_ALIAS_SHIFT 1 | ||
| 1056 | #else | ||
| 1057 | #define DC_ALIAS_SHIFT 0 | ||
| 1058 | #endif | ||
| 1059 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | ||
| 1060 | { | ||
| 1061 | struct page *page; | ||
| 1062 | unsigned long color; | ||
| 1063 | |||
| 1064 | { | ||
| 1065 | pte_t *ptep = pte_alloc_one_fast(mm, address); | ||
| 1066 | |||
| 1067 | if (ptep) | ||
| 1068 | return ptep; | ||
| 1069 | } | ||
| 1070 | 678 | ||
| 1071 | color = VPTE_COLOR(address); | 679 | if (unlikely(new_version)) |
| 1072 | page = alloc_pages(GFP_KERNEL|__GFP_REPEAT, DC_ALIAS_SHIFT); | 680 | smp_new_mmu_context_version(); |
| 1073 | if (page) { | ||
| 1074 | unsigned long *to_free; | ||
| 1075 | unsigned long paddr; | ||
| 1076 | pte_t *pte; | ||
| 1077 | |||
| 1078 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 1079 | set_page_count(page, 1); | ||
| 1080 | ClearPageCompound(page); | ||
| 1081 | |||
| 1082 | set_page_count((page + 1), 1); | ||
| 1083 | ClearPageCompound(page + 1); | ||
| 1084 | #endif | ||
| 1085 | paddr = (unsigned long) page_address(page); | ||
| 1086 | memset((char *)paddr, 0, (PAGE_SIZE << DC_ALIAS_SHIFT)); | ||
| 1087 | |||
| 1088 | if (!color) { | ||
| 1089 | pte = (pte_t *) paddr; | ||
| 1090 | to_free = (unsigned long *) (paddr + PAGE_SIZE); | ||
| 1091 | } else { | ||
| 1092 | pte = (pte_t *) (paddr + PAGE_SIZE); | ||
| 1093 | to_free = (unsigned long *) paddr; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 1097 | /* Now free the other one up, adjust cache size. */ | ||
| 1098 | preempt_disable(); | ||
| 1099 | *to_free = (unsigned long) pte_quicklist[color ^ 0x1]; | ||
| 1100 | pte_quicklist[color ^ 0x1] = to_free; | ||
| 1101 | pgtable_cache_size++; | ||
| 1102 | preempt_enable(); | ||
| 1103 | #endif | ||
| 1104 | |||
| 1105 | return pte; | ||
| 1106 | } | ||
| 1107 | return NULL; | ||
| 1108 | } | 681 | } |
| 1109 | 682 | ||
| 1110 | void sparc_ultra_dump_itlb(void) | 683 | void sparc_ultra_dump_itlb(void) |
| @@ -1196,9 +769,78 @@ void sparc_ultra_dump_dtlb(void) | |||
| 1196 | 769 | ||
| 1197 | extern unsigned long cmdline_memory_size; | 770 | extern unsigned long cmdline_memory_size; |
| 1198 | 771 | ||
| 1199 | unsigned long __init bootmem_init(unsigned long *pages_avail) | 772 | /* Find a free area for the bootmem map, avoiding the kernel image |
| 773 | * and the initial ramdisk. | ||
| 774 | */ | ||
| 775 | static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, | ||
| 776 | unsigned long end_pfn) | ||
| 777 | { | ||
| 778 | unsigned long avoid_start, avoid_end, bootmap_size; | ||
| 779 | int i; | ||
| 780 | |||
| 781 | bootmap_size = ((end_pfn - start_pfn) + 7) / 8; | ||
| 782 | bootmap_size = ALIGN(bootmap_size, sizeof(long)); | ||
| 783 | |||
| 784 | avoid_start = avoid_end = 0; | ||
| 785 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 786 | avoid_start = initrd_start; | ||
| 787 | avoid_end = PAGE_ALIGN(initrd_end); | ||
| 788 | #endif | ||
| 789 | |||
| 790 | #ifdef CONFIG_DEBUG_BOOTMEM | ||
| 791 | prom_printf("choose_bootmap_pfn: kern[%lx:%lx] avoid[%lx:%lx]\n", | ||
| 792 | kern_base, PAGE_ALIGN(kern_base + kern_size), | ||
| 793 | avoid_start, avoid_end); | ||
| 794 | #endif | ||
| 795 | for (i = 0; i < pavail_ents; i++) { | ||
| 796 | unsigned long start, end; | ||
| 797 | |||
| 798 | start = pavail[i].phys_addr; | ||
| 799 | end = start + pavail[i].reg_size; | ||
| 800 | |||
| 801 | while (start < end) { | ||
| 802 | if (start >= kern_base && | ||
| 803 | start < PAGE_ALIGN(kern_base + kern_size)) { | ||
| 804 | start = PAGE_ALIGN(kern_base + kern_size); | ||
| 805 | continue; | ||
| 806 | } | ||
| 807 | if (start >= avoid_start && start < avoid_end) { | ||
| 808 | start = avoid_end; | ||
| 809 | continue; | ||
| 810 | } | ||
| 811 | |||
| 812 | if ((end - start) < bootmap_size) | ||
| 813 | break; | ||
| 814 | |||
| 815 | if (start < kern_base && | ||
| 816 | (start + bootmap_size) > kern_base) { | ||
| 817 | start = PAGE_ALIGN(kern_base + kern_size); | ||
| 818 | continue; | ||
| 819 | } | ||
| 820 | |||
| 821 | if (start < avoid_start && | ||
| 822 | (start + bootmap_size) > avoid_start) { | ||
| 823 | start = avoid_end; | ||
| 824 | continue; | ||
| 825 | } | ||
| 826 | |||
| 827 | /* OK, it doesn't overlap anything, use it. */ | ||
| 828 | #ifdef CONFIG_DEBUG_BOOTMEM | ||
| 829 | prom_printf("choose_bootmap_pfn: Using %lx [%lx]\n", | ||
| 830 | start >> PAGE_SHIFT, start); | ||
| 831 | #endif | ||
| 832 | return start >> PAGE_SHIFT; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | prom_printf("Cannot find free area for bootmap, aborting.\n"); | ||
| 837 | prom_halt(); | ||
| 838 | } | ||
| 839 | |||
| 840 | static unsigned long __init bootmem_init(unsigned long *pages_avail, | ||
| 841 | unsigned long phys_base) | ||
| 1200 | { | 842 | { |
| 1201 | unsigned long bootmap_size, start_pfn, end_pfn; | 843 | unsigned long bootmap_size, end_pfn; |
| 1202 | unsigned long end_of_phys_memory = 0UL; | 844 | unsigned long end_of_phys_memory = 0UL; |
| 1203 | unsigned long bootmap_pfn, bytes_avail, size; | 845 | unsigned long bootmap_pfn, bytes_avail, size; |
| 1204 | int i; | 846 | int i; |
| @@ -1236,14 +878,6 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
| 1236 | 878 | ||
| 1237 | *pages_avail = bytes_avail >> PAGE_SHIFT; | 879 | *pages_avail = bytes_avail >> PAGE_SHIFT; |
| 1238 | 880 | ||
| 1239 | /* Start with page aligned address of last symbol in kernel | ||
| 1240 | * image. The kernel is hard mapped below PAGE_OFFSET in a | ||
| 1241 | * 4MB locked TLB translation. | ||
| 1242 | */ | ||
| 1243 | start_pfn = PAGE_ALIGN(kern_base + kern_size) >> PAGE_SHIFT; | ||
| 1244 | |||
| 1245 | bootmap_pfn = start_pfn; | ||
| 1246 | |||
| 1247 | end_pfn = end_of_phys_memory >> PAGE_SHIFT; | 881 | end_pfn = end_of_phys_memory >> PAGE_SHIFT; |
| 1248 | 882 | ||
| 1249 | #ifdef CONFIG_BLK_DEV_INITRD | 883 | #ifdef CONFIG_BLK_DEV_INITRD |
| @@ -1260,23 +894,22 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
| 1260 | "(0x%016lx > 0x%016lx)\ndisabling initrd\n", | 894 | "(0x%016lx > 0x%016lx)\ndisabling initrd\n", |
| 1261 | initrd_end, end_of_phys_memory); | 895 | initrd_end, end_of_phys_memory); |
| 1262 | initrd_start = 0; | 896 | initrd_start = 0; |
| 1263 | } | 897 | initrd_end = 0; |
| 1264 | if (initrd_start) { | ||
| 1265 | if (initrd_start >= (start_pfn << PAGE_SHIFT) && | ||
| 1266 | initrd_start < (start_pfn << PAGE_SHIFT) + 2 * PAGE_SIZE) | ||
| 1267 | bootmap_pfn = PAGE_ALIGN (initrd_end) >> PAGE_SHIFT; | ||
| 1268 | } | 898 | } |
| 1269 | } | 899 | } |
| 1270 | #endif | 900 | #endif |
| 1271 | /* Initialize the boot-time allocator. */ | 901 | /* Initialize the boot-time allocator. */ |
| 1272 | max_pfn = max_low_pfn = end_pfn; | 902 | max_pfn = max_low_pfn = end_pfn; |
| 1273 | min_low_pfn = pfn_base; | 903 | min_low_pfn = (phys_base >> PAGE_SHIFT); |
| 904 | |||
| 905 | bootmap_pfn = choose_bootmap_pfn(min_low_pfn, end_pfn); | ||
| 1274 | 906 | ||
| 1275 | #ifdef CONFIG_DEBUG_BOOTMEM | 907 | #ifdef CONFIG_DEBUG_BOOTMEM |
| 1276 | prom_printf("init_bootmem(min[%lx], bootmap[%lx], max[%lx])\n", | 908 | prom_printf("init_bootmem(min[%lx], bootmap[%lx], max[%lx])\n", |
| 1277 | min_low_pfn, bootmap_pfn, max_low_pfn); | 909 | min_low_pfn, bootmap_pfn, max_low_pfn); |
| 1278 | #endif | 910 | #endif |
| 1279 | bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, pfn_base, end_pfn); | 911 | bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, |
| 912 | min_low_pfn, end_pfn); | ||
| 1280 | 913 | ||
| 1281 | /* Now register the available physical memory with the | 914 | /* Now register the available physical memory with the |
| 1282 | * allocator. | 915 | * allocator. |
| @@ -1324,9 +957,26 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
| 1324 | reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); | 957 | reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); |
| 1325 | *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; | 958 | *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; |
| 1326 | 959 | ||
| 960 | for (i = 0; i < pavail_ents; i++) { | ||
| 961 | unsigned long start_pfn, end_pfn; | ||
| 962 | |||
| 963 | start_pfn = pavail[i].phys_addr >> PAGE_SHIFT; | ||
| 964 | end_pfn = (start_pfn + (pavail[i].reg_size >> PAGE_SHIFT)); | ||
| 965 | #ifdef CONFIG_DEBUG_BOOTMEM | ||
| 966 | prom_printf("memory_present(0, %lx, %lx)\n", | ||
| 967 | start_pfn, end_pfn); | ||
| 968 | #endif | ||
| 969 | memory_present(0, start_pfn, end_pfn); | ||
| 970 | } | ||
| 971 | |||
| 972 | sparse_init(); | ||
| 973 | |||
| 1327 | return end_pfn; | 974 | return end_pfn; |
| 1328 | } | 975 | } |
| 1329 | 976 | ||
| 977 | static struct linux_prom64_registers pall[MAX_BANKS] __initdata; | ||
| 978 | static int pall_ents __initdata; | ||
| 979 | |||
| 1330 | #ifdef CONFIG_DEBUG_PAGEALLOC | 980 | #ifdef CONFIG_DEBUG_PAGEALLOC |
| 1331 | static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, pgprot_t prot) | 981 | static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, pgprot_t prot) |
| 1332 | { | 982 | { |
| @@ -1382,14 +1032,44 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, | |||
| 1382 | return alloc_bytes; | 1032 | return alloc_bytes; |
| 1383 | } | 1033 | } |
| 1384 | 1034 | ||
| 1385 | static struct linux_prom64_registers pall[MAX_BANKS] __initdata; | ||
| 1386 | static int pall_ents __initdata; | ||
| 1387 | |||
| 1388 | extern unsigned int kvmap_linear_patch[1]; | 1035 | extern unsigned int kvmap_linear_patch[1]; |
| 1036 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
| 1037 | |||
| 1038 | static void __init mark_kpte_bitmap(unsigned long start, unsigned long end) | ||
| 1039 | { | ||
| 1040 | const unsigned long shift_256MB = 28; | ||
| 1041 | const unsigned long mask_256MB = ((1UL << shift_256MB) - 1UL); | ||
| 1042 | const unsigned long size_256MB = (1UL << shift_256MB); | ||
| 1043 | |||
| 1044 | while (start < end) { | ||
| 1045 | long remains; | ||
| 1046 | |||
| 1047 | remains = end - start; | ||
| 1048 | if (remains < size_256MB) | ||
| 1049 | break; | ||
| 1050 | |||
| 1051 | if (start & mask_256MB) { | ||
| 1052 | start = (start + size_256MB) & ~mask_256MB; | ||
| 1053 | continue; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | while (remains >= size_256MB) { | ||
| 1057 | unsigned long index = start >> shift_256MB; | ||
| 1058 | |||
| 1059 | __set_bit(index, kpte_linear_bitmap); | ||
| 1060 | |||
| 1061 | start += size_256MB; | ||
| 1062 | remains -= size_256MB; | ||
| 1063 | } | ||
| 1064 | } | ||
| 1065 | } | ||
| 1389 | 1066 | ||
| 1390 | static void __init kernel_physical_mapping_init(void) | 1067 | static void __init kernel_physical_mapping_init(void) |
| 1391 | { | 1068 | { |
| 1392 | unsigned long i, mem_alloced = 0UL; | 1069 | unsigned long i; |
| 1070 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 1071 | unsigned long mem_alloced = 0UL; | ||
| 1072 | #endif | ||
| 1393 | 1073 | ||
| 1394 | read_obp_memory("reg", &pall[0], &pall_ents); | 1074 | read_obp_memory("reg", &pall[0], &pall_ents); |
| 1395 | 1075 | ||
| @@ -1398,10 +1078,16 @@ static void __init kernel_physical_mapping_init(void) | |||
| 1398 | 1078 | ||
| 1399 | phys_start = pall[i].phys_addr; | 1079 | phys_start = pall[i].phys_addr; |
| 1400 | phys_end = phys_start + pall[i].reg_size; | 1080 | phys_end = phys_start + pall[i].reg_size; |
| 1081 | |||
| 1082 | mark_kpte_bitmap(phys_start, phys_end); | ||
| 1083 | |||
| 1084 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 1401 | mem_alloced += kernel_map_range(phys_start, phys_end, | 1085 | mem_alloced += kernel_map_range(phys_start, phys_end, |
| 1402 | PAGE_KERNEL); | 1086 | PAGE_KERNEL); |
| 1087 | #endif | ||
| 1403 | } | 1088 | } |
| 1404 | 1089 | ||
| 1090 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 1405 | printk("Allocated %ld bytes for kernel page tables.\n", | 1091 | printk("Allocated %ld bytes for kernel page tables.\n", |
| 1406 | mem_alloced); | 1092 | mem_alloced); |
| 1407 | 1093 | ||
| @@ -1409,8 +1095,10 @@ static void __init kernel_physical_mapping_init(void) | |||
| 1409 | flushi(&kvmap_linear_patch[0]); | 1095 | flushi(&kvmap_linear_patch[0]); |
| 1410 | 1096 | ||
| 1411 | __flush_tlb_all(); | 1097 | __flush_tlb_all(); |
| 1098 | #endif | ||
| 1412 | } | 1099 | } |
| 1413 | 1100 | ||
| 1101 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 1414 | void kernel_map_pages(struct page *page, int numpages, int enable) | 1102 | void kernel_map_pages(struct page *page, int numpages, int enable) |
| 1415 | { | 1103 | { |
| 1416 | unsigned long phys_start = page_to_pfn(page) << PAGE_SHIFT; | 1104 | unsigned long phys_start = page_to_pfn(page) << PAGE_SHIFT; |
| @@ -1419,6 +1107,9 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
| 1419 | kernel_map_range(phys_start, phys_end, | 1107 | kernel_map_range(phys_start, phys_end, |
| 1420 | (enable ? PAGE_KERNEL : __pgprot(0))); | 1108 | (enable ? PAGE_KERNEL : __pgprot(0))); |
| 1421 | 1109 | ||
| 1110 | flush_tsb_kernel_range(PAGE_OFFSET + phys_start, | ||
| 1111 | PAGE_OFFSET + phys_end); | ||
| 1112 | |||
| 1422 | /* we should perform an IPI and flush all tlbs, | 1113 | /* we should perform an IPI and flush all tlbs, |
| 1423 | * but that can deadlock->flush only current cpu. | 1114 | * but that can deadlock->flush only current cpu. |
| 1424 | */ | 1115 | */ |
| @@ -1439,18 +1130,150 @@ unsigned long __init find_ecache_flush_span(unsigned long size) | |||
| 1439 | return ~0UL; | 1130 | return ~0UL; |
| 1440 | } | 1131 | } |
| 1441 | 1132 | ||
| 1133 | static void __init tsb_phys_patch(void) | ||
| 1134 | { | ||
| 1135 | struct tsb_ldquad_phys_patch_entry *pquad; | ||
| 1136 | struct tsb_phys_patch_entry *p; | ||
| 1137 | |||
| 1138 | pquad = &__tsb_ldquad_phys_patch; | ||
| 1139 | while (pquad < &__tsb_ldquad_phys_patch_end) { | ||
| 1140 | unsigned long addr = pquad->addr; | ||
| 1141 | |||
| 1142 | if (tlb_type == hypervisor) | ||
| 1143 | *(unsigned int *) addr = pquad->sun4v_insn; | ||
| 1144 | else | ||
| 1145 | *(unsigned int *) addr = pquad->sun4u_insn; | ||
| 1146 | wmb(); | ||
| 1147 | __asm__ __volatile__("flush %0" | ||
| 1148 | : /* no outputs */ | ||
| 1149 | : "r" (addr)); | ||
| 1150 | |||
| 1151 | pquad++; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | p = &__tsb_phys_patch; | ||
| 1155 | while (p < &__tsb_phys_patch_end) { | ||
| 1156 | unsigned long addr = p->addr; | ||
| 1157 | |||
| 1158 | *(unsigned int *) addr = p->insn; | ||
| 1159 | wmb(); | ||
| 1160 | __asm__ __volatile__("flush %0" | ||
| 1161 | : /* no outputs */ | ||
| 1162 | : "r" (addr)); | ||
| 1163 | |||
| 1164 | p++; | ||
| 1165 | } | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | /* Don't mark as init, we give this to the Hypervisor. */ | ||
| 1169 | static struct hv_tsb_descr ktsb_descr[2]; | ||
| 1170 | extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES]; | ||
| 1171 | |||
| 1172 | static void __init sun4v_ktsb_init(void) | ||
| 1173 | { | ||
| 1174 | unsigned long ktsb_pa; | ||
| 1175 | |||
| 1176 | /* First KTSB for PAGE_SIZE mappings. */ | ||
| 1177 | ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE); | ||
| 1178 | |||
| 1179 | switch (PAGE_SIZE) { | ||
| 1180 | case 8 * 1024: | ||
| 1181 | default: | ||
| 1182 | ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_8K; | ||
| 1183 | ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_8K; | ||
| 1184 | break; | ||
| 1185 | |||
| 1186 | case 64 * 1024: | ||
| 1187 | ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_64K; | ||
| 1188 | ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_64K; | ||
| 1189 | break; | ||
| 1190 | |||
| 1191 | case 512 * 1024: | ||
| 1192 | ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_512K; | ||
| 1193 | ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_512K; | ||
| 1194 | break; | ||
| 1195 | |||
| 1196 | case 4 * 1024 * 1024: | ||
| 1197 | ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_4MB; | ||
| 1198 | ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_4MB; | ||
| 1199 | break; | ||
| 1200 | }; | ||
| 1201 | |||
| 1202 | ktsb_descr[0].assoc = 1; | ||
| 1203 | ktsb_descr[0].num_ttes = KERNEL_TSB_NENTRIES; | ||
| 1204 | ktsb_descr[0].ctx_idx = 0; | ||
| 1205 | ktsb_descr[0].tsb_base = ktsb_pa; | ||
| 1206 | ktsb_descr[0].resv = 0; | ||
| 1207 | |||
| 1208 | /* Second KTSB for 4MB/256MB mappings. */ | ||
| 1209 | ktsb_pa = (kern_base + | ||
| 1210 | ((unsigned long)&swapper_4m_tsb[0] - KERNBASE)); | ||
| 1211 | |||
| 1212 | ktsb_descr[1].pgsz_idx = HV_PGSZ_IDX_4MB; | ||
| 1213 | ktsb_descr[1].pgsz_mask = (HV_PGSZ_MASK_4MB | | ||
| 1214 | HV_PGSZ_MASK_256MB); | ||
| 1215 | ktsb_descr[1].assoc = 1; | ||
| 1216 | ktsb_descr[1].num_ttes = KERNEL_TSB4M_NENTRIES; | ||
| 1217 | ktsb_descr[1].ctx_idx = 0; | ||
| 1218 | ktsb_descr[1].tsb_base = ktsb_pa; | ||
| 1219 | ktsb_descr[1].resv = 0; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | void __cpuinit sun4v_ktsb_register(void) | ||
| 1223 | { | ||
| 1224 | register unsigned long func asm("%o5"); | ||
| 1225 | register unsigned long arg0 asm("%o0"); | ||
| 1226 | register unsigned long arg1 asm("%o1"); | ||
| 1227 | unsigned long pa; | ||
| 1228 | |||
| 1229 | pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE); | ||
| 1230 | |||
| 1231 | func = HV_FAST_MMU_TSB_CTX0; | ||
| 1232 | arg0 = 2; | ||
| 1233 | arg1 = pa; | ||
| 1234 | __asm__ __volatile__("ta %6" | ||
| 1235 | : "=&r" (func), "=&r" (arg0), "=&r" (arg1) | ||
| 1236 | : "0" (func), "1" (arg0), "2" (arg1), | ||
| 1237 | "i" (HV_FAST_TRAP)); | ||
| 1238 | } | ||
| 1239 | |||
| 1442 | /* paging_init() sets up the page tables */ | 1240 | /* paging_init() sets up the page tables */ |
| 1443 | 1241 | ||
| 1444 | extern void cheetah_ecache_flush_init(void); | 1242 | extern void cheetah_ecache_flush_init(void); |
| 1243 | extern void sun4v_patch_tlb_handlers(void); | ||
| 1445 | 1244 | ||
| 1446 | static unsigned long last_valid_pfn; | 1245 | static unsigned long last_valid_pfn; |
| 1447 | pgd_t swapper_pg_dir[2048]; | 1246 | pgd_t swapper_pg_dir[2048]; |
| 1448 | 1247 | ||
| 1248 | static void sun4u_pgprot_init(void); | ||
| 1249 | static void sun4v_pgprot_init(void); | ||
| 1250 | |||
| 1449 | void __init paging_init(void) | 1251 | void __init paging_init(void) |
| 1450 | { | 1252 | { |
| 1451 | unsigned long end_pfn, pages_avail, shift; | 1253 | unsigned long end_pfn, pages_avail, shift, phys_base; |
| 1452 | unsigned long real_end, i; | 1254 | unsigned long real_end, i; |
| 1453 | 1255 | ||
| 1256 | kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; | ||
| 1257 | kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; | ||
| 1258 | |||
| 1259 | /* Invalidate both kernel TSBs. */ | ||
| 1260 | memset(swapper_tsb, 0x40, sizeof(swapper_tsb)); | ||
| 1261 | memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb)); | ||
| 1262 | |||
| 1263 | if (tlb_type == hypervisor) | ||
| 1264 | sun4v_pgprot_init(); | ||
| 1265 | else | ||
| 1266 | sun4u_pgprot_init(); | ||
| 1267 | |||
| 1268 | if (tlb_type == cheetah_plus || | ||
| 1269 | tlb_type == hypervisor) | ||
| 1270 | tsb_phys_patch(); | ||
| 1271 | |||
| 1272 | if (tlb_type == hypervisor) { | ||
| 1273 | sun4v_patch_tlb_handlers(); | ||
| 1274 | sun4v_ktsb_init(); | ||
| 1275 | } | ||
| 1276 | |||
| 1454 | /* Find available physical memory... */ | 1277 | /* Find available physical memory... */ |
| 1455 | read_obp_memory("available", &pavail[0], &pavail_ents); | 1278 | read_obp_memory("available", &pavail[0], &pavail_ents); |
| 1456 | 1279 | ||
| @@ -1458,11 +1281,6 @@ void __init paging_init(void) | |||
| 1458 | for (i = 0; i < pavail_ents; i++) | 1281 | for (i = 0; i < pavail_ents; i++) |
| 1459 | phys_base = min(phys_base, pavail[i].phys_addr); | 1282 | phys_base = min(phys_base, pavail[i].phys_addr); |
| 1460 | 1283 | ||
| 1461 | pfn_base = phys_base >> PAGE_SHIFT; | ||
| 1462 | |||
| 1463 | kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; | ||
| 1464 | kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; | ||
| 1465 | |||
| 1466 | set_bit(0, mmu_context_bmap); | 1284 | set_bit(0, mmu_context_bmap); |
| 1467 | 1285 | ||
| 1468 | shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE); | 1286 | shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE); |
| @@ -1486,47 +1304,38 @@ void __init paging_init(void) | |||
| 1486 | pud_set(pud_offset(&swapper_pg_dir[0], 0), | 1304 | pud_set(pud_offset(&swapper_pg_dir[0], 0), |
| 1487 | swapper_low_pmd_dir + (shift / sizeof(pgd_t))); | 1305 | swapper_low_pmd_dir + (shift / sizeof(pgd_t))); |
| 1488 | 1306 | ||
| 1489 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); | ||
| 1490 | |||
| 1491 | inherit_prom_mappings(); | 1307 | inherit_prom_mappings(); |
| 1492 | 1308 | ||
| 1493 | /* Ok, we can use our TLB miss and window trap handlers safely. | 1309 | /* Ok, we can use our TLB miss and window trap handlers safely. */ |
| 1494 | * We need to do a quick peek here to see if we are on StarFire | 1310 | setup_tba(); |
| 1495 | * or not, so setup_tba can setup the IRQ globals correctly (it | ||
| 1496 | * needs to get the hard smp processor id correctly). | ||
| 1497 | */ | ||
| 1498 | { | ||
| 1499 | extern void setup_tba(int); | ||
| 1500 | setup_tba(this_is_starfire); | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | inherit_locked_prom_mappings(1); | ||
| 1504 | 1311 | ||
| 1505 | __flush_tlb_all(); | 1312 | __flush_tlb_all(); |
| 1506 | 1313 | ||
| 1314 | if (tlb_type == hypervisor) | ||
| 1315 | sun4v_ktsb_register(); | ||
| 1316 | |||
| 1507 | /* Setup bootmem... */ | 1317 | /* Setup bootmem... */ |
| 1508 | pages_avail = 0; | 1318 | pages_avail = 0; |
| 1509 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); | 1319 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail, phys_base); |
| 1320 | |||
| 1321 | max_mapnr = last_valid_pfn; | ||
| 1510 | 1322 | ||
| 1511 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 1512 | kernel_physical_mapping_init(); | 1323 | kernel_physical_mapping_init(); |
| 1513 | #endif | ||
| 1514 | 1324 | ||
| 1515 | { | 1325 | { |
| 1516 | unsigned long zones_size[MAX_NR_ZONES]; | 1326 | unsigned long zones_size[MAX_NR_ZONES]; |
| 1517 | unsigned long zholes_size[MAX_NR_ZONES]; | 1327 | unsigned long zholes_size[MAX_NR_ZONES]; |
| 1518 | unsigned long npages; | ||
| 1519 | int znum; | 1328 | int znum; |
| 1520 | 1329 | ||
| 1521 | for (znum = 0; znum < MAX_NR_ZONES; znum++) | 1330 | for (znum = 0; znum < MAX_NR_ZONES; znum++) |
| 1522 | zones_size[znum] = zholes_size[znum] = 0; | 1331 | zones_size[znum] = zholes_size[znum] = 0; |
| 1523 | 1332 | ||
| 1524 | npages = end_pfn - pfn_base; | 1333 | zones_size[ZONE_DMA] = end_pfn; |
| 1525 | zones_size[ZONE_DMA] = npages; | 1334 | zholes_size[ZONE_DMA] = end_pfn - pages_avail; |
| 1526 | zholes_size[ZONE_DMA] = npages - pages_avail; | ||
| 1527 | 1335 | ||
| 1528 | free_area_init_node(0, &contig_page_data, zones_size, | 1336 | free_area_init_node(0, &contig_page_data, zones_size, |
| 1529 | phys_base >> PAGE_SHIFT, zholes_size); | 1337 | __pa(PAGE_OFFSET) >> PAGE_SHIFT, |
| 1338 | zholes_size); | ||
| 1530 | } | 1339 | } |
| 1531 | 1340 | ||
| 1532 | device_scan(); | 1341 | device_scan(); |
| @@ -1596,7 +1405,6 @@ void __init mem_init(void) | |||
| 1596 | 1405 | ||
| 1597 | taint_real_pages(); | 1406 | taint_real_pages(); |
| 1598 | 1407 | ||
| 1599 | max_mapnr = last_valid_pfn - pfn_base; | ||
| 1600 | high_memory = __va(last_valid_pfn << PAGE_SHIFT); | 1408 | high_memory = __va(last_valid_pfn << PAGE_SHIFT); |
| 1601 | 1409 | ||
| 1602 | #ifdef CONFIG_DEBUG_BOOTMEM | 1410 | #ifdef CONFIG_DEBUG_BOOTMEM |
| @@ -1676,3 +1484,342 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
| 1676 | } | 1484 | } |
| 1677 | } | 1485 | } |
| 1678 | #endif | 1486 | #endif |
| 1487 | |||
| 1488 | #define _PAGE_CACHE_4U (_PAGE_CP_4U | _PAGE_CV_4U) | ||
| 1489 | #define _PAGE_CACHE_4V (_PAGE_CP_4V | _PAGE_CV_4V) | ||
| 1490 | #define __DIRTY_BITS_4U (_PAGE_MODIFIED_4U | _PAGE_WRITE_4U | _PAGE_W_4U) | ||
| 1491 | #define __DIRTY_BITS_4V (_PAGE_MODIFIED_4V | _PAGE_WRITE_4V | _PAGE_W_4V) | ||
| 1492 | #define __ACCESS_BITS_4U (_PAGE_ACCESSED_4U | _PAGE_READ_4U | _PAGE_R) | ||
| 1493 | #define __ACCESS_BITS_4V (_PAGE_ACCESSED_4V | _PAGE_READ_4V | _PAGE_R) | ||
| 1494 | |||
| 1495 | pgprot_t PAGE_KERNEL __read_mostly; | ||
| 1496 | EXPORT_SYMBOL(PAGE_KERNEL); | ||
| 1497 | |||
| 1498 | pgprot_t PAGE_KERNEL_LOCKED __read_mostly; | ||
| 1499 | pgprot_t PAGE_COPY __read_mostly; | ||
| 1500 | |||
| 1501 | pgprot_t PAGE_SHARED __read_mostly; | ||
| 1502 | EXPORT_SYMBOL(PAGE_SHARED); | ||
| 1503 | |||
| 1504 | pgprot_t PAGE_EXEC __read_mostly; | ||
| 1505 | unsigned long pg_iobits __read_mostly; | ||
| 1506 | |||
| 1507 | unsigned long _PAGE_IE __read_mostly; | ||
| 1508 | |||
| 1509 | unsigned long _PAGE_E __read_mostly; | ||
| 1510 | EXPORT_SYMBOL(_PAGE_E); | ||
| 1511 | |||
| 1512 | unsigned long _PAGE_CACHE __read_mostly; | ||
| 1513 | EXPORT_SYMBOL(_PAGE_CACHE); | ||
| 1514 | |||
| 1515 | static void prot_init_common(unsigned long page_none, | ||
| 1516 | unsigned long page_shared, | ||
| 1517 | unsigned long page_copy, | ||
| 1518 | unsigned long page_readonly, | ||
| 1519 | unsigned long page_exec_bit) | ||
| 1520 | { | ||
| 1521 | PAGE_COPY = __pgprot(page_copy); | ||
| 1522 | PAGE_SHARED = __pgprot(page_shared); | ||
| 1523 | |||
| 1524 | protection_map[0x0] = __pgprot(page_none); | ||
| 1525 | protection_map[0x1] = __pgprot(page_readonly & ~page_exec_bit); | ||
| 1526 | protection_map[0x2] = __pgprot(page_copy & ~page_exec_bit); | ||
| 1527 | protection_map[0x3] = __pgprot(page_copy & ~page_exec_bit); | ||
| 1528 | protection_map[0x4] = __pgprot(page_readonly); | ||
| 1529 | protection_map[0x5] = __pgprot(page_readonly); | ||
| 1530 | protection_map[0x6] = __pgprot(page_copy); | ||
| 1531 | protection_map[0x7] = __pgprot(page_copy); | ||
| 1532 | protection_map[0x8] = __pgprot(page_none); | ||
| 1533 | protection_map[0x9] = __pgprot(page_readonly & ~page_exec_bit); | ||
| 1534 | protection_map[0xa] = __pgprot(page_shared & ~page_exec_bit); | ||
| 1535 | protection_map[0xb] = __pgprot(page_shared & ~page_exec_bit); | ||
| 1536 | protection_map[0xc] = __pgprot(page_readonly); | ||
| 1537 | protection_map[0xd] = __pgprot(page_readonly); | ||
| 1538 | protection_map[0xe] = __pgprot(page_shared); | ||
| 1539 | protection_map[0xf] = __pgprot(page_shared); | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | static void __init sun4u_pgprot_init(void) | ||
| 1543 | { | ||
| 1544 | unsigned long page_none, page_shared, page_copy, page_readonly; | ||
| 1545 | unsigned long page_exec_bit; | ||
| 1546 | |||
| 1547 | PAGE_KERNEL = __pgprot (_PAGE_PRESENT_4U | _PAGE_VALID | | ||
| 1548 | _PAGE_CACHE_4U | _PAGE_P_4U | | ||
| 1549 | __ACCESS_BITS_4U | __DIRTY_BITS_4U | | ||
| 1550 | _PAGE_EXEC_4U); | ||
| 1551 | PAGE_KERNEL_LOCKED = __pgprot (_PAGE_PRESENT_4U | _PAGE_VALID | | ||
| 1552 | _PAGE_CACHE_4U | _PAGE_P_4U | | ||
| 1553 | __ACCESS_BITS_4U | __DIRTY_BITS_4U | | ||
| 1554 | _PAGE_EXEC_4U | _PAGE_L_4U); | ||
| 1555 | PAGE_EXEC = __pgprot(_PAGE_EXEC_4U); | ||
| 1556 | |||
| 1557 | _PAGE_IE = _PAGE_IE_4U; | ||
| 1558 | _PAGE_E = _PAGE_E_4U; | ||
| 1559 | _PAGE_CACHE = _PAGE_CACHE_4U; | ||
| 1560 | |||
| 1561 | pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4U | __DIRTY_BITS_4U | | ||
| 1562 | __ACCESS_BITS_4U | _PAGE_E_4U); | ||
| 1563 | |||
| 1564 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^ | ||
| 1565 | 0xfffff80000000000; | ||
| 1566 | kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U | | ||
| 1567 | _PAGE_P_4U | _PAGE_W_4U); | ||
| 1568 | |||
| 1569 | /* XXX Should use 256MB on Panther. XXX */ | ||
| 1570 | kern_linear_pte_xor[1] = kern_linear_pte_xor[0]; | ||
| 1571 | |||
| 1572 | _PAGE_SZBITS = _PAGE_SZBITS_4U; | ||
| 1573 | _PAGE_ALL_SZ_BITS = (_PAGE_SZ4MB_4U | _PAGE_SZ512K_4U | | ||
| 1574 | _PAGE_SZ64K_4U | _PAGE_SZ8K_4U | | ||
| 1575 | _PAGE_SZ32MB_4U | _PAGE_SZ256MB_4U); | ||
| 1576 | |||
| 1577 | |||
| 1578 | page_none = _PAGE_PRESENT_4U | _PAGE_ACCESSED_4U | _PAGE_CACHE_4U; | ||
| 1579 | page_shared = (_PAGE_VALID | _PAGE_PRESENT_4U | _PAGE_CACHE_4U | | ||
| 1580 | __ACCESS_BITS_4U | _PAGE_WRITE_4U | _PAGE_EXEC_4U); | ||
| 1581 | page_copy = (_PAGE_VALID | _PAGE_PRESENT_4U | _PAGE_CACHE_4U | | ||
| 1582 | __ACCESS_BITS_4U | _PAGE_EXEC_4U); | ||
| 1583 | page_readonly = (_PAGE_VALID | _PAGE_PRESENT_4U | _PAGE_CACHE_4U | | ||
| 1584 | __ACCESS_BITS_4U | _PAGE_EXEC_4U); | ||
| 1585 | |||
| 1586 | page_exec_bit = _PAGE_EXEC_4U; | ||
| 1587 | |||
| 1588 | prot_init_common(page_none, page_shared, page_copy, page_readonly, | ||
| 1589 | page_exec_bit); | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | static void __init sun4v_pgprot_init(void) | ||
| 1593 | { | ||
| 1594 | unsigned long page_none, page_shared, page_copy, page_readonly; | ||
| 1595 | unsigned long page_exec_bit; | ||
| 1596 | |||
| 1597 | PAGE_KERNEL = __pgprot (_PAGE_PRESENT_4V | _PAGE_VALID | | ||
| 1598 | _PAGE_CACHE_4V | _PAGE_P_4V | | ||
| 1599 | __ACCESS_BITS_4V | __DIRTY_BITS_4V | | ||
| 1600 | _PAGE_EXEC_4V); | ||
| 1601 | PAGE_KERNEL_LOCKED = PAGE_KERNEL; | ||
| 1602 | PAGE_EXEC = __pgprot(_PAGE_EXEC_4V); | ||
| 1603 | |||
| 1604 | _PAGE_IE = _PAGE_IE_4V; | ||
| 1605 | _PAGE_E = _PAGE_E_4V; | ||
| 1606 | _PAGE_CACHE = _PAGE_CACHE_4V; | ||
| 1607 | |||
| 1608 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^ | ||
| 1609 | 0xfffff80000000000; | ||
| 1610 | kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V | | ||
| 1611 | _PAGE_P_4V | _PAGE_W_4V); | ||
| 1612 | |||
| 1613 | kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^ | ||
| 1614 | 0xfffff80000000000; | ||
| 1615 | kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V | | ||
| 1616 | _PAGE_P_4V | _PAGE_W_4V); | ||
| 1617 | |||
| 1618 | pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4V | __DIRTY_BITS_4V | | ||
| 1619 | __ACCESS_BITS_4V | _PAGE_E_4V); | ||
| 1620 | |||
| 1621 | _PAGE_SZBITS = _PAGE_SZBITS_4V; | ||
| 1622 | _PAGE_ALL_SZ_BITS = (_PAGE_SZ16GB_4V | _PAGE_SZ2GB_4V | | ||
| 1623 | _PAGE_SZ256MB_4V | _PAGE_SZ32MB_4V | | ||
| 1624 | _PAGE_SZ4MB_4V | _PAGE_SZ512K_4V | | ||
| 1625 | _PAGE_SZ64K_4V | _PAGE_SZ8K_4V); | ||
| 1626 | |||
| 1627 | page_none = _PAGE_PRESENT_4V | _PAGE_ACCESSED_4V | _PAGE_CACHE_4V; | ||
| 1628 | page_shared = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V | | ||
| 1629 | __ACCESS_BITS_4V | _PAGE_WRITE_4V | _PAGE_EXEC_4V); | ||
| 1630 | page_copy = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V | | ||
| 1631 | __ACCESS_BITS_4V | _PAGE_EXEC_4V); | ||
| 1632 | page_readonly = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V | | ||
| 1633 | __ACCESS_BITS_4V | _PAGE_EXEC_4V); | ||
| 1634 | |||
| 1635 | page_exec_bit = _PAGE_EXEC_4V; | ||
| 1636 | |||
| 1637 | prot_init_common(page_none, page_shared, page_copy, page_readonly, | ||
| 1638 | page_exec_bit); | ||
| 1639 | } | ||
| 1640 | |||
| 1641 | unsigned long pte_sz_bits(unsigned long sz) | ||
| 1642 | { | ||
| 1643 | if (tlb_type == hypervisor) { | ||
| 1644 | switch (sz) { | ||
| 1645 | case 8 * 1024: | ||
| 1646 | default: | ||
| 1647 | return _PAGE_SZ8K_4V; | ||
| 1648 | case 64 * 1024: | ||
| 1649 | return _PAGE_SZ64K_4V; | ||
| 1650 | case 512 * 1024: | ||
| 1651 | return _PAGE_SZ512K_4V; | ||
| 1652 | case 4 * 1024 * 1024: | ||
| 1653 | return _PAGE_SZ4MB_4V; | ||
| 1654 | }; | ||
| 1655 | } else { | ||
| 1656 | switch (sz) { | ||
| 1657 | case 8 * 1024: | ||
| 1658 | default: | ||
| 1659 | return _PAGE_SZ8K_4U; | ||
| 1660 | case 64 * 1024: | ||
| 1661 | return _PAGE_SZ64K_4U; | ||
| 1662 | case 512 * 1024: | ||
| 1663 | return _PAGE_SZ512K_4U; | ||
| 1664 | case 4 * 1024 * 1024: | ||
| 1665 | return _PAGE_SZ4MB_4U; | ||
| 1666 | }; | ||
| 1667 | } | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space, unsigned long page_size) | ||
| 1671 | { | ||
| 1672 | pte_t pte; | ||
| 1673 | |||
| 1674 | pte_val(pte) = page | pgprot_val(pgprot_noncached(prot)); | ||
| 1675 | pte_val(pte) |= (((unsigned long)space) << 32); | ||
| 1676 | pte_val(pte) |= pte_sz_bits(page_size); | ||
| 1677 | |||
| 1678 | return pte; | ||
| 1679 | } | ||
| 1680 | |||
| 1681 | static unsigned long kern_large_tte(unsigned long paddr) | ||
| 1682 | { | ||
| 1683 | unsigned long val; | ||
| 1684 | |||
| 1685 | val = (_PAGE_VALID | _PAGE_SZ4MB_4U | | ||
| 1686 | _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_P_4U | | ||
| 1687 | _PAGE_EXEC_4U | _PAGE_L_4U | _PAGE_W_4U); | ||
| 1688 | if (tlb_type == hypervisor) | ||
| 1689 | val = (_PAGE_VALID | _PAGE_SZ4MB_4V | | ||
| 1690 | _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_P_4V | | ||
| 1691 | _PAGE_EXEC_4V | _PAGE_W_4V); | ||
| 1692 | |||
| 1693 | return val | paddr; | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | /* | ||
| 1697 | * Translate PROM's mapping we capture at boot time into physical address. | ||
| 1698 | * The second parameter is only set from prom_callback() invocations. | ||
| 1699 | */ | ||
| 1700 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) | ||
| 1701 | { | ||
| 1702 | unsigned long mask; | ||
| 1703 | int i; | ||
| 1704 | |||
| 1705 | mask = _PAGE_PADDR_4U; | ||
| 1706 | if (tlb_type == hypervisor) | ||
| 1707 | mask = _PAGE_PADDR_4V; | ||
| 1708 | |||
| 1709 | for (i = 0; i < prom_trans_ents; i++) { | ||
| 1710 | struct linux_prom_translation *p = &prom_trans[i]; | ||
| 1711 | |||
| 1712 | if (promva >= p->virt && | ||
| 1713 | promva < (p->virt + p->size)) { | ||
| 1714 | unsigned long base = p->data & mask; | ||
| 1715 | |||
| 1716 | if (error) | ||
| 1717 | *error = 0; | ||
| 1718 | return base + (promva & (8192 - 1)); | ||
| 1719 | } | ||
| 1720 | } | ||
| 1721 | if (error) | ||
| 1722 | *error = 1; | ||
| 1723 | return 0UL; | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | /* XXX We should kill off this ugly thing at so me point. XXX */ | ||
| 1727 | unsigned long sun4u_get_pte(unsigned long addr) | ||
| 1728 | { | ||
| 1729 | pgd_t *pgdp; | ||
| 1730 | pud_t *pudp; | ||
| 1731 | pmd_t *pmdp; | ||
| 1732 | pte_t *ptep; | ||
| 1733 | unsigned long mask = _PAGE_PADDR_4U; | ||
| 1734 | |||
| 1735 | if (tlb_type == hypervisor) | ||
| 1736 | mask = _PAGE_PADDR_4V; | ||
| 1737 | |||
| 1738 | if (addr >= PAGE_OFFSET) | ||
| 1739 | return addr & mask; | ||
| 1740 | |||
| 1741 | if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) | ||
| 1742 | return prom_virt_to_phys(addr, NULL); | ||
| 1743 | |||
| 1744 | pgdp = pgd_offset_k(addr); | ||
| 1745 | pudp = pud_offset(pgdp, addr); | ||
| 1746 | pmdp = pmd_offset(pudp, addr); | ||
| 1747 | ptep = pte_offset_kernel(pmdp, addr); | ||
| 1748 | |||
| 1749 | return pte_val(*ptep) & mask; | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | /* If not locked, zap it. */ | ||
| 1753 | void __flush_tlb_all(void) | ||
| 1754 | { | ||
| 1755 | unsigned long pstate; | ||
| 1756 | int i; | ||
| 1757 | |||
| 1758 | __asm__ __volatile__("flushw\n\t" | ||
| 1759 | "rdpr %%pstate, %0\n\t" | ||
| 1760 | "wrpr %0, %1, %%pstate" | ||
| 1761 | : "=r" (pstate) | ||
| 1762 | : "i" (PSTATE_IE)); | ||
| 1763 | if (tlb_type == spitfire) { | ||
| 1764 | for (i = 0; i < 64; i++) { | ||
| 1765 | /* Spitfire Errata #32 workaround */ | ||
| 1766 | /* NOTE: Always runs on spitfire, so no | ||
| 1767 | * cheetah+ page size encodings. | ||
| 1768 | */ | ||
| 1769 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 1770 | "flush %%g6" | ||
| 1771 | : /* No outputs */ | ||
| 1772 | : "r" (0), | ||
| 1773 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 1774 | |||
| 1775 | if (!(spitfire_get_dtlb_data(i) & _PAGE_L_4U)) { | ||
| 1776 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 1777 | "membar #Sync" | ||
| 1778 | : /* no outputs */ | ||
| 1779 | : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
| 1780 | spitfire_put_dtlb_data(i, 0x0UL); | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | /* Spitfire Errata #32 workaround */ | ||
| 1784 | /* NOTE: Always runs on spitfire, so no | ||
| 1785 | * cheetah+ page size encodings. | ||
| 1786 | */ | ||
| 1787 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 1788 | "flush %%g6" | ||
| 1789 | : /* No outputs */ | ||
| 1790 | : "r" (0), | ||
| 1791 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 1792 | |||
| 1793 | if (!(spitfire_get_itlb_data(i) & _PAGE_L_4U)) { | ||
| 1794 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
| 1795 | "membar #Sync" | ||
| 1796 | : /* no outputs */ | ||
| 1797 | : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); | ||
| 1798 | spitfire_put_itlb_data(i, 0x0UL); | ||
| 1799 | } | ||
| 1800 | } | ||
| 1801 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
| 1802 | cheetah_flush_dtlb_all(); | ||
| 1803 | cheetah_flush_itlb_all(); | ||
| 1804 | } | ||
| 1805 | __asm__ __volatile__("wrpr %0, 0, %%pstate" | ||
| 1806 | : : "r" (pstate)); | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
| 1810 | |||
| 1811 | void online_page(struct page *page) | ||
| 1812 | { | ||
| 1813 | ClearPageReserved(page); | ||
| 1814 | set_page_count(page, 0); | ||
| 1815 | free_cold_page(page); | ||
| 1816 | totalram_pages++; | ||
| 1817 | num_physpages++; | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | int remove_memory(u64 start, u64 size) | ||
| 1821 | { | ||
| 1822 | return -EINVAL; | ||
| 1823 | } | ||
| 1824 | |||
| 1825 | #endif /* CONFIG_MEMORY_HOTPLUG */ | ||
diff --git a/arch/sparc64/mm/tlb.c b/arch/sparc64/mm/tlb.c index 8b104be4662b..a079cf42505e 100644 --- a/arch/sparc64/mm/tlb.c +++ b/arch/sparc64/mm/tlb.c | |||
| @@ -25,6 +25,8 @@ void flush_tlb_pending(void) | |||
| 25 | struct mmu_gather *mp = &__get_cpu_var(mmu_gathers); | 25 | struct mmu_gather *mp = &__get_cpu_var(mmu_gathers); |
| 26 | 26 | ||
| 27 | if (mp->tlb_nr) { | 27 | if (mp->tlb_nr) { |
| 28 | flush_tsb_user(mp); | ||
| 29 | |||
| 28 | if (CTX_VALID(mp->mm->context)) { | 30 | if (CTX_VALID(mp->mm->context)) { |
| 29 | #ifdef CONFIG_SMP | 31 | #ifdef CONFIG_SMP |
| 30 | smp_flush_tlb_pending(mp->mm, mp->tlb_nr, | 32 | smp_flush_tlb_pending(mp->mm, mp->tlb_nr, |
| @@ -47,7 +49,8 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t | |||
| 47 | if (pte_exec(orig)) | 49 | if (pte_exec(orig)) |
| 48 | vaddr |= 0x1UL; | 50 | vaddr |= 0x1UL; |
| 49 | 51 | ||
| 50 | if (pte_dirty(orig)) { | 52 | if (tlb_type != hypervisor && |
| 53 | pte_dirty(orig)) { | ||
| 51 | unsigned long paddr, pfn = pte_pfn(orig); | 54 | unsigned long paddr, pfn = pte_pfn(orig); |
| 52 | struct address_space *mapping; | 55 | struct address_space *mapping; |
| 53 | struct page *page; | 56 | struct page *page; |
| @@ -89,62 +92,3 @@ no_cache_flush: | |||
| 89 | if (nr >= TLB_BATCH_NR) | 92 | if (nr >= TLB_BATCH_NR) |
| 90 | flush_tlb_pending(); | 93 | flush_tlb_pending(); |
| 91 | } | 94 | } |
| 92 | |||
| 93 | void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) | ||
| 94 | { | ||
| 95 | struct mmu_gather *mp = &__get_cpu_var(mmu_gathers); | ||
| 96 | unsigned long nr = mp->tlb_nr; | ||
| 97 | long s = start, e = end, vpte_base; | ||
| 98 | |||
| 99 | if (mp->fullmm) | ||
| 100 | return; | ||
| 101 | |||
| 102 | /* If start is greater than end, that is a real problem. */ | ||
| 103 | BUG_ON(start > end); | ||
| 104 | |||
| 105 | /* However, straddling the VA space hole is quite normal. */ | ||
| 106 | s &= PMD_MASK; | ||
| 107 | e = (e + PMD_SIZE - 1) & PMD_MASK; | ||
| 108 | |||
| 109 | vpte_base = (tlb_type == spitfire ? | ||
| 110 | VPTE_BASE_SPITFIRE : | ||
| 111 | VPTE_BASE_CHEETAH); | ||
| 112 | |||
| 113 | if (unlikely(nr != 0 && mm != mp->mm)) { | ||
| 114 | flush_tlb_pending(); | ||
| 115 | nr = 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | if (nr == 0) | ||
| 119 | mp->mm = mm; | ||
| 120 | |||
| 121 | start = vpte_base + (s >> (PAGE_SHIFT - 3)); | ||
| 122 | end = vpte_base + (e >> (PAGE_SHIFT - 3)); | ||
| 123 | |||
| 124 | /* If the request straddles the VA space hole, we | ||
| 125 | * need to swap start and end. The reason this | ||
| 126 | * occurs is that "vpte_base" is the center of | ||
| 127 | * the linear page table mapping area. Thus, | ||
| 128 | * high addresses with the sign bit set map to | ||
| 129 | * addresses below vpte_base and non-sign bit | ||
| 130 | * addresses map to addresses above vpte_base. | ||
| 131 | */ | ||
| 132 | if (end < start) { | ||
| 133 | unsigned long tmp = start; | ||
| 134 | |||
| 135 | start = end; | ||
| 136 | end = tmp; | ||
| 137 | } | ||
| 138 | |||
| 139 | while (start < end) { | ||
| 140 | mp->vaddrs[nr] = start; | ||
| 141 | mp->tlb_nr = ++nr; | ||
| 142 | if (nr >= TLB_BATCH_NR) { | ||
| 143 | flush_tlb_pending(); | ||
| 144 | nr = 0; | ||
| 145 | } | ||
| 146 | start += PAGE_SIZE; | ||
| 147 | } | ||
| 148 | if (nr) | ||
| 149 | flush_tlb_pending(); | ||
| 150 | } | ||
diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c new file mode 100644 index 000000000000..b2064e2a44d6 --- /dev/null +++ b/arch/sparc64/mm/tsb.c | |||
| @@ -0,0 +1,440 @@ | |||
| 1 | /* arch/sparc64/mm/tsb.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <asm/system.h> | ||
| 8 | #include <asm/page.h> | ||
| 9 | #include <asm/tlbflush.h> | ||
| 10 | #include <asm/tlb.h> | ||
| 11 | #include <asm/mmu_context.h> | ||
| 12 | #include <asm/pgtable.h> | ||
| 13 | #include <asm/tsb.h> | ||
| 14 | #include <asm/oplib.h> | ||
| 15 | |||
| 16 | extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES]; | ||
| 17 | |||
| 18 | static inline unsigned long tsb_hash(unsigned long vaddr, unsigned long nentries) | ||
| 19 | { | ||
| 20 | vaddr >>= PAGE_SHIFT; | ||
| 21 | return vaddr & (nentries - 1); | ||
| 22 | } | ||
| 23 | |||
| 24 | static inline int tag_compare(unsigned long tag, unsigned long vaddr) | ||
| 25 | { | ||
| 26 | return (tag == (vaddr >> 22)); | ||
| 27 | } | ||
| 28 | |||
| 29 | /* TSB flushes need only occur on the processor initiating the address | ||
| 30 | * space modification, not on each cpu the address space has run on. | ||
| 31 | * Only the TLB flush needs that treatment. | ||
| 32 | */ | ||
| 33 | |||
| 34 | void flush_tsb_kernel_range(unsigned long start, unsigned long end) | ||
| 35 | { | ||
| 36 | unsigned long v; | ||
| 37 | |||
| 38 | for (v = start; v < end; v += PAGE_SIZE) { | ||
| 39 | unsigned long hash = tsb_hash(v, KERNEL_TSB_NENTRIES); | ||
| 40 | struct tsb *ent = &swapper_tsb[hash]; | ||
| 41 | |||
| 42 | if (tag_compare(ent->tag, v)) { | ||
| 43 | ent->tag = (1UL << TSB_TAG_INVALID_BIT); | ||
| 44 | membar_storeload_storestore(); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | void flush_tsb_user(struct mmu_gather *mp) | ||
| 50 | { | ||
| 51 | struct mm_struct *mm = mp->mm; | ||
| 52 | unsigned long nentries, base, flags; | ||
| 53 | struct tsb *tsb; | ||
| 54 | int i; | ||
| 55 | |||
| 56 | spin_lock_irqsave(&mm->context.lock, flags); | ||
| 57 | |||
| 58 | tsb = mm->context.tsb; | ||
| 59 | nentries = mm->context.tsb_nentries; | ||
| 60 | |||
| 61 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) | ||
| 62 | base = __pa(tsb); | ||
| 63 | else | ||
| 64 | base = (unsigned long) tsb; | ||
| 65 | |||
| 66 | for (i = 0; i < mp->tlb_nr; i++) { | ||
| 67 | unsigned long v = mp->vaddrs[i]; | ||
| 68 | unsigned long tag, ent, hash; | ||
| 69 | |||
| 70 | v &= ~0x1UL; | ||
| 71 | |||
| 72 | hash = tsb_hash(v, nentries); | ||
| 73 | ent = base + (hash * sizeof(struct tsb)); | ||
| 74 | tag = (v >> 22UL); | ||
| 75 | |||
| 76 | tsb_flush(ent, tag); | ||
| 77 | } | ||
| 78 | |||
| 79 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_bytes) | ||
| 83 | { | ||
| 84 | unsigned long tsb_reg, base, tsb_paddr; | ||
| 85 | unsigned long page_sz, tte; | ||
| 86 | |||
| 87 | mm->context.tsb_nentries = tsb_bytes / sizeof(struct tsb); | ||
| 88 | |||
| 89 | base = TSBMAP_BASE; | ||
| 90 | tte = pgprot_val(PAGE_KERNEL_LOCKED); | ||
| 91 | tsb_paddr = __pa(mm->context.tsb); | ||
| 92 | BUG_ON(tsb_paddr & (tsb_bytes - 1UL)); | ||
| 93 | |||
| 94 | /* Use the smallest page size that can map the whole TSB | ||
| 95 | * in one TLB entry. | ||
| 96 | */ | ||
| 97 | switch (tsb_bytes) { | ||
| 98 | case 8192 << 0: | ||
| 99 | tsb_reg = 0x0UL; | ||
| 100 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 101 | base += (tsb_paddr & 8192); | ||
| 102 | #endif | ||
| 103 | page_sz = 8192; | ||
| 104 | break; | ||
| 105 | |||
| 106 | case 8192 << 1: | ||
| 107 | tsb_reg = 0x1UL; | ||
| 108 | page_sz = 64 * 1024; | ||
| 109 | break; | ||
| 110 | |||
| 111 | case 8192 << 2: | ||
| 112 | tsb_reg = 0x2UL; | ||
| 113 | page_sz = 64 * 1024; | ||
| 114 | break; | ||
| 115 | |||
| 116 | case 8192 << 3: | ||
| 117 | tsb_reg = 0x3UL; | ||
| 118 | page_sz = 64 * 1024; | ||
| 119 | break; | ||
| 120 | |||
| 121 | case 8192 << 4: | ||
| 122 | tsb_reg = 0x4UL; | ||
| 123 | page_sz = 512 * 1024; | ||
| 124 | break; | ||
| 125 | |||
| 126 | case 8192 << 5: | ||
| 127 | tsb_reg = 0x5UL; | ||
| 128 | page_sz = 512 * 1024; | ||
| 129 | break; | ||
| 130 | |||
| 131 | case 8192 << 6: | ||
| 132 | tsb_reg = 0x6UL; | ||
| 133 | page_sz = 512 * 1024; | ||
| 134 | break; | ||
| 135 | |||
| 136 | case 8192 << 7: | ||
| 137 | tsb_reg = 0x7UL; | ||
| 138 | page_sz = 4 * 1024 * 1024; | ||
| 139 | break; | ||
| 140 | |||
| 141 | default: | ||
| 142 | BUG(); | ||
| 143 | }; | ||
| 144 | tte |= pte_sz_bits(page_sz); | ||
| 145 | |||
| 146 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) { | ||
| 147 | /* Physical mapping, no locked TLB entry for TSB. */ | ||
| 148 | tsb_reg |= tsb_paddr; | ||
| 149 | |||
| 150 | mm->context.tsb_reg_val = tsb_reg; | ||
| 151 | mm->context.tsb_map_vaddr = 0; | ||
| 152 | mm->context.tsb_map_pte = 0; | ||
| 153 | } else { | ||
| 154 | tsb_reg |= base; | ||
| 155 | tsb_reg |= (tsb_paddr & (page_sz - 1UL)); | ||
| 156 | tte |= (tsb_paddr & ~(page_sz - 1UL)); | ||
| 157 | |||
| 158 | mm->context.tsb_reg_val = tsb_reg; | ||
| 159 | mm->context.tsb_map_vaddr = base; | ||
| 160 | mm->context.tsb_map_pte = tte; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Setup the Hypervisor TSB descriptor. */ | ||
| 164 | if (tlb_type == hypervisor) { | ||
| 165 | struct hv_tsb_descr *hp = &mm->context.tsb_descr; | ||
| 166 | |||
| 167 | switch (PAGE_SIZE) { | ||
| 168 | case 8192: | ||
| 169 | default: | ||
| 170 | hp->pgsz_idx = HV_PGSZ_IDX_8K; | ||
| 171 | break; | ||
| 172 | |||
| 173 | case 64 * 1024: | ||
| 174 | hp->pgsz_idx = HV_PGSZ_IDX_64K; | ||
| 175 | break; | ||
| 176 | |||
| 177 | case 512 * 1024: | ||
| 178 | hp->pgsz_idx = HV_PGSZ_IDX_512K; | ||
| 179 | break; | ||
| 180 | |||
| 181 | case 4 * 1024 * 1024: | ||
| 182 | hp->pgsz_idx = HV_PGSZ_IDX_4MB; | ||
| 183 | break; | ||
| 184 | }; | ||
| 185 | hp->assoc = 1; | ||
| 186 | hp->num_ttes = tsb_bytes / 16; | ||
| 187 | hp->ctx_idx = 0; | ||
| 188 | switch (PAGE_SIZE) { | ||
| 189 | case 8192: | ||
| 190 | default: | ||
| 191 | hp->pgsz_mask = HV_PGSZ_MASK_8K; | ||
| 192 | break; | ||
| 193 | |||
| 194 | case 64 * 1024: | ||
| 195 | hp->pgsz_mask = HV_PGSZ_MASK_64K; | ||
| 196 | break; | ||
| 197 | |||
| 198 | case 512 * 1024: | ||
| 199 | hp->pgsz_mask = HV_PGSZ_MASK_512K; | ||
| 200 | break; | ||
| 201 | |||
| 202 | case 4 * 1024 * 1024: | ||
| 203 | hp->pgsz_mask = HV_PGSZ_MASK_4MB; | ||
| 204 | break; | ||
| 205 | }; | ||
| 206 | hp->tsb_base = tsb_paddr; | ||
| 207 | hp->resv = 0; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | static kmem_cache_t *tsb_caches[8] __read_mostly; | ||
| 212 | |||
| 213 | static const char *tsb_cache_names[8] = { | ||
| 214 | "tsb_8KB", | ||
| 215 | "tsb_16KB", | ||
| 216 | "tsb_32KB", | ||
| 217 | "tsb_64KB", | ||
| 218 | "tsb_128KB", | ||
| 219 | "tsb_256KB", | ||
| 220 | "tsb_512KB", | ||
| 221 | "tsb_1MB", | ||
| 222 | }; | ||
| 223 | |||
| 224 | void __init tsb_cache_init(void) | ||
| 225 | { | ||
| 226 | unsigned long i; | ||
| 227 | |||
| 228 | for (i = 0; i < 8; i++) { | ||
| 229 | unsigned long size = 8192 << i; | ||
| 230 | const char *name = tsb_cache_names[i]; | ||
| 231 | |||
| 232 | tsb_caches[i] = kmem_cache_create(name, | ||
| 233 | size, size, | ||
| 234 | SLAB_HWCACHE_ALIGN | | ||
| 235 | SLAB_MUST_HWCACHE_ALIGN, | ||
| 236 | NULL, NULL); | ||
| 237 | if (!tsb_caches[i]) { | ||
| 238 | prom_printf("Could not create %s cache\n", name); | ||
| 239 | prom_halt(); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | /* When the RSS of an address space exceeds mm->context.tsb_rss_limit, | ||
| 245 | * do_sparc64_fault() invokes this routine to try and grow the TSB. | ||
| 246 | * | ||
| 247 | * When we reach the maximum TSB size supported, we stick ~0UL into | ||
| 248 | * mm->context.tsb_rss_limit so the grow checks in update_mmu_cache() | ||
| 249 | * will not trigger any longer. | ||
| 250 | * | ||
| 251 | * The TSB can be anywhere from 8K to 1MB in size, in increasing powers | ||
| 252 | * of two. The TSB must be aligned to it's size, so f.e. a 512K TSB | ||
| 253 | * must be 512K aligned. It also must be physically contiguous, so we | ||
| 254 | * cannot use vmalloc(). | ||
| 255 | * | ||
| 256 | * The idea here is to grow the TSB when the RSS of the process approaches | ||
| 257 | * the number of entries that the current TSB can hold at once. Currently, | ||
| 258 | * we trigger when the RSS hits 3/4 of the TSB capacity. | ||
| 259 | */ | ||
| 260 | void tsb_grow(struct mm_struct *mm, unsigned long rss) | ||
| 261 | { | ||
| 262 | unsigned long max_tsb_size = 1 * 1024 * 1024; | ||
| 263 | unsigned long new_size, old_size, flags; | ||
| 264 | struct tsb *old_tsb, *new_tsb; | ||
| 265 | unsigned long new_cache_index, old_cache_index; | ||
| 266 | unsigned long new_rss_limit; | ||
| 267 | gfp_t gfp_flags; | ||
| 268 | |||
| 269 | if (max_tsb_size > (PAGE_SIZE << MAX_ORDER)) | ||
| 270 | max_tsb_size = (PAGE_SIZE << MAX_ORDER); | ||
| 271 | |||
| 272 | new_cache_index = 0; | ||
| 273 | for (new_size = 8192; new_size < max_tsb_size; new_size <<= 1UL) { | ||
| 274 | unsigned long n_entries = new_size / sizeof(struct tsb); | ||
| 275 | |||
| 276 | n_entries = (n_entries * 3) / 4; | ||
| 277 | if (n_entries > rss) | ||
| 278 | break; | ||
| 279 | |||
| 280 | new_cache_index++; | ||
| 281 | } | ||
| 282 | |||
| 283 | if (new_size == max_tsb_size) | ||
| 284 | new_rss_limit = ~0UL; | ||
| 285 | else | ||
| 286 | new_rss_limit = ((new_size / sizeof(struct tsb)) * 3) / 4; | ||
| 287 | |||
| 288 | retry_tsb_alloc: | ||
| 289 | gfp_flags = GFP_KERNEL; | ||
| 290 | if (new_size > (PAGE_SIZE * 2)) | ||
| 291 | gfp_flags = __GFP_NOWARN | __GFP_NORETRY; | ||
| 292 | |||
| 293 | new_tsb = kmem_cache_alloc(tsb_caches[new_cache_index], gfp_flags); | ||
| 294 | if (unlikely(!new_tsb)) { | ||
| 295 | /* Not being able to fork due to a high-order TSB | ||
| 296 | * allocation failure is very bad behavior. Just back | ||
| 297 | * down to a 0-order allocation and force no TSB | ||
| 298 | * growing for this address space. | ||
| 299 | */ | ||
| 300 | if (mm->context.tsb == NULL && new_cache_index > 0) { | ||
| 301 | new_cache_index = 0; | ||
| 302 | new_size = 8192; | ||
| 303 | new_rss_limit = ~0UL; | ||
| 304 | goto retry_tsb_alloc; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* If we failed on a TSB grow, we are under serious | ||
| 308 | * memory pressure so don't try to grow any more. | ||
| 309 | */ | ||
| 310 | if (mm->context.tsb != NULL) | ||
| 311 | mm->context.tsb_rss_limit = ~0UL; | ||
| 312 | return; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* Mark all tags as invalid. */ | ||
| 316 | tsb_init(new_tsb, new_size); | ||
| 317 | |||
| 318 | /* Ok, we are about to commit the changes. If we are | ||
| 319 | * growing an existing TSB the locking is very tricky, | ||
| 320 | * so WATCH OUT! | ||
| 321 | * | ||
| 322 | * We have to hold mm->context.lock while committing to the | ||
| 323 | * new TSB, this synchronizes us with processors in | ||
| 324 | * flush_tsb_user() and switch_mm() for this address space. | ||
| 325 | * | ||
| 326 | * But even with that lock held, processors run asynchronously | ||
| 327 | * accessing the old TSB via TLB miss handling. This is OK | ||
| 328 | * because those actions are just propagating state from the | ||
| 329 | * Linux page tables into the TSB, page table mappings are not | ||
| 330 | * being changed. If a real fault occurs, the processor will | ||
| 331 | * synchronize with us when it hits flush_tsb_user(), this is | ||
| 332 | * also true for the case where vmscan is modifying the page | ||
| 333 | * tables. The only thing we need to be careful with is to | ||
| 334 | * skip any locked TSB entries during copy_tsb(). | ||
| 335 | * | ||
| 336 | * When we finish committing to the new TSB, we have to drop | ||
| 337 | * the lock and ask all other cpus running this address space | ||
| 338 | * to run tsb_context_switch() to see the new TSB table. | ||
| 339 | */ | ||
| 340 | spin_lock_irqsave(&mm->context.lock, flags); | ||
| 341 | |||
| 342 | old_tsb = mm->context.tsb; | ||
| 343 | old_cache_index = (mm->context.tsb_reg_val & 0x7UL); | ||
| 344 | old_size = mm->context.tsb_nentries * sizeof(struct tsb); | ||
| 345 | |||
| 346 | |||
| 347 | /* Handle multiple threads trying to grow the TSB at the same time. | ||
| 348 | * One will get in here first, and bump the size and the RSS limit. | ||
| 349 | * The others will get in here next and hit this check. | ||
| 350 | */ | ||
| 351 | if (unlikely(old_tsb && (rss < mm->context.tsb_rss_limit))) { | ||
| 352 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 353 | |||
| 354 | kmem_cache_free(tsb_caches[new_cache_index], new_tsb); | ||
| 355 | return; | ||
| 356 | } | ||
| 357 | |||
| 358 | mm->context.tsb_rss_limit = new_rss_limit; | ||
| 359 | |||
| 360 | if (old_tsb) { | ||
| 361 | extern void copy_tsb(unsigned long old_tsb_base, | ||
| 362 | unsigned long old_tsb_size, | ||
| 363 | unsigned long new_tsb_base, | ||
| 364 | unsigned long new_tsb_size); | ||
| 365 | unsigned long old_tsb_base = (unsigned long) old_tsb; | ||
| 366 | unsigned long new_tsb_base = (unsigned long) new_tsb; | ||
| 367 | |||
| 368 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) { | ||
| 369 | old_tsb_base = __pa(old_tsb_base); | ||
| 370 | new_tsb_base = __pa(new_tsb_base); | ||
| 371 | } | ||
| 372 | copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size); | ||
| 373 | } | ||
| 374 | |||
| 375 | mm->context.tsb = new_tsb; | ||
| 376 | setup_tsb_params(mm, new_size); | ||
| 377 | |||
| 378 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 379 | |||
| 380 | /* If old_tsb is NULL, we're being invoked for the first time | ||
| 381 | * from init_new_context(). | ||
| 382 | */ | ||
| 383 | if (old_tsb) { | ||
| 384 | /* Reload it on the local cpu. */ | ||
| 385 | tsb_context_switch(mm); | ||
| 386 | |||
| 387 | /* Now force other processors to do the same. */ | ||
| 388 | smp_tsb_sync(mm); | ||
| 389 | |||
| 390 | /* Now it is safe to free the old tsb. */ | ||
| 391 | kmem_cache_free(tsb_caches[old_cache_index], old_tsb); | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
| 396 | { | ||
| 397 | spin_lock_init(&mm->context.lock); | ||
| 398 | |||
| 399 | mm->context.sparc64_ctx_val = 0UL; | ||
| 400 | |||
| 401 | /* copy_mm() copies over the parent's mm_struct before calling | ||
| 402 | * us, so we need to zero out the TSB pointer or else tsb_grow() | ||
| 403 | * will be confused and think there is an older TSB to free up. | ||
| 404 | */ | ||
| 405 | mm->context.tsb = NULL; | ||
| 406 | |||
| 407 | /* If this is fork, inherit the parent's TSB size. We would | ||
| 408 | * grow it to that size on the first page fault anyways. | ||
| 409 | */ | ||
| 410 | tsb_grow(mm, get_mm_rss(mm)); | ||
| 411 | |||
| 412 | if (unlikely(!mm->context.tsb)) | ||
| 413 | return -ENOMEM; | ||
| 414 | |||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | void destroy_context(struct mm_struct *mm) | ||
| 419 | { | ||
| 420 | unsigned long flags, cache_index; | ||
| 421 | |||
| 422 | cache_index = (mm->context.tsb_reg_val & 0x7UL); | ||
| 423 | kmem_cache_free(tsb_caches[cache_index], mm->context.tsb); | ||
| 424 | |||
| 425 | /* We can remove these later, but for now it's useful | ||
| 426 | * to catch any bogus post-destroy_context() references | ||
| 427 | * to the TSB. | ||
| 428 | */ | ||
| 429 | mm->context.tsb = NULL; | ||
| 430 | mm->context.tsb_reg_val = 0UL; | ||
| 431 | |||
| 432 | spin_lock_irqsave(&ctx_alloc_lock, flags); | ||
| 433 | |||
| 434 | if (CTX_VALID(mm->context)) { | ||
| 435 | unsigned long nr = CTX_NRBITS(mm->context); | ||
| 436 | mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63)); | ||
| 437 | } | ||
| 438 | |||
| 439 | spin_unlock_irqrestore(&ctx_alloc_lock, flags); | ||
| 440 | } | ||
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index e4c9151fa116..f8479fad4047 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <asm/head.h> | 15 | #include <asm/head.h> |
| 16 | #include <asm/thread_info.h> | 16 | #include <asm/thread_info.h> |
| 17 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
| 18 | #include <asm/hypervisor.h> | ||
| 18 | 19 | ||
| 19 | /* Basically, most of the Spitfire vs. Cheetah madness | 20 | /* Basically, most of the Spitfire vs. Cheetah madness |
| 20 | * has to do with the fact that Cheetah does not support | 21 | * has to do with the fact that Cheetah does not support |
| @@ -29,16 +30,18 @@ | |||
| 29 | .text | 30 | .text |
| 30 | .align 32 | 31 | .align 32 |
| 31 | .globl __flush_tlb_mm | 32 | .globl __flush_tlb_mm |
| 32 | __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */ | 33 | __flush_tlb_mm: /* 18 insns */ |
| 34 | /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */ | ||
| 33 | ldxa [%o1] ASI_DMMU, %g2 | 35 | ldxa [%o1] ASI_DMMU, %g2 |
| 34 | cmp %g2, %o0 | 36 | cmp %g2, %o0 |
| 35 | bne,pn %icc, __spitfire_flush_tlb_mm_slow | 37 | bne,pn %icc, __spitfire_flush_tlb_mm_slow |
| 36 | mov 0x50, %g3 | 38 | mov 0x50, %g3 |
| 37 | stxa %g0, [%g3] ASI_DMMU_DEMAP | 39 | stxa %g0, [%g3] ASI_DMMU_DEMAP |
| 38 | stxa %g0, [%g3] ASI_IMMU_DEMAP | 40 | stxa %g0, [%g3] ASI_IMMU_DEMAP |
| 41 | sethi %hi(KERNBASE), %g3 | ||
| 42 | flush %g3 | ||
| 39 | retl | 43 | retl |
| 40 | flush %g6 | 44 | nop |
| 41 | nop | ||
| 42 | nop | 45 | nop |
| 43 | nop | 46 | nop |
| 44 | nop | 47 | nop |
| @@ -51,7 +54,7 @@ __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */ | |||
| 51 | 54 | ||
| 52 | .align 32 | 55 | .align 32 |
| 53 | .globl __flush_tlb_pending | 56 | .globl __flush_tlb_pending |
| 54 | __flush_tlb_pending: | 57 | __flush_tlb_pending: /* 26 insns */ |
| 55 | /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */ | 58 | /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */ |
| 56 | rdpr %pstate, %g7 | 59 | rdpr %pstate, %g7 |
| 57 | sllx %o1, 3, %o1 | 60 | sllx %o1, 3, %o1 |
| @@ -72,7 +75,8 @@ __flush_tlb_pending: | |||
| 72 | brnz,pt %o1, 1b | 75 | brnz,pt %o1, 1b |
| 73 | nop | 76 | nop |
| 74 | stxa %g2, [%o4] ASI_DMMU | 77 | stxa %g2, [%o4] ASI_DMMU |
| 75 | flush %g6 | 78 | sethi %hi(KERNBASE), %o4 |
| 79 | flush %o4 | ||
| 76 | retl | 80 | retl |
| 77 | wrpr %g7, 0x0, %pstate | 81 | wrpr %g7, 0x0, %pstate |
| 78 | nop | 82 | nop |
| @@ -82,7 +86,8 @@ __flush_tlb_pending: | |||
| 82 | 86 | ||
| 83 | .align 32 | 87 | .align 32 |
| 84 | .globl __flush_tlb_kernel_range | 88 | .globl __flush_tlb_kernel_range |
| 85 | __flush_tlb_kernel_range: /* %o0=start, %o1=end */ | 89 | __flush_tlb_kernel_range: /* 16 insns */ |
| 90 | /* %o0=start, %o1=end */ | ||
| 86 | cmp %o0, %o1 | 91 | cmp %o0, %o1 |
| 87 | be,pn %xcc, 2f | 92 | be,pn %xcc, 2f |
| 88 | sethi %hi(PAGE_SIZE), %o4 | 93 | sethi %hi(PAGE_SIZE), %o4 |
| @@ -94,8 +99,11 @@ __flush_tlb_kernel_range: /* %o0=start, %o1=end */ | |||
| 94 | membar #Sync | 99 | membar #Sync |
| 95 | brnz,pt %o3, 1b | 100 | brnz,pt %o3, 1b |
| 96 | sub %o3, %o4, %o3 | 101 | sub %o3, %o4, %o3 |
| 97 | 2: retl | 102 | 2: sethi %hi(KERNBASE), %o3 |
| 98 | flush %g6 | 103 | flush %o3 |
| 104 | retl | ||
| 105 | nop | ||
| 106 | nop | ||
| 99 | 107 | ||
| 100 | __spitfire_flush_tlb_mm_slow: | 108 | __spitfire_flush_tlb_mm_slow: |
| 101 | rdpr %pstate, %g1 | 109 | rdpr %pstate, %g1 |
| @@ -105,7 +113,8 @@ __spitfire_flush_tlb_mm_slow: | |||
| 105 | stxa %g0, [%g3] ASI_IMMU_DEMAP | 113 | stxa %g0, [%g3] ASI_IMMU_DEMAP |
| 106 | flush %g6 | 114 | flush %g6 |
| 107 | stxa %g2, [%o1] ASI_DMMU | 115 | stxa %g2, [%o1] ASI_DMMU |
| 108 | flush %g6 | 116 | sethi %hi(KERNBASE), %o1 |
| 117 | flush %o1 | ||
| 109 | retl | 118 | retl |
| 110 | wrpr %g1, 0, %pstate | 119 | wrpr %g1, 0, %pstate |
| 111 | 120 | ||
| @@ -181,7 +190,7 @@ __flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */ | |||
| 181 | .previous | 190 | .previous |
| 182 | 191 | ||
| 183 | /* Cheetah specific versions, patched at boot time. */ | 192 | /* Cheetah specific versions, patched at boot time. */ |
| 184 | __cheetah_flush_tlb_mm: /* 18 insns */ | 193 | __cheetah_flush_tlb_mm: /* 19 insns */ |
| 185 | rdpr %pstate, %g7 | 194 | rdpr %pstate, %g7 |
| 186 | andn %g7, PSTATE_IE, %g2 | 195 | andn %g7, PSTATE_IE, %g2 |
| 187 | wrpr %g2, 0x0, %pstate | 196 | wrpr %g2, 0x0, %pstate |
| @@ -196,12 +205,13 @@ __cheetah_flush_tlb_mm: /* 18 insns */ | |||
| 196 | stxa %g0, [%g3] ASI_DMMU_DEMAP | 205 | stxa %g0, [%g3] ASI_DMMU_DEMAP |
| 197 | stxa %g0, [%g3] ASI_IMMU_DEMAP | 206 | stxa %g0, [%g3] ASI_IMMU_DEMAP |
| 198 | stxa %g2, [%o2] ASI_DMMU | 207 | stxa %g2, [%o2] ASI_DMMU |
| 199 | flush %g6 | 208 | sethi %hi(KERNBASE), %o2 |
| 209 | flush %o2 | ||
| 200 | wrpr %g0, 0, %tl | 210 | wrpr %g0, 0, %tl |
| 201 | retl | 211 | retl |
| 202 | wrpr %g7, 0x0, %pstate | 212 | wrpr %g7, 0x0, %pstate |
| 203 | 213 | ||
| 204 | __cheetah_flush_tlb_pending: /* 26 insns */ | 214 | __cheetah_flush_tlb_pending: /* 27 insns */ |
| 205 | /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */ | 215 | /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */ |
| 206 | rdpr %pstate, %g7 | 216 | rdpr %pstate, %g7 |
| 207 | sllx %o1, 3, %o1 | 217 | sllx %o1, 3, %o1 |
| @@ -225,7 +235,8 @@ __cheetah_flush_tlb_pending: /* 26 insns */ | |||
| 225 | brnz,pt %o1, 1b | 235 | brnz,pt %o1, 1b |
| 226 | nop | 236 | nop |
| 227 | stxa %g2, [%o4] ASI_DMMU | 237 | stxa %g2, [%o4] ASI_DMMU |
| 228 | flush %g6 | 238 | sethi %hi(KERNBASE), %o4 |
| 239 | flush %o4 | ||
| 229 | wrpr %g0, 0, %tl | 240 | wrpr %g0, 0, %tl |
| 230 | retl | 241 | retl |
| 231 | wrpr %g7, 0x0, %pstate | 242 | wrpr %g7, 0x0, %pstate |
| @@ -245,7 +256,76 @@ __cheetah_flush_dcache_page: /* 11 insns */ | |||
| 245 | nop | 256 | nop |
| 246 | #endif /* DCACHE_ALIASING_POSSIBLE */ | 257 | #endif /* DCACHE_ALIASING_POSSIBLE */ |
| 247 | 258 | ||
| 248 | cheetah_patch_one: | 259 | /* Hypervisor specific versions, patched at boot time. */ |
| 260 | __hypervisor_tlb_tl0_error: | ||
| 261 | save %sp, -192, %sp | ||
| 262 | mov %i0, %o0 | ||
| 263 | call hypervisor_tlbop_error | ||
| 264 | mov %i1, %o1 | ||
| 265 | ret | ||
| 266 | restore | ||
| 267 | |||
| 268 | __hypervisor_flush_tlb_mm: /* 10 insns */ | ||
| 269 | mov %o0, %o2 /* ARG2: mmu context */ | ||
| 270 | mov 0, %o0 /* ARG0: CPU lists unimplemented */ | ||
| 271 | mov 0, %o1 /* ARG1: CPU lists unimplemented */ | ||
| 272 | mov HV_MMU_ALL, %o3 /* ARG3: flags */ | ||
| 273 | mov HV_FAST_MMU_DEMAP_CTX, %o5 | ||
| 274 | ta HV_FAST_TRAP | ||
| 275 | brnz,pn %o0, __hypervisor_tlb_tl0_error | ||
| 276 | mov HV_FAST_MMU_DEMAP_CTX, %o1 | ||
| 277 | retl | ||
| 278 | nop | ||
| 279 | |||
| 280 | __hypervisor_flush_tlb_pending: /* 16 insns */ | ||
| 281 | /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */ | ||
| 282 | sllx %o1, 3, %g1 | ||
| 283 | mov %o2, %g2 | ||
| 284 | mov %o0, %g3 | ||
| 285 | 1: sub %g1, (1 << 3), %g1 | ||
| 286 | ldx [%g2 + %g1], %o0 /* ARG0: vaddr + IMMU-bit */ | ||
| 287 | mov %g3, %o1 /* ARG1: mmu context */ | ||
| 288 | mov HV_MMU_ALL, %o2 /* ARG2: flags */ | ||
| 289 | srlx %o0, PAGE_SHIFT, %o0 | ||
| 290 | sllx %o0, PAGE_SHIFT, %o0 | ||
| 291 | ta HV_MMU_UNMAP_ADDR_TRAP | ||
| 292 | brnz,pn %o0, __hypervisor_tlb_tl0_error | ||
| 293 | mov HV_MMU_UNMAP_ADDR_TRAP, %o1 | ||
| 294 | brnz,pt %g1, 1b | ||
| 295 | nop | ||
| 296 | retl | ||
| 297 | nop | ||
| 298 | |||
| 299 | __hypervisor_flush_tlb_kernel_range: /* 16 insns */ | ||
| 300 | /* %o0=start, %o1=end */ | ||
| 301 | cmp %o0, %o1 | ||
| 302 | be,pn %xcc, 2f | ||
| 303 | sethi %hi(PAGE_SIZE), %g3 | ||
| 304 | mov %o0, %g1 | ||
| 305 | sub %o1, %g1, %g2 | ||
| 306 | sub %g2, %g3, %g2 | ||
| 307 | 1: add %g1, %g2, %o0 /* ARG0: virtual address */ | ||
| 308 | mov 0, %o1 /* ARG1: mmu context */ | ||
| 309 | mov HV_MMU_ALL, %o2 /* ARG2: flags */ | ||
| 310 | ta HV_MMU_UNMAP_ADDR_TRAP | ||
| 311 | brnz,pn %o0, __hypervisor_tlb_tl0_error | ||
| 312 | mov HV_MMU_UNMAP_ADDR_TRAP, %o1 | ||
| 313 | brnz,pt %g2, 1b | ||
| 314 | sub %g2, %g3, %g2 | ||
| 315 | 2: retl | ||
| 316 | nop | ||
| 317 | |||
| 318 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 319 | /* XXX Niagara and friends have an 8K cache, so no aliasing is | ||
| 320 | * XXX possible, but nothing explicit in the Hypervisor API | ||
| 321 | * XXX guarantees this. | ||
| 322 | */ | ||
| 323 | __hypervisor_flush_dcache_page: /* 2 insns */ | ||
| 324 | retl | ||
| 325 | nop | ||
| 326 | #endif | ||
| 327 | |||
| 328 | tlb_patch_one: | ||
| 249 | 1: lduw [%o1], %g1 | 329 | 1: lduw [%o1], %g1 |
| 250 | stw %g1, [%o0] | 330 | stw %g1, [%o0] |
| 251 | flush %o0 | 331 | flush %o0 |
| @@ -264,22 +344,22 @@ cheetah_patch_cachetlbops: | |||
| 264 | or %o0, %lo(__flush_tlb_mm), %o0 | 344 | or %o0, %lo(__flush_tlb_mm), %o0 |
| 265 | sethi %hi(__cheetah_flush_tlb_mm), %o1 | 345 | sethi %hi(__cheetah_flush_tlb_mm), %o1 |
| 266 | or %o1, %lo(__cheetah_flush_tlb_mm), %o1 | 346 | or %o1, %lo(__cheetah_flush_tlb_mm), %o1 |
| 267 | call cheetah_patch_one | 347 | call tlb_patch_one |
| 268 | mov 18, %o2 | 348 | mov 19, %o2 |
| 269 | 349 | ||
| 270 | sethi %hi(__flush_tlb_pending), %o0 | 350 | sethi %hi(__flush_tlb_pending), %o0 |
| 271 | or %o0, %lo(__flush_tlb_pending), %o0 | 351 | or %o0, %lo(__flush_tlb_pending), %o0 |
| 272 | sethi %hi(__cheetah_flush_tlb_pending), %o1 | 352 | sethi %hi(__cheetah_flush_tlb_pending), %o1 |
| 273 | or %o1, %lo(__cheetah_flush_tlb_pending), %o1 | 353 | or %o1, %lo(__cheetah_flush_tlb_pending), %o1 |
| 274 | call cheetah_patch_one | 354 | call tlb_patch_one |
| 275 | mov 26, %o2 | 355 | mov 27, %o2 |
| 276 | 356 | ||
| 277 | #ifdef DCACHE_ALIASING_POSSIBLE | 357 | #ifdef DCACHE_ALIASING_POSSIBLE |
| 278 | sethi %hi(__flush_dcache_page), %o0 | 358 | sethi %hi(__flush_dcache_page), %o0 |
| 279 | or %o0, %lo(__flush_dcache_page), %o0 | 359 | or %o0, %lo(__flush_dcache_page), %o0 |
| 280 | sethi %hi(__cheetah_flush_dcache_page), %o1 | 360 | sethi %hi(__cheetah_flush_dcache_page), %o1 |
| 281 | or %o1, %lo(__cheetah_flush_dcache_page), %o1 | 361 | or %o1, %lo(__cheetah_flush_dcache_page), %o1 |
| 282 | call cheetah_patch_one | 362 | call tlb_patch_one |
| 283 | mov 11, %o2 | 363 | mov 11, %o2 |
| 284 | #endif /* DCACHE_ALIASING_POSSIBLE */ | 364 | #endif /* DCACHE_ALIASING_POSSIBLE */ |
| 285 | 365 | ||
| @@ -295,16 +375,14 @@ cheetah_patch_cachetlbops: | |||
| 295 | * %g1 address arg 1 (tlb page and range flushes) | 375 | * %g1 address arg 1 (tlb page and range flushes) |
| 296 | * %g7 address arg 2 (tlb range flush only) | 376 | * %g7 address arg 2 (tlb range flush only) |
| 297 | * | 377 | * |
| 298 | * %g6 ivector table, don't touch | 378 | * %g6 scratch 1 |
| 299 | * %g2 scratch 1 | 379 | * %g2 scratch 2 |
| 300 | * %g3 scratch 2 | 380 | * %g3 scratch 3 |
| 301 | * %g4 scratch 3 | 381 | * %g4 scratch 4 |
| 302 | * | ||
| 303 | * TODO: Make xcall TLB range flushes use the tricks above... -DaveM | ||
| 304 | */ | 382 | */ |
| 305 | .align 32 | 383 | .align 32 |
| 306 | .globl xcall_flush_tlb_mm | 384 | .globl xcall_flush_tlb_mm |
| 307 | xcall_flush_tlb_mm: | 385 | xcall_flush_tlb_mm: /* 21 insns */ |
| 308 | mov PRIMARY_CONTEXT, %g2 | 386 | mov PRIMARY_CONTEXT, %g2 |
| 309 | ldxa [%g2] ASI_DMMU, %g3 | 387 | ldxa [%g2] ASI_DMMU, %g3 |
| 310 | srlx %g3, CTX_PGSZ1_NUC_SHIFT, %g4 | 388 | srlx %g3, CTX_PGSZ1_NUC_SHIFT, %g4 |
| @@ -316,9 +394,19 @@ xcall_flush_tlb_mm: | |||
| 316 | stxa %g0, [%g4] ASI_IMMU_DEMAP | 394 | stxa %g0, [%g4] ASI_IMMU_DEMAP |
| 317 | stxa %g3, [%g2] ASI_DMMU | 395 | stxa %g3, [%g2] ASI_DMMU |
| 318 | retry | 396 | retry |
| 397 | nop | ||
| 398 | nop | ||
| 399 | nop | ||
| 400 | nop | ||
| 401 | nop | ||
| 402 | nop | ||
| 403 | nop | ||
| 404 | nop | ||
| 405 | nop | ||
| 406 | nop | ||
| 319 | 407 | ||
| 320 | .globl xcall_flush_tlb_pending | 408 | .globl xcall_flush_tlb_pending |
| 321 | xcall_flush_tlb_pending: | 409 | xcall_flush_tlb_pending: /* 21 insns */ |
| 322 | /* %g5=context, %g1=nr, %g7=vaddrs[] */ | 410 | /* %g5=context, %g1=nr, %g7=vaddrs[] */ |
| 323 | sllx %g1, 3, %g1 | 411 | sllx %g1, 3, %g1 |
| 324 | mov PRIMARY_CONTEXT, %g4 | 412 | mov PRIMARY_CONTEXT, %g4 |
| @@ -341,9 +429,10 @@ xcall_flush_tlb_pending: | |||
| 341 | nop | 429 | nop |
| 342 | stxa %g2, [%g4] ASI_DMMU | 430 | stxa %g2, [%g4] ASI_DMMU |
| 343 | retry | 431 | retry |
| 432 | nop | ||
| 344 | 433 | ||
| 345 | .globl xcall_flush_tlb_kernel_range | 434 | .globl xcall_flush_tlb_kernel_range |
| 346 | xcall_flush_tlb_kernel_range: | 435 | xcall_flush_tlb_kernel_range: /* 25 insns */ |
| 347 | sethi %hi(PAGE_SIZE - 1), %g2 | 436 | sethi %hi(PAGE_SIZE - 1), %g2 |
| 348 | or %g2, %lo(PAGE_SIZE - 1), %g2 | 437 | or %g2, %lo(PAGE_SIZE - 1), %g2 |
| 349 | andn %g1, %g2, %g1 | 438 | andn %g1, %g2, %g1 |
| @@ -360,14 +449,30 @@ xcall_flush_tlb_kernel_range: | |||
| 360 | retry | 449 | retry |
| 361 | nop | 450 | nop |
| 362 | nop | 451 | nop |
| 452 | nop | ||
| 453 | nop | ||
| 454 | nop | ||
| 455 | nop | ||
| 456 | nop | ||
| 457 | nop | ||
| 458 | nop | ||
| 459 | nop | ||
| 460 | nop | ||
| 363 | 461 | ||
| 364 | /* This runs in a very controlled environment, so we do | 462 | /* This runs in a very controlled environment, so we do |
| 365 | * not need to worry about BH races etc. | 463 | * not need to worry about BH races etc. |
| 366 | */ | 464 | */ |
| 367 | .globl xcall_sync_tick | 465 | .globl xcall_sync_tick |
| 368 | xcall_sync_tick: | 466 | xcall_sync_tick: |
| 369 | rdpr %pstate, %g2 | 467 | |
| 468 | 661: rdpr %pstate, %g2 | ||
| 370 | wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate | 469 | wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate |
| 470 | .section .sun4v_2insn_patch, "ax" | ||
| 471 | .word 661b | ||
| 472 | nop | ||
| 473 | nop | ||
| 474 | .previous | ||
| 475 | |||
| 371 | rdpr %pil, %g2 | 476 | rdpr %pil, %g2 |
| 372 | wrpr %g0, 15, %pil | 477 | wrpr %g0, 15, %pil |
| 373 | sethi %hi(109f), %g7 | 478 | sethi %hi(109f), %g7 |
| @@ -390,8 +495,15 @@ xcall_sync_tick: | |||
| 390 | */ | 495 | */ |
| 391 | .globl xcall_report_regs | 496 | .globl xcall_report_regs |
| 392 | xcall_report_regs: | 497 | xcall_report_regs: |
| 393 | rdpr %pstate, %g2 | 498 | |
| 499 | 661: rdpr %pstate, %g2 | ||
| 394 | wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate | 500 | wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate |
| 501 | .section .sun4v_2insn_patch, "ax" | ||
| 502 | .word 661b | ||
| 503 | nop | ||
| 504 | nop | ||
| 505 | .previous | ||
| 506 | |||
| 395 | rdpr %pil, %g2 | 507 | rdpr %pil, %g2 |
| 396 | wrpr %g0, 15, %pil | 508 | wrpr %g0, 15, %pil |
| 397 | sethi %hi(109f), %g7 | 509 | sethi %hi(109f), %g7 |
| @@ -453,62 +565,96 @@ xcall_flush_dcache_page_spitfire: /* %g1 == physical page address | |||
| 453 | nop | 565 | nop |
| 454 | nop | 566 | nop |
| 455 | 567 | ||
| 456 | .data | 568 | /* %g5: error |
| 457 | 569 | * %g6: tlb op | |
| 458 | errata32_hwbug: | 570 | */ |
| 459 | .xword 0 | 571 | __hypervisor_tlb_xcall_error: |
| 460 | 572 | mov %g5, %g4 | |
| 461 | .text | 573 | mov %g6, %g5 |
| 462 | 574 | ba,pt %xcc, etrap | |
| 463 | /* These two are not performance critical... */ | 575 | rd %pc, %g7 |
| 464 | .globl xcall_flush_tlb_all_spitfire | 576 | mov %l4, %o0 |
| 465 | xcall_flush_tlb_all_spitfire: | 577 | call hypervisor_tlbop_error_xcall |
| 466 | /* Spitfire Errata #32 workaround. */ | 578 | mov %l5, %o1 |
| 467 | sethi %hi(errata32_hwbug), %g4 | 579 | ba,a,pt %xcc, rtrap_clr_l6 |
| 468 | stx %g0, [%g4 + %lo(errata32_hwbug)] | 580 | |
| 469 | 581 | .globl __hypervisor_xcall_flush_tlb_mm | |
| 470 | clr %g2 | 582 | __hypervisor_xcall_flush_tlb_mm: /* 21 insns */ |
| 471 | clr %g3 | 583 | /* %g5=ctx, g1,g2,g3,g4,g7=scratch, %g6=unusable */ |
| 472 | 1: ldxa [%g3] ASI_DTLB_DATA_ACCESS, %g4 | 584 | mov %o0, %g2 |
| 473 | and %g4, _PAGE_L, %g5 | 585 | mov %o1, %g3 |
| 474 | brnz,pn %g5, 2f | 586 | mov %o2, %g4 |
| 475 | mov TLB_TAG_ACCESS, %g7 | 587 | mov %o3, %g1 |
| 476 | 588 | mov %o5, %g7 | |
| 477 | stxa %g0, [%g7] ASI_DMMU | 589 | clr %o0 /* ARG0: CPU lists unimplemented */ |
| 478 | membar #Sync | 590 | clr %o1 /* ARG1: CPU lists unimplemented */ |
| 479 | stxa %g0, [%g3] ASI_DTLB_DATA_ACCESS | 591 | mov %g5, %o2 /* ARG2: mmu context */ |
| 592 | mov HV_MMU_ALL, %o3 /* ARG3: flags */ | ||
| 593 | mov HV_FAST_MMU_DEMAP_CTX, %o5 | ||
| 594 | ta HV_FAST_TRAP | ||
| 595 | mov HV_FAST_MMU_DEMAP_CTX, %g6 | ||
| 596 | brnz,pn %o0, __hypervisor_tlb_xcall_error | ||
| 597 | mov %o0, %g5 | ||
| 598 | mov %g2, %o0 | ||
| 599 | mov %g3, %o1 | ||
| 600 | mov %g4, %o2 | ||
| 601 | mov %g1, %o3 | ||
| 602 | mov %g7, %o5 | ||
| 480 | membar #Sync | 603 | membar #Sync |
| 604 | retry | ||
| 481 | 605 | ||
| 482 | /* Spitfire Errata #32 workaround. */ | 606 | .globl __hypervisor_xcall_flush_tlb_pending |
| 483 | sethi %hi(errata32_hwbug), %g4 | 607 | __hypervisor_xcall_flush_tlb_pending: /* 21 insns */ |
| 484 | stx %g0, [%g4 + %lo(errata32_hwbug)] | 608 | /* %g5=ctx, %g1=nr, %g7=vaddrs[], %g2,%g3,%g4,g6=scratch */ |
| 485 | 609 | sllx %g1, 3, %g1 | |
| 486 | 2: ldxa [%g3] ASI_ITLB_DATA_ACCESS, %g4 | 610 | mov %o0, %g2 |
| 487 | and %g4, _PAGE_L, %g5 | 611 | mov %o1, %g3 |
| 488 | brnz,pn %g5, 2f | 612 | mov %o2, %g4 |
| 489 | mov TLB_TAG_ACCESS, %g7 | 613 | 1: sub %g1, (1 << 3), %g1 |
| 490 | 614 | ldx [%g7 + %g1], %o0 /* ARG0: virtual address */ | |
| 491 | stxa %g0, [%g7] ASI_IMMU | 615 | mov %g5, %o1 /* ARG1: mmu context */ |
| 492 | membar #Sync | 616 | mov HV_MMU_ALL, %o2 /* ARG2: flags */ |
| 493 | stxa %g0, [%g3] ASI_ITLB_DATA_ACCESS | 617 | srlx %o0, PAGE_SHIFT, %o0 |
| 618 | sllx %o0, PAGE_SHIFT, %o0 | ||
| 619 | ta HV_MMU_UNMAP_ADDR_TRAP | ||
| 620 | mov HV_MMU_UNMAP_ADDR_TRAP, %g6 | ||
| 621 | brnz,a,pn %o0, __hypervisor_tlb_xcall_error | ||
| 622 | mov %o0, %g5 | ||
| 623 | brnz,pt %g1, 1b | ||
| 624 | nop | ||
| 625 | mov %g2, %o0 | ||
| 626 | mov %g3, %o1 | ||
| 627 | mov %g4, %o2 | ||
| 494 | membar #Sync | 628 | membar #Sync |
| 495 | |||
| 496 | /* Spitfire Errata #32 workaround. */ | ||
| 497 | sethi %hi(errata32_hwbug), %g4 | ||
| 498 | stx %g0, [%g4 + %lo(errata32_hwbug)] | ||
| 499 | |||
| 500 | 2: add %g2, 1, %g2 | ||
| 501 | cmp %g2, SPITFIRE_HIGHEST_LOCKED_TLBENT | ||
| 502 | ble,pt %icc, 1b | ||
| 503 | sll %g2, 3, %g3 | ||
| 504 | flush %g6 | ||
| 505 | retry | 629 | retry |
| 506 | 630 | ||
| 507 | .globl xcall_flush_tlb_all_cheetah | 631 | .globl __hypervisor_xcall_flush_tlb_kernel_range |
| 508 | xcall_flush_tlb_all_cheetah: | 632 | __hypervisor_xcall_flush_tlb_kernel_range: /* 25 insns */ |
| 509 | mov 0x80, %g2 | 633 | /* %g1=start, %g7=end, g2,g3,g4,g5,g6=scratch */ |
| 510 | stxa %g0, [%g2] ASI_DMMU_DEMAP | 634 | sethi %hi(PAGE_SIZE - 1), %g2 |
| 511 | stxa %g0, [%g2] ASI_IMMU_DEMAP | 635 | or %g2, %lo(PAGE_SIZE - 1), %g2 |
| 636 | andn %g1, %g2, %g1 | ||
| 637 | andn %g7, %g2, %g7 | ||
| 638 | sub %g7, %g1, %g3 | ||
| 639 | add %g2, 1, %g2 | ||
| 640 | sub %g3, %g2, %g3 | ||
| 641 | mov %o0, %g2 | ||
| 642 | mov %o1, %g4 | ||
| 643 | mov %o2, %g7 | ||
| 644 | 1: add %g1, %g3, %o0 /* ARG0: virtual address */ | ||
| 645 | mov 0, %o1 /* ARG1: mmu context */ | ||
| 646 | mov HV_MMU_ALL, %o2 /* ARG2: flags */ | ||
| 647 | ta HV_MMU_UNMAP_ADDR_TRAP | ||
| 648 | mov HV_MMU_UNMAP_ADDR_TRAP, %g6 | ||
| 649 | brnz,pn %o0, __hypervisor_tlb_xcall_error | ||
| 650 | mov %o0, %g5 | ||
| 651 | sethi %hi(PAGE_SIZE), %o2 | ||
| 652 | brnz,pt %g3, 1b | ||
| 653 | sub %g3, %o2, %g3 | ||
| 654 | mov %g2, %o0 | ||
| 655 | mov %g4, %o1 | ||
| 656 | mov %g7, %o2 | ||
| 657 | membar #Sync | ||
| 512 | retry | 658 | retry |
| 513 | 659 | ||
| 514 | /* These just get rescheduled to PIL vectors. */ | 660 | /* These just get rescheduled to PIL vectors. */ |
| @@ -527,4 +673,70 @@ xcall_capture: | |||
| 527 | wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint | 673 | wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint |
| 528 | retry | 674 | retry |
| 529 | 675 | ||
| 676 | .globl xcall_new_mmu_context_version | ||
| 677 | xcall_new_mmu_context_version: | ||
| 678 | wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint | ||
| 679 | retry | ||
| 680 | |||
| 530 | #endif /* CONFIG_SMP */ | 681 | #endif /* CONFIG_SMP */ |
| 682 | |||
| 683 | |||
| 684 | .globl hypervisor_patch_cachetlbops | ||
| 685 | hypervisor_patch_cachetlbops: | ||
| 686 | save %sp, -128, %sp | ||
| 687 | |||
| 688 | sethi %hi(__flush_tlb_mm), %o0 | ||
| 689 | or %o0, %lo(__flush_tlb_mm), %o0 | ||
| 690 | sethi %hi(__hypervisor_flush_tlb_mm), %o1 | ||
| 691 | or %o1, %lo(__hypervisor_flush_tlb_mm), %o1 | ||
| 692 | call tlb_patch_one | ||
| 693 | mov 10, %o2 | ||
| 694 | |||
| 695 | sethi %hi(__flush_tlb_pending), %o0 | ||
| 696 | or %o0, %lo(__flush_tlb_pending), %o0 | ||
| 697 | sethi %hi(__hypervisor_flush_tlb_pending), %o1 | ||
| 698 | or %o1, %lo(__hypervisor_flush_tlb_pending), %o1 | ||
| 699 | call tlb_patch_one | ||
| 700 | mov 16, %o2 | ||
| 701 | |||
| 702 | sethi %hi(__flush_tlb_kernel_range), %o0 | ||
| 703 | or %o0, %lo(__flush_tlb_kernel_range), %o0 | ||
| 704 | sethi %hi(__hypervisor_flush_tlb_kernel_range), %o1 | ||
| 705 | or %o1, %lo(__hypervisor_flush_tlb_kernel_range), %o1 | ||
| 706 | call tlb_patch_one | ||
| 707 | mov 16, %o2 | ||
| 708 | |||
| 709 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 710 | sethi %hi(__flush_dcache_page), %o0 | ||
| 711 | or %o0, %lo(__flush_dcache_page), %o0 | ||
| 712 | sethi %hi(__hypervisor_flush_dcache_page), %o1 | ||
| 713 | or %o1, %lo(__hypervisor_flush_dcache_page), %o1 | ||
| 714 | call tlb_patch_one | ||
| 715 | mov 2, %o2 | ||
| 716 | #endif /* DCACHE_ALIASING_POSSIBLE */ | ||
| 717 | |||
| 718 | #ifdef CONFIG_SMP | ||
| 719 | sethi %hi(xcall_flush_tlb_mm), %o0 | ||
| 720 | or %o0, %lo(xcall_flush_tlb_mm), %o0 | ||
| 721 | sethi %hi(__hypervisor_xcall_flush_tlb_mm), %o1 | ||
| 722 | or %o1, %lo(__hypervisor_xcall_flush_tlb_mm), %o1 | ||
| 723 | call tlb_patch_one | ||
| 724 | mov 21, %o2 | ||
| 725 | |||
| 726 | sethi %hi(xcall_flush_tlb_pending), %o0 | ||
| 727 | or %o0, %lo(xcall_flush_tlb_pending), %o0 | ||
| 728 | sethi %hi(__hypervisor_xcall_flush_tlb_pending), %o1 | ||
| 729 | or %o1, %lo(__hypervisor_xcall_flush_tlb_pending), %o1 | ||
| 730 | call tlb_patch_one | ||
| 731 | mov 21, %o2 | ||
| 732 | |||
| 733 | sethi %hi(xcall_flush_tlb_kernel_range), %o0 | ||
| 734 | or %o0, %lo(xcall_flush_tlb_kernel_range), %o0 | ||
| 735 | sethi %hi(__hypervisor_xcall_flush_tlb_kernel_range), %o1 | ||
| 736 | or %o1, %lo(__hypervisor_xcall_flush_tlb_kernel_range), %o1 | ||
| 737 | call tlb_patch_one | ||
| 738 | mov 25, %o2 | ||
| 739 | #endif /* CONFIG_SMP */ | ||
| 740 | |||
| 741 | ret | ||
| 742 | restore | ||
diff --git a/arch/sparc64/prom/cif.S b/arch/sparc64/prom/cif.S index 29d0ae74aed8..5f27ad779c0c 100644 --- a/arch/sparc64/prom/cif.S +++ b/arch/sparc64/prom/cif.S | |||
| @@ -1,10 +1,12 @@ | |||
| 1 | /* cif.S: PROM entry/exit assembler trampolines. | 1 | /* cif.S: PROM entry/exit assembler trampolines. |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 3 | * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
| 4 | * Copyright (C) 2005 David S. Miller <davem@davemloft.net> | 4 | * Copyright (C) 2005, 2006 David S. Miller <davem@davemloft.net> |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <asm/pstate.h> | 7 | #include <asm/pstate.h> |
| 8 | #include <asm/cpudata.h> | ||
| 9 | #include <asm/thread_info.h> | ||
| 8 | 10 | ||
| 9 | .text | 11 | .text |
| 10 | .globl prom_cif_interface | 12 | .globl prom_cif_interface |
| @@ -12,78 +14,16 @@ prom_cif_interface: | |||
| 12 | sethi %hi(p1275buf), %o0 | 14 | sethi %hi(p1275buf), %o0 |
| 13 | or %o0, %lo(p1275buf), %o0 | 15 | or %o0, %lo(p1275buf), %o0 |
| 14 | ldx [%o0 + 0x010], %o1 ! prom_cif_stack | 16 | ldx [%o0 + 0x010], %o1 ! prom_cif_stack |
| 15 | save %o1, -0x190, %sp | 17 | save %o1, -192, %sp |
| 16 | ldx [%i0 + 0x008], %l2 ! prom_cif_handler | 18 | ldx [%i0 + 0x008], %l2 ! prom_cif_handler |
| 17 | rdpr %pstate, %l4 | 19 | mov %g4, %l0 |
| 18 | wrpr %g0, 0x15, %pstate ! save alternate globals | 20 | mov %g5, %l1 |
| 19 | stx %g1, [%sp + 2047 + 0x0b0] | 21 | mov %g6, %l3 |
| 20 | stx %g2, [%sp + 2047 + 0x0b8] | ||
| 21 | stx %g3, [%sp + 2047 + 0x0c0] | ||
| 22 | stx %g4, [%sp + 2047 + 0x0c8] | ||
| 23 | stx %g5, [%sp + 2047 + 0x0d0] | ||
| 24 | stx %g6, [%sp + 2047 + 0x0d8] | ||
| 25 | stx %g7, [%sp + 2047 + 0x0e0] | ||
| 26 | wrpr %g0, 0x814, %pstate ! save interrupt globals | ||
| 27 | stx %g1, [%sp + 2047 + 0x0e8] | ||
| 28 | stx %g2, [%sp + 2047 + 0x0f0] | ||
| 29 | stx %g3, [%sp + 2047 + 0x0f8] | ||
| 30 | stx %g4, [%sp + 2047 + 0x100] | ||
| 31 | stx %g5, [%sp + 2047 + 0x108] | ||
| 32 | stx %g6, [%sp + 2047 + 0x110] | ||
| 33 | stx %g7, [%sp + 2047 + 0x118] | ||
| 34 | wrpr %g0, 0x14, %pstate ! save normal globals | ||
| 35 | stx %g1, [%sp + 2047 + 0x120] | ||
| 36 | stx %g2, [%sp + 2047 + 0x128] | ||
| 37 | stx %g3, [%sp + 2047 + 0x130] | ||
| 38 | stx %g4, [%sp + 2047 + 0x138] | ||
| 39 | stx %g5, [%sp + 2047 + 0x140] | ||
| 40 | stx %g6, [%sp + 2047 + 0x148] | ||
| 41 | stx %g7, [%sp + 2047 + 0x150] | ||
| 42 | wrpr %g0, 0x414, %pstate ! save mmu globals | ||
| 43 | stx %g1, [%sp + 2047 + 0x158] | ||
| 44 | stx %g2, [%sp + 2047 + 0x160] | ||
| 45 | stx %g3, [%sp + 2047 + 0x168] | ||
| 46 | stx %g4, [%sp + 2047 + 0x170] | ||
| 47 | stx %g5, [%sp + 2047 + 0x178] | ||
| 48 | stx %g6, [%sp + 2047 + 0x180] | ||
| 49 | stx %g7, [%sp + 2047 + 0x188] | ||
| 50 | mov %g1, %l0 ! also save to locals, so we can handle | ||
| 51 | mov %g2, %l1 ! tlb faults later on, when accessing | ||
| 52 | mov %g3, %l3 ! the stack. | ||
| 53 | mov %g7, %l5 | ||
| 54 | wrpr %l4, PSTATE_IE, %pstate ! turn off interrupts | ||
| 55 | call %l2 | 22 | call %l2 |
| 56 | add %i0, 0x018, %o0 ! prom_args | 23 | add %i0, 0x018, %o0 ! prom_args |
| 57 | wrpr %g0, 0x414, %pstate ! restore mmu globals | 24 | mov %l0, %g4 |
| 58 | mov %l0, %g1 | 25 | mov %l1, %g5 |
| 59 | mov %l1, %g2 | 26 | mov %l3, %g6 |
| 60 | mov %l3, %g3 | ||
| 61 | mov %l5, %g7 | ||
| 62 | wrpr %g0, 0x14, %pstate ! restore normal globals | ||
| 63 | ldx [%sp + 2047 + 0x120], %g1 | ||
| 64 | ldx [%sp + 2047 + 0x128], %g2 | ||
| 65 | ldx [%sp + 2047 + 0x130], %g3 | ||
| 66 | ldx [%sp + 2047 + 0x138], %g4 | ||
| 67 | ldx [%sp + 2047 + 0x140], %g5 | ||
| 68 | ldx [%sp + 2047 + 0x148], %g6 | ||
| 69 | ldx [%sp + 2047 + 0x150], %g7 | ||
| 70 | wrpr %g0, 0x814, %pstate ! restore interrupt globals | ||
| 71 | ldx [%sp + 2047 + 0x0e8], %g1 | ||
| 72 | ldx [%sp + 2047 + 0x0f0], %g2 | ||
| 73 | ldx [%sp + 2047 + 0x0f8], %g3 | ||
| 74 | ldx [%sp + 2047 + 0x100], %g4 | ||
| 75 | ldx [%sp + 2047 + 0x108], %g5 | ||
| 76 | ldx [%sp + 2047 + 0x110], %g6 | ||
| 77 | ldx [%sp + 2047 + 0x118], %g7 | ||
| 78 | wrpr %g0, 0x15, %pstate ! restore alternate globals | ||
| 79 | ldx [%sp + 2047 + 0x0b0], %g1 | ||
| 80 | ldx [%sp + 2047 + 0x0b8], %g2 | ||
| 81 | ldx [%sp + 2047 + 0x0c0], %g3 | ||
| 82 | ldx [%sp + 2047 + 0x0c8], %g4 | ||
| 83 | ldx [%sp + 2047 + 0x0d0], %g5 | ||
| 84 | ldx [%sp + 2047 + 0x0d8], %g6 | ||
| 85 | ldx [%sp + 2047 + 0x0e0], %g7 | ||
| 86 | wrpr %l4, 0, %pstate ! restore original pstate | ||
| 87 | ret | 27 | ret |
| 88 | restore | 28 | restore |
| 89 | 29 | ||
| @@ -91,135 +31,18 @@ prom_cif_interface: | |||
| 91 | prom_cif_callback: | 31 | prom_cif_callback: |
| 92 | sethi %hi(p1275buf), %o1 | 32 | sethi %hi(p1275buf), %o1 |
| 93 | or %o1, %lo(p1275buf), %o1 | 33 | or %o1, %lo(p1275buf), %o1 |
| 94 | save %sp, -0x270, %sp | 34 | save %sp, -192, %sp |
| 95 | rdpr %pstate, %l4 | 35 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
| 96 | wrpr %g0, 0x15, %pstate ! save PROM alternate globals | 36 | LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %o0) |
| 97 | stx %g1, [%sp + 2047 + 0x0b0] | 37 | ldx [%g6 + TI_TASK], %g4 |
| 98 | stx %g2, [%sp + 2047 + 0x0b8] | ||
| 99 | stx %g3, [%sp + 2047 + 0x0c0] | ||
| 100 | stx %g4, [%sp + 2047 + 0x0c8] | ||
| 101 | stx %g5, [%sp + 2047 + 0x0d0] | ||
| 102 | stx %g6, [%sp + 2047 + 0x0d8] | ||
| 103 | stx %g7, [%sp + 2047 + 0x0e0] | ||
| 104 | ! restore Linux alternate globals | ||
| 105 | ldx [%sp + 2047 + 0x190], %g1 | ||
| 106 | ldx [%sp + 2047 + 0x198], %g2 | ||
| 107 | ldx [%sp + 2047 + 0x1a0], %g3 | ||
| 108 | ldx [%sp + 2047 + 0x1a8], %g4 | ||
| 109 | ldx [%sp + 2047 + 0x1b0], %g5 | ||
| 110 | ldx [%sp + 2047 + 0x1b8], %g6 | ||
| 111 | ldx [%sp + 2047 + 0x1c0], %g7 | ||
| 112 | wrpr %g0, 0x814, %pstate ! save PROM interrupt globals | ||
| 113 | stx %g1, [%sp + 2047 + 0x0e8] | ||
| 114 | stx %g2, [%sp + 2047 + 0x0f0] | ||
| 115 | stx %g3, [%sp + 2047 + 0x0f8] | ||
| 116 | stx %g4, [%sp + 2047 + 0x100] | ||
| 117 | stx %g5, [%sp + 2047 + 0x108] | ||
| 118 | stx %g6, [%sp + 2047 + 0x110] | ||
| 119 | stx %g7, [%sp + 2047 + 0x118] | ||
| 120 | ! restore Linux interrupt globals | ||
| 121 | ldx [%sp + 2047 + 0x1c8], %g1 | ||
| 122 | ldx [%sp + 2047 + 0x1d0], %g2 | ||
| 123 | ldx [%sp + 2047 + 0x1d8], %g3 | ||
| 124 | ldx [%sp + 2047 + 0x1e0], %g4 | ||
| 125 | ldx [%sp + 2047 + 0x1e8], %g5 | ||
| 126 | ldx [%sp + 2047 + 0x1f0], %g6 | ||
| 127 | ldx [%sp + 2047 + 0x1f8], %g7 | ||
| 128 | wrpr %g0, 0x14, %pstate ! save PROM normal globals | ||
| 129 | stx %g1, [%sp + 2047 + 0x120] | ||
| 130 | stx %g2, [%sp + 2047 + 0x128] | ||
| 131 | stx %g3, [%sp + 2047 + 0x130] | ||
| 132 | stx %g4, [%sp + 2047 + 0x138] | ||
| 133 | stx %g5, [%sp + 2047 + 0x140] | ||
| 134 | stx %g6, [%sp + 2047 + 0x148] | ||
| 135 | stx %g7, [%sp + 2047 + 0x150] | ||
| 136 | ! restore Linux normal globals | ||
| 137 | ldx [%sp + 2047 + 0x200], %g1 | ||
| 138 | ldx [%sp + 2047 + 0x208], %g2 | ||
| 139 | ldx [%sp + 2047 + 0x210], %g3 | ||
| 140 | ldx [%sp + 2047 + 0x218], %g4 | ||
| 141 | ldx [%sp + 2047 + 0x220], %g5 | ||
| 142 | ldx [%sp + 2047 + 0x228], %g6 | ||
| 143 | ldx [%sp + 2047 + 0x230], %g7 | ||
| 144 | wrpr %g0, 0x414, %pstate ! save PROM mmu globals | ||
| 145 | stx %g1, [%sp + 2047 + 0x158] | ||
| 146 | stx %g2, [%sp + 2047 + 0x160] | ||
| 147 | stx %g3, [%sp + 2047 + 0x168] | ||
| 148 | stx %g4, [%sp + 2047 + 0x170] | ||
| 149 | stx %g5, [%sp + 2047 + 0x178] | ||
| 150 | stx %g6, [%sp + 2047 + 0x180] | ||
| 151 | stx %g7, [%sp + 2047 + 0x188] | ||
| 152 | ! restore Linux mmu globals | ||
| 153 | ldx [%sp + 2047 + 0x238], %o0 | ||
| 154 | ldx [%sp + 2047 + 0x240], %o1 | ||
| 155 | ldx [%sp + 2047 + 0x248], %l2 | ||
| 156 | ldx [%sp + 2047 + 0x250], %l3 | ||
| 157 | ldx [%sp + 2047 + 0x258], %l5 | ||
| 158 | ldx [%sp + 2047 + 0x260], %l6 | ||
| 159 | ldx [%sp + 2047 + 0x268], %l7 | ||
| 160 | ! switch to Linux tba | ||
| 161 | sethi %hi(sparc64_ttable_tl0), %l1 | ||
| 162 | rdpr %tba, %l0 ! save PROM tba | ||
| 163 | mov %o0, %g1 | ||
| 164 | mov %o1, %g2 | ||
| 165 | mov %l2, %g3 | ||
| 166 | mov %l3, %g4 | ||
| 167 | mov %l5, %g5 | ||
| 168 | mov %l6, %g6 | ||
| 169 | mov %l7, %g7 | ||
| 170 | wrpr %l1, %tba ! install Linux tba | ||
| 171 | wrpr %l4, 0, %pstate ! restore PSTATE | ||
| 172 | call prom_world | 38 | call prom_world |
| 173 | mov %g0, %o0 | 39 | mov 0, %o0 |
| 174 | ldx [%i1 + 0x000], %l2 | 40 | ldx [%i1 + 0x000], %l2 |
| 175 | call %l2 | 41 | call %l2 |
| 176 | mov %i0, %o0 | 42 | mov %i0, %o0 |
| 177 | mov %o0, %l1 | 43 | mov %o0, %l1 |
| 178 | call prom_world | 44 | call prom_world |
| 179 | or %g0, 1, %o0 | 45 | mov 1, %o0 |
| 180 | wrpr %g0, 0x14, %pstate ! interrupts off | ||
| 181 | ! restore PROM mmu globals | ||
| 182 | ldx [%sp + 2047 + 0x158], %o0 | ||
| 183 | ldx [%sp + 2047 + 0x160], %o1 | ||
| 184 | ldx [%sp + 2047 + 0x168], %l2 | ||
| 185 | ldx [%sp + 2047 + 0x170], %l3 | ||
| 186 | ldx [%sp + 2047 + 0x178], %l5 | ||
| 187 | ldx [%sp + 2047 + 0x180], %l6 | ||
| 188 | ldx [%sp + 2047 + 0x188], %l7 | ||
| 189 | wrpr %g0, 0x414, %pstate ! restore PROM mmu globals | ||
| 190 | mov %o0, %g1 | ||
| 191 | mov %o1, %g2 | ||
| 192 | mov %l2, %g3 | ||
| 193 | mov %l3, %g4 | ||
| 194 | mov %l5, %g5 | ||
| 195 | mov %l6, %g6 | ||
| 196 | mov %l7, %g7 | ||
| 197 | wrpr %l0, %tba ! restore PROM tba | ||
| 198 | wrpr %g0, 0x14, %pstate ! restore PROM normal globals | ||
| 199 | ldx [%sp + 2047 + 0x120], %g1 | ||
| 200 | ldx [%sp + 2047 + 0x128], %g2 | ||
| 201 | ldx [%sp + 2047 + 0x130], %g3 | ||
| 202 | ldx [%sp + 2047 + 0x138], %g4 | ||
| 203 | ldx [%sp + 2047 + 0x140], %g5 | ||
| 204 | ldx [%sp + 2047 + 0x148], %g6 | ||
| 205 | ldx [%sp + 2047 + 0x150], %g7 | ||
| 206 | wrpr %g0, 0x814, %pstate ! restore PROM interrupt globals | ||
| 207 | ldx [%sp + 2047 + 0x0e8], %g1 | ||
| 208 | ldx [%sp + 2047 + 0x0f0], %g2 | ||
| 209 | ldx [%sp + 2047 + 0x0f8], %g3 | ||
| 210 | ldx [%sp + 2047 + 0x100], %g4 | ||
| 211 | ldx [%sp + 2047 + 0x108], %g5 | ||
| 212 | ldx [%sp + 2047 + 0x110], %g6 | ||
| 213 | ldx [%sp + 2047 + 0x118], %g7 | ||
| 214 | wrpr %g0, 0x15, %pstate ! restore PROM alternate globals | ||
| 215 | ldx [%sp + 2047 + 0x0b0], %g1 | ||
| 216 | ldx [%sp + 2047 + 0x0b8], %g2 | ||
| 217 | ldx [%sp + 2047 + 0x0c0], %g3 | ||
| 218 | ldx [%sp + 2047 + 0x0c8], %g4 | ||
| 219 | ldx [%sp + 2047 + 0x0d0], %g5 | ||
| 220 | ldx [%sp + 2047 + 0x0d8], %g6 | ||
| 221 | ldx [%sp + 2047 + 0x0e0], %g7 | ||
| 222 | wrpr %l4, 0, %pstate | ||
| 223 | ret | 46 | ret |
| 224 | restore %l1, 0, %o0 | 47 | restore %l1, 0, %o0 |
| 225 | 48 | ||
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c index ac6d035dd150..7c25c54cefdc 100644 --- a/arch/sparc64/prom/console.c +++ b/arch/sparc64/prom/console.c | |||
| @@ -102,6 +102,9 @@ prom_query_input_device(void) | |||
| 102 | if (!strncmp (propb, "rsc", 3)) | 102 | if (!strncmp (propb, "rsc", 3)) |
| 103 | return PROMDEV_IRSC; | 103 | return PROMDEV_IRSC; |
| 104 | 104 | ||
| 105 | if (!strncmp (propb, "virtual-console", 3)) | ||
| 106 | return PROMDEV_IVCONS; | ||
| 107 | |||
| 105 | if (strncmp (propb, "tty", 3) || !propb[3]) | 108 | if (strncmp (propb, "tty", 3) || !propb[3]) |
| 106 | return PROMDEV_I_UNK; | 109 | return PROMDEV_I_UNK; |
| 107 | 110 | ||
| @@ -143,6 +146,9 @@ prom_query_output_device(void) | |||
| 143 | if (!strncmp (propb, "rsc", 3)) | 146 | if (!strncmp (propb, "rsc", 3)) |
| 144 | return PROMDEV_ORSC; | 147 | return PROMDEV_ORSC; |
| 145 | 148 | ||
| 149 | if (!strncmp (propb, "virtual-console", 3)) | ||
| 150 | return PROMDEV_OVCONS; | ||
| 151 | |||
| 146 | if (strncmp (propb, "tty", 3) || !propb[3]) | 152 | if (strncmp (propb, "tty", 3) || !propb[3]) |
| 147 | return PROMDEV_O_UNK; | 153 | return PROMDEV_O_UNK; |
| 148 | 154 | ||
diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c index f3cc2d8578b2..1c0db842a6f4 100644 --- a/arch/sparc64/prom/init.c +++ b/arch/sparc64/prom/init.c | |||
| @@ -14,11 +14,10 @@ | |||
| 14 | #include <asm/openprom.h> | 14 | #include <asm/openprom.h> |
| 15 | #include <asm/oplib.h> | 15 | #include <asm/oplib.h> |
| 16 | 16 | ||
| 17 | enum prom_major_version prom_vers; | 17 | /* OBP version string. */ |
| 18 | unsigned int prom_rev, prom_prev; | 18 | char prom_version[80]; |
| 19 | 19 | ||
| 20 | /* The root node of the prom device tree. */ | 20 | /* The root node of the prom device tree. */ |
| 21 | int prom_root_node; | ||
| 22 | int prom_stdin, prom_stdout; | 21 | int prom_stdin, prom_stdout; |
| 23 | int prom_chosen_node; | 22 | int prom_chosen_node; |
| 24 | 23 | ||
| @@ -31,68 +30,25 @@ extern void prom_cif_init(void *, void *); | |||
| 31 | 30 | ||
| 32 | void __init prom_init(void *cif_handler, void *cif_stack) | 31 | void __init prom_init(void *cif_handler, void *cif_stack) |
| 33 | { | 32 | { |
| 34 | char buffer[80], *p; | ||
| 35 | int ints[3]; | ||
| 36 | int node; | 33 | int node; |
| 37 | int i = 0; | ||
| 38 | int bufadjust; | ||
| 39 | |||
| 40 | prom_vers = PROM_P1275; | ||
| 41 | 34 | ||
| 42 | prom_cif_init(cif_handler, cif_stack); | 35 | prom_cif_init(cif_handler, cif_stack); |
| 43 | 36 | ||
| 44 | prom_root_node = prom_getsibling(0); | ||
| 45 | if((prom_root_node == 0) || (prom_root_node == -1)) | ||
| 46 | prom_halt(); | ||
| 47 | |||
| 48 | prom_chosen_node = prom_finddevice(prom_chosen_path); | 37 | prom_chosen_node = prom_finddevice(prom_chosen_path); |
| 49 | if (!prom_chosen_node || prom_chosen_node == -1) | 38 | if (!prom_chosen_node || prom_chosen_node == -1) |
| 50 | prom_halt(); | 39 | prom_halt(); |
| 51 | 40 | ||
| 52 | prom_stdin = prom_getint (prom_chosen_node, "stdin"); | 41 | prom_stdin = prom_getint(prom_chosen_node, "stdin"); |
| 53 | prom_stdout = prom_getint (prom_chosen_node, "stdout"); | 42 | prom_stdout = prom_getint(prom_chosen_node, "stdout"); |
| 54 | 43 | ||
| 55 | node = prom_finddevice("/openprom"); | 44 | node = prom_finddevice("/openprom"); |
| 56 | if (!node || node == -1) | 45 | if (!node || node == -1) |
| 57 | prom_halt(); | 46 | prom_halt(); |
| 58 | 47 | ||
| 59 | prom_getstring (node, "version", buffer, sizeof (buffer)); | 48 | prom_getstring(node, "version", prom_version, sizeof(prom_version)); |
| 60 | |||
| 61 | prom_printf ("\n"); | ||
| 62 | |||
| 63 | if (strncmp (buffer, "OBP ", 4)) | ||
| 64 | goto strange_version; | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Version field is expected to be 'OBP xx.yy.zz date...' | ||
| 68 | * However, Sun can't stick to this format very well, so | ||
| 69 | * we need to check for 'OBP xx.yy.zz date...' and adjust | ||
| 70 | * accordingly. -spot | ||
| 71 | */ | ||
| 72 | |||
| 73 | if (strncmp (buffer, "OBP ", 5)) | ||
| 74 | bufadjust = 4; | ||
| 75 | else | ||
| 76 | bufadjust = 5; | ||
| 77 | |||
| 78 | p = buffer + bufadjust; | ||
| 79 | while (p && isdigit(*p) && i < 3) { | ||
| 80 | ints[i++] = simple_strtoul(p, NULL, 0); | ||
| 81 | if ((p = strchr(p, '.')) != NULL) | ||
| 82 | p++; | ||
| 83 | } | ||
| 84 | if (i != 3) | ||
| 85 | goto strange_version; | ||
| 86 | |||
| 87 | prom_rev = ints[1]; | ||
| 88 | prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2]; | ||
| 89 | |||
| 90 | printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust); | ||
| 91 | 49 | ||
| 92 | /* Initialization successful. */ | 50 | prom_printf("\n"); |
| 93 | return; | ||
| 94 | 51 | ||
| 95 | strange_version: | 52 | printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); |
| 96 | prom_printf ("Strange OBP version `%s'.\n", buffer); | 53 | printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); |
| 97 | prom_halt (); | ||
| 98 | } | 54 | } |
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 87f5cfce23bb..577bde8b6647 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c | |||
| @@ -112,28 +112,20 @@ unsigned char prom_get_idprom(char *idbuf, int num_bytes) | |||
| 112 | return 0xff; | 112 | return 0xff; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /* Get the major prom version number. */ | 115 | /* Install Linux trap table so PROM uses that instead of its own. */ |
| 116 | int prom_version(void) | 116 | void prom_set_trap_table(unsigned long tba) |
| 117 | { | ||
| 118 | return PROM_P1275; | ||
| 119 | } | ||
| 120 | |||
| 121 | /* Get the prom plugin-revision. */ | ||
| 122 | int prom_getrev(void) | ||
| 123 | { | ||
| 124 | return prom_rev; | ||
| 125 | } | ||
| 126 | |||
| 127 | /* Get the prom firmware print revision. */ | ||
| 128 | int prom_getprev(void) | ||
| 129 | { | 117 | { |
| 130 | return prom_prev; | 118 | p1275_cmd("SUNW,set-trap-table", |
| 119 | (P1275_ARG(0, P1275_ARG_IN_64B) | | ||
| 120 | P1275_INOUT(1, 0)), tba); | ||
| 131 | } | 121 | } |
| 132 | 122 | ||
| 133 | /* Install Linux trap table so PROM uses that instead of its own. */ | 123 | void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa) |
| 134 | void prom_set_trap_table(unsigned long tba) | ||
| 135 | { | 124 | { |
| 136 | p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); | 125 | p1275_cmd("SUNW,set-trap-table", |
| 126 | (P1275_ARG(0, P1275_ARG_IN_64B) | | ||
| 127 | P1275_ARG(1, P1275_ARG_IN_64B) | | ||
| 128 | P1275_INOUT(2, 0)), tba, mmfsa); | ||
| 137 | } | 129 | } |
| 138 | 130 | ||
| 139 | int prom_get_mmu_ihandle(void) | 131 | int prom_get_mmu_ihandle(void) |
| @@ -303,9 +295,21 @@ int prom_wakeupsystem(void) | |||
| 303 | } | 295 | } |
| 304 | 296 | ||
| 305 | #ifdef CONFIG_SMP | 297 | #ifdef CONFIG_SMP |
| 306 | void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0) | 298 | void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) |
| 299 | { | ||
| 300 | p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); | ||
| 301 | } | ||
| 302 | |||
| 303 | void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) | ||
| 304 | { | ||
| 305 | p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), | ||
| 306 | cpuid, pc, arg); | ||
| 307 | } | ||
| 308 | |||
| 309 | void prom_stopcpu_cpuid(int cpuid) | ||
| 307 | { | 310 | { |
| 308 | p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0); | 311 | p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), |
| 312 | cpuid); | ||
| 309 | } | 313 | } |
| 310 | 314 | ||
| 311 | void prom_stopself(void) | 315 | void prom_stopself(void) |
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index a5a7c5712028..2b32c489860c 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c | |||
| @@ -30,16 +30,6 @@ extern void prom_world(int); | |||
| 30 | extern void prom_cif_interface(void); | 30 | extern void prom_cif_interface(void); |
| 31 | extern void prom_cif_callback(void); | 31 | extern void prom_cif_callback(void); |
| 32 | 32 | ||
| 33 | static inline unsigned long spitfire_get_primary_context(void) | ||
| 34 | { | ||
| 35 | unsigned long ctx; | ||
| 36 | |||
| 37 | __asm__ __volatile__("ldxa [%1] %2, %0" | ||
| 38 | : "=r" (ctx) | ||
| 39 | : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
| 40 | return ctx; | ||
| 41 | } | ||
| 42 | |||
| 43 | /* | 33 | /* |
| 44 | * This provides SMP safety on the p1275buf. prom_callback() drops this lock | 34 | * This provides SMP safety on the p1275buf. prom_callback() drops this lock |
| 45 | * to allow recursuve acquisition. | 35 | * to allow recursuve acquisition. |
| @@ -55,7 +45,6 @@ long p1275_cmd(const char *service, long fmt, ...) | |||
| 55 | long attrs, x; | 45 | long attrs, x; |
| 56 | 46 | ||
| 57 | p = p1275buf.prom_buffer; | 47 | p = p1275buf.prom_buffer; |
| 58 | BUG_ON((spitfire_get_primary_context() & CTX_NR_MASK) != 0); | ||
| 59 | 48 | ||
| 60 | spin_lock_irqsave(&prom_entry_lock, flags); | 49 | spin_lock_irqsave(&prom_entry_lock, flags); |
| 61 | 50 | ||
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c index b1ff9e87dcc6..49075abd7cbc 100644 --- a/arch/sparc64/prom/tree.c +++ b/arch/sparc64/prom/tree.c | |||
| @@ -51,7 +51,7 @@ prom_getparent(int node) | |||
| 51 | __inline__ int | 51 | __inline__ int |
| 52 | __prom_getsibling(int node) | 52 | __prom_getsibling(int node) |
| 53 | { | 53 | { |
| 54 | return p1275_cmd ("peer", P1275_INOUT(1, 1), node); | 54 | return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | __inline__ int | 57 | __inline__ int |
| @@ -59,9 +59,12 @@ prom_getsibling(int node) | |||
| 59 | { | 59 | { |
| 60 | int sibnode; | 60 | int sibnode; |
| 61 | 61 | ||
| 62 | if(node == -1) return 0; | 62 | if (node == -1) |
| 63 | return 0; | ||
| 63 | sibnode = __prom_getsibling(node); | 64 | sibnode = __prom_getsibling(node); |
| 64 | if(sibnode == -1) return 0; | 65 | if (sibnode == -1) |
| 66 | return 0; | ||
| 67 | |||
| 65 | return sibnode; | 68 | return sibnode; |
| 66 | } | 69 | } |
| 67 | 70 | ||
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 3ab4677395f2..5284996780a7 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c | |||
| @@ -90,7 +90,7 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o | |||
| 90 | len = PAGE_ALIGN(len); | 90 | len = PAGE_ALIGN(len); |
| 91 | if(!(flags & MAP_FIXED)) | 91 | if(!(flags & MAP_FIXED)) |
| 92 | addr = 0; | 92 | addr = 0; |
| 93 | else if (len > 0xf0000000UL || addr > 0xf0000000UL - len) | 93 | else if (len > STACK_TOP32 || addr > STACK_TOP32 - len) |
| 94 | goto out_putf; | 94 | goto out_putf; |
| 95 | ret_type = flags & _MAP_NEW; | 95 | ret_type = flags & _MAP_NEW; |
| 96 | flags &= ~_MAP_NEW; | 96 | flags &= ~_MAP_NEW; |
| @@ -102,7 +102,7 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o | |||
| 102 | (unsigned long) prot, (unsigned long) flags, off); | 102 | (unsigned long) prot, (unsigned long) flags, off); |
| 103 | up_write(¤t->mm->mmap_sem); | 103 | up_write(¤t->mm->mmap_sem); |
| 104 | if(!ret_type) | 104 | if(!ret_type) |
| 105 | retval = ((retval < 0xf0000000) ? 0 : retval); | 105 | retval = ((retval < STACK_TOP32) ? 0 : retval); |
| 106 | 106 | ||
| 107 | out_putf: | 107 | out_putf: |
| 108 | if (file) | 108 | if (file) |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bd49b25fba6b..6c6c5498899f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
| @@ -9097,6 +9097,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) | |||
| 9097 | tp->phy_id = PHY_ID_INVALID; | 9097 | tp->phy_id = PHY_ID_INVALID; |
| 9098 | tp->led_ctrl = LED_CTRL_MODE_PHY_1; | 9098 | tp->led_ctrl = LED_CTRL_MODE_PHY_1; |
| 9099 | 9099 | ||
| 9100 | /* Do not even try poking around in here on Sun parts. */ | ||
| 9101 | if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) | ||
| 9102 | return; | ||
| 9103 | |||
| 9100 | tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); | 9104 | tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); |
| 9101 | if (val == NIC_SRAM_DATA_SIG_MAGIC) { | 9105 | if (val == NIC_SRAM_DATA_SIG_MAGIC) { |
| 9102 | u32 nic_cfg, led_cfg; | 9106 | u32 nic_cfg, led_cfg; |
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 1c8b612d8234..3e156e005f2e 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c | |||
| @@ -440,7 +440,8 @@ static int __init bbc_i2c_init(void) | |||
| 440 | struct linux_ebus_device *edev = NULL; | 440 | struct linux_ebus_device *edev = NULL; |
| 441 | int err, index = 0; | 441 | int err, index = 0; |
| 442 | 442 | ||
| 443 | if (tlb_type != cheetah || !bbc_present()) | 443 | if ((tlb_type != cheetah && tlb_type != cheetah_plus) || |
| 444 | !bbc_present()) | ||
| 444 | return -ENODEV; | 445 | return -ENODEV; |
| 445 | 446 | ||
| 446 | for_each_ebus(ebus) { | 447 | for_each_ebus(ebus) { |
| @@ -486,3 +487,4 @@ static void bbc_i2c_cleanup(void) | |||
| 486 | 487 | ||
| 487 | module_init(bbc_i2c_init); | 488 | module_init(bbc_i2c_init); |
| 488 | module_exit(bbc_i2c_cleanup); | 489 | module_exit(bbc_i2c_cleanup); |
| 490 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b3c561abe3f6..89e5413cc2a3 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
| @@ -582,6 +582,13 @@ config SERIAL_SUNSAB_CONSOLE | |||
| 582 | on your Sparc system as the console, you can do so by answering | 582 | on your Sparc system as the console, you can do so by answering |
| 583 | Y to this option. | 583 | Y to this option. |
| 584 | 584 | ||
| 585 | config SERIAL_SUNHV | ||
| 586 | bool "Sun4v Hypervisor Console support" | ||
| 587 | depends on SPARC64 | ||
| 588 | help | ||
| 589 | This driver supports the console device found on SUN4V Sparc | ||
| 590 | systems. Say Y if you want to be able to use this device. | ||
| 591 | |||
| 585 | config SERIAL_IP22_ZILOG | 592 | config SERIAL_IP22_ZILOG |
| 586 | tristate "IP22 Zilog8530 serial support" | 593 | tristate "IP22 Zilog8530 serial support" |
| 587 | depends on SGI_IP22 | 594 | depends on SGI_IP22 |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index eaf8e01db198..50c221af9e6d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
| @@ -30,6 +30,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o | |||
| 30 | obj-$(CONFIG_SERIAL_SA1100) += sa1100.o | 30 | obj-$(CONFIG_SERIAL_SA1100) += sa1100.o |
| 31 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o | 31 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o |
| 32 | obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o | 32 | obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o |
| 33 | obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o | ||
| 33 | obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o | 34 | obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o |
| 34 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o | 35 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o |
| 35 | obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o | 36 | obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o |
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c new file mode 100644 index 000000000000..f137804b3133 --- /dev/null +++ b/drivers/serial/sunhv.c | |||
| @@ -0,0 +1,550 @@ | |||
| 1 | /* sunhv.c: Serial driver for SUN4V hypervisor console. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/module.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/errno.h> | ||
| 9 | #include <linux/tty.h> | ||
| 10 | #include <linux/tty_flip.h> | ||
| 11 | #include <linux/major.h> | ||
| 12 | #include <linux/circ_buf.h> | ||
| 13 | #include <linux/serial.h> | ||
| 14 | #include <linux/sysrq.h> | ||
| 15 | #include <linux/console.h> | ||
| 16 | #include <linux/spinlock.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | |||
| 21 | #include <asm/hypervisor.h> | ||
| 22 | #include <asm/spitfire.h> | ||
| 23 | #include <asm/vdev.h> | ||
| 24 | #include <asm/oplib.h> | ||
| 25 | #include <asm/irq.h> | ||
| 26 | |||
| 27 | #if defined(CONFIG_MAGIC_SYSRQ) | ||
| 28 | #define SUPPORT_SYSRQ | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #include <linux/serial_core.h> | ||
| 32 | |||
| 33 | #include "suncore.h" | ||
| 34 | |||
| 35 | #define CON_BREAK ((long)-1) | ||
| 36 | #define CON_HUP ((long)-2) | ||
| 37 | |||
| 38 | static inline long hypervisor_con_getchar(long *status) | ||
| 39 | { | ||
| 40 | register unsigned long func asm("%o5"); | ||
| 41 | register unsigned long arg0 asm("%o0"); | ||
| 42 | register unsigned long arg1 asm("%o1"); | ||
| 43 | |||
| 44 | func = HV_FAST_CONS_GETCHAR; | ||
| 45 | arg0 = 0; | ||
| 46 | arg1 = 0; | ||
| 47 | __asm__ __volatile__("ta %6" | ||
| 48 | : "=&r" (func), "=&r" (arg0), "=&r" (arg1) | ||
| 49 | : "0" (func), "1" (arg0), "2" (arg1), | ||
| 50 | "i" (HV_FAST_TRAP)); | ||
| 51 | |||
| 52 | *status = arg0; | ||
| 53 | |||
| 54 | return (long) arg1; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline long hypervisor_con_putchar(long ch) | ||
| 58 | { | ||
| 59 | register unsigned long func asm("%o5"); | ||
| 60 | register unsigned long arg0 asm("%o0"); | ||
| 61 | |||
| 62 | func = HV_FAST_CONS_PUTCHAR; | ||
| 63 | arg0 = ch; | ||
| 64 | __asm__ __volatile__("ta %4" | ||
| 65 | : "=&r" (func), "=&r" (arg0) | ||
| 66 | : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP)); | ||
| 67 | |||
| 68 | return (long) arg0; | ||
| 69 | } | ||
| 70 | |||
| 71 | #define IGNORE_BREAK 0x1 | ||
| 72 | #define IGNORE_ALL 0x2 | ||
| 73 | |||
| 74 | static int hung_up = 0; | ||
| 75 | |||
| 76 | static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs) | ||
| 77 | { | ||
| 78 | struct tty_struct *tty = NULL; | ||
| 79 | int saw_console_brk = 0; | ||
| 80 | int limit = 10000; | ||
| 81 | |||
| 82 | if (port->info != NULL) /* Unopened serial console */ | ||
| 83 | tty = port->info->tty; | ||
| 84 | |||
| 85 | while (limit-- > 0) { | ||
| 86 | long status; | ||
| 87 | long c = hypervisor_con_getchar(&status); | ||
| 88 | unsigned char flag; | ||
| 89 | |||
| 90 | if (status == HV_EWOULDBLOCK) | ||
| 91 | break; | ||
| 92 | |||
| 93 | if (c == CON_BREAK) { | ||
| 94 | if (uart_handle_break(port)) | ||
| 95 | continue; | ||
| 96 | saw_console_brk = 1; | ||
| 97 | c = 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (c == CON_HUP) { | ||
| 101 | hung_up = 1; | ||
| 102 | uart_handle_dcd_change(port, 0); | ||
| 103 | } else if (hung_up) { | ||
| 104 | hung_up = 0; | ||
| 105 | uart_handle_dcd_change(port, 1); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (tty == NULL) { | ||
| 109 | uart_handle_sysrq_char(port, c, regs); | ||
| 110 | continue; | ||
| 111 | } | ||
| 112 | |||
| 113 | flag = TTY_NORMAL; | ||
| 114 | port->icount.rx++; | ||
| 115 | if (c == CON_BREAK) { | ||
| 116 | port->icount.brk++; | ||
| 117 | if (uart_handle_break(port)) | ||
| 118 | continue; | ||
| 119 | flag = TTY_BREAK; | ||
| 120 | } | ||
| 121 | |||
| 122 | if (uart_handle_sysrq_char(port, c, regs)) | ||
| 123 | continue; | ||
| 124 | |||
| 125 | if ((port->ignore_status_mask & IGNORE_ALL) || | ||
| 126 | ((port->ignore_status_mask & IGNORE_BREAK) && | ||
| 127 | (c == CON_BREAK))) | ||
| 128 | continue; | ||
| 129 | |||
| 130 | tty_insert_flip_char(tty, c, flag); | ||
| 131 | } | ||
| 132 | |||
| 133 | if (saw_console_brk) | ||
| 134 | sun_do_break(); | ||
| 135 | |||
| 136 | return tty; | ||
| 137 | } | ||
| 138 | |||
| 139 | static void transmit_chars(struct uart_port *port) | ||
| 140 | { | ||
| 141 | struct circ_buf *xmit; | ||
| 142 | |||
| 143 | if (!port->info) | ||
| 144 | return; | ||
| 145 | |||
| 146 | xmit = &port->info->xmit; | ||
| 147 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | ||
| 148 | return; | ||
| 149 | |||
| 150 | while (!uart_circ_empty(xmit)) { | ||
| 151 | long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); | ||
| 152 | |||
| 153 | if (status != HV_EOK) | ||
| 154 | break; | ||
| 155 | |||
| 156 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
| 157 | port->icount.tx++; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
| 161 | uart_write_wakeup(port); | ||
| 162 | } | ||
| 163 | |||
| 164 | static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 165 | { | ||
| 166 | struct uart_port *port = dev_id; | ||
| 167 | struct tty_struct *tty; | ||
| 168 | unsigned long flags; | ||
| 169 | |||
| 170 | spin_lock_irqsave(&port->lock, flags); | ||
| 171 | tty = receive_chars(port, regs); | ||
| 172 | transmit_chars(port); | ||
| 173 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 174 | |||
| 175 | if (tty) | ||
| 176 | tty_flip_buffer_push(tty); | ||
| 177 | |||
| 178 | return IRQ_HANDLED; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* port->lock is not held. */ | ||
| 182 | static unsigned int sunhv_tx_empty(struct uart_port *port) | ||
| 183 | { | ||
| 184 | /* Transmitter is always empty for us. If the circ buffer | ||
| 185 | * is non-empty or there is an x_char pending, our caller | ||
| 186 | * will do the right thing and ignore what we return here. | ||
| 187 | */ | ||
| 188 | return TIOCSER_TEMT; | ||
| 189 | } | ||
| 190 | |||
| 191 | /* port->lock held by caller. */ | ||
| 192 | static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
| 193 | { | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* port->lock is held by caller and interrupts are disabled. */ | ||
| 198 | static unsigned int sunhv_get_mctrl(struct uart_port *port) | ||
| 199 | { | ||
| 200 | return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* port->lock held by caller. */ | ||
| 204 | static void sunhv_stop_tx(struct uart_port *port) | ||
| 205 | { | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* port->lock held by caller. */ | ||
| 210 | static void sunhv_start_tx(struct uart_port *port) | ||
| 211 | { | ||
| 212 | struct circ_buf *xmit = &port->info->xmit; | ||
| 213 | |||
| 214 | while (!uart_circ_empty(xmit)) { | ||
| 215 | long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); | ||
| 216 | |||
| 217 | if (status != HV_EOK) | ||
| 218 | break; | ||
| 219 | |||
| 220 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
| 221 | port->icount.tx++; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | /* port->lock is not held. */ | ||
| 226 | static void sunhv_send_xchar(struct uart_port *port, char ch) | ||
| 227 | { | ||
| 228 | unsigned long flags; | ||
| 229 | int limit = 10000; | ||
| 230 | |||
| 231 | spin_lock_irqsave(&port->lock, flags); | ||
| 232 | |||
| 233 | while (limit-- > 0) { | ||
| 234 | long status = hypervisor_con_putchar(ch); | ||
| 235 | if (status == HV_EOK) | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | |||
| 239 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 240 | } | ||
| 241 | |||
| 242 | /* port->lock held by caller. */ | ||
| 243 | static void sunhv_stop_rx(struct uart_port *port) | ||
| 244 | { | ||
| 245 | } | ||
| 246 | |||
| 247 | /* port->lock held by caller. */ | ||
| 248 | static void sunhv_enable_ms(struct uart_port *port) | ||
| 249 | { | ||
| 250 | } | ||
| 251 | |||
| 252 | /* port->lock is not held. */ | ||
| 253 | static void sunhv_break_ctl(struct uart_port *port, int break_state) | ||
| 254 | { | ||
| 255 | if (break_state) { | ||
| 256 | unsigned long flags; | ||
| 257 | int limit = 1000000; | ||
| 258 | |||
| 259 | spin_lock_irqsave(&port->lock, flags); | ||
| 260 | |||
| 261 | while (limit-- > 0) { | ||
| 262 | long status = hypervisor_con_putchar(CON_BREAK); | ||
| 263 | if (status == HV_EOK) | ||
| 264 | break; | ||
| 265 | udelay(2); | ||
| 266 | } | ||
| 267 | |||
| 268 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | /* port->lock is not held. */ | ||
| 273 | static int sunhv_startup(struct uart_port *port) | ||
| 274 | { | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* port->lock is not held. */ | ||
| 279 | static void sunhv_shutdown(struct uart_port *port) | ||
| 280 | { | ||
| 281 | } | ||
| 282 | |||
| 283 | /* port->lock is not held. */ | ||
| 284 | static void sunhv_set_termios(struct uart_port *port, struct termios *termios, | ||
| 285 | struct termios *old) | ||
| 286 | { | ||
| 287 | unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); | ||
| 288 | unsigned int quot = uart_get_divisor(port, baud); | ||
| 289 | unsigned int iflag, cflag; | ||
| 290 | unsigned long flags; | ||
| 291 | |||
| 292 | spin_lock_irqsave(&port->lock, flags); | ||
| 293 | |||
| 294 | iflag = termios->c_iflag; | ||
| 295 | cflag = termios->c_cflag; | ||
| 296 | |||
| 297 | port->ignore_status_mask = 0; | ||
| 298 | if (iflag & IGNBRK) | ||
| 299 | port->ignore_status_mask |= IGNORE_BREAK; | ||
| 300 | if ((cflag & CREAD) == 0) | ||
| 301 | port->ignore_status_mask |= IGNORE_ALL; | ||
| 302 | |||
| 303 | /* XXX */ | ||
| 304 | uart_update_timeout(port, cflag, | ||
| 305 | (port->uartclk / (16 * quot))); | ||
| 306 | |||
| 307 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 308 | } | ||
| 309 | |||
| 310 | static const char *sunhv_type(struct uart_port *port) | ||
| 311 | { | ||
| 312 | return "SUN4V HCONS"; | ||
| 313 | } | ||
| 314 | |||
| 315 | static void sunhv_release_port(struct uart_port *port) | ||
| 316 | { | ||
| 317 | } | ||
| 318 | |||
| 319 | static int sunhv_request_port(struct uart_port *port) | ||
| 320 | { | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | static void sunhv_config_port(struct uart_port *port, int flags) | ||
| 325 | { | ||
| 326 | } | ||
| 327 | |||
| 328 | static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser) | ||
| 329 | { | ||
| 330 | return -EINVAL; | ||
| 331 | } | ||
| 332 | |||
| 333 | static struct uart_ops sunhv_pops = { | ||
| 334 | .tx_empty = sunhv_tx_empty, | ||
| 335 | .set_mctrl = sunhv_set_mctrl, | ||
| 336 | .get_mctrl = sunhv_get_mctrl, | ||
| 337 | .stop_tx = sunhv_stop_tx, | ||
| 338 | .start_tx = sunhv_start_tx, | ||
| 339 | .send_xchar = sunhv_send_xchar, | ||
| 340 | .stop_rx = sunhv_stop_rx, | ||
| 341 | .enable_ms = sunhv_enable_ms, | ||
| 342 | .break_ctl = sunhv_break_ctl, | ||
| 343 | .startup = sunhv_startup, | ||
| 344 | .shutdown = sunhv_shutdown, | ||
| 345 | .set_termios = sunhv_set_termios, | ||
| 346 | .type = sunhv_type, | ||
| 347 | .release_port = sunhv_release_port, | ||
| 348 | .request_port = sunhv_request_port, | ||
| 349 | .config_port = sunhv_config_port, | ||
| 350 | .verify_port = sunhv_verify_port, | ||
| 351 | }; | ||
| 352 | |||
| 353 | static struct uart_driver sunhv_reg = { | ||
| 354 | .owner = THIS_MODULE, | ||
| 355 | .driver_name = "serial", | ||
| 356 | .devfs_name = "tts/", | ||
| 357 | .dev_name = "ttyS", | ||
| 358 | .major = TTY_MAJOR, | ||
| 359 | }; | ||
| 360 | |||
| 361 | static struct uart_port *sunhv_port; | ||
| 362 | |||
| 363 | static inline void sunhv_console_putchar(struct uart_port *port, char c) | ||
| 364 | { | ||
| 365 | unsigned long flags; | ||
| 366 | int limit = 1000000; | ||
| 367 | |||
| 368 | spin_lock_irqsave(&port->lock, flags); | ||
| 369 | |||
| 370 | while (limit-- > 0) { | ||
| 371 | long status = hypervisor_con_putchar(c); | ||
| 372 | if (status == HV_EOK) | ||
| 373 | break; | ||
| 374 | udelay(2); | ||
| 375 | } | ||
| 376 | |||
| 377 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 378 | } | ||
| 379 | |||
| 380 | static void sunhv_console_write(struct console *con, const char *s, unsigned n) | ||
| 381 | { | ||
| 382 | struct uart_port *port = sunhv_port; | ||
| 383 | int i; | ||
| 384 | |||
| 385 | for (i = 0; i < n; i++) { | ||
| 386 | if (*s == '\n') | ||
| 387 | sunhv_console_putchar(port, '\r'); | ||
| 388 | sunhv_console_putchar(port, *s++); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | static struct console sunhv_console = { | ||
| 393 | .name = "ttyHV", | ||
| 394 | .write = sunhv_console_write, | ||
| 395 | .device = uart_console_device, | ||
| 396 | .flags = CON_PRINTBUFFER, | ||
| 397 | .index = -1, | ||
| 398 | .data = &sunhv_reg, | ||
| 399 | }; | ||
| 400 | |||
| 401 | static inline struct console *SUNHV_CONSOLE(void) | ||
| 402 | { | ||
| 403 | if (con_is_present()) | ||
| 404 | return NULL; | ||
| 405 | |||
| 406 | sunhv_console.index = 0; | ||
| 407 | |||
| 408 | return &sunhv_console; | ||
| 409 | } | ||
| 410 | |||
| 411 | static int __init hv_console_compatible(char *buf, int len) | ||
| 412 | { | ||
| 413 | while (len) { | ||
| 414 | int this_len; | ||
| 415 | |||
| 416 | if (!strcmp(buf, "qcn")) | ||
| 417 | return 1; | ||
| 418 | |||
| 419 | this_len = strlen(buf) + 1; | ||
| 420 | |||
| 421 | buf += this_len; | ||
| 422 | len -= this_len; | ||
| 423 | } | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | static unsigned int __init get_interrupt(void) | ||
| 429 | { | ||
| 430 | const char *cons_str = "console"; | ||
| 431 | const char *compat_str = "compatible"; | ||
| 432 | int node = prom_getchild(sun4v_vdev_root); | ||
| 433 | char buf[64]; | ||
| 434 | int err, len; | ||
| 435 | |||
| 436 | node = prom_searchsiblings(node, cons_str); | ||
| 437 | if (!node) | ||
| 438 | return 0; | ||
| 439 | |||
| 440 | len = prom_getproplen(node, compat_str); | ||
| 441 | if (len == 0 || len == -1) | ||
| 442 | return 0; | ||
| 443 | |||
| 444 | err = prom_getproperty(node, compat_str, buf, 64); | ||
| 445 | if (err == -1) | ||
| 446 | return 0; | ||
| 447 | |||
| 448 | if (!hv_console_compatible(buf, len)) | ||
| 449 | return 0; | ||
| 450 | |||
| 451 | /* Ok, the this is the OBP node for the sun4v hypervisor | ||
| 452 | * console device. Decode the interrupt. | ||
| 453 | */ | ||
| 454 | return sun4v_vdev_device_interrupt(node); | ||
| 455 | } | ||
| 456 | |||
| 457 | static int __init sunhv_init(void) | ||
| 458 | { | ||
| 459 | struct uart_port *port; | ||
| 460 | int ret; | ||
| 461 | |||
| 462 | if (tlb_type != hypervisor) | ||
| 463 | return -ENODEV; | ||
| 464 | |||
| 465 | port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); | ||
| 466 | if (unlikely(!port)) | ||
| 467 | return -ENOMEM; | ||
| 468 | |||
| 469 | memset(port, 0, sizeof(struct uart_port)); | ||
| 470 | |||
| 471 | port->line = 0; | ||
| 472 | port->ops = &sunhv_pops; | ||
| 473 | port->type = PORT_SUNHV; | ||
| 474 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ | ||
| 475 | |||
| 476 | /* Set this just to make uart_configure_port() happy. */ | ||
| 477 | port->membase = (unsigned char __iomem *) __pa(port); | ||
| 478 | |||
| 479 | port->irq = get_interrupt(); | ||
| 480 | if (!port->irq) { | ||
| 481 | kfree(port); | ||
| 482 | return -ENODEV; | ||
| 483 | } | ||
| 484 | |||
| 485 | sunhv_reg.minor = sunserial_current_minor; | ||
| 486 | sunhv_reg.nr = 1; | ||
| 487 | |||
| 488 | ret = uart_register_driver(&sunhv_reg); | ||
| 489 | if (ret < 0) { | ||
| 490 | printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", | ||
| 491 | ret); | ||
| 492 | kfree(port); | ||
| 493 | |||
| 494 | return ret; | ||
| 495 | } | ||
| 496 | |||
| 497 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; | ||
| 498 | sunserial_current_minor += 1; | ||
| 499 | |||
| 500 | sunhv_reg.cons = SUNHV_CONSOLE(); | ||
| 501 | |||
| 502 | sunhv_port = port; | ||
| 503 | |||
| 504 | ret = uart_add_one_port(&sunhv_reg, port); | ||
| 505 | if (ret < 0) { | ||
| 506 | printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); | ||
| 507 | sunserial_current_minor -= 1; | ||
| 508 | uart_unregister_driver(&sunhv_reg); | ||
| 509 | kfree(port); | ||
| 510 | sunhv_port = NULL; | ||
| 511 | return -ENODEV; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (request_irq(port->irq, sunhv_interrupt, | ||
| 515 | SA_SHIRQ, "serial(sunhv)", port)) { | ||
| 516 | printk(KERN_ERR "sunhv: Cannot register IRQ\n"); | ||
| 517 | uart_remove_one_port(&sunhv_reg, port); | ||
| 518 | sunserial_current_minor -= 1; | ||
| 519 | uart_unregister_driver(&sunhv_reg); | ||
| 520 | kfree(port); | ||
| 521 | sunhv_port = NULL; | ||
| 522 | return -ENODEV; | ||
| 523 | } | ||
| 524 | |||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | static void __exit sunhv_exit(void) | ||
| 529 | { | ||
| 530 | struct uart_port *port = sunhv_port; | ||
| 531 | |||
| 532 | BUG_ON(!port); | ||
| 533 | |||
| 534 | free_irq(port->irq, port); | ||
| 535 | |||
| 536 | uart_remove_one_port(&sunhv_reg, port); | ||
| 537 | sunserial_current_minor -= 1; | ||
| 538 | |||
| 539 | uart_unregister_driver(&sunhv_reg); | ||
| 540 | |||
| 541 | kfree(sunhv_port); | ||
| 542 | sunhv_port = NULL; | ||
| 543 | } | ||
| 544 | |||
| 545 | module_init(sunhv_init); | ||
| 546 | module_exit(sunhv_exit); | ||
| 547 | |||
| 548 | MODULE_AUTHOR("David S. Miller"); | ||
| 549 | MODULE_DESCRIPTION("SUN4V Hypervisor console driver") | ||
| 550 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 85664228a0b6..a2fb0c2fb121 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c | |||
| @@ -955,14 +955,13 @@ static struct console sunsab_console = { | |||
| 955 | .index = -1, | 955 | .index = -1, |
| 956 | .data = &sunsab_reg, | 956 | .data = &sunsab_reg, |
| 957 | }; | 957 | }; |
| 958 | #define SUNSAB_CONSOLE (&sunsab_console) | ||
| 959 | 958 | ||
| 960 | static void __init sunsab_console_init(void) | 959 | static inline struct console *SUNSAB_CONSOLE(void) |
| 961 | { | 960 | { |
| 962 | int i; | 961 | int i; |
| 963 | 962 | ||
| 964 | if (con_is_present()) | 963 | if (con_is_present()) |
| 965 | return; | 964 | return NULL; |
| 966 | 965 | ||
| 967 | for (i = 0; i < num_channels; i++) { | 966 | for (i = 0; i < num_channels; i++) { |
| 968 | int this_minor = sunsab_reg.minor + i; | 967 | int this_minor = sunsab_reg.minor + i; |
| @@ -971,13 +970,14 @@ static void __init sunsab_console_init(void) | |||
| 971 | break; | 970 | break; |
| 972 | } | 971 | } |
| 973 | if (i == num_channels) | 972 | if (i == num_channels) |
| 974 | return; | 973 | return NULL; |
| 975 | 974 | ||
| 976 | sunsab_console.index = i; | 975 | sunsab_console.index = i; |
| 977 | register_console(&sunsab_console); | 976 | |
| 977 | return &sunsab_console; | ||
| 978 | } | 978 | } |
| 979 | #else | 979 | #else |
| 980 | #define SUNSAB_CONSOLE (NULL) | 980 | #define SUNSAB_CONSOLE() (NULL) |
| 981 | #define sunsab_console_init() do { } while (0) | 981 | #define sunsab_console_init() do { } while (0) |
| 982 | #endif | 982 | #endif |
| 983 | 983 | ||
| @@ -1124,7 +1124,6 @@ static int __init sunsab_init(void) | |||
| 1124 | 1124 | ||
| 1125 | sunsab_reg.minor = sunserial_current_minor; | 1125 | sunsab_reg.minor = sunserial_current_minor; |
| 1126 | sunsab_reg.nr = num_channels; | 1126 | sunsab_reg.nr = num_channels; |
| 1127 | sunsab_reg.cons = SUNSAB_CONSOLE; | ||
| 1128 | 1127 | ||
| 1129 | ret = uart_register_driver(&sunsab_reg); | 1128 | ret = uart_register_driver(&sunsab_reg); |
| 1130 | if (ret < 0) { | 1129 | if (ret < 0) { |
| @@ -1143,10 +1142,12 @@ static int __init sunsab_init(void) | |||
| 1143 | return ret; | 1142 | return ret; |
| 1144 | } | 1143 | } |
| 1145 | 1144 | ||
| 1145 | sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; | ||
| 1146 | |||
| 1147 | sunsab_reg.cons = SUNSAB_CONSOLE(); | ||
| 1148 | |||
| 1146 | sunserial_current_minor += num_channels; | 1149 | sunserial_current_minor += num_channels; |
| 1147 | 1150 | ||
| 1148 | sunsab_console_init(); | ||
| 1149 | |||
| 1150 | for (i = 0; i < num_channels; i++) { | 1151 | for (i = 0; i < num_channels; i++) { |
| 1151 | struct uart_sunsab_port *up = &sunsab_ports[i]; | 1152 | struct uart_sunsab_port *up = &sunsab_ports[i]; |
| 1152 | 1153 | ||
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 4e453fa966ae..46c44b83f57c 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c | |||
| @@ -1280,6 +1280,7 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) | |||
| 1280 | struct serio *serio; | 1280 | struct serio *serio; |
| 1281 | #endif | 1281 | #endif |
| 1282 | 1282 | ||
| 1283 | spin_lock_init(&up->port.lock); | ||
| 1283 | up->port.line = channel; | 1284 | up->port.line = channel; |
| 1284 | up->port.type = PORT_UNKNOWN; | 1285 | up->port.type = PORT_UNKNOWN; |
| 1285 | up->port.uartclk = (SU_BASE_BAUD * 16); | 1286 | up->port.uartclk = (SU_BASE_BAUD * 16); |
| @@ -1464,18 +1465,17 @@ static struct console sunsu_cons = { | |||
| 1464 | .index = -1, | 1465 | .index = -1, |
| 1465 | .data = &sunsu_reg, | 1466 | .data = &sunsu_reg, |
| 1466 | }; | 1467 | }; |
| 1467 | #define SUNSU_CONSOLE (&sunsu_cons) | ||
| 1468 | 1468 | ||
| 1469 | /* | 1469 | /* |
| 1470 | * Register console. | 1470 | * Register console. |
| 1471 | */ | 1471 | */ |
| 1472 | 1472 | ||
| 1473 | static int __init sunsu_serial_console_init(void) | 1473 | static inline struct console *SUNSU_CONSOLE(void) |
| 1474 | { | 1474 | { |
| 1475 | int i; | 1475 | int i; |
| 1476 | 1476 | ||
| 1477 | if (con_is_present()) | 1477 | if (con_is_present()) |
| 1478 | return 0; | 1478 | return NULL; |
| 1479 | 1479 | ||
| 1480 | for (i = 0; i < UART_NR; i++) { | 1480 | for (i = 0; i < UART_NR; i++) { |
| 1481 | int this_minor = sunsu_reg.minor + i; | 1481 | int this_minor = sunsu_reg.minor + i; |
| @@ -1484,16 +1484,16 @@ static int __init sunsu_serial_console_init(void) | |||
| 1484 | break; | 1484 | break; |
| 1485 | } | 1485 | } |
| 1486 | if (i == UART_NR) | 1486 | if (i == UART_NR) |
| 1487 | return 0; | 1487 | return NULL; |
| 1488 | if (sunsu_ports[i].port_node == 0) | 1488 | if (sunsu_ports[i].port_node == 0) |
| 1489 | return 0; | 1489 | return NULL; |
| 1490 | 1490 | ||
| 1491 | sunsu_cons.index = i; | 1491 | sunsu_cons.index = i; |
| 1492 | register_console(&sunsu_cons); | 1492 | |
| 1493 | return 0; | 1493 | return &sunsu_cons; |
| 1494 | } | 1494 | } |
| 1495 | #else | 1495 | #else |
| 1496 | #define SUNSU_CONSOLE (NULL) | 1496 | #define SUNSU_CONSOLE() (NULL) |
| 1497 | #define sunsu_serial_console_init() do { } while (0) | 1497 | #define sunsu_serial_console_init() do { } while (0) |
| 1498 | #endif | 1498 | #endif |
| 1499 | 1499 | ||
| @@ -1510,6 +1510,7 @@ static int __init sunsu_serial_init(void) | |||
| 1510 | up->su_type == SU_PORT_KBD) | 1510 | up->su_type == SU_PORT_KBD) |
| 1511 | continue; | 1511 | continue; |
| 1512 | 1512 | ||
| 1513 | spin_lock_init(&up->port.lock); | ||
| 1513 | up->port.flags |= UPF_BOOT_AUTOCONF; | 1514 | up->port.flags |= UPF_BOOT_AUTOCONF; |
| 1514 | up->port.type = PORT_UNKNOWN; | 1515 | up->port.type = PORT_UNKNOWN; |
| 1515 | up->port.uartclk = (SU_BASE_BAUD * 16); | 1516 | up->port.uartclk = (SU_BASE_BAUD * 16); |
| @@ -1523,16 +1524,19 @@ static int __init sunsu_serial_init(void) | |||
| 1523 | } | 1524 | } |
| 1524 | 1525 | ||
| 1525 | sunsu_reg.minor = sunserial_current_minor; | 1526 | sunsu_reg.minor = sunserial_current_minor; |
| 1526 | sunserial_current_minor += instance; | ||
| 1527 | 1527 | ||
| 1528 | sunsu_reg.nr = instance; | 1528 | sunsu_reg.nr = instance; |
| 1529 | sunsu_reg.cons = SUNSU_CONSOLE; | ||
| 1530 | 1529 | ||
| 1531 | ret = uart_register_driver(&sunsu_reg); | 1530 | ret = uart_register_driver(&sunsu_reg); |
| 1532 | if (ret < 0) | 1531 | if (ret < 0) |
| 1533 | return ret; | 1532 | return ret; |
| 1534 | 1533 | ||
| 1535 | sunsu_serial_console_init(); | 1534 | sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; |
| 1535 | |||
| 1536 | sunserial_current_minor += instance; | ||
| 1537 | |||
| 1538 | sunsu_reg.cons = SUNSU_CONSOLE(); | ||
| 1539 | |||
| 1536 | for (i = 0; i < UART_NR; i++) { | 1540 | for (i = 0; i < UART_NR; i++) { |
| 1537 | struct uart_sunsu_port *up = &sunsu_ports[i]; | 1541 | struct uart_sunsu_port *up = &sunsu_ports[i]; |
| 1538 | 1542 | ||
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 5cc4d4c2935c..10b35c6f287d 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c | |||
| @@ -1390,7 +1390,6 @@ static struct console sunzilog_console = { | |||
| 1390 | .index = -1, | 1390 | .index = -1, |
| 1391 | .data = &sunzilog_reg, | 1391 | .data = &sunzilog_reg, |
| 1392 | }; | 1392 | }; |
| 1393 | #define SUNZILOG_CONSOLE (&sunzilog_console) | ||
| 1394 | 1393 | ||
| 1395 | static int __init sunzilog_console_init(void) | 1394 | static int __init sunzilog_console_init(void) |
| 1396 | { | 1395 | { |
| @@ -1413,8 +1412,31 @@ static int __init sunzilog_console_init(void) | |||
| 1413 | register_console(&sunzilog_console); | 1412 | register_console(&sunzilog_console); |
| 1414 | return 0; | 1413 | return 0; |
| 1415 | } | 1414 | } |
| 1415 | |||
| 1416 | static inline struct console *SUNZILOG_CONSOLE(void) | ||
| 1417 | { | ||
| 1418 | int i; | ||
| 1419 | |||
| 1420 | if (con_is_present()) | ||
| 1421 | return NULL; | ||
| 1422 | |||
| 1423 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
| 1424 | int this_minor = sunzilog_reg.minor + i; | ||
| 1425 | |||
| 1426 | if ((this_minor - 64) == (serial_console - 1)) | ||
| 1427 | break; | ||
| 1428 | } | ||
| 1429 | if (i == NUM_CHANNELS) | ||
| 1430 | return NULL; | ||
| 1431 | |||
| 1432 | sunzilog_console.index = i; | ||
| 1433 | sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; | ||
| 1434 | |||
| 1435 | return &sunzilog_console; | ||
| 1436 | } | ||
| 1437 | |||
| 1416 | #else | 1438 | #else |
| 1417 | #define SUNZILOG_CONSOLE (NULL) | 1439 | #define SUNZILOG_CONSOLE() (NULL) |
| 1418 | #define sunzilog_console_init() do { } while (0) | 1440 | #define sunzilog_console_init() do { } while (0) |
| 1419 | #endif | 1441 | #endif |
| 1420 | 1442 | ||
| @@ -1666,14 +1688,15 @@ static int __init sunzilog_ports_init(void) | |||
| 1666 | } | 1688 | } |
| 1667 | 1689 | ||
| 1668 | sunzilog_reg.nr = uart_count; | 1690 | sunzilog_reg.nr = uart_count; |
| 1669 | sunzilog_reg.cons = SUNZILOG_CONSOLE; | ||
| 1670 | |||
| 1671 | sunzilog_reg.minor = sunserial_current_minor; | 1691 | sunzilog_reg.minor = sunserial_current_minor; |
| 1672 | sunserial_current_minor += uart_count; | ||
| 1673 | 1692 | ||
| 1674 | ret = uart_register_driver(&sunzilog_reg); | 1693 | ret = uart_register_driver(&sunzilog_reg); |
| 1675 | if (ret == 0) { | 1694 | if (ret == 0) { |
| 1676 | sunzilog_console_init(); | 1695 | sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; |
| 1696 | sunzilog_reg.cons = SUNZILOG_CONSOLE(); | ||
| 1697 | |||
| 1698 | sunserial_current_minor += uart_count; | ||
| 1699 | |||
| 1677 | for (i = 0; i < NUM_CHANNELS; i++) { | 1700 | for (i = 0; i < NUM_CHANNELS; i++) { |
| 1678 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; | 1701 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; |
| 1679 | 1702 | ||
diff --git a/include/asm-sparc/idprom.h b/include/asm-sparc/idprom.h index d856e640acd3..59083ed85232 100644 --- a/include/asm-sparc/idprom.h +++ b/include/asm-sparc/idprom.h | |||
| @@ -7,27 +7,19 @@ | |||
| 7 | #ifndef _SPARC_IDPROM_H | 7 | #ifndef _SPARC_IDPROM_H |
| 8 | #define _SPARC_IDPROM_H | 8 | #define _SPARC_IDPROM_H |
| 9 | 9 | ||
| 10 | /* Offset into the EEPROM where the id PROM is located on the 4c */ | 10 | #include <linux/types.h> |
| 11 | #define IDPROM_OFFSET 0x7d8 | ||
| 12 | 11 | ||
| 13 | /* On sun4m; physical. */ | 12 | struct idprom { |
| 14 | /* MicroSPARC(-II) does not decode 31rd bit, but it works. */ | 13 | u8 id_format; /* Format identifier (always 0x01) */ |
| 15 | #define IDPROM_OFFSET_M 0xfd8 | 14 | u8 id_machtype; /* Machine type */ |
| 16 | 15 | u8 id_ethaddr[6]; /* Hardware ethernet address */ | |
| 17 | struct idprom | 16 | s32 id_date; /* Date of manufacture */ |
| 18 | { | 17 | u32 id_sernum:24; /* Unique serial number */ |
| 19 | unsigned char id_format; /* Format identifier (always 0x01) */ | 18 | u8 id_cksum; /* Checksum - xor of the data bytes */ |
| 20 | unsigned char id_machtype; /* Machine type */ | 19 | u8 reserved[16]; |
| 21 | unsigned char id_ethaddr[6]; /* Hardware ethernet address */ | ||
| 22 | long id_date; /* Date of manufacture */ | ||
| 23 | unsigned int id_sernum:24; /* Unique serial number */ | ||
| 24 | unsigned char id_cksum; /* Checksum - xor of the data bytes */ | ||
| 25 | unsigned char reserved[16]; | ||
| 26 | }; | 20 | }; |
| 27 | 21 | ||
| 28 | extern struct idprom *idprom; | 22 | extern struct idprom *idprom; |
| 29 | extern void idprom_init(void); | 23 | extern void idprom_init(void); |
| 30 | 24 | ||
| 31 | #define IDPROM_SIZE (sizeof(struct idprom)) | ||
| 32 | |||
| 33 | #endif /* !(_SPARC_IDPROM_H) */ | 25 | #endif /* !(_SPARC_IDPROM_H) */ |
diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index d0d76b30eb4c..f283f8aaf6a9 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h | |||
| @@ -165,6 +165,7 @@ enum prom_input_device { | |||
| 165 | PROMDEV_ITTYA, /* input from ttya */ | 165 | PROMDEV_ITTYA, /* input from ttya */ |
| 166 | PROMDEV_ITTYB, /* input from ttyb */ | 166 | PROMDEV_ITTYB, /* input from ttyb */ |
| 167 | PROMDEV_IRSC, /* input from rsc */ | 167 | PROMDEV_IRSC, /* input from rsc */ |
| 168 | PROMDEV_IVCONS, /* input from virtual-console */ | ||
| 168 | PROMDEV_I_UNK, | 169 | PROMDEV_I_UNK, |
| 169 | }; | 170 | }; |
| 170 | 171 | ||
| @@ -177,6 +178,7 @@ enum prom_output_device { | |||
| 177 | PROMDEV_OTTYA, /* to ttya */ | 178 | PROMDEV_OTTYA, /* to ttya */ |
| 178 | PROMDEV_OTTYB, /* to ttyb */ | 179 | PROMDEV_OTTYB, /* to ttyb */ |
| 179 | PROMDEV_ORSC, /* to rsc */ | 180 | PROMDEV_ORSC, /* to rsc */ |
| 181 | PROMDEV_OVCONS, /* to virtual-console */ | ||
| 180 | PROMDEV_O_UNK, | 182 | PROMDEV_O_UNK, |
| 181 | }; | 183 | }; |
| 182 | 184 | ||
diff --git a/include/asm-sparc/uaccess.h b/include/asm-sparc/uaccess.h index f8f1ec1f06e6..3cf132e1aa25 100644 --- a/include/asm-sparc/uaccess.h +++ b/include/asm-sparc/uaccess.h | |||
| @@ -120,17 +120,6 @@ case 8: __put_user_asm(x,d,addr,__pu_ret); break; \ | |||
| 120 | default: __pu_ret = __put_user_bad(); break; \ | 120 | default: __pu_ret = __put_user_bad(); break; \ |
| 121 | } } else { __pu_ret = -EFAULT; } __pu_ret; }) | 121 | } } else { __pu_ret = -EFAULT; } __pu_ret; }) |
| 122 | 122 | ||
| 123 | #define __put_user_check_ret(x,addr,size,retval) ({ \ | ||
| 124 | register int __foo __asm__ ("l1"); \ | ||
| 125 | if (__access_ok(addr,size)) { \ | ||
| 126 | switch (size) { \ | ||
| 127 | case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \ | ||
| 128 | case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \ | ||
| 129 | case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \ | ||
| 130 | case 8: __put_user_asm_ret(x,d,addr,retval,__foo); break; \ | ||
| 131 | default: if (__put_user_bad()) return retval; break; \ | ||
| 132 | } } else return retval; }) | ||
| 133 | |||
| 134 | #define __put_user_nocheck(x,addr,size) ({ \ | 123 | #define __put_user_nocheck(x,addr,size) ({ \ |
| 135 | register int __pu_ret; \ | 124 | register int __pu_ret; \ |
| 136 | switch (size) { \ | 125 | switch (size) { \ |
| @@ -141,16 +130,6 @@ case 8: __put_user_asm(x,d,addr,__pu_ret); break; \ | |||
| 141 | default: __pu_ret = __put_user_bad(); break; \ | 130 | default: __pu_ret = __put_user_bad(); break; \ |
| 142 | } __pu_ret; }) | 131 | } __pu_ret; }) |
| 143 | 132 | ||
| 144 | #define __put_user_nocheck_ret(x,addr,size,retval) ({ \ | ||
| 145 | register int __foo __asm__ ("l1"); \ | ||
| 146 | switch (size) { \ | ||
| 147 | case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \ | ||
| 148 | case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \ | ||
| 149 | case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \ | ||
| 150 | case 8: __put_user_asm_ret(x,d,addr,retval,__foo); break; \ | ||
| 151 | default: if (__put_user_bad()) return retval; break; \ | ||
| 152 | } }) | ||
| 153 | |||
| 154 | #define __put_user_asm(x,size,addr,ret) \ | 133 | #define __put_user_asm(x,size,addr,ret) \ |
| 155 | __asm__ __volatile__( \ | 134 | __asm__ __volatile__( \ |
| 156 | "/* Put user asm, inline. */\n" \ | 135 | "/* Put user asm, inline. */\n" \ |
| @@ -170,32 +149,6 @@ __asm__ __volatile__( \ | |||
| 170 | : "=&r" (ret) : "r" (x), "m" (*__m(addr)), \ | 149 | : "=&r" (ret) : "r" (x), "m" (*__m(addr)), \ |
| 171 | "i" (-EFAULT)) | 150 | "i" (-EFAULT)) |
| 172 | 151 | ||
| 173 | #define __put_user_asm_ret(x,size,addr,ret,foo) \ | ||
| 174 | if (__builtin_constant_p(ret) && ret == -EFAULT) \ | ||
| 175 | __asm__ __volatile__( \ | ||
| 176 | "/* Put user asm ret, inline. */\n" \ | ||
| 177 | "1:\t" "st"#size " %1, %2\n\n\t" \ | ||
| 178 | ".section __ex_table,#alloc\n\t" \ | ||
| 179 | ".align 4\n\t" \ | ||
| 180 | ".word 1b, __ret_efault\n\n\t" \ | ||
| 181 | ".previous\n\n\t" \ | ||
| 182 | : "=r" (foo) : "r" (x), "m" (*__m(addr))); \ | ||
| 183 | else \ | ||
| 184 | __asm__ __volatile( \ | ||
| 185 | "/* Put user asm ret, inline. */\n" \ | ||
| 186 | "1:\t" "st"#size " %1, %2\n\n\t" \ | ||
| 187 | ".section .fixup,#alloc,#execinstr\n\t" \ | ||
| 188 | ".align 4\n" \ | ||
| 189 | "3:\n\t" \ | ||
| 190 | "ret\n\t" \ | ||
| 191 | " restore %%g0, %3, %%o0\n\t" \ | ||
| 192 | ".previous\n\n\t" \ | ||
| 193 | ".section __ex_table,#alloc\n\t" \ | ||
| 194 | ".align 4\n\t" \ | ||
| 195 | ".word 1b, 3b\n\n\t" \ | ||
| 196 | ".previous\n\n\t" \ | ||
| 197 | : "=r" (foo) : "r" (x), "m" (*__m(addr)), "i" (ret)) | ||
| 198 | |||
| 199 | extern int __put_user_bad(void); | 152 | extern int __put_user_bad(void); |
| 200 | 153 | ||
| 201 | #define __get_user_check(x,addr,size,type) ({ \ | 154 | #define __get_user_check(x,addr,size,type) ({ \ |
diff --git a/include/asm-sparc64/a.out.h b/include/asm-sparc64/a.out.h index 02af289e3f46..35cb5c9e0c92 100644 --- a/include/asm-sparc64/a.out.h +++ b/include/asm-sparc64/a.out.h | |||
| @@ -95,7 +95,11 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */ | |||
| 95 | 95 | ||
| 96 | #ifdef __KERNEL__ | 96 | #ifdef __KERNEL__ |
| 97 | 97 | ||
| 98 | #define STACK_TOP (test_thread_flag(TIF_32BIT) ? 0xf0000000 : 0x80000000000L) | 98 | #define STACK_TOP32 ((1UL << 32UL) - PAGE_SIZE) |
| 99 | #define STACK_TOP64 (0x0000080000000000UL - (1UL << 32UL)) | ||
| 100 | |||
| 101 | #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ | ||
| 102 | STACK_TOP32 : STACK_TOP64) | ||
| 99 | 103 | ||
| 100 | #endif | 104 | #endif |
| 101 | 105 | ||
diff --git a/include/asm-sparc64/asi.h b/include/asm-sparc64/asi.h index 534855660f2a..662a21107ae6 100644 --- a/include/asm-sparc64/asi.h +++ b/include/asm-sparc64/asi.h | |||
| @@ -25,14 +25,27 @@ | |||
| 25 | 25 | ||
| 26 | /* SpitFire and later extended ASIs. The "(III)" marker designates | 26 | /* SpitFire and later extended ASIs. The "(III)" marker designates |
| 27 | * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates | 27 | * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates |
| 28 | * Chip Multi Threading specific ASIs. | 28 | * Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific |
| 29 | * ASIs, "(4V)" designates SUN4V specific ASIs. | ||
| 29 | */ | 30 | */ |
| 30 | #define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ | 31 | #define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ |
| 31 | #define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ | 32 | #define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ |
| 33 | #define ASI_BLK_AIUP_4V 0x16 /* (4V) Prim, user, block ld/st */ | ||
| 34 | #define ASI_BLK_AIUS_4V 0x17 /* (4V) Sec, user, block ld/st */ | ||
| 32 | #define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ | 35 | #define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ |
| 33 | #define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ | 36 | #define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ |
| 37 | #define ASI_BLK_AIUP_L_4V 0x1e /* (4V) Prim, user, block, l-endian*/ | ||
| 38 | #define ASI_BLK_AIUS_L_4V 0x1f /* (4V) Sec, user, block, l-endian */ | ||
| 39 | #define ASI_SCRATCHPAD 0x20 /* (4V) Scratch Pad Registers */ | ||
| 40 | #define ASI_MMU 0x21 /* (4V) MMU Context Registers */ | ||
| 41 | #define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load, | ||
| 42 | * secondary, user | ||
| 43 | */ | ||
| 34 | #define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ | 44 | #define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ |
| 45 | #define ASI_QUEUE 0x25 /* (4V) Interrupt Queue Registers */ | ||
| 46 | #define ASI_QUAD_LDD_PHYS_4V 0x26 /* (4V) Physical, qword load */ | ||
| 35 | #define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ | 47 | #define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ |
| 48 | #define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */ | ||
| 36 | #define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ | 49 | #define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ |
| 37 | #define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ | 50 | #define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ |
| 38 | #define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ | 51 | #define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ |
| @@ -137,6 +150,9 @@ | |||
| 137 | #define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ | 150 | #define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ |
| 138 | #define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ | 151 | #define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ |
| 139 | #define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ | 152 | #define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ |
| 153 | #define ASI_BLK_INIT_QUAD_LDD_P 0xe2 /* (NG) init-store, twin load, | ||
| 154 | * primary, implicit | ||
| 155 | */ | ||
| 140 | #define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ | 156 | #define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ |
| 141 | #define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ | 157 | #define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ |
| 142 | #define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ | 158 | #define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ |
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h index 74de79dca915..c66a81bbc84d 100644 --- a/include/asm-sparc64/cpudata.h +++ b/include/asm-sparc64/cpudata.h | |||
| @@ -1,41 +1,224 @@ | |||
| 1 | /* cpudata.h: Per-cpu parameters. | 1 | /* cpudata.h: Per-cpu parameters. |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2003, 2005 David S. Miller (davem@redhat.com) | 3 | * Copyright (C) 2003, 2005, 2006 David S. Miller (davem@davemloft.net) |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #ifndef _SPARC64_CPUDATA_H | 6 | #ifndef _SPARC64_CPUDATA_H |
| 7 | #define _SPARC64_CPUDATA_H | 7 | #define _SPARC64_CPUDATA_H |
| 8 | 8 | ||
| 9 | #include <asm/hypervisor.h> | ||
| 10 | #include <asm/asi.h> | ||
| 11 | |||
| 12 | #ifndef __ASSEMBLY__ | ||
| 13 | |||
| 9 | #include <linux/percpu.h> | 14 | #include <linux/percpu.h> |
| 15 | #include <linux/threads.h> | ||
| 10 | 16 | ||
| 11 | typedef struct { | 17 | typedef struct { |
| 12 | /* Dcache line 1 */ | 18 | /* Dcache line 1 */ |
| 13 | unsigned int __softirq_pending; /* must be 1st, see rtrap.S */ | 19 | unsigned int __softirq_pending; /* must be 1st, see rtrap.S */ |
| 14 | unsigned int multiplier; | 20 | unsigned int multiplier; |
| 15 | unsigned int counter; | 21 | unsigned int counter; |
| 16 | unsigned int idle_volume; | 22 | unsigned int __pad1; |
| 17 | unsigned long clock_tick; /* %tick's per second */ | 23 | unsigned long clock_tick; /* %tick's per second */ |
| 18 | unsigned long udelay_val; | 24 | unsigned long udelay_val; |
| 19 | 25 | ||
| 20 | /* Dcache line 2 */ | 26 | /* Dcache line 2, rarely used */ |
| 21 | unsigned int pgcache_size; | ||
| 22 | unsigned int __pad1; | ||
| 23 | unsigned long *pte_cache[2]; | ||
| 24 | unsigned long *pgd_cache; | ||
| 25 | |||
| 26 | /* Dcache line 3, rarely used */ | ||
| 27 | unsigned int dcache_size; | 27 | unsigned int dcache_size; |
| 28 | unsigned int dcache_line_size; | 28 | unsigned int dcache_line_size; |
| 29 | unsigned int icache_size; | 29 | unsigned int icache_size; |
| 30 | unsigned int icache_line_size; | 30 | unsigned int icache_line_size; |
| 31 | unsigned int ecache_size; | 31 | unsigned int ecache_size; |
| 32 | unsigned int ecache_line_size; | 32 | unsigned int ecache_line_size; |
| 33 | unsigned int __pad2; | ||
| 34 | unsigned int __pad3; | 33 | unsigned int __pad3; |
| 34 | unsigned int __pad4; | ||
| 35 | } cpuinfo_sparc; | 35 | } cpuinfo_sparc; |
| 36 | 36 | ||
| 37 | DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); | 37 | DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); |
| 38 | #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) | 38 | #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) |
| 39 | #define local_cpu_data() __get_cpu_var(__cpu_data) | 39 | #define local_cpu_data() __get_cpu_var(__cpu_data) |
| 40 | 40 | ||
| 41 | /* Trap handling code needs to get at a few critical values upon | ||
| 42 | * trap entry and to process TSB misses. These cannot be in the | ||
| 43 | * per_cpu() area as we really need to lock them into the TLB and | ||
| 44 | * thus make them part of the main kernel image. As a result we | ||
| 45 | * try to make this as small as possible. | ||
| 46 | * | ||
| 47 | * This is padded out and aligned to 64-bytes to avoid false sharing | ||
| 48 | * on SMP. | ||
| 49 | */ | ||
| 50 | |||
| 51 | /* If you modify the size of this structure, please update | ||
| 52 | * TRAP_BLOCK_SZ_SHIFT below. | ||
| 53 | */ | ||
| 54 | struct thread_info; | ||
| 55 | struct trap_per_cpu { | ||
| 56 | /* D-cache line 1: Basic thread information, cpu and device mondo queues */ | ||
| 57 | struct thread_info *thread; | ||
| 58 | unsigned long pgd_paddr; | ||
| 59 | unsigned long cpu_mondo_pa; | ||
| 60 | unsigned long dev_mondo_pa; | ||
| 61 | |||
| 62 | /* D-cache line 2: Error Mondo Queue and kernel buffer pointers */ | ||
| 63 | unsigned long resum_mondo_pa; | ||
| 64 | unsigned long resum_kernel_buf_pa; | ||
| 65 | unsigned long nonresum_mondo_pa; | ||
| 66 | unsigned long nonresum_kernel_buf_pa; | ||
| 67 | |||
| 68 | /* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */ | ||
| 69 | struct hv_fault_status fault_info; | ||
| 70 | |||
| 71 | /* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */ | ||
| 72 | unsigned long cpu_mondo_block_pa; | ||
| 73 | unsigned long cpu_list_pa; | ||
| 74 | unsigned long __pad1[2]; | ||
| 75 | |||
| 76 | /* Dcache line 8: Unused, needed to keep trap_block a power-of-2 in size. */ | ||
| 77 | unsigned long __pad2[4]; | ||
| 78 | } __attribute__((aligned(64))); | ||
| 79 | extern struct trap_per_cpu trap_block[NR_CPUS]; | ||
| 80 | extern void init_cur_cpu_trap(struct thread_info *); | ||
| 81 | extern void setup_tba(void); | ||
| 82 | |||
| 83 | struct cpuid_patch_entry { | ||
| 84 | unsigned int addr; | ||
| 85 | unsigned int cheetah_safari[4]; | ||
| 86 | unsigned int cheetah_jbus[4]; | ||
| 87 | unsigned int starfire[4]; | ||
| 88 | unsigned int sun4v[4]; | ||
| 89 | }; | ||
| 90 | extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end; | ||
| 91 | |||
| 92 | struct sun4v_1insn_patch_entry { | ||
| 93 | unsigned int addr; | ||
| 94 | unsigned int insn; | ||
| 95 | }; | ||
| 96 | extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch, | ||
| 97 | __sun4v_1insn_patch_end; | ||
| 98 | |||
| 99 | struct sun4v_2insn_patch_entry { | ||
| 100 | unsigned int addr; | ||
| 101 | unsigned int insns[2]; | ||
| 102 | }; | ||
| 103 | extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, | ||
| 104 | __sun4v_2insn_patch_end; | ||
| 105 | |||
| 106 | #endif /* !(__ASSEMBLY__) */ | ||
| 107 | |||
| 108 | #define TRAP_PER_CPU_THREAD 0x00 | ||
| 109 | #define TRAP_PER_CPU_PGD_PADDR 0x08 | ||
| 110 | #define TRAP_PER_CPU_CPU_MONDO_PA 0x10 | ||
| 111 | #define TRAP_PER_CPU_DEV_MONDO_PA 0x18 | ||
| 112 | #define TRAP_PER_CPU_RESUM_MONDO_PA 0x20 | ||
| 113 | #define TRAP_PER_CPU_RESUM_KBUF_PA 0x28 | ||
| 114 | #define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30 | ||
| 115 | #define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38 | ||
| 116 | #define TRAP_PER_CPU_FAULT_INFO 0x40 | ||
| 117 | #define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0 | ||
| 118 | #define TRAP_PER_CPU_CPU_LIST_PA 0xc8 | ||
| 119 | |||
| 120 | #define TRAP_BLOCK_SZ_SHIFT 8 | ||
| 121 | |||
| 122 | #include <asm/scratchpad.h> | ||
| 123 | |||
| 124 | #define __GET_CPUID(REG) \ | ||
| 125 | /* Spitfire implementation (default). */ \ | ||
| 126 | 661: ldxa [%g0] ASI_UPA_CONFIG, REG; \ | ||
| 127 | srlx REG, 17, REG; \ | ||
| 128 | and REG, 0x1f, REG; \ | ||
| 129 | nop; \ | ||
| 130 | .section .cpuid_patch, "ax"; \ | ||
| 131 | /* Instruction location. */ \ | ||
| 132 | .word 661b; \ | ||
| 133 | /* Cheetah Safari implementation. */ \ | ||
| 134 | ldxa [%g0] ASI_SAFARI_CONFIG, REG; \ | ||
| 135 | srlx REG, 17, REG; \ | ||
| 136 | and REG, 0x3ff, REG; \ | ||
| 137 | nop; \ | ||
| 138 | /* Cheetah JBUS implementation. */ \ | ||
| 139 | ldxa [%g0] ASI_JBUS_CONFIG, REG; \ | ||
| 140 | srlx REG, 17, REG; \ | ||
| 141 | and REG, 0x1f, REG; \ | ||
| 142 | nop; \ | ||
| 143 | /* Starfire implementation. */ \ | ||
| 144 | sethi %hi(0x1fff40000d0 >> 9), REG; \ | ||
| 145 | sllx REG, 9, REG; \ | ||
| 146 | or REG, 0xd0, REG; \ | ||
| 147 | lduwa [REG] ASI_PHYS_BYPASS_EC_E, REG;\ | ||
| 148 | /* sun4v implementation. */ \ | ||
| 149 | mov SCRATCHPAD_CPUID, REG; \ | ||
| 150 | ldxa [REG] ASI_SCRATCHPAD, REG; \ | ||
| 151 | nop; \ | ||
| 152 | nop; \ | ||
| 153 | .previous; | ||
| 154 | |||
| 155 | #ifdef CONFIG_SMP | ||
| 156 | |||
| 157 | #define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ | ||
| 158 | __GET_CPUID(TMP) \ | ||
| 159 | sethi %hi(trap_block), DEST; \ | ||
| 160 | sllx TMP, TRAP_BLOCK_SZ_SHIFT, TMP; \ | ||
| 161 | or DEST, %lo(trap_block), DEST; \ | ||
| 162 | add DEST, TMP, DEST; \ | ||
| 163 | |||
| 164 | /* Clobbers TMP, current address space PGD phys address into DEST. */ | ||
| 165 | #define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ | ||
| 166 | TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ | ||
| 167 | ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; | ||
| 168 | |||
| 169 | /* Clobbers TMP, loads local processor's IRQ work area into DEST. */ | ||
| 170 | #define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ | ||
| 171 | __GET_CPUID(TMP) \ | ||
| 172 | sethi %hi(__irq_work), DEST; \ | ||
| 173 | sllx TMP, 6, TMP; \ | ||
| 174 | or DEST, %lo(__irq_work), DEST; \ | ||
| 175 | add DEST, TMP, DEST; | ||
| 176 | |||
| 177 | /* Clobbers TMP, loads DEST with current thread info pointer. */ | ||
| 178 | #define TRAP_LOAD_THREAD_REG(DEST, TMP) \ | ||
| 179 | TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ | ||
| 180 | ldx [DEST + TRAP_PER_CPU_THREAD], DEST; | ||
| 181 | |||
| 182 | /* Given the current thread info pointer in THR, load the per-cpu | ||
| 183 | * area base of the current processor into DEST. REG1, REG2, and REG3 are | ||
| 184 | * clobbered. | ||
| 185 | * | ||
| 186 | * You absolutely cannot use DEST as a temporary in this code. The | ||
| 187 | * reason is that traps can happen during execution, and return from | ||
| 188 | * trap will load the fully resolved DEST per-cpu base. This can corrupt | ||
| 189 | * the calculations done by the macro mid-stream. | ||
| 190 | */ | ||
| 191 | #define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \ | ||
| 192 | ldub [THR + TI_CPU], REG1; \ | ||
| 193 | sethi %hi(__per_cpu_shift), REG3; \ | ||
| 194 | sethi %hi(__per_cpu_base), REG2; \ | ||
| 195 | ldx [REG3 + %lo(__per_cpu_shift)], REG3; \ | ||
| 196 | ldx [REG2 + %lo(__per_cpu_base)], REG2; \ | ||
| 197 | sllx REG1, REG3, REG3; \ | ||
| 198 | add REG3, REG2, DEST; | ||
| 199 | |||
| 200 | #else | ||
| 201 | |||
| 202 | #define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ | ||
| 203 | sethi %hi(trap_block), DEST; \ | ||
| 204 | or DEST, %lo(trap_block), DEST; \ | ||
| 205 | |||
| 206 | /* Uniprocessor versions, we know the cpuid is zero. */ | ||
| 207 | #define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ | ||
| 208 | TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ | ||
| 209 | ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; | ||
| 210 | |||
| 211 | #define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ | ||
| 212 | sethi %hi(__irq_work), DEST; \ | ||
| 213 | or DEST, %lo(__irq_work), DEST; | ||
| 214 | |||
| 215 | #define TRAP_LOAD_THREAD_REG(DEST, TMP) \ | ||
| 216 | TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ | ||
| 217 | ldx [DEST + TRAP_PER_CPU_THREAD], DEST; | ||
| 218 | |||
| 219 | /* No per-cpu areas on uniprocessor, so no need to load DEST. */ | ||
| 220 | #define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) | ||
| 221 | |||
| 222 | #endif /* !(CONFIG_SMP) */ | ||
| 223 | |||
| 41 | #endif /* _SPARC64_CPUDATA_H */ | 224 | #endif /* _SPARC64_CPUDATA_H */ |
diff --git a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h index 69539a8ab833..303d85e2f82e 100644 --- a/include/asm-sparc64/elf.h +++ b/include/asm-sparc64/elf.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #ifdef __KERNEL__ | 10 | #ifdef __KERNEL__ |
| 11 | #include <asm/processor.h> | 11 | #include <asm/processor.h> |
| 12 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
| 13 | #include <asm/spitfire.h> | ||
| 13 | #endif | 14 | #endif |
| 14 | 15 | ||
| 15 | /* | 16 | /* |
| @@ -68,6 +69,7 @@ | |||
| 68 | #define HWCAP_SPARC_MULDIV 8 | 69 | #define HWCAP_SPARC_MULDIV 8 |
| 69 | #define HWCAP_SPARC_V9 16 | 70 | #define HWCAP_SPARC_V9 16 |
| 70 | #define HWCAP_SPARC_ULTRA3 32 | 71 | #define HWCAP_SPARC_ULTRA3 32 |
| 72 | #define HWCAP_SPARC_BLKINIT 64 | ||
| 71 | 73 | ||
| 72 | /* | 74 | /* |
| 73 | * These are used to set parameters in the core dumps. | 75 | * These are used to set parameters in the core dumps. |
| @@ -145,11 +147,21 @@ typedef struct { | |||
| 145 | instruction set this cpu supports. */ | 147 | instruction set this cpu supports. */ |
| 146 | 148 | ||
| 147 | /* On Ultra, we support all of the v8 capabilities. */ | 149 | /* On Ultra, we support all of the v8 capabilities. */ |
| 148 | #define ELF_HWCAP ((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ | 150 | static inline unsigned int sparc64_elf_hwcap(void) |
| 149 | HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \ | 151 | { |
| 150 | HWCAP_SPARC_V9) | \ | 152 | unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | |
| 151 | ((tlb_type == cheetah || tlb_type == cheetah_plus) ? \ | 153 | HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | |
| 152 | HWCAP_SPARC_ULTRA3 : 0)) | 154 | HWCAP_SPARC_V9); |
| 155 | |||
| 156 | if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 157 | cap |= HWCAP_SPARC_ULTRA3; | ||
| 158 | else if (tlb_type == hypervisor) | ||
| 159 | cap |= HWCAP_SPARC_BLKINIT; | ||
| 160 | |||
| 161 | return cap; | ||
| 162 | } | ||
| 163 | |||
| 164 | #define ELF_HWCAP sparc64_elf_hwcap(); | ||
| 153 | 165 | ||
| 154 | /* This yields a string that ld.so will use to load implementation | 166 | /* This yields a string that ld.so will use to load implementation |
| 155 | specific libraries for optimization. This is more specific in | 167 | specific libraries for optimization. This is more specific in |
diff --git a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h index 0abd3a674e8f..67960a751f4d 100644 --- a/include/asm-sparc64/head.h +++ b/include/asm-sparc64/head.h | |||
| @@ -4,12 +4,21 @@ | |||
| 4 | 4 | ||
| 5 | #include <asm/pstate.h> | 5 | #include <asm/pstate.h> |
| 6 | 6 | ||
| 7 | /* wrpr %g0, val, %gl */ | ||
| 8 | #define SET_GL(val) \ | ||
| 9 | .word 0xa1902000 | val | ||
| 10 | |||
| 11 | /* rdpr %gl, %gN */ | ||
| 12 | #define GET_GL_GLOBAL(N) \ | ||
| 13 | .word 0x81540000 | (N << 25) | ||
| 14 | |||
| 7 | #define KERNBASE 0x400000 | 15 | #define KERNBASE 0x400000 |
| 8 | 16 | ||
| 9 | #define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ) | 17 | #define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ) |
| 10 | 18 | ||
| 11 | #define __CHEETAH_ID 0x003e0014 | 19 | #define __CHEETAH_ID 0x003e0014 |
| 12 | #define __JALAPENO_ID 0x003e0016 | 20 | #define __JALAPENO_ID 0x003e0016 |
| 21 | #define __SERRANO_ID 0x003e0022 | ||
| 13 | 22 | ||
| 14 | #define CHEETAH_MANUF 0x003e | 23 | #define CHEETAH_MANUF 0x003e |
| 15 | #define CHEETAH_IMPL 0x0014 /* Ultra-III */ | 24 | #define CHEETAH_IMPL 0x0014 /* Ultra-III */ |
| @@ -19,6 +28,12 @@ | |||
| 19 | #define PANTHER_IMPL 0x0019 /* Ultra-IV+ */ | 28 | #define PANTHER_IMPL 0x0019 /* Ultra-IV+ */ |
| 20 | #define SERRANO_IMPL 0x0022 /* Ultra-IIIi+ */ | 29 | #define SERRANO_IMPL 0x0022 /* Ultra-IIIi+ */ |
| 21 | 30 | ||
| 31 | #define BRANCH_IF_SUN4V(tmp1,label) \ | ||
| 32 | sethi %hi(is_sun4v), %tmp1; \ | ||
| 33 | lduw [%tmp1 + %lo(is_sun4v)], %tmp1; \ | ||
| 34 | brnz,pn %tmp1, label; \ | ||
| 35 | nop | ||
| 36 | |||
| 22 | #define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label) \ | 37 | #define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label) \ |
| 23 | rdpr %ver, %tmp1; \ | 38 | rdpr %ver, %tmp1; \ |
| 24 | sethi %hi(__CHEETAH_ID), %tmp2; \ | 39 | sethi %hi(__CHEETAH_ID), %tmp2; \ |
diff --git a/include/asm-sparc64/hypervisor.h b/include/asm-sparc64/hypervisor.h new file mode 100644 index 000000000000..612bf319753f --- /dev/null +++ b/include/asm-sparc64/hypervisor.h | |||
| @@ -0,0 +1,2128 @@ | |||
| 1 | #ifndef _SPARC64_HYPERVISOR_H | ||
| 2 | #define _SPARC64_HYPERVISOR_H | ||
| 3 | |||
| 4 | /* Sun4v hypervisor interfaces and defines. | ||
| 5 | * | ||
| 6 | * Hypervisor calls are made via traps to software traps number 0x80 | ||
| 7 | * and above. Registers %o0 to %o5 serve as argument, status, and | ||
| 8 | * return value registers. | ||
| 9 | * | ||
| 10 | * There are two kinds of these traps. First there are the normal | ||
| 11 | * "fast traps" which use software trap 0x80 and encode the function | ||
| 12 | * to invoke by number in register %o5. Argument and return value | ||
| 13 | * handling is as follows: | ||
| 14 | * | ||
| 15 | * ----------------------------------------------- | ||
| 16 | * | %o5 | function number | undefined | | ||
| 17 | * | %o0 | argument 0 | return status | | ||
| 18 | * | %o1 | argument 1 | return value 1 | | ||
| 19 | * | %o2 | argument 2 | return value 2 | | ||
| 20 | * | %o3 | argument 3 | return value 3 | | ||
| 21 | * | %o4 | argument 4 | return value 4 | | ||
| 22 | * ----------------------------------------------- | ||
| 23 | * | ||
| 24 | * The second type are "hyper-fast traps" which encode the function | ||
| 25 | * number in the software trap number itself. So these use trap | ||
| 26 | * numbers > 0x80. The register usage for hyper-fast traps is as | ||
| 27 | * follows: | ||
| 28 | * | ||
| 29 | * ----------------------------------------------- | ||
| 30 | * | %o0 | argument 0 | return status | | ||
| 31 | * | %o1 | argument 1 | return value 1 | | ||
| 32 | * | %o2 | argument 2 | return value 2 | | ||
| 33 | * | %o3 | argument 3 | return value 3 | | ||
| 34 | * | %o4 | argument 4 | return value 4 | | ||
| 35 | * ----------------------------------------------- | ||
| 36 | * | ||
| 37 | * Registers providing explicit arguments to the hypervisor calls | ||
| 38 | * are volatile across the call. Upon return their values are | ||
| 39 | * undefined unless explicitly specified as containing a particular | ||
| 40 | * return value by the specific call. The return status is always | ||
| 41 | * returned in register %o0, zero indicates a successful execution of | ||
| 42 | * the hypervisor call and other values indicate an error status as | ||
| 43 | * defined below. So, for example, if a hyper-fast trap takes | ||
| 44 | * arguments 0, 1, and 2, then %o0, %o1, and %o2 are volatile across | ||
| 45 | * the call and %o3, %o4, and %o5 would be preserved. | ||
| 46 | * | ||
| 47 | * If the hypervisor trap is invalid, or the fast trap function number | ||
| 48 | * is invalid, HV_EBADTRAP will be returned in %o0. Also, all 64-bits | ||
| 49 | * of the argument and return values are significant. | ||
| 50 | */ | ||
| 51 | |||
| 52 | /* Trap numbers. */ | ||
| 53 | #define HV_FAST_TRAP 0x80 | ||
| 54 | #define HV_MMU_MAP_ADDR_TRAP 0x83 | ||
| 55 | #define HV_MMU_UNMAP_ADDR_TRAP 0x84 | ||
| 56 | #define HV_TTRACE_ADDENTRY_TRAP 0x85 | ||
| 57 | #define HV_CORE_TRAP 0xff | ||
| 58 | |||
| 59 | /* Error codes. */ | ||
| 60 | #define HV_EOK 0 /* Successful return */ | ||
| 61 | #define HV_ENOCPU 1 /* Invalid CPU id */ | ||
| 62 | #define HV_ENORADDR 2 /* Invalid real address */ | ||
| 63 | #define HV_ENOINTR 3 /* Invalid interrupt id */ | ||
| 64 | #define HV_EBADPGSZ 4 /* Invalid pagesize encoding */ | ||
| 65 | #define HV_EBADTSB 5 /* Invalid TSB description */ | ||
| 66 | #define HV_EINVAL 6 /* Invalid argument */ | ||
| 67 | #define HV_EBADTRAP 7 /* Invalid function number */ | ||
| 68 | #define HV_EBADALIGN 8 /* Invalid address alignment */ | ||
| 69 | #define HV_EWOULDBLOCK 9 /* Cannot complete w/o blocking */ | ||
| 70 | #define HV_ENOACCESS 10 /* No access to resource */ | ||
| 71 | #define HV_EIO 11 /* I/O error */ | ||
| 72 | #define HV_ECPUERROR 12 /* CPU in error state */ | ||
| 73 | #define HV_ENOTSUPPORTED 13 /* Function not supported */ | ||
| 74 | #define HV_ENOMAP 14 /* No mapping found */ | ||
| 75 | #define HV_ETOOMANY 15 /* Too many items specified */ | ||
| 76 | |||
| 77 | /* mach_exit() | ||
| 78 | * TRAP: HV_FAST_TRAP | ||
| 79 | * FUNCTION: HV_FAST_MACH_EXIT | ||
| 80 | * ARG0: exit code | ||
| 81 | * ERRORS: This service does not return. | ||
| 82 | * | ||
| 83 | * Stop all CPUs in the virtual domain and place them into the stopped | ||
| 84 | * state. The 64-bit exit code may be passed to a service entity as | ||
| 85 | * the domain's exit status. On systems without a service entity, the | ||
| 86 | * domain will undergo a reset, and the boot firmware will be | ||
| 87 | * reloaded. | ||
| 88 | * | ||
| 89 | * This function will never return to the guest that invokes it. | ||
| 90 | * | ||
| 91 | * Note: By convention an exit code of zero denotes a successful exit by | ||
| 92 | * the guest code. A non-zero exit code denotes a guest specific | ||
| 93 | * error indication. | ||
| 94 | * | ||
| 95 | */ | ||
| 96 | #define HV_FAST_MACH_EXIT 0x00 | ||
| 97 | |||
| 98 | /* Domain services. */ | ||
| 99 | |||
| 100 | /* mach_desc() | ||
| 101 | * TRAP: HV_FAST_TRAP | ||
| 102 | * FUNCTION: HV_FAST_MACH_DESC | ||
| 103 | * ARG0: buffer | ||
| 104 | * ARG1: length | ||
| 105 | * RET0: status | ||
| 106 | * RET1: length | ||
| 107 | * ERRORS: HV_EBADALIGN Buffer is badly aligned | ||
| 108 | * HV_ENORADDR Buffer is to an illegal real address. | ||
| 109 | * HV_EINVAL Buffer length is too small for complete | ||
| 110 | * machine description. | ||
| 111 | * | ||
| 112 | * Copy the most current machine description into the buffer indicated | ||
| 113 | * by the real address in ARG0. The buffer provided must be 16 byte | ||
| 114 | * aligned. Upon success or HV_EINVAL, this service returns the | ||
| 115 | * actual size of the machine description in the RET1 return value. | ||
| 116 | * | ||
| 117 | * Note: A method of determining the appropriate buffer size for the | ||
| 118 | * machine description is to first call this service with a buffer | ||
| 119 | * length of 0 bytes. | ||
| 120 | */ | ||
| 121 | #define HV_FAST_MACH_DESC 0x01 | ||
| 122 | |||
| 123 | /* mach_exit() | ||
| 124 | * TRAP: HV_FAST_TRAP | ||
| 125 | * FUNCTION: HV_FAST_MACH_SIR | ||
| 126 | * ERRORS: This service does not return. | ||
| 127 | * | ||
| 128 | * Perform a software initiated reset of the virtual machine domain. | ||
| 129 | * All CPUs are captured as soon as possible, all hardware devices are | ||
| 130 | * returned to the entry default state, and the domain is restarted at | ||
| 131 | * the SIR (trap type 0x04) real trap table (RTBA) entry point on one | ||
| 132 | * of the CPUs. The single CPU restarted is selected as determined by | ||
| 133 | * platform specific policy. Memory is preserved across this | ||
| 134 | * operation. | ||
| 135 | */ | ||
| 136 | #define HV_FAST_MACH_SIR 0x02 | ||
| 137 | |||
| 138 | /* mach_set_soft_state() | ||
| 139 | * TRAP: HV_FAST_TRAP | ||
| 140 | * FUNCTION: HV_FAST_MACH_SET_SOFT_STATE | ||
| 141 | * ARG0: software state | ||
| 142 | * ARG1: software state description pointer | ||
| 143 | * RET0: status | ||
| 144 | * ERRORS: EINVAL software state not valid or software state | ||
| 145 | * description is not NULL terminated | ||
| 146 | * ENORADDR software state description pointer is not a | ||
| 147 | * valid real address | ||
| 148 | * EBADALIGNED software state description is not correctly | ||
| 149 | * aligned | ||
| 150 | * | ||
| 151 | * This allows the guest to report it's soft state to the hypervisor. There | ||
| 152 | * are two primary components to this state. The first part states whether | ||
| 153 | * the guest software is running or not. The second containts optional | ||
| 154 | * details specific to the software. | ||
| 155 | * | ||
| 156 | * The software state argument is defined below in HV_SOFT_STATE_*, and | ||
| 157 | * indicates whether the guest is operating normally or in a transitional | ||
| 158 | * state. | ||
| 159 | * | ||
| 160 | * The software state description argument is a real address of a data buffer | ||
| 161 | * of size 32-bytes aligned on a 32-byte boundary. It is treated as a NULL | ||
| 162 | * terminated 7-bit ASCII string of up to 31 characters not including the | ||
| 163 | * NULL termination. | ||
| 164 | */ | ||
| 165 | #define HV_FAST_MACH_SET_SOFT_STATE 0x03 | ||
| 166 | #define HV_SOFT_STATE_NORMAL 0x01 | ||
| 167 | #define HV_SOFT_STATE_TRANSITION 0x02 | ||
| 168 | |||
| 169 | /* mach_get_soft_state() | ||
| 170 | * TRAP: HV_FAST_TRAP | ||
| 171 | * FUNCTION: HV_FAST_MACH_GET_SOFT_STATE | ||
| 172 | * ARG0: software state description pointer | ||
| 173 | * RET0: status | ||
| 174 | * RET1: software state | ||
| 175 | * ERRORS: ENORADDR software state description pointer is not a | ||
| 176 | * valid real address | ||
| 177 | * EBADALIGNED software state description is not correctly | ||
| 178 | * aligned | ||
| 179 | * | ||
| 180 | * Retrieve the current value of the guest's software state. The rules | ||
| 181 | * for the software state pointer are the same as for mach_set_soft_state() | ||
| 182 | * above. | ||
| 183 | */ | ||
| 184 | #define HV_FAST_MACH_GET_SOFT_STATE 0x04 | ||
| 185 | |||
| 186 | /* CPU services. | ||
| 187 | * | ||
| 188 | * CPUs represent devices that can execute software threads. A single | ||
| 189 | * chip that contains multiple cores or strands is represented as | ||
| 190 | * multiple CPUs with unique CPU identifiers. CPUs are exported to | ||
| 191 | * OBP via the machine description (and to the OS via the OBP device | ||
| 192 | * tree). CPUs are always in one of three states: stopped, running, | ||
| 193 | * or error. | ||
| 194 | * | ||
| 195 | * A CPU ID is a pre-assigned 16-bit value that uniquely identifies a | ||
| 196 | * CPU within a logical domain. Operations that are to be performed | ||
| 197 | * on multiple CPUs specify them via a CPU list. A CPU list is an | ||
| 198 | * array in real memory, of which each 16-bit word is a CPU ID. CPU | ||
| 199 | * lists are passed through the API as two arguments. The first is | ||
| 200 | * the number of entries (16-bit words) in the CPU list, and the | ||
| 201 | * second is the (real address) pointer to the CPU ID list. | ||
| 202 | */ | ||
| 203 | |||
| 204 | /* cpu_start() | ||
| 205 | * TRAP: HV_FAST_TRAP | ||
| 206 | * FUNCTION: HV_FAST_CPU_START | ||
| 207 | * ARG0: CPU ID | ||
| 208 | * ARG1: PC | ||
| 209 | * ARG1: RTBA | ||
| 210 | * ARG1: target ARG0 | ||
| 211 | * RET0: status | ||
| 212 | * ERRORS: ENOCPU Invalid CPU ID | ||
| 213 | * EINVAL Target CPU ID is not in the stopped state | ||
| 214 | * ENORADDR Invalid PC or RTBA real address | ||
| 215 | * EBADALIGN Unaligned PC or unaligned RTBA | ||
| 216 | * EWOULDBLOCK Starting resources are not available | ||
| 217 | * | ||
| 218 | * Start CPU with given CPU ID with PC in %pc and with a real trap | ||
| 219 | * base address value of RTBA. The indicated CPU must be in the | ||
| 220 | * stopped state. The supplied RTBA must be aligned on a 256 byte | ||
| 221 | * boundary. On successful completion, the specified CPU will be in | ||
| 222 | * the running state and will be supplied with "target ARG0" in %o0 | ||
| 223 | * and RTBA in %tba. | ||
| 224 | */ | ||
| 225 | #define HV_FAST_CPU_START 0x10 | ||
| 226 | |||
| 227 | /* cpu_stop() | ||
| 228 | * TRAP: HV_FAST_TRAP | ||
| 229 | * FUNCTION: HV_FAST_CPU_STOP | ||
| 230 | * ARG0: CPU ID | ||
| 231 | * RET0: status | ||
| 232 | * ERRORS: ENOCPU Invalid CPU ID | ||
| 233 | * EINVAL Target CPU ID is the current cpu | ||
| 234 | * EINVAL Target CPU ID is not in the running state | ||
| 235 | * EWOULDBLOCK Stopping resources are not available | ||
| 236 | * ENOTSUPPORTED Not supported on this platform | ||
| 237 | * | ||
| 238 | * The specified CPU is stopped. The indicated CPU must be in the | ||
| 239 | * running state. On completion, it will be in the stopped state. It | ||
| 240 | * is not legal to stop the current CPU. | ||
| 241 | * | ||
| 242 | * Note: As this service cannot be used to stop the current cpu, this service | ||
| 243 | * may not be used to stop the last running CPU in a domain. To stop | ||
| 244 | * and exit a running domain, a guest must use the mach_exit() service. | ||
| 245 | */ | ||
| 246 | #define HV_FAST_CPU_STOP 0x11 | ||
| 247 | |||
| 248 | /* cpu_yield() | ||
| 249 | * TRAP: HV_FAST_TRAP | ||
| 250 | * FUNCTION: HV_FAST_CPU_YIELD | ||
| 251 | * RET0: status | ||
| 252 | * ERRORS: No possible error. | ||
| 253 | * | ||
| 254 | * Suspend execution on the current CPU. Execution will resume when | ||
| 255 | * an interrupt (device, %stick_compare, or cross-call) is targeted to | ||
| 256 | * the CPU. On some CPUs, this API may be used by the hypervisor to | ||
| 257 | * save power by disabling hardware strands. | ||
| 258 | */ | ||
| 259 | #define HV_FAST_CPU_YIELD 0x12 | ||
| 260 | |||
| 261 | #ifndef __ASSEMBLY__ | ||
| 262 | extern unsigned long sun4v_cpu_yield(void); | ||
| 263 | #endif | ||
| 264 | |||
| 265 | /* cpu_qconf() | ||
| 266 | * TRAP: HV_FAST_TRAP | ||
| 267 | * FUNCTION: HV_FAST_CPU_QCONF | ||
| 268 | * ARG0: queue | ||
| 269 | * ARG1: base real address | ||
| 270 | * ARG2: number of entries | ||
| 271 | * RET0: status | ||
| 272 | * ERRORS: ENORADDR Invalid base real address | ||
| 273 | * EINVAL Invalid queue or number of entries is less | ||
| 274 | * than 2 or too large. | ||
| 275 | * EBADALIGN Base real address is not correctly aligned | ||
| 276 | * for size. | ||
| 277 | * | ||
| 278 | * Configure the given queue to be placed at the given base real | ||
| 279 | * address, with the given number of entries. The number of entries | ||
| 280 | * must be a power of 2. The base real address must be aligned | ||
| 281 | * exactly to match the queue size. Each queue entry is 64 bytes | ||
| 282 | * long, so for example a 32 entry queue must be aligned on a 2048 | ||
| 283 | * byte real address boundary. | ||
| 284 | * | ||
| 285 | * The specified queue is unconfigured if the number of entries is given | ||
| 286 | * as zero. | ||
| 287 | * | ||
| 288 | * For the current version of this API service, the argument queue is defined | ||
| 289 | * as follows: | ||
| 290 | * | ||
| 291 | * queue description | ||
| 292 | * ----- ------------------------- | ||
| 293 | * 0x3c cpu mondo queue | ||
| 294 | * 0x3d device mondo queue | ||
| 295 | * 0x3e resumable error queue | ||
| 296 | * 0x3f non-resumable error queue | ||
| 297 | * | ||
| 298 | * Note: The maximum number of entries for each queue for a specific cpu may | ||
| 299 | * be determined from the machine description. | ||
| 300 | */ | ||
| 301 | #define HV_FAST_CPU_QCONF 0x14 | ||
| 302 | #define HV_CPU_QUEUE_CPU_MONDO 0x3c | ||
| 303 | #define HV_CPU_QUEUE_DEVICE_MONDO 0x3d | ||
| 304 | #define HV_CPU_QUEUE_RES_ERROR 0x3e | ||
| 305 | #define HV_CPU_QUEUE_NONRES_ERROR 0x3f | ||
| 306 | |||
| 307 | #ifndef __ASSEMBLY__ | ||
| 308 | extern unsigned long sun4v_cpu_qconf(unsigned long type, | ||
| 309 | unsigned long queue_paddr, | ||
| 310 | unsigned long num_queue_entries); | ||
| 311 | #endif | ||
| 312 | |||
| 313 | /* cpu_qinfo() | ||
| 314 | * TRAP: HV_FAST_TRAP | ||
| 315 | * FUNCTION: HV_FAST_CPU_QINFO | ||
| 316 | * ARG0: queue | ||
| 317 | * RET0: status | ||
| 318 | * RET1: base real address | ||
| 319 | * RET1: number of entries | ||
| 320 | * ERRORS: EINVAL Invalid queue | ||
| 321 | * | ||
| 322 | * Return the configuration info for the given queue. The base real | ||
| 323 | * address and number of entries of the defined queue are returned. | ||
| 324 | * The queue argument values are the same as for cpu_qconf() above. | ||
| 325 | * | ||
| 326 | * If the specified queue is a valid queue number, but no queue has | ||
| 327 | * been defined, the number of entries will be set to zero and the | ||
| 328 | * base real address returned is undefined. | ||
| 329 | */ | ||
| 330 | #define HV_FAST_CPU_QINFO 0x15 | ||
| 331 | |||
| 332 | /* cpu_mondo_send() | ||
| 333 | * TRAP: HV_FAST_TRAP | ||
| 334 | * FUNCTION: HV_FAST_CPU_MONDO_SEND | ||
| 335 | * ARG0-1: CPU list | ||
| 336 | * ARG2: data real address | ||
| 337 | * RET0: status | ||
| 338 | * ERRORS: EBADALIGN Mondo data is not 64-byte aligned or CPU list | ||
| 339 | * is not 2-byte aligned. | ||
| 340 | * ENORADDR Invalid data mondo address, or invalid cpu list | ||
| 341 | * address. | ||
| 342 | * ENOCPU Invalid cpu in CPU list | ||
| 343 | * EWOULDBLOCK Some or all of the listed CPUs did not receive | ||
| 344 | * the mondo | ||
| 345 | * ECPUERROR One or more of the listed CPUs are in error | ||
| 346 | * state, use HV_FAST_CPU_STATE to see which ones | ||
| 347 | * EINVAL CPU list includes caller's CPU ID | ||
| 348 | * | ||
| 349 | * Send a mondo interrupt to the CPUs in the given CPU list with the | ||
| 350 | * 64-bytes at the given data real address. The data must be 64-byte | ||
| 351 | * aligned. The mondo data will be delivered to the cpu_mondo queues | ||
| 352 | * of the recipient CPUs. | ||
| 353 | * | ||
| 354 | * In all cases, error or not, the CPUs in the CPU list to which the | ||
| 355 | * mondo has been successfully delivered will be indicated by having | ||
| 356 | * their entry in CPU list updated with the value 0xffff. | ||
| 357 | */ | ||
| 358 | #define HV_FAST_CPU_MONDO_SEND 0x42 | ||
| 359 | |||
| 360 | #ifndef __ASSEMBLY__ | ||
| 361 | extern unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, unsigned long cpu_list_pa, unsigned long mondo_block_pa); | ||
| 362 | #endif | ||
| 363 | |||
| 364 | /* cpu_myid() | ||
| 365 | * TRAP: HV_FAST_TRAP | ||
| 366 | * FUNCTION: HV_FAST_CPU_MYID | ||
| 367 | * RET0: status | ||
| 368 | * RET1: CPU ID | ||
| 369 | * ERRORS: No errors defined. | ||
| 370 | * | ||
| 371 | * Return the hypervisor ID handle for the current CPU. Use by a | ||
| 372 | * virtual CPU to discover it's own identity. | ||
| 373 | */ | ||
| 374 | #define HV_FAST_CPU_MYID 0x16 | ||
| 375 | |||
| 376 | /* cpu_state() | ||
| 377 | * TRAP: HV_FAST_TRAP | ||
| 378 | * FUNCTION: HV_FAST_CPU_STATE | ||
| 379 | * ARG0: CPU ID | ||
| 380 | * RET0: status | ||
| 381 | * RET1: state | ||
| 382 | * ERRORS: ENOCPU Invalid CPU ID | ||
| 383 | * | ||
| 384 | * Retrieve the current state of the CPU with the given CPU ID. | ||
| 385 | */ | ||
| 386 | #define HV_FAST_CPU_STATE 0x17 | ||
| 387 | #define HV_CPU_STATE_STOPPED 0x01 | ||
| 388 | #define HV_CPU_STATE_RUNNING 0x02 | ||
| 389 | #define HV_CPU_STATE_ERROR 0x03 | ||
| 390 | |||
| 391 | #ifndef __ASSEMBLY__ | ||
| 392 | extern long sun4v_cpu_state(unsigned long cpuid); | ||
| 393 | #endif | ||
| 394 | |||
| 395 | /* cpu_set_rtba() | ||
| 396 | * TRAP: HV_FAST_TRAP | ||
| 397 | * FUNCTION: HV_FAST_CPU_SET_RTBA | ||
| 398 | * ARG0: RTBA | ||
| 399 | * RET0: status | ||
| 400 | * RET1: previous RTBA | ||
| 401 | * ERRORS: ENORADDR Invalid RTBA real address | ||
| 402 | * EBADALIGN RTBA is incorrectly aligned for a trap table | ||
| 403 | * | ||
| 404 | * Set the real trap base address of the local cpu to the given RTBA. | ||
| 405 | * The supplied RTBA must be aligned on a 256 byte boundary. Upon | ||
| 406 | * success the previous value of the RTBA is returned in RET1. | ||
| 407 | * | ||
| 408 | * Note: This service does not affect %tba | ||
| 409 | */ | ||
| 410 | #define HV_FAST_CPU_SET_RTBA 0x18 | ||
| 411 | |||
| 412 | /* cpu_set_rtba() | ||
| 413 | * TRAP: HV_FAST_TRAP | ||
| 414 | * FUNCTION: HV_FAST_CPU_GET_RTBA | ||
| 415 | * RET0: status | ||
| 416 | * RET1: previous RTBA | ||
| 417 | * ERRORS: No possible error. | ||
| 418 | * | ||
| 419 | * Returns the current value of RTBA in RET1. | ||
| 420 | */ | ||
| 421 | #define HV_FAST_CPU_GET_RTBA 0x19 | ||
| 422 | |||
| 423 | /* MMU services. | ||
| 424 | * | ||
| 425 | * Layout of a TSB description for mmu_tsb_ctx{,non}0() calls. | ||
| 426 | */ | ||
| 427 | #ifndef __ASSEMBLY__ | ||
| 428 | struct hv_tsb_descr { | ||
| 429 | unsigned short pgsz_idx; | ||
| 430 | unsigned short assoc; | ||
| 431 | unsigned int num_ttes; /* in TTEs */ | ||
| 432 | unsigned int ctx_idx; | ||
| 433 | unsigned int pgsz_mask; | ||
| 434 | unsigned long tsb_base; | ||
| 435 | unsigned long resv; | ||
| 436 | }; | ||
| 437 | #endif | ||
| 438 | #define HV_TSB_DESCR_PGSZ_IDX_OFFSET 0x00 | ||
| 439 | #define HV_TSB_DESCR_ASSOC_OFFSET 0x02 | ||
| 440 | #define HV_TSB_DESCR_NUM_TTES_OFFSET 0x04 | ||
| 441 | #define HV_TSB_DESCR_CTX_IDX_OFFSET 0x08 | ||
| 442 | #define HV_TSB_DESCR_PGSZ_MASK_OFFSET 0x0c | ||
| 443 | #define HV_TSB_DESCR_TSB_BASE_OFFSET 0x10 | ||
| 444 | #define HV_TSB_DESCR_RESV_OFFSET 0x18 | ||
| 445 | |||
| 446 | /* Page size bitmask. */ | ||
| 447 | #define HV_PGSZ_MASK_8K (1 << 0) | ||
| 448 | #define HV_PGSZ_MASK_64K (1 << 1) | ||
| 449 | #define HV_PGSZ_MASK_512K (1 << 2) | ||
| 450 | #define HV_PGSZ_MASK_4MB (1 << 3) | ||
| 451 | #define HV_PGSZ_MASK_32MB (1 << 4) | ||
| 452 | #define HV_PGSZ_MASK_256MB (1 << 5) | ||
| 453 | #define HV_PGSZ_MASK_2GB (1 << 6) | ||
| 454 | #define HV_PGSZ_MASK_16GB (1 << 7) | ||
| 455 | |||
| 456 | /* Page size index. The value given in the TSB descriptor must correspond | ||
| 457 | * to the smallest page size specified in the pgsz_mask page size bitmask. | ||
| 458 | */ | ||
| 459 | #define HV_PGSZ_IDX_8K 0 | ||
| 460 | #define HV_PGSZ_IDX_64K 1 | ||
| 461 | #define HV_PGSZ_IDX_512K 2 | ||
| 462 | #define HV_PGSZ_IDX_4MB 3 | ||
| 463 | #define HV_PGSZ_IDX_32MB 4 | ||
| 464 | #define HV_PGSZ_IDX_256MB 5 | ||
| 465 | #define HV_PGSZ_IDX_2GB 6 | ||
| 466 | #define HV_PGSZ_IDX_16GB 7 | ||
| 467 | |||
| 468 | /* MMU fault status area. | ||
| 469 | * | ||
| 470 | * MMU related faults have their status and fault address information | ||
| 471 | * placed into a memory region made available by privileged code. Each | ||
| 472 | * virtual processor must make a mmu_fault_area_conf() call to tell the | ||
| 473 | * hypervisor where that processor's fault status should be stored. | ||
| 474 | * | ||
| 475 | * The fault status block is a multiple of 64-bytes and must be aligned | ||
| 476 | * on a 64-byte boundary. | ||
| 477 | */ | ||
| 478 | #ifndef __ASSEMBLY__ | ||
| 479 | struct hv_fault_status { | ||
| 480 | unsigned long i_fault_type; | ||
| 481 | unsigned long i_fault_addr; | ||
| 482 | unsigned long i_fault_ctx; | ||
| 483 | unsigned long i_reserved[5]; | ||
| 484 | unsigned long d_fault_type; | ||
| 485 | unsigned long d_fault_addr; | ||
| 486 | unsigned long d_fault_ctx; | ||
| 487 | unsigned long d_reserved[5]; | ||
| 488 | }; | ||
| 489 | #endif | ||
| 490 | #define HV_FAULT_I_TYPE_OFFSET 0x00 | ||
| 491 | #define HV_FAULT_I_ADDR_OFFSET 0x08 | ||
| 492 | #define HV_FAULT_I_CTX_OFFSET 0x10 | ||
| 493 | #define HV_FAULT_D_TYPE_OFFSET 0x40 | ||
| 494 | #define HV_FAULT_D_ADDR_OFFSET 0x48 | ||
| 495 | #define HV_FAULT_D_CTX_OFFSET 0x50 | ||
| 496 | |||
| 497 | #define HV_FAULT_TYPE_FAST_MISS 1 | ||
| 498 | #define HV_FAULT_TYPE_FAST_PROT 2 | ||
| 499 | #define HV_FAULT_TYPE_MMU_MISS 3 | ||
| 500 | #define HV_FAULT_TYPE_INV_RA 4 | ||
| 501 | #define HV_FAULT_TYPE_PRIV_VIOL 5 | ||
| 502 | #define HV_FAULT_TYPE_PROT_VIOL 6 | ||
| 503 | #define HV_FAULT_TYPE_NFO 7 | ||
| 504 | #define HV_FAULT_TYPE_NFO_SEFF 8 | ||
| 505 | #define HV_FAULT_TYPE_INV_VA 9 | ||
| 506 | #define HV_FAULT_TYPE_INV_ASI 10 | ||
| 507 | #define HV_FAULT_TYPE_NC_ATOMIC 11 | ||
| 508 | #define HV_FAULT_TYPE_PRIV_ACT 12 | ||
| 509 | #define HV_FAULT_TYPE_RESV1 13 | ||
| 510 | #define HV_FAULT_TYPE_UNALIGNED 14 | ||
| 511 | #define HV_FAULT_TYPE_INV_PGSZ 15 | ||
| 512 | /* Values 16 --> -2 are reserved. */ | ||
| 513 | #define HV_FAULT_TYPE_MULTIPLE -1 | ||
| 514 | |||
| 515 | /* Flags argument for mmu_{map,unmap}_addr(), mmu_demap_{page,context,all}(), | ||
| 516 | * and mmu_{map,unmap}_perm_addr(). | ||
| 517 | */ | ||
| 518 | #define HV_MMU_DMMU 0x01 | ||
| 519 | #define HV_MMU_IMMU 0x02 | ||
| 520 | #define HV_MMU_ALL (HV_MMU_DMMU | HV_MMU_IMMU) | ||
| 521 | |||
| 522 | /* mmu_map_addr() | ||
| 523 | * TRAP: HV_MMU_MAP_ADDR_TRAP | ||
| 524 | * ARG0: virtual address | ||
| 525 | * ARG1: mmu context | ||
| 526 | * ARG2: TTE | ||
| 527 | * ARG3: flags (HV_MMU_{IMMU,DMMU}) | ||
| 528 | * ERRORS: EINVAL Invalid virtual address, mmu context, or flags | ||
| 529 | * EBADPGSZ Invalid page size value | ||
| 530 | * ENORADDR Invalid real address in TTE | ||
| 531 | * | ||
| 532 | * Create a non-permanent mapping using the given TTE, virtual | ||
| 533 | * address, and mmu context. The flags argument determines which | ||
| 534 | * (data, or instruction, or both) TLB the mapping gets loaded into. | ||
| 535 | * | ||
| 536 | * The behavior is undefined if the valid bit is clear in the TTE. | ||
| 537 | * | ||
| 538 | * Note: This API call is for privileged code to specify temporary translation | ||
| 539 | * mappings without the need to create and manage a TSB. | ||
| 540 | */ | ||
| 541 | |||
| 542 | /* mmu_unmap_addr() | ||
| 543 | * TRAP: HV_MMU_UNMAP_ADDR_TRAP | ||
| 544 | * ARG0: virtual address | ||
| 545 | * ARG1: mmu context | ||
| 546 | * ARG2: flags (HV_MMU_{IMMU,DMMU}) | ||
| 547 | * ERRORS: EINVAL Invalid virtual address, mmu context, or flags | ||
| 548 | * | ||
| 549 | * Demaps the given virtual address in the given mmu context on this | ||
| 550 | * CPU. This function is intended to be used to demap pages mapped | ||
| 551 | * with mmu_map_addr. This service is equivalent to invoking | ||
| 552 | * mmu_demap_page() with only the current CPU in the CPU list. The | ||
| 553 | * flags argument determines which (data, or instruction, or both) TLB | ||
| 554 | * the mapping gets unmapped from. | ||
| 555 | * | ||
| 556 | * Attempting to perform an unmap operation for a previously defined | ||
| 557 | * permanent mapping will have undefined results. | ||
| 558 | */ | ||
| 559 | |||
| 560 | /* mmu_tsb_ctx0() | ||
| 561 | * TRAP: HV_FAST_TRAP | ||
| 562 | * FUNCTION: HV_FAST_MMU_TSB_CTX0 | ||
| 563 | * ARG0: number of TSB descriptions | ||
| 564 | * ARG1: TSB descriptions pointer | ||
| 565 | * RET0: status | ||
| 566 | * ERRORS: ENORADDR Invalid TSB descriptions pointer or | ||
| 567 | * TSB base within a descriptor | ||
| 568 | * EBADALIGN TSB descriptions pointer is not aligned | ||
| 569 | * to an 8-byte boundary, or TSB base | ||
| 570 | * within a descriptor is not aligned for | ||
| 571 | * the given TSB size | ||
| 572 | * EBADPGSZ Invalid page size in a TSB descriptor | ||
| 573 | * EBADTSB Invalid associativity or size in a TSB | ||
| 574 | * descriptor | ||
| 575 | * EINVAL Invalid number of TSB descriptions, or | ||
| 576 | * invalid context index in a TSB | ||
| 577 | * descriptor, or index page size not | ||
| 578 | * equal to smallest page size in page | ||
| 579 | * size bitmask field. | ||
| 580 | * | ||
| 581 | * Configures the TSBs for the current CPU for virtual addresses with | ||
| 582 | * context zero. The TSB descriptions pointer is a pointer to an | ||
| 583 | * array of the given number of TSB descriptions. | ||
| 584 | * | ||
| 585 | * Note: The maximum number of TSBs available to a virtual CPU is given by the | ||
| 586 | * mmu-max-#tsbs property of the cpu's corresponding "cpu" node in the | ||
| 587 | * machine description. | ||
| 588 | */ | ||
| 589 | #define HV_FAST_MMU_TSB_CTX0 0x20 | ||
| 590 | |||
| 591 | /* mmu_tsb_ctxnon0() | ||
| 592 | * TRAP: HV_FAST_TRAP | ||
| 593 | * FUNCTION: HV_FAST_MMU_TSB_CTXNON0 | ||
| 594 | * ARG0: number of TSB descriptions | ||
| 595 | * ARG1: TSB descriptions pointer | ||
| 596 | * RET0: status | ||
| 597 | * ERRORS: Same as for mmu_tsb_ctx0() above. | ||
| 598 | * | ||
| 599 | * Configures the TSBs for the current CPU for virtual addresses with | ||
| 600 | * non-zero contexts. The TSB descriptions pointer is a pointer to an | ||
| 601 | * array of the given number of TSB descriptions. | ||
| 602 | * | ||
| 603 | * Note: A maximum of 16 TSBs may be specified in the TSB description list. | ||
| 604 | */ | ||
| 605 | #define HV_FAST_MMU_TSB_CTXNON0 0x21 | ||
| 606 | |||
| 607 | /* mmu_demap_page() | ||
| 608 | * TRAP: HV_FAST_TRAP | ||
| 609 | * FUNCTION: HV_FAST_MMU_DEMAP_PAGE | ||
| 610 | * ARG0: reserved, must be zero | ||
| 611 | * ARG1: reserved, must be zero | ||
| 612 | * ARG2: virtual address | ||
| 613 | * ARG3: mmu context | ||
| 614 | * ARG4: flags (HV_MMU_{IMMU,DMMU}) | ||
| 615 | * RET0: status | ||
| 616 | * ERRORS: EINVAL Invalid virutal address, context, or | ||
| 617 | * flags value | ||
| 618 | * ENOTSUPPORTED ARG0 or ARG1 is non-zero | ||
| 619 | * | ||
| 620 | * Demaps any page mapping of the given virtual address in the given | ||
| 621 | * mmu context for the current virtual CPU. Any virtually tagged | ||
| 622 | * caches are guaranteed to be kept consistent. The flags argument | ||
| 623 | * determines which TLB (instruction, or data, or both) participate in | ||
| 624 | * the operation. | ||
| 625 | * | ||
| 626 | * ARG0 and ARG1 are both reserved and must be set to zero. | ||
| 627 | */ | ||
| 628 | #define HV_FAST_MMU_DEMAP_PAGE 0x22 | ||
| 629 | |||
| 630 | /* mmu_demap_ctx() | ||
| 631 | * TRAP: HV_FAST_TRAP | ||
| 632 | * FUNCTION: HV_FAST_MMU_DEMAP_CTX | ||
| 633 | * ARG0: reserved, must be zero | ||
| 634 | * ARG1: reserved, must be zero | ||
| 635 | * ARG2: mmu context | ||
| 636 | * ARG3: flags (HV_MMU_{IMMU,DMMU}) | ||
| 637 | * RET0: status | ||
| 638 | * ERRORS: EINVAL Invalid context or flags value | ||
| 639 | * ENOTSUPPORTED ARG0 or ARG1 is non-zero | ||
| 640 | * | ||
| 641 | * Demaps all non-permanent virtual page mappings previously specified | ||
| 642 | * for the given context for the current virtual CPU. Any virtual | ||
| 643 | * tagged caches are guaranteed to be kept consistent. The flags | ||
| 644 | * argument determines which TLB (instruction, or data, or both) | ||
| 645 | * participate in the operation. | ||
| 646 | * | ||
| 647 | * ARG0 and ARG1 are both reserved and must be set to zero. | ||
| 648 | */ | ||
| 649 | #define HV_FAST_MMU_DEMAP_CTX 0x23 | ||
| 650 | |||
| 651 | /* mmu_demap_all() | ||
| 652 | * TRAP: HV_FAST_TRAP | ||
| 653 | * FUNCTION: HV_FAST_MMU_DEMAP_ALL | ||
| 654 | * ARG0: reserved, must be zero | ||
| 655 | * ARG1: reserved, must be zero | ||
| 656 | * ARG2: flags (HV_MMU_{IMMU,DMMU}) | ||
| 657 | * RET0: status | ||
| 658 | * ERRORS: EINVAL Invalid flags value | ||
| 659 | * ENOTSUPPORTED ARG0 or ARG1 is non-zero | ||
| 660 | * | ||
| 661 | * Demaps all non-permanent virtual page mappings previously specified | ||
| 662 | * for the current virtual CPU. Any virtual tagged caches are | ||
| 663 | * guaranteed to be kept consistent. The flags argument determines | ||
| 664 | * which TLB (instruction, or data, or both) participate in the | ||
| 665 | * operation. | ||
| 666 | * | ||
| 667 | * ARG0 and ARG1 are both reserved and must be set to zero. | ||
| 668 | */ | ||
| 669 | #define HV_FAST_MMU_DEMAP_ALL 0x24 | ||
| 670 | |||
| 671 | /* mmu_map_perm_addr() | ||
| 672 | * TRAP: HV_FAST_TRAP | ||
| 673 | * FUNCTION: HV_FAST_MMU_MAP_PERM_ADDR | ||
| 674 | * ARG0: virtual address | ||
| 675 | * ARG1: reserved, must be zero | ||
| 676 | * ARG2: TTE | ||
| 677 | * ARG3: flags (HV_MMU_{IMMU,DMMU}) | ||
| 678 | * RET0: status | ||
| 679 | * ERRORS: EINVAL Invalid virutal address or flags value | ||
| 680 | * EBADPGSZ Invalid page size value | ||
| 681 | * ENORADDR Invalid real address in TTE | ||
| 682 | * ETOOMANY Too many mappings (max of 8 reached) | ||
| 683 | * | ||
| 684 | * Create a permanent mapping using the given TTE and virtual address | ||
| 685 | * for context 0 on the calling virtual CPU. A maximum of 8 such | ||
| 686 | * permanent mappings may be specified by privileged code. Mappings | ||
| 687 | * may be removed with mmu_unmap_perm_addr(). | ||
| 688 | * | ||
| 689 | * The behavior is undefined if a TTE with the valid bit clear is given. | ||
| 690 | * | ||
| 691 | * Note: This call is used to specify address space mappings for which | ||
| 692 | * privileged code does not expect to receive misses. For example, | ||
| 693 | * this mechanism can be used to map kernel nucleus code and data. | ||
| 694 | */ | ||
| 695 | #define HV_FAST_MMU_MAP_PERM_ADDR 0x25 | ||
| 696 | |||
| 697 | /* mmu_fault_area_conf() | ||
| 698 | * TRAP: HV_FAST_TRAP | ||
| 699 | * FUNCTION: HV_FAST_MMU_FAULT_AREA_CONF | ||
| 700 | * ARG0: real address | ||
| 701 | * RET0: status | ||
| 702 | * RET1: previous mmu fault area real address | ||
| 703 | * ERRORS: ENORADDR Invalid real address | ||
| 704 | * EBADALIGN Invalid alignment for fault area | ||
| 705 | * | ||
| 706 | * Configure the MMU fault status area for the calling CPU. A 64-byte | ||
| 707 | * aligned real address specifies where MMU fault status information | ||
| 708 | * is placed. The return value is the previously specified area, or 0 | ||
| 709 | * for the first invocation. Specifying a fault area at real address | ||
| 710 | * 0 is not allowed. | ||
| 711 | */ | ||
| 712 | #define HV_FAST_MMU_FAULT_AREA_CONF 0x26 | ||
| 713 | |||
| 714 | /* mmu_enable() | ||
| 715 | * TRAP: HV_FAST_TRAP | ||
| 716 | * FUNCTION: HV_FAST_MMU_ENABLE | ||
| 717 | * ARG0: enable flag | ||
| 718 | * ARG1: return target address | ||
| 719 | * RET0: status | ||
| 720 | * ERRORS: ENORADDR Invalid real address when disabling | ||
| 721 | * translation. | ||
| 722 | * EBADALIGN The return target address is not | ||
| 723 | * aligned to an instruction. | ||
| 724 | * EINVAL The enable flag request the current | ||
| 725 | * operating mode (e.g. disable if already | ||
| 726 | * disabled) | ||
| 727 | * | ||
| 728 | * Enable or disable virtual address translation for the calling CPU | ||
| 729 | * within the virtual machine domain. If the enable flag is zero, | ||
| 730 | * translation is disabled, any non-zero value will enable | ||
| 731 | * translation. | ||
| 732 | * | ||
| 733 | * When this function returns, the newly selected translation mode | ||
| 734 | * will be active. If the mmu is being enabled, then the return | ||
| 735 | * target address is a virtual address else it is a real address. | ||
| 736 | * | ||
| 737 | * Upon successful completion, control will be returned to the given | ||
| 738 | * return target address (ie. the cpu will jump to that address). On | ||
| 739 | * failure, the previous mmu mode remains and the trap simply returns | ||
| 740 | * as normal with the appropriate error code in RET0. | ||
| 741 | */ | ||
| 742 | #define HV_FAST_MMU_ENABLE 0x27 | ||
| 743 | |||
| 744 | /* mmu_unmap_perm_addr() | ||
| 745 | * TRAP: HV_FAST_TRAP | ||
| 746 | * FUNCTION: HV_FAST_MMU_UNMAP_PERM_ADDR | ||
| 747 | * ARG0: virtual address | ||
| 748 | * ARG1: reserved, must be zero | ||
| 749 | * ARG2: flags (HV_MMU_{IMMU,DMMU}) | ||
| 750 | * RET0: status | ||
| 751 | * ERRORS: EINVAL Invalid virutal address or flags value | ||
| 752 | * ENOMAP Specified mapping was not found | ||
| 753 | * | ||
| 754 | * Demaps any permanent page mapping (established via | ||
| 755 | * mmu_map_perm_addr()) at the given virtual address for context 0 on | ||
| 756 | * the current virtual CPU. Any virtual tagged caches are guaranteed | ||
| 757 | * to be kept consistent. | ||
| 758 | */ | ||
| 759 | #define HV_FAST_MMU_UNMAP_PERM_ADDR 0x28 | ||
| 760 | |||
| 761 | /* mmu_tsb_ctx0_info() | ||
| 762 | * TRAP: HV_FAST_TRAP | ||
| 763 | * FUNCTION: HV_FAST_MMU_TSB_CTX0_INFO | ||
| 764 | * ARG0: max TSBs | ||
| 765 | * ARG1: buffer pointer | ||
| 766 | * RET0: status | ||
| 767 | * RET1: number of TSBs | ||
| 768 | * ERRORS: EINVAL Supplied buffer is too small | ||
| 769 | * EBADALIGN The buffer pointer is badly aligned | ||
| 770 | * ENORADDR Invalid real address for buffer pointer | ||
| 771 | * | ||
| 772 | * Return the TSB configuration as previous defined by mmu_tsb_ctx0() | ||
| 773 | * into the provided buffer. The size of the buffer is given in ARG1 | ||
| 774 | * in terms of the number of TSB description entries. | ||
| 775 | * | ||
| 776 | * Upon return, RET1 always contains the number of TSB descriptions | ||
| 777 | * previously configured. If zero TSBs were configured, EOK is | ||
| 778 | * returned with RET1 containing 0. | ||
| 779 | */ | ||
| 780 | #define HV_FAST_MMU_TSB_CTX0_INFO 0x29 | ||
| 781 | |||
| 782 | /* mmu_tsb_ctxnon0_info() | ||
| 783 | * TRAP: HV_FAST_TRAP | ||
| 784 | * FUNCTION: HV_FAST_MMU_TSB_CTXNON0_INFO | ||
| 785 | * ARG0: max TSBs | ||
| 786 | * ARG1: buffer pointer | ||
| 787 | * RET0: status | ||
| 788 | * RET1: number of TSBs | ||
| 789 | * ERRORS: EINVAL Supplied buffer is too small | ||
| 790 | * EBADALIGN The buffer pointer is badly aligned | ||
| 791 | * ENORADDR Invalid real address for buffer pointer | ||
| 792 | * | ||
| 793 | * Return the TSB configuration as previous defined by | ||
| 794 | * mmu_tsb_ctxnon0() into the provided buffer. The size of the buffer | ||
| 795 | * is given in ARG1 in terms of the number of TSB description entries. | ||
| 796 | * | ||
| 797 | * Upon return, RET1 always contains the number of TSB descriptions | ||
| 798 | * previously configured. If zero TSBs were configured, EOK is | ||
| 799 | * returned with RET1 containing 0. | ||
| 800 | */ | ||
| 801 | #define HV_FAST_MMU_TSB_CTXNON0_INFO 0x2a | ||
| 802 | |||
| 803 | /* mmu_fault_area_info() | ||
| 804 | * TRAP: HV_FAST_TRAP | ||
| 805 | * FUNCTION: HV_FAST_MMU_FAULT_AREA_INFO | ||
| 806 | * RET0: status | ||
| 807 | * RET1: fault area real address | ||
| 808 | * ERRORS: No errors defined. | ||
| 809 | * | ||
| 810 | * Return the currently defined MMU fault status area for the current | ||
| 811 | * CPU. The real address of the fault status area is returned in | ||
| 812 | * RET1, or 0 is returned in RET1 if no fault status area is defined. | ||
| 813 | * | ||
| 814 | * Note: mmu_fault_area_conf() may be called with the return value (RET1) | ||
| 815 | * from this service if there is a need to save and restore the fault | ||
| 816 | * area for a cpu. | ||
| 817 | */ | ||
| 818 | #define HV_FAST_MMU_FAULT_AREA_INFO 0x2b | ||
| 819 | |||
| 820 | /* Cache and Memory services. */ | ||
| 821 | |||
| 822 | /* mem_scrub() | ||
| 823 | * TRAP: HV_FAST_TRAP | ||
| 824 | * FUNCTION: HV_FAST_MEM_SCRUB | ||
| 825 | * ARG0: real address | ||
| 826 | * ARG1: length | ||
| 827 | * RET0: status | ||
| 828 | * RET1: length scrubbed | ||
| 829 | * ERRORS: ENORADDR Invalid real address | ||
| 830 | * EBADALIGN Start address or length are not correctly | ||
| 831 | * aligned | ||
| 832 | * EINVAL Length is zero | ||
| 833 | * | ||
| 834 | * Zero the memory contents in the range real address to real address | ||
| 835 | * plus length minus 1. Also, valid ECC will be generated for that | ||
| 836 | * memory address range. Scrubbing is started at the given real | ||
| 837 | * address, but may not scrub the entire given length. The actual | ||
| 838 | * length scrubbed will be returned in RET1. | ||
| 839 | * | ||
| 840 | * The real address and length must be aligned on an 8K boundary, or | ||
| 841 | * contain the start address and length from a sun4v error report. | ||
| 842 | * | ||
| 843 | * Note: There are two uses for this function. The first use is to block clear | ||
| 844 | * and initialize memory and the second is to scrub an u ncorrectable | ||
| 845 | * error reported via a resumable or non-resumable trap. The second | ||
| 846 | * use requires the arguments to be equal to the real address and length | ||
| 847 | * provided in a sun4v memory error report. | ||
| 848 | */ | ||
| 849 | #define HV_FAST_MEM_SCRUB 0x31 | ||
| 850 | |||
| 851 | /* mem_sync() | ||
| 852 | * TRAP: HV_FAST_TRAP | ||
| 853 | * FUNCTION: HV_FAST_MEM_SYNC | ||
| 854 | * ARG0: real address | ||
| 855 | * ARG1: length | ||
| 856 | * RET0: status | ||
| 857 | * RET1: length synced | ||
| 858 | * ERRORS: ENORADDR Invalid real address | ||
| 859 | * EBADALIGN Start address or length are not correctly | ||
| 860 | * aligned | ||
| 861 | * EINVAL Length is zero | ||
| 862 | * | ||
| 863 | * Force the next access within the real address to real address plus | ||
| 864 | * length minus 1 to be fetches from main system memory. Less than | ||
| 865 | * the given length may be synced, the actual amount synced is | ||
| 866 | * returned in RET1. The real address and length must be aligned on | ||
| 867 | * an 8K boundary. | ||
| 868 | */ | ||
| 869 | #define HV_FAST_MEM_SYNC 0x32 | ||
| 870 | |||
| 871 | /* Time of day services. | ||
| 872 | * | ||
| 873 | * The hypervisor maintains the time of day on a per-domain basis. | ||
| 874 | * Changing the time of day in one domain does not affect the time of | ||
| 875 | * day on any other domain. | ||
| 876 | * | ||
| 877 | * Time is described by a single unsigned 64-bit word which is the | ||
| 878 | * number of seconds since the UNIX Epoch (00:00:00 UTC, January 1, | ||
| 879 | * 1970). | ||
| 880 | */ | ||
| 881 | |||
| 882 | /* tod_get() | ||
| 883 | * TRAP: HV_FAST_TRAP | ||
| 884 | * FUNCTION: HV_FAST_TOD_GET | ||
| 885 | * RET0: status | ||
| 886 | * RET1: TOD | ||
| 887 | * ERRORS: EWOULDBLOCK TOD resource is temporarily unavailable | ||
| 888 | * ENOTSUPPORTED If TOD not supported on this platform | ||
| 889 | * | ||
| 890 | * Return the current time of day. May block if TOD access is | ||
| 891 | * temporarily not possible. | ||
| 892 | */ | ||
| 893 | #define HV_FAST_TOD_GET 0x50 | ||
| 894 | |||
| 895 | /* tod_set() | ||
| 896 | * TRAP: HV_FAST_TRAP | ||
| 897 | * FUNCTION: HV_FAST_TOD_SET | ||
| 898 | * ARG0: TOD | ||
| 899 | * RET0: status | ||
| 900 | * ERRORS: EWOULDBLOCK TOD resource is temporarily unavailable | ||
| 901 | * ENOTSUPPORTED If TOD not supported on this platform | ||
| 902 | * | ||
| 903 | * The current time of day is set to the value specified in ARG0. May | ||
| 904 | * block if TOD access is temporarily not possible. | ||
| 905 | */ | ||
| 906 | #define HV_FAST_TOD_SET 0x51 | ||
| 907 | |||
| 908 | /* Console services */ | ||
| 909 | |||
| 910 | /* con_getchar() | ||
| 911 | * TRAP: HV_FAST_TRAP | ||
| 912 | * FUNCTION: HV_FAST_CONS_GETCHAR | ||
| 913 | * RET0: status | ||
| 914 | * RET1: character | ||
| 915 | * ERRORS: EWOULDBLOCK No character available. | ||
| 916 | * | ||
| 917 | * Returns a character from the console device. If no character is | ||
| 918 | * available then an EWOULDBLOCK error is returned. If a character is | ||
| 919 | * available, then the returned status is EOK and the character value | ||
| 920 | * is in RET1. | ||
| 921 | * | ||
| 922 | * A virtual BREAK is represented by the 64-bit value -1. | ||
| 923 | * | ||
| 924 | * A virtual HUP signal is represented by the 64-bit value -2. | ||
| 925 | */ | ||
| 926 | #define HV_FAST_CONS_GETCHAR 0x60 | ||
| 927 | |||
| 928 | /* con_putchar() | ||
| 929 | * TRAP: HV_FAST_TRAP | ||
| 930 | * FUNCTION: HV_FAST_CONS_PUTCHAR | ||
| 931 | * ARG0: character | ||
| 932 | * RET0: status | ||
| 933 | * ERRORS: EINVAL Illegal character | ||
| 934 | * EWOULDBLOCK Output buffer currently full, would block | ||
| 935 | * | ||
| 936 | * Send a character to the console device. Only character values | ||
| 937 | * between 0 and 255 may be used. Values outside this range are | ||
| 938 | * invalid except for the 64-bit value -1 which is used to send a | ||
| 939 | * virtual BREAK. | ||
| 940 | */ | ||
| 941 | #define HV_FAST_CONS_PUTCHAR 0x61 | ||
| 942 | |||
| 943 | /* Trap trace services. | ||
| 944 | * | ||
| 945 | * The hypervisor provides a trap tracing capability for privileged | ||
| 946 | * code running on each virtual CPU. Privileged code provides a | ||
| 947 | * round-robin trap trace queue within which the hypervisor writes | ||
| 948 | * 64-byte entries detailing hyperprivileged traps taken n behalf of | ||
| 949 | * privileged code. This is provided as a debugging capability for | ||
| 950 | * privileged code. | ||
| 951 | * | ||
| 952 | * The trap trace control structure is 64-bytes long and placed at the | ||
| 953 | * start (offset 0) of the trap trace buffer, and is described as | ||
| 954 | * follows: | ||
| 955 | */ | ||
| 956 | #ifndef __ASSEMBLY__ | ||
| 957 | struct hv_trap_trace_control { | ||
| 958 | unsigned long head_offset; | ||
| 959 | unsigned long tail_offset; | ||
| 960 | unsigned long __reserved[0x30 / sizeof(unsigned long)]; | ||
| 961 | }; | ||
| 962 | #endif | ||
| 963 | #define HV_TRAP_TRACE_CTRL_HEAD_OFFSET 0x00 | ||
| 964 | #define HV_TRAP_TRACE_CTRL_TAIL_OFFSET 0x08 | ||
| 965 | |||
| 966 | /* The head offset is the offset of the most recently completed entry | ||
| 967 | * in the trap-trace buffer. The tail offset is the offset of the | ||
| 968 | * next entry to be written. The control structure is owned and | ||
| 969 | * modified by the hypervisor. A guest may not modify the control | ||
| 970 | * structure contents. Attempts to do so will result in undefined | ||
| 971 | * behavior for the guest. | ||
| 972 | * | ||
| 973 | * Each trap trace buffer entry is layed out as follows: | ||
| 974 | */ | ||
| 975 | #ifndef __ASSEMBLY__ | ||
| 976 | struct hv_trap_trace_entry { | ||
| 977 | unsigned char type; /* Hypervisor or guest entry? */ | ||
| 978 | unsigned char hpstate; /* Hyper-privileged state */ | ||
| 979 | unsigned char tl; /* Trap level */ | ||
| 980 | unsigned char gl; /* Global register level */ | ||
| 981 | unsigned short tt; /* Trap type */ | ||
| 982 | unsigned short tag; /* Extended trap identifier */ | ||
| 983 | unsigned long tstate; /* Trap state */ | ||
| 984 | unsigned long tick; /* Tick */ | ||
| 985 | unsigned long tpc; /* Trap PC */ | ||
| 986 | unsigned long f1; /* Entry specific */ | ||
| 987 | unsigned long f2; /* Entry specific */ | ||
| 988 | unsigned long f3; /* Entry specific */ | ||
| 989 | unsigned long f4; /* Entry specific */ | ||
| 990 | }; | ||
| 991 | #endif | ||
| 992 | #define HV_TRAP_TRACE_ENTRY_TYPE 0x00 | ||
| 993 | #define HV_TRAP_TRACE_ENTRY_HPSTATE 0x01 | ||
| 994 | #define HV_TRAP_TRACE_ENTRY_TL 0x02 | ||
| 995 | #define HV_TRAP_TRACE_ENTRY_GL 0x03 | ||
| 996 | #define HV_TRAP_TRACE_ENTRY_TT 0x04 | ||
| 997 | #define HV_TRAP_TRACE_ENTRY_TAG 0x06 | ||
| 998 | #define HV_TRAP_TRACE_ENTRY_TSTATE 0x08 | ||
| 999 | #define HV_TRAP_TRACE_ENTRY_TICK 0x10 | ||
| 1000 | #define HV_TRAP_TRACE_ENTRY_TPC 0x18 | ||
| 1001 | #define HV_TRAP_TRACE_ENTRY_F1 0x20 | ||
| 1002 | #define HV_TRAP_TRACE_ENTRY_F2 0x28 | ||
| 1003 | #define HV_TRAP_TRACE_ENTRY_F3 0x30 | ||
| 1004 | #define HV_TRAP_TRACE_ENTRY_F4 0x38 | ||
| 1005 | |||
| 1006 | /* The type field is encoded as follows. */ | ||
| 1007 | #define HV_TRAP_TYPE_UNDEF 0x00 /* Entry content undefined */ | ||
| 1008 | #define HV_TRAP_TYPE_HV 0x01 /* Hypervisor trap entry */ | ||
| 1009 | #define HV_TRAP_TYPE_GUEST 0xff /* Added via ttrace_addentry() */ | ||
| 1010 | |||
| 1011 | /* ttrace_buf_conf() | ||
| 1012 | * TRAP: HV_FAST_TRAP | ||
| 1013 | * FUNCTION: HV_FAST_TTRACE_BUF_CONF | ||
| 1014 | * ARG0: real address | ||
| 1015 | * ARG1: number of entries | ||
| 1016 | * RET0: status | ||
| 1017 | * RET1: number of entries | ||
| 1018 | * ERRORS: ENORADDR Invalid real address | ||
| 1019 | * EINVAL Size is too small | ||
| 1020 | * EBADALIGN Real address not aligned on 64-byte boundary | ||
| 1021 | * | ||
| 1022 | * Requests hypervisor trap tracing and declares a virtual CPU's trap | ||
| 1023 | * trace buffer to the hypervisor. The real address supplies the real | ||
| 1024 | * base address of the trap trace queue and must be 64-byte aligned. | ||
| 1025 | * Specifying a value of 0 for the number of entries disables trap | ||
| 1026 | * tracing for the calling virtual CPU. The buffer allocated must be | ||
| 1027 | * sized for a power of two number of 64-byte trap trace entries plus | ||
| 1028 | * an initial 64-byte control structure. | ||
| 1029 | * | ||
| 1030 | * This may be invoked any number of times so that a virtual CPU may | ||
| 1031 | * relocate a trap trace buffer or create "snapshots" of information. | ||
| 1032 | * | ||
| 1033 | * If the real address is illegal or badly aligned, then trap tracing | ||
| 1034 | * is disabled and an error is returned. | ||
| 1035 | * | ||
| 1036 | * Upon failure with EINVAL, this service call returns in RET1 the | ||
| 1037 | * minimum number of buffer entries required. Upon other failures | ||
| 1038 | * RET1 is undefined. | ||
| 1039 | */ | ||
| 1040 | #define HV_FAST_TTRACE_BUF_CONF 0x90 | ||
| 1041 | |||
| 1042 | /* ttrace_buf_info() | ||
| 1043 | * TRAP: HV_FAST_TRAP | ||
| 1044 | * FUNCTION: HV_FAST_TTRACE_BUF_INFO | ||
| 1045 | * RET0: status | ||
| 1046 | * RET1: real address | ||
| 1047 | * RET2: size | ||
| 1048 | * ERRORS: None defined. | ||
| 1049 | * | ||
| 1050 | * Returns the size and location of the previously declared trap-trace | ||
| 1051 | * buffer. In the event that no buffer was previously defined, or the | ||
| 1052 | * buffer is disabled, this call will return a size of zero bytes. | ||
| 1053 | */ | ||
| 1054 | #define HV_FAST_TTRACE_BUF_INFO 0x91 | ||
| 1055 | |||
| 1056 | /* ttrace_enable() | ||
| 1057 | * TRAP: HV_FAST_TRAP | ||
| 1058 | * FUNCTION: HV_FAST_TTRACE_ENABLE | ||
| 1059 | * ARG0: enable | ||
| 1060 | * RET0: status | ||
| 1061 | * RET1: previous enable state | ||
| 1062 | * ERRORS: EINVAL No trap trace buffer currently defined | ||
| 1063 | * | ||
| 1064 | * Enable or disable trap tracing, and return the previous enabled | ||
| 1065 | * state in RET1. Future systems may define various flags for the | ||
| 1066 | * enable argument (ARG0), for the moment a guest should pass | ||
| 1067 | * "(uint64_t) -1" to enable, and "(uint64_t) 0" to disable all | ||
| 1068 | * tracing - which will ensure future compatability. | ||
| 1069 | */ | ||
| 1070 | #define HV_FAST_TTRACE_ENABLE 0x92 | ||
| 1071 | |||
| 1072 | /* ttrace_freeze() | ||
| 1073 | * TRAP: HV_FAST_TRAP | ||
| 1074 | * FUNCTION: HV_FAST_TTRACE_FREEZE | ||
| 1075 | * ARG0: freeze | ||
| 1076 | * RET0: status | ||
| 1077 | * RET1: previous freeze state | ||
| 1078 | * ERRORS: EINVAL No trap trace buffer currently defined | ||
| 1079 | * | ||
| 1080 | * Freeze or unfreeze trap tracing, returning the previous freeze | ||
| 1081 | * state in RET1. A guest should pass a non-zero value to freeze and | ||
| 1082 | * a zero value to unfreeze all tracing. The returned previous state | ||
| 1083 | * is 0 for not frozen and 1 for frozen. | ||
| 1084 | */ | ||
| 1085 | #define HV_FAST_TTRACE_FREEZE 0x93 | ||
| 1086 | |||
| 1087 | /* ttrace_addentry() | ||
| 1088 | * TRAP: HV_TTRACE_ADDENTRY_TRAP | ||
| 1089 | * ARG0: tag (16-bits) | ||
| 1090 | * ARG1: data word 0 | ||
| 1091 | * ARG2: data word 1 | ||
| 1092 | * ARG3: data word 2 | ||
| 1093 | * ARG4: data word 3 | ||
| 1094 | * RET0: status | ||
| 1095 | * ERRORS: EINVAL No trap trace buffer currently defined | ||
| 1096 | * | ||
| 1097 | * Add an entry to the trap trace buffer. Upon return only ARG0/RET0 | ||
| 1098 | * is modified - none of the other registers holding arguments are | ||
| 1099 | * volatile across this hypervisor service. | ||
| 1100 | */ | ||
| 1101 | |||
| 1102 | /* Core dump services. | ||
| 1103 | * | ||
| 1104 | * Since the hypervisor viraulizes and thus obscures a lot of the | ||
| 1105 | * physical machine layout and state, traditional OS crash dumps can | ||
| 1106 | * be difficult to diagnose especially when the problem is a | ||
| 1107 | * configuration error of some sort. | ||
| 1108 | * | ||
| 1109 | * The dump services provide an opaque buffer into which the | ||
| 1110 | * hypervisor can place it's internal state in order to assist in | ||
| 1111 | * debugging such situations. The contents are opaque and extremely | ||
| 1112 | * platform and hypervisor implementation specific. The guest, during | ||
| 1113 | * a core dump, requests that the hypervisor update any information in | ||
| 1114 | * the dump buffer in preparation to being dumped as part of the | ||
| 1115 | * domain's memory image. | ||
| 1116 | */ | ||
| 1117 | |||
| 1118 | /* dump_buf_update() | ||
| 1119 | * TRAP: HV_FAST_TRAP | ||
| 1120 | * FUNCTION: HV_FAST_DUMP_BUF_UPDATE | ||
| 1121 | * ARG0: real address | ||
| 1122 | * ARG1: size | ||
| 1123 | * RET0: status | ||
| 1124 | * RET1: required size of dump buffer | ||
| 1125 | * ERRORS: ENORADDR Invalid real address | ||
| 1126 | * EBADALIGN Real address is not aligned on a 64-byte | ||
| 1127 | * boundary | ||
| 1128 | * EINVAL Size is non-zero but less than minimum size | ||
| 1129 | * required | ||
| 1130 | * ENOTSUPPORTED Operation not supported on current logical | ||
| 1131 | * domain | ||
| 1132 | * | ||
| 1133 | * Declare a domain dump buffer to the hypervisor. The real address | ||
| 1134 | * provided for the domain dump buffer must be 64-byte aligned. The | ||
| 1135 | * size specifies the size of the dump buffer and may be larger than | ||
| 1136 | * the minimum size specified in the machine description. The | ||
| 1137 | * hypervisor will fill the dump buffer with opaque data. | ||
| 1138 | * | ||
| 1139 | * Note: A guest may elect to include dump buffer contents as part of a crash | ||
| 1140 | * dump to assist with debugging. This function may be called any number | ||
| 1141 | * of times so that a guest may relocate a dump buffer, or create | ||
| 1142 | * "snapshots" of any dump-buffer information. Each call to | ||
| 1143 | * dump_buf_update() atomically declares the new dump buffer to the | ||
| 1144 | * hypervisor. | ||
| 1145 | * | ||
| 1146 | * A specified size of 0 unconfigures the dump buffer. If the real | ||
| 1147 | * address is illegal or badly aligned, then any currently active dump | ||
| 1148 | * buffer is disabled and an error is returned. | ||
| 1149 | * | ||
| 1150 | * In the event that the call fails with EINVAL, RET1 contains the | ||
| 1151 | * minimum size requires by the hypervisor for a valid dump buffer. | ||
| 1152 | */ | ||
| 1153 | #define HV_FAST_DUMP_BUF_UPDATE 0x94 | ||
| 1154 | |||
| 1155 | /* dump_buf_info() | ||
| 1156 | * TRAP: HV_FAST_TRAP | ||
| 1157 | * FUNCTION: HV_FAST_DUMP_BUF_INFO | ||
| 1158 | * RET0: status | ||
| 1159 | * RET1: real address of current dump buffer | ||
| 1160 | * RET2: size of current dump buffer | ||
| 1161 | * ERRORS: No errors defined. | ||
| 1162 | * | ||
| 1163 | * Return the currently configures dump buffer description. A | ||
| 1164 | * returned size of 0 bytes indicates an undefined dump buffer. In | ||
| 1165 | * this case the return address in RET1 is undefined. | ||
| 1166 | */ | ||
| 1167 | #define HV_FAST_DUMP_BUF_INFO 0x95 | ||
| 1168 | |||
| 1169 | /* Device interrupt services. | ||
| 1170 | * | ||
| 1171 | * Device interrupts are allocated to system bus bridges by the hypervisor, | ||
| 1172 | * and described to OBP in the machine description. OBP then describes | ||
| 1173 | * these interrupts to the OS via properties in the device tree. | ||
| 1174 | * | ||
| 1175 | * Terminology: | ||
| 1176 | * | ||
| 1177 | * cpuid Unique opaque value which represents a target cpu. | ||
| 1178 | * | ||
| 1179 | * devhandle Device handle. It uniquely identifies a device, and | ||
| 1180 | * consistes of the lower 28-bits of the hi-cell of the | ||
| 1181 | * first entry of the device's "reg" property in the | ||
| 1182 | * OBP device tree. | ||
| 1183 | * | ||
| 1184 | * devino Device interrupt number. Specifies the relative | ||
| 1185 | * interrupt number within the device. The unique | ||
| 1186 | * combination of devhandle and devino are used to | ||
| 1187 | * identify a specific device interrupt. | ||
| 1188 | * | ||
| 1189 | * Note: The devino value is the same as the values in the | ||
| 1190 | * "interrupts" property or "interrupt-map" property | ||
| 1191 | * in the OBP device tree for that device. | ||
| 1192 | * | ||
| 1193 | * sysino System interrupt number. A 64-bit unsigned interger | ||
| 1194 | * representing a unique interrupt within a virtual | ||
| 1195 | * machine. | ||
| 1196 | * | ||
| 1197 | * intr_state A flag representing the interrupt state for a given | ||
| 1198 | * sysino. The state values are defined below. | ||
| 1199 | * | ||
| 1200 | * intr_enabled A flag representing the 'enabled' state for a given | ||
| 1201 | * sysino. The enable values are defined below. | ||
| 1202 | */ | ||
| 1203 | |||
| 1204 | #define HV_INTR_STATE_IDLE 0 /* Nothing pending */ | ||
| 1205 | #define HV_INTR_STATE_RECEIVED 1 /* Interrupt received by hardware */ | ||
| 1206 | #define HV_INTR_STATE_DELIVERED 2 /* Interrupt delivered to queue */ | ||
| 1207 | |||
| 1208 | #define HV_INTR_DISABLED 0 /* sysino not enabled */ | ||
| 1209 | #define HV_INTR_ENABLED 1 /* sysino enabled */ | ||
| 1210 | |||
| 1211 | /* intr_devino_to_sysino() | ||
| 1212 | * TRAP: HV_FAST_TRAP | ||
| 1213 | * FUNCTION: HV_FAST_INTR_DEVINO2SYSINO | ||
| 1214 | * ARG0: devhandle | ||
| 1215 | * ARG1: devino | ||
| 1216 | * RET0: status | ||
| 1217 | * RET1: sysino | ||
| 1218 | * ERRORS: EINVAL Invalid devhandle/devino | ||
| 1219 | * | ||
| 1220 | * Converts a device specific interrupt number of the given | ||
| 1221 | * devhandle/devino into a system specific ino (sysino). | ||
| 1222 | */ | ||
| 1223 | #define HV_FAST_INTR_DEVINO2SYSINO 0xa0 | ||
| 1224 | |||
| 1225 | #ifndef __ASSEMBLY__ | ||
| 1226 | extern unsigned long sun4v_devino_to_sysino(unsigned long devhandle, | ||
| 1227 | unsigned long devino); | ||
| 1228 | #endif | ||
| 1229 | |||
| 1230 | /* intr_getenabled() | ||
| 1231 | * TRAP: HV_FAST_TRAP | ||
| 1232 | * FUNCTION: HV_FAST_INTR_GETENABLED | ||
| 1233 | * ARG0: sysino | ||
| 1234 | * RET0: status | ||
| 1235 | * RET1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) | ||
| 1236 | * ERRORS: EINVAL Invalid sysino | ||
| 1237 | * | ||
| 1238 | * Returns interrupt enabled state in RET1 for the interrupt defined | ||
| 1239 | * by the given sysino. | ||
| 1240 | */ | ||
| 1241 | #define HV_FAST_INTR_GETENABLED 0xa1 | ||
| 1242 | |||
| 1243 | #ifndef __ASSEMBLY__ | ||
| 1244 | extern unsigned long sun4v_intr_getenabled(unsigned long sysino); | ||
| 1245 | #endif | ||
| 1246 | |||
| 1247 | /* intr_setenabled() | ||
| 1248 | * TRAP: HV_FAST_TRAP | ||
| 1249 | * FUNCTION: HV_FAST_INTR_SETENABLED | ||
| 1250 | * ARG0: sysino | ||
| 1251 | * ARG1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) | ||
| 1252 | * RET0: status | ||
| 1253 | * ERRORS: EINVAL Invalid sysino or intr_enabled value | ||
| 1254 | * | ||
| 1255 | * Set the 'enabled' state of the interrupt sysino. | ||
| 1256 | */ | ||
| 1257 | #define HV_FAST_INTR_SETENABLED 0xa2 | ||
| 1258 | |||
| 1259 | #ifndef __ASSEMBLY__ | ||
| 1260 | extern unsigned long sun4v_intr_setenabled(unsigned long sysino, unsigned long intr_enabled); | ||
| 1261 | #endif | ||
| 1262 | |||
| 1263 | /* intr_getstate() | ||
| 1264 | * TRAP: HV_FAST_TRAP | ||
| 1265 | * FUNCTION: HV_FAST_INTR_GETSTATE | ||
| 1266 | * ARG0: sysino | ||
| 1267 | * RET0: status | ||
| 1268 | * RET1: intr_state (HV_INTR_STATE_*) | ||
| 1269 | * ERRORS: EINVAL Invalid sysino | ||
| 1270 | * | ||
| 1271 | * Returns current state of the interrupt defined by the given sysino. | ||
| 1272 | */ | ||
| 1273 | #define HV_FAST_INTR_GETSTATE 0xa3 | ||
| 1274 | |||
| 1275 | #ifndef __ASSEMBLY__ | ||
| 1276 | extern unsigned long sun4v_intr_getstate(unsigned long sysino); | ||
| 1277 | #endif | ||
| 1278 | |||
| 1279 | /* intr_setstate() | ||
| 1280 | * TRAP: HV_FAST_TRAP | ||
| 1281 | * FUNCTION: HV_FAST_INTR_SETSTATE | ||
| 1282 | * ARG0: sysino | ||
| 1283 | * ARG1: intr_state (HV_INTR_STATE_*) | ||
| 1284 | * RET0: status | ||
| 1285 | * ERRORS: EINVAL Invalid sysino or intr_state value | ||
| 1286 | * | ||
| 1287 | * Sets the current state of the interrupt described by the given sysino | ||
| 1288 | * value. | ||
| 1289 | * | ||
| 1290 | * Note: Setting the state to HV_INTR_STATE_IDLE clears any pending | ||
| 1291 | * interrupt for sysino. | ||
| 1292 | */ | ||
| 1293 | #define HV_FAST_INTR_SETSTATE 0xa4 | ||
| 1294 | |||
| 1295 | #ifndef __ASSEMBLY__ | ||
| 1296 | extern unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long intr_state); | ||
| 1297 | #endif | ||
| 1298 | |||
| 1299 | /* intr_gettarget() | ||
| 1300 | * TRAP: HV_FAST_TRAP | ||
| 1301 | * FUNCTION: HV_FAST_INTR_GETTARGET | ||
| 1302 | * ARG0: sysino | ||
| 1303 | * RET0: status | ||
| 1304 | * RET1: cpuid | ||
| 1305 | * ERRORS: EINVAL Invalid sysino | ||
| 1306 | * | ||
| 1307 | * Returns CPU that is the current target of the interrupt defined by | ||
| 1308 | * the given sysino. The CPU value returned is undefined if the target | ||
| 1309 | * has not been set via intr_settarget(). | ||
| 1310 | */ | ||
| 1311 | #define HV_FAST_INTR_GETTARGET 0xa5 | ||
| 1312 | |||
| 1313 | #ifndef __ASSEMBLY__ | ||
| 1314 | extern unsigned long sun4v_intr_gettarget(unsigned long sysino); | ||
| 1315 | #endif | ||
| 1316 | |||
| 1317 | /* intr_settarget() | ||
| 1318 | * TRAP: HV_FAST_TRAP | ||
| 1319 | * FUNCTION: HV_FAST_INTR_SETTARGET | ||
| 1320 | * ARG0: sysino | ||
| 1321 | * ARG1: cpuid | ||
| 1322 | * RET0: status | ||
| 1323 | * ERRORS: EINVAL Invalid sysino | ||
| 1324 | * ENOCPU Invalid cpuid | ||
| 1325 | * | ||
| 1326 | * Set the target CPU for the interrupt defined by the given sysino. | ||
| 1327 | */ | ||
| 1328 | #define HV_FAST_INTR_SETTARGET 0xa6 | ||
| 1329 | |||
| 1330 | #ifndef __ASSEMBLY__ | ||
| 1331 | extern unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cpuid); | ||
| 1332 | #endif | ||
| 1333 | |||
| 1334 | /* PCI IO services. | ||
| 1335 | * | ||
| 1336 | * See the terminology descriptions in the device interrupt services | ||
| 1337 | * section above as those apply here too. Here are terminology | ||
| 1338 | * definitions specific to these PCI IO services: | ||
| 1339 | * | ||
| 1340 | * tsbnum TSB number. Indentifies which io-tsb is used. | ||
| 1341 | * For this version of the specification, tsbnum | ||
| 1342 | * must be zero. | ||
| 1343 | * | ||
| 1344 | * tsbindex TSB index. Identifies which entry in the TSB | ||
| 1345 | * is used. The first entry is zero. | ||
| 1346 | * | ||
| 1347 | * tsbid A 64-bit aligned data structure which contains | ||
| 1348 | * a tsbnum and a tsbindex. Bits 63:32 contain the | ||
| 1349 | * tsbnum and bits 31:00 contain the tsbindex. | ||
| 1350 | * | ||
| 1351 | * Use the HV_PCI_TSBID() macro to construct such | ||
| 1352 | * values. | ||
| 1353 | * | ||
| 1354 | * io_attributes IO attributes for IOMMU mappings. One of more | ||
| 1355 | * of the attritbute bits are stores in a 64-bit | ||
| 1356 | * value. The values are defined below. | ||
| 1357 | * | ||
| 1358 | * r_addr 64-bit real address | ||
| 1359 | * | ||
| 1360 | * pci_device PCI device address. A PCI device address identifies | ||
| 1361 | * a specific device on a specific PCI bus segment. | ||
| 1362 | * A PCI device address ia a 32-bit unsigned integer | ||
| 1363 | * with the following format: | ||
| 1364 | * | ||
| 1365 | * 00000000.bbbbbbbb.dddddfff.00000000 | ||
| 1366 | * | ||
| 1367 | * Use the HV_PCI_DEVICE_BUILD() macro to construct | ||
| 1368 | * such values. | ||
| 1369 | * | ||
| 1370 | * pci_config_offset | ||
| 1371 | * PCI configureation space offset. For conventional | ||
| 1372 | * PCI a value between 0 and 255. For extended | ||
| 1373 | * configuration space, a value between 0 and 4095. | ||
| 1374 | * | ||
| 1375 | * Note: For PCI configuration space accesses, the offset | ||
| 1376 | * must be aligned to the access size. | ||
| 1377 | * | ||
| 1378 | * error_flag A return value which specifies if the action succeeded | ||
| 1379 | * or failed. 0 means no error, non-0 means some error | ||
| 1380 | * occurred while performing the service. | ||
| 1381 | * | ||
| 1382 | * io_sync_direction | ||
| 1383 | * Direction definition for pci_dma_sync(), defined | ||
| 1384 | * below in HV_PCI_SYNC_*. | ||
| 1385 | * | ||
| 1386 | * io_page_list A list of io_page_addresses, an io_page_address is | ||
| 1387 | * a real address. | ||
| 1388 | * | ||
| 1389 | * io_page_list_p A pointer to an io_page_list. | ||
| 1390 | * | ||
| 1391 | * "size based byte swap" - Some functions do size based byte swapping | ||
| 1392 | * which allows sw to access pointers and | ||
| 1393 | * counters in native form when the processor | ||
| 1394 | * operates in a different endianness than the | ||
| 1395 | * IO bus. Size-based byte swapping converts a | ||
| 1396 | * multi-byte field between big-endian and | ||
| 1397 | * little-endian format. | ||
| 1398 | */ | ||
| 1399 | |||
| 1400 | #define HV_PCI_MAP_ATTR_READ 0x01 | ||
| 1401 | #define HV_PCI_MAP_ATTR_WRITE 0x02 | ||
| 1402 | |||
| 1403 | #define HV_PCI_DEVICE_BUILD(b,d,f) \ | ||
| 1404 | ((((b) & 0xff) << 16) | \ | ||
| 1405 | (((d) & 0x1f) << 11) | \ | ||
| 1406 | (((f) & 0x07) << 8)) | ||
| 1407 | |||
| 1408 | #define HV_PCI_TSBID(__tsb_num, __tsb_index) \ | ||
| 1409 | ((((u64)(__tsb_num)) << 32UL) | ((u64)(__tsb_index))) | ||
| 1410 | |||
| 1411 | #define HV_PCI_SYNC_FOR_DEVICE 0x01 | ||
| 1412 | #define HV_PCI_SYNC_FOR_CPU 0x02 | ||
| 1413 | |||
| 1414 | /* pci_iommu_map() | ||
| 1415 | * TRAP: HV_FAST_TRAP | ||
| 1416 | * FUNCTION: HV_FAST_PCI_IOMMU_MAP | ||
| 1417 | * ARG0: devhandle | ||
| 1418 | * ARG1: tsbid | ||
| 1419 | * ARG2: #ttes | ||
| 1420 | * ARG3: io_attributes | ||
| 1421 | * ARG4: io_page_list_p | ||
| 1422 | * RET0: status | ||
| 1423 | * RET1: #ttes mapped | ||
| 1424 | * ERRORS: EINVAL Invalid devhandle/tsbnum/tsbindex/io_attributes | ||
| 1425 | * EBADALIGN Improperly aligned real address | ||
| 1426 | * ENORADDR Invalid real address | ||
| 1427 | * | ||
| 1428 | * Create IOMMU mappings in the sun4v device defined by the given | ||
| 1429 | * devhandle. The mappings are created in the TSB defined by the | ||
| 1430 | * tsbnum component of the given tsbid. The first mapping is created | ||
| 1431 | * in the TSB i ndex defined by the tsbindex component of the given tsbid. | ||
| 1432 | * The call creates up to #ttes mappings, the first one at tsbnum, tsbindex, | ||
| 1433 | * the second at tsbnum, tsbindex + 1, etc. | ||
| 1434 | * | ||
| 1435 | * All mappings are created with the attributes defined by the io_attributes | ||
| 1436 | * argument. The page mapping addresses are described in the io_page_list | ||
| 1437 | * defined by the given io_page_list_p, which is a pointer to the io_page_list. | ||
| 1438 | * The first entry in the io_page_list is the address for the first iotte, the | ||
| 1439 | * 2nd for the 2nd iotte, and so on. | ||
| 1440 | * | ||
| 1441 | * Each io_page_address in the io_page_list must be appropriately aligned. | ||
| 1442 | * #ttes must be greater than zero. For this version of the spec, the tsbnum | ||
| 1443 | * component of the given tsbid must be zero. | ||
| 1444 | * | ||
| 1445 | * Returns the actual number of mappings creates, which may be less than | ||
| 1446 | * or equal to the argument #ttes. If the function returns a value which | ||
| 1447 | * is less than the #ttes, the caller may continus to call the function with | ||
| 1448 | * an updated tsbid, #ttes, io_page_list_p arguments until all pages are | ||
| 1449 | * mapped. | ||
| 1450 | * | ||
| 1451 | * Note: This function does not imply an iotte cache flush. The guest must | ||
| 1452 | * demap an entry before re-mapping it. | ||
| 1453 | */ | ||
| 1454 | #define HV_FAST_PCI_IOMMU_MAP 0xb0 | ||
| 1455 | |||
| 1456 | /* pci_iommu_demap() | ||
| 1457 | * TRAP: HV_FAST_TRAP | ||
| 1458 | * FUNCTION: HV_FAST_PCI_IOMMU_DEMAP | ||
| 1459 | * ARG0: devhandle | ||
| 1460 | * ARG1: tsbid | ||
| 1461 | * ARG2: #ttes | ||
| 1462 | * RET0: status | ||
| 1463 | * RET1: #ttes demapped | ||
| 1464 | * ERRORS: EINVAL Invalid devhandle/tsbnum/tsbindex | ||
| 1465 | * | ||
| 1466 | * Demap and flush IOMMU mappings in the device defined by the given | ||
| 1467 | * devhandle. Demaps up to #ttes entries in the TSB defined by the tsbnum | ||
| 1468 | * component of the given tsbid, starting at the TSB index defined by the | ||
| 1469 | * tsbindex component of the given tsbid. | ||
| 1470 | * | ||
| 1471 | * For this version of the spec, the tsbnum of the given tsbid must be zero. | ||
| 1472 | * #ttes must be greater than zero. | ||
| 1473 | * | ||
| 1474 | * Returns the actual number of ttes demapped, which may be less than or equal | ||
| 1475 | * to the argument #ttes. If #ttes demapped is less than #ttes, the caller | ||
| 1476 | * may continue to call this function with updated tsbid and #ttes arguments | ||
| 1477 | * until all pages are demapped. | ||
| 1478 | * | ||
| 1479 | * Note: Entries do not have to be mapped to be demapped. A demap of an | ||
| 1480 | * unmapped page will flush the entry from the tte cache. | ||
| 1481 | */ | ||
| 1482 | #define HV_FAST_PCI_IOMMU_DEMAP 0xb1 | ||
| 1483 | |||
| 1484 | /* pci_iommu_getmap() | ||
| 1485 | * TRAP: HV_FAST_TRAP | ||
| 1486 | * FUNCTION: HV_FAST_PCI_IOMMU_GETMAP | ||
| 1487 | * ARG0: devhandle | ||
| 1488 | * ARG1: tsbid | ||
| 1489 | * RET0: status | ||
| 1490 | * RET1: io_attributes | ||
| 1491 | * RET2: real address | ||
| 1492 | * ERRORS: EINVAL Invalid devhandle/tsbnum/tsbindex | ||
| 1493 | * ENOMAP Mapping is not valid, no translation exists | ||
| 1494 | * | ||
| 1495 | * Read and return the mapping in the device described by the given devhandle | ||
| 1496 | * and tsbid. If successful, the io_attributes shall be returned in RET1 | ||
| 1497 | * and the page address of the mapping shall be returned in RET2. | ||
| 1498 | * | ||
| 1499 | * For this version of the spec, the tsbnum component of the given tsbid | ||
| 1500 | * must be zero. | ||
| 1501 | */ | ||
| 1502 | #define HV_FAST_PCI_IOMMU_GETMAP 0xb2 | ||
| 1503 | |||
| 1504 | /* pci_iommu_getbypass() | ||
| 1505 | * TRAP: HV_FAST_TRAP | ||
| 1506 | * FUNCTION: HV_FAST_PCI_IOMMU_GETBYPASS | ||
| 1507 | * ARG0: devhandle | ||
| 1508 | * ARG1: real address | ||
| 1509 | * ARG2: io_attributes | ||
| 1510 | * RET0: status | ||
| 1511 | * RET1: io_addr | ||
| 1512 | * ERRORS: EINVAL Invalid devhandle/io_attributes | ||
| 1513 | * ENORADDR Invalid real address | ||
| 1514 | * ENOTSUPPORTED Function not supported in this implementation. | ||
| 1515 | * | ||
| 1516 | * Create a "special" mapping in the device described by the given devhandle, | ||
| 1517 | * for the given real address and attributes. Return the IO address in RET1 | ||
| 1518 | * if successful. | ||
| 1519 | */ | ||
| 1520 | #define HV_FAST_PCI_IOMMU_GETBYPASS 0xb3 | ||
| 1521 | |||
| 1522 | /* pci_config_get() | ||
| 1523 | * TRAP: HV_FAST_TRAP | ||
| 1524 | * FUNCTION: HV_FAST_PCI_CONFIG_GET | ||
| 1525 | * ARG0: devhandle | ||
| 1526 | * ARG1: pci_device | ||
| 1527 | * ARG2: pci_config_offset | ||
| 1528 | * ARG3: size | ||
| 1529 | * RET0: status | ||
| 1530 | * RET1: error_flag | ||
| 1531 | * RET2: data | ||
| 1532 | * ERRORS: EINVAL Invalid devhandle/pci_device/offset/size | ||
| 1533 | * EBADALIGN pci_config_offset not size aligned | ||
| 1534 | * ENOACCESS Access to this offset is not permitted | ||
| 1535 | * | ||
| 1536 | * Read PCI configuration space for the adapter described by the given | ||
| 1537 | * devhandle. Read size (1, 2, or 4) bytes of data from the given | ||
| 1538 | * pci_device, at pci_config_offset from the beginning of the device's | ||
| 1539 | * configuration space. If there was no error, RET1 is set to zero and | ||
| 1540 | * RET2 is set to the data read. Insignificant bits in RET2 are not | ||
| 1541 | * guarenteed to have any specific value and therefore must be ignored. | ||
| 1542 | * | ||
| 1543 | * The data returned in RET2 is size based byte swapped. | ||
| 1544 | * | ||
| 1545 | * If an error occurs during the read, set RET1 to a non-zero value. The | ||
| 1546 | * given pci_config_offset must be 'size' aligned. | ||
| 1547 | */ | ||
| 1548 | #define HV_FAST_PCI_CONFIG_GET 0xb4 | ||
| 1549 | |||
| 1550 | /* pci_config_put() | ||
| 1551 | * TRAP: HV_FAST_TRAP | ||
| 1552 | * FUNCTION: HV_FAST_PCI_CONFIG_PUT | ||
| 1553 | * ARG0: devhandle | ||
| 1554 | * ARG1: pci_device | ||
| 1555 | * ARG2: pci_config_offset | ||
| 1556 | * ARG3: size | ||
| 1557 | * ARG4: data | ||
| 1558 | * RET0: status | ||
| 1559 | * RET1: error_flag | ||
| 1560 | * ERRORS: EINVAL Invalid devhandle/pci_device/offset/size | ||
| 1561 | * EBADALIGN pci_config_offset not size aligned | ||
| 1562 | * ENOACCESS Access to this offset is not permitted | ||
| 1563 | * | ||
| 1564 | * Write PCI configuration space for the adapter described by the given | ||
| 1565 | * devhandle. Write size (1, 2, or 4) bytes of data in a single operation, | ||
| 1566 | * at pci_config_offset from the beginning of the device's configuration | ||
| 1567 | * space. The data argument contains the data to be written to configuration | ||
| 1568 | * space. Prior to writing, the data is size based byte swapped. | ||
| 1569 | * | ||
| 1570 | * If an error occurs during the write access, do not generate an error | ||
| 1571 | * report, do set RET1 to a non-zero value. Otherwise RET1 is zero. | ||
| 1572 | * The given pci_config_offset must be 'size' aligned. | ||
| 1573 | * | ||
| 1574 | * This function is permitted to read from offset zero in the configuration | ||
| 1575 | * space described by the given pci_device if necessary to ensure that the | ||
| 1576 | * write access to config space completes. | ||
| 1577 | */ | ||
| 1578 | #define HV_FAST_PCI_CONFIG_PUT 0xb5 | ||
| 1579 | |||
| 1580 | /* pci_peek() | ||
| 1581 | * TRAP: HV_FAST_TRAP | ||
| 1582 | * FUNCTION: HV_FAST_PCI_PEEK | ||
| 1583 | * ARG0: devhandle | ||
| 1584 | * ARG1: real address | ||
| 1585 | * ARG2: size | ||
| 1586 | * RET0: status | ||
| 1587 | * RET1: error_flag | ||
| 1588 | * RET2: data | ||
| 1589 | * ERRORS: EINVAL Invalid devhandle or size | ||
| 1590 | * EBADALIGN Improperly aligned real address | ||
| 1591 | * ENORADDR Bad real address | ||
| 1592 | * ENOACCESS Guest access prohibited | ||
| 1593 | * | ||
| 1594 | * Attempt to read the IO address given by the given devhandle, real address, | ||
| 1595 | * and size. Size must be 1, 2, 4, or 8. The read is performed as a single | ||
| 1596 | * access operation using the given size. If an error occurs when reading | ||
| 1597 | * from the given location, do not generate an error report, but return a | ||
| 1598 | * non-zero value in RET1. If the read was successful, return zero in RET1 | ||
| 1599 | * and return the actual data read in RET2. The data returned is size based | ||
| 1600 | * byte swapped. | ||
| 1601 | * | ||
| 1602 | * Non-significant bits in RET2 are not guarenteed to have any specific value | ||
| 1603 | * and therefore must be ignored. If RET1 is returned as non-zero, the data | ||
| 1604 | * value is not guarenteed to have any specific value and should be ignored. | ||
| 1605 | * | ||
| 1606 | * The caller must have permission to read from the given devhandle, real | ||
| 1607 | * address, which must be an IO address. The argument real address must be a | ||
| 1608 | * size aligned address. | ||
| 1609 | * | ||
| 1610 | * The hypervisor implementation of this function must block access to any | ||
| 1611 | * IO address that the guest does not have explicit permission to access. | ||
| 1612 | */ | ||
| 1613 | #define HV_FAST_PCI_PEEK 0xb6 | ||
| 1614 | |||
| 1615 | /* pci_poke() | ||
| 1616 | * TRAP: HV_FAST_TRAP | ||
| 1617 | * FUNCTION: HV_FAST_PCI_POKE | ||
| 1618 | * ARG0: devhandle | ||
| 1619 | * ARG1: real address | ||
| 1620 | * ARG2: size | ||
| 1621 | * ARG3: data | ||
| 1622 | * ARG4: pci_device | ||
| 1623 | * RET0: status | ||
| 1624 | * RET1: error_flag | ||
| 1625 | * ERRORS: EINVAL Invalid devhandle, size, or pci_device | ||
| 1626 | * EBADALIGN Improperly aligned real address | ||
| 1627 | * ENORADDR Bad real address | ||
| 1628 | * ENOACCESS Guest access prohibited | ||
| 1629 | * ENOTSUPPORTED Function is not supported by implementation | ||
| 1630 | * | ||
| 1631 | * Attempt to write data to the IO address given by the given devhandle, | ||
| 1632 | * real address, and size. Size must be 1, 2, 4, or 8. The write is | ||
| 1633 | * performed as a single access operation using the given size. Prior to | ||
| 1634 | * writing the data is size based swapped. | ||
| 1635 | * | ||
| 1636 | * If an error occurs when writing to the given location, do not generate an | ||
| 1637 | * error report, but return a non-zero value in RET1. If the write was | ||
| 1638 | * successful, return zero in RET1. | ||
| 1639 | * | ||
| 1640 | * pci_device describes the configuration address of the device being | ||
| 1641 | * written to. The implementation may safely read from offset 0 with | ||
| 1642 | * the configuration space of the device described by devhandle and | ||
| 1643 | * pci_device in order to guarantee that the write portion of the operation | ||
| 1644 | * completes | ||
| 1645 | * | ||
| 1646 | * Any error that occurs due to the read shall be reported using the normal | ||
| 1647 | * error reporting mechanisms .. the read error is not suppressed. | ||
| 1648 | * | ||
| 1649 | * The caller must have permission to write to the given devhandle, real | ||
| 1650 | * address, which must be an IO address. The argument real address must be a | ||
| 1651 | * size aligned address. The caller must have permission to read from | ||
| 1652 | * the given devhandle, pci_device cofiguration space offset 0. | ||
| 1653 | * | ||
| 1654 | * The hypervisor implementation of this function must block access to any | ||
| 1655 | * IO address that the guest does not have explicit permission to access. | ||
| 1656 | */ | ||
| 1657 | #define HV_FAST_PCI_POKE 0xb7 | ||
| 1658 | |||
| 1659 | /* pci_dma_sync() | ||
| 1660 | * TRAP: HV_FAST_TRAP | ||
| 1661 | * FUNCTION: HV_FAST_PCI_DMA_SYNC | ||
| 1662 | * ARG0: devhandle | ||
| 1663 | * ARG1: real address | ||
| 1664 | * ARG2: size | ||
| 1665 | * ARG3: io_sync_direction | ||
| 1666 | * RET0: status | ||
| 1667 | * RET1: #synced | ||
| 1668 | * ERRORS: EINVAL Invalid devhandle or io_sync_direction | ||
| 1669 | * ENORADDR Bad real address | ||
| 1670 | * | ||
| 1671 | * Synchronize a memory region described by the given real address and size, | ||
| 1672 | * for the device defined by the given devhandle using the direction(s) | ||
| 1673 | * defined by the given io_sync_direction. The argument size is the size of | ||
| 1674 | * the memory region in bytes. | ||
| 1675 | * | ||
| 1676 | * Return the actual number of bytes synchronized in the return value #synced, | ||
| 1677 | * which may be less than or equal to the argument size. If the return | ||
| 1678 | * value #synced is less than size, the caller must continue to call this | ||
| 1679 | * function with updated real address and size arguments until the entire | ||
| 1680 | * memory region is synchronized. | ||
| 1681 | */ | ||
| 1682 | #define HV_FAST_PCI_DMA_SYNC 0xb8 | ||
| 1683 | |||
| 1684 | /* PCI MSI services. */ | ||
| 1685 | |||
| 1686 | #define HV_MSITYPE_MSI32 0x00 | ||
| 1687 | #define HV_MSITYPE_MSI64 0x01 | ||
| 1688 | |||
| 1689 | #define HV_MSIQSTATE_IDLE 0x00 | ||
| 1690 | #define HV_MSIQSTATE_ERROR 0x01 | ||
| 1691 | |||
| 1692 | #define HV_MSIQ_INVALID 0x00 | ||
| 1693 | #define HV_MSIQ_VALID 0x01 | ||
| 1694 | |||
| 1695 | #define HV_MSISTATE_IDLE 0x00 | ||
| 1696 | #define HV_MSISTATE_DELIVERED 0x01 | ||
| 1697 | |||
| 1698 | #define HV_MSIVALID_INVALID 0x00 | ||
| 1699 | #define HV_MSIVALID_VALID 0x01 | ||
| 1700 | |||
| 1701 | #define HV_PCIE_MSGTYPE_PME_MSG 0x18 | ||
| 1702 | #define HV_PCIE_MSGTYPE_PME_ACK_MSG 0x1b | ||
| 1703 | #define HV_PCIE_MSGTYPE_CORR_MSG 0x30 | ||
| 1704 | #define HV_PCIE_MSGTYPE_NONFATAL_MSG 0x31 | ||
| 1705 | #define HV_PCIE_MSGTYPE_FATAL_MSG 0x33 | ||
| 1706 | |||
| 1707 | #define HV_MSG_INVALID 0x00 | ||
| 1708 | #define HV_MSG_VALID 0x01 | ||
| 1709 | |||
| 1710 | /* pci_msiq_conf() | ||
| 1711 | * TRAP: HV_FAST_TRAP | ||
| 1712 | * FUNCTION: HV_FAST_PCI_MSIQ_CONF | ||
| 1713 | * ARG0: devhandle | ||
| 1714 | * ARG1: msiqid | ||
| 1715 | * ARG2: real address | ||
| 1716 | * ARG3: number of entries | ||
| 1717 | * RET0: status | ||
| 1718 | * ERRORS: EINVAL Invalid devhandle, msiqid or nentries | ||
| 1719 | * EBADALIGN Improperly aligned real address | ||
| 1720 | * ENORADDR Bad real address | ||
| 1721 | * | ||
| 1722 | * Configure the MSI queue given by the devhandle and msiqid arguments, | ||
| 1723 | * and to be placed at the given real address and be of the given | ||
| 1724 | * number of entries. The real address must be aligned exactly to match | ||
| 1725 | * the queue size. Each queue entry is 64-bytes long, so f.e. a 32 entry | ||
| 1726 | * queue must be aligned on a 2048 byte real address boundary. The MSI-EQ | ||
| 1727 | * Head and Tail are initialized so that the MSI-EQ is 'empty'. | ||
| 1728 | * | ||
| 1729 | * Implementation Note: Certain implementations have fixed sized queues. In | ||
| 1730 | * that case, number of entries must contain the correct | ||
| 1731 | * value. | ||
| 1732 | */ | ||
| 1733 | #define HV_FAST_PCI_MSIQ_CONF 0xc0 | ||
| 1734 | |||
| 1735 | /* pci_msiq_info() | ||
| 1736 | * TRAP: HV_FAST_TRAP | ||
| 1737 | * FUNCTION: HV_FAST_PCI_MSIQ_INFO | ||
| 1738 | * ARG0: devhandle | ||
| 1739 | * ARG1: msiqid | ||
| 1740 | * RET0: status | ||
| 1741 | * RET1: real address | ||
| 1742 | * RET2: number of entries | ||
| 1743 | * ERRORS: EINVAL Invalid devhandle or msiqid | ||
| 1744 | * | ||
| 1745 | * Return the configuration information for the MSI queue described | ||
| 1746 | * by the given devhandle and msiqid. The base address of the queue | ||
| 1747 | * is returned in ARG1 and the number of entries is returned in ARG2. | ||
| 1748 | * If the queue is unconfigured, the real address is undefined and the | ||
| 1749 | * number of entries will be returned as zero. | ||
| 1750 | */ | ||
| 1751 | #define HV_FAST_PCI_MSIQ_INFO 0xc1 | ||
| 1752 | |||
| 1753 | /* pci_msiq_getvalid() | ||
| 1754 | * TRAP: HV_FAST_TRAP | ||
| 1755 | * FUNCTION: HV_FAST_PCI_MSIQ_GETVALID | ||
| 1756 | * ARG0: devhandle | ||
| 1757 | * ARG1: msiqid | ||
| 1758 | * RET0: status | ||
| 1759 | * RET1: msiqvalid (HV_MSIQ_VALID or HV_MSIQ_INVALID) | ||
| 1760 | * ERRORS: EINVAL Invalid devhandle or msiqid | ||
| 1761 | * | ||
| 1762 | * Get the valid state of the MSI-EQ described by the given devhandle and | ||
| 1763 | * msiqid. | ||
| 1764 | */ | ||
| 1765 | #define HV_FAST_PCI_MSIQ_GETVALID 0xc2 | ||
| 1766 | |||
| 1767 | /* pci_msiq_setvalid() | ||
| 1768 | * TRAP: HV_FAST_TRAP | ||
| 1769 | * FUNCTION: HV_FAST_PCI_MSIQ_SETVALID | ||
| 1770 | * ARG0: devhandle | ||
| 1771 | * ARG1: msiqid | ||
| 1772 | * ARG2: msiqvalid (HV_MSIQ_VALID or HV_MSIQ_INVALID) | ||
| 1773 | * RET0: status | ||
| 1774 | * ERRORS: EINVAL Invalid devhandle or msiqid or msiqvalid | ||
| 1775 | * value or MSI EQ is uninitialized | ||
| 1776 | * | ||
| 1777 | * Set the valid state of the MSI-EQ described by the given devhandle and | ||
| 1778 | * msiqid to the given msiqvalid. | ||
| 1779 | */ | ||
| 1780 | #define HV_FAST_PCI_MSIQ_SETVALID 0xc3 | ||
| 1781 | |||
| 1782 | /* pci_msiq_getstate() | ||
| 1783 | * TRAP: HV_FAST_TRAP | ||
| 1784 | * FUNCTION: HV_FAST_PCI_MSIQ_GETSTATE | ||
| 1785 | * ARG0: devhandle | ||
| 1786 | * ARG1: msiqid | ||
| 1787 | * RET0: status | ||
| 1788 | * RET1: msiqstate (HV_MSIQSTATE_IDLE or HV_MSIQSTATE_ERROR) | ||
| 1789 | * ERRORS: EINVAL Invalid devhandle or msiqid | ||
| 1790 | * | ||
| 1791 | * Get the state of the MSI-EQ described by the given devhandle and | ||
| 1792 | * msiqid. | ||
| 1793 | */ | ||
| 1794 | #define HV_FAST_PCI_MSIQ_GETSTATE 0xc4 | ||
| 1795 | |||
| 1796 | /* pci_msiq_getvalid() | ||
| 1797 | * TRAP: HV_FAST_TRAP | ||
| 1798 | * FUNCTION: HV_FAST_PCI_MSIQ_GETVALID | ||
| 1799 | * ARG0: devhandle | ||
| 1800 | * ARG1: msiqid | ||
| 1801 | * ARG2: msiqstate (HV_MSIQSTATE_IDLE or HV_MSIQSTATE_ERROR) | ||
| 1802 | * RET0: status | ||
| 1803 | * ERRORS: EINVAL Invalid devhandle or msiqid or msiqstate | ||
| 1804 | * value or MSI EQ is uninitialized | ||
| 1805 | * | ||
| 1806 | * Set the state of the MSI-EQ described by the given devhandle and | ||
| 1807 | * msiqid to the given msiqvalid. | ||
| 1808 | */ | ||
| 1809 | #define HV_FAST_PCI_MSIQ_SETSTATE 0xc5 | ||
| 1810 | |||
| 1811 | /* pci_msiq_gethead() | ||
| 1812 | * TRAP: HV_FAST_TRAP | ||
| 1813 | * FUNCTION: HV_FAST_PCI_MSIQ_GETHEAD | ||
| 1814 | * ARG0: devhandle | ||
| 1815 | * ARG1: msiqid | ||
| 1816 | * RET0: status | ||
| 1817 | * RET1: msiqhead | ||
| 1818 | * ERRORS: EINVAL Invalid devhandle or msiqid | ||
| 1819 | * | ||
| 1820 | * Get the current MSI EQ queue head for the MSI-EQ described by the | ||
| 1821 | * given devhandle and msiqid. | ||
| 1822 | */ | ||
| 1823 | #define HV_FAST_PCI_MSIQ_GETHEAD 0xc6 | ||
| 1824 | |||
| 1825 | /* pci_msiq_sethead() | ||
| 1826 | * TRAP: HV_FAST_TRAP | ||
| 1827 | * FUNCTION: HV_FAST_PCI_MSIQ_SETHEAD | ||
| 1828 | * ARG0: devhandle | ||
| 1829 | * ARG1: msiqid | ||
| 1830 | * ARG2: msiqhead | ||
| 1831 | * RET0: status | ||
| 1832 | * ERRORS: EINVAL Invalid devhandle or msiqid or msiqhead, | ||
| 1833 | * or MSI EQ is uninitialized | ||
| 1834 | * | ||
| 1835 | * Set the current MSI EQ queue head for the MSI-EQ described by the | ||
| 1836 | * given devhandle and msiqid. | ||
| 1837 | */ | ||
| 1838 | #define HV_FAST_PCI_MSIQ_SETHEAD 0xc7 | ||
| 1839 | |||
| 1840 | /* pci_msiq_gettail() | ||
| 1841 | * TRAP: HV_FAST_TRAP | ||
| 1842 | * FUNCTION: HV_FAST_PCI_MSIQ_GETTAIL | ||
| 1843 | * ARG0: devhandle | ||
| 1844 | * ARG1: msiqid | ||
| 1845 | * RET0: status | ||
| 1846 | * RET1: msiqtail | ||
| 1847 | * ERRORS: EINVAL Invalid devhandle or msiqid | ||
| 1848 | * | ||
| 1849 | * Get the current MSI EQ queue tail for the MSI-EQ described by the | ||
| 1850 | * given devhandle and msiqid. | ||
| 1851 | */ | ||
| 1852 | #define HV_FAST_PCI_MSIQ_GETTAIL 0xc8 | ||
| 1853 | |||
| 1854 | /* pci_msi_getvalid() | ||
| 1855 | * TRAP: HV_FAST_TRAP | ||
| 1856 | * FUNCTION: HV_FAST_PCI_MSI_GETVALID | ||
| 1857 | * ARG0: devhandle | ||
| 1858 | * ARG1: msinum | ||
| 1859 | * RET0: status | ||
| 1860 | * RET1: msivalidstate | ||
| 1861 | * ERRORS: EINVAL Invalid devhandle or msinum | ||
| 1862 | * | ||
| 1863 | * Get the current valid/enabled state for the MSI defined by the | ||
| 1864 | * given devhandle and msinum. | ||
| 1865 | */ | ||
| 1866 | #define HV_FAST_PCI_MSI_GETVALID 0xc9 | ||
| 1867 | |||
| 1868 | /* pci_msi_setvalid() | ||
| 1869 | * TRAP: HV_FAST_TRAP | ||
| 1870 | * FUNCTION: HV_FAST_PCI_MSI_SETVALID | ||
| 1871 | * ARG0: devhandle | ||
| 1872 | * ARG1: msinum | ||
| 1873 | * ARG2: msivalidstate | ||
| 1874 | * RET0: status | ||
| 1875 | * ERRORS: EINVAL Invalid devhandle or msinum or msivalidstate | ||
| 1876 | * | ||
| 1877 | * Set the current valid/enabled state for the MSI defined by the | ||
| 1878 | * given devhandle and msinum. | ||
| 1879 | */ | ||
| 1880 | #define HV_FAST_PCI_MSI_SETVALID 0xca | ||
| 1881 | |||
| 1882 | /* pci_msi_getmsiq() | ||
| 1883 | * TRAP: HV_FAST_TRAP | ||
| 1884 | * FUNCTION: HV_FAST_PCI_MSI_GETMSIQ | ||
| 1885 | * ARG0: devhandle | ||
| 1886 | * ARG1: msinum | ||
| 1887 | * RET0: status | ||
| 1888 | * RET1: msiqid | ||
| 1889 | * ERRORS: EINVAL Invalid devhandle or msinum or MSI is unbound | ||
| 1890 | * | ||
| 1891 | * Get the MSI EQ that the MSI defined by the given devhandle and | ||
| 1892 | * msinum is bound to. | ||
| 1893 | */ | ||
| 1894 | #define HV_FAST_PCI_MSI_GETMSIQ 0xcb | ||
| 1895 | |||
| 1896 | /* pci_msi_setmsiq() | ||
| 1897 | * TRAP: HV_FAST_TRAP | ||
| 1898 | * FUNCTION: HV_FAST_PCI_MSI_SETMSIQ | ||
| 1899 | * ARG0: devhandle | ||
| 1900 | * ARG1: msinum | ||
| 1901 | * ARG2: msitype | ||
| 1902 | * ARG3: msiqid | ||
| 1903 | * RET0: status | ||
| 1904 | * ERRORS: EINVAL Invalid devhandle or msinum or msiqid | ||
| 1905 | * | ||
| 1906 | * Set the MSI EQ that the MSI defined by the given devhandle and | ||
| 1907 | * msinum is bound to. | ||
| 1908 | */ | ||
| 1909 | #define HV_FAST_PCI_MSI_SETMSIQ 0xcc | ||
| 1910 | |||
| 1911 | /* pci_msi_getstate() | ||
| 1912 | * TRAP: HV_FAST_TRAP | ||
| 1913 | * FUNCTION: HV_FAST_PCI_MSI_GETSTATE | ||
| 1914 | * ARG0: devhandle | ||
| 1915 | * ARG1: msinum | ||
| 1916 | * RET0: status | ||
| 1917 | * RET1: msistate | ||
| 1918 | * ERRORS: EINVAL Invalid devhandle or msinum | ||
| 1919 | * | ||
| 1920 | * Get the state of the MSI defined by the given devhandle and msinum. | ||
| 1921 | * If not initialized, return HV_MSISTATE_IDLE. | ||
| 1922 | */ | ||
| 1923 | #define HV_FAST_PCI_MSI_GETSTATE 0xcd | ||
| 1924 | |||
| 1925 | /* pci_msi_setstate() | ||
| 1926 | * TRAP: HV_FAST_TRAP | ||
| 1927 | * FUNCTION: HV_FAST_PCI_MSI_SETSTATE | ||
| 1928 | * ARG0: devhandle | ||
| 1929 | * ARG1: msinum | ||
| 1930 | * ARG2: msistate | ||
| 1931 | * RET0: status | ||
| 1932 | * ERRORS: EINVAL Invalid devhandle or msinum or msistate | ||
| 1933 | * | ||
| 1934 | * Set the state of the MSI defined by the given devhandle and msinum. | ||
| 1935 | */ | ||
| 1936 | #define HV_FAST_PCI_MSI_SETSTATE 0xce | ||
| 1937 | |||
| 1938 | /* pci_msg_getmsiq() | ||
| 1939 | * TRAP: HV_FAST_TRAP | ||
| 1940 | * FUNCTION: HV_FAST_PCI_MSG_GETMSIQ | ||
| 1941 | * ARG0: devhandle | ||
| 1942 | * ARG1: msgtype | ||
| 1943 | * RET0: status | ||
| 1944 | * RET1: msiqid | ||
| 1945 | * ERRORS: EINVAL Invalid devhandle or msgtype | ||
| 1946 | * | ||
| 1947 | * Get the MSI EQ of the MSG defined by the given devhandle and msgtype. | ||
| 1948 | */ | ||
| 1949 | #define HV_FAST_PCI_MSG_GETMSIQ 0xd0 | ||
| 1950 | |||
| 1951 | /* pci_msg_setmsiq() | ||
| 1952 | * TRAP: HV_FAST_TRAP | ||
| 1953 | * FUNCTION: HV_FAST_PCI_MSG_SETMSIQ | ||
| 1954 | * ARG0: devhandle | ||
| 1955 | * ARG1: msgtype | ||
| 1956 | * ARG2: msiqid | ||
| 1957 | * RET0: status | ||
| 1958 | * ERRORS: EINVAL Invalid devhandle, msgtype, or msiqid | ||
| 1959 | * | ||
| 1960 | * Set the MSI EQ of the MSG defined by the given devhandle and msgtype. | ||
| 1961 | */ | ||
| 1962 | #define HV_FAST_PCI_MSG_SETMSIQ 0xd1 | ||
| 1963 | |||
| 1964 | /* pci_msg_getvalid() | ||
| 1965 | * TRAP: HV_FAST_TRAP | ||
| 1966 | * FUNCTION: HV_FAST_PCI_MSG_GETVALID | ||
| 1967 | * ARG0: devhandle | ||
| 1968 | * ARG1: msgtype | ||
| 1969 | * RET0: status | ||
| 1970 | * RET1: msgvalidstate | ||
| 1971 | * ERRORS: EINVAL Invalid devhandle or msgtype | ||
| 1972 | * | ||
| 1973 | * Get the valid/enabled state of the MSG defined by the given | ||
| 1974 | * devhandle and msgtype. | ||
| 1975 | */ | ||
| 1976 | #define HV_FAST_PCI_MSG_GETVALID 0xd2 | ||
| 1977 | |||
| 1978 | /* pci_msg_setvalid() | ||
| 1979 | * TRAP: HV_FAST_TRAP | ||
| 1980 | * FUNCTION: HV_FAST_PCI_MSG_SETVALID | ||
| 1981 | * ARG0: devhandle | ||
| 1982 | * ARG1: msgtype | ||
| 1983 | * ARG2: msgvalidstate | ||
| 1984 | * RET0: status | ||
| 1985 | * ERRORS: EINVAL Invalid devhandle or msgtype or msgvalidstate | ||
| 1986 | * | ||
| 1987 | * Set the valid/enabled state of the MSG defined by the given | ||
| 1988 | * devhandle and msgtype. | ||
| 1989 | */ | ||
| 1990 | #define HV_FAST_PCI_MSG_SETVALID 0xd3 | ||
| 1991 | |||
| 1992 | /* Performance counter services. */ | ||
| 1993 | |||
| 1994 | #define HV_PERF_JBUS_PERF_CTRL_REG 0x00 | ||
| 1995 | #define HV_PERF_JBUS_PERF_CNT_REG 0x01 | ||
| 1996 | #define HV_PERF_DRAM_PERF_CTRL_REG_0 0x02 | ||
| 1997 | #define HV_PERF_DRAM_PERF_CNT_REG_0 0x03 | ||
| 1998 | #define HV_PERF_DRAM_PERF_CTRL_REG_1 0x04 | ||
| 1999 | #define HV_PERF_DRAM_PERF_CNT_REG_1 0x05 | ||
| 2000 | #define HV_PERF_DRAM_PERF_CTRL_REG_2 0x06 | ||
| 2001 | #define HV_PERF_DRAM_PERF_CNT_REG_2 0x07 | ||
| 2002 | #define HV_PERF_DRAM_PERF_CTRL_REG_3 0x08 | ||
| 2003 | #define HV_PERF_DRAM_PERF_CNT_REG_3 0x09 | ||
| 2004 | |||
| 2005 | /* get_perfreg() | ||
| 2006 | * TRAP: HV_FAST_TRAP | ||
| 2007 | * FUNCTION: HV_FAST_GET_PERFREG | ||
| 2008 | * ARG0: performance reg number | ||
| 2009 | * RET0: status | ||
| 2010 | * RET1: performance reg value | ||
| 2011 | * ERRORS: EINVAL Invalid performance register number | ||
| 2012 | * ENOACCESS No access allowed to performance counters | ||
| 2013 | * | ||
| 2014 | * Read the value of the given DRAM/JBUS performance counter/control register. | ||
| 2015 | */ | ||
| 2016 | #define HV_FAST_GET_PERFREG 0x100 | ||
| 2017 | |||
| 2018 | /* set_perfreg() | ||
| 2019 | * TRAP: HV_FAST_TRAP | ||
| 2020 | * FUNCTION: HV_FAST_SET_PERFREG | ||
| 2021 | * ARG0: performance reg number | ||
| 2022 | * ARG1: performance reg value | ||
| 2023 | * RET0: status | ||
| 2024 | * ERRORS: EINVAL Invalid performance register number | ||
| 2025 | * ENOACCESS No access allowed to performance counters | ||
| 2026 | * | ||
| 2027 | * Write the given performance reg value to the given DRAM/JBUS | ||
| 2028 | * performance counter/control register. | ||
| 2029 | */ | ||
| 2030 | #define HV_FAST_SET_PERFREG 0x101 | ||
| 2031 | |||
| 2032 | /* MMU statistics services. | ||
| 2033 | * | ||
| 2034 | * The hypervisor maintains MMU statistics and privileged code provides | ||
| 2035 | * a buffer where these statistics can be collected. It is continually | ||
| 2036 | * updated once configured. The layout is as follows: | ||
| 2037 | */ | ||
| 2038 | #ifndef __ASSEMBLY__ | ||
| 2039 | struct hv_mmu_statistics { | ||
| 2040 | unsigned long immu_tsb_hits_ctx0_8k_tte; | ||
| 2041 | unsigned long immu_tsb_ticks_ctx0_8k_tte; | ||
| 2042 | unsigned long immu_tsb_hits_ctx0_64k_tte; | ||
| 2043 | unsigned long immu_tsb_ticks_ctx0_64k_tte; | ||
| 2044 | unsigned long __reserved1[2]; | ||
| 2045 | unsigned long immu_tsb_hits_ctx0_4mb_tte; | ||
| 2046 | unsigned long immu_tsb_ticks_ctx0_4mb_tte; | ||
| 2047 | unsigned long __reserved2[2]; | ||
| 2048 | unsigned long immu_tsb_hits_ctx0_256mb_tte; | ||
| 2049 | unsigned long immu_tsb_ticks_ctx0_256mb_tte; | ||
| 2050 | unsigned long __reserved3[4]; | ||
| 2051 | unsigned long immu_tsb_hits_ctxnon0_8k_tte; | ||
| 2052 | unsigned long immu_tsb_ticks_ctxnon0_8k_tte; | ||
| 2053 | unsigned long immu_tsb_hits_ctxnon0_64k_tte; | ||
| 2054 | unsigned long immu_tsb_ticks_ctxnon0_64k_tte; | ||
| 2055 | unsigned long __reserved4[2]; | ||
| 2056 | unsigned long immu_tsb_hits_ctxnon0_4mb_tte; | ||
| 2057 | unsigned long immu_tsb_ticks_ctxnon0_4mb_tte; | ||
| 2058 | unsigned long __reserved5[2]; | ||
| 2059 | unsigned long immu_tsb_hits_ctxnon0_256mb_tte; | ||
| 2060 | unsigned long immu_tsb_ticks_ctxnon0_256mb_tte; | ||
| 2061 | unsigned long __reserved6[4]; | ||
| 2062 | unsigned long dmmu_tsb_hits_ctx0_8k_tte; | ||
| 2063 | unsigned long dmmu_tsb_ticks_ctx0_8k_tte; | ||
| 2064 | unsigned long dmmu_tsb_hits_ctx0_64k_tte; | ||
| 2065 | unsigned long dmmu_tsb_ticks_ctx0_64k_tte; | ||
| 2066 | unsigned long __reserved7[2]; | ||
| 2067 | unsigned long dmmu_tsb_hits_ctx0_4mb_tte; | ||
| 2068 | unsigned long dmmu_tsb_ticks_ctx0_4mb_tte; | ||
| 2069 | unsigned long __reserved8[2]; | ||
| 2070 | unsigned long dmmu_tsb_hits_ctx0_256mb_tte; | ||
| 2071 | unsigned long dmmu_tsb_ticks_ctx0_256mb_tte; | ||
| 2072 | unsigned long __reserved9[4]; | ||
| 2073 | unsigned long dmmu_tsb_hits_ctxnon0_8k_tte; | ||
| 2074 | unsigned long dmmu_tsb_ticks_ctxnon0_8k_tte; | ||
| 2075 | unsigned long dmmu_tsb_hits_ctxnon0_64k_tte; | ||
| 2076 | unsigned long dmmu_tsb_ticks_ctxnon0_64k_tte; | ||
| 2077 | unsigned long __reserved10[2]; | ||
| 2078 | unsigned long dmmu_tsb_hits_ctxnon0_4mb_tte; | ||
| 2079 | unsigned long dmmu_tsb_ticks_ctxnon0_4mb_tte; | ||
| 2080 | unsigned long __reserved11[2]; | ||
| 2081 | unsigned long dmmu_tsb_hits_ctxnon0_256mb_tte; | ||
| 2082 | unsigned long dmmu_tsb_ticks_ctxnon0_256mb_tte; | ||
| 2083 | unsigned long __reserved12[4]; | ||
| 2084 | }; | ||
| 2085 | #endif | ||
| 2086 | |||
| 2087 | /* mmustat_conf() | ||
| 2088 | * TRAP: HV_FAST_TRAP | ||
| 2089 | * FUNCTION: HV_FAST_MMUSTAT_CONF | ||
| 2090 | * ARG0: real address | ||
| 2091 | * RET0: status | ||
| 2092 | * RET1: real address | ||
| 2093 | * ERRORS: ENORADDR Invalid real address | ||
| 2094 | * EBADALIGN Real address not aligned on 64-byte boundary | ||
| 2095 | * EBADTRAP API not supported on this processor | ||
| 2096 | * | ||
| 2097 | * Enable MMU statistic gathering using the buffer at the given real | ||
| 2098 | * address on the current virtual CPU. The new buffer real address | ||
| 2099 | * is given in ARG1, and the previously specified buffer real address | ||
| 2100 | * is returned in RET1, or is returned as zero for the first invocation. | ||
| 2101 | * | ||
| 2102 | * If the passed in real address argument is zero, this will disable | ||
| 2103 | * MMU statistic collection on the current virtual CPU. If an error is | ||
| 2104 | * returned then no statistics are collected. | ||
| 2105 | * | ||
| 2106 | * The buffer contents should be initialized to all zeros before being | ||
| 2107 | * given to the hypervisor or else the statistics will be meaningless. | ||
| 2108 | */ | ||
| 2109 | #define HV_FAST_MMUSTAT_CONF 0x102 | ||
| 2110 | |||
| 2111 | /* mmustat_info() | ||
| 2112 | * TRAP: HV_FAST_TRAP | ||
| 2113 | * FUNCTION: HV_FAST_MMUSTAT_INFO | ||
| 2114 | * RET0: status | ||
| 2115 | * RET1: real address | ||
| 2116 | * ERRORS: EBADTRAP API not supported on this processor | ||
| 2117 | * | ||
| 2118 | * Return the current state and real address of the currently configured | ||
| 2119 | * MMU statistics buffer on the current virtual CPU. | ||
| 2120 | */ | ||
| 2121 | #define HV_FAST_MMUSTAT_INFO 0x103 | ||
| 2122 | |||
| 2123 | /* Function numbers for HV_CORE_TRAP. */ | ||
| 2124 | #define HV_CORE_VER 0x00 | ||
| 2125 | #define HV_CORE_PUTCHAR 0x01 | ||
| 2126 | #define HV_CORE_EXIT 0x02 | ||
| 2127 | |||
| 2128 | #endif /* !(_SPARC64_HYPERVISOR_H) */ | ||
diff --git a/include/asm-sparc64/idprom.h b/include/asm-sparc64/idprom.h index 701483c5465d..77fbf987385f 100644 --- a/include/asm-sparc64/idprom.h +++ b/include/asm-sparc64/idprom.h | |||
| @@ -9,15 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | 11 | ||
| 12 | /* Offset into the EEPROM where the id PROM is located on the 4c */ | 12 | struct idprom { |
| 13 | #define IDPROM_OFFSET 0x7d8 | ||
| 14 | |||
| 15 | /* On sun4m; physical. */ | ||
| 16 | /* MicroSPARC(-II) does not decode 31rd bit, but it works. */ | ||
| 17 | #define IDPROM_OFFSET_M 0xfd8 | ||
| 18 | |||
| 19 | struct idprom | ||
| 20 | { | ||
| 21 | u8 id_format; /* Format identifier (always 0x01) */ | 13 | u8 id_format; /* Format identifier (always 0x01) */ |
| 22 | u8 id_machtype; /* Machine type */ | 14 | u8 id_machtype; /* Machine type */ |
| 23 | u8 id_ethaddr[6]; /* Hardware ethernet address */ | 15 | u8 id_ethaddr[6]; /* Hardware ethernet address */ |
| @@ -30,6 +22,4 @@ struct idprom | |||
| 30 | extern struct idprom *idprom; | 22 | extern struct idprom *idprom; |
| 31 | extern void idprom_init(void); | 23 | extern void idprom_init(void); |
| 32 | 24 | ||
| 33 | #define IDPROM_SIZE (sizeof(struct idprom)) | ||
| 34 | |||
| 35 | #endif /* !(_SPARC_IDPROM_H) */ | 25 | #endif /* !(_SPARC_IDPROM_H) */ |
diff --git a/include/asm-sparc64/intr_queue.h b/include/asm-sparc64/intr_queue.h new file mode 100644 index 000000000000..206077dedc2a --- /dev/null +++ b/include/asm-sparc64/intr_queue.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef _SPARC64_INTR_QUEUE_H | ||
| 2 | #define _SPARC64_INTR_QUEUE_H | ||
| 3 | |||
| 4 | /* Sun4v interrupt queue registers, accessed via ASI_QUEUE. */ | ||
| 5 | |||
| 6 | #define INTRQ_CPU_MONDO_HEAD 0x3c0 /* CPU mondo head */ | ||
| 7 | #define INTRQ_CPU_MONDO_TAIL 0x3c8 /* CPU mondo tail */ | ||
| 8 | #define INTRQ_DEVICE_MONDO_HEAD 0x3d0 /* Device mondo head */ | ||
| 9 | #define INTRQ_DEVICE_MONDO_TAIL 0x3d8 /* Device mondo tail */ | ||
| 10 | #define INTRQ_RESUM_MONDO_HEAD 0x3e0 /* Resumable error mondo head */ | ||
| 11 | #define INTRQ_RESUM_MONDO_TAIL 0x3e8 /* Resumable error mondo tail */ | ||
| 12 | #define INTRQ_NONRESUM_MONDO_HEAD 0x3f0 /* Non-resumable error mondo head */ | ||
| 13 | #define INTRQ_NONRESUM_MONDO_TAIL 0x3f8 /* Non-resumable error mondo head */ | ||
| 14 | |||
| 15 | #endif /* !(_SPARC64_INTR_QUEUE_H) */ | ||
diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index 8b70edcb80dc..de33d6e1afb5 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h | |||
| @@ -72,8 +72,11 @@ struct ino_bucket { | |||
| 72 | #define IMAP_VALID 0x80000000 /* IRQ Enabled */ | 72 | #define IMAP_VALID 0x80000000 /* IRQ Enabled */ |
| 73 | #define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */ | 73 | #define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */ |
| 74 | #define IMAP_TID_JBUS 0x7c000000 /* JBUS TargetID */ | 74 | #define IMAP_TID_JBUS 0x7c000000 /* JBUS TargetID */ |
| 75 | #define IMAP_TID_SHIFT 26 | ||
| 75 | #define IMAP_AID_SAFARI 0x7c000000 /* Safari AgentID */ | 76 | #define IMAP_AID_SAFARI 0x7c000000 /* Safari AgentID */ |
| 77 | #define IMAP_AID_SHIFT 26 | ||
| 76 | #define IMAP_NID_SAFARI 0x03e00000 /* Safari NodeID */ | 78 | #define IMAP_NID_SAFARI 0x03e00000 /* Safari NodeID */ |
| 79 | #define IMAP_NID_SHIFT 21 | ||
| 77 | #define IMAP_IGN 0x000007c0 /* IRQ Group Number */ | 80 | #define IMAP_IGN 0x000007c0 /* IRQ Group Number */ |
| 78 | #define IMAP_INO 0x0000003f /* IRQ Number */ | 81 | #define IMAP_INO 0x0000003f /* IRQ Number */ |
| 79 | #define IMAP_INR 0x000007ff /* Full interrupt number*/ | 82 | #define IMAP_INR 0x000007ff /* Full interrupt number*/ |
| @@ -111,6 +114,7 @@ extern void disable_irq(unsigned int); | |||
| 111 | #define disable_irq_nosync disable_irq | 114 | #define disable_irq_nosync disable_irq |
| 112 | extern void enable_irq(unsigned int); | 115 | extern void enable_irq(unsigned int); |
| 113 | extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap); | 116 | extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap); |
| 117 | extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags); | ||
| 114 | extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); | 118 | extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); |
| 115 | 119 | ||
| 116 | static __inline__ void set_softint(unsigned long bits) | 120 | static __inline__ void set_softint(unsigned long bits) |
diff --git a/include/asm-sparc64/mmu.h b/include/asm-sparc64/mmu.h index 8627eed6e83d..230ba678d3b0 100644 --- a/include/asm-sparc64/mmu.h +++ b/include/asm-sparc64/mmu.h | |||
| @@ -4,20 +4,9 @@ | |||
| 4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
| 5 | #include <asm/page.h> | 5 | #include <asm/page.h> |
| 6 | #include <asm/const.h> | 6 | #include <asm/const.h> |
| 7 | #include <asm/hypervisor.h> | ||
| 7 | 8 | ||
| 8 | /* | 9 | #define CTX_NR_BITS 13 |
| 9 | * For the 8k pagesize kernel, use only 10 hw context bits to optimize some | ||
| 10 | * shifts in the fast tlbmiss handlers, instead of all 13 bits (specifically | ||
| 11 | * for vpte offset calculation). For other pagesizes, this optimization in | ||
| 12 | * the tlbhandlers can not be done; but still, all 13 bits can not be used | ||
| 13 | * because the tlb handlers use "andcc" instruction which sign extends 13 | ||
| 14 | * bit arguments. | ||
| 15 | */ | ||
| 16 | #if PAGE_SHIFT == 13 | ||
| 17 | #define CTX_NR_BITS 10 | ||
| 18 | #else | ||
| 19 | #define CTX_NR_BITS 12 | ||
| 20 | #endif | ||
| 21 | 10 | ||
| 22 | #define TAG_CONTEXT_BITS ((_AC(1,UL) << CTX_NR_BITS) - _AC(1,UL)) | 11 | #define TAG_CONTEXT_BITS ((_AC(1,UL) << CTX_NR_BITS) - _AC(1,UL)) |
| 23 | 12 | ||
| @@ -90,8 +79,27 @@ | |||
| 90 | 79 | ||
| 91 | #ifndef __ASSEMBLY__ | 80 | #ifndef __ASSEMBLY__ |
| 92 | 81 | ||
| 82 | #define TSB_ENTRY_ALIGNMENT 16 | ||
| 83 | |||
| 84 | struct tsb { | ||
| 85 | unsigned long tag; | ||
| 86 | unsigned long pte; | ||
| 87 | } __attribute__((aligned(TSB_ENTRY_ALIGNMENT))); | ||
| 88 | |||
| 89 | extern void __tsb_insert(unsigned long ent, unsigned long tag, unsigned long pte); | ||
| 90 | extern void tsb_flush(unsigned long ent, unsigned long tag); | ||
| 91 | extern void tsb_init(struct tsb *tsb, unsigned long size); | ||
| 92 | |||
| 93 | typedef struct { | 93 | typedef struct { |
| 94 | unsigned long sparc64_ctx_val; | 94 | spinlock_t lock; |
| 95 | unsigned long sparc64_ctx_val; | ||
| 96 | struct tsb *tsb; | ||
| 97 | unsigned long tsb_rss_limit; | ||
| 98 | unsigned long tsb_nentries; | ||
| 99 | unsigned long tsb_reg_val; | ||
| 100 | unsigned long tsb_map_vaddr; | ||
| 101 | unsigned long tsb_map_pte; | ||
| 102 | struct hv_tsb_descr tsb_descr; | ||
| 95 | } mm_context_t; | 103 | } mm_context_t; |
| 96 | 104 | ||
| 97 | #endif /* !__ASSEMBLY__ */ | 105 | #endif /* !__ASSEMBLY__ */ |
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index 57ee7b306189..e7974321d052 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h | |||
| @@ -19,96 +19,98 @@ extern unsigned long tlb_context_cache; | |||
| 19 | extern unsigned long mmu_context_bmap[]; | 19 | extern unsigned long mmu_context_bmap[]; |
| 20 | 20 | ||
| 21 | extern void get_new_mmu_context(struct mm_struct *mm); | 21 | extern void get_new_mmu_context(struct mm_struct *mm); |
| 22 | #ifdef CONFIG_SMP | ||
| 23 | extern void smp_new_mmu_context_version(void); | ||
| 24 | #else | ||
| 25 | #define smp_new_mmu_context_version() do { } while (0) | ||
| 26 | #endif | ||
| 27 | |||
| 28 | extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm); | ||
| 29 | extern void destroy_context(struct mm_struct *mm); | ||
| 30 | |||
| 31 | extern void __tsb_context_switch(unsigned long pgd_pa, | ||
| 32 | unsigned long tsb_reg, | ||
| 33 | unsigned long tsb_vaddr, | ||
| 34 | unsigned long tsb_pte, | ||
| 35 | unsigned long tsb_descr_pa); | ||
| 36 | |||
| 37 | static inline void tsb_context_switch(struct mm_struct *mm) | ||
| 38 | { | ||
| 39 | __tsb_context_switch(__pa(mm->pgd), mm->context.tsb_reg_val, | ||
| 40 | mm->context.tsb_map_vaddr, | ||
| 41 | mm->context.tsb_map_pte, | ||
| 42 | __pa(&mm->context.tsb_descr)); | ||
| 43 | } | ||
| 22 | 44 | ||
| 23 | /* Initialize a new mmu context. This is invoked when a new | 45 | extern void tsb_grow(struct mm_struct *mm, unsigned long mm_rss); |
| 24 | * address space instance (unique or shared) is instantiated. | 46 | #ifdef CONFIG_SMP |
| 25 | * This just needs to set mm->context to an invalid context. | 47 | extern void smp_tsb_sync(struct mm_struct *mm); |
| 26 | */ | 48 | #else |
| 27 | #define init_new_context(__tsk, __mm) \ | 49 | #define smp_tsb_sync(__mm) do { } while (0) |
| 28 | (((__mm)->context.sparc64_ctx_val = 0UL), 0) | 50 | #endif |
| 29 | |||
| 30 | /* Destroy a dead context. This occurs when mmput drops the | ||
| 31 | * mm_users count to zero, the mmaps have been released, and | ||
| 32 | * all the page tables have been flushed. Our job is to destroy | ||
| 33 | * any remaining processor-specific state, and in the sparc64 | ||
| 34 | * case this just means freeing up the mmu context ID held by | ||
| 35 | * this task if valid. | ||
| 36 | */ | ||
| 37 | #define destroy_context(__mm) \ | ||
| 38 | do { spin_lock(&ctx_alloc_lock); \ | ||
| 39 | if (CTX_VALID((__mm)->context)) { \ | ||
| 40 | unsigned long nr = CTX_NRBITS((__mm)->context); \ | ||
| 41 | mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63)); \ | ||
| 42 | } \ | ||
| 43 | spin_unlock(&ctx_alloc_lock); \ | ||
| 44 | } while(0) | ||
| 45 | |||
| 46 | /* Reload the two core values used by TLB miss handler | ||
| 47 | * processing on sparc64. They are: | ||
| 48 | * 1) The physical address of mm->pgd, when full page | ||
| 49 | * table walks are necessary, this is where the | ||
| 50 | * search begins. | ||
| 51 | * 2) A "PGD cache". For 32-bit tasks only pgd[0] is | ||
| 52 | * ever used since that maps the entire low 4GB | ||
| 53 | * completely. To speed up TLB miss processing we | ||
| 54 | * make this value available to the handlers. This | ||
| 55 | * decreases the amount of memory traffic incurred. | ||
| 56 | */ | ||
| 57 | #define reload_tlbmiss_state(__tsk, __mm) \ | ||
| 58 | do { \ | ||
| 59 | register unsigned long paddr asm("o5"); \ | ||
| 60 | register unsigned long pgd_cache asm("o4"); \ | ||
| 61 | paddr = __pa((__mm)->pgd); \ | ||
| 62 | pgd_cache = 0UL; \ | ||
| 63 | if (task_thread_info(__tsk)->flags & _TIF_32BIT) \ | ||
| 64 | pgd_cache = get_pgd_cache((__mm)->pgd); \ | ||
| 65 | __asm__ __volatile__("wrpr %%g0, 0x494, %%pstate\n\t" \ | ||
| 66 | "mov %3, %%g4\n\t" \ | ||
| 67 | "mov %0, %%g7\n\t" \ | ||
| 68 | "stxa %1, [%%g4] %2\n\t" \ | ||
| 69 | "membar #Sync\n\t" \ | ||
| 70 | "wrpr %%g0, 0x096, %%pstate" \ | ||
| 71 | : /* no outputs */ \ | ||
| 72 | : "r" (paddr), "r" (pgd_cache),\ | ||
| 73 | "i" (ASI_DMMU), "i" (TSB_REG)); \ | ||
| 74 | } while(0) | ||
| 75 | 51 | ||
| 76 | /* Set MMU context in the actual hardware. */ | 52 | /* Set MMU context in the actual hardware. */ |
| 77 | #define load_secondary_context(__mm) \ | 53 | #define load_secondary_context(__mm) \ |
| 78 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" \ | 54 | __asm__ __volatile__( \ |
| 79 | "flush %%g6" \ | 55 | "\n661: stxa %0, [%1] %2\n" \ |
| 80 | : /* No outputs */ \ | 56 | " .section .sun4v_1insn_patch, \"ax\"\n" \ |
| 81 | : "r" (CTX_HWBITS((__mm)->context)), \ | 57 | " .word 661b\n" \ |
| 82 | "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU)) | 58 | " stxa %0, [%1] %3\n" \ |
| 59 | " .previous\n" \ | ||
| 60 | " flush %%g6\n" \ | ||
| 61 | : /* No outputs */ \ | ||
| 62 | : "r" (CTX_HWBITS((__mm)->context)), \ | ||
| 63 | "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU), "i" (ASI_MMU)) | ||
| 83 | 64 | ||
| 84 | extern void __flush_tlb_mm(unsigned long, unsigned long); | 65 | extern void __flush_tlb_mm(unsigned long, unsigned long); |
| 85 | 66 | ||
| 86 | /* Switch the current MM context. */ | 67 | /* Switch the current MM context. Interrupts are disabled. */ |
| 87 | static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) | 68 | static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) |
| 88 | { | 69 | { |
| 89 | unsigned long ctx_valid; | 70 | unsigned long ctx_valid, flags; |
| 90 | int cpu; | 71 | int cpu; |
| 91 | 72 | ||
| 92 | /* Note: page_table_lock is used here to serialize switch_mm | 73 | spin_lock_irqsave(&mm->context.lock, flags); |
| 93 | * and activate_mm, and their calls to get_new_mmu_context. | ||
| 94 | * This use of page_table_lock is unrelated to its other uses. | ||
| 95 | */ | ||
| 96 | spin_lock(&mm->page_table_lock); | ||
| 97 | ctx_valid = CTX_VALID(mm->context); | 74 | ctx_valid = CTX_VALID(mm->context); |
| 98 | if (!ctx_valid) | 75 | if (!ctx_valid) |
| 99 | get_new_mmu_context(mm); | 76 | get_new_mmu_context(mm); |
| 100 | spin_unlock(&mm->page_table_lock); | ||
| 101 | 77 | ||
| 102 | if (!ctx_valid || (old_mm != mm)) { | 78 | /* We have to be extremely careful here or else we will miss |
| 103 | load_secondary_context(mm); | 79 | * a TSB grow if we switch back and forth between a kernel |
| 104 | reload_tlbmiss_state(tsk, mm); | 80 | * thread and an address space which has it's TSB size increased |
| 105 | } | 81 | * on another processor. |
| 82 | * | ||
| 83 | * It is possible to play some games in order to optimize the | ||
| 84 | * switch, but the safest thing to do is to unconditionally | ||
| 85 | * perform the secondary context load and the TSB context switch. | ||
| 86 | * | ||
| 87 | * For reference the bad case is, for address space "A": | ||
| 88 | * | ||
| 89 | * CPU 0 CPU 1 | ||
| 90 | * run address space A | ||
| 91 | * set cpu0's bits in cpu_vm_mask | ||
| 92 | * switch to kernel thread, borrow | ||
| 93 | * address space A via entry_lazy_tlb | ||
| 94 | * run address space A | ||
| 95 | * set cpu1's bit in cpu_vm_mask | ||
| 96 | * flush_tlb_pending() | ||
| 97 | * reset cpu_vm_mask to just cpu1 | ||
| 98 | * TSB grow | ||
| 99 | * run address space A | ||
| 100 | * context was valid, so skip | ||
| 101 | * TSB context switch | ||
| 102 | * | ||
| 103 | * At that point cpu0 continues to use a stale TSB, the one from | ||
| 104 | * before the TSB grow performed on cpu1. cpu1 did not cross-call | ||
| 105 | * cpu0 to update it's TSB because at that point the cpu_vm_mask | ||
| 106 | * only had cpu1 set in it. | ||
| 107 | */ | ||
| 108 | load_secondary_context(mm); | ||
| 109 | tsb_context_switch(mm); | ||
| 106 | 110 | ||
| 107 | /* Even if (mm == old_mm) we _must_ check | 111 | /* Any time a processor runs a context on an address space |
| 108 | * the cpu_vm_mask. If we do not we could | 112 | * for the first time, we must flush that context out of the |
| 109 | * corrupt the TLB state because of how | 113 | * local TLB. |
| 110 | * smp_flush_tlb_{page,range,mm} on sparc64 | ||
| 111 | * and lazy tlb switches work. -DaveM | ||
| 112 | */ | 114 | */ |
| 113 | cpu = smp_processor_id(); | 115 | cpu = smp_processor_id(); |
| 114 | if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) { | 116 | if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) { |
| @@ -116,6 +118,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str | |||
| 116 | __flush_tlb_mm(CTX_HWBITS(mm->context), | 118 | __flush_tlb_mm(CTX_HWBITS(mm->context), |
| 117 | SECONDARY_CONTEXT); | 119 | SECONDARY_CONTEXT); |
| 118 | } | 120 | } |
| 121 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 119 | } | 122 | } |
| 120 | 123 | ||
| 121 | #define deactivate_mm(tsk,mm) do { } while (0) | 124 | #define deactivate_mm(tsk,mm) do { } while (0) |
| @@ -123,23 +126,20 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str | |||
| 123 | /* Activate a new MM instance for the current task. */ | 126 | /* Activate a new MM instance for the current task. */ |
| 124 | static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm) | 127 | static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm) |
| 125 | { | 128 | { |
| 129 | unsigned long flags; | ||
| 126 | int cpu; | 130 | int cpu; |
| 127 | 131 | ||
| 128 | /* Note: page_table_lock is used here to serialize switch_mm | 132 | spin_lock_irqsave(&mm->context.lock, flags); |
| 129 | * and activate_mm, and their calls to get_new_mmu_context. | ||
| 130 | * This use of page_table_lock is unrelated to its other uses. | ||
| 131 | */ | ||
| 132 | spin_lock(&mm->page_table_lock); | ||
| 133 | if (!CTX_VALID(mm->context)) | 133 | if (!CTX_VALID(mm->context)) |
| 134 | get_new_mmu_context(mm); | 134 | get_new_mmu_context(mm); |
| 135 | cpu = smp_processor_id(); | 135 | cpu = smp_processor_id(); |
| 136 | if (!cpu_isset(cpu, mm->cpu_vm_mask)) | 136 | if (!cpu_isset(cpu, mm->cpu_vm_mask)) |
| 137 | cpu_set(cpu, mm->cpu_vm_mask); | 137 | cpu_set(cpu, mm->cpu_vm_mask); |
| 138 | spin_unlock(&mm->page_table_lock); | ||
| 139 | 138 | ||
| 140 | load_secondary_context(mm); | 139 | load_secondary_context(mm); |
| 141 | __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); | 140 | __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); |
| 142 | reload_tlbmiss_state(current, mm); | 141 | tsb_context_switch(mm); |
| 142 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | #endif /* !(__ASSEMBLY__) */ | 145 | #endif /* !(__ASSEMBLY__) */ |
diff --git a/include/asm-sparc64/numnodes.h b/include/asm-sparc64/numnodes.h new file mode 100644 index 000000000000..017e7e74f5e7 --- /dev/null +++ b/include/asm-sparc64/numnodes.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef _SPARC64_NUMNODES_H | ||
| 2 | #define _SPARC64_NUMNODES_H | ||
| 3 | |||
| 4 | #define NODES_SHIFT 0 | ||
| 5 | |||
| 6 | #endif /* !(_SPARC64_NUMNODES_H) */ | ||
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index 3c59b2693fb9..c754676e13ef 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h | |||
| @@ -12,18 +12,8 @@ | |||
| 12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
| 13 | #include <asm/openprom.h> | 13 | #include <asm/openprom.h> |
| 14 | 14 | ||
| 15 | /* Enumeration to describe the prom major version we have detected. */ | 15 | /* OBP version string. */ |
| 16 | enum prom_major_version { | 16 | extern char prom_version[]; |
| 17 | PROM_V0, /* Original sun4c V0 prom */ | ||
| 18 | PROM_V2, /* sun4c and early sun4m V2 prom */ | ||
| 19 | PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */ | ||
| 20 | PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */ | ||
| 21 | PROM_AP1000, /* actually no prom at all */ | ||
| 22 | }; | ||
| 23 | |||
| 24 | extern enum prom_major_version prom_vers; | ||
| 25 | /* Revision, and firmware revision. */ | ||
| 26 | extern unsigned int prom_rev, prom_prev; | ||
| 27 | 17 | ||
| 28 | /* Root node of the prom device tree, this stays constant after | 18 | /* Root node of the prom device tree, this stays constant after |
| 29 | * initialization is complete. | 19 | * initialization is complete. |
| @@ -39,6 +29,9 @@ extern int prom_stdin, prom_stdout; | |||
| 39 | extern int prom_chosen_node; | 29 | extern int prom_chosen_node; |
| 40 | 30 | ||
| 41 | /* Helper values and strings in arch/sparc64/kernel/head.S */ | 31 | /* Helper values and strings in arch/sparc64/kernel/head.S */ |
| 32 | extern const char prom_peer_name[]; | ||
| 33 | extern const char prom_compatible_name[]; | ||
| 34 | extern const char prom_root_compatible[]; | ||
| 42 | extern const char prom_finddev_name[]; | 35 | extern const char prom_finddev_name[]; |
| 43 | extern const char prom_chosen_path[]; | 36 | extern const char prom_chosen_path[]; |
| 44 | extern const char prom_getprop_name[]; | 37 | extern const char prom_getprop_name[]; |
| @@ -130,15 +123,6 @@ extern void prom_setcallback(callback_func_t func_ptr); | |||
| 130 | */ | 123 | */ |
| 131 | extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); | 124 | extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); |
| 132 | 125 | ||
| 133 | /* Get the prom major version. */ | ||
| 134 | extern int prom_version(void); | ||
| 135 | |||
| 136 | /* Get the prom plugin revision. */ | ||
| 137 | extern int prom_getrev(void); | ||
| 138 | |||
| 139 | /* Get the prom firmware revision. */ | ||
| 140 | extern int prom_getprev(void); | ||
| 141 | |||
| 142 | /* Character operations to/from the console.... */ | 126 | /* Character operations to/from the console.... */ |
| 143 | 127 | ||
| 144 | /* Non-blocking get character from console. */ | 128 | /* Non-blocking get character from console. */ |
| @@ -164,6 +148,7 @@ enum prom_input_device { | |||
| 164 | PROMDEV_ITTYA, /* input from ttya */ | 148 | PROMDEV_ITTYA, /* input from ttya */ |
| 165 | PROMDEV_ITTYB, /* input from ttyb */ | 149 | PROMDEV_ITTYB, /* input from ttyb */ |
| 166 | PROMDEV_IRSC, /* input from rsc */ | 150 | PROMDEV_IRSC, /* input from rsc */ |
| 151 | PROMDEV_IVCONS, /* input from virtual-console */ | ||
| 167 | PROMDEV_I_UNK, | 152 | PROMDEV_I_UNK, |
| 168 | }; | 153 | }; |
| 169 | 154 | ||
| @@ -176,6 +161,7 @@ enum prom_output_device { | |||
| 176 | PROMDEV_OTTYA, /* to ttya */ | 161 | PROMDEV_OTTYA, /* to ttya */ |
| 177 | PROMDEV_OTTYB, /* to ttyb */ | 162 | PROMDEV_OTTYB, /* to ttyb */ |
| 178 | PROMDEV_ORSC, /* to rsc */ | 163 | PROMDEV_ORSC, /* to rsc */ |
| 164 | PROMDEV_OVCONS, /* to virtual-console */ | ||
| 179 | PROMDEV_O_UNK, | 165 | PROMDEV_O_UNK, |
| 180 | }; | 166 | }; |
| 181 | 167 | ||
| @@ -183,10 +169,18 @@ extern enum prom_output_device prom_query_output_device(void); | |||
| 183 | 169 | ||
| 184 | /* Multiprocessor operations... */ | 170 | /* Multiprocessor operations... */ |
| 185 | #ifdef CONFIG_SMP | 171 | #ifdef CONFIG_SMP |
| 186 | /* Start the CPU with the given device tree node, context table, and context | 172 | /* Start the CPU with the given device tree node at the passed program |
| 187 | * at the passed program counter. | 173 | * counter with the given arg passed in via register %o0. |
| 174 | */ | ||
| 175 | extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg); | ||
| 176 | |||
| 177 | /* Start the CPU with the given cpu ID at the passed program | ||
| 178 | * counter with the given arg passed in via register %o0. | ||
| 188 | */ | 179 | */ |
| 189 | extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0); | 180 | extern void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg); |
| 181 | |||
| 182 | /* Stop the CPU with the given cpu ID. */ | ||
| 183 | extern void prom_stopcpu_cpuid(int cpuid); | ||
| 190 | 184 | ||
| 191 | /* Stop the current CPU. */ | 185 | /* Stop the current CPU. */ |
| 192 | extern void prom_stopself(void); | 186 | extern void prom_stopself(void); |
| @@ -335,6 +329,7 @@ int cpu_find_by_mid(int mid, int *prom_node); | |||
| 335 | 329 | ||
| 336 | /* Client interface level routines. */ | 330 | /* Client interface level routines. */ |
| 337 | extern void prom_set_trap_table(unsigned long tba); | 331 | extern void prom_set_trap_table(unsigned long tba); |
| 332 | extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa); | ||
| 338 | 333 | ||
| 339 | extern long p1275_cmd(const char *, long, ...); | 334 | extern long p1275_cmd(const char *, long, ...); |
| 340 | 335 | ||
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index 5426bb28a993..fcb2812265f4 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h | |||
| @@ -104,10 +104,12 @@ typedef unsigned long pgprot_t; | |||
| 104 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) | 104 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) |
| 105 | #define ARCH_HAS_SETCLEAR_HUGE_PTE | 105 | #define ARCH_HAS_SETCLEAR_HUGE_PTE |
| 106 | #define ARCH_HAS_HUGETLB_PREFAULT_HOOK | 106 | #define ARCH_HAS_HUGETLB_PREFAULT_HOOK |
| 107 | #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA | ||
| 107 | #endif | 108 | #endif |
| 108 | 109 | ||
| 109 | #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \ | 110 | #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \ |
| 110 | (_AC(0x0000000070000000,UL)) : (PAGE_OFFSET)) | 111 | (_AC(0x0000000070000000,UL)) : \ |
| 112 | (_AC(0xfffff80000000000,UL) + (1UL << 32UL))) | ||
| 111 | 113 | ||
| 112 | #endif /* !(__ASSEMBLY__) */ | 114 | #endif /* !(__ASSEMBLY__) */ |
| 113 | 115 | ||
| @@ -124,17 +126,10 @@ typedef unsigned long pgprot_t; | |||
| 124 | #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) | 126 | #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) |
| 125 | #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) | 127 | #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) |
| 126 | 128 | ||
| 127 | /* PFNs are real physical page numbers. However, mem_map only begins to record | 129 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) |
| 128 | * per-page information starting at pfn_base. This is to handle systems where | ||
| 129 | * the first physical page in the machine is at some huge physical address, | ||
| 130 | * such as 4GB. This is common on a partitioned E10000, for example. | ||
| 131 | */ | ||
| 132 | extern struct page *pfn_to_page(unsigned long pfn); | ||
| 133 | extern unsigned long page_to_pfn(struct page *); | ||
| 134 | 130 | ||
| 135 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr)>>PAGE_SHIFT) | 131 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr)>>PAGE_SHIFT) |
| 136 | 132 | ||
| 137 | #define pfn_valid(pfn) (((pfn)-(pfn_base)) < max_mapnr) | ||
| 138 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) | 133 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) |
| 139 | 134 | ||
| 140 | #define virt_to_phys __pa | 135 | #define virt_to_phys __pa |
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index dd35a2c7798a..1396f110939a 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h | |||
| @@ -139,6 +139,9 @@ struct pci_pbm_info { | |||
| 139 | /* Opaque 32-bit system bus Port ID. */ | 139 | /* Opaque 32-bit system bus Port ID. */ |
| 140 | u32 portid; | 140 | u32 portid; |
| 141 | 141 | ||
| 142 | /* Opaque 32-bit handle used for hypervisor calls. */ | ||
| 143 | u32 devhandle; | ||
| 144 | |||
| 142 | /* Chipset version information. */ | 145 | /* Chipset version information. */ |
| 143 | int chip_type; | 146 | int chip_type; |
| 144 | #define PBM_CHIP_TYPE_SABRE 1 | 147 | #define PBM_CHIP_TYPE_SABRE 1 |
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 89bd71b1c0d8..7c5a589ea437 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h | |||
| @@ -41,10 +41,26 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) | |||
| 41 | 41 | ||
| 42 | struct pci_dev; | 42 | struct pci_dev; |
| 43 | 43 | ||
| 44 | struct pci_iommu_ops { | ||
| 45 | void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *); | ||
| 46 | void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t); | ||
| 47 | dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int); | ||
| 48 | void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int); | ||
| 49 | int (*map_sg)(struct pci_dev *, struct scatterlist *, int, int); | ||
| 50 | void (*unmap_sg)(struct pci_dev *, struct scatterlist *, int, int); | ||
| 51 | void (*dma_sync_single_for_cpu)(struct pci_dev *, dma_addr_t, size_t, int); | ||
| 52 | void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int); | ||
| 53 | }; | ||
| 54 | |||
| 55 | extern struct pci_iommu_ops *pci_iommu_ops; | ||
| 56 | |||
| 44 | /* Allocate and map kernel buffer using consistent mode DMA for a device. | 57 | /* Allocate and map kernel buffer using consistent mode DMA for a device. |
| 45 | * hwdev should be valid struct pci_dev pointer for PCI devices. | 58 | * hwdev should be valid struct pci_dev pointer for PCI devices. |
| 46 | */ | 59 | */ |
| 47 | extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle); | 60 | static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) |
| 61 | { | ||
| 62 | return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle); | ||
| 63 | } | ||
| 48 | 64 | ||
| 49 | /* Free and unmap a consistent DMA buffer. | 65 | /* Free and unmap a consistent DMA buffer. |
| 50 | * cpu_addr is what was returned from pci_alloc_consistent, | 66 | * cpu_addr is what was returned from pci_alloc_consistent, |
| @@ -54,7 +70,10 @@ extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t | |||
| 54 | * References to the memory and mappings associated with cpu_addr/dma_addr | 70 | * References to the memory and mappings associated with cpu_addr/dma_addr |
| 55 | * past this call are illegal. | 71 | * past this call are illegal. |
| 56 | */ | 72 | */ |
| 57 | extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); | 73 | static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) |
| 74 | { | ||
| 75 | return pci_iommu_ops->free_consistent(hwdev, size, vaddr, dma_handle); | ||
| 76 | } | ||
| 58 | 77 | ||
| 59 | /* Map a single buffer of the indicated size for DMA in streaming mode. | 78 | /* Map a single buffer of the indicated size for DMA in streaming mode. |
| 60 | * The 32-bit bus address to use is returned. | 79 | * The 32-bit bus address to use is returned. |
| @@ -62,7 +81,10 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, | |||
| 62 | * Once the device is given the dma address, the device owns this memory | 81 | * Once the device is given the dma address, the device owns this memory |
| 63 | * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. | 82 | * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. |
| 64 | */ | 83 | */ |
| 65 | extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); | 84 | static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) |
| 85 | { | ||
| 86 | return pci_iommu_ops->map_single(hwdev, ptr, size, direction); | ||
| 87 | } | ||
| 66 | 88 | ||
| 67 | /* Unmap a single streaming mode DMA translation. The dma_addr and size | 89 | /* Unmap a single streaming mode DMA translation. The dma_addr and size |
| 68 | * must match what was provided for in a previous pci_map_single call. All | 90 | * must match what was provided for in a previous pci_map_single call. All |
| @@ -71,7 +93,10 @@ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, | |||
| 71 | * After this call, reads by the cpu to the buffer are guaranteed to see | 93 | * After this call, reads by the cpu to the buffer are guaranteed to see |
| 72 | * whatever the device wrote there. | 94 | * whatever the device wrote there. |
| 73 | */ | 95 | */ |
| 74 | extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); | 96 | static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) |
| 97 | { | ||
| 98 | pci_iommu_ops->unmap_single(hwdev, dma_addr, size, direction); | ||
| 99 | } | ||
| 75 | 100 | ||
| 76 | /* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */ | 101 | /* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */ |
| 77 | #define pci_map_page(dev, page, off, size, dir) \ | 102 | #define pci_map_page(dev, page, off, size, dir) \ |
| @@ -107,15 +132,19 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t | |||
| 107 | * Device ownership issues as mentioned above for pci_map_single are | 132 | * Device ownership issues as mentioned above for pci_map_single are |
| 108 | * the same here. | 133 | * the same here. |
| 109 | */ | 134 | */ |
| 110 | extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, | 135 | static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) |
| 111 | int nents, int direction); | 136 | { |
| 137 | return pci_iommu_ops->map_sg(hwdev, sg, nents, direction); | ||
| 138 | } | ||
| 112 | 139 | ||
| 113 | /* Unmap a set of streaming mode DMA translations. | 140 | /* Unmap a set of streaming mode DMA translations. |
| 114 | * Again, cpu read rules concerning calls here are the same as for | 141 | * Again, cpu read rules concerning calls here are the same as for |
| 115 | * pci_unmap_single() above. | 142 | * pci_unmap_single() above. |
| 116 | */ | 143 | */ |
| 117 | extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, | 144 | static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction) |
| 118 | int nhwents, int direction); | 145 | { |
| 146 | pci_iommu_ops->unmap_sg(hwdev, sg, nhwents, direction); | ||
| 147 | } | ||
| 119 | 148 | ||
| 120 | /* Make physical memory consistent for a single | 149 | /* Make physical memory consistent for a single |
| 121 | * streaming mode DMA translation after a transfer. | 150 | * streaming mode DMA translation after a transfer. |
| @@ -127,8 +156,10 @@ extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, | |||
| 127 | * must first perform a pci_dma_sync_for_device, and then the | 156 | * must first perform a pci_dma_sync_for_device, and then the |
| 128 | * device again owns the buffer. | 157 | * device again owns the buffer. |
| 129 | */ | 158 | */ |
| 130 | extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, | 159 | static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) |
| 131 | size_t size, int direction); | 160 | { |
| 161 | pci_iommu_ops->dma_sync_single_for_cpu(hwdev, dma_handle, size, direction); | ||
| 162 | } | ||
| 132 | 163 | ||
| 133 | static inline void | 164 | static inline void |
| 134 | pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, | 165 | pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, |
| @@ -144,7 +175,10 @@ pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, | |||
| 144 | * The same as pci_dma_sync_single_* but for a scatter-gather list, | 175 | * The same as pci_dma_sync_single_* but for a scatter-gather list, |
| 145 | * same rules and usage. | 176 | * same rules and usage. |
| 146 | */ | 177 | */ |
| 147 | extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); | 178 | static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) |
| 179 | { | ||
| 180 | pci_iommu_ops->dma_sync_sg_for_cpu(hwdev, sg, nelems, direction); | ||
| 181 | } | ||
| 148 | 182 | ||
| 149 | static inline void | 183 | static inline void |
| 150 | pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, | 184 | pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, |
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h index a96067cca963..12e4a273bd43 100644 --- a/include/asm-sparc64/pgalloc.h +++ b/include/asm-sparc64/pgalloc.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
| 7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
| 8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
| 9 | #include <linux/slab.h> | ||
| 9 | 10 | ||
| 10 | #include <asm/spitfire.h> | 11 | #include <asm/spitfire.h> |
| 11 | #include <asm/cpudata.h> | 12 | #include <asm/cpudata.h> |
| @@ -13,172 +14,59 @@ | |||
| 13 | #include <asm/page.h> | 14 | #include <asm/page.h> |
| 14 | 15 | ||
| 15 | /* Page table allocation/freeing. */ | 16 | /* Page table allocation/freeing. */ |
| 16 | #ifdef CONFIG_SMP | 17 | extern kmem_cache_t *pgtable_cache; |
| 17 | /* Sliiiicck */ | ||
| 18 | #define pgt_quicklists local_cpu_data() | ||
| 19 | #else | ||
| 20 | extern struct pgtable_cache_struct { | ||
| 21 | unsigned long *pgd_cache; | ||
| 22 | unsigned long *pte_cache[2]; | ||
| 23 | unsigned int pgcache_size; | ||
| 24 | } pgt_quicklists; | ||
| 25 | #endif | ||
| 26 | #define pgd_quicklist (pgt_quicklists.pgd_cache) | ||
| 27 | #define pmd_quicklist ((unsigned long *)0) | ||
| 28 | #define pte_quicklist (pgt_quicklists.pte_cache) | ||
| 29 | #define pgtable_cache_size (pgt_quicklists.pgcache_size) | ||
| 30 | 18 | ||
| 31 | static __inline__ void free_pgd_fast(pgd_t *pgd) | 19 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
| 32 | { | 20 | { |
| 33 | preempt_disable(); | 21 | return kmem_cache_alloc(pgtable_cache, GFP_KERNEL); |
| 34 | *(unsigned long *)pgd = (unsigned long) pgd_quicklist; | ||
| 35 | pgd_quicklist = (unsigned long *) pgd; | ||
| 36 | pgtable_cache_size++; | ||
| 37 | preempt_enable(); | ||
| 38 | } | 22 | } |
| 39 | 23 | ||
| 40 | static __inline__ pgd_t *get_pgd_fast(void) | 24 | static inline void pgd_free(pgd_t *pgd) |
| 41 | { | 25 | { |
| 42 | unsigned long *ret; | 26 | kmem_cache_free(pgtable_cache, pgd); |
| 43 | |||
| 44 | preempt_disable(); | ||
| 45 | if((ret = pgd_quicklist) != NULL) { | ||
| 46 | pgd_quicklist = (unsigned long *)(*ret); | ||
| 47 | ret[0] = 0; | ||
| 48 | pgtable_cache_size--; | ||
| 49 | preempt_enable(); | ||
| 50 | } else { | ||
| 51 | preempt_enable(); | ||
| 52 | ret = (unsigned long *) __get_free_page(GFP_KERNEL|__GFP_REPEAT); | ||
| 53 | if(ret) | ||
| 54 | memset(ret, 0, PAGE_SIZE); | ||
| 55 | } | ||
| 56 | return (pgd_t *)ret; | ||
| 57 | } | 27 | } |
| 58 | 28 | ||
| 59 | static __inline__ void free_pgd_slow(pgd_t *pgd) | ||
| 60 | { | ||
| 61 | free_page((unsigned long)pgd); | ||
| 62 | } | ||
| 63 | |||
| 64 | #ifdef DCACHE_ALIASING_POSSIBLE | ||
| 65 | #define VPTE_COLOR(address) (((address) >> (PAGE_SHIFT + 10)) & 1UL) | ||
| 66 | #define DCACHE_COLOR(address) (((address) >> PAGE_SHIFT) & 1UL) | ||
| 67 | #else | ||
| 68 | #define VPTE_COLOR(address) 0 | ||
| 69 | #define DCACHE_COLOR(address) 0 | ||
| 70 | #endif | ||
| 71 | |||
| 72 | #define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) | 29 | #define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) |
| 73 | 30 | ||
| 74 | static __inline__ pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) | 31 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) |
| 75 | { | 32 | { |
| 76 | unsigned long *ret; | 33 | return kmem_cache_alloc(pgtable_cache, |
| 77 | int color = 0; | 34 | GFP_KERNEL|__GFP_REPEAT); |
| 78 | |||
| 79 | preempt_disable(); | ||
| 80 | if (pte_quicklist[color] == NULL) | ||
| 81 | color = 1; | ||
| 82 | |||
| 83 | if((ret = (unsigned long *)pte_quicklist[color]) != NULL) { | ||
| 84 | pte_quicklist[color] = (unsigned long *)(*ret); | ||
| 85 | ret[0] = 0; | ||
| 86 | pgtable_cache_size--; | ||
| 87 | } | ||
| 88 | preempt_enable(); | ||
| 89 | |||
| 90 | return (pmd_t *)ret; | ||
| 91 | } | 35 | } |
| 92 | 36 | ||
| 93 | static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) | 37 | static inline void pmd_free(pmd_t *pmd) |
| 94 | { | 38 | { |
| 95 | pmd_t *pmd; | 39 | kmem_cache_free(pgtable_cache, pmd); |
| 96 | |||
| 97 | pmd = pmd_alloc_one_fast(mm, address); | ||
| 98 | if (!pmd) { | ||
| 99 | pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); | ||
| 100 | if (pmd) | ||
| 101 | memset(pmd, 0, PAGE_SIZE); | ||
| 102 | } | ||
| 103 | return pmd; | ||
| 104 | } | 40 | } |
| 105 | 41 | ||
| 106 | static __inline__ void free_pmd_fast(pmd_t *pmd) | 42 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, |
| 43 | unsigned long address) | ||
| 107 | { | 44 | { |
| 108 | unsigned long color = DCACHE_COLOR((unsigned long)pmd); | 45 | return kmem_cache_alloc(pgtable_cache, |
| 109 | 46 | GFP_KERNEL|__GFP_REPEAT); | |
| 110 | preempt_disable(); | ||
| 111 | *(unsigned long *)pmd = (unsigned long) pte_quicklist[color]; | ||
| 112 | pte_quicklist[color] = (unsigned long *) pmd; | ||
| 113 | pgtable_cache_size++; | ||
| 114 | preempt_enable(); | ||
| 115 | } | 47 | } |
| 116 | 48 | ||
| 117 | static __inline__ void free_pmd_slow(pmd_t *pmd) | 49 | static inline struct page *pte_alloc_one(struct mm_struct *mm, |
| 50 | unsigned long address) | ||
| 118 | { | 51 | { |
| 119 | free_page((unsigned long)pmd); | 52 | return virt_to_page(pte_alloc_one_kernel(mm, address)); |
| 120 | } | 53 | } |
| 121 | 54 | ||
| 122 | #define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE) | ||
| 123 | #define pmd_populate(MM,PMD,PTE_PAGE) \ | ||
| 124 | pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE)) | ||
| 125 | |||
| 126 | extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address); | ||
| 127 | |||
| 128 | static inline struct page * | ||
| 129 | pte_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
| 130 | { | ||
| 131 | pte_t *pte = pte_alloc_one_kernel(mm, addr); | ||
| 132 | |||
| 133 | if (pte) | ||
| 134 | return virt_to_page(pte); | ||
| 135 | |||
| 136 | return NULL; | ||
| 137 | } | ||
| 138 | |||
| 139 | static __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) | ||
| 140 | { | ||
| 141 | unsigned long color = VPTE_COLOR(address); | ||
| 142 | unsigned long *ret; | ||
| 143 | |||
| 144 | preempt_disable(); | ||
| 145 | if((ret = (unsigned long *)pte_quicklist[color]) != NULL) { | ||
| 146 | pte_quicklist[color] = (unsigned long *)(*ret); | ||
| 147 | ret[0] = 0; | ||
| 148 | pgtable_cache_size--; | ||
| 149 | } | ||
| 150 | preempt_enable(); | ||
| 151 | return (pte_t *)ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | static __inline__ void free_pte_fast(pte_t *pte) | ||
| 155 | { | ||
| 156 | unsigned long color = DCACHE_COLOR((unsigned long)pte); | ||
| 157 | |||
| 158 | preempt_disable(); | ||
| 159 | *(unsigned long *)pte = (unsigned long) pte_quicklist[color]; | ||
| 160 | pte_quicklist[color] = (unsigned long *) pte; | ||
| 161 | pgtable_cache_size++; | ||
| 162 | preempt_enable(); | ||
| 163 | } | ||
| 164 | |||
| 165 | static __inline__ void free_pte_slow(pte_t *pte) | ||
| 166 | { | ||
| 167 | free_page((unsigned long)pte); | ||
| 168 | } | ||
| 169 | |||
| 170 | static inline void pte_free_kernel(pte_t *pte) | 55 | static inline void pte_free_kernel(pte_t *pte) |
| 171 | { | 56 | { |
| 172 | free_pte_fast(pte); | 57 | kmem_cache_free(pgtable_cache, pte); |
| 173 | } | 58 | } |
| 174 | 59 | ||
| 175 | static inline void pte_free(struct page *ptepage) | 60 | static inline void pte_free(struct page *ptepage) |
| 176 | { | 61 | { |
| 177 | free_pte_fast(page_address(ptepage)); | 62 | pte_free_kernel(page_address(ptepage)); |
| 178 | } | 63 | } |
| 179 | 64 | ||
| 180 | #define pmd_free(pmd) free_pmd_fast(pmd) | 65 | |
| 181 | #define pgd_free(pgd) free_pgd_fast(pgd) | 66 | #define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE) |
| 182 | #define pgd_alloc(mm) get_pgd_fast() | 67 | #define pmd_populate(MM,PMD,PTE_PAGE) \ |
| 68 | pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE)) | ||
| 69 | |||
| 70 | #define check_pgt_cache() do { } while (0) | ||
| 183 | 71 | ||
| 184 | #endif /* _SPARC64_PGALLOC_H */ | 72 | #endif /* _SPARC64_PGALLOC_H */ |
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index f0a9b44d3eb5..ed4124edf837 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h | |||
| @@ -25,7 +25,8 @@ | |||
| 25 | #include <asm/const.h> | 25 | #include <asm/const.h> |
| 26 | 26 | ||
| 27 | /* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB). | 27 | /* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB). |
| 28 | * The page copy blockops can use 0x2000000 to 0x10000000. | 28 | * The page copy blockops can use 0x2000000 to 0x4000000. |
| 29 | * The TSB is mapped in the 0x4000000 to 0x6000000 range. | ||
| 29 | * The PROM resides in an area spanning 0xf0000000 to 0x100000000. | 30 | * The PROM resides in an area spanning 0xf0000000 to 0x100000000. |
| 30 | * The vmalloc area spans 0x100000000 to 0x200000000. | 31 | * The vmalloc area spans 0x100000000 to 0x200000000. |
| 31 | * Since modules need to be in the lowest 32-bits of the address space, | 32 | * Since modules need to be in the lowest 32-bits of the address space, |
| @@ -34,6 +35,7 @@ | |||
| 34 | * 0x400000000. | 35 | * 0x400000000. |
| 35 | */ | 36 | */ |
| 36 | #define TLBTEMP_BASE _AC(0x0000000002000000,UL) | 37 | #define TLBTEMP_BASE _AC(0x0000000002000000,UL) |
| 38 | #define TSBMAP_BASE _AC(0x0000000004000000,UL) | ||
| 37 | #define MODULES_VADDR _AC(0x0000000010000000,UL) | 39 | #define MODULES_VADDR _AC(0x0000000010000000,UL) |
| 38 | #define MODULES_LEN _AC(0x00000000e0000000,UL) | 40 | #define MODULES_LEN _AC(0x00000000e0000000,UL) |
| 39 | #define MODULES_END _AC(0x00000000f0000000,UL) | 41 | #define MODULES_END _AC(0x00000000f0000000,UL) |
| @@ -88,162 +90,538 @@ | |||
| 88 | 90 | ||
| 89 | #endif /* !(__ASSEMBLY__) */ | 91 | #endif /* !(__ASSEMBLY__) */ |
| 90 | 92 | ||
| 91 | /* Spitfire/Cheetah TTE bits. */ | 93 | /* PTE bits which are the same in SUN4U and SUN4V format. */ |
| 92 | #define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */ | 94 | #define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */ |
| 93 | #define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit up to date*/ | 95 | #define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/ |
| 94 | #define _PAGE_SZ4MB _AC(0x6000000000000000,UL) /* 4MB Page */ | 96 | |
| 95 | #define _PAGE_SZ512K _AC(0x4000000000000000,UL) /* 512K Page */ | 97 | /* SUN4U pte bits... */ |
| 96 | #define _PAGE_SZ64K _AC(0x2000000000000000,UL) /* 64K Page */ | 98 | #define _PAGE_SZ4MB_4U _AC(0x6000000000000000,UL) /* 4MB Page */ |
| 97 | #define _PAGE_SZ8K _AC(0x0000000000000000,UL) /* 8K Page */ | 99 | #define _PAGE_SZ512K_4U _AC(0x4000000000000000,UL) /* 512K Page */ |
| 98 | #define _PAGE_NFO _AC(0x1000000000000000,UL) /* No Fault Only */ | 100 | #define _PAGE_SZ64K_4U _AC(0x2000000000000000,UL) /* 64K Page */ |
| 99 | #define _PAGE_IE _AC(0x0800000000000000,UL) /* Invert Endianness */ | 101 | #define _PAGE_SZ8K_4U _AC(0x0000000000000000,UL) /* 8K Page */ |
| 100 | #define _PAGE_SOFT2 _AC(0x07FC000000000000,UL) /* Software bits, set 2 */ | 102 | #define _PAGE_NFO_4U _AC(0x1000000000000000,UL) /* No Fault Only */ |
| 101 | #define _PAGE_RES1 _AC(0x0002000000000000,UL) /* Reserved */ | 103 | #define _PAGE_IE_4U _AC(0x0800000000000000,UL) /* Invert Endianness */ |
| 102 | #define _PAGE_SZ32MB _AC(0x0001000000000000,UL) /* (Panther) 32MB page */ | 104 | #define _PAGE_SOFT2_4U _AC(0x07FC000000000000,UL) /* Software bits, set 2 */ |
| 103 | #define _PAGE_SZ256MB _AC(0x2001000000000000,UL) /* (Panther) 256MB page */ | 105 | #define _PAGE_RES1_4U _AC(0x0002000000000000,UL) /* Reserved */ |
| 104 | #define _PAGE_SN _AC(0x0000800000000000,UL) /* (Cheetah) Snoop */ | 106 | #define _PAGE_SZ32MB_4U _AC(0x0001000000000000,UL) /* (Panther) 32MB page */ |
| 105 | #define _PAGE_RES2 _AC(0x0000780000000000,UL) /* Reserved */ | 107 | #define _PAGE_SZ256MB_4U _AC(0x2001000000000000,UL) /* (Panther) 256MB page */ |
| 106 | #define _PAGE_PADDR_SF _AC(0x000001FFFFFFE000,UL) /* (Spitfire) paddr[40:13]*/ | 108 | #define _PAGE_SN_4U _AC(0x0000800000000000,UL) /* (Cheetah) Snoop */ |
| 107 | #define _PAGE_PADDR _AC(0x000007FFFFFFE000,UL) /* (Cheetah) paddr[42:13] */ | 109 | #define _PAGE_RES2_4U _AC(0x0000780000000000,UL) /* Reserved */ |
| 108 | #define _PAGE_SOFT _AC(0x0000000000001F80,UL) /* Software bits */ | 110 | #define _PAGE_PADDR_4U _AC(0x000007FFFFFFE000,UL) /* (Cheetah) pa[42:13] */ |
| 109 | #define _PAGE_L _AC(0x0000000000000040,UL) /* Locked TTE */ | 111 | #define _PAGE_SOFT_4U _AC(0x0000000000001F80,UL) /* Software bits: */ |
| 110 | #define _PAGE_CP _AC(0x0000000000000020,UL) /* Cacheable in P-Cache */ | 112 | #define _PAGE_EXEC_4U _AC(0x0000000000001000,UL) /* Executable SW bit */ |
| 111 | #define _PAGE_CV _AC(0x0000000000000010,UL) /* Cacheable in V-Cache */ | 113 | #define _PAGE_MODIFIED_4U _AC(0x0000000000000800,UL) /* Modified (dirty) */ |
| 112 | #define _PAGE_E _AC(0x0000000000000008,UL) /* side-Effect */ | 114 | #define _PAGE_FILE_4U _AC(0x0000000000000800,UL) /* Pagecache page */ |
| 113 | #define _PAGE_P _AC(0x0000000000000004,UL) /* Privileged Page */ | 115 | #define _PAGE_ACCESSED_4U _AC(0x0000000000000400,UL) /* Accessed (ref'd) */ |
| 114 | #define _PAGE_W _AC(0x0000000000000002,UL) /* Writable */ | 116 | #define _PAGE_READ_4U _AC(0x0000000000000200,UL) /* Readable SW Bit */ |
| 115 | #define _PAGE_G _AC(0x0000000000000001,UL) /* Global */ | 117 | #define _PAGE_WRITE_4U _AC(0x0000000000000100,UL) /* Writable SW Bit */ |
| 116 | 118 | #define _PAGE_PRESENT_4U _AC(0x0000000000000080,UL) /* Present */ | |
| 117 | /* Here are the SpitFire software bits we use in the TTE's. | 119 | #define _PAGE_L_4U _AC(0x0000000000000040,UL) /* Locked TTE */ |
| 118 | * | 120 | #define _PAGE_CP_4U _AC(0x0000000000000020,UL) /* Cacheable in P-Cache */ |
| 119 | * WARNING: If you are going to try and start using some | 121 | #define _PAGE_CV_4U _AC(0x0000000000000010,UL) /* Cacheable in V-Cache */ |
| 120 | * of the soft2 bits, you will need to make | 122 | #define _PAGE_E_4U _AC(0x0000000000000008,UL) /* side-Effect */ |
| 121 | * modifications to the swap entry implementation. | 123 | #define _PAGE_P_4U _AC(0x0000000000000004,UL) /* Privileged Page */ |
| 122 | * For example, one thing that could happen is that | 124 | #define _PAGE_W_4U _AC(0x0000000000000002,UL) /* Writable */ |
| 123 | * swp_entry_to_pte() would BUG_ON() if you tried | 125 | |
| 124 | * to use one of the soft2 bits for _PAGE_FILE. | 126 | /* SUN4V pte bits... */ |
| 125 | * | 127 | #define _PAGE_NFO_4V _AC(0x4000000000000000,UL) /* No Fault Only */ |
| 126 | * Like other architectures, I have aliased _PAGE_FILE with | 128 | #define _PAGE_SOFT2_4V _AC(0x3F00000000000000,UL) /* Software bits, set 2 */ |
| 127 | * _PAGE_MODIFIED. This works because _PAGE_FILE is never | 129 | #define _PAGE_MODIFIED_4V _AC(0x2000000000000000,UL) /* Modified (dirty) */ |
| 128 | * interpreted that way unless _PAGE_PRESENT is clear. | 130 | #define _PAGE_ACCESSED_4V _AC(0x1000000000000000,UL) /* Accessed (ref'd) */ |
| 129 | */ | 131 | #define _PAGE_READ_4V _AC(0x0800000000000000,UL) /* Readable SW Bit */ |
| 130 | #define _PAGE_EXEC _AC(0x0000000000001000,UL) /* Executable SW bit */ | 132 | #define _PAGE_WRITE_4V _AC(0x0400000000000000,UL) /* Writable SW Bit */ |
| 131 | #define _PAGE_MODIFIED _AC(0x0000000000000800,UL) /* Modified (dirty) */ | 133 | #define _PAGE_PADDR_4V _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13] */ |
| 132 | #define _PAGE_FILE _AC(0x0000000000000800,UL) /* Pagecache page */ | 134 | #define _PAGE_IE_4V _AC(0x0000000000001000,UL) /* Invert Endianness */ |
| 133 | #define _PAGE_ACCESSED _AC(0x0000000000000400,UL) /* Accessed (ref'd) */ | 135 | #define _PAGE_E_4V _AC(0x0000000000000800,UL) /* side-Effect */ |
| 134 | #define _PAGE_READ _AC(0x0000000000000200,UL) /* Readable SW Bit */ | 136 | #define _PAGE_CP_4V _AC(0x0000000000000400,UL) /* Cacheable in P-Cache */ |
| 135 | #define _PAGE_WRITE _AC(0x0000000000000100,UL) /* Writable SW Bit */ | 137 | #define _PAGE_CV_4V _AC(0x0000000000000200,UL) /* Cacheable in V-Cache */ |
| 136 | #define _PAGE_PRESENT _AC(0x0000000000000080,UL) /* Present */ | 138 | #define _PAGE_P_4V _AC(0x0000000000000100,UL) /* Privileged Page */ |
| 139 | #define _PAGE_EXEC_4V _AC(0x0000000000000080,UL) /* Executable Page */ | ||
| 140 | #define _PAGE_W_4V _AC(0x0000000000000040,UL) /* Writable */ | ||
| 141 | #define _PAGE_SOFT_4V _AC(0x0000000000000030,UL) /* Software bits */ | ||
| 142 | #define _PAGE_FILE_4V _AC(0x0000000000000020,UL) /* Pagecache page */ | ||
| 143 | #define _PAGE_PRESENT_4V _AC(0x0000000000000010,UL) /* Present */ | ||
| 144 | #define _PAGE_RESV_4V _AC(0x0000000000000008,UL) /* Reserved */ | ||
| 145 | #define _PAGE_SZ16GB_4V _AC(0x0000000000000007,UL) /* 16GB Page */ | ||
| 146 | #define _PAGE_SZ2GB_4V _AC(0x0000000000000006,UL) /* 2GB Page */ | ||
| 147 | #define _PAGE_SZ256MB_4V _AC(0x0000000000000005,UL) /* 256MB Page */ | ||
| 148 | #define _PAGE_SZ32MB_4V _AC(0x0000000000000004,UL) /* 32MB Page */ | ||
| 149 | #define _PAGE_SZ4MB_4V _AC(0x0000000000000003,UL) /* 4MB Page */ | ||
| 150 | #define _PAGE_SZ512K_4V _AC(0x0000000000000002,UL) /* 512K Page */ | ||
| 151 | #define _PAGE_SZ64K_4V _AC(0x0000000000000001,UL) /* 64K Page */ | ||
| 152 | #define _PAGE_SZ8K_4V _AC(0x0000000000000000,UL) /* 8K Page */ | ||
| 137 | 153 | ||
| 138 | #if PAGE_SHIFT == 13 | 154 | #if PAGE_SHIFT == 13 |
| 139 | #define _PAGE_SZBITS _PAGE_SZ8K | 155 | #define _PAGE_SZBITS_4U _PAGE_SZ8K_4U |
| 156 | #define _PAGE_SZBITS_4V _PAGE_SZ8K_4V | ||
| 140 | #elif PAGE_SHIFT == 16 | 157 | #elif PAGE_SHIFT == 16 |
| 141 | #define _PAGE_SZBITS _PAGE_SZ64K | 158 | #define _PAGE_SZBITS_4U _PAGE_SZ64K_4U |
| 159 | #define _PAGE_SZBITS_4V _PAGE_SZ64K_4V | ||
| 142 | #elif PAGE_SHIFT == 19 | 160 | #elif PAGE_SHIFT == 19 |
| 143 | #define _PAGE_SZBITS _PAGE_SZ512K | 161 | #define _PAGE_SZBITS_4U _PAGE_SZ512K_4U |
| 162 | #define _PAGE_SZBITS_4V _PAGE_SZ512K_4V | ||
| 144 | #elif PAGE_SHIFT == 22 | 163 | #elif PAGE_SHIFT == 22 |
| 145 | #define _PAGE_SZBITS _PAGE_SZ4MB | 164 | #define _PAGE_SZBITS_4U _PAGE_SZ4MB_4U |
| 165 | #define _PAGE_SZBITS_4V _PAGE_SZ4MB_4V | ||
| 146 | #else | 166 | #else |
| 147 | #error Wrong PAGE_SHIFT specified | 167 | #error Wrong PAGE_SHIFT specified |
| 148 | #endif | 168 | #endif |
| 149 | 169 | ||
| 150 | #if defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) | 170 | #if defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) |
| 151 | #define _PAGE_SZHUGE _PAGE_SZ4MB | 171 | #define _PAGE_SZHUGE_4U _PAGE_SZ4MB_4U |
| 172 | #define _PAGE_SZHUGE_4V _PAGE_SZ4MB_4V | ||
| 152 | #elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K) | 173 | #elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K) |
| 153 | #define _PAGE_SZHUGE _PAGE_SZ512K | 174 | #define _PAGE_SZHUGE_4U _PAGE_SZ512K_4U |
| 175 | #define _PAGE_SZHUGE_4V _PAGE_SZ512K_4V | ||
| 154 | #elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K) | 176 | #elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K) |
| 155 | #define _PAGE_SZHUGE _PAGE_SZ64K | 177 | #define _PAGE_SZHUGE_4U _PAGE_SZ64K_4U |
| 178 | #define _PAGE_SZHUGE_4V _PAGE_SZ64K_4V | ||
| 156 | #endif | 179 | #endif |
| 157 | 180 | ||
| 158 | #define _PAGE_CACHE (_PAGE_CP | _PAGE_CV) | 181 | /* These are actually filled in at boot time by sun4{u,v}_pgprot_init() */ |
| 182 | #define __P000 __pgprot(0) | ||
| 183 | #define __P001 __pgprot(0) | ||
| 184 | #define __P010 __pgprot(0) | ||
| 185 | #define __P011 __pgprot(0) | ||
| 186 | #define __P100 __pgprot(0) | ||
| 187 | #define __P101 __pgprot(0) | ||
| 188 | #define __P110 __pgprot(0) | ||
| 189 | #define __P111 __pgprot(0) | ||
| 190 | |||
| 191 | #define __S000 __pgprot(0) | ||
| 192 | #define __S001 __pgprot(0) | ||
| 193 | #define __S010 __pgprot(0) | ||
| 194 | #define __S011 __pgprot(0) | ||
| 195 | #define __S100 __pgprot(0) | ||
| 196 | #define __S101 __pgprot(0) | ||
| 197 | #define __S110 __pgprot(0) | ||
| 198 | #define __S111 __pgprot(0) | ||
| 159 | 199 | ||
| 160 | #define __DIRTY_BITS (_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W) | 200 | #ifndef __ASSEMBLY__ |
| 161 | #define __ACCESS_BITS (_PAGE_ACCESSED | _PAGE_READ | _PAGE_R) | ||
| 162 | #define __PRIV_BITS _PAGE_P | ||
| 163 | 201 | ||
| 164 | #define PAGE_NONE __pgprot (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE) | 202 | extern pte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long); |
| 165 | 203 | ||
| 166 | /* Don't set the TTE _PAGE_W bit here, else the dirty bit never gets set. */ | 204 | extern unsigned long pte_sz_bits(unsigned long size); |
| 167 | #define PAGE_SHARED __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ | ||
| 168 | __ACCESS_BITS | _PAGE_WRITE | _PAGE_EXEC) | ||
| 169 | 205 | ||
| 170 | #define PAGE_COPY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ | 206 | extern pgprot_t PAGE_KERNEL; |
| 171 | __ACCESS_BITS | _PAGE_EXEC) | 207 | extern pgprot_t PAGE_KERNEL_LOCKED; |
| 208 | extern pgprot_t PAGE_COPY; | ||
| 209 | extern pgprot_t PAGE_SHARED; | ||
| 172 | 210 | ||
| 173 | #define PAGE_READONLY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ | 211 | /* XXX This uglyness is for the atyfb driver's sparc mmap() support. XXX */ |
| 174 | __ACCESS_BITS | _PAGE_EXEC) | 212 | extern unsigned long _PAGE_IE; |
| 213 | extern unsigned long _PAGE_E; | ||
| 214 | extern unsigned long _PAGE_CACHE; | ||
| 175 | 215 | ||
| 176 | #define PAGE_KERNEL __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ | 216 | extern unsigned long pg_iobits; |
| 177 | __PRIV_BITS | \ | 217 | extern unsigned long _PAGE_ALL_SZ_BITS; |
| 178 | __ACCESS_BITS | __DIRTY_BITS | _PAGE_EXEC) | 218 | extern unsigned long _PAGE_SZBITS; |
| 179 | 219 | ||
| 180 | #define PAGE_SHARED_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ | 220 | extern struct page *mem_map_zero; |
| 181 | _PAGE_CACHE | \ | 221 | #define ZERO_PAGE(vaddr) (mem_map_zero) |
| 182 | __ACCESS_BITS | _PAGE_WRITE) | ||
| 183 | 222 | ||
| 184 | #define PAGE_COPY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ | 223 | /* PFNs are real physical page numbers. However, mem_map only begins to record |
| 185 | _PAGE_CACHE | __ACCESS_BITS) | 224 | * per-page information starting at pfn_base. This is to handle systems where |
| 225 | * the first physical page in the machine is at some huge physical address, | ||
| 226 | * such as 4GB. This is common on a partitioned E10000, for example. | ||
| 227 | */ | ||
| 228 | static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) | ||
| 229 | { | ||
| 230 | unsigned long paddr = pfn << PAGE_SHIFT; | ||
| 231 | unsigned long sz_bits; | ||
| 232 | |||
| 233 | sz_bits = 0UL; | ||
| 234 | if (_PAGE_SZBITS_4U != 0UL || _PAGE_SZBITS_4V != 0UL) { | ||
| 235 | __asm__ __volatile__( | ||
| 236 | "\n661: sethi %uhi(%1), %0\n" | ||
| 237 | " sllx %0, 32, %0\n" | ||
| 238 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 239 | " .word 661b\n" | ||
| 240 | " mov %2, %0\n" | ||
| 241 | " nop\n" | ||
| 242 | " .previous\n" | ||
| 243 | : "=r" (sz_bits) | ||
| 244 | : "i" (_PAGE_SZBITS_4U), "i" (_PAGE_SZBITS_4V)); | ||
| 245 | } | ||
| 246 | return __pte(paddr | sz_bits | pgprot_val(prot)); | ||
| 247 | } | ||
| 248 | #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) | ||
| 186 | 249 | ||
| 187 | #define PAGE_READONLY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ | 250 | /* This one can be done with two shifts. */ |
| 188 | _PAGE_CACHE | __ACCESS_BITS) | 251 | static inline unsigned long pte_pfn(pte_t pte) |
| 252 | { | ||
| 253 | unsigned long ret; | ||
| 254 | |||
| 255 | __asm__ __volatile__( | ||
| 256 | "\n661: sllx %1, %2, %0\n" | ||
| 257 | " srlx %0, %3, %0\n" | ||
| 258 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 259 | " .word 661b\n" | ||
| 260 | " sllx %1, %4, %0\n" | ||
| 261 | " srlx %0, %5, %0\n" | ||
| 262 | " .previous\n" | ||
| 263 | : "=r" (ret) | ||
| 264 | : "r" (pte_val(pte)), | ||
| 265 | "i" (21), "i" (21 + PAGE_SHIFT), | ||
| 266 | "i" (8), "i" (8 + PAGE_SHIFT)); | ||
| 267 | |||
| 268 | return ret; | ||
| 269 | } | ||
| 270 | #define pte_page(x) pfn_to_page(pte_pfn(x)) | ||
| 189 | 271 | ||
| 190 | #define _PFN_MASK _PAGE_PADDR | 272 | static inline pte_t pte_modify(pte_t pte, pgprot_t prot) |
| 273 | { | ||
| 274 | unsigned long mask, tmp; | ||
| 275 | |||
| 276 | /* SUN4U: 0x600307ffffffecb8 (negated == 0x9ffcf80000001347) | ||
| 277 | * SUN4V: 0x30ffffffffffee17 (negated == 0xcf000000000011e8) | ||
| 278 | * | ||
| 279 | * Even if we use negation tricks the result is still a 6 | ||
| 280 | * instruction sequence, so don't try to play fancy and just | ||
| 281 | * do the most straightforward implementation. | ||
| 282 | * | ||
| 283 | * Note: We encode this into 3 sun4v 2-insn patch sequences. | ||
| 284 | */ | ||
| 191 | 285 | ||
| 192 | #define pg_iobits (_PAGE_VALID | _PAGE_PRESENT | __DIRTY_BITS | \ | 286 | __asm__ __volatile__( |
| 193 | __ACCESS_BITS | _PAGE_E) | 287 | "\n661: sethi %%uhi(%2), %1\n" |
| 288 | " sethi %%hi(%2), %0\n" | ||
| 289 | "\n662: or %1, %%ulo(%2), %1\n" | ||
| 290 | " or %0, %%lo(%2), %0\n" | ||
| 291 | "\n663: sllx %1, 32, %1\n" | ||
| 292 | " or %0, %1, %0\n" | ||
| 293 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 294 | " .word 661b\n" | ||
| 295 | " sethi %%uhi(%3), %1\n" | ||
| 296 | " sethi %%hi(%3), %0\n" | ||
| 297 | " .word 662b\n" | ||
| 298 | " or %1, %%ulo(%3), %1\n" | ||
| 299 | " or %0, %%lo(%3), %0\n" | ||
| 300 | " .word 663b\n" | ||
| 301 | " sllx %1, 32, %1\n" | ||
| 302 | " or %0, %1, %0\n" | ||
| 303 | " .previous\n" | ||
| 304 | : "=r" (mask), "=r" (tmp) | ||
| 305 | : "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U | | ||
| 306 | _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | _PAGE_PRESENT_4U | | ||
| 307 | _PAGE_SZBITS_4U), | ||
| 308 | "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V | | ||
| 309 | _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V | | ||
| 310 | _PAGE_SZBITS_4V)); | ||
| 311 | |||
| 312 | return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask)); | ||
| 313 | } | ||
| 194 | 314 | ||
| 195 | #define __P000 PAGE_NONE | 315 | static inline pte_t pgoff_to_pte(unsigned long off) |
| 196 | #define __P001 PAGE_READONLY_NOEXEC | 316 | { |
| 197 | #define __P010 PAGE_COPY_NOEXEC | 317 | off <<= PAGE_SHIFT; |
| 198 | #define __P011 PAGE_COPY_NOEXEC | 318 | |
| 199 | #define __P100 PAGE_READONLY | 319 | __asm__ __volatile__( |
| 200 | #define __P101 PAGE_READONLY | 320 | "\n661: or %0, %2, %0\n" |
| 201 | #define __P110 PAGE_COPY | 321 | " .section .sun4v_1insn_patch, \"ax\"\n" |
| 202 | #define __P111 PAGE_COPY | 322 | " .word 661b\n" |
| 323 | " or %0, %3, %0\n" | ||
| 324 | " .previous\n" | ||
| 325 | : "=r" (off) | ||
| 326 | : "0" (off), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V)); | ||
| 327 | |||
| 328 | return __pte(off); | ||
| 329 | } | ||
| 203 | 330 | ||
| 204 | #define __S000 PAGE_NONE | 331 | static inline pgprot_t pgprot_noncached(pgprot_t prot) |
| 205 | #define __S001 PAGE_READONLY_NOEXEC | 332 | { |
| 206 | #define __S010 PAGE_SHARED_NOEXEC | 333 | unsigned long val = pgprot_val(prot); |
| 207 | #define __S011 PAGE_SHARED_NOEXEC | 334 | |
| 208 | #define __S100 PAGE_READONLY | 335 | __asm__ __volatile__( |
| 209 | #define __S101 PAGE_READONLY | 336 | "\n661: andn %0, %2, %0\n" |
| 210 | #define __S110 PAGE_SHARED | 337 | " or %0, %3, %0\n" |
| 211 | #define __S111 PAGE_SHARED | 338 | " .section .sun4v_2insn_patch, \"ax\"\n" |
| 339 | " .word 661b\n" | ||
| 340 | " andn %0, %4, %0\n" | ||
| 341 | " or %0, %3, %0\n" | ||
| 342 | " .previous\n" | ||
| 343 | : "=r" (val) | ||
| 344 | : "0" (val), "i" (_PAGE_CP_4U | _PAGE_CV_4U), "i" (_PAGE_E_4U), | ||
| 345 | "i" (_PAGE_CP_4V | _PAGE_CV_4V), "i" (_PAGE_E_4V)); | ||
| 346 | |||
| 347 | return __pgprot(val); | ||
| 348 | } | ||
| 349 | /* Various pieces of code check for platform support by ifdef testing | ||
| 350 | * on "pgprot_noncached". That's broken and should be fixed, but for | ||
| 351 | * now... | ||
| 352 | */ | ||
| 353 | #define pgprot_noncached pgprot_noncached | ||
| 212 | 354 | ||
| 213 | #ifndef __ASSEMBLY__ | 355 | #ifdef CONFIG_HUGETLB_PAGE |
| 356 | static inline pte_t pte_mkhuge(pte_t pte) | ||
| 357 | { | ||
| 358 | unsigned long mask; | ||
| 359 | |||
| 360 | __asm__ __volatile__( | ||
| 361 | "\n661: sethi %%uhi(%1), %0\n" | ||
| 362 | " sllx %0, 32, %0\n" | ||
| 363 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 364 | " .word 661b\n" | ||
| 365 | " mov %2, %0\n" | ||
| 366 | " nop\n" | ||
| 367 | " .previous\n" | ||
| 368 | : "=r" (mask) | ||
| 369 | : "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V)); | ||
| 370 | |||
| 371 | return __pte(pte_val(pte) | mask); | ||
| 372 | } | ||
| 373 | #endif | ||
| 214 | 374 | ||
| 215 | extern unsigned long phys_base; | 375 | static inline pte_t pte_mkdirty(pte_t pte) |
| 216 | extern unsigned long pfn_base; | 376 | { |
| 377 | unsigned long val = pte_val(pte), tmp; | ||
| 378 | |||
| 379 | __asm__ __volatile__( | ||
| 380 | "\n661: or %0, %3, %0\n" | ||
| 381 | " nop\n" | ||
| 382 | "\n662: nop\n" | ||
| 383 | " nop\n" | ||
| 384 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 385 | " .word 661b\n" | ||
| 386 | " sethi %%uhi(%4), %1\n" | ||
| 387 | " sllx %1, 32, %1\n" | ||
| 388 | " .word 662b\n" | ||
| 389 | " or %1, %%lo(%4), %1\n" | ||
| 390 | " or %0, %1, %0\n" | ||
| 391 | " .previous\n" | ||
| 392 | : "=r" (val), "=r" (tmp) | ||
| 393 | : "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U), | ||
| 394 | "i" (_PAGE_MODIFIED_4V | _PAGE_W_4V)); | ||
| 395 | |||
| 396 | return __pte(val); | ||
| 397 | } | ||
| 217 | 398 | ||
| 218 | extern struct page *mem_map_zero; | 399 | static inline pte_t pte_mkclean(pte_t pte) |
| 219 | #define ZERO_PAGE(vaddr) (mem_map_zero) | 400 | { |
| 401 | unsigned long val = pte_val(pte), tmp; | ||
| 402 | |||
| 403 | __asm__ __volatile__( | ||
| 404 | "\n661: andn %0, %3, %0\n" | ||
| 405 | " nop\n" | ||
| 406 | "\n662: nop\n" | ||
| 407 | " nop\n" | ||
| 408 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 409 | " .word 661b\n" | ||
| 410 | " sethi %%uhi(%4), %1\n" | ||
| 411 | " sllx %1, 32, %1\n" | ||
| 412 | " .word 662b\n" | ||
| 413 | " or %1, %%lo(%4), %1\n" | ||
| 414 | " andn %0, %1, %0\n" | ||
| 415 | " .previous\n" | ||
| 416 | : "=r" (val), "=r" (tmp) | ||
| 417 | : "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U), | ||
| 418 | "i" (_PAGE_MODIFIED_4V | _PAGE_W_4V)); | ||
| 419 | |||
| 420 | return __pte(val); | ||
| 421 | } | ||
| 220 | 422 | ||
| 221 | /* PFNs are real physical page numbers. However, mem_map only begins to record | 423 | static inline pte_t pte_mkwrite(pte_t pte) |
| 222 | * per-page information starting at pfn_base. This is to handle systems where | 424 | { |
| 223 | * the first physical page in the machine is at some huge physical address, | 425 | unsigned long val = pte_val(pte), mask; |
| 224 | * such as 4GB. This is common on a partitioned E10000, for example. | 426 | |
| 225 | */ | 427 | __asm__ __volatile__( |
| 428 | "\n661: mov %1, %0\n" | ||
| 429 | " nop\n" | ||
| 430 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 431 | " .word 661b\n" | ||
| 432 | " sethi %%uhi(%2), %0\n" | ||
| 433 | " sllx %0, 32, %0\n" | ||
| 434 | " .previous\n" | ||
| 435 | : "=r" (mask) | ||
| 436 | : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); | ||
| 437 | |||
| 438 | return __pte(val | mask); | ||
| 439 | } | ||
| 226 | 440 | ||
| 227 | #define pfn_pte(pfn, prot) \ | 441 | static inline pte_t pte_wrprotect(pte_t pte) |
| 228 | __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot) | _PAGE_SZBITS) | 442 | { |
| 229 | #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) | 443 | unsigned long val = pte_val(pte), tmp; |
| 444 | |||
| 445 | __asm__ __volatile__( | ||
| 446 | "\n661: andn %0, %3, %0\n" | ||
| 447 | " nop\n" | ||
| 448 | "\n662: nop\n" | ||
| 449 | " nop\n" | ||
| 450 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 451 | " .word 661b\n" | ||
| 452 | " sethi %%uhi(%4), %1\n" | ||
| 453 | " sllx %1, 32, %1\n" | ||
| 454 | " .word 662b\n" | ||
| 455 | " or %1, %%lo(%4), %1\n" | ||
| 456 | " andn %0, %1, %0\n" | ||
| 457 | " .previous\n" | ||
| 458 | : "=r" (val), "=r" (tmp) | ||
| 459 | : "0" (val), "i" (_PAGE_WRITE_4U | _PAGE_W_4U), | ||
| 460 | "i" (_PAGE_WRITE_4V | _PAGE_W_4V)); | ||
| 461 | |||
| 462 | return __pte(val); | ||
| 463 | } | ||
| 464 | |||
| 465 | static inline pte_t pte_mkold(pte_t pte) | ||
| 466 | { | ||
| 467 | unsigned long mask; | ||
| 468 | |||
| 469 | __asm__ __volatile__( | ||
| 470 | "\n661: mov %1, %0\n" | ||
| 471 | " nop\n" | ||
| 472 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 473 | " .word 661b\n" | ||
| 474 | " sethi %%uhi(%2), %0\n" | ||
| 475 | " sllx %0, 32, %0\n" | ||
| 476 | " .previous\n" | ||
| 477 | : "=r" (mask) | ||
| 478 | : "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V)); | ||
| 479 | |||
| 480 | mask |= _PAGE_R; | ||
| 481 | |||
| 482 | return __pte(pte_val(pte) & ~mask); | ||
| 483 | } | ||
| 484 | |||
| 485 | static inline pte_t pte_mkyoung(pte_t pte) | ||
| 486 | { | ||
| 487 | unsigned long mask; | ||
| 488 | |||
| 489 | __asm__ __volatile__( | ||
| 490 | "\n661: mov %1, %0\n" | ||
| 491 | " nop\n" | ||
| 492 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 493 | " .word 661b\n" | ||
| 494 | " sethi %%uhi(%2), %0\n" | ||
| 495 | " sllx %0, 32, %0\n" | ||
| 496 | " .previous\n" | ||
| 497 | : "=r" (mask) | ||
| 498 | : "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V)); | ||
| 499 | |||
| 500 | mask |= _PAGE_R; | ||
| 501 | |||
| 502 | return __pte(pte_val(pte) | mask); | ||
| 503 | } | ||
| 230 | 504 | ||
| 231 | #define pte_pfn(x) ((pte_val(x) & _PAGE_PADDR)>>PAGE_SHIFT) | 505 | static inline unsigned long pte_young(pte_t pte) |
| 232 | #define pte_page(x) pfn_to_page(pte_pfn(x)) | 506 | { |
| 507 | unsigned long mask; | ||
| 508 | |||
| 509 | __asm__ __volatile__( | ||
| 510 | "\n661: mov %1, %0\n" | ||
| 511 | " nop\n" | ||
| 512 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 513 | " .word 661b\n" | ||
| 514 | " sethi %%uhi(%2), %0\n" | ||
| 515 | " sllx %0, 32, %0\n" | ||
| 516 | " .previous\n" | ||
| 517 | : "=r" (mask) | ||
| 518 | : "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V)); | ||
| 519 | |||
| 520 | return (pte_val(pte) & mask); | ||
| 521 | } | ||
| 522 | |||
| 523 | static inline unsigned long pte_dirty(pte_t pte) | ||
| 524 | { | ||
| 525 | unsigned long mask; | ||
| 526 | |||
| 527 | __asm__ __volatile__( | ||
| 528 | "\n661: mov %1, %0\n" | ||
| 529 | " nop\n" | ||
| 530 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 531 | " .word 661b\n" | ||
| 532 | " sethi %%uhi(%2), %0\n" | ||
| 533 | " sllx %0, 32, %0\n" | ||
| 534 | " .previous\n" | ||
| 535 | : "=r" (mask) | ||
| 536 | : "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V)); | ||
| 537 | |||
| 538 | return (pte_val(pte) & mask); | ||
| 539 | } | ||
| 233 | 540 | ||
| 234 | static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot) | 541 | static inline unsigned long pte_write(pte_t pte) |
| 235 | { | 542 | { |
| 236 | pte_t __pte; | 543 | unsigned long mask; |
| 237 | const unsigned long preserve_mask = (_PFN_MASK | | 544 | |
| 238 | _PAGE_MODIFIED | _PAGE_ACCESSED | | 545 | __asm__ __volatile__( |
| 239 | _PAGE_CACHE | _PAGE_E | | 546 | "\n661: mov %1, %0\n" |
| 240 | _PAGE_PRESENT | _PAGE_SZBITS); | 547 | " nop\n" |
| 548 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 549 | " .word 661b\n" | ||
| 550 | " sethi %%uhi(%2), %0\n" | ||
| 551 | " sllx %0, 32, %0\n" | ||
| 552 | " .previous\n" | ||
| 553 | : "=r" (mask) | ||
| 554 | : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); | ||
| 555 | |||
| 556 | return (pte_val(pte) & mask); | ||
| 557 | } | ||
| 241 | 558 | ||
| 242 | pte_val(__pte) = (pte_val(orig_pte) & preserve_mask) | | 559 | static inline unsigned long pte_exec(pte_t pte) |
| 243 | (pgprot_val(new_prot) & ~preserve_mask); | 560 | { |
| 561 | unsigned long mask; | ||
| 562 | |||
| 563 | __asm__ __volatile__( | ||
| 564 | "\n661: sethi %%hi(%1), %0\n" | ||
| 565 | " .section .sun4v_1insn_patch, \"ax\"\n" | ||
| 566 | " .word 661b\n" | ||
| 567 | " mov %2, %0\n" | ||
| 568 | " .previous\n" | ||
| 569 | : "=r" (mask) | ||
| 570 | : "i" (_PAGE_EXEC_4U), "i" (_PAGE_EXEC_4V)); | ||
| 571 | |||
| 572 | return (pte_val(pte) & mask); | ||
| 573 | } | ||
| 244 | 574 | ||
| 245 | return __pte; | 575 | static inline unsigned long pte_read(pte_t pte) |
| 576 | { | ||
| 577 | unsigned long mask; | ||
| 578 | |||
| 579 | __asm__ __volatile__( | ||
| 580 | "\n661: mov %1, %0\n" | ||
| 581 | " nop\n" | ||
| 582 | " .section .sun4v_2insn_patch, \"ax\"\n" | ||
| 583 | " .word 661b\n" | ||
| 584 | " sethi %%uhi(%2), %0\n" | ||
| 585 | " sllx %0, 32, %0\n" | ||
| 586 | " .previous\n" | ||
| 587 | : "=r" (mask) | ||
| 588 | : "i" (_PAGE_READ_4U), "i" (_PAGE_READ_4V)); | ||
| 589 | |||
| 590 | return (pte_val(pte) & mask); | ||
| 246 | } | 591 | } |
| 592 | |||
| 593 | static inline unsigned long pte_file(pte_t pte) | ||
| 594 | { | ||
| 595 | unsigned long val = pte_val(pte); | ||
| 596 | |||
| 597 | __asm__ __volatile__( | ||
| 598 | "\n661: and %0, %2, %0\n" | ||
| 599 | " .section .sun4v_1insn_patch, \"ax\"\n" | ||
| 600 | " .word 661b\n" | ||
| 601 | " and %0, %3, %0\n" | ||
| 602 | " .previous\n" | ||
| 603 | : "=r" (val) | ||
| 604 | : "0" (val), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V)); | ||
| 605 | |||
| 606 | return val; | ||
| 607 | } | ||
| 608 | |||
| 609 | static inline unsigned long pte_present(pte_t pte) | ||
| 610 | { | ||
| 611 | unsigned long val = pte_val(pte); | ||
| 612 | |||
| 613 | __asm__ __volatile__( | ||
| 614 | "\n661: and %0, %2, %0\n" | ||
| 615 | " .section .sun4v_1insn_patch, \"ax\"\n" | ||
| 616 | " .word 661b\n" | ||
| 617 | " and %0, %3, %0\n" | ||
| 618 | " .previous\n" | ||
| 619 | : "=r" (val) | ||
| 620 | : "0" (val), "i" (_PAGE_PRESENT_4U), "i" (_PAGE_PRESENT_4V)); | ||
| 621 | |||
| 622 | return val; | ||
| 623 | } | ||
| 624 | |||
| 247 | #define pmd_set(pmdp, ptep) \ | 625 | #define pmd_set(pmdp, ptep) \ |
| 248 | (pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL)) | 626 | (pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL)) |
| 249 | #define pud_set(pudp, pmdp) \ | 627 | #define pud_set(pudp, pmdp) \ |
| @@ -253,8 +631,6 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot) | |||
| 253 | #define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd)) | 631 | #define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd)) |
| 254 | #define pud_page(pud) \ | 632 | #define pud_page(pud) \ |
| 255 | ((unsigned long) __va((((unsigned long)pud_val(pud))<<11UL))) | 633 | ((unsigned long) __va((((unsigned long)pud_val(pud))<<11UL))) |
| 256 | #define pte_none(pte) (!pte_val(pte)) | ||
| 257 | #define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) | ||
| 258 | #define pmd_none(pmd) (!pmd_val(pmd)) | 634 | #define pmd_none(pmd) (!pmd_val(pmd)) |
| 259 | #define pmd_bad(pmd) (0) | 635 | #define pmd_bad(pmd) (0) |
| 260 | #define pmd_present(pmd) (pmd_val(pmd) != 0U) | 636 | #define pmd_present(pmd) (pmd_val(pmd) != 0U) |
| @@ -264,30 +640,8 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot) | |||
| 264 | #define pud_present(pud) (pud_val(pud) != 0U) | 640 | #define pud_present(pud) (pud_val(pud) != 0U) |
| 265 | #define pud_clear(pudp) (pud_val(*(pudp)) = 0U) | 641 | #define pud_clear(pudp) (pud_val(*(pudp)) = 0U) |
| 266 | 642 | ||
| 267 | /* The following only work if pte_present() is true. | 643 | /* Same in both SUN4V and SUN4U. */ |
| 268 | * Undefined behaviour if not.. | 644 | #define pte_none(pte) (!pte_val(pte)) |
| 269 | */ | ||
| 270 | #define pte_read(pte) (pte_val(pte) & _PAGE_READ) | ||
| 271 | #define pte_exec(pte) (pte_val(pte) & _PAGE_EXEC) | ||
| 272 | #define pte_write(pte) (pte_val(pte) & _PAGE_WRITE) | ||
| 273 | #define pte_dirty(pte) (pte_val(pte) & _PAGE_MODIFIED) | ||
| 274 | #define pte_young(pte) (pte_val(pte) & _PAGE_ACCESSED) | ||
| 275 | #define pte_wrprotect(pte) (__pte(pte_val(pte) & ~(_PAGE_WRITE|_PAGE_W))) | ||
| 276 | #define pte_rdprotect(pte) \ | ||
| 277 | (__pte(((pte_val(pte)<<1UL)>>1UL) & ~_PAGE_READ)) | ||
| 278 | #define pte_mkclean(pte) \ | ||
| 279 | (__pte(pte_val(pte) & ~(_PAGE_MODIFIED|_PAGE_W))) | ||
| 280 | #define pte_mkold(pte) \ | ||
| 281 | (__pte(((pte_val(pte)<<1UL)>>1UL) & ~_PAGE_ACCESSED)) | ||
| 282 | |||
| 283 | /* Permanent address of a page. */ | ||
| 284 | #define __page_address(page) page_address(page) | ||
| 285 | |||
| 286 | /* Be very careful when you change these three, they are delicate. */ | ||
| 287 | #define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R)) | ||
| 288 | #define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_WRITE)) | ||
| 289 | #define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W)) | ||
| 290 | #define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_SZHUGE)) | ||
| 291 | 645 | ||
| 292 | /* to find an entry in a page-table-directory. */ | 646 | /* to find an entry in a page-table-directory. */ |
| 293 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) | 647 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) |
| @@ -296,11 +650,6 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot) | |||
| 296 | /* to find an entry in a kernel page-table-directory */ | 650 | /* to find an entry in a kernel page-table-directory */ |
| 297 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | 651 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) |
| 298 | 652 | ||
| 299 | /* extract the pgd cache used for optimizing the tlb miss | ||
| 300 | * slow path when executing 32-bit compat processes | ||
| 301 | */ | ||
| 302 | #define get_pgd_cache(pgd) ((unsigned long) pgd_val(*pgd) << 11) | ||
| 303 | |||
| 304 | /* Find an entry in the second-level page table.. */ | 653 | /* Find an entry in the second-level page table.. */ |
| 305 | #define pmd_offset(pudp, address) \ | 654 | #define pmd_offset(pudp, address) \ |
| 306 | ((pmd_t *) pud_page(*(pudp)) + \ | 655 | ((pmd_t *) pud_page(*(pudp)) + \ |
| @@ -327,6 +676,9 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p | |||
| 327 | 676 | ||
| 328 | /* It is more efficient to let flush_tlb_kernel_range() | 677 | /* It is more efficient to let flush_tlb_kernel_range() |
| 329 | * handle init_mm tlb flushes. | 678 | * handle init_mm tlb flushes. |
| 679 | * | ||
| 680 | * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U | ||
| 681 | * and SUN4V pte layout, so this inline test is fine. | ||
| 330 | */ | 682 | */ |
| 331 | if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID)) | 683 | if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID)) |
| 332 | tlb_batch_add(mm, addr, ptep, orig); | 684 | tlb_batch_add(mm, addr, ptep, orig); |
| @@ -361,42 +713,23 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); | |||
| 361 | #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) | 713 | #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) |
| 362 | 714 | ||
| 363 | /* File offset in PTE support. */ | 715 | /* File offset in PTE support. */ |
| 364 | #define pte_file(pte) (pte_val(pte) & _PAGE_FILE) | 716 | extern unsigned long pte_file(pte_t); |
| 365 | #define pte_to_pgoff(pte) (pte_val(pte) >> PAGE_SHIFT) | 717 | #define pte_to_pgoff(pte) (pte_val(pte) >> PAGE_SHIFT) |
| 366 | #define pgoff_to_pte(off) (__pte(((off) << PAGE_SHIFT) | _PAGE_FILE)) | 718 | extern pte_t pgoff_to_pte(unsigned long); |
| 367 | #define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL) | 719 | #define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL) |
| 368 | 720 | ||
| 369 | extern unsigned long prom_virt_to_phys(unsigned long, int *); | 721 | extern unsigned long prom_virt_to_phys(unsigned long, int *); |
| 370 | 722 | ||
| 371 | static __inline__ unsigned long | 723 | extern unsigned long sun4u_get_pte(unsigned long); |
| 372 | sun4u_get_pte (unsigned long addr) | ||
| 373 | { | ||
| 374 | pgd_t *pgdp; | ||
| 375 | pud_t *pudp; | ||
| 376 | pmd_t *pmdp; | ||
| 377 | pte_t *ptep; | ||
| 378 | |||
| 379 | if (addr >= PAGE_OFFSET) | ||
| 380 | return addr & _PAGE_PADDR; | ||
| 381 | if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) | ||
| 382 | return prom_virt_to_phys(addr, NULL); | ||
| 383 | pgdp = pgd_offset_k(addr); | ||
| 384 | pudp = pud_offset(pgdp, addr); | ||
| 385 | pmdp = pmd_offset(pudp, addr); | ||
| 386 | ptep = pte_offset_kernel(pmdp, addr); | ||
| 387 | return pte_val(*ptep) & _PAGE_PADDR; | ||
| 388 | } | ||
| 389 | 724 | ||
| 390 | static __inline__ unsigned long | 725 | static inline unsigned long __get_phys(unsigned long addr) |
| 391 | __get_phys (unsigned long addr) | ||
| 392 | { | 726 | { |
| 393 | return sun4u_get_pte (addr); | 727 | return sun4u_get_pte(addr); |
| 394 | } | 728 | } |
| 395 | 729 | ||
| 396 | static __inline__ int | 730 | static inline int __get_iospace(unsigned long addr) |
| 397 | __get_iospace (unsigned long addr) | ||
| 398 | { | 731 | { |
| 399 | return ((sun4u_get_pte (addr) & 0xf0000000) >> 28); | 732 | return ((sun4u_get_pte(addr) & 0xf0000000) >> 28); |
| 400 | } | 733 | } |
| 401 | 734 | ||
| 402 | extern unsigned long *sparc64_valid_addr_bitmap; | 735 | extern unsigned long *sparc64_valid_addr_bitmap; |
| @@ -409,11 +742,6 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, | |||
| 409 | unsigned long pfn, | 742 | unsigned long pfn, |
| 410 | unsigned long size, pgprot_t prot); | 743 | unsigned long size, pgprot_t prot); |
| 411 | 744 | ||
| 412 | /* Clear virtual and physical cachability, set side-effect bit. */ | ||
| 413 | #define pgprot_noncached(prot) \ | ||
| 414 | (__pgprot((pgprot_val(prot) & ~(_PAGE_CP | _PAGE_CV)) | \ | ||
| 415 | _PAGE_E)) | ||
| 416 | |||
| 417 | /* | 745 | /* |
| 418 | * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in | 746 | * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in |
| 419 | * its high 4 bits. These macros/functions put it there or get it from there. | 747 | * its high 4 bits. These macros/functions put it there or get it from there. |
| @@ -424,8 +752,11 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, | |||
| 424 | 752 | ||
| 425 | #include <asm-generic/pgtable.h> | 753 | #include <asm-generic/pgtable.h> |
| 426 | 754 | ||
| 427 | /* We provide our own get_unmapped_area to cope with VA holes for userland */ | 755 | /* We provide our own get_unmapped_area to cope with VA holes and |
| 756 | * SHM area cache aliasing for userland. | ||
| 757 | */ | ||
| 428 | #define HAVE_ARCH_UNMAPPED_AREA | 758 | #define HAVE_ARCH_UNMAPPED_AREA |
| 759 | #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN | ||
| 429 | 760 | ||
| 430 | /* We provide a special get_unmapped_area for framebuffer mmaps to try and use | 761 | /* We provide a special get_unmapped_area for framebuffer mmaps to try and use |
| 431 | * the largest alignment possible such that larget PTEs can be used. | 762 | * the largest alignment possible such that larget PTEs can be used. |
| @@ -435,12 +766,9 @@ extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long, | |||
| 435 | unsigned long); | 766 | unsigned long); |
| 436 | #define HAVE_ARCH_FB_UNMAPPED_AREA | 767 | #define HAVE_ARCH_FB_UNMAPPED_AREA |
| 437 | 768 | ||
| 438 | /* | 769 | extern void pgtable_cache_init(void); |
| 439 | * No page table caches to initialise | 770 | extern void sun4v_register_fault_status(void); |
| 440 | */ | 771 | extern void sun4v_ktsb_register(void); |
| 441 | #define pgtable_cache_init() do { } while (0) | ||
| 442 | |||
| 443 | extern void check_pgt_cache(void); | ||
| 444 | 772 | ||
| 445 | #endif /* !(__ASSEMBLY__) */ | 773 | #endif /* !(__ASSEMBLY__) */ |
| 446 | 774 | ||
diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h index 8f87750c3517..79f827eb3f5d 100644 --- a/include/asm-sparc64/pil.h +++ b/include/asm-sparc64/pil.h | |||
| @@ -16,11 +16,13 @@ | |||
| 16 | #define PIL_SMP_CALL_FUNC 1 | 16 | #define PIL_SMP_CALL_FUNC 1 |
| 17 | #define PIL_SMP_RECEIVE_SIGNAL 2 | 17 | #define PIL_SMP_RECEIVE_SIGNAL 2 |
| 18 | #define PIL_SMP_CAPTURE 3 | 18 | #define PIL_SMP_CAPTURE 3 |
| 19 | #define PIL_SMP_CTX_NEW_VERSION 4 | ||
| 19 | 20 | ||
| 20 | #ifndef __ASSEMBLY__ | 21 | #ifndef __ASSEMBLY__ |
| 21 | #define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \ | 22 | #define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \ |
| 22 | (PIL) == PIL_SMP_RECEIVE_SIGNAL || \ | 23 | (PIL) == PIL_SMP_RECEIVE_SIGNAL || \ |
| 23 | (PIL) == PIL_SMP_CAPTURE) | 24 | (PIL) == PIL_SMP_CAPTURE || \ |
| 25 | (PIL) == PIL_SMP_CTX_NEW_VERSION) | ||
| 24 | #endif | 26 | #endif |
| 25 | 27 | ||
| 26 | #endif /* !(_SPARC64_PIL_H) */ | 28 | #endif /* !(_SPARC64_PIL_H) */ |
diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h index cd8d9b4c8658..c6896b88283e 100644 --- a/include/asm-sparc64/processor.h +++ b/include/asm-sparc64/processor.h | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | * User lives in his very own context, and cannot reference us. Note | 28 | * User lives in his very own context, and cannot reference us. Note |
| 29 | * that TASK_SIZE is a misnomer, it really gives maximum user virtual | 29 | * that TASK_SIZE is a misnomer, it really gives maximum user virtual |
| 30 | * address that the kernel will allocate out. | 30 | * address that the kernel will allocate out. |
| 31 | * | ||
| 32 | * XXX No longer using virtual page tables, kill this upper limit... | ||
| 31 | */ | 33 | */ |
| 32 | #define VA_BITS 44 | 34 | #define VA_BITS 44 |
| 33 | #ifndef __ASSEMBLY__ | 35 | #ifndef __ASSEMBLY__ |
| @@ -37,18 +39,6 @@ | |||
| 37 | #endif | 39 | #endif |
| 38 | #define TASK_SIZE ((unsigned long)-VPTE_SIZE) | 40 | #define TASK_SIZE ((unsigned long)-VPTE_SIZE) |
| 39 | 41 | ||
| 40 | /* | ||
| 41 | * The vpte base must be able to hold the entire vpte, half | ||
| 42 | * of which lives above, and half below, the base. And it | ||
| 43 | * is placed as close to the highest address range as possible. | ||
| 44 | */ | ||
| 45 | #define VPTE_BASE_SPITFIRE (-(VPTE_SIZE/2)) | ||
| 46 | #if 1 | ||
| 47 | #define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE | ||
| 48 | #else | ||
| 49 | #define VPTE_BASE_CHEETAH 0xffe0000000000000 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #ifndef __ASSEMBLY__ | 42 | #ifndef __ASSEMBLY__ |
| 53 | 43 | ||
| 54 | typedef struct { | 44 | typedef struct { |
| @@ -101,7 +91,8 @@ extern unsigned long thread_saved_pc(struct task_struct *); | |||
| 101 | /* Do necessary setup to start up a newly executed thread. */ | 91 | /* Do necessary setup to start up a newly executed thread. */ |
| 102 | #define start_thread(regs, pc, sp) \ | 92 | #define start_thread(regs, pc, sp) \ |
| 103 | do { \ | 93 | do { \ |
| 104 | regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (ASI_PNF << 24); \ | 94 | unsigned long __asi = ASI_PNF; \ |
| 95 | regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (__asi << 24UL); \ | ||
| 105 | regs->tpc = ((pc & (~3)) - 4); \ | 96 | regs->tpc = ((pc & (~3)) - 4); \ |
| 106 | regs->tnpc = regs->tpc + 4; \ | 97 | regs->tnpc = regs->tpc + 4; \ |
| 107 | regs->y = 0; \ | 98 | regs->y = 0; \ |
| @@ -138,10 +129,10 @@ do { \ | |||
| 138 | 129 | ||
| 139 | #define start_thread32(regs, pc, sp) \ | 130 | #define start_thread32(regs, pc, sp) \ |
| 140 | do { \ | 131 | do { \ |
| 132 | unsigned long __asi = ASI_PNF; \ | ||
| 141 | pc &= 0x00000000ffffffffUL; \ | 133 | pc &= 0x00000000ffffffffUL; \ |
| 142 | sp &= 0x00000000ffffffffUL; \ | 134 | sp &= 0x00000000ffffffffUL; \ |
| 143 | \ | 135 | regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM) | (__asi << 24UL); \ |
| 144 | regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM); \ | ||
| 145 | regs->tpc = ((pc & (~3)) - 4); \ | 136 | regs->tpc = ((pc & (~3)) - 4); \ |
| 146 | regs->tnpc = regs->tpc + 4; \ | 137 | regs->tnpc = regs->tpc + 4; \ |
| 147 | regs->y = 0; \ | 138 | regs->y = 0; \ |
| @@ -226,6 +217,8 @@ static inline void prefetchw(const void *x) | |||
| 226 | 217 | ||
| 227 | #define spin_lock_prefetch(x) prefetchw(x) | 218 | #define spin_lock_prefetch(x) prefetchw(x) |
| 228 | 219 | ||
| 220 | #define HAVE_ARCH_PICK_MMAP_LAYOUT | ||
| 221 | |||
| 229 | #endif /* !(__ASSEMBLY__) */ | 222 | #endif /* !(__ASSEMBLY__) */ |
| 230 | 223 | ||
| 231 | #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ | 224 | #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ |
diff --git a/include/asm-sparc64/pstate.h b/include/asm-sparc64/pstate.h index 29fb74aa805d..49a7924a89ab 100644 --- a/include/asm-sparc64/pstate.h +++ b/include/asm-sparc64/pstate.h | |||
| @@ -28,11 +28,12 @@ | |||
| 28 | 28 | ||
| 29 | /* The V9 TSTATE Register (with SpitFire and Linux extensions). | 29 | /* The V9 TSTATE Register (with SpitFire and Linux extensions). |
| 30 | * | 30 | * |
| 31 | * --------------------------------------------------------------- | 31 | * --------------------------------------------------------------------- |
| 32 | * | Resv | CCR | ASI | %pil | PSTATE | Resv | CWP | | 32 | * | Resv | GL | CCR | ASI | %pil | PSTATE | Resv | CWP | |
| 33 | * --------------------------------------------------------------- | 33 | * --------------------------------------------------------------------- |
| 34 | * 63 40 39 32 31 24 23 20 19 8 7 5 4 0 | 34 | * 63 43 42 40 39 32 31 24 23 20 19 8 7 5 4 0 |
| 35 | */ | 35 | */ |
| 36 | #define TSTATE_GL _AC(0x0000070000000000,UL) /* Global reg level */ | ||
| 36 | #define TSTATE_CCR _AC(0x000000ff00000000,UL) /* Condition Codes. */ | 37 | #define TSTATE_CCR _AC(0x000000ff00000000,UL) /* Condition Codes. */ |
| 37 | #define TSTATE_XCC _AC(0x000000f000000000,UL) /* Condition Codes. */ | 38 | #define TSTATE_XCC _AC(0x000000f000000000,UL) /* Condition Codes. */ |
| 38 | #define TSTATE_XNEG _AC(0x0000008000000000,UL) /* %xcc Negative. */ | 39 | #define TSTATE_XNEG _AC(0x0000008000000000,UL) /* %xcc Negative. */ |
diff --git a/include/asm-sparc64/scratchpad.h b/include/asm-sparc64/scratchpad.h new file mode 100644 index 000000000000..5e8b01fb3343 --- /dev/null +++ b/include/asm-sparc64/scratchpad.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef _SPARC64_SCRATCHPAD_H | ||
| 2 | #define _SPARC64_SCRATCHPAD_H | ||
| 3 | |||
| 4 | /* Sun4v scratchpad registers, accessed via ASI_SCRATCHPAD. */ | ||
| 5 | |||
| 6 | #define SCRATCHPAD_MMU_MISS 0x00 /* Shared with OBP - set by OBP */ | ||
| 7 | #define SCRATCHPAD_CPUID 0x08 /* Shared with OBP - set by hypervisor */ | ||
| 8 | #define SCRATCHPAD_UTSBREG1 0x10 | ||
| 9 | #define SCRATCHPAD_UTSBREG2 0x18 | ||
| 10 | /* 0x20 and 0x28, hypervisor only... */ | ||
| 11 | #define SCRATCHPAD_UNUSED1 0x30 | ||
| 12 | #define SCRATCHPAD_UNUSED2 0x38 /* Reserved for OBP */ | ||
| 13 | |||
| 14 | #endif /* !(_SPARC64_SCRATCHPAD_H) */ | ||
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index 473edb2603ec..89d86ecaab24 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h | |||
| @@ -33,37 +33,13 @@ | |||
| 33 | extern cpumask_t phys_cpu_present_map; | 33 | extern cpumask_t phys_cpu_present_map; |
| 34 | #define cpu_possible_map phys_cpu_present_map | 34 | #define cpu_possible_map phys_cpu_present_map |
| 35 | 35 | ||
| 36 | extern cpumask_t cpu_sibling_map[NR_CPUS]; | ||
| 37 | |||
| 36 | /* | 38 | /* |
| 37 | * General functions that each host system must provide. | 39 | * General functions that each host system must provide. |
| 38 | */ | 40 | */ |
| 39 | 41 | ||
| 40 | static __inline__ int hard_smp_processor_id(void) | 42 | extern int hard_smp_processor_id(void); |
| 41 | { | ||
| 42 | if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
| 43 | unsigned long cfg, ver; | ||
| 44 | __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver)); | ||
| 45 | if ((ver >> 32) == 0x003e0016) { | ||
| 46 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | ||
| 47 | : "=r" (cfg) | ||
| 48 | : "i" (ASI_JBUS_CONFIG)); | ||
| 49 | return ((cfg >> 17) & 0x1f); | ||
| 50 | } else { | ||
| 51 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | ||
| 52 | : "=r" (cfg) | ||
| 53 | : "i" (ASI_SAFARI_CONFIG)); | ||
| 54 | return ((cfg >> 17) & 0x3ff); | ||
| 55 | } | ||
| 56 | } else if (this_is_starfire != 0) { | ||
| 57 | return starfire_hard_smp_processor_id(); | ||
| 58 | } else { | ||
| 59 | unsigned long upaconfig; | ||
| 60 | __asm__ __volatile__("ldxa [%%g0] %1, %0" | ||
| 61 | : "=r" (upaconfig) | ||
| 62 | : "i" (ASI_UPA_CONFIG)); | ||
| 63 | return ((upaconfig >> 17) & 0x1f); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | #define raw_smp_processor_id() (current_thread_info()->cpu) | 43 | #define raw_smp_processor_id() (current_thread_info()->cpu) |
| 68 | 44 | ||
| 69 | extern void smp_setup_cpu_possible_map(void); | 45 | extern void smp_setup_cpu_possible_map(void); |
diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h new file mode 100644 index 000000000000..ed5c9d8541e2 --- /dev/null +++ b/include/asm-sparc64/sparsemem.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef _SPARC64_SPARSEMEM_H | ||
| 2 | #define _SPARC64_SPARSEMEM_H | ||
| 3 | |||
| 4 | #ifdef __KERNEL__ | ||
| 5 | |||
| 6 | #define SECTION_SIZE_BITS 26 | ||
| 7 | #define MAX_PHYSADDR_BITS 42 | ||
| 8 | #define MAX_PHYSMEM_BITS 42 | ||
| 9 | |||
| 10 | #endif /* !(__KERNEL__) */ | ||
| 11 | |||
| 12 | #endif /* !(_SPARC64_SPARSEMEM_H) */ | ||
diff --git a/include/asm-sparc64/spitfire.h b/include/asm-sparc64/spitfire.h index 962638c9d122..23ad8a7987ad 100644 --- a/include/asm-sparc64/spitfire.h +++ b/include/asm-sparc64/spitfire.h | |||
| @@ -44,6 +44,7 @@ enum ultra_tlb_layout { | |||
| 44 | spitfire = 0, | 44 | spitfire = 0, |
| 45 | cheetah = 1, | 45 | cheetah = 1, |
| 46 | cheetah_plus = 2, | 46 | cheetah_plus = 2, |
| 47 | hypervisor = 3, | ||
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | extern enum ultra_tlb_layout tlb_type; | 50 | extern enum ultra_tlb_layout tlb_type; |
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index af254e581834..a18ec87a52c1 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h | |||
| @@ -209,9 +209,10 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \ | |||
| 209 | /* so that ASI is only written if it changes, think again. */ \ | 209 | /* so that ASI is only written if it changes, think again. */ \ |
| 210 | __asm__ __volatile__("wr %%g0, %0, %%asi" \ | 210 | __asm__ __volatile__("wr %%g0, %0, %%asi" \ |
| 211 | : : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\ | 211 | : : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\ |
| 212 | trap_block[current_thread_info()->cpu].thread = \ | ||
| 213 | task_thread_info(next); \ | ||
| 212 | __asm__ __volatile__( \ | 214 | __asm__ __volatile__( \ |
| 213 | "mov %%g4, %%g7\n\t" \ | 215 | "mov %%g4, %%g7\n\t" \ |
| 214 | "wrpr %%g0, 0x95, %%pstate\n\t" \ | ||
| 215 | "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \ | 216 | "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \ |
| 216 | "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \ | 217 | "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \ |
| 217 | "rdpr %%wstate, %%o5\n\t" \ | 218 | "rdpr %%wstate, %%o5\n\t" \ |
| @@ -225,14 +226,10 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \ | |||
| 225 | "ldx [%%g6 + %3], %%o6\n\t" \ | 226 | "ldx [%%g6 + %3], %%o6\n\t" \ |
| 226 | "ldub [%%g6 + %2], %%o5\n\t" \ | 227 | "ldub [%%g6 + %2], %%o5\n\t" \ |
| 227 | "ldub [%%g6 + %4], %%o7\n\t" \ | 228 | "ldub [%%g6 + %4], %%o7\n\t" \ |
| 228 | "mov %%g6, %%l2\n\t" \ | ||
| 229 | "wrpr %%o5, 0x0, %%wstate\n\t" \ | 229 | "wrpr %%o5, 0x0, %%wstate\n\t" \ |
| 230 | "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \ | 230 | "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \ |
| 231 | "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ | 231 | "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ |
| 232 | "wrpr %%g0, 0x94, %%pstate\n\t" \ | ||
| 233 | "mov %%l2, %%g6\n\t" \ | ||
| 234 | "ldx [%%g6 + %6], %%g4\n\t" \ | 232 | "ldx [%%g6 + %6], %%g4\n\t" \ |
| 235 | "wrpr %%g0, 0x96, %%pstate\n\t" \ | ||
| 236 | "brz,pt %%o7, 1f\n\t" \ | 233 | "brz,pt %%o7, 1f\n\t" \ |
| 237 | " mov %%g7, %0\n\t" \ | 234 | " mov %%g7, %0\n\t" \ |
| 238 | "b,a ret_from_syscall\n\t" \ | 235 | "b,a ret_from_syscall\n\t" \ |
diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h index ac9d068aab4f..2ebf7f27bf91 100644 --- a/include/asm-sparc64/thread_info.h +++ b/include/asm-sparc64/thread_info.h | |||
| @@ -64,8 +64,6 @@ struct thread_info { | |||
| 64 | __u64 kernel_cntd0, kernel_cntd1; | 64 | __u64 kernel_cntd0, kernel_cntd1; |
| 65 | __u64 pcr_reg; | 65 | __u64 pcr_reg; |
| 66 | 66 | ||
| 67 | __u64 cee_stuff; | ||
| 68 | |||
| 69 | struct restart_block restart_block; | 67 | struct restart_block restart_block; |
| 70 | 68 | ||
| 71 | struct pt_regs *kern_una_regs; | 69 | struct pt_regs *kern_una_regs; |
| @@ -104,10 +102,9 @@ struct thread_info { | |||
| 104 | #define TI_KERN_CNTD0 0x00000480 | 102 | #define TI_KERN_CNTD0 0x00000480 |
| 105 | #define TI_KERN_CNTD1 0x00000488 | 103 | #define TI_KERN_CNTD1 0x00000488 |
| 106 | #define TI_PCR 0x00000490 | 104 | #define TI_PCR 0x00000490 |
| 107 | #define TI_CEE_STUFF 0x00000498 | 105 | #define TI_RESTART_BLOCK 0x00000498 |
| 108 | #define TI_RESTART_BLOCK 0x000004a0 | 106 | #define TI_KUNA_REGS 0x000004c0 |
| 109 | #define TI_KUNA_REGS 0x000004c8 | 107 | #define TI_KUNA_INSN 0x000004c8 |
| 110 | #define TI_KUNA_INSN 0x000004d0 | ||
| 111 | #define TI_FPREGS 0x00000500 | 108 | #define TI_FPREGS 0x00000500 |
| 112 | 109 | ||
| 113 | /* We embed this in the uppermost byte of thread_info->flags */ | 110 | /* We embed this in the uppermost byte of thread_info->flags */ |
diff --git a/include/asm-sparc64/timex.h b/include/asm-sparc64/timex.h index 9e8d4175bcb2..2a5e4ebaad80 100644 --- a/include/asm-sparc64/timex.h +++ b/include/asm-sparc64/timex.h | |||
| @@ -14,4 +14,10 @@ | |||
| 14 | typedef unsigned long cycles_t; | 14 | typedef unsigned long cycles_t; |
| 15 | #define get_cycles() tick_ops->get_tick() | 15 | #define get_cycles() tick_ops->get_tick() |
| 16 | 16 | ||
| 17 | #define ARCH_HAS_READ_CURRENT_TIMER 1 | ||
| 18 | #define read_current_timer(timer_val_p) \ | ||
| 19 | ({ *timer_val_p = tick_ops->get_tick(); \ | ||
| 20 | 0; \ | ||
| 21 | }) | ||
| 22 | |||
| 17 | #endif | 23 | #endif |
diff --git a/include/asm-sparc64/tlbflush.h b/include/asm-sparc64/tlbflush.h index 3ef9909ac3ac..9ad5d9c51d42 100644 --- a/include/asm-sparc64/tlbflush.h +++ b/include/asm-sparc64/tlbflush.h | |||
| @@ -5,6 +5,11 @@ | |||
| 5 | #include <linux/mm.h> | 5 | #include <linux/mm.h> |
| 6 | #include <asm/mmu_context.h> | 6 | #include <asm/mmu_context.h> |
| 7 | 7 | ||
| 8 | /* TSB flush operations. */ | ||
| 9 | struct mmu_gather; | ||
| 10 | extern void flush_tsb_kernel_range(unsigned long start, unsigned long end); | ||
| 11 | extern void flush_tsb_user(struct mmu_gather *mp); | ||
| 12 | |||
| 8 | /* TLB flush operations. */ | 13 | /* TLB flush operations. */ |
| 9 | 14 | ||
| 10 | extern void flush_tlb_pending(void); | 15 | extern void flush_tlb_pending(void); |
| @@ -14,28 +19,36 @@ extern void flush_tlb_pending(void); | |||
| 14 | #define flush_tlb_page(vma,addr) flush_tlb_pending() | 19 | #define flush_tlb_page(vma,addr) flush_tlb_pending() |
| 15 | #define flush_tlb_mm(mm) flush_tlb_pending() | 20 | #define flush_tlb_mm(mm) flush_tlb_pending() |
| 16 | 21 | ||
| 22 | /* Local cpu only. */ | ||
| 17 | extern void __flush_tlb_all(void); | 23 | extern void __flush_tlb_all(void); |
| 24 | |||
| 18 | extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r); | 25 | extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r); |
| 19 | 26 | ||
| 20 | extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end); | 27 | extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end); |
| 21 | 28 | ||
| 22 | #ifndef CONFIG_SMP | 29 | #ifndef CONFIG_SMP |
| 23 | 30 | ||
| 24 | #define flush_tlb_all() __flush_tlb_all() | ||
| 25 | #define flush_tlb_kernel_range(start,end) \ | 31 | #define flush_tlb_kernel_range(start,end) \ |
| 26 | __flush_tlb_kernel_range(start,end) | 32 | do { flush_tsb_kernel_range(start,end); \ |
| 33 | __flush_tlb_kernel_range(start,end); \ | ||
| 34 | } while (0) | ||
| 27 | 35 | ||
| 28 | #else /* CONFIG_SMP */ | 36 | #else /* CONFIG_SMP */ |
| 29 | 37 | ||
| 30 | extern void smp_flush_tlb_all(void); | ||
| 31 | extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); | 38 | extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); |
| 32 | 39 | ||
| 33 | #define flush_tlb_all() smp_flush_tlb_all() | ||
| 34 | #define flush_tlb_kernel_range(start, end) \ | 40 | #define flush_tlb_kernel_range(start, end) \ |
| 35 | smp_flush_tlb_kernel_range(start, end) | 41 | do { flush_tsb_kernel_range(start,end); \ |
| 42 | smp_flush_tlb_kernel_range(start, end); \ | ||
| 43 | } while (0) | ||
| 36 | 44 | ||
| 37 | #endif /* ! CONFIG_SMP */ | 45 | #endif /* ! CONFIG_SMP */ |
| 38 | 46 | ||
| 39 | extern void flush_tlb_pgtables(struct mm_struct *, unsigned long, unsigned long); | 47 | static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) |
| 48 | { | ||
| 49 | /* We don't use virtual page tables for TLB miss processing | ||
| 50 | * any more. Nowadays we use the TSB. | ||
| 51 | */ | ||
| 52 | } | ||
| 40 | 53 | ||
| 41 | #endif /* _SPARC64_TLBFLUSH_H */ | 54 | #endif /* _SPARC64_TLBFLUSH_H */ |
diff --git a/include/asm-sparc64/tsb.h b/include/asm-sparc64/tsb.h new file mode 100644 index 000000000000..e82612cd9f33 --- /dev/null +++ b/include/asm-sparc64/tsb.h | |||
| @@ -0,0 +1,281 @@ | |||
| 1 | #ifndef _SPARC64_TSB_H | ||
| 2 | #define _SPARC64_TSB_H | ||
| 3 | |||
| 4 | /* The sparc64 TSB is similar to the powerpc hashtables. It's a | ||
| 5 | * power-of-2 sized table of TAG/PTE pairs. The cpu precomputes | ||
| 6 | * pointers into this table for 8K and 64K page sizes, and also a | ||
| 7 | * comparison TAG based upon the virtual address and context which | ||
| 8 | * faults. | ||
| 9 | * | ||
| 10 | * TLB miss trap handler software does the actual lookup via something | ||
| 11 | * of the form: | ||
| 12 | * | ||
| 13 | * ldxa [%g0] ASI_{D,I}MMU_TSB_8KB_PTR, %g1 | ||
| 14 | * ldxa [%g0] ASI_{D,I}MMU, %g6 | ||
| 15 | * sllx %g6, 22, %g6 | ||
| 16 | * srlx %g6, 22, %g6 | ||
| 17 | * ldda [%g1] ASI_NUCLEUS_QUAD_LDD, %g4 | ||
| 18 | * cmp %g4, %g6 | ||
| 19 | * bne,pn %xcc, tsb_miss_{d,i}tlb | ||
| 20 | * mov FAULT_CODE_{D,I}TLB, %g3 | ||
| 21 | * stxa %g5, [%g0] ASI_{D,I}TLB_DATA_IN | ||
| 22 | * retry | ||
| 23 | * | ||
| 24 | * | ||
| 25 | * Each 16-byte slot of the TSB is the 8-byte tag and then the 8-byte | ||
| 26 | * PTE. The TAG is of the same layout as the TLB TAG TARGET mmu | ||
| 27 | * register which is: | ||
| 28 | * | ||
| 29 | * ------------------------------------------------- | ||
| 30 | * | - | CONTEXT | - | VADDR bits 63:22 | | ||
| 31 | * ------------------------------------------------- | ||
| 32 | * 63 61 60 48 47 42 41 0 | ||
| 33 | * | ||
| 34 | * But actually, since we use per-mm TSB's, we zero out the CONTEXT | ||
| 35 | * field. | ||
| 36 | * | ||
| 37 | * Like the powerpc hashtables we need to use locking in order to | ||
| 38 | * synchronize while we update the entries. PTE updates need locking | ||
| 39 | * as well. | ||
| 40 | * | ||
| 41 | * We need to carefully choose a lock bits for the TSB entry. We | ||
| 42 | * choose to use bit 47 in the tag. Also, since we never map anything | ||
| 43 | * at page zero in context zero, we use zero as an invalid tag entry. | ||
| 44 | * When the lock bit is set, this forces a tag comparison failure. | ||
| 45 | */ | ||
| 46 | |||
| 47 | #define TSB_TAG_LOCK_BIT 47 | ||
| 48 | #define TSB_TAG_LOCK_HIGH (1 << (TSB_TAG_LOCK_BIT - 32)) | ||
| 49 | |||
| 50 | #define TSB_TAG_INVALID_BIT 46 | ||
| 51 | #define TSB_TAG_INVALID_HIGH (1 << (TSB_TAG_INVALID_BIT - 32)) | ||
| 52 | |||
| 53 | #define TSB_MEMBAR membar #StoreStore | ||
| 54 | |||
| 55 | /* Some cpus support physical address quad loads. We want to use | ||
| 56 | * those if possible so we don't need to hard-lock the TSB mapping | ||
| 57 | * into the TLB. We encode some instruction patching in order to | ||
| 58 | * support this. | ||
| 59 | * | ||
| 60 | * The kernel TSB is locked into the TLB by virtue of being in the | ||
| 61 | * kernel image, so we don't play these games for swapper_tsb access. | ||
| 62 | */ | ||
| 63 | #ifndef __ASSEMBLY__ | ||
| 64 | struct tsb_ldquad_phys_patch_entry { | ||
| 65 | unsigned int addr; | ||
| 66 | unsigned int sun4u_insn; | ||
| 67 | unsigned int sun4v_insn; | ||
| 68 | }; | ||
| 69 | extern struct tsb_ldquad_phys_patch_entry __tsb_ldquad_phys_patch, | ||
| 70 | __tsb_ldquad_phys_patch_end; | ||
| 71 | |||
| 72 | struct tsb_phys_patch_entry { | ||
| 73 | unsigned int addr; | ||
| 74 | unsigned int insn; | ||
| 75 | }; | ||
| 76 | extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; | ||
| 77 | #endif | ||
| 78 | #define TSB_LOAD_QUAD(TSB, REG) \ | ||
| 79 | 661: ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG; \ | ||
| 80 | .section .tsb_ldquad_phys_patch, "ax"; \ | ||
| 81 | .word 661b; \ | ||
| 82 | ldda [TSB] ASI_QUAD_LDD_PHYS, REG; \ | ||
| 83 | ldda [TSB] ASI_QUAD_LDD_PHYS_4V, REG; \ | ||
| 84 | .previous | ||
| 85 | |||
| 86 | #define TSB_LOAD_TAG_HIGH(TSB, REG) \ | ||
| 87 | 661: lduwa [TSB] ASI_N, REG; \ | ||
| 88 | .section .tsb_phys_patch, "ax"; \ | ||
| 89 | .word 661b; \ | ||
| 90 | lduwa [TSB] ASI_PHYS_USE_EC, REG; \ | ||
| 91 | .previous | ||
| 92 | |||
| 93 | #define TSB_LOAD_TAG(TSB, REG) \ | ||
| 94 | 661: ldxa [TSB] ASI_N, REG; \ | ||
| 95 | .section .tsb_phys_patch, "ax"; \ | ||
| 96 | .word 661b; \ | ||
| 97 | ldxa [TSB] ASI_PHYS_USE_EC, REG; \ | ||
| 98 | .previous | ||
| 99 | |||
| 100 | #define TSB_CAS_TAG_HIGH(TSB, REG1, REG2) \ | ||
| 101 | 661: casa [TSB] ASI_N, REG1, REG2; \ | ||
| 102 | .section .tsb_phys_patch, "ax"; \ | ||
| 103 | .word 661b; \ | ||
| 104 | casa [TSB] ASI_PHYS_USE_EC, REG1, REG2; \ | ||
| 105 | .previous | ||
| 106 | |||
| 107 | #define TSB_CAS_TAG(TSB, REG1, REG2) \ | ||
| 108 | 661: casxa [TSB] ASI_N, REG1, REG2; \ | ||
| 109 | .section .tsb_phys_patch, "ax"; \ | ||
| 110 | .word 661b; \ | ||
| 111 | casxa [TSB] ASI_PHYS_USE_EC, REG1, REG2; \ | ||
| 112 | .previous | ||
| 113 | |||
| 114 | #define TSB_STORE(ADDR, VAL) \ | ||
| 115 | 661: stxa VAL, [ADDR] ASI_N; \ | ||
| 116 | .section .tsb_phys_patch, "ax"; \ | ||
| 117 | .word 661b; \ | ||
| 118 | stxa VAL, [ADDR] ASI_PHYS_USE_EC; \ | ||
| 119 | .previous | ||
| 120 | |||
| 121 | #define TSB_LOCK_TAG(TSB, REG1, REG2) \ | ||
| 122 | 99: TSB_LOAD_TAG_HIGH(TSB, REG1); \ | ||
| 123 | sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\ | ||
| 124 | andcc REG1, REG2, %g0; \ | ||
| 125 | bne,pn %icc, 99b; \ | ||
| 126 | nop; \ | ||
| 127 | TSB_CAS_TAG_HIGH(TSB, REG1, REG2); \ | ||
| 128 | cmp REG1, REG2; \ | ||
| 129 | bne,pn %icc, 99b; \ | ||
| 130 | nop; \ | ||
| 131 | TSB_MEMBAR | ||
| 132 | |||
| 133 | #define TSB_WRITE(TSB, TTE, TAG) \ | ||
| 134 | add TSB, 0x8, TSB; \ | ||
| 135 | TSB_STORE(TSB, TTE); \ | ||
| 136 | sub TSB, 0x8, TSB; \ | ||
| 137 | TSB_MEMBAR; \ | ||
| 138 | TSB_STORE(TSB, TAG); | ||
| 139 | |||
| 140 | #define KTSB_LOAD_QUAD(TSB, REG) \ | ||
| 141 | ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG; | ||
| 142 | |||
| 143 | #define KTSB_STORE(ADDR, VAL) \ | ||
| 144 | stxa VAL, [ADDR] ASI_N; | ||
| 145 | |||
| 146 | #define KTSB_LOCK_TAG(TSB, REG1, REG2) \ | ||
| 147 | 99: lduwa [TSB] ASI_N, REG1; \ | ||
| 148 | sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\ | ||
| 149 | andcc REG1, REG2, %g0; \ | ||
| 150 | bne,pn %icc, 99b; \ | ||
| 151 | nop; \ | ||
| 152 | casa [TSB] ASI_N, REG1, REG2;\ | ||
| 153 | cmp REG1, REG2; \ | ||
| 154 | bne,pn %icc, 99b; \ | ||
| 155 | nop; \ | ||
| 156 | TSB_MEMBAR | ||
| 157 | |||
| 158 | #define KTSB_WRITE(TSB, TTE, TAG) \ | ||
| 159 | add TSB, 0x8, TSB; \ | ||
| 160 | stxa TTE, [TSB] ASI_N; \ | ||
| 161 | sub TSB, 0x8, TSB; \ | ||
| 162 | TSB_MEMBAR; \ | ||
| 163 | stxa TAG, [TSB] ASI_N; | ||
| 164 | |||
| 165 | /* Do a kernel page table walk. Leaves physical PTE pointer in | ||
| 166 | * REG1. Jumps to FAIL_LABEL on early page table walk termination. | ||
| 167 | * VADDR will not be clobbered, but REG2 will. | ||
| 168 | */ | ||
| 169 | #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \ | ||
| 170 | sethi %hi(swapper_pg_dir), REG1; \ | ||
| 171 | or REG1, %lo(swapper_pg_dir), REG1; \ | ||
| 172 | sllx VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \ | ||
| 173 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
| 174 | andn REG2, 0x3, REG2; \ | ||
| 175 | lduw [REG1 + REG2], REG1; \ | ||
| 176 | brz,pn REG1, FAIL_LABEL; \ | ||
| 177 | sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ | ||
| 178 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
| 179 | sllx REG1, 11, REG1; \ | ||
| 180 | andn REG2, 0x3, REG2; \ | ||
| 181 | lduwa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ | ||
| 182 | brz,pn REG1, FAIL_LABEL; \ | ||
| 183 | sllx VADDR, 64 - PMD_SHIFT, REG2; \ | ||
| 184 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
| 185 | sllx REG1, 11, REG1; \ | ||
| 186 | andn REG2, 0x7, REG2; \ | ||
| 187 | add REG1, REG2, REG1; | ||
| 188 | |||
| 189 | /* Do a user page table walk in MMU globals. Leaves physical PTE | ||
| 190 | * pointer in REG1. Jumps to FAIL_LABEL on early page table walk | ||
| 191 | * termination. Physical base of page tables is in PHYS_PGD which | ||
| 192 | * will not be modified. | ||
| 193 | * | ||
| 194 | * VADDR will not be clobbered, but REG1 and REG2 will. | ||
| 195 | */ | ||
| 196 | #define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL) \ | ||
| 197 | sllx VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \ | ||
| 198 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
| 199 | andn REG2, 0x3, REG2; \ | ||
| 200 | lduwa [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \ | ||
| 201 | brz,pn REG1, FAIL_LABEL; \ | ||
| 202 | sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ | ||
| 203 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
| 204 | sllx REG1, 11, REG1; \ | ||
| 205 | andn REG2, 0x3, REG2; \ | ||
| 206 | lduwa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ | ||
| 207 | brz,pn REG1, FAIL_LABEL; \ | ||
| 208 | sllx VADDR, 64 - PMD_SHIFT, REG2; \ | ||
| 209 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | ||
| 210 | sllx REG1, 11, REG1; \ | ||
| 211 | andn REG2, 0x7, REG2; \ | ||
| 212 | add REG1, REG2, REG1; | ||
| 213 | |||
| 214 | /* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0. | ||
| 215 | * If no entry is found, FAIL_LABEL will be branched to. On success | ||
| 216 | * the resulting PTE value will be left in REG1. VADDR is preserved | ||
| 217 | * by this routine. | ||
| 218 | */ | ||
| 219 | #define OBP_TRANS_LOOKUP(VADDR, REG1, REG2, REG3, FAIL_LABEL) \ | ||
| 220 | sethi %hi(prom_trans), REG1; \ | ||
| 221 | or REG1, %lo(prom_trans), REG1; \ | ||
| 222 | 97: ldx [REG1 + 0x00], REG2; \ | ||
| 223 | brz,pn REG2, FAIL_LABEL; \ | ||
| 224 | nop; \ | ||
| 225 | ldx [REG1 + 0x08], REG3; \ | ||
| 226 | add REG2, REG3, REG3; \ | ||
| 227 | cmp REG2, VADDR; \ | ||
| 228 | bgu,pt %xcc, 98f; \ | ||
| 229 | cmp VADDR, REG3; \ | ||
| 230 | bgeu,pt %xcc, 98f; \ | ||
| 231 | ldx [REG1 + 0x10], REG3; \ | ||
| 232 | sub VADDR, REG2, REG2; \ | ||
| 233 | ba,pt %xcc, 99f; \ | ||
| 234 | add REG3, REG2, REG1; \ | ||
| 235 | 98: ba,pt %xcc, 97b; \ | ||
| 236 | add REG1, (3 * 8), REG1; \ | ||
| 237 | 99: | ||
| 238 | |||
| 239 | /* We use a 32K TSB for the whole kernel, this allows to | ||
| 240 | * handle about 16MB of modules and vmalloc mappings without | ||
| 241 | * incurring many hash conflicts. | ||
| 242 | */ | ||
| 243 | #define KERNEL_TSB_SIZE_BYTES (32 * 1024) | ||
| 244 | #define KERNEL_TSB_NENTRIES \ | ||
| 245 | (KERNEL_TSB_SIZE_BYTES / 16) | ||
| 246 | #define KERNEL_TSB4M_NENTRIES 4096 | ||
| 247 | |||
| 248 | /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL | ||
| 249 | * on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries | ||
| 250 | * and the found TTE will be left in REG1. REG3 and REG4 must | ||
| 251 | * be an even/odd pair of registers. | ||
| 252 | * | ||
| 253 | * VADDR and TAG will be preserved and not clobbered by this macro. | ||
| 254 | */ | ||
| 255 | #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ | ||
| 256 | sethi %hi(swapper_tsb), REG1; \ | ||
| 257 | or REG1, %lo(swapper_tsb), REG1; \ | ||
| 258 | srlx VADDR, PAGE_SHIFT, REG2; \ | ||
| 259 | and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \ | ||
| 260 | sllx REG2, 4, REG2; \ | ||
| 261 | add REG1, REG2, REG2; \ | ||
| 262 | KTSB_LOAD_QUAD(REG2, REG3); \ | ||
| 263 | cmp REG3, TAG; \ | ||
| 264 | be,a,pt %xcc, OK_LABEL; \ | ||
| 265 | mov REG4, REG1; | ||
| 266 | |||
| 267 | /* This version uses a trick, the TAG is already (VADDR >> 22) so | ||
| 268 | * we can make use of that for the index computation. | ||
| 269 | */ | ||
| 270 | #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ | ||
| 271 | sethi %hi(swapper_4m_tsb), REG1; \ | ||
| 272 | or REG1, %lo(swapper_4m_tsb), REG1; \ | ||
| 273 | and TAG, (KERNEL_TSB_NENTRIES - 1), REG2; \ | ||
| 274 | sllx REG2, 4, REG2; \ | ||
| 275 | add REG1, REG2, REG2; \ | ||
| 276 | KTSB_LOAD_QUAD(REG2, REG3); \ | ||
| 277 | cmp REG3, TAG; \ | ||
| 278 | be,a,pt %xcc, OK_LABEL; \ | ||
| 279 | mov REG4, REG1; | ||
| 280 | |||
| 281 | #endif /* !(_SPARC64_TSB_H) */ | ||
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index 2784f80094c3..2d5e3c464df5 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h | |||
| @@ -93,7 +93,7 @@ | |||
| 93 | 93 | ||
| 94 | #define SYSCALL_TRAP(routine, systbl) \ | 94 | #define SYSCALL_TRAP(routine, systbl) \ |
| 95 | sethi %hi(109f), %g7; \ | 95 | sethi %hi(109f), %g7; \ |
| 96 | ba,pt %xcc, scetrap; \ | 96 | ba,pt %xcc, etrap; \ |
| 97 | 109: or %g7, %lo(109b), %g7; \ | 97 | 109: or %g7, %lo(109b), %g7; \ |
| 98 | sethi %hi(systbl), %l7; \ | 98 | sethi %hi(systbl), %l7; \ |
| 99 | ba,pt %xcc, routine; \ | 99 | ba,pt %xcc, routine; \ |
| @@ -109,14 +109,14 @@ | |||
| 109 | nop;nop;nop; | 109 | nop;nop;nop; |
| 110 | 110 | ||
| 111 | #define TRAP_UTRAP(handler,lvl) \ | 111 | #define TRAP_UTRAP(handler,lvl) \ |
| 112 | ldx [%g6 + TI_UTRAPS], %g1; \ | 112 | mov handler, %g3; \ |
| 113 | sethi %hi(109f), %g7; \ | 113 | ba,pt %xcc, utrap_trap; \ |
| 114 | brz,pn %g1, utrap; \ | 114 | mov lvl, %g4; \ |
| 115 | or %g7, %lo(109f), %g7; \ | 115 | nop; \ |
| 116 | ba,pt %xcc, utrap; \ | 116 | nop; \ |
| 117 | 109: ldx [%g1 + handler*8], %g1; \ | 117 | nop; \ |
| 118 | ba,pt %xcc, utrap_ill; \ | 118 | nop; \ |
| 119 | mov lvl, %o1; | 119 | nop; |
| 120 | 120 | ||
| 121 | #ifdef CONFIG_SUNOS_EMUL | 121 | #ifdef CONFIG_SUNOS_EMUL |
| 122 | #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall32, sunos_sys_table) | 122 | #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall32, sunos_sys_table) |
| @@ -136,8 +136,6 @@ | |||
| 136 | #else | 136 | #else |
| 137 | #define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall) | 137 | #define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall) |
| 138 | #endif | 138 | #endif |
| 139 | /* FIXME: Write these actually */ | ||
| 140 | #define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall) | ||
| 141 | #define BREAKPOINT_TRAP TRAP(breakpoint_trap) | 139 | #define BREAKPOINT_TRAP TRAP(breakpoint_trap) |
| 142 | 140 | ||
| 143 | #define TRAP_IRQ(routine, level) \ | 141 | #define TRAP_IRQ(routine, level) \ |
| @@ -182,6 +180,26 @@ | |||
| 182 | #define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl) | 180 | #define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl) |
| 183 | #endif | 181 | #endif |
| 184 | 182 | ||
| 183 | #define SUN4V_ITSB_MISS \ | ||
| 184 | ldxa [%g0] ASI_SCRATCHPAD, %g2; \ | ||
| 185 | ldx [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4; \ | ||
| 186 | ldx [%g2 + HV_FAULT_I_CTX_OFFSET], %g5; \ | ||
| 187 | srlx %g4, 22, %g6; \ | ||
| 188 | ba,pt %xcc, sun4v_itsb_miss; \ | ||
| 189 | nop; \ | ||
| 190 | nop; \ | ||
| 191 | nop; | ||
| 192 | |||
| 193 | #define SUN4V_DTSB_MISS \ | ||
| 194 | ldxa [%g0] ASI_SCRATCHPAD, %g2; \ | ||
| 195 | ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4; \ | ||
| 196 | ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5; \ | ||
| 197 | srlx %g4, 22, %g6; \ | ||
| 198 | ba,pt %xcc, sun4v_dtsb_miss; \ | ||
| 199 | nop; \ | ||
| 200 | nop; \ | ||
| 201 | nop; | ||
| 202 | |||
| 185 | /* Before touching these macros, you owe it to yourself to go and | 203 | /* Before touching these macros, you owe it to yourself to go and |
| 186 | * see how arch/sparc64/kernel/winfixup.S works... -DaveM | 204 | * see how arch/sparc64/kernel/winfixup.S works... -DaveM |
| 187 | * | 205 | * |
| @@ -221,6 +239,31 @@ | |||
| 221 | saved; retry; nop; nop; nop; nop; nop; nop; \ | 239 | saved; retry; nop; nop; nop; nop; nop; nop; \ |
| 222 | nop; nop; nop; nop; nop; nop; nop; nop; | 240 | nop; nop; nop; nop; nop; nop; nop; nop; |
| 223 | 241 | ||
| 242 | #define SPILL_0_NORMAL_ETRAP \ | ||
| 243 | etrap_kernel_spill: \ | ||
| 244 | stx %l0, [%sp + STACK_BIAS + 0x00]; \ | ||
| 245 | stx %l1, [%sp + STACK_BIAS + 0x08]; \ | ||
| 246 | stx %l2, [%sp + STACK_BIAS + 0x10]; \ | ||
| 247 | stx %l3, [%sp + STACK_BIAS + 0x18]; \ | ||
| 248 | stx %l4, [%sp + STACK_BIAS + 0x20]; \ | ||
| 249 | stx %l5, [%sp + STACK_BIAS + 0x28]; \ | ||
| 250 | stx %l6, [%sp + STACK_BIAS + 0x30]; \ | ||
| 251 | stx %l7, [%sp + STACK_BIAS + 0x38]; \ | ||
| 252 | stx %i0, [%sp + STACK_BIAS + 0x40]; \ | ||
| 253 | stx %i1, [%sp + STACK_BIAS + 0x48]; \ | ||
| 254 | stx %i2, [%sp + STACK_BIAS + 0x50]; \ | ||
| 255 | stx %i3, [%sp + STACK_BIAS + 0x58]; \ | ||
| 256 | stx %i4, [%sp + STACK_BIAS + 0x60]; \ | ||
| 257 | stx %i5, [%sp + STACK_BIAS + 0x68]; \ | ||
| 258 | stx %i6, [%sp + STACK_BIAS + 0x70]; \ | ||
| 259 | stx %i7, [%sp + STACK_BIAS + 0x78]; \ | ||
| 260 | saved; \ | ||
| 261 | sub %g1, 2, %g1; \ | ||
| 262 | ba,pt %xcc, etrap_save; \ | ||
| 263 | wrpr %g1, %cwp; \ | ||
| 264 | nop; nop; nop; nop; nop; nop; nop; nop; \ | ||
| 265 | nop; nop; nop; nop; | ||
| 266 | |||
| 224 | /* Normal 64bit spill */ | 267 | /* Normal 64bit spill */ |
| 225 | #define SPILL_1_GENERIC(ASI) \ | 268 | #define SPILL_1_GENERIC(ASI) \ |
| 226 | add %sp, STACK_BIAS + 0x00, %g1; \ | 269 | add %sp, STACK_BIAS + 0x00, %g1; \ |
| @@ -254,6 +297,67 @@ | |||
| 254 | b,a,pt %xcc, spill_fixup_mna; \ | 297 | b,a,pt %xcc, spill_fixup_mna; \ |
| 255 | b,a,pt %xcc, spill_fixup; | 298 | b,a,pt %xcc, spill_fixup; |
| 256 | 299 | ||
| 300 | #define SPILL_1_GENERIC_ETRAP \ | ||
| 301 | etrap_user_spill_64bit: \ | ||
| 302 | stxa %l0, [%sp + STACK_BIAS + 0x00] %asi; \ | ||
| 303 | stxa %l1, [%sp + STACK_BIAS + 0x08] %asi; \ | ||
| 304 | stxa %l2, [%sp + STACK_BIAS + 0x10] %asi; \ | ||
| 305 | stxa %l3, [%sp + STACK_BIAS + 0x18] %asi; \ | ||
| 306 | stxa %l4, [%sp + STACK_BIAS + 0x20] %asi; \ | ||
| 307 | stxa %l5, [%sp + STACK_BIAS + 0x28] %asi; \ | ||
| 308 | stxa %l6, [%sp + STACK_BIAS + 0x30] %asi; \ | ||
| 309 | stxa %l7, [%sp + STACK_BIAS + 0x38] %asi; \ | ||
| 310 | stxa %i0, [%sp + STACK_BIAS + 0x40] %asi; \ | ||
| 311 | stxa %i1, [%sp + STACK_BIAS + 0x48] %asi; \ | ||
| 312 | stxa %i2, [%sp + STACK_BIAS + 0x50] %asi; \ | ||
| 313 | stxa %i3, [%sp + STACK_BIAS + 0x58] %asi; \ | ||
| 314 | stxa %i4, [%sp + STACK_BIAS + 0x60] %asi; \ | ||
| 315 | stxa %i5, [%sp + STACK_BIAS + 0x68] %asi; \ | ||
| 316 | stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \ | ||
| 317 | stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \ | ||
| 318 | saved; \ | ||
| 319 | sub %g1, 2, %g1; \ | ||
| 320 | ba,pt %xcc, etrap_save; \ | ||
| 321 | wrpr %g1, %cwp; \ | ||
| 322 | nop; nop; nop; nop; nop; \ | ||
| 323 | nop; nop; nop; nop; \ | ||
| 324 | ba,a,pt %xcc, etrap_spill_fixup_64bit; \ | ||
| 325 | ba,a,pt %xcc, etrap_spill_fixup_64bit; \ | ||
| 326 | ba,a,pt %xcc, etrap_spill_fixup_64bit; | ||
| 327 | |||
| 328 | #define SPILL_1_GENERIC_ETRAP_FIXUP \ | ||
| 329 | etrap_spill_fixup_64bit: \ | ||
| 330 | ldub [%g6 + TI_WSAVED], %g1; \ | ||
| 331 | sll %g1, 3, %g3; \ | ||
| 332 | add %g6, %g3, %g3; \ | ||
| 333 | stx %sp, [%g3 + TI_RWIN_SPTRS]; \ | ||
| 334 | sll %g1, 7, %g3; \ | ||
| 335 | add %g6, %g3, %g3; \ | ||
| 336 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00]; \ | ||
| 337 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08]; \ | ||
| 338 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10]; \ | ||
| 339 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18]; \ | ||
| 340 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20]; \ | ||
| 341 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28]; \ | ||
| 342 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30]; \ | ||
| 343 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38]; \ | ||
| 344 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40]; \ | ||
| 345 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48]; \ | ||
| 346 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50]; \ | ||
| 347 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58]; \ | ||
| 348 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60]; \ | ||
| 349 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68]; \ | ||
| 350 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70]; \ | ||
| 351 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78]; \ | ||
| 352 | add %g1, 1, %g1; \ | ||
| 353 | stb %g1, [%g6 + TI_WSAVED]; \ | ||
| 354 | saved; \ | ||
| 355 | rdpr %cwp, %g1; \ | ||
| 356 | sub %g1, 2, %g1; \ | ||
| 357 | ba,pt %xcc, etrap_save; \ | ||
| 358 | wrpr %g1, %cwp; \ | ||
| 359 | nop; nop; nop | ||
| 360 | |||
| 257 | /* Normal 32bit spill */ | 361 | /* Normal 32bit spill */ |
| 258 | #define SPILL_2_GENERIC(ASI) \ | 362 | #define SPILL_2_GENERIC(ASI) \ |
| 259 | srl %sp, 0, %sp; \ | 363 | srl %sp, 0, %sp; \ |
| @@ -287,6 +391,68 @@ | |||
| 287 | b,a,pt %xcc, spill_fixup_mna; \ | 391 | b,a,pt %xcc, spill_fixup_mna; \ |
| 288 | b,a,pt %xcc, spill_fixup; | 392 | b,a,pt %xcc, spill_fixup; |
| 289 | 393 | ||
| 394 | #define SPILL_2_GENERIC_ETRAP \ | ||
| 395 | etrap_user_spill_32bit: \ | ||
| 396 | srl %sp, 0, %sp; \ | ||
| 397 | stwa %l0, [%sp + 0x00] %asi; \ | ||
| 398 | stwa %l1, [%sp + 0x04] %asi; \ | ||
| 399 | stwa %l2, [%sp + 0x08] %asi; \ | ||
| 400 | stwa %l3, [%sp + 0x0c] %asi; \ | ||
| 401 | stwa %l4, [%sp + 0x10] %asi; \ | ||
| 402 | stwa %l5, [%sp + 0x14] %asi; \ | ||
| 403 | stwa %l6, [%sp + 0x18] %asi; \ | ||
| 404 | stwa %l7, [%sp + 0x1c] %asi; \ | ||
| 405 | stwa %i0, [%sp + 0x20] %asi; \ | ||
| 406 | stwa %i1, [%sp + 0x24] %asi; \ | ||
| 407 | stwa %i2, [%sp + 0x28] %asi; \ | ||
| 408 | stwa %i3, [%sp + 0x2c] %asi; \ | ||
| 409 | stwa %i4, [%sp + 0x30] %asi; \ | ||
| 410 | stwa %i5, [%sp + 0x34] %asi; \ | ||
| 411 | stwa %i6, [%sp + 0x38] %asi; \ | ||
| 412 | stwa %i7, [%sp + 0x3c] %asi; \ | ||
| 413 | saved; \ | ||
| 414 | sub %g1, 2, %g1; \ | ||
| 415 | ba,pt %xcc, etrap_save; \ | ||
| 416 | wrpr %g1, %cwp; \ | ||
| 417 | nop; nop; nop; nop; \ | ||
| 418 | nop; nop; nop; nop; \ | ||
| 419 | ba,a,pt %xcc, etrap_spill_fixup_32bit; \ | ||
| 420 | ba,a,pt %xcc, etrap_spill_fixup_32bit; \ | ||
| 421 | ba,a,pt %xcc, etrap_spill_fixup_32bit; | ||
| 422 | |||
| 423 | #define SPILL_2_GENERIC_ETRAP_FIXUP \ | ||
| 424 | etrap_spill_fixup_32bit: \ | ||
| 425 | ldub [%g6 + TI_WSAVED], %g1; \ | ||
| 426 | sll %g1, 3, %g3; \ | ||
| 427 | add %g6, %g3, %g3; \ | ||
| 428 | stx %sp, [%g3 + TI_RWIN_SPTRS]; \ | ||
| 429 | sll %g1, 7, %g3; \ | ||
| 430 | add %g6, %g3, %g3; \ | ||
| 431 | stw %l0, [%g3 + TI_REG_WINDOW + 0x00]; \ | ||
| 432 | stw %l1, [%g3 + TI_REG_WINDOW + 0x04]; \ | ||
| 433 | stw %l2, [%g3 + TI_REG_WINDOW + 0x08]; \ | ||
| 434 | stw %l3, [%g3 + TI_REG_WINDOW + 0x0c]; \ | ||
| 435 | stw %l4, [%g3 + TI_REG_WINDOW + 0x10]; \ | ||
| 436 | stw %l5, [%g3 + TI_REG_WINDOW + 0x14]; \ | ||
| 437 | stw %l6, [%g3 + TI_REG_WINDOW + 0x18]; \ | ||
| 438 | stw %l7, [%g3 + TI_REG_WINDOW + 0x1c]; \ | ||
| 439 | stw %i0, [%g3 + TI_REG_WINDOW + 0x20]; \ | ||
| 440 | stw %i1, [%g3 + TI_REG_WINDOW + 0x24]; \ | ||
| 441 | stw %i2, [%g3 + TI_REG_WINDOW + 0x28]; \ | ||
| 442 | stw %i3, [%g3 + TI_REG_WINDOW + 0x2c]; \ | ||
| 443 | stw %i4, [%g3 + TI_REG_WINDOW + 0x30]; \ | ||
| 444 | stw %i5, [%g3 + TI_REG_WINDOW + 0x34]; \ | ||
| 445 | stw %i6, [%g3 + TI_REG_WINDOW + 0x38]; \ | ||
| 446 | stw %i7, [%g3 + TI_REG_WINDOW + 0x3c]; \ | ||
| 447 | add %g1, 1, %g1; \ | ||
| 448 | stb %g1, [%g6 + TI_WSAVED]; \ | ||
| 449 | saved; \ | ||
| 450 | rdpr %cwp, %g1; \ | ||
| 451 | sub %g1, 2, %g1; \ | ||
| 452 | ba,pt %xcc, etrap_save; \ | ||
| 453 | wrpr %g1, %cwp; \ | ||
| 454 | nop; nop; nop | ||
| 455 | |||
| 290 | #define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP) | 456 | #define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP) |
| 291 | #define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP) | 457 | #define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP) |
| 292 | #define SPILL_3_NORMAL SPILL_0_NORMAL | 458 | #define SPILL_3_NORMAL SPILL_0_NORMAL |
| @@ -325,6 +491,35 @@ | |||
| 325 | restored; retry; nop; nop; nop; nop; nop; nop; \ | 491 | restored; retry; nop; nop; nop; nop; nop; nop; \ |
| 326 | nop; nop; nop; nop; nop; nop; nop; nop; | 492 | nop; nop; nop; nop; nop; nop; nop; nop; |
| 327 | 493 | ||
| 494 | #define FILL_0_NORMAL_RTRAP \ | ||
| 495 | kern_rtt_fill: \ | ||
| 496 | rdpr %cwp, %g1; \ | ||
| 497 | sub %g1, 1, %g1; \ | ||
| 498 | wrpr %g1, %cwp; \ | ||
| 499 | ldx [%sp + STACK_BIAS + 0x00], %l0; \ | ||
| 500 | ldx [%sp + STACK_BIAS + 0x08], %l1; \ | ||
| 501 | ldx [%sp + STACK_BIAS + 0x10], %l2; \ | ||
| 502 | ldx [%sp + STACK_BIAS + 0x18], %l3; \ | ||
| 503 | ldx [%sp + STACK_BIAS + 0x20], %l4; \ | ||
| 504 | ldx [%sp + STACK_BIAS + 0x28], %l5; \ | ||
| 505 | ldx [%sp + STACK_BIAS + 0x30], %l6; \ | ||
| 506 | ldx [%sp + STACK_BIAS + 0x38], %l7; \ | ||
| 507 | ldx [%sp + STACK_BIAS + 0x40], %i0; \ | ||
| 508 | ldx [%sp + STACK_BIAS + 0x48], %i1; \ | ||
| 509 | ldx [%sp + STACK_BIAS + 0x50], %i2; \ | ||
| 510 | ldx [%sp + STACK_BIAS + 0x58], %i3; \ | ||
| 511 | ldx [%sp + STACK_BIAS + 0x60], %i4; \ | ||
| 512 | ldx [%sp + STACK_BIAS + 0x68], %i5; \ | ||
| 513 | ldx [%sp + STACK_BIAS + 0x70], %i6; \ | ||
| 514 | ldx [%sp + STACK_BIAS + 0x78], %i7; \ | ||
| 515 | restored; \ | ||
| 516 | add %g1, 1, %g1; \ | ||
| 517 | ba,pt %xcc, kern_rtt_restore; \ | ||
| 518 | wrpr %g1, %cwp; \ | ||
| 519 | nop; nop; nop; nop; nop; \ | ||
| 520 | nop; nop; nop; nop; | ||
| 521 | |||
| 522 | |||
| 328 | /* Normal 64bit fill */ | 523 | /* Normal 64bit fill */ |
| 329 | #define FILL_1_GENERIC(ASI) \ | 524 | #define FILL_1_GENERIC(ASI) \ |
| 330 | add %sp, STACK_BIAS + 0x00, %g1; \ | 525 | add %sp, STACK_BIAS + 0x00, %g1; \ |
| @@ -356,6 +551,33 @@ | |||
| 356 | b,a,pt %xcc, fill_fixup_mna; \ | 551 | b,a,pt %xcc, fill_fixup_mna; \ |
| 357 | b,a,pt %xcc, fill_fixup; | 552 | b,a,pt %xcc, fill_fixup; |
| 358 | 553 | ||
| 554 | #define FILL_1_GENERIC_RTRAP \ | ||
| 555 | user_rtt_fill_64bit: \ | ||
| 556 | ldxa [%sp + STACK_BIAS + 0x00] %asi, %l0; \ | ||
| 557 | ldxa [%sp + STACK_BIAS + 0x08] %asi, %l1; \ | ||
| 558 | ldxa [%sp + STACK_BIAS + 0x10] %asi, %l2; \ | ||
| 559 | ldxa [%sp + STACK_BIAS + 0x18] %asi, %l3; \ | ||
| 560 | ldxa [%sp + STACK_BIAS + 0x20] %asi, %l4; \ | ||
| 561 | ldxa [%sp + STACK_BIAS + 0x28] %asi, %l5; \ | ||
| 562 | ldxa [%sp + STACK_BIAS + 0x30] %asi, %l6; \ | ||
| 563 | ldxa [%sp + STACK_BIAS + 0x38] %asi, %l7; \ | ||
| 564 | ldxa [%sp + STACK_BIAS + 0x40] %asi, %i0; \ | ||
| 565 | ldxa [%sp + STACK_BIAS + 0x48] %asi, %i1; \ | ||
| 566 | ldxa [%sp + STACK_BIAS + 0x50] %asi, %i2; \ | ||
| 567 | ldxa [%sp + STACK_BIAS + 0x58] %asi, %i3; \ | ||
| 568 | ldxa [%sp + STACK_BIAS + 0x60] %asi, %i4; \ | ||
| 569 | ldxa [%sp + STACK_BIAS + 0x68] %asi, %i5; \ | ||
| 570 | ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \ | ||
| 571 | ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \ | ||
| 572 | ba,pt %xcc, user_rtt_pre_restore; \ | ||
| 573 | restored; \ | ||
| 574 | nop; nop; nop; nop; nop; nop; \ | ||
| 575 | nop; nop; nop; nop; nop; \ | ||
| 576 | ba,a,pt %xcc, user_rtt_fill_fixup; \ | ||
| 577 | ba,a,pt %xcc, user_rtt_fill_fixup; \ | ||
| 578 | ba,a,pt %xcc, user_rtt_fill_fixup; | ||
| 579 | |||
| 580 | |||
| 359 | /* Normal 32bit fill */ | 581 | /* Normal 32bit fill */ |
| 360 | #define FILL_2_GENERIC(ASI) \ | 582 | #define FILL_2_GENERIC(ASI) \ |
| 361 | srl %sp, 0, %sp; \ | 583 | srl %sp, 0, %sp; \ |
| @@ -387,6 +609,34 @@ | |||
| 387 | b,a,pt %xcc, fill_fixup_mna; \ | 609 | b,a,pt %xcc, fill_fixup_mna; \ |
| 388 | b,a,pt %xcc, fill_fixup; | 610 | b,a,pt %xcc, fill_fixup; |
| 389 | 611 | ||
| 612 | #define FILL_2_GENERIC_RTRAP \ | ||
| 613 | user_rtt_fill_32bit: \ | ||
| 614 | srl %sp, 0, %sp; \ | ||
| 615 | lduwa [%sp + 0x00] %asi, %l0; \ | ||
| 616 | lduwa [%sp + 0x04] %asi, %l1; \ | ||
| 617 | lduwa [%sp + 0x08] %asi, %l2; \ | ||
| 618 | lduwa [%sp + 0x0c] %asi, %l3; \ | ||
| 619 | lduwa [%sp + 0x10] %asi, %l4; \ | ||
| 620 | lduwa [%sp + 0x14] %asi, %l5; \ | ||
| 621 | lduwa [%sp + 0x18] %asi, %l6; \ | ||
| 622 | lduwa [%sp + 0x1c] %asi, %l7; \ | ||
| 623 | lduwa [%sp + 0x20] %asi, %i0; \ | ||
| 624 | lduwa [%sp + 0x24] %asi, %i1; \ | ||
| 625 | lduwa [%sp + 0x28] %asi, %i2; \ | ||
| 626 | lduwa [%sp + 0x2c] %asi, %i3; \ | ||
| 627 | lduwa [%sp + 0x30] %asi, %i4; \ | ||
| 628 | lduwa [%sp + 0x34] %asi, %i5; \ | ||
| 629 | lduwa [%sp + 0x38] %asi, %i6; \ | ||
| 630 | lduwa [%sp + 0x3c] %asi, %i7; \ | ||
| 631 | ba,pt %xcc, user_rtt_pre_restore; \ | ||
| 632 | restored; \ | ||
| 633 | nop; nop; nop; nop; nop; \ | ||
| 634 | nop; nop; nop; nop; nop; \ | ||
| 635 | ba,a,pt %xcc, user_rtt_fill_fixup; \ | ||
| 636 | ba,a,pt %xcc, user_rtt_fill_fixup; \ | ||
| 637 | ba,a,pt %xcc, user_rtt_fill_fixup; | ||
| 638 | |||
| 639 | |||
| 390 | #define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP) | 640 | #define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP) |
| 391 | #define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP) | 641 | #define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP) |
| 392 | #define FILL_3_NORMAL FILL_0_NORMAL | 642 | #define FILL_3_NORMAL FILL_0_NORMAL |
diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h index c91d1e38eac6..afe236ba555b 100644 --- a/include/asm-sparc64/uaccess.h +++ b/include/asm-sparc64/uaccess.h | |||
| @@ -114,16 +114,6 @@ case 8: __put_user_asm(data,x,addr,__pu_ret); break; \ | |||
| 114 | default: __pu_ret = __put_user_bad(); break; \ | 114 | default: __pu_ret = __put_user_bad(); break; \ |
| 115 | } __pu_ret; }) | 115 | } __pu_ret; }) |
| 116 | 116 | ||
| 117 | #define __put_user_nocheck_ret(data,addr,size,retval) ({ \ | ||
| 118 | register int __foo __asm__ ("l1"); \ | ||
| 119 | switch (size) { \ | ||
| 120 | case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \ | ||
| 121 | case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \ | ||
| 122 | case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \ | ||
| 123 | case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \ | ||
| 124 | default: if (__put_user_bad()) return retval; break; \ | ||
| 125 | } }) | ||
| 126 | |||
| 127 | #define __put_user_asm(x,size,addr,ret) \ | 117 | #define __put_user_asm(x,size,addr,ret) \ |
| 128 | __asm__ __volatile__( \ | 118 | __asm__ __volatile__( \ |
| 129 | "/* Put user asm, inline. */\n" \ | 119 | "/* Put user asm, inline. */\n" \ |
| @@ -143,33 +133,6 @@ __asm__ __volatile__( \ | |||
| 143 | : "=r" (ret) : "r" (x), "r" (__m(addr)), \ | 133 | : "=r" (ret) : "r" (x), "r" (__m(addr)), \ |
| 144 | "i" (-EFAULT)) | 134 | "i" (-EFAULT)) |
| 145 | 135 | ||
| 146 | #define __put_user_asm_ret(x,size,addr,ret,foo) \ | ||
| 147 | if (__builtin_constant_p(ret) && ret == -EFAULT) \ | ||
| 148 | __asm__ __volatile__( \ | ||
| 149 | "/* Put user asm ret, inline. */\n" \ | ||
| 150 | "1:\t" "st"#size "a %1, [%2] %%asi\n\n\t" \ | ||
| 151 | ".section __ex_table,\"a\"\n\t" \ | ||
| 152 | ".align 4\n\t" \ | ||
| 153 | ".word 1b, __ret_efault\n\n\t" \ | ||
| 154 | ".previous\n\n\t" \ | ||
| 155 | : "=r" (foo) : "r" (x), "r" (__m(addr))); \ | ||
| 156 | else \ | ||
| 157 | __asm__ __volatile__( \ | ||
| 158 | "/* Put user asm ret, inline. */\n" \ | ||
| 159 | "1:\t" "st"#size "a %1, [%2] %%asi\n\n\t" \ | ||
| 160 | ".section .fixup,#alloc,#execinstr\n\t" \ | ||
| 161 | ".align 4\n" \ | ||
| 162 | "3:\n\t" \ | ||
| 163 | "ret\n\t" \ | ||
| 164 | " restore %%g0, %3, %%o0\n\n\t" \ | ||
| 165 | ".previous\n\t" \ | ||
| 166 | ".section __ex_table,\"a\"\n\t" \ | ||
| 167 | ".align 4\n\t" \ | ||
| 168 | ".word 1b, 3b\n\n\t" \ | ||
| 169 | ".previous\n\n\t" \ | ||
| 170 | : "=r" (foo) : "r" (x), "r" (__m(addr)), \ | ||
| 171 | "i" (ret)) | ||
| 172 | |||
| 173 | extern int __put_user_bad(void); | 136 | extern int __put_user_bad(void); |
| 174 | 137 | ||
| 175 | #define __get_user_nocheck(data,addr,size,type) ({ \ | 138 | #define __get_user_nocheck(data,addr,size,type) ({ \ |
| @@ -289,14 +252,7 @@ copy_in_user(void __user *to, void __user *from, unsigned long size) | |||
| 289 | } | 252 | } |
| 290 | #define __copy_in_user copy_in_user | 253 | #define __copy_in_user copy_in_user |
| 291 | 254 | ||
| 292 | extern unsigned long __must_check __bzero_noasi(void __user *, unsigned long); | 255 | extern unsigned long __must_check __clear_user(void __user *, unsigned long); |
| 293 | |||
| 294 | static inline unsigned long __must_check | ||
| 295 | __clear_user(void __user *addr, unsigned long size) | ||
| 296 | { | ||
| 297 | |||
| 298 | return __bzero_noasi(addr, size); | ||
| 299 | } | ||
| 300 | 256 | ||
| 301 | #define clear_user __clear_user | 257 | #define clear_user __clear_user |
| 302 | 258 | ||
diff --git a/include/asm-sparc64/vdev.h b/include/asm-sparc64/vdev.h new file mode 100644 index 000000000000..996e6be7b976 --- /dev/null +++ b/include/asm-sparc64/vdev.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | /* vdev.h: SUN4V virtual device interfaces and defines. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _SPARC64_VDEV_H | ||
| 7 | #define _SPARC64_VDEV_H | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | |||
| 11 | extern u32 sun4v_vdev_devhandle; | ||
| 12 | extern int sun4v_vdev_root; | ||
| 13 | |||
| 14 | extern unsigned int sun4v_vdev_device_interrupt(unsigned int); | ||
| 15 | |||
| 16 | #endif /* !(_SPARC64_VDEV_H) */ | ||
diff --git a/include/asm-sparc64/xor.h b/include/asm-sparc64/xor.h index 8b3a7e4b6062..8ce3f1813e28 100644 --- a/include/asm-sparc64/xor.h +++ b/include/asm-sparc64/xor.h | |||
| @@ -2,9 +2,11 @@ | |||
| 2 | * include/asm-sparc64/xor.h | 2 | * include/asm-sparc64/xor.h |
| 3 | * | 3 | * |
| 4 | * High speed xor_block operation for RAID4/5 utilizing the | 4 | * High speed xor_block operation for RAID4/5 utilizing the |
| 5 | * UltraSparc Visual Instruction Set. | 5 | * UltraSparc Visual Instruction Set and Niagara block-init |
| 6 | * twin-load instructions. | ||
| 6 | * | 7 | * |
| 7 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) | 8 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) |
| 9 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
| 8 | * | 10 | * |
| 9 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
| @@ -16,8 +18,7 @@ | |||
| 16 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 17 | */ | 19 | */ |
| 18 | 20 | ||
| 19 | #include <asm/pstate.h> | 21 | #include <asm/spitfire.h> |
| 20 | #include <asm/asi.h> | ||
| 21 | 22 | ||
| 22 | extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); | 23 | extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); |
| 23 | extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, | 24 | extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, |
| @@ -37,4 +38,29 @@ static struct xor_block_template xor_block_VIS = { | |||
| 37 | .do_5 = xor_vis_5, | 38 | .do_5 = xor_vis_5, |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | #define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS) | 41 | extern void xor_niagara_2(unsigned long, unsigned long *, unsigned long *); |
| 42 | extern void xor_niagara_3(unsigned long, unsigned long *, unsigned long *, | ||
| 43 | unsigned long *); | ||
| 44 | extern void xor_niagara_4(unsigned long, unsigned long *, unsigned long *, | ||
| 45 | unsigned long *, unsigned long *); | ||
| 46 | extern void xor_niagara_5(unsigned long, unsigned long *, unsigned long *, | ||
| 47 | unsigned long *, unsigned long *, unsigned long *); | ||
| 48 | |||
| 49 | static struct xor_block_template xor_block_niagara = { | ||
| 50 | .name = "Niagara", | ||
| 51 | .do_2 = xor_niagara_2, | ||
| 52 | .do_3 = xor_niagara_3, | ||
| 53 | .do_4 = xor_niagara_4, | ||
| 54 | .do_5 = xor_niagara_5, | ||
| 55 | }; | ||
| 56 | |||
| 57 | #undef XOR_TRY_TEMPLATES | ||
| 58 | #define XOR_TRY_TEMPLATES \ | ||
| 59 | do { \ | ||
| 60 | xor_speed(&xor_block_VIS); \ | ||
| 61 | xor_speed(&xor_block_niagara); \ | ||
| 62 | } while (0) | ||
| 63 | |||
| 64 | /* For VIS for everything except Niagara. */ | ||
| 65 | #define XOR_SELECT_TEMPLATE(FASTEST) \ | ||
| 66 | (tlb_type == hypervisor ? &xor_block_niagara : &xor_block_VIS) | ||
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 4041122dabfc..57abcea1cb5d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
| @@ -127,6 +127,9 @@ | |||
| 127 | /* Hilscher netx */ | 127 | /* Hilscher netx */ |
| 128 | #define PORT_NETX 71 | 128 | #define PORT_NETX 71 |
| 129 | 129 | ||
| 130 | /* SUN4V Hypervisor Console */ | ||
| 131 | #define PORT_SUNHV 72 | ||
| 132 | |||
| 130 | #ifdef __KERNEL__ | 133 | #ifdef __KERNEL__ |
| 131 | 134 | ||
| 132 | #include <linux/config.h> | 135 | #include <linux/config.h> |
