提交 c4a1745a 编写于 作者: L Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (230 commits)
  [SPARC64]: Update defconfig.
  [SPARC64]: Fix 2 bugs in huge page support.
  [SPARC64]: CONFIG_BLK_DEV_RAM fix
  [SPARC64]: Optimized TSB table initialization.
  [SPARC64]: Allow CONFIG_MEMORY_HOTPLUG to build.
  [SPARC64]: Use SLAB caches for TSB tables.
  [SPARC64]: Don't kill the page allocator when growing a TSB.
  [SPARC64]: Randomize mm->mmap_base when PF_RANDOMIZE is set.
  [SPARC64]: Increase top of 32-bit process stack.
  [SPARC64]: Top-down address space allocation for 32-bit tasks.
  [SPARC64] bbc_i2c: Fix cpu check and add missing module license.
  [SPARC64]: Fix and re-enable dynamic TSB sizing.
  [SUNSU]: Fix missing spinlock initialization.
  [TG3]: Do not try to access NIC_SRAM_DATA_SIG on Sun parts.
  [SPARC64]: First cut at VIS simulator for Niagara.
  [SPARC64]: Fix system type in /proc/cpuinfo and remove bogus OBP check.
  [SPARC64]: Add SMT scheduling support for Niagara.
  [SPARC64]: Fix 32-bit truncation which broke sparsemem.
  [SPARC64]: Move over to sparsemem.
  [SPARC64]: Fix new context version SMP handling.
  ...
...@@ -217,7 +217,7 @@ static void _sparc_free_io(struct resource *res) ...@@ -217,7 +217,7 @@ static void _sparc_free_io(struct resource *res)
unsigned long plen; unsigned long plen;
plen = res->end - res->start + 1; plen = res->end - res->start + 1;
if ((plen & (PAGE_SIZE-1)) != 0) BUG(); BUG_ON((plen & (PAGE_SIZE-1)) != 0);
sparc_unmapiorange(res->start, plen); sparc_unmapiorange(res->start, plen);
release_resource(res); release_resource(res);
} }
...@@ -512,8 +512,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) ...@@ -512,8 +512,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba)
dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
int direction) int direction)
{ {
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
/* IIep is write-through, not flushing. */ /* IIep is write-through, not flushing. */
return virt_to_phys(ptr); return virt_to_phys(ptr);
} }
...@@ -528,8 +527,7 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, ...@@ -528,8 +527,7 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size,
int direction) int direction)
{ {
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
if (direction != PCI_DMA_TODEVICE) { if (direction != PCI_DMA_TODEVICE) {
mmu_inval_dma_area((unsigned long)phys_to_virt(ba), mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
(size + PAGE_SIZE-1) & PAGE_MASK); (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,8 +540,7 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size,
dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
unsigned long offset, size_t size, int direction) unsigned long offset, size_t size, int direction)
{ {
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
/* IIep is write-through, not flushing. */ /* IIep is write-through, not flushing. */
return page_to_phys(page) + offset; return page_to_phys(page) + offset;
} }
...@@ -551,8 +548,7 @@ dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, ...@@ -551,8 +548,7 @@ dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
void pci_unmap_page(struct pci_dev *hwdev, void pci_unmap_page(struct pci_dev *hwdev,
dma_addr_t dma_address, size_t size, int direction) dma_addr_t dma_address, size_t size, int direction)
{ {
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
/* mmu_inval_dma_area XXX */ /* mmu_inval_dma_area XXX */
} }
...@@ -576,11 +572,10 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, ...@@ -576,11 +572,10 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
{ {
int n; int n;
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
/* IIep is write-through, not flushing. */ /* IIep is write-through, not flushing. */
for (n = 0; n < nents; n++) { for (n = 0; n < nents; n++) {
if (page_address(sg->page) == NULL) BUG(); BUG_ON(page_address(sg->page) == NULL);
sg->dvma_address = virt_to_phys(page_address(sg->page)); sg->dvma_address = virt_to_phys(page_address(sg->page));
sg->dvma_length = sg->length; sg->dvma_length = sg->length;
sg++; sg++;
...@@ -597,11 +592,10 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, ...@@ -597,11 +592,10 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
{ {
int n; int n;
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
if (direction != PCI_DMA_TODEVICE) { if (direction != PCI_DMA_TODEVICE) {
for (n = 0; n < nents; n++) { for (n = 0; n < nents; n++) {
if (page_address(sg->page) == NULL) BUG(); BUG_ON(page_address(sg->page) == NULL);
mmu_inval_dma_area( mmu_inval_dma_area(
(unsigned long) page_address(sg->page), (unsigned long) page_address(sg->page),
(sg->length + PAGE_SIZE-1) & PAGE_MASK); (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,8 +616,7 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
*/ */
void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
{ {
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
if (direction != PCI_DMA_TODEVICE) { if (direction != PCI_DMA_TODEVICE) {
mmu_inval_dma_area((unsigned long)phys_to_virt(ba), mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
(size + PAGE_SIZE-1) & PAGE_MASK); (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,8 +625,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t si
void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
{ {
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
if (direction != PCI_DMA_TODEVICE) { if (direction != PCI_DMA_TODEVICE) {
mmu_inval_dma_area((unsigned long)phys_to_virt(ba), mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
(size + PAGE_SIZE-1) & PAGE_MASK); (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,11 +642,10 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int
{ {
int n; int n;
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
if (direction != PCI_DMA_TODEVICE) { if (direction != PCI_DMA_TODEVICE) {
for (n = 0; n < nents; n++) { for (n = 0; n < nents; n++) {
if (page_address(sg->page) == NULL) BUG(); BUG_ON(page_address(sg->page) == NULL);
mmu_inval_dma_area( mmu_inval_dma_area(
(unsigned long) page_address(sg->page), (unsigned long) page_address(sg->page),
(sg->length + PAGE_SIZE-1) & PAGE_MASK); (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,11 +658,10 @@ void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, i
{ {
int n; int n;
if (direction == PCI_DMA_NONE) BUG_ON(direction == PCI_DMA_NONE);
BUG();
if (direction != PCI_DMA_TODEVICE) { if (direction != PCI_DMA_TODEVICE) {
for (n = 0; n < nents; n++) { for (n = 0; n < nents; n++) {
if (page_address(sg->page) == NULL) BUG(); BUG_ON(page_address(sg->page) == NULL);
mmu_inval_dma_area( mmu_inval_dma_area(
(unsigned long) page_address(sg->page), (unsigned long) page_address(sg->page),
(sg->length + PAGE_SIZE-1) & PAGE_MASK); (sg->length + PAGE_SIZE-1) & PAGE_MASK);
......
...@@ -186,6 +186,15 @@ endchoice ...@@ -186,6 +186,15 @@ endchoice
endmenu endmenu
config ARCH_SPARSEMEM_ENABLE
def_bool y
config ARCH_SPARSEMEM_DEFAULT
def_bool y
config LARGE_ALLOCS
def_bool y
source "mm/Kconfig" source "mm/Kconfig"
config GENERIC_ISA_DMA config GENERIC_ISA_DMA
...@@ -350,6 +359,15 @@ config SOLARIS_EMUL ...@@ -350,6 +359,15 @@ config SOLARIS_EMUL
endmenu endmenu
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on SMP
default y
help
SMT scheduler support improves the CPU scheduler's decision making
when dealing with UltraSPARC cpus at a cost of slightly increased
overhead in some places. If unsure say N here.
config CMDLINE_BOOL config CMDLINE_BOOL
bool "Default bootloader kernel arguments" bool "Default bootloader kernel arguments"
......
# #
# Automatically generated make config: don't edit # Automatically generated make config: don't edit
# Linux kernel version: 2.6.16-rc2 # Linux kernel version: 2.6.16
# Tue Feb 7 17:47:18 2006 # Mon Mar 20 01:23:21 2006
# #
CONFIG_SPARC=y CONFIG_SPARC=y
CONFIG_SPARC64=y CONFIG_SPARC64=y
...@@ -115,14 +115,20 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y ...@@ -115,14 +115,20 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HUGETLB_PAGE_SIZE_4MB=y CONFIG_HUGETLB_PAGE_SIZE_4MB=y
# CONFIG_HUGETLB_PAGE_SIZE_512K is not set # CONFIG_HUGETLB_PAGE_SIZE_512K is not set
# CONFIG_HUGETLB_PAGE_SIZE_64K is not set # CONFIG_HUGETLB_PAGE_SIZE_64K is not set
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_LARGE_ALLOCS=y
CONFIG_SELECT_MEMORY_MODEL=y CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y # CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set # CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set CONFIG_SPARSEMEM_MANUAL=y
CONFIG_FLATMEM=y CONFIG_SPARSEMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set # CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_ISA_DMA=y
CONFIG_SBUS=y CONFIG_SBUS=y
CONFIG_SBUSCHAR=y CONFIG_SBUSCHAR=y
...@@ -655,6 +661,7 @@ CONFIG_SERIAL_SUNCORE=y ...@@ -655,6 +661,7 @@ CONFIG_SERIAL_SUNCORE=y
CONFIG_SERIAL_SUNSU=y CONFIG_SERIAL_SUNSU=y
CONFIG_SERIAL_SUNSU_CONSOLE=y CONFIG_SERIAL_SUNSU_CONSOLE=y
CONFIG_SERIAL_SUNSAB=m CONFIG_SERIAL_SUNSAB=m
CONFIG_SERIAL_SUNHV=y
CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set # CONFIG_SERIAL_JSM is not set
...@@ -1116,11 +1123,7 @@ CONFIG_USB_HIDDEV=y ...@@ -1116,11 +1123,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_INFINIBAND is not set # CONFIG_INFINIBAND is not set
# #
# SN Devices # EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
#
#
# EDAC - error detection and reporting (RAS)
# #
# #
......
...@@ -11,10 +11,12 @@ obj-y := process.o setup.o cpu.o idprom.o \ ...@@ -11,10 +11,12 @@ obj-y := process.o setup.o cpu.o idprom.o \
traps.o devices.o auxio.o una_asm.o \ traps.o devices.o auxio.o una_asm.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \ unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
visemul.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o
obj-$(CONFIG_SMP) += smp.o trampoline.o obj-$(CONFIG_SMP) += smp.o trampoline.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
...@@ -38,5 +40,5 @@ else ...@@ -38,5 +40,5 @@ else
CMODEL_CFLAG := -m64 -mcmodel=medlow CMODEL_CFLAG := -m64 -mcmodel=medlow
endif endif
head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \ head.o: head.S ttable.S itlb_miss.S dtlb_miss.S ktlb.S tsb.S \
etrap.S rtrap.S winfixup.S entry.S etrap.S rtrap.S winfixup.S entry.S
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/mmu_context.h>
static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout32_library(struct file*); 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,6 +239,8 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(current->mm->start_data = N_DATADDR(ex)); (current->mm->start_data = N_DATADDR(ex));
current->mm->brk = ex.a_bss + current->mm->brk = ex.a_bss +
(current->mm->start_brk = N_BSSADDR(ex)); (current->mm->start_brk = N_BSSADDR(ex));
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;
current->mm->mmap = NULL; current->mm->mmap = NULL;
compute_creds(bprm); compute_creds(bprm);
...@@ -329,15 +332,8 @@ beyond_if: ...@@ -329,15 +332,8 @@ beyond_if:
current->mm->start_stack = current->mm->start_stack =
(unsigned long) create_aout32_tables((char __user *)bprm->p, bprm); (unsigned long) create_aout32_tables((char __user *)bprm->p, bprm);
if (!(orig_thr_flags & _TIF_32BIT)) { tsb_context_switch(current->mm);
unsigned long pgd_cache = get_pgd_cache(current->mm->pgd);
__asm__ __volatile__("stxa\t%0, [%1] %2\n\t"
"membar #Sync"
: /* no outputs */
: "r" (pgd_cache),
"r" (TSB_REG), "i" (ASI_DMMU));
}
start_thread32(regs, ex.a_entry, current->mm->start_stack); start_thread32(regs, ex.a_entry, current->mm->start_stack);
if (current->ptrace & PT_PTRACED) if (current->ptrace & PT_PTRACED)
send_sig(SIGTRAP, current, 0); send_sig(SIGTRAP, current, 0);
......
...@@ -153,7 +153,9 @@ MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); ...@@ -153,7 +153,9 @@ MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
#undef MODULE_DESCRIPTION #undef MODULE_DESCRIPTION
#undef MODULE_AUTHOR #undef MODULE_AUTHOR
#include <asm/a.out.h>
#undef TASK_SIZE #undef TASK_SIZE
#define TASK_SIZE 0xf0000000 #define TASK_SIZE STACK_TOP32
#include "../../../fs/binfmt_elf.c" #include "../../../fs/binfmt_elf.c"
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/fpumacro.h> #include <asm/fpumacro.h>
#include <asm/cpudata.h> #include <asm/cpudata.h>
#include <asm/spitfire.h>
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
...@@ -71,6 +72,12 @@ void __init cpu_probe(void) ...@@ -71,6 +72,12 @@ void __init cpu_probe(void)
unsigned long ver, fpu_vers, manuf, impl, fprs; unsigned long ver, fpu_vers, manuf, impl, fprs;
int i; int i;
if (tlb_type == hypervisor) {
sparc_cpu_type = "UltraSparc T1 (Niagara)";
sparc_fpu_type = "UltraSparc T1 integrated FPU";
return;
}
fprs = fprs_read(); fprs = fprs_read();
fprs_write(FPRS_FEF); fprs_write(FPRS_FEF);
__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/bootmem.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/oplib.h> #include <asm/oplib.h>
...@@ -20,6 +21,8 @@ ...@@ -20,6 +21,8 @@
#include <asm/spitfire.h> #include <asm/spitfire.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/cpudata.h> #include <asm/cpudata.h>
#include <asm/vdev.h>
#include <asm/irq.h>
/* Used to synchronize acceses to NatSemi SUPER I/O chip configure /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
* operations in asm/ns87303.h * operations in asm/ns87303.h
...@@ -29,13 +32,158 @@ DEFINE_SPINLOCK(ns87303_lock); ...@@ -29,13 +32,158 @@ DEFINE_SPINLOCK(ns87303_lock);
extern void cpu_probe(void); extern void cpu_probe(void);
extern void central_probe(void); extern void central_probe(void);
static char *cpu_mid_prop(void) u32 sun4v_vdev_devhandle;
int sun4v_vdev_root;
struct vdev_intmap {
unsigned int phys;
unsigned int irq;
unsigned int cnode;
unsigned int cinterrupt;
};
struct vdev_intmask {
unsigned int phys;
unsigned int interrupt;
unsigned int __unused;
};
static struct vdev_intmap *vdev_intmap;
static int vdev_num_intmap;
static struct vdev_intmask vdev_intmask;
static void __init sun4v_virtual_device_probe(void)
{
struct linux_prom64_registers regs;
struct vdev_intmap *ip;
int node, sz, err;
if (tlb_type != hypervisor)
return;
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "virtual-devices");
if (!node) {
prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
prom_halt();
}
sun4v_vdev_root = node;
prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
sz = prom_getproplen(node, "interrupt-map");
if (sz <= 0) {
prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
prom_halt();
}
if ((sz % sizeof(*ip)) != 0) {
prom_printf("SUN4V: Bogus interrupt-map property size %d\n",
sz);
prom_halt();
}
vdev_intmap = ip = alloc_bootmem_low_pages(sz);
if (!vdev_intmap) {
prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n");
prom_halt();
}
err = prom_getproperty(node, "interrupt-map", (char *) ip, sz);
if (err == -1) {
prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n");
prom_halt();
}
if (err != sz) {
prom_printf("SUN4V: Inconsistent interrupt-map size, "
"proplen(%d) vs getprop(%d).\n", sz,err);
prom_halt();
}
vdev_num_intmap = err / sizeof(*ip);
err = prom_getproperty(node, "interrupt-map-mask",
(char *) &vdev_intmask,
sizeof(vdev_intmask));
if (err <= 0) {
prom_printf("SUN4V: Fatal error, no vdev "
"interrupt-map-mask.\n");
prom_halt();
}
if (err % sizeof(vdev_intmask)) {
prom_printf("SUN4V: Bogus interrupt-map-mask "
"property size %d\n", err);
prom_halt();
}
printk("SUN4V: virtual-devices devhandle[%x]\n",
sun4v_vdev_devhandle);
}
unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
{
unsigned int irq, reg;
int err, i;
err = prom_getproperty(dev_node, "interrupts",
(char *) &irq, sizeof(irq));
if (err <= 0) {
printk("VDEV: Cannot get \"interrupts\" "
"property for OBP node %x\n", dev_node);
return 0;
}
err = prom_getproperty(dev_node, "reg",
(char *) &reg, sizeof(reg));
if (err <= 0) {
printk("VDEV: Cannot get \"reg\" "
"property for OBP node %x\n", dev_node);
return 0;
}
for (i = 0; i < vdev_num_intmap; i++) {
if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) &&
vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) {
irq = vdev_intmap[i].cinterrupt;
break;
}
}
if (i == vdev_num_intmap) {
printk("VDEV: No matching interrupt map entry "
"for OBP node %x\n", dev_node);
return 0;
}
return sun4v_build_irq(sun4v_vdev_devhandle, irq, 5, 0);
}
static const char *cpu_mid_prop(void)
{ {
if (tlb_type == spitfire) if (tlb_type == spitfire)
return "upa-portid"; return "upa-portid";
return "portid"; return "portid";
} }
static int get_cpu_mid(int prom_node)
{
if (tlb_type == hypervisor) {
struct linux_prom64_registers reg;
if (prom_getproplen(prom_node, "cpuid") == 4)
return prom_getintdefault(prom_node, "cpuid", 0);
prom_getproperty(prom_node, "reg", (char *) &reg, sizeof(reg));
return (reg.phys_addr >> 32) & 0x0fffffffUL;
} else {
const char *prop_name = cpu_mid_prop();
return prom_getintdefault(prom_node, prop_name, 0);
}
}
static int check_cpu_node(int nd, int *cur_inst, static int check_cpu_node(int nd, int *cur_inst,
int (*compare)(int, int, void *), void *compare_arg, int (*compare)(int, int, void *), void *compare_arg,
int *prom_node, int *mid) int *prom_node, int *mid)
...@@ -50,7 +198,7 @@ static int check_cpu_node(int nd, int *cur_inst, ...@@ -50,7 +198,7 @@ static int check_cpu_node(int nd, int *cur_inst,
if (prom_node) if (prom_node)
*prom_node = nd; *prom_node = nd;
if (mid) if (mid)
*mid = prom_getintdefault(nd, cpu_mid_prop(), 0); *mid = get_cpu_mid(nd);
return 0; return 0;
} }
...@@ -105,7 +253,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg) ...@@ -105,7 +253,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg)
int desired_mid = (int) (long) _arg; int desired_mid = (int) (long) _arg;
int this_mid; int this_mid;
this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0); this_mid = get_cpu_mid(nd);
if (this_mid == desired_mid) if (this_mid == desired_mid)
return 0; return 0;
return -ENODEV; return -ENODEV;
...@@ -126,7 +274,8 @@ void __init device_scan(void) ...@@ -126,7 +274,8 @@ void __init device_scan(void)
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
{ {
int err, cpu_node; int err, cpu_node, def;
err = cpu_find_by_instance(0, &cpu_node, NULL); err = cpu_find_by_instance(0, &cpu_node, NULL);
if (err) { if (err) {
prom_printf("No cpu nodes, cannot continue\n"); prom_printf("No cpu nodes, cannot continue\n");
...@@ -135,21 +284,40 @@ void __init device_scan(void) ...@@ -135,21 +284,40 @@ void __init device_scan(void)
cpu_data(0).clock_tick = prom_getintdefault(cpu_node, cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
"clock-frequency", "clock-frequency",
0); 0);
def = ((tlb_type == hypervisor) ?
(8 * 1024) :
(16 * 1024));
cpu_data(0).dcache_size = prom_getintdefault(cpu_node, cpu_data(0).dcache_size = prom_getintdefault(cpu_node,
"dcache-size", "dcache-size",
16 * 1024); def);
def = 32;
cpu_data(0).dcache_line_size = cpu_data(0).dcache_line_size =
prom_getintdefault(cpu_node, "dcache-line-size", 32); prom_getintdefault(cpu_node, "dcache-line-size",
def);
def = 16 * 1024;
cpu_data(0).icache_size = prom_getintdefault(cpu_node, cpu_data(0).icache_size = prom_getintdefault(cpu_node,
"icache-size", "icache-size",
16 * 1024); def);
def = 32;
cpu_data(0).icache_line_size = cpu_data(0).icache_line_size =
prom_getintdefault(cpu_node, "icache-line-size", 32); prom_getintdefault(cpu_node, "icache-line-size",
def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
cpu_data(0).ecache_size = prom_getintdefault(cpu_node, cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
"ecache-size", "ecache-size",
4 * 1024 * 1024); def);
def = 64;
cpu_data(0).ecache_line_size = cpu_data(0).ecache_line_size =
prom_getintdefault(cpu_node, "ecache-line-size", 64); prom_getintdefault(cpu_node, "ecache-line-size",
def);
printk("CPU[0]: Caches " printk("CPU[0]: Caches "
"D[sz(%d):line_sz(%d)] " "D[sz(%d):line_sz(%d)] "
"I[sz(%d):line_sz(%d)] " "I[sz(%d):line_sz(%d)] "
...@@ -160,6 +328,7 @@ void __init device_scan(void) ...@@ -160,6 +328,7 @@ void __init device_scan(void)
} }
#endif #endif
sun4v_virtual_device_probe();
central_probe(); central_probe();
cpu_probe(); cpu_probe();
......
/* $Id: dtlb_backend.S,v 1.16 2001/10/09 04:02:11 davem Exp $
* dtlb_backend.S: Back end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
* Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <asm/pgtable.h>
#include <asm/mmu.h>
#define VALID_SZ_BITS (_PAGE_VALID | _PAGE_SZBITS)
#define VPTE_BITS (_PAGE_CP | _PAGE_CV | _PAGE_P )
#define VPTE_SHIFT (PAGE_SHIFT - 3)
/* Ways we can get here:
*
* 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1.
* 2) Nucleus loads and stores to/from user/kernel window save areas.
* 3) VPTE misses from dtlb_base and itlb_base.
*
* We need to extract out the PMD and PGDIR indexes from the
* linear virtual page table access address. The PTE index
* is at the bottom, but we are not concerned with it. Bits
* 0 to 2 are clear since each PTE is 8 bytes in size. Each
* PMD and PGDIR entry are 4 bytes in size. Thus, this
* address looks something like:
*
* |---------------------------------------------------------------|
* | ... | PGDIR index | PMD index | PTE index | |
* |---------------------------------------------------------------|
* 63 F E D C B A 3 2 0 <- bit nr
*
* The variable bits above are defined as:
* A --> 3 + (PAGE_SHIFT - log2(8))
* --> 3 + (PAGE_SHIFT - 3) - 1
* (ie. this is "bit 3" + PAGE_SIZE - size of PTE entry in bits - 1)
* B --> A + 1
* C --> B + (PAGE_SHIFT - log2(4))
* --> B + (PAGE_SHIFT - 2) - 1
* (ie. this is "bit B" + PAGE_SIZE - size of PMD entry in bits - 1)
* D --> C + 1
* E --> D + (PAGE_SHIFT - log2(4))
* --> D + (PAGE_SHIFT - 2) - 1
* (ie. this is "bit D" + PAGE_SIZE - size of PGDIR entry in bits - 1)
* F --> E + 1
*
* (Note how "B" always evalutes to PAGE_SHIFT, all the other constants
* cancel out.)
*
* For 8K PAGE_SIZE (thus, PAGE_SHIFT of 13) the bit numbers are:
* A --> 12
* B --> 13
* C --> 23
* D --> 24
* E --> 34
* F --> 35
*
* For 64K PAGE_SIZE (thus, PAGE_SHIFT of 16) the bit numbers are:
* A --> 15
* B --> 16
* C --> 29
* D --> 30
* E --> 43
* F --> 44
*
* Because bits both above and below each PGDIR and PMD index need to
* be masked out, and the index can be as long as 14 bits (when using a
* 64K PAGE_SIZE, and thus a PAGE_SHIFT of 16), we need 3 instructions
* to extract each index out.
*
* Shifts do not pair very well on UltraSPARC-I, II, IIi, and IIe, so
* we try to avoid using them for the entire operation. We could setup
* a mask anywhere from bit 31 down to bit 10 using the sethi instruction.
*
* We need a mask covering bits B --> C and one covering D --> E.
* For 8K PAGE_SIZE these masks are 0x00ffe000 and 0x7ff000000.
* For 64K PAGE_SIZE these masks are 0x3fff0000 and 0xfffc0000000.
* The second in each set cannot be loaded with a single sethi
* instruction, because the upper bits are past bit 32. We would
* need to use a sethi + a shift.
*
* For the time being, we use 2 shifts and a simple "and" mask.
* We shift left to clear the bits above the index, we shift down
* to clear the bits below the index (sans the log2(4 or 8) bits)
* and a mask to clear the log2(4 or 8) bits. We need therefore
* define 4 shift counts, all of which are relative to PAGE_SHIFT.
*
* Although unsupportable for other reasons, this does mean that
* 512K and 4MB page sizes would be generaally supported by the
* kernel. (ELF binaries would break with > 64K PAGE_SIZE since
* the sections are only aligned that strongly).
*
* The operations performed for extraction are thus:
*
* ((X << FOO_SHIFT_LEFT) >> FOO_SHIFT_RIGHT) & ~0x3
*
*/
#define A (3 + (PAGE_SHIFT - 3) - 1)
#define B (A + 1)
#define C (B + (PAGE_SHIFT - 2) - 1)
#define D (C + 1)
#define E (D + (PAGE_SHIFT - 2) - 1)
#define F (E + 1)
#define PMD_SHIFT_LEFT (64 - D)
#define PMD_SHIFT_RIGHT (64 - (D - B) - 2)
#define PGDIR_SHIFT_LEFT (64 - F)
#define PGDIR_SHIFT_RIGHT (64 - (F - D) - 2)
#define LOW_MASK_BITS 0x3
/* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss */
ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS
add %g3, %g3, %g5 ! Compute VPTE base
cmp %g4, %g5 ! VPTE miss?
bgeu,pt %xcc, 1f ! Continue here
andcc %g4, TAG_CONTEXT_BITS, %g5 ! tl0 miss Nucleus test
ba,a,pt %xcc, from_tl1_trap ! Fall to tl0 miss
1: sllx %g6, VPTE_SHIFT, %g4 ! Position TAG_ACCESS
or %g4, %g5, %g4 ! Prepare TAG_ACCESS
/* TLB1 ** ICACHE line 2: Quick VPTE miss */
mov TSB_REG, %g1 ! Grab TSB reg
ldxa [%g1] ASI_DMMU, %g5 ! Doing PGD caching?
sllx %g6, PMD_SHIFT_LEFT, %g1 ! Position PMD offset
be,pn %xcc, sparc64_vpte_nucleus ! Is it from Nucleus?
srlx %g1, PMD_SHIFT_RIGHT, %g1 ! Mask PMD offset bits
brnz,pt %g5, sparc64_vpte_continue ! Yep, go like smoke
andn %g1, LOW_MASK_BITS, %g1 ! Final PMD mask
sllx %g6, PGDIR_SHIFT_LEFT, %g5 ! Position PGD offset
/* TLB1 ** ICACHE line 3: Quick VPTE miss */
srlx %g5, PGDIR_SHIFT_RIGHT, %g5 ! Mask PGD offset bits
andn %g5, LOW_MASK_BITS, %g5 ! Final PGD mask
lduwa [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
brz,pn %g5, vpte_noent ! Valid?
sparc64_kpte_continue:
sllx %g5, 11, %g5 ! Shift into place
sparc64_vpte_continue:
lduwa [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
sllx %g5, 11, %g5 ! Shift into place
brz,pn %g5, vpte_noent ! Valid?
/* TLB1 ** ICACHE line 4: Quick VPTE miss */
mov (VALID_SZ_BITS >> 61), %g1 ! upper vpte into %g1
sllx %g1, 61, %g1 ! finish calc
or %g5, VPTE_BITS, %g5 ! Prepare VPTE data
or %g5, %g1, %g5 ! ...
mov TLB_SFSR, %g1 ! Restore %g1 value
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load VPTE into TLB
stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS
retry ! Load PTE once again
#undef VALID_SZ_BITS
#undef VPTE_SHIFT
#undef VPTE_BITS
#undef A
#undef B
#undef C
#undef D
#undef E
#undef F
#undef PMD_SHIFT_LEFT
#undef PMD_SHIFT_RIGHT
#undef PGDIR_SHIFT_LEFT
#undef PGDIR_SHIFT_RIGHT
#undef LOW_MASK_BITS
/* $Id: dtlb_base.S,v 1.17 2001/10/11 22:33:52 davem Exp $
* dtlb_base.S: Front end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
* Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <asm/pgtable.h>
#include <asm/mmu.h>
/* %g1 TLB_SFSR (%g1 + %g1 == TLB_TAG_ACCESS)
* %g2 (KERN_HIGHBITS | KERN_LOWBITS)
* %g3 VPTE base (0xfffffffe00000000) Spitfire/Blackbird (44-bit VA space)
* (0xffe0000000000000) Cheetah (64-bit VA space)
* %g7 __pa(current->mm->pgd)
*
* The VPTE base value is completely magic, but note that
* few places in the kernel other than these TLB miss
* handlers know anything about the VPTE mechanism or
* how it works (see VPTE_SIZE, TASK_SIZE and PTRS_PER_PGD).
* Consider the 44-bit VADDR Ultra-I/II case as an example:
*
* VA[0 : (1<<43)] produce VPTE index [%g3 : 0]
* VA[0 : -(1<<43)] produce VPTE index [%g3-(1<<(43-PAGE_SHIFT+3)) : %g3]
*
* For Cheetah's 64-bit VADDR space this is:
*
* VA[0 : (1<<63)] produce VPTE index [%g3 : 0]
* VA[0 : -(1<<63)] produce VPTE index [%g3-(1<<(63-PAGE_SHIFT+3)) : %g3]
*
* If you're paying attention you'll notice that this means half of
* the VPTE table is above %g3 and half is below, low VA addresses
* map progressively upwards from %g3, and high VA addresses map
* progressively upwards towards %g3. This trick was needed to make
* the same 8 instruction handler work both for Spitfire/Blackbird's
* peculiar VA space hole configuration and the full 64-bit VA space
* one of Cheetah at the same time.
*/
/* Ways we can get here:
*
* 1) Nucleus loads and stores to/from PA-->VA direct mappings.
* 2) Nucleus loads and stores to/from vmalloc() areas.
* 3) User loads and stores.
* 4) User space accesses by nucleus at tl0
*/
#if PAGE_SHIFT == 13
/*
* To compute vpte offset, we need to do ((addr >> 13) << 3),
* which can be optimized to (addr >> 10) if bits 10/11/12 can
* be guaranteed to be 0 ... mmu_context.h does guarantee this
* by only using 10 bits in the hwcontext value.
*/
#define CREATE_VPTE_OFFSET1(r1, r2) nop
#define CREATE_VPTE_OFFSET2(r1, r2) \
srax r1, 10, r2
#else
#define CREATE_VPTE_OFFSET1(r1, r2) \
srax r1, PAGE_SHIFT, r2
#define CREATE_VPTE_OFFSET2(r1, r2) \
sllx r2, 3, r2
#endif
/* DTLB ** ICACHE line 1: Quick user TLB misses */
mov TLB_SFSR, %g1
ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS
andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus?
from_tl1_trap:
rdpr %tl, %g5 ! For TL==3 test
CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset
be,pn %xcc, kvmap ! Yep, special processing
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
cmp %g5, 4 ! Last trap level?
/* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */
be,pn %xcc, longpath ! Yep, cannot risk VPTE miss
nop ! delay slot
ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE
1: brgez,pn %g5, longpath ! Invalid, branch out
nop ! Delay-slot
9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
retry ! Trap return
nop
/* DTLB ** ICACHE line 3: winfixups+real_faults */
longpath:
rdpr %pstate, %g5 ! Move into alternate globals
wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tl, %g4 ! See where we came from.
cmp %g4, 1 ! Is etrap/rtrap window fault?
mov TLB_TAG_ACCESS, %g4 ! Prepare for fault processing
ldxa [%g4] ASI_DMMU, %g5 ! Load faulting VA page
be,pt %xcc, sparc64_realfault_common ! Jump to normal fault handling
mov FAULT_CODE_DTLB, %g4 ! It was read from DTLB
/* DTLB ** ICACHE line 4: Unused... */
ba,a,pt %xcc, winfix_trampoline ! Call window fixup code
nop
nop
nop
nop
nop
nop
nop
#undef CREATE_VPTE_OFFSET1
#undef CREATE_VPTE_OFFSET2
/* DTLB ** ICACHE line 1: Context 0 check and TSB load */
ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! Get TSB 8K pointer
ldxa [%g0] ASI_DMMU, %g6 ! Get TAG TARGET
srlx %g6, 48, %g5 ! Get context
sllx %g6, 22, %g6 ! Zero out context
brz,pn %g5, kvmap_dtlb ! Context 0 processing
srlx %g6, 22, %g6 ! Delay slot
TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry
cmp %g4, %g6 ! Compare TAG
/* DTLB ** ICACHE line 2: TSB compare and TLB load */
bne,pn %xcc, tsb_miss_dtlb ! Miss
mov FAULT_CODE_DTLB, %g3
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load TLB
retry ! Trap done
nop
nop
nop
nop
/* DTLB ** ICACHE line 3: */
nop
nop
nop
nop
nop
nop
nop
nop
/* DTLB ** ICACHE line 4: */
nop
nop
nop
nop
nop
nop
nop
nop
...@@ -277,10 +277,9 @@ static inline void *ebus_alloc(size_t size) ...@@ -277,10 +277,9 @@ static inline void *ebus_alloc(size_t size)
{ {
void *mem; void *mem;
mem = kmalloc(size, GFP_ATOMIC); mem = kzalloc(size, GFP_ATOMIC);
if (!mem) if (!mem)
panic("ebus_alloc: out of memory"); panic("ebus_alloc: out of memory");
memset((char *)mem, 0, size);
return mem; return mem;
} }
......
...@@ -50,7 +50,8 @@ do_fpdis: ...@@ -50,7 +50,8 @@ do_fpdis:
add %g0, %g0, %g0 add %g0, %g0, %g0
ba,a,pt %xcc, rtrap_clr_l6 ba,a,pt %xcc, rtrap_clr_l6
1: ldub [%g6 + TI_FPSAVED], %g5 1: TRAP_LOAD_THREAD_REG(%g6, %g1)
ldub [%g6 + TI_FPSAVED], %g5
wr %g0, FPRS_FEF, %fprs wr %g0, FPRS_FEF, %fprs
andcc %g5, FPRS_FEF, %g0 andcc %g5, FPRS_FEF, %g0
be,a,pt %icc, 1f be,a,pt %icc, 1f
...@@ -96,10 +97,22 @@ do_fpdis: ...@@ -96,10 +97,22 @@ do_fpdis:
add %g6, TI_FPREGS + 0x80, %g1 add %g6, TI_FPREGS + 0x80, %g1
faddd %f0, %f2, %f4 faddd %f0, %f2, %f4
fmuld %f0, %f2, %f6 fmuld %f0, %f2, %f6
ldxa [%g3] ASI_DMMU, %g5
661: ldxa [%g3] ASI_DMMU, %g5
.section .sun4v_1insn_patch, "ax"
.word 661b
ldxa [%g3] ASI_MMU, %g5
.previous
sethi %hi(sparc64_kern_sec_context), %g2 sethi %hi(sparc64_kern_sec_context), %g2
ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
stxa %g2, [%g3] ASI_DMMU
661: stxa %g2, [%g3] ASI_DMMU
.section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g2, [%g3] ASI_MMU
.previous
membar #Sync membar #Sync
add %g6, TI_FPREGS + 0xc0, %g2 add %g6, TI_FPREGS + 0xc0, %g2
faddd %f0, %f2, %f8 faddd %f0, %f2, %f8
...@@ -125,11 +138,23 @@ do_fpdis: ...@@ -125,11 +138,23 @@ do_fpdis:
fzero %f32 fzero %f32
mov SECONDARY_CONTEXT, %g3 mov SECONDARY_CONTEXT, %g3
fzero %f34 fzero %f34
ldxa [%g3] ASI_DMMU, %g5
661: ldxa [%g3] ASI_DMMU, %g5
.section .sun4v_1insn_patch, "ax"
.word 661b
ldxa [%g3] ASI_MMU, %g5
.previous
add %g6, TI_FPREGS, %g1 add %g6, TI_FPREGS, %g1
sethi %hi(sparc64_kern_sec_context), %g2 sethi %hi(sparc64_kern_sec_context), %g2
ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
stxa %g2, [%g3] ASI_DMMU
661: stxa %g2, [%g3] ASI_DMMU
.section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g2, [%g3] ASI_MMU
.previous
membar #Sync membar #Sync
add %g6, TI_FPREGS + 0x40, %g2 add %g6, TI_FPREGS + 0x40, %g2
faddd %f32, %f34, %f36 faddd %f32, %f34, %f36
...@@ -154,10 +179,22 @@ do_fpdis: ...@@ -154,10 +179,22 @@ do_fpdis:
nop nop
3: mov SECONDARY_CONTEXT, %g3 3: mov SECONDARY_CONTEXT, %g3
add %g6, TI_FPREGS, %g1 add %g6, TI_FPREGS, %g1
ldxa [%g3] ASI_DMMU, %g5
661: ldxa [%g3] ASI_DMMU, %g5
.section .sun4v_1insn_patch, "ax"
.word 661b
ldxa [%g3] ASI_MMU, %g5
.previous
sethi %hi(sparc64_kern_sec_context), %g2 sethi %hi(sparc64_kern_sec_context), %g2
ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
stxa %g2, [%g3] ASI_DMMU
661: stxa %g2, [%g3] ASI_DMMU
.section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g2, [%g3] ASI_MMU
.previous
membar #Sync membar #Sync
mov 0x40, %g2 mov 0x40, %g2
membar #Sync membar #Sync
...@@ -168,7 +205,13 @@ do_fpdis: ...@@ -168,7 +205,13 @@ do_fpdis:
ldda [%g1 + %g2] ASI_BLK_S, %f48 ldda [%g1 + %g2] ASI_BLK_S, %f48
membar #Sync membar #Sync
fpdis_exit: fpdis_exit:
stxa %g5, [%g3] ASI_DMMU
661: stxa %g5, [%g3] ASI_DMMU
.section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g5, [%g3] ASI_MMU
.previous
membar #Sync membar #Sync
fpdis_exit2: fpdis_exit2:
wr %g7, 0, %gsr wr %g7, 0, %gsr
...@@ -189,6 +232,7 @@ fp_other_bounce: ...@@ -189,6 +232,7 @@ fp_other_bounce:
.globl do_fpother_check_fitos .globl do_fpother_check_fitos
.align 32 .align 32
do_fpother_check_fitos: do_fpother_check_fitos:
TRAP_LOAD_THREAD_REG(%g6, %g1)
sethi %hi(fp_other_bounce - 4), %g7 sethi %hi(fp_other_bounce - 4), %g7
or %g7, %lo(fp_other_bounce - 4), %g7 or %g7, %lo(fp_other_bounce - 4), %g7
...@@ -312,6 +356,7 @@ fitos_emul_fini: ...@@ -312,6 +356,7 @@ fitos_emul_fini:
.globl do_fptrap .globl do_fptrap
.align 32 .align 32
do_fptrap: do_fptrap:
TRAP_LOAD_THREAD_REG(%g6, %g1)
stx %fsr, [%g6 + TI_XFSR] stx %fsr, [%g6 + TI_XFSR]
do_fptrap_after_fsr: do_fptrap_after_fsr:
ldub [%g6 + TI_FPSAVED], %g3 ldub [%g6 + TI_FPSAVED], %g3
...@@ -321,10 +366,22 @@ do_fptrap_after_fsr: ...@@ -321,10 +366,22 @@ do_fptrap_after_fsr:
rd %gsr, %g3 rd %gsr, %g3
stx %g3, [%g6 + TI_GSR] stx %g3, [%g6 + TI_GSR]
mov SECONDARY_CONTEXT, %g3 mov SECONDARY_CONTEXT, %g3
ldxa [%g3] ASI_DMMU, %g5
661: ldxa [%g3] ASI_DMMU, %g5
.section .sun4v_1insn_patch, "ax"
.word 661b
ldxa [%g3] ASI_MMU, %g5
.previous
sethi %hi(sparc64_kern_sec_context), %g2 sethi %hi(sparc64_kern_sec_context), %g2
ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
stxa %g2, [%g3] ASI_DMMU
661: stxa %g2, [%g3] ASI_DMMU
.section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g2, [%g3] ASI_MMU
.previous
membar #Sync membar #Sync
add %g6, TI_FPREGS, %g2 add %g6, TI_FPREGS, %g2
andcc %g1, FPRS_DL, %g0 andcc %g1, FPRS_DL, %g0
...@@ -339,7 +396,13 @@ do_fptrap_after_fsr: ...@@ -339,7 +396,13 @@ do_fptrap_after_fsr:
stda %f48, [%g2 + %g3] ASI_BLK_S stda %f48, [%g2 + %g3] ASI_BLK_S
5: mov SECONDARY_CONTEXT, %g1 5: mov SECONDARY_CONTEXT, %g1
membar #Sync membar #Sync
stxa %g5, [%g1] ASI_DMMU
661: stxa %g5, [%g1] ASI_DMMU
.section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g5, [%g1] ASI_MMU
.previous
membar #Sync membar #Sync
ba,pt %xcc, etrap ba,pt %xcc, etrap
wr %g0, 0, %fprs wr %g0, 0, %fprs
...@@ -353,8 +416,6 @@ do_fptrap_after_fsr: ...@@ -353,8 +416,6 @@ do_fptrap_after_fsr:
* *
* With this method we can do most of the cross-call tlb/cache * With this method we can do most of the cross-call tlb/cache
* flushing very quickly. * flushing very quickly.
*
* Current CPU's IRQ worklist table is locked into %g6, don't touch.
*/ */
.text .text
.align 32 .align 32
...@@ -378,6 +439,8 @@ do_ivec: ...@@ -378,6 +439,8 @@ do_ivec:
sllx %g2, %g4, %g2 sllx %g2, %g4, %g2
sllx %g4, 2, %g4 sllx %g4, 2, %g4
TRAP_LOAD_IRQ_WORK(%g6, %g1)
lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */
stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */
...@@ -399,76 +462,6 @@ do_ivec_xcall: ...@@ -399,76 +462,6 @@ do_ivec_xcall:
1: jmpl %g3, %g0 1: jmpl %g3, %g0
nop nop
.globl save_alternate_globals
save_alternate_globals: /* %o0 = save_area */
rdpr %pstate, %o5
andn %o5, PSTATE_IE, %o1
wrpr %o1, PSTATE_AG, %pstate
stx %g0, [%o0 + 0x00]
stx %g1, [%o0 + 0x08]
stx %g2, [%o0 + 0x10]
stx %g3, [%o0 + 0x18]
stx %g4, [%o0 + 0x20]
stx %g5, [%o0 + 0x28]
stx %g6, [%o0 + 0x30]
stx %g7, [%o0 + 0x38]
wrpr %o1, PSTATE_IG, %pstate
stx %g0, [%o0 + 0x40]
stx %g1, [%o0 + 0x48]
stx %g2, [%o0 + 0x50]
stx %g3, [%o0 + 0x58]
stx %g4, [%o0 + 0x60]
stx %g5, [%o0 + 0x68]
stx %g6, [%o0 + 0x70]
stx %g7, [%o0 + 0x78]
wrpr %o1, PSTATE_MG, %pstate
stx %g0, [%o0 + 0x80]
stx %g1, [%o0 + 0x88]
stx %g2, [%o0 + 0x90]
stx %g3, [%o0 + 0x98]
stx %g4, [%o0 + 0xa0]
stx %g5, [%o0 + 0xa8]
stx %g6, [%o0 + 0xb0]
stx %g7, [%o0 + 0xb8]
wrpr %o5, 0x0, %pstate
retl
nop
.globl restore_alternate_globals
restore_alternate_globals: /* %o0 = save_area */
rdpr %pstate, %o5
andn %o5, PSTATE_IE, %o1
wrpr %o1, PSTATE_AG, %pstate
ldx [%o0 + 0x00], %g0
ldx [%o0 + 0x08], %g1
ldx [%o0 + 0x10], %g2
ldx [%o0 + 0x18], %g3
ldx [%o0 + 0x20], %g4
ldx [%o0 + 0x28], %g5
ldx [%o0 + 0x30], %g6
ldx [%o0 + 0x38], %g7
wrpr %o1, PSTATE_IG, %pstate
ldx [%o0 + 0x40], %g0
ldx [%o0 + 0x48], %g1
ldx [%o0 + 0x50], %g2
ldx [%o0 + 0x58], %g3
ldx [%o0 + 0x60], %g4
ldx [%o0 + 0x68], %g5
ldx [%o0 + 0x70], %g6
ldx [%o0 + 0x78], %g7
wrpr %o1, PSTATE_MG, %pstate
ldx [%o0 + 0x80], %g0
ldx [%o0 + 0x88], %g1
ldx [%o0 + 0x90], %g2
ldx [%o0 + 0x98], %g3
ldx [%o0 + 0xa0], %g4
ldx [%o0 + 0xa8], %g5
ldx [%o0 + 0xb0], %g6
ldx [%o0 + 0xb8], %g7
wrpr %o5, 0x0, %pstate
retl
nop
.globl getcc, setcc .globl getcc, setcc
getcc: getcc:
ldx [%o0 + PT_V9_TSTATE], %o1 ldx [%o0 + PT_V9_TSTATE], %o1
...@@ -488,9 +481,24 @@ setcc: ...@@ -488,9 +481,24 @@ setcc:
retl retl
stx %o1, [%o0 + PT_V9_TSTATE] stx %o1, [%o0 + PT_V9_TSTATE]
.globl utrap, utrap_ill .globl utrap_trap
utrap: brz,pn %g1, etrap utrap_trap: /* %g3=handler,%g4=level */
TRAP_LOAD_THREAD_REG(%g6, %g1)
ldx [%g6 + TI_UTRAPS], %g1
brnz,pt %g1, invoke_utrap
nop nop
ba,pt %xcc, etrap
rd %pc, %g7
mov %l4, %o1
call bad_trap
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
invoke_utrap:
sllx %g3, 3, %g3
ldx [%g1 + %g3], %g1
save %sp, -128, %sp save %sp, -128, %sp
rdpr %tstate, %l6 rdpr %tstate, %l6
rdpr %cwp, %l7 rdpr %cwp, %l7
...@@ -500,17 +508,6 @@ utrap: brz,pn %g1, etrap ...@@ -500,17 +508,6 @@ utrap: brz,pn %g1, etrap
rdpr %tnpc, %l7 rdpr %tnpc, %l7
wrpr %g1, 0, %tnpc wrpr %g1, 0, %tnpc
done done
utrap_ill:
call bad_trap
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
/* XXX Here is stuff we still need to write... -DaveM XXX */
.globl netbsd_syscall
netbsd_syscall:
retl
nop
/* We need to carefully read the error status, ACK /* We need to carefully read the error status, ACK
* the errors, prevent recursive traps, and pass the * the errors, prevent recursive traps, and pass the
...@@ -1001,7 +998,7 @@ dcpe_icpe_tl1_common: ...@@ -1001,7 +998,7 @@ dcpe_icpe_tl1_common:
* %g3: scratch * %g3: scratch
* %g4: AFSR * %g4: AFSR
* %g5: AFAR * %g5: AFAR
* %g6: current thread ptr * %g6: unused, will have current thread ptr after etrap
* %g7: scratch * %g7: scratch
*/ */
__cheetah_log_error: __cheetah_log_error:
...@@ -1539,13 +1536,14 @@ ret_from_syscall: ...@@ -1539,13 +1536,14 @@ ret_from_syscall:
1: b,pt %xcc, ret_sys_call 1: b,pt %xcc, ret_sys_call
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
sparc_exit: wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate sparc_exit: rdpr %pstate, %g2
wrpr %g2, PSTATE_IE, %pstate
rdpr %otherwin, %g1 rdpr %otherwin, %g1
rdpr %cansave, %g3 rdpr %cansave, %g3
add %g3, %g1, %g3 add %g3, %g1, %g3
wrpr %g3, 0x0, %cansave wrpr %g3, 0x0, %cansave
wrpr %g0, 0x0, %otherwin wrpr %g0, 0x0, %otherwin
wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate wrpr %g2, 0x0, %pstate
ba,pt %xcc, sys_exit ba,pt %xcc, sys_exit
stb %g0, [%g6 + TI_WSAVED] stb %g0, [%g6 + TI_WSAVED]
...@@ -1690,3 +1688,138 @@ __flushw_user: ...@@ -1690,3 +1688,138 @@ __flushw_user:
restore %g0, %g0, %g0 restore %g0, %g0, %g0
2: retl 2: retl
nop nop
#ifdef CONFIG_SMP
.globl hard_smp_processor_id
hard_smp_processor_id:
#endif
.globl real_hard_smp_processor_id
real_hard_smp_processor_id:
__GET_CPUID(%o0)
retl
nop
/* %o0: devhandle
* %o1: devino
*
* returns %o0: sysino
*/
.globl sun4v_devino_to_sysino
sun4v_devino_to_sysino:
mov HV_FAST_INTR_DEVINO2SYSINO, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
/* %o0: sysino
*
* returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
.globl sun4v_intr_getenabled
sun4v_intr_getenabled:
mov HV_FAST_INTR_GETENABLED, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
/* %o0: sysino
* %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
.globl sun4v_intr_setenabled
sun4v_intr_setenabled:
mov HV_FAST_INTR_SETENABLED, %o5
ta HV_FAST_TRAP
retl
nop
/* %o0: sysino
*
* returns %o0: intr_state (HV_INTR_STATE_*)
*/
.globl sun4v_intr_getstate
sun4v_intr_getstate:
mov HV_FAST_INTR_GETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
/* %o0: sysino
* %o1: intr_state (HV_INTR_STATE_*)
*/
.globl sun4v_intr_setstate
sun4v_intr_setstate:
mov HV_FAST_INTR_SETSTATE, %o5
ta HV_FAST_TRAP
retl
nop
/* %o0: sysino
*
* returns %o0: cpuid
*/
.globl sun4v_intr_gettarget
sun4v_intr_gettarget:
mov HV_FAST_INTR_GETTARGET, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
/* %o0: sysino
* %o1: cpuid
*/
.globl sun4v_intr_settarget
sun4v_intr_settarget:
mov HV_FAST_INTR_SETTARGET, %o5
ta HV_FAST_TRAP
retl
nop
/* %o0: type
* %o1: queue paddr
* %o2: num queue entries
*
* returns %o0: status
*/
.globl sun4v_cpu_qconf
sun4v_cpu_qconf:
mov HV_FAST_CPU_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
/* returns %o0: status
*/
.globl sun4v_cpu_yield
sun4v_cpu_yield:
mov HV_FAST_CPU_YIELD, %o5
ta HV_FAST_TRAP
retl
nop
/* %o0: num cpus in cpu list
* %o1: cpu list paddr
* %o2: mondo block paddr
*
* returns %o0: status
*/
.globl sun4v_cpu_mondo_send
sun4v_cpu_mondo_send:
mov HV_FAST_CPU_MONDO_SEND, %o5
ta HV_FAST_TRAP
retl
nop
/* %o0: CPU ID
*
* returns %o0: -status if status non-zero, else
* %o0: cpu state as HV_CPU_STATE_*
*/
.globl sun4v_cpu_state
sun4v_cpu_state:
mov HV_FAST_CPU_STATE, %o5
ta HV_FAST_TRAP
brnz,pn %o0, 1f
sub %g0, %o0, %o0
mov %o1, %o0
1: retl
nop
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
.globl etrap, etrap_irq, etraptl1 .globl etrap, etrap_irq, etraptl1
etrap: rdpr %pil, %g2 etrap: rdpr %pil, %g2
etrap_irq: etrap_irq:
TRAP_LOAD_THREAD_REG(%g6, %g1)
rdpr %tstate, %g1 rdpr %tstate, %g1
sllx %g2, 20, %g3 sllx %g2, 20, %g3
andcc %g1, TSTATE_PRIV, %g0 andcc %g1, TSTATE_PRIV, %g0
...@@ -54,7 +55,31 @@ etrap_irq: ...@@ -54,7 +55,31 @@ etrap_irq:
rd %y, %g3 rd %y, %g3
stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]
st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y]
save %g2, -STACK_BIAS, %sp ! Ordering here is critical
rdpr %cansave, %g1
brnz,pt %g1, etrap_save
nop
rdpr %cwp, %g1
add %g1, 2, %g1
wrpr %g1, %cwp
be,pt %xcc, etrap_user_spill
mov ASI_AIUP, %g3
rdpr %otherwin, %g3
brz %g3, etrap_kernel_spill
mov ASI_AIUS, %g3
etrap_user_spill:
wr %g3, 0x0, %asi
ldx [%g6 + TI_FLAGS], %g3
and %g3, _TIF_32BIT, %g3
brnz,pt %g3, etrap_user_spill_32bit
nop
ba,a,pt %xcc, etrap_user_spill_64bit
etrap_save: save %g2, -STACK_BIAS, %sp
mov %g6, %l6 mov %g6, %l6
bne,pn %xcc, 3f bne,pn %xcc, 3f
...@@ -70,42 +95,56 @@ etrap_irq: ...@@ -70,42 +95,56 @@ etrap_irq:
wrpr %g2, 0, %wstate wrpr %g2, 0, %wstate
sethi %hi(sparc64_kern_pri_context), %g2 sethi %hi(sparc64_kern_pri_context), %g2
ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3 ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3
stxa %g3, [%l4] ASI_DMMU
flush %l6 661: stxa %g3, [%l4] ASI_DMMU
wr %g0, ASI_AIUS, %asi .section .sun4v_1insn_patch, "ax"
2: wrpr %g0, 0x0, %tl .word 661b
mov %g4, %l4 stxa %g3, [%l4] ASI_MMU
.previous
sethi %hi(KERNBASE), %l4
flush %l4
mov ASI_AIUS, %l7
2: mov %g4, %l4
mov %g5, %l5 mov %g5, %l5
add %g7, 4, %l2
/* Go to trap time globals so we can save them. */
661: wrpr %g0, ETRAP_PSTATE1, %pstate
.section .sun4v_1insn_patch, "ax"
.word 661b
SET_GL(0)
.previous
mov %g7, %l2
wrpr %g0, ETRAP_PSTATE1, %pstate
stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] stx %g1, [%sp + PTREGS_OFF + PT_V9_G1]
stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] stx %g2, [%sp + PTREGS_OFF + PT_V9_G2]
sllx %l7, 24, %l7
stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] stx %g3, [%sp + PTREGS_OFF + PT_V9_G3]
rdpr %cwp, %l0
stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] stx %g4, [%sp + PTREGS_OFF + PT_V9_G4]
stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] stx %g5, [%sp + PTREGS_OFF + PT_V9_G5]
stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] stx %g6, [%sp + PTREGS_OFF + PT_V9_G6]
stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] stx %g7, [%sp + PTREGS_OFF + PT_V9_G7]
or %l7, %l0, %l7
sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0
or %l7, %l0, %l7
wrpr %l2, %tnpc
wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate
stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] stx %i0, [%sp + PTREGS_OFF + PT_V9_I0]
stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] stx %i1, [%sp + PTREGS_OFF + PT_V9_I1]
stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] stx %i2, [%sp + PTREGS_OFF + PT_V9_I2]
stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] stx %i3, [%sp + PTREGS_OFF + PT_V9_I3]
stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] stx %i4, [%sp + PTREGS_OFF + PT_V9_I4]
stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] stx %i5, [%sp + PTREGS_OFF + PT_V9_I5]
stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] stx %i6, [%sp + PTREGS_OFF + PT_V9_I6]
stx %i7, [%sp + PTREGS_OFF + PT_V9_I7]
wrpr %g0, ETRAP_PSTATE2, %pstate
mov %l6, %g6 mov %l6, %g6
#ifdef CONFIG_SMP stx %i7, [%sp + PTREGS_OFF + PT_V9_I7]
mov TSB_REG, %g3 LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %l1)
ldxa [%g3] ASI_IMMU, %g5 ldx [%g6 + TI_TASK], %g4
#endif done
jmpl %l2 + 0x4, %g0
ldx [%g6 + TI_TASK], %g4
3: ldub [%l6 + TI_FPDEPTH], %l5 3: mov ASI_P, %l7
ldub [%l6 + TI_FPDEPTH], %l5
add %l6, TI_FPSAVED + 1, %l4 add %l6, TI_FPSAVED + 1, %l4
srl %l5, 1, %l3 srl %l5, 1, %l3
add %l5, 2, %l5 add %l5, 2, %l5
...@@ -125,6 +164,7 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. ...@@ -125,6 +164,7 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
* 0x58 TL4's TT * 0x58 TL4's TT
* 0x60 TL * 0x60 TL
*/ */
TRAP_LOAD_THREAD_REG(%g6, %g1)
sub %sp, ((4 * 8) * 4) + 8, %g2 sub %sp, ((4 * 8) * 4) + 8, %g2
rdpr %tl, %g1 rdpr %tl, %g1
...@@ -148,6 +188,11 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. ...@@ -148,6 +188,11 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
rdpr %tt, %g3 rdpr %tt, %g3
stx %g3, [%g2 + STACK_BIAS + 0x38] stx %g3, [%g2 + STACK_BIAS + 0x38]
sethi %hi(is_sun4v), %g3
lduw [%g3 + %lo(is_sun4v)], %g3
brnz,pn %g3, finish_tl1_capture
nop
wrpr %g0, 3, %tl wrpr %g0, 3, %tl
rdpr %tstate, %g3 rdpr %tstate, %g3
stx %g3, [%g2 + STACK_BIAS + 0x40] 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,91 +213,20 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
rdpr %tt, %g3 rdpr %tt, %g3
stx %g3, [%g2 + STACK_BIAS + 0x78] stx %g3, [%g2 + STACK_BIAS + 0x78]
wrpr %g1, %tl
stx %g1, [%g2 + STACK_BIAS + 0x80] stx %g1, [%g2 + STACK_BIAS + 0x80]
finish_tl1_capture:
wrpr %g0, 1, %tl
661: nop
.section .sun4v_1insn_patch, "ax"
.word 661b
SET_GL(1)
.previous
rdpr %tstate, %g1 rdpr %tstate, %g1
sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2 sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2
ba,pt %xcc, 1b ba,pt %xcc, 1b
andcc %g1, TSTATE_PRIV, %g0 andcc %g1, TSTATE_PRIV, %g0
.align 64
.globl scetrap
scetrap: rdpr %pil, %g2
rdpr %tstate, %g1
sllx %g2, 20, %g3
andcc %g1, TSTATE_PRIV, %g0
or %g1, %g3, %g1
bne,pn %xcc, 1f
sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2
wrpr %g0, 7, %cleanwin
sllx %g1, 51, %g3
sethi %hi(TASK_REGOFF), %g2
or %g2, %lo(TASK_REGOFF), %g2
brlz,pn %g3, 1f
add %g6, %g2, %g2
wr %g0, 0, %fprs
1: rdpr %tpc, %g3
stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]
rdpr %tnpc, %g1
stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]
stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]
save %g2, -STACK_BIAS, %sp ! Ordering here is critical
mov %g6, %l6
bne,pn %xcc, 2f
mov ASI_P, %l7
rdpr %canrestore, %g3
rdpr %wstate, %g2
wrpr %g0, 0, %canrestore
sll %g2, 3, %g2
mov PRIMARY_CONTEXT, %l4
wrpr %g3, 0, %otherwin
wrpr %g2, 0, %wstate
sethi %hi(sparc64_kern_pri_context), %g2
ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3
stxa %g3, [%l4] ASI_DMMU
flush %l6
mov ASI_AIUS, %l7
2: mov %g4, %l4
mov %g5, %l5
add %g7, 0x4, %l2
wrpr %g0, ETRAP_PSTATE1, %pstate
stx %g1, [%sp + PTREGS_OFF + PT_V9_G1]
stx %g2, [%sp + PTREGS_OFF + PT_V9_G2]
sllx %l7, 24, %l7
stx %g3, [%sp + PTREGS_OFF + PT_V9_G3]
rdpr %cwp, %l0
stx %g4, [%sp + PTREGS_OFF + PT_V9_G4]
stx %g5, [%sp + PTREGS_OFF + PT_V9_G5]
stx %g6, [%sp + PTREGS_OFF + PT_V9_G6]
stx %g7, [%sp + PTREGS_OFF + PT_V9_G7]
or %l7, %l0, %l7
sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0
or %l7, %l0, %l7
wrpr %l2, %tnpc
wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate
stx %i0, [%sp + PTREGS_OFF + PT_V9_I0]
stx %i1, [%sp + PTREGS_OFF + PT_V9_I1]
stx %i2, [%sp + PTREGS_OFF + PT_V9_I2]
stx %i3, [%sp + PTREGS_OFF + PT_V9_I3]
stx %i4, [%sp + PTREGS_OFF + PT_V9_I4]
stx %i5, [%sp + PTREGS_OFF + PT_V9_I5]
stx %i6, [%sp + PTREGS_OFF + PT_V9_I6]
mov %l6, %g6
stx %i7, [%sp + PTREGS_OFF + PT_V9_I7]
#ifdef CONFIG_SMP
mov TSB_REG, %g3
ldxa [%g3] ASI_IMMU, %g5
#endif
ldx [%g6 + TI_TASK], %g4
done
#undef TASK_REGOFF #undef TASK_REGOFF
#undef ETRAP_PSTATE1 #undef ETRAP_PSTATE1
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <asm/head.h> #include <asm/head.h>
#include <asm/ttable.h> #include <asm/ttable.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/cpudata.h>
/* This section from from _start to sparc64_boot_end should fit into /* This section from from _start to sparc64_boot_end should fit into
* 0x0000000000404000 to 0x0000000000408000. * 0x0000000000404000 to 0x0000000000408000.
...@@ -94,12 +95,17 @@ sparc64_boot: ...@@ -94,12 +95,17 @@ sparc64_boot:
wrpr %g1, 0x0, %pstate wrpr %g1, 0x0, %pstate
ba,a,pt %xcc, 1f ba,a,pt %xcc, 1f
.globl prom_finddev_name, prom_chosen_path .globl prom_finddev_name, prom_chosen_path, prom_root_node
.globl prom_getprop_name, prom_mmu_name .globl prom_getprop_name, prom_mmu_name, prom_peer_name
.globl prom_callmethod_name, prom_translate_name .globl prom_callmethod_name, prom_translate_name, prom_root_compatible
.globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
.globl prom_boot_mapped_pc, prom_boot_mapping_mode .globl prom_boot_mapped_pc, prom_boot_mapping_mode
.globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
.globl is_sun4v
prom_peer_name:
.asciz "peer"
prom_compatible_name:
.asciz "compatible"
prom_finddev_name: prom_finddev_name:
.asciz "finddevice" .asciz "finddevice"
prom_chosen_path: prom_chosen_path:
...@@ -116,7 +122,13 @@ prom_map_name: ...@@ -116,7 +122,13 @@ prom_map_name:
.asciz "map" .asciz "map"
prom_unmap_name: prom_unmap_name:
.asciz "unmap" .asciz "unmap"
prom_sun4v_name:
.asciz "sun4v"
.align 4 .align 4
prom_root_compatible:
.skip 64
prom_root_node:
.word 0
prom_mmu_ihandle_cache: prom_mmu_ihandle_cache:
.word 0 .word 0
prom_boot_mapped_pc: prom_boot_mapped_pc:
...@@ -128,8 +140,54 @@ prom_boot_mapping_phys_high: ...@@ -128,8 +140,54 @@ prom_boot_mapping_phys_high:
.xword 0 .xword 0
prom_boot_mapping_phys_low: prom_boot_mapping_phys_low:
.xword 0 .xword 0
is_sun4v:
.word 0
1: 1:
rd %pc, %l0 rd %pc, %l0
mov (1b - prom_peer_name), %l1
sub %l0, %l1, %l1
mov 0, %l2
/* prom_root_node = prom_peer(0) */
stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "peer"
mov 1, %l3
stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, 0
stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
call %l7
add %sp, (2047 + 128), %o0 ! argument array
ldx [%sp + 2047 + 128 + 0x20], %l4 ! prom root node
mov (1b - prom_root_node), %l1
sub %l0, %l1, %l1
stw %l4, [%l1]
mov (1b - prom_getprop_name), %l1
mov (1b - prom_compatible_name), %l2
mov (1b - prom_root_compatible), %l5
sub %l0, %l1, %l1
sub %l0, %l2, %l2
sub %l0, %l5, %l5
/* prom_getproperty(prom_root_node, "compatible",
* &prom_root_compatible, 64)
*/
stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
mov 4, %l3
stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
mov 1, %l3
stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, prom_root_node
stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible"
stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_root_compatible
mov 64, %l3
stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size
stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
call %l7
add %sp, (2047 + 128), %o0 ! argument array
mov (1b - prom_finddev_name), %l1 mov (1b - prom_finddev_name), %l1
mov (1b - prom_chosen_path), %l2 mov (1b - prom_chosen_path), %l2
mov (1b - prom_boot_mapped_pc), %l3 mov (1b - prom_boot_mapped_pc), %l3
...@@ -238,6 +296,27 @@ prom_boot_mapping_phys_low: ...@@ -238,6 +296,27 @@ prom_boot_mapping_phys_low:
add %sp, (192 + 128), %sp add %sp, (192 + 128), %sp
sparc64_boot_after_remap: sparc64_boot_after_remap:
sethi %hi(prom_root_compatible), %g1
or %g1, %lo(prom_root_compatible), %g1
sethi %hi(prom_sun4v_name), %g7
or %g7, %lo(prom_sun4v_name), %g7
mov 5, %g3
1: ldub [%g7], %g2
ldub [%g1], %g4
cmp %g2, %g4
bne,pn %icc, 2f
add %g7, 1, %g7
subcc %g3, 1, %g3
bne,pt %xcc, 1b
add %g1, 1, %g1
sethi %hi(is_sun4v), %g1
or %g1, %lo(is_sun4v), %g1
mov 1, %g7
stw %g7, [%g1]
2:
BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot) BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot) BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
ba,pt %xcc, spitfire_boot ba,pt %xcc, spitfire_boot
...@@ -301,20 +380,58 @@ jump_to_sun4u_init: ...@@ -301,20 +380,58 @@ jump_to_sun4u_init:
nop nop
sun4u_init: sun4u_init:
BRANCH_IF_SUN4V(g1, sun4v_init)
/* Set ctx 0 */ /* Set ctx 0 */
mov PRIMARY_CONTEXT, %g7 mov PRIMARY_CONTEXT, %g7
stxa %g0, [%g7] ASI_DMMU stxa %g0, [%g7] ASI_DMMU
membar #Sync membar #Sync
mov SECONDARY_CONTEXT, %g7 mov SECONDARY_CONTEXT, %g7
stxa %g0, [%g7] ASI_DMMU stxa %g0, [%g7] ASI_DMMU
membar #Sync membar #Sync
BRANCH_IF_ANY_CHEETAH(g1,g7,cheetah_tlb_fixup) ba,pt %xcc, sun4u_continue
nop
sun4v_init:
/* Set ctx 0 */
mov PRIMARY_CONTEXT, %g7
stxa %g0, [%g7] ASI_MMU
membar #Sync
mov SECONDARY_CONTEXT, %g7
stxa %g0, [%g7] ASI_MMU
membar #Sync
ba,pt %xcc, niagara_tlb_fixup
nop
sun4u_continue:
BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup)
ba,pt %xcc, spitfire_tlb_fixup ba,pt %xcc, spitfire_tlb_fixup
nop nop
niagara_tlb_fixup:
mov 3, %g2 /* Set TLB type to hypervisor. */
sethi %hi(tlb_type), %g1
stw %g2, [%g1 + %lo(tlb_type)]
/* Patch copy/clear ops. */
call niagara_patch_copyops
nop
call niagara_patch_bzero
nop
call niagara_patch_pageops
nop
/* Patch TLB/cache ops. */
call hypervisor_patch_cachetlbops
nop
ba,pt %xcc, tlb_fixup_done
nop
cheetah_tlb_fixup: cheetah_tlb_fixup:
mov 2, %g2 /* Set TLB type to cheetah+. */ mov 2, %g2 /* Set TLB type to cheetah+. */
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f) BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f)
...@@ -411,85 +528,55 @@ setup_trap_table: ...@@ -411,85 +528,55 @@ setup_trap_table:
wrpr %g0, 15, %pil wrpr %g0, 15, %pil
/* Make the firmware call to jump over to the Linux trap table. */ /* Make the firmware call to jump over to the Linux trap table. */
call prom_set_trap_table sethi %hi(is_sun4v), %o0
sethi %hi(sparc64_ttable_tl0), %o0 lduw [%o0 + %lo(is_sun4v)], %o0
brz,pt %o0, 1f
nop
/* Start using proper page size encodings in ctx register. */ TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
sethi %hi(sparc64_kern_pri_context), %g3 add %g2, TRAP_PER_CPU_FAULT_INFO, %g2
ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 stxa %g2, [%g0] ASI_SCRATCHPAD
mov PRIMARY_CONTEXT, %g1
stxa %g2, [%g1] ASI_DMMU
membar #Sync
/* The Linux trap handlers expect various trap global registers /* Compute physical address:
* to be setup with some fixed values. So here we set these
* up very carefully. These globals are:
*
* Alternate Globals (PSTATE_AG):
*
* %g6 --> current_thread_info()
*
* MMU Globals (PSTATE_MG):
*
* %g1 --> TLB_SFSR
* %g2 --> ((_PAGE_VALID | _PAGE_SZ4MB |
* _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
* ^ 0xfffff80000000000)
* (this %g2 value is used for computing the PAGE_OFFSET kernel
* TLB entries quickly, the virtual address of the fault XOR'd
* with this %g2 value is the PTE to load into the TLB)
* %g3 --> VPTE_BASE_CHEETAH or VPTE_BASE_SPITFIRE
* *
* Interrupt Globals (PSTATE_IG, setup by init_irqwork_curcpu()): * paddr = kern_base + (mmfsa_vaddr - KERNBASE)
*
* %g6 --> __irq_work[smp_processor_id()]
*/ */
sethi %hi(KERNBASE), %g3
sub %g2, %g3, %g2
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
rdpr %pstate, %o1 call prom_set_trap_table_sun4v
mov %g6, %o2 sethi %hi(sparc64_ttable_tl0), %o0
wrpr %o1, PSTATE_AG, %pstate
mov %o2, %g6 ba,pt %xcc, 2f
#define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
wrpr %o1, PSTATE_MG, %pstate
mov TSB_REG, %g1
stxa %g0, [%g1] ASI_DMMU
membar #Sync
stxa %g0, [%g1] ASI_IMMU
membar #Sync
mov TLB_SFSR, %g1
sethi %uhi(KERN_HIGHBITS), %g2
or %g2, %ulo(KERN_HIGHBITS), %g2
sllx %g2, 32, %g2
or %g2, KERN_LOWBITS, %g2
BRANCH_IF_ANY_CHEETAH(g3,g7,8f)
ba,pt %xcc, 9f
nop nop
8: 1: call prom_set_trap_table
sethi %uhi(VPTE_BASE_CHEETAH), %g3 sethi %hi(sparc64_ttable_tl0), %o0
or %g3, %ulo(VPTE_BASE_CHEETAH), %g3
ba,pt %xcc, 2f
sllx %g3, 32, %g3
9: /* Start using proper page size encodings in ctx register. */
sethi %uhi(VPTE_BASE_SPITFIRE), %g3 2: sethi %hi(sparc64_kern_pri_context), %g3
or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2
sllx %g3, 32, %g3
2: mov PRIMARY_CONTEXT, %g1
clr %g7
#undef KERN_HIGHBITS 661: stxa %g2, [%g1] ASI_DMMU
#undef KERN_LOWBITS .section .sun4v_1insn_patch, "ax"
.word 661b
stxa %g2, [%g1] ASI_MMU
.previous
membar #Sync
/* Kill PROM timer */ /* Kill PROM timer */
sethi %hi(0x80000000), %o2 sethi %hi(0x80000000), %o2
sllx %o2, 32, %o2 sllx %o2, 32, %o2
wr %o2, 0, %tick_cmpr wr %o2, 0, %tick_cmpr
BRANCH_IF_ANY_CHEETAH(o2,o3,1f) BRANCH_IF_SUN4V(o2, 1f)
BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
ba,pt %xcc, 2f ba,pt %xcc, 2f
nop nop
...@@ -502,7 +589,6 @@ setup_trap_table: ...@@ -502,7 +589,6 @@ setup_trap_table:
2: 2:
wrpr %g0, %g0, %wstate wrpr %g0, %g0, %wstate
wrpr %o1, 0x0, %pstate
call init_irqwork_curcpu call init_irqwork_curcpu
nop nop
...@@ -517,7 +603,7 @@ setup_trap_table: ...@@ -517,7 +603,7 @@ setup_trap_table:
restore restore
.globl setup_tba .globl setup_tba
setup_tba: /* i0 = is_starfire */ setup_tba:
save %sp, -192, %sp save %sp, -192, %sp
/* The boot processor is the only cpu which invokes this /* The boot processor is the only cpu which invokes this
...@@ -536,31 +622,35 @@ setup_tba: /* i0 = is_starfire */ ...@@ -536,31 +622,35 @@ setup_tba: /* i0 = is_starfire */
restore restore
sparc64_boot_end: sparc64_boot_end:
#include "systbls.S"
#include "ktlb.S" #include "ktlb.S"
#include "tsb.S"
#include "etrap.S" #include "etrap.S"
#include "rtrap.S" #include "rtrap.S"
#include "winfixup.S" #include "winfixup.S"
#include "entry.S" #include "entry.S"
#include "sun4v_tlb_miss.S"
#include "sun4v_ivec.S"
/* /*
* The following skip makes sure the trap table in ttable.S is aligned * The following skip makes sure the trap table in ttable.S is aligned
* on a 32K boundary as required by the v9 specs for TBA register. * on a 32K boundary as required by the v9 specs for TBA register.
*
* We align to a 32K boundary, then we have the 32K kernel TSB,
* then the 32K aligned trap table.
*/ */
1: 1:
.skip 0x4000 + _start - 1b .skip 0x4000 + _start - 1b
#ifdef CONFIG_SBUS .globl swapper_tsb
/* This is just a hack to fool make depend config.h discovering swapper_tsb:
strategy: As the .S files below need config.h, but .skip (32 * 1024)
make depend does not find it for them, we include config.h
in head.S */
#endif
! 0x0000000000408000 ! 0x0000000000408000
#include "ttable.S" #include "ttable.S"
#include "systbls.S"
.data .data
.align 8 .align 8
.globl prom_tba, tlb_type .globl prom_tba, tlb_type
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/cpudata.h> #include <asm/cpudata.h>
#include <asm/auxio.h> #include <asm/auxio.h>
#include <asm/head.h>
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void distribute_irqs(void); static void distribute_irqs(void);
...@@ -136,12 +138,48 @@ out_unlock: ...@@ -136,12 +138,48 @@ out_unlock:
return 0; return 0;
} }
extern unsigned long real_hard_smp_processor_id(void);
static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
{
unsigned int tid;
if (this_is_starfire) {
tid = starfire_translate(imap, cpuid);
tid <<= IMAP_TID_SHIFT;
tid &= IMAP_TID_UPA;
} else {
if (tlb_type == cheetah || tlb_type == cheetah_plus) {
unsigned long ver;
__asm__ ("rdpr %%ver, %0" : "=r" (ver));
if ((ver >> 32UL) == __JALAPENO_ID ||
(ver >> 32UL) == __SERRANO_ID) {
tid = cpuid << IMAP_TID_SHIFT;
tid &= IMAP_TID_JBUS;
} else {
unsigned int a = cpuid & 0x1f;
unsigned int n = (cpuid >> 5) & 0x1f;
tid = ((a << IMAP_AID_SHIFT) |
(n << IMAP_NID_SHIFT));
tid &= (IMAP_AID_SAFARI |
IMAP_NID_SAFARI);;
}
} else {
tid = cpuid << IMAP_TID_SHIFT;
tid &= IMAP_TID_UPA;
}
}
return tid;
}
/* Now these are always passed a true fully specified sun4u INO. */ /* Now these are always passed a true fully specified sun4u INO. */
void enable_irq(unsigned int irq) void enable_irq(unsigned int irq)
{ {
struct ino_bucket *bucket = __bucket(irq); struct ino_bucket *bucket = __bucket(irq);
unsigned long imap; unsigned long imap, cpuid;
unsigned long tid;
imap = bucket->imap; imap = bucket->imap;
if (imap == 0UL) if (imap == 0UL)
...@@ -149,47 +187,38 @@ void enable_irq(unsigned int irq) ...@@ -149,47 +187,38 @@ void enable_irq(unsigned int irq)
preempt_disable(); preempt_disable();
if (tlb_type == cheetah || tlb_type == cheetah_plus) { /* This gets the physical processor ID, even on uniprocessor,
unsigned long ver; * so we can always program the interrupt target correctly.
*/
__asm__ ("rdpr %%ver, %0" : "=r" (ver)); cpuid = real_hard_smp_processor_id();
if ((ver >> 32) == 0x003e0016) {
/* We set it to our JBUS ID. */ if (tlb_type == hypervisor) {
__asm__ __volatile__("ldxa [%%g0] %1, %0" unsigned int ino = __irq_ino(irq);
: "=r" (tid) int err;
: "i" (ASI_JBUS_CONFIG));
tid = ((tid & (0x1fUL<<17)) << 9); err = sun4v_intr_settarget(ino, cpuid);
tid &= IMAP_TID_JBUS; if (err != HV_EOK)
} else { printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
/* We set it to our Safari AID. */ ino, cpuid, err);
__asm__ __volatile__("ldxa [%%g0] %1, %0" err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
: "=r" (tid) if (err != HV_EOK)
: "i" (ASI_SAFARI_CONFIG)); printk("sun4v_intr_setenabled(%x): err(%d)\n",
tid = ((tid & (0x3ffUL<<17)) << 9); ino, err);
tid &= IMAP_AID_SAFARI;
}
} else if (this_is_starfire == 0) {
/* We set it to our UPA MID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
tid &= IMAP_TID_UPA;
} else { } else {
tid = (starfire_translate(imap, smp_processor_id()) << 26); unsigned int tid = sun4u_compute_tid(imap, cpuid);
tid &= IMAP_TID_UPA;
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
* of this SYSIO's preconfigured IGN in the SYSIO Control
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* IMAP_INR field can be set by the programmer here.
*
* Things like FFB can now be handled via the new IRQ
* mechanism.
*/
upa_writel(tid | IMAP_VALID, imap);
} }
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
* of this SYSIO's preconfigured IGN in the SYSIO Control
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* IMAP_INR field can be set by the programmer here.
*
* Things like FFB can now be handled via the new IRQ mechanism.
*/
upa_writel(tid | IMAP_VALID, imap);
preempt_enable(); preempt_enable();
} }
...@@ -201,16 +230,26 @@ void disable_irq(unsigned int irq) ...@@ -201,16 +230,26 @@ void disable_irq(unsigned int irq)
imap = bucket->imap; imap = bucket->imap;
if (imap != 0UL) { if (imap != 0UL) {
u32 tmp; if (tlb_type == hypervisor) {
unsigned int ino = __irq_ino(irq);
int err;
err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
if (err != HV_EOK)
printk("sun4v_intr_setenabled(%x): "
"err(%d)\n", ino, err);
} else {
u32 tmp;
/* NOTE: We do not want to futz with the IRQ clear registers /* NOTE: We do not want to futz with the IRQ clear registers
* and move the state to IDLE, the SCSI code does call * and move the state to IDLE, the SCSI code does call
* disable_irq() to assure atomicity in the queue cmd * disable_irq() to assure atomicity in the queue cmd
* SCSI adapter driver code. Thus we'd lose interrupts. * SCSI adapter driver code. Thus we'd lose interrupts.
*/ */
tmp = upa_readl(imap); tmp = upa_readl(imap);
tmp &= ~IMAP_VALID; tmp &= ~IMAP_VALID;
upa_writel(tmp, imap); upa_writel(tmp, imap);
}
} }
} }
...@@ -248,6 +287,8 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long ...@@ -248,6 +287,8 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long
return __irq(&pil0_dummy_bucket); return __irq(&pil0_dummy_bucket);
} }
BUG_ON(tlb_type == hypervisor);
/* RULE: Both must be specified in all other cases. */ /* RULE: Both must be specified in all other cases. */
if (iclr == 0UL || imap == 0UL) { if (iclr == 0UL || imap == 0UL) {
prom_printf("Invalid build_irq %d %d %016lx %016lx\n", 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,12 +316,11 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long
goto out; goto out;
} }
bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC); bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC);
if (!bucket->irq_info) { if (!bucket->irq_info) {
prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
prom_halt(); prom_halt();
} }
memset(bucket->irq_info, 0, sizeof(struct irq_desc));
/* Ok, looks good, set it up. Don't touch the irq_chain or /* Ok, looks good, set it up. Don't touch the irq_chain or
* the pending flag. * the pending flag.
...@@ -294,6 +334,37 @@ out: ...@@ -294,6 +334,37 @@ out:
return __irq(bucket); return __irq(bucket);
} }
unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags)
{
struct ino_bucket *bucket;
unsigned long sysino;
sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
/* Catch accidental accesses to these things. IMAP/ICLR handling
* is done by hypervisor calls on sun4v platforms, not by direct
* register accesses.
*
* But we need to make them look unique for the disable_irq() logic
* in free_irq().
*/
bucket->imap = ~0UL - sysino;
bucket->iclr = ~0UL - sysino;
bucket->pil = pil;
bucket->flags = flags;
bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC);
if (!bucket->irq_info) {
prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
prom_halt();
}
return __irq(bucket);
}
static void atomic_bucket_insert(struct ino_bucket *bucket) static void atomic_bucket_insert(struct ino_bucket *bucket)
{ {
unsigned long pstate; unsigned long pstate;
...@@ -482,7 +553,6 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -482,7 +553,6 @@ void free_irq(unsigned int irq, void *dev_id)
bucket = __bucket(irq); bucket = __bucket(irq);
if (bucket != &pil0_dummy_bucket) { if (bucket != &pil0_dummy_bucket) {
struct irq_desc *desc = bucket->irq_info; struct irq_desc *desc = bucket->irq_info;
unsigned long imap = bucket->imap;
int ent, i; int ent, i;
for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
...@@ -495,6 +565,8 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -495,6 +565,8 @@ void free_irq(unsigned int irq, void *dev_id)
} }
if (!desc->action_active_mask) { if (!desc->action_active_mask) {
unsigned long imap = bucket->imap;
/* This unique interrupt source is now inactive. */ /* This unique interrupt source is now inactive. */
bucket->flags &= ~IBF_ACTIVE; bucket->flags &= ~IBF_ACTIVE;
...@@ -592,7 +664,18 @@ static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) ...@@ -592,7 +664,18 @@ static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs)
break; break;
} }
if (bp->pil != 0) { if (bp->pil != 0) {
upa_writel(ICLR_IDLE, bp->iclr); if (tlb_type == hypervisor) {
unsigned int ino = __irq_ino(bp);
int err;
err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
if (err != HV_EOK)
printk("sun4v_intr_setstate(%x): "
"err(%d)\n", ino, err);
} else {
upa_writel(ICLR_IDLE, bp->iclr);
}
/* Test and add entropy */ /* Test and add entropy */
if (random & SA_SAMPLE_RANDOM) if (random & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq); add_interrupt_randomness(irq);
...@@ -694,7 +777,7 @@ irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) ...@@ -694,7 +777,7 @@ irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
val = readb(auxio_register); val = readb(auxio_register);
val |= AUXIO_AUX1_FTCNT; val |= AUXIO_AUX1_FTCNT;
writeb(val, auxio_register); writeb(val, auxio_register);
val &= AUXIO_AUX1_FTCNT; val &= ~AUXIO_AUX1_FTCNT;
writeb(val, auxio_register); writeb(val, auxio_register);
doing_pdma = 0; doing_pdma = 0;
...@@ -727,25 +810,23 @@ EXPORT_SYMBOL(probe_irq_off); ...@@ -727,25 +810,23 @@ EXPORT_SYMBOL(probe_irq_off);
static int retarget_one_irq(struct irqaction *p, int goal_cpu) static int retarget_one_irq(struct irqaction *p, int goal_cpu)
{ {
struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table; struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table;
unsigned long imap = bucket->imap;
unsigned int tid;
while (!cpu_online(goal_cpu)) { while (!cpu_online(goal_cpu)) {
if (++goal_cpu >= NR_CPUS) if (++goal_cpu >= NR_CPUS)
goal_cpu = 0; goal_cpu = 0;
} }
if (tlb_type == cheetah || tlb_type == cheetah_plus) { if (tlb_type == hypervisor) {
tid = goal_cpu << 26; unsigned int ino = __irq_ino(bucket);
tid &= IMAP_AID_SAFARI;
} else if (this_is_starfire == 0) { sun4v_intr_settarget(ino, goal_cpu);
tid = goal_cpu << 26; sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
tid &= IMAP_TID_UPA;
} else { } else {
tid = (starfire_translate(imap, goal_cpu) << 26); unsigned long imap = bucket->imap;
tid &= IMAP_TID_UPA; unsigned int tid = sun4u_compute_tid(imap, goal_cpu);
upa_writel(tid | IMAP_VALID, imap);
} }
upa_writel(tid | IMAP_VALID, imap);
do { do {
if (++goal_cpu >= NR_CPUS) if (++goal_cpu >= NR_CPUS)
...@@ -848,33 +929,114 @@ static void kill_prom_timer(void) ...@@ -848,33 +929,114 @@ static void kill_prom_timer(void)
void init_irqwork_curcpu(void) void init_irqwork_curcpu(void)
{ {
register struct irq_work_struct *workp asm("o2");
register unsigned long tmp asm("o3");
int cpu = hard_smp_processor_id(); int cpu = hard_smp_processor_id();
memset(__irq_work + cpu, 0, sizeof(*workp)); memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct));
}
/* Make sure we are called with PSTATE_IE disabled. */
__asm__ __volatile__("rdpr %%pstate, %0\n\t" static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type)
: "=r" (tmp)); {
if (tmp & PSTATE_IE) { unsigned long num_entries = 128;
prom_printf("BUG: init_irqwork_curcpu() called with " unsigned long status;
"PSTATE_IE enabled, bailing.\n");
__asm__ __volatile__("mov %%i7, %0\n\t" status = sun4v_cpu_qconf(type, paddr, num_entries);
: "=r" (tmp)); if (status != HV_EOK) {
prom_printf("BUG: Called from %lx\n", tmp); prom_printf("SUN4V: sun4v_cpu_qconf(%lu:%lx:%lu) failed, "
"err %lu\n", type, paddr, num_entries, status);
prom_halt(); prom_halt();
} }
}
/* Set interrupt globals. */ static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
workp = &__irq_work[cpu]; {
__asm__ __volatile__( struct trap_per_cpu *tb = &trap_block[this_cpu];
"rdpr %%pstate, %0\n\t"
"wrpr %0, %1, %%pstate\n\t" register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO);
"mov %2, %%g6\n\t" register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO);
"wrpr %0, 0x0, %%pstate\n\t" register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR);
: "=&r" (tmp) register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR);
: "i" (PSTATE_IG), "r" (workp)); }
static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, int use_bootmem)
{
void *page;
if (use_bootmem)
page = alloc_bootmem_low_pages(PAGE_SIZE);
else
page = (void *) get_zeroed_page(GFP_ATOMIC);
if (!page) {
prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
prom_halt();
}
*pa_ptr = __pa(page);
}
static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, int use_bootmem)
{
void *page;
if (use_bootmem)
page = alloc_bootmem_low_pages(PAGE_SIZE);
else
page = (void *) get_zeroed_page(GFP_ATOMIC);
if (!page) {
prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
prom_halt();
}
*pa_ptr = __pa(page);
}
static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem)
{
#ifdef CONFIG_SMP
void *page;
BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
if (use_bootmem)
page = alloc_bootmem_low_pages(PAGE_SIZE);
else
page = (void *) get_zeroed_page(GFP_ATOMIC);
if (!page) {
prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
prom_halt();
}
tb->cpu_mondo_block_pa = __pa(page);
tb->cpu_list_pa = __pa(page + 64);
#endif
}
/* Allocate and register the mondo and error queues for this cpu. */
void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load)
{
struct trap_per_cpu *tb = &trap_block[cpu];
if (alloc) {
alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem);
alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem);
alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem);
alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem);
alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem);
alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem);
init_cpu_send_mondo_info(tb, use_bootmem);
}
if (load) {
if (cpu != hard_smp_processor_id()) {
prom_printf("SUN4V: init mondo on cpu %d not %d\n",
cpu, hard_smp_processor_id());
prom_halt();
}
sun4v_register_mondo_queues(cpu);
}
} }
/* Only invoked on boot processor. */ /* Only invoked on boot processor. */
...@@ -884,6 +1046,9 @@ void __init init_IRQ(void) ...@@ -884,6 +1046,9 @@ void __init init_IRQ(void)
kill_prom_timer(); kill_prom_timer();
memset(&ivector_table[0], 0, sizeof(ivector_table)); memset(&ivector_table[0], 0, sizeof(ivector_table));
if (tlb_type == hypervisor)
sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1);
/* We need to clear any IRQ's pending in the soft interrupt /* We need to clear any IRQ's pending in the soft interrupt
* registers, a spurious one could be left around from the * registers, a spurious one could be left around from the
* PROM timer which we just disabled. * PROM timer which we just disabled.
......
/* $Id: itlb_base.S,v 1.12 2002/02/09 19:49:30 davem Exp $
* itlb_base.S: Front end to ITLB miss replacement strategy.
* This is included directly into the trap table.
*
* Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#if PAGE_SHIFT == 13
/*
* To compute vpte offset, we need to do ((addr >> 13) << 3),
* which can be optimized to (addr >> 10) if bits 10/11/12 can
* be guaranteed to be 0 ... mmu_context.h does guarantee this
* by only using 10 bits in the hwcontext value.
*/
#define CREATE_VPTE_OFFSET1(r1, r2) \
srax r1, 10, r2
#define CREATE_VPTE_OFFSET2(r1, r2) nop
#else /* PAGE_SHIFT */
#define CREATE_VPTE_OFFSET1(r1, r2) \
srax r1, PAGE_SHIFT, r2
#define CREATE_VPTE_OFFSET2(r1, r2) \
sllx r2, 3, r2
#endif /* PAGE_SHIFT */
/* Ways we can get here:
*
* 1) Nucleus instruction misses from module code.
* 2) All user instruction misses.
*
* All real page faults merge their code paths to the
* sparc64_realfault_common label below.
*/
/* ITLB ** ICACHE line 1: Quick user TLB misses */
mov TLB_SFSR, %g1
ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS
CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE
1: brgez,pn %g5, 3f ! Not valid, branch out
sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot
andcc %g5, %g4, %g0 ! Executable?
/* ITLB ** ICACHE line 2: Real faults */
be,pn %xcc, 3f ! Nope, branch.
nop ! Delay-slot
2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB
retry ! Trap return
3: rdpr %pstate, %g4 ! Move into alt-globals
wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tpc, %g5 ! And load faulting VA
mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB
/* ITLB ** ICACHE line 3: Finish faults */
sparc64_realfault_common: ! Called by dtlb_miss
stb %g4, [%g6 + TI_FAULT_CODE]
stx %g5, [%g6 + TI_FAULT_ADDR]
ba,pt %xcc, etrap ! Save state
1: rd %pc, %g7 ! ...
call do_sparc64_fault ! Call fault handler
add %sp, PTREGS_OFF, %o0! Compute pt_regs arg
ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state
nop
/* ITLB ** ICACHE line 4: Window fixups */
winfix_trampoline:
rdpr %tpc, %g3 ! Prepare winfixup TNPC
or %g3, 0x7c, %g3 ! Compute branch offset
wrpr %g3, %tnpc ! Write it into TNPC
done ! Do it to it
nop
nop
nop
nop
#undef CREATE_VPTE_OFFSET1
#undef CREATE_VPTE_OFFSET2
/* ITLB ** ICACHE line 1: Context 0 check and TSB load */
ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! Get TSB 8K pointer
ldxa [%g0] ASI_IMMU, %g6 ! Get TAG TARGET
srlx %g6, 48, %g5 ! Get context
sllx %g6, 22, %g6 ! Zero out context
brz,pn %g5, kvmap_itlb ! Context 0 processing
srlx %g6, 22, %g6 ! Delay slot
TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry
cmp %g4, %g6 ! Compare TAG
/* ITLB ** ICACHE line 2: TSB compare and TLB load */
bne,pn %xcc, tsb_miss_itlb ! Miss
mov FAULT_CODE_ITLB, %g3
andcc %g5, _PAGE_EXEC_4U, %g0 ! Executable?
be,pn %xcc, tsb_do_fault
nop ! Delay slot, fill me
stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB
retry ! Trap done
nop
/* ITLB ** ICACHE line 3: */
nop
nop
nop
nop
nop
nop
nop
nop
/* ITLB ** ICACHE line 4: */
nop
nop
nop
nop
nop
nop
nop
nop
...@@ -4,191 +4,276 @@ ...@@ -4,191 +4,276 @@
* Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de) * Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <asm/head.h> #include <asm/head.h>
#include <asm/asi.h> #include <asm/asi.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tsb.h>
.text .text
.align 32 .align 32
/* kvmap_itlb:
* On a second level vpte miss, check whether the original fault is to the OBP /* g6: TAG TARGET */
* range (note that this is only possible for instruction miss, data misses to mov TLB_TAG_ACCESS, %g4
* obp range do not use vpte). If so, go back directly to the faulting address. ldxa [%g4] ASI_IMMU, %g4
* This is because we want to read the tpc, otherwise we have no way of knowing
* the 8k aligned faulting address if we are using >8k kernel pagesize. This /* sun4v_itlb_miss branches here with the missing virtual
* also ensures no vpte range addresses are dropped into tlb while obp is * address already loaded into %g4
* executing (see inherit_locked_prom_mappings() rant).
*/
sparc64_vpte_nucleus:
/* Note that kvmap below has verified that the address is
* in the range MODULES_VADDR --> VMALLOC_END already. So
* here we need only check if it is an OBP address or not.
*/ */
kvmap_itlb_4v:
kvmap_itlb_nonlinear:
/* Catch kernel NULL pointer calls. */
sethi %hi(PAGE_SIZE), %g5
cmp %g4, %g5
bleu,pn %xcc, kvmap_dtlb_longpath
nop
KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_itlb_load)
kvmap_itlb_tsb_miss:
sethi %hi(LOW_OBP_ADDRESS), %g5 sethi %hi(LOW_OBP_ADDRESS), %g5
cmp %g4, %g5 cmp %g4, %g5
blu,pn %xcc, kern_vpte blu,pn %xcc, kvmap_itlb_vmalloc_addr
mov 0x1, %g5 mov 0x1, %g5
sllx %g5, 32, %g5 sllx %g5, 32, %g5
cmp %g4, %g5 cmp %g4, %g5
blu,pn %xcc, vpte_insn_obp blu,pn %xcc, kvmap_itlb_obp
nop nop
/* These two instructions are patched by paginig_init(). */ kvmap_itlb_vmalloc_addr:
kern_vpte: KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
sethi %hi(swapper_pgd_zero), %g5
lduw [%g5 + %lo(swapper_pgd_zero)], %g5
/* With kernel PGD in %g5, branch back into dtlb_backend. */ KTSB_LOCK_TAG(%g1, %g2, %g7)
ba,pt %xcc, sparc64_kpte_continue
andn %g1, 0x3, %g1 /* Finish PMD offset adjustment. */
vpte_noent: /* Load and check PTE. */
/* Restore previous TAG_ACCESS, %g5 is zero, and we will ldxa [%g5] ASI_PHYS_USE_EC, %g5
* skip over the trap instruction so that the top level mov 1, %g7
* TLB miss handler will thing this %g5 value is just an sllx %g7, TSB_TAG_INVALID_BIT, %g7
* invalid PTE, thus branching to full fault processing. brgez,a,pn %g5, kvmap_itlb_longpath
*/ KTSB_STORE(%g1, %g7)
mov TLB_SFSR, %g1
stxa %g4, [%g1 + %g1] ASI_DMMU KTSB_WRITE(%g1, %g5, %g6)
done
/* fallthrough to TLB load */
vpte_insn_obp:
/* Behave as if we are at TL0. */
wrpr %g0, 1, %tl
rdpr %tpc, %g4 /* Find original faulting iaddr */
srlx %g4, 13, %g4 /* Throw out context bits */
sllx %g4, 13, %g4 /* g4 has vpn + ctx0 now */
/* Restore previous TAG_ACCESS. */
mov TLB_SFSR, %g1
stxa %g4, [%g1 + %g1] ASI_IMMU
sethi %hi(prom_trans), %g5
or %g5, %lo(prom_trans), %g5
1: ldx [%g5 + 0x00], %g6 ! base
brz,a,pn %g6, longpath ! no more entries, fail
mov TLB_SFSR, %g1 ! and restore %g1
ldx [%g5 + 0x08], %g1 ! len
add %g6, %g1, %g1 ! end
cmp %g6, %g4
bgu,pt %xcc, 2f
cmp %g4, %g1
bgeu,pt %xcc, 2f
ldx [%g5 + 0x10], %g1 ! PTE
/* TLB load, restore %g1, and return from trap. */
sub %g4, %g6, %g6
add %g1, %g6, %g5
mov TLB_SFSR, %g1
stxa %g5, [%g0] ASI_ITLB_DATA_IN
retry
2: ba,pt %xcc, 1b kvmap_itlb_load:
add %g5, (3 * 8), %g5 ! next entry
661: stxa %g5, [%g0] ASI_ITLB_DATA_IN
kvmap_do_obp:
sethi %hi(prom_trans), %g5
or %g5, %lo(prom_trans), %g5
srlx %g4, 13, %g4
sllx %g4, 13, %g4
1: ldx [%g5 + 0x00], %g6 ! base
brz,a,pn %g6, longpath ! no more entries, fail
mov TLB_SFSR, %g1 ! and restore %g1
ldx [%g5 + 0x08], %g1 ! len
add %g6, %g1, %g1 ! end
cmp %g6, %g4
bgu,pt %xcc, 2f
cmp %g4, %g1
bgeu,pt %xcc, 2f
ldx [%g5 + 0x10], %g1 ! PTE
/* TLB load, restore %g1, and return from trap. */
sub %g4, %g6, %g6
add %g1, %g6, %g5
mov TLB_SFSR, %g1
stxa %g5, [%g0] ASI_DTLB_DATA_IN
retry retry
.section .sun4v_2insn_patch, "ax"
.word 661b
nop
nop
.previous
/* For sun4v the ASI_ITLB_DATA_IN store and the retry
* instruction get nop'd out and we get here to branch
* to the sun4v tlb load code. The registers are setup
* as follows:
*
* %g4: vaddr
* %g5: PTE
* %g6: TAG
*
* The sun4v TLB load wants the PTE in %g3 so we fix that
* up here.
*/
ba,pt %xcc, sun4v_itlb_load
mov %g5, %g3
2: ba,pt %xcc, 1b kvmap_itlb_longpath:
add %g5, (3 * 8), %g5 ! next entry
661: rdpr %pstate, %g5
wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
.section .sun4v_2insn_patch, "ax"
.word 661b
SET_GL(1)
nop
.previous
rdpr %tpc, %g5
ba,pt %xcc, sparc64_realfault_common
mov FAULT_CODE_ITLB, %g4
kvmap_itlb_obp:
OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
KTSB_LOCK_TAG(%g1, %g2, %g7)
KTSB_WRITE(%g1, %g5, %g6)
ba,pt %xcc, kvmap_itlb_load
nop
kvmap_dtlb_obp:
OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
KTSB_LOCK_TAG(%g1, %g2, %g7)
KTSB_WRITE(%g1, %g5, %g6)
ba,pt %xcc, kvmap_dtlb_load
nop
/*
* On a first level data miss, check whether this is to the OBP range (note
* that such accesses can be made by prom, as well as by kernel using
* prom_getproperty on "address"), and if so, do not use vpte access ...
* rather, use information saved during inherit_prom_mappings() using 8k
* pagesize.
*/
.align 32 .align 32
kvmap: kvmap_dtlb_tsb4m_load:
brgez,pn %g4, kvmap_nonlinear KTSB_LOCK_TAG(%g1, %g2, %g7)
KTSB_WRITE(%g1, %g5, %g6)
ba,pt %xcc, kvmap_dtlb_load
nop nop
#ifdef CONFIG_DEBUG_PAGEALLOC kvmap_dtlb:
/* %g6: TAG TARGET */
mov TLB_TAG_ACCESS, %g4
ldxa [%g4] ASI_DMMU, %g4
/* sun4v_dtlb_miss branches here with the missing virtual
* address already loaded into %g4
*/
kvmap_dtlb_4v:
brgez,pn %g4, kvmap_dtlb_nonlinear
nop
/* Correct TAG_TARGET is already in %g6, check 4mb TSB. */
KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
/* TSB entry address left in %g1, lookup linear PTE.
* Must preserve %g1 and %g6 (TAG).
*/
kvmap_dtlb_tsb4m_miss:
sethi %hi(kpte_linear_bitmap), %g2
or %g2, %lo(kpte_linear_bitmap), %g2
/* Clear the PAGE_OFFSET top virtual bits, then shift
* down to get a 256MB physical address index.
*/
sllx %g4, 21, %g5
mov 1, %g7
srlx %g5, 21 + 28, %g5
/* Don't try this at home kids... this depends upon srlx
* only taking the low 6 bits of the shift count in %g5.
*/
sllx %g7, %g5, %g7
/* Divide by 64 to get the offset into the bitmask. */
srlx %g5, 6, %g5
sllx %g5, 3, %g5
/* kern_linear_pte_xor[((mask & bit) ? 1 : 0)] */
ldx [%g2 + %g5], %g2
andcc %g2, %g7, %g0
sethi %hi(kern_linear_pte_xor), %g5
or %g5, %lo(kern_linear_pte_xor), %g5
bne,a,pt %xcc, 1f
add %g5, 8, %g5
1: ldx [%g5], %g2
.globl kvmap_linear_patch .globl kvmap_linear_patch
kvmap_linear_patch: kvmap_linear_patch:
#endif ba,pt %xcc, kvmap_dtlb_tsb4m_load
ba,pt %xcc, kvmap_load
xor %g2, %g4, %g5 xor %g2, %g4, %g5
#ifdef CONFIG_DEBUG_PAGEALLOC kvmap_dtlb_vmalloc_addr:
sethi %hi(swapper_pg_dir), %g5 KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
or %g5, %lo(swapper_pg_dir), %g5
sllx %g4, 64 - (PGDIR_SHIFT + PGDIR_BITS), %g6 KTSB_LOCK_TAG(%g1, %g2, %g7)
srlx %g6, 64 - PAGE_SHIFT, %g6
andn %g6, 0x3, %g6 /* Load and check PTE. */
lduw [%g5 + %g6], %g5 ldxa [%g5] ASI_PHYS_USE_EC, %g5
brz,pn %g5, longpath mov 1, %g7
sllx %g4, 64 - (PMD_SHIFT + PMD_BITS), %g6 sllx %g7, TSB_TAG_INVALID_BIT, %g7
srlx %g6, 64 - PAGE_SHIFT, %g6 brgez,a,pn %g5, kvmap_dtlb_longpath
sllx %g5, 11, %g5 KTSB_STORE(%g1, %g7)
andn %g6, 0x3, %g6
lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 KTSB_WRITE(%g1, %g5, %g6)
brz,pn %g5, longpath
sllx %g4, 64 - PMD_SHIFT, %g6 /* fallthrough to TLB load */
srlx %g6, 64 - PAGE_SHIFT, %g6
sllx %g5, 11, %g5 kvmap_dtlb_load:
andn %g6, 0x7, %g6
ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 661: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
brz,pn %g5, longpath retry
.section .sun4v_2insn_patch, "ax"
.word 661b
nop
nop
.previous
/* For sun4v the ASI_DTLB_DATA_IN store and the retry
* instruction get nop'd out and we get here to branch
* to the sun4v tlb load code. The registers are setup
* as follows:
*
* %g4: vaddr
* %g5: PTE
* %g6: TAG
*
* The sun4v TLB load wants the PTE in %g3 so we fix that
* up here.
*/
ba,pt %xcc, sun4v_dtlb_load
mov %g5, %g3
kvmap_dtlb_nonlinear:
/* Catch kernel NULL pointer derefs. */
sethi %hi(PAGE_SIZE), %g5
cmp %g4, %g5
bleu,pn %xcc, kvmap_dtlb_longpath
nop nop
ba,a,pt %xcc, kvmap_load
#endif
kvmap_nonlinear: KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
kvmap_dtlb_tsbmiss:
sethi %hi(MODULES_VADDR), %g5 sethi %hi(MODULES_VADDR), %g5
cmp %g4, %g5 cmp %g4, %g5
blu,pn %xcc, longpath blu,pn %xcc, kvmap_dtlb_longpath
mov (VMALLOC_END >> 24), %g5 mov (VMALLOC_END >> 24), %g5
sllx %g5, 24, %g5 sllx %g5, 24, %g5
cmp %g4, %g5 cmp %g4, %g5
bgeu,pn %xcc, longpath bgeu,pn %xcc, kvmap_dtlb_longpath
nop nop
kvmap_check_obp: kvmap_check_obp:
sethi %hi(LOW_OBP_ADDRESS), %g5 sethi %hi(LOW_OBP_ADDRESS), %g5
cmp %g4, %g5 cmp %g4, %g5
blu,pn %xcc, kvmap_vmalloc_addr blu,pn %xcc, kvmap_dtlb_vmalloc_addr
mov 0x1, %g5 mov 0x1, %g5
sllx %g5, 32, %g5 sllx %g5, 32, %g5
cmp %g4, %g5 cmp %g4, %g5
blu,pn %xcc, kvmap_do_obp blu,pn %xcc, kvmap_dtlb_obp
nop nop
ba,pt %xcc, kvmap_dtlb_vmalloc_addr
kvmap_vmalloc_addr:
/* If we get here, a vmalloc addr was accessed, load kernel VPTE. */
ldxa [%g3 + %g6] ASI_N, %g5
brgez,pn %g5, longpath
nop nop
kvmap_load: kvmap_dtlb_longpath:
/* PTE is valid, load into TLB and return from trap. */
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB 661: rdpr %pstate, %g5
retry wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
.section .sun4v_2insn_patch, "ax"
.word 661b
SET_GL(1)
ldxa [%g0] ASI_SCRATCHPAD, %g5
.previous
rdpr %tl, %g3
cmp %g3, 1
661: mov TLB_TAG_ACCESS, %g4
ldxa [%g4] ASI_DMMU, %g5
.section .sun4v_2insn_patch, "ax"
.word 661b
ldx [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
nop
.previous
be,pt %xcc, sparc64_realfault_common
mov FAULT_CODE_DTLB, %g4
ba,pt %xcc, winfix_trampoline
nop
...@@ -188,6 +188,7 @@ extern void psycho_init(int, char *); ...@@ -188,6 +188,7 @@ extern void psycho_init(int, char *);
extern void schizo_init(int, char *); extern void schizo_init(int, char *);
extern void schizo_plus_init(int, char *); extern void schizo_plus_init(int, char *);
extern void tomatillo_init(int, char *); extern void tomatillo_init(int, char *);
extern void sun4v_pci_init(int, char *);
static struct { static struct {
char *model_name; char *model_name;
...@@ -204,6 +205,7 @@ static struct { ...@@ -204,6 +205,7 @@ static struct {
{ "pci108e,8002", schizo_plus_init }, { "pci108e,8002", schizo_plus_init },
{ "SUNW,tomatillo", tomatillo_init }, { "SUNW,tomatillo", tomatillo_init },
{ "pci108e,a801", tomatillo_init }, { "pci108e,a801", tomatillo_init },
{ "SUNW,sun4v-pci", sun4v_pci_init },
}; };
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0])) sizeof(pci_controller_table[0]))
...@@ -283,6 +285,12 @@ int __init pcic_present(void) ...@@ -283,6 +285,12 @@ int __init pcic_present(void)
return pci_controller_scan(pci_is_controller); return pci_controller_scan(pci_is_controller);
} }
struct pci_iommu_ops *pci_iommu_ops;
EXPORT_SYMBOL(pci_iommu_ops);
extern struct pci_iommu_ops pci_sun4u_iommu_ops,
pci_sun4v_iommu_ops;
/* Find each controller in the system, attach and initialize /* Find each controller in the system, attach and initialize
* software state structure for each and link into the * software state structure for each and link into the
* pci_controller_root. Setup the controller enough such * pci_controller_root. Setup the controller enough such
...@@ -290,6 +298,11 @@ int __init pcic_present(void) ...@@ -290,6 +298,11 @@ int __init pcic_present(void)
*/ */
static void __init pci_controller_probe(void) static void __init pci_controller_probe(void)
{ {
if (tlb_type == hypervisor)
pci_iommu_ops = &pci_sun4v_iommu_ops;
else
pci_iommu_ops = &pci_sun4u_iommu_ops;
printk("PCI: Probing for controllers.\n"); printk("PCI: Probing for controllers.\n");
pci_controller_scan(pci_controller_init); pci_controller_scan(pci_controller_init);
......
...@@ -39,6 +39,8 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm, ...@@ -39,6 +39,8 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm,
{ {
int node; int node;
*nregs = 0;
/* /*
* Return the PBM's PROM node in case we are it's PCI device, * Return the PBM's PROM node in case we are it's PCI device,
* as the PBM's reg property is different to standard PCI reg * 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,10 +53,8 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm,
pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || pdev->device == PCI_DEVICE_ID_SUN_SCHIZO ||
pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
pdev->device == PCI_DEVICE_ID_SUN_SABRE || pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) { pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
*nregs = 0;
return bus_prom_node; return bus_prom_node;
}
node = prom_getchild(bus_prom_node); node = prom_getchild(bus_prom_node);
while (node != 0) { while (node != 0) {
...@@ -541,135 +541,183 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, ...@@ -541,135 +541,183 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
pci_assign_unassigned(pbm, bus); pci_assign_unassigned(pbm, bus);
} }
static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm,
struct pci_dev *toplevel_pdev,
struct pci_dev *pdev,
unsigned int interrupt)
{ {
struct linux_prom_pci_intmap bridge_local_intmap[PROM_PCIIMAP_MAX], *intmap; unsigned int ret;
struct linux_prom_pci_intmask bridge_local_intmask, *intmask;
struct pcidev_cookie *dev_pcp = pdev->sysdata;
struct pci_pbm_info *pbm = dev_pcp->pbm;
struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
unsigned int hi, mid, lo, irq;
int i, num_intmap, map_slot;
intmap = &pbm->pbm_intmap[0]; if (unlikely(interrupt < 1 || interrupt > 4)) {
intmask = &pbm->pbm_intmask; printk("%s: Device %s interrupt value of %u is strange.\n",
num_intmap = pbm->num_pbm_intmap; pbm->name, pci_name(pdev), interrupt);
map_slot = 0; return interrupt;
}
/* If we are underneath a PCI bridge, use PROM register ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1;
* property of the parent bridge which is closest to
* the PBM. printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
* pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
* However if that parent bridge has interrupt map/mask interrupt, PCI_SLOT(pdev->devfn), ret);
* properties of its own we use the PROM register property
* of the next child device on the path to PDEV. return ret;
* }
* In detail the two cases are (note that the 'X' below is the
* 'next child on the path to PDEV' mentioned above): static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
* struct pci_dev *toplevel_pdev,
* 1) PBM --> PCI bus lacking int{map,mask} --> X ... PDEV struct pci_dev *pbus,
* struct pci_dev *pdev,
* Here we use regs of 'PCI bus' device. unsigned int interrupt,
* unsigned int *cnode)
* 2) PBM --> PCI bus with int{map,mask} --> X ... PDEV {
* struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX];
* Here we use regs of 'X'. Note that X can be PDEV. struct linux_prom_pci_intmask imask;
*/ struct pcidev_cookie *pbus_pcp = pbus->sysdata;
if (pdev->bus->number != pbm->pci_first_busno) { struct pcidev_cookie *pdev_pcp = pdev->sysdata;
struct pcidev_cookie *bus_pcp, *regs_pcp; struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs;
struct pci_dev *bus_dev, *regs_dev; int plen, num_imap, i;
int plen; unsigned int hi, mid, lo, irq, orig_interrupt;
*cnode = pbus_pcp->prom_node;
plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map",
(char *) &imap[0], sizeof(imap));
if (plen <= 0 ||
(plen % sizeof(struct linux_prom_pci_intmap)) != 0) {
printk("%s: Device %s interrupt-map has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
num_imap = plen / sizeof(struct linux_prom_pci_intmap);
plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask",
(char *) &imask, sizeof(imask));
if (plen <= 0 ||
(plen % sizeof(struct linux_prom_pci_intmask)) != 0) {
printk("%s: Device %s interrupt-map-mask has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
orig_interrupt = interrupt;
bus_dev = pdev->bus->self; hi = pregs->phys_hi & imask.phys_hi;
regs_dev = pdev; mid = pregs->phys_mid & imask.phys_mid;
lo = pregs->phys_lo & imask.phys_lo;
irq = interrupt & imask.interrupt;
while (bus_dev->bus && for (i = 0; i < num_imap; i++) {
bus_dev->bus->number != pbm->pci_first_busno) { if (imap[i].phys_hi == hi &&
regs_dev = bus_dev; imap[i].phys_mid == mid &&
bus_dev = bus_dev->bus->self; imap[i].phys_lo == lo &&
imap[i].interrupt == irq) {
*cnode = imap[i].cnode;
interrupt = imap[i].cinterrupt;
} }
}
regs_pcp = regs_dev->sysdata; printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
pregs = regs_pcp->prom_regs; pbm->name, pci_name(toplevel_pdev),
pci_name(pbus), pci_name(pdev),
orig_interrupt, interrupt);
bus_pcp = bus_dev->sysdata; no_intmap:
return interrupt;
}
/* But if the PCI bridge has it's own interrupt map /* For each PCI bus on the way to the root:
* and mask properties, use that and the regs of the * 1) If it has an interrupt-map property, apply it.
* PCI entity at the next level down on the path to the * 2) Else, swivel the interrupt number based upon the PCI device number.
* device. *
*/ * Return the "IRQ controller" node. If this is the PBM's device node,
plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map", * all interrupt translations are complete, else we should use that node's
(char *) &bridge_local_intmap[0], * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt.
sizeof(bridge_local_intmap)); */
if (plen != -1) { static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm,
intmap = &bridge_local_intmap[0]; struct pci_dev *pdev,
num_intmap = plen / sizeof(struct linux_prom_pci_intmap); unsigned int *interrupt)
plen = prom_getproperty(bus_pcp->prom_node, {
"interrupt-map-mask", struct pci_dev *toplevel_pdev = pdev;
(char *) &bridge_local_intmask, struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata;
sizeof(bridge_local_intmask)); unsigned int cnode = toplevel_pcp->prom_node;
if (plen == -1) {
printk("pci_intmap_match: Warning! Bridge has intmap " while (pdev->bus->number != pbm->pci_first_busno) {
"but no intmask.\n"); struct pci_dev *pbus = pdev->bus->self;
printk("pci_intmap_match: Trying to recover.\n"); struct pcidev_cookie *pcp = pbus->sysdata;
return 0; int plen;
}
if (pdev->bus->self != bus_dev) plen = prom_getproplen(pcp->prom_node, "interrupt-map");
map_slot = 1; if (plen <= 0) {
*interrupt = pci_slot_swivel(pbm, toplevel_pdev,
pdev, *interrupt);
cnode = pcp->prom_node;
} else { } else {
pregs = bus_pcp->prom_regs; *interrupt = pci_apply_intmap(pbm, toplevel_pdev,
map_slot = 1; pbus, pdev,
*interrupt, &cnode);
while (pcp->prom_node != cnode &&
pbus->bus->number != pbm->pci_first_busno) {
pbus = pbus->bus->self;
pcp = pbus->sysdata;
}
} }
} pdev = pbus;
if (map_slot) { if (cnode == pbm->prom_node)
*interrupt = ((*interrupt break;
- 1
+ PCI_SLOT(pdev->devfn)) & 0x3) + 1;
} }
hi = pregs->phys_hi & intmask->phys_hi; return cnode;
mid = pregs->phys_mid & intmask->phys_mid; }
lo = pregs->phys_lo & intmask->phys_lo;
irq = *interrupt & intmask->interrupt; static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
{
for (i = 0; i < num_intmap; i++) { struct pcidev_cookie *dev_pcp = pdev->sysdata;
if (intmap[i].phys_hi == hi && struct pci_pbm_info *pbm = dev_pcp->pbm;
intmap[i].phys_mid == mid && struct linux_prom_pci_registers reg[PROMREG_MAX];
intmap[i].phys_lo == lo && unsigned int hi, mid, lo, irq;
intmap[i].interrupt == irq) { int i, cnode, plen;
*interrupt = intmap[i].cinterrupt;
printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n", cnode = pci_intmap_match_to_root(pbm, pdev, interrupt);
pdev->bus->number, PCI_SLOT(pdev->devfn), if (cnode == pbm->prom_node)
map_slot, *interrupt); goto success;
return 1;
} plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg));
if (plen <= 0 ||
(plen % sizeof(struct linux_prom_pci_registers)) != 0) {
printk("%s: OBP node %x reg property has bad len %d\n",
pbm->name, cnode, plen);
goto fail;
} }
/* We will run this code even if pbm->num_pbm_intmap is zero, just so hi = reg[0].phys_hi & pbm->pbm_intmask.phys_hi;
* we can apply the slot mapping to the PROM interrupt property value. mid = reg[0].phys_mid & pbm->pbm_intmask.phys_mid;
* So do not spit out these warnings in that case. lo = reg[0].phys_lo & pbm->pbm_intmask.phys_lo;
*/ irq = *interrupt & pbm->pbm_intmask.interrupt;
if (num_intmap != 0) {
/* Print it both to OBP console and kernel one so that if bootup for (i = 0; i < pbm->num_pbm_intmap; i++) {
* hangs here the user has the information to report. struct linux_prom_pci_intmap *intmap;
*/
prom_printf("pci_intmap_match: bus %02x, devfn %02x: ", intmap = &pbm->pbm_intmap[i];
pdev->bus->number, pdev->devfn);
prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", if (intmap->phys_hi == hi &&
pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); intmap->phys_mid == mid &&
prom_printf("Please email this information to davem@redhat.com\n"); intmap->phys_lo == lo &&
intmap->interrupt == irq) {
printk("pci_intmap_match: bus %02x, devfn %02x: ", *interrupt = intmap->cinterrupt;
pdev->bus->number, pdev->devfn); goto success;
printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", }
pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
printk("Please email this information to davem@redhat.com\n");
} }
fail:
return 0; return 0;
success:
printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
pdev->bus->number, PCI_SLOT(pdev->devfn),
*interrupt);
return 1;
} }
static void __init pdev_fixup_irq(struct pci_dev *pdev) 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,16 +751,18 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
return; return;
} }
/* Fully specified already? */ if (tlb_type != hypervisor) {
if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { /* Fully specified already? */
pdev->irq = p->irq_build(pbm, pdev, prom_irq); if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
goto have_irq; pdev->irq = p->irq_build(pbm, pdev, prom_irq);
} goto have_irq;
}
/* An onboard device? (bit 5 set) */ /* An onboard device? (bit 5 set) */
if ((prom_irq & PCI_IRQ_INO) & 0x20) { if ((prom_irq & PCI_IRQ_INO) & 0x20) {
pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
goto have_irq; goto have_irq;
}
} }
/* Can we find a matching entry in the interrupt-map? */ /* Can we find a matching entry in the interrupt-map? */
...@@ -927,33 +977,30 @@ void pci_register_legacy_regions(struct resource *io_res, ...@@ -927,33 +977,30 @@ void pci_register_legacy_regions(struct resource *io_res,
struct resource *p; struct resource *p;
/* VGA Video RAM. */ /* VGA Video RAM. */
p = kmalloc(sizeof(*p), GFP_KERNEL); p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) if (!p)
return; return;
memset(p, 0, sizeof(*p));
p->name = "Video RAM area"; p->name = "Video RAM area";
p->start = mem_res->start + 0xa0000UL; p->start = mem_res->start + 0xa0000UL;
p->end = p->start + 0x1ffffUL; p->end = p->start + 0x1ffffUL;
p->flags = IORESOURCE_BUSY; p->flags = IORESOURCE_BUSY;
request_resource(mem_res, p); request_resource(mem_res, p);
p = kmalloc(sizeof(*p), GFP_KERNEL); p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) if (!p)
return; return;
memset(p, 0, sizeof(*p));
p->name = "System ROM"; p->name = "System ROM";
p->start = mem_res->start + 0xf0000UL; p->start = mem_res->start + 0xf0000UL;
p->end = p->start + 0xffffUL; p->end = p->start + 0xffffUL;
p->flags = IORESOURCE_BUSY; p->flags = IORESOURCE_BUSY;
request_resource(mem_res, p); request_resource(mem_res, p);
p = kmalloc(sizeof(*p), GFP_KERNEL); p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) if (!p)
return; return;
memset(p, 0, sizeof(*p));
p->name = "Video ROM"; p->name = "Video ROM";
p->start = mem_res->start + 0xc0000UL; p->start = mem_res->start + 0xc0000UL;
p->end = p->start + 0x7fffUL; p->end = p->start + 0x7fffUL;
......
...@@ -139,12 +139,11 @@ void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, ...@@ -139,12 +139,11 @@ void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset,
/* Allocate and initialize the free area map. */ /* Allocate and initialize the free area map. */
sz = num_tsb_entries / 8; sz = num_tsb_entries / 8;
sz = (sz + 7UL) & ~7UL; sz = (sz + 7UL) & ~7UL;
iommu->arena.map = kmalloc(sz, GFP_KERNEL); iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) { if (!iommu->arena.map) {
prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
prom_halt(); prom_halt();
} }
memset(iommu->arena.map, 0, sz);
iommu->arena.limit = num_tsb_entries; iommu->arena.limit = num_tsb_entries;
/* Allocate and initialize the dummy page which we /* 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,7 +218,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
* DMA for PCI device PDEV. Return non-NULL cpu-side address if * DMA for PCI device PDEV. Return non-NULL cpu-side address if
* successful and set *DMA_ADDRP to the PCI side dma address. * successful and set *DMA_ADDRP to the PCI side dma address.
*/ */
void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; 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,7 +266,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
} }
/* Free and unmap a consistent DMA translation. */ /* Free and unmap a consistent DMA translation. */
void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; struct pci_iommu *iommu;
...@@ -294,7 +293,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ ...@@ -294,7 +293,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
/* Map a single buffer at PTR of SZ bytes for PCI DMA /* Map a single buffer at PTR of SZ bytes for PCI DMA
* in streaming mode. * in streaming mode.
*/ */
dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; struct pci_iommu *iommu;
...@@ -415,7 +414,7 @@ do_flush_sync: ...@@ -415,7 +414,7 @@ do_flush_sync:
} }
/* Unmap a single streaming mode DMA translation. */ /* Unmap a single streaming mode DMA translation. */
void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; struct pci_iommu *iommu;
...@@ -548,7 +547,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, ...@@ -548,7 +547,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
* When making changes here, inspect the assembly output. I was having * When making changes here, inspect the assembly output. I was having
* hard time to kepp this routine out of using stack slots for holding variables. * hard time to kepp this routine out of using stack slots for holding variables.
*/ */
int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; struct pci_iommu *iommu;
...@@ -562,9 +561,9 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int ...@@ -562,9 +561,9 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int
/* Fast path single entry scatterlists. */ /* Fast path single entry scatterlists. */
if (nelems == 1) { if (nelems == 1) {
sglist->dma_address = sglist->dma_address =
pci_map_single(pdev, pci_4u_map_single(pdev,
(page_address(sglist->page) + sglist->offset), (page_address(sglist->page) + sglist->offset),
sglist->length, direction); sglist->length, direction);
if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE))
return 0; return 0;
sglist->dma_length = sglist->length; sglist->dma_length = sglist->length;
...@@ -635,7 +634,7 @@ bad_no_ctx: ...@@ -635,7 +634,7 @@ bad_no_ctx:
} }
/* Unmap a set of streaming mode DMA translations. */ /* Unmap a set of streaming mode DMA translations. */
void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; struct pci_iommu *iommu;
...@@ -695,7 +694,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, ...@@ -695,7 +694,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
/* Make physical memory consistent for a single /* Make physical memory consistent for a single
* streaming mode DMA translation after a transfer. * streaming mode DMA translation after a transfer.
*/ */
void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; 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,7 +734,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size
/* Make physical memory consistent for a set of streaming /* Make physical memory consistent for a set of streaming
* mode DMA translations after a transfer. * mode DMA translations after a transfer.
*/ */
void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{ {
struct pcidev_cookie *pcp; struct pcidev_cookie *pcp;
struct pci_iommu *iommu; struct pci_iommu *iommu;
...@@ -776,6 +775,17 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i ...@@ -776,6 +775,17 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
struct pci_iommu_ops pci_sun4u_iommu_ops = {
.alloc_consistent = pci_4u_alloc_consistent,
.free_consistent = pci_4u_free_consistent,
.map_single = pci_4u_map_single,
.unmap_single = pci_4u_unmap_single,
.map_sg = pci_4u_map_sg,
.unmap_sg = pci_4u_unmap_sg,
.dma_sync_single_for_cpu = pci_4u_dma_sync_single_for_cpu,
.dma_sync_sg_for_cpu = pci_4u_dma_sync_sg_for_cpu,
};
static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
{ {
struct pci_dev *ali_isa_bridge; struct pci_dev *ali_isa_bridge;
......
...@@ -286,17 +286,17 @@ static unsigned char psycho_pil_table[] = { ...@@ -286,17 +286,17 @@ static unsigned char psycho_pil_table[] = {
/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */
/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */
/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */
/*0x20*/4, /* SCSI */ /*0x20*/5, /* SCSI */
/*0x21*/5, /* Ethernet */ /*0x21*/5, /* Ethernet */
/*0x22*/8, /* Parallel Port */ /*0x22*/8, /* Parallel Port */
/*0x23*/13, /* Audio Record */ /*0x23*/13, /* Audio Record */
/*0x24*/14, /* Audio Playback */ /*0x24*/14, /* Audio Playback */
/*0x25*/15, /* PowerFail */ /*0x25*/15, /* PowerFail */
/*0x26*/4, /* second SCSI */ /*0x26*/5, /* second SCSI */
/*0x27*/11, /* Floppy */ /*0x27*/11, /* Floppy */
/*0x28*/4, /* Spare Hardware */ /*0x28*/5, /* Spare Hardware */
/*0x29*/9, /* Keyboard */ /*0x29*/9, /* Keyboard */
/*0x2a*/4, /* Mouse */ /*0x2a*/5, /* Mouse */
/*0x2b*/12, /* Serial */ /*0x2b*/12, /* Serial */
/*0x2c*/10, /* Timer 0 */ /*0x2c*/10, /* Timer 0 */
/*0x2d*/11, /* Timer 1 */ /*0x2d*/11, /* Timer 1 */
...@@ -313,11 +313,11 @@ static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) ...@@ -313,11 +313,11 @@ static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = psycho_pil_table[ino]; ret = psycho_pil_table[ino];
if (ret == 0 && pdev == NULL) { if (ret == 0 && pdev == NULL) {
ret = 4; ret = 5;
} else if (ret == 0) { } else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) { switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE: case PCI_BASE_CLASS_STORAGE:
ret = 4; ret = 5;
break; break;
case PCI_BASE_CLASS_NETWORK: case PCI_BASE_CLASS_NETWORK:
...@@ -336,7 +336,7 @@ static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) ...@@ -336,7 +336,7 @@ static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
break; break;
default: default:
ret = 4; ret = 5;
break; break;
}; };
} }
...@@ -1164,7 +1164,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) ...@@ -1164,7 +1164,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
static void pbm_scan_bus(struct pci_controller_info *p, static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm) struct pci_pbm_info *pbm)
{ {
struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie) { if (!cookie) {
prom_printf("PSYCHO: Critical allocation failure.\n"); prom_printf("PSYCHO: Critical allocation failure.\n");
...@@ -1172,7 +1172,6 @@ static void pbm_scan_bus(struct pci_controller_info *p, ...@@ -1172,7 +1172,6 @@ static void pbm_scan_bus(struct pci_controller_info *p,
} }
/* All we care about is the PBM. */ /* All we care about is the PBM. */
memset(cookie, 0, sizeof(*cookie));
cookie->pbm = pbm; cookie->pbm = pbm;
pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
...@@ -1465,18 +1464,16 @@ void psycho_init(int node, char *model_name) ...@@ -1465,18 +1464,16 @@ void psycho_init(int node, char *model_name)
} }
} }
p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p) { if (!p) {
prom_printf("PSYCHO: Fatal memory allocation error.\n"); prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt(); prom_halt();
} }
memset(p, 0, sizeof(*p)); iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu) { if (!iommu) {
prom_printf("PSYCHO: Fatal memory allocation error.\n"); prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt(); prom_halt();
} }
memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = p->pbm_B.iommu = iommu; p->pbm_A.iommu = p->pbm_B.iommu = iommu;
p->next = pci_controller_root; p->next = pci_controller_root;
......
...@@ -533,17 +533,17 @@ static unsigned char sabre_pil_table[] = { ...@@ -533,17 +533,17 @@ static unsigned char sabre_pil_table[] = {
/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */
/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */
/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */
/*0x20*/4, /* SCSI */ /*0x20*/5, /* SCSI */
/*0x21*/5, /* Ethernet */ /*0x21*/5, /* Ethernet */
/*0x22*/8, /* Parallel Port */ /*0x22*/8, /* Parallel Port */
/*0x23*/13, /* Audio Record */ /*0x23*/13, /* Audio Record */
/*0x24*/14, /* Audio Playback */ /*0x24*/14, /* Audio Playback */
/*0x25*/15, /* PowerFail */ /*0x25*/15, /* PowerFail */
/*0x26*/4, /* second SCSI */ /*0x26*/5, /* second SCSI */
/*0x27*/11, /* Floppy */ /*0x27*/11, /* Floppy */
/*0x28*/4, /* Spare Hardware */ /*0x28*/5, /* Spare Hardware */
/*0x29*/9, /* Keyboard */ /*0x29*/9, /* Keyboard */
/*0x2a*/4, /* Mouse */ /*0x2a*/5, /* Mouse */
/*0x2b*/12, /* Serial */ /*0x2b*/12, /* Serial */
/*0x2c*/10, /* Timer 0 */ /*0x2c*/10, /* Timer 0 */
/*0x2d*/11, /* Timer 1 */ /*0x2d*/11, /* Timer 1 */
...@@ -565,11 +565,11 @@ static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) ...@@ -565,11 +565,11 @@ static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = sabre_pil_table[ino]; ret = sabre_pil_table[ino];
if (ret == 0 && pdev == NULL) { if (ret == 0 && pdev == NULL) {
ret = 4; ret = 5;
} else if (ret == 0) { } else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) { switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE: case PCI_BASE_CLASS_STORAGE:
ret = 4; ret = 5;
break; break;
case PCI_BASE_CLASS_NETWORK: case PCI_BASE_CLASS_NETWORK:
...@@ -588,7 +588,7 @@ static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) ...@@ -588,7 +588,7 @@ static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
break; break;
default: default:
ret = 4; ret = 5;
break; break;
}; };
} }
...@@ -1167,7 +1167,7 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) ...@@ -1167,7 +1167,7 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm)
{ {
struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie) { if (!cookie) {
prom_printf("SABRE: Critical allocation failure.\n"); prom_printf("SABRE: Critical allocation failure.\n");
...@@ -1175,7 +1175,6 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) ...@@ -1175,7 +1175,6 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm)
} }
/* All we care about is the PBM. */ /* All we care about is the PBM. */
memset(cookie, 0, sizeof(*cookie));
cookie->pbm = pbm; cookie->pbm = pbm;
return cookie; return cookie;
...@@ -1556,19 +1555,17 @@ void sabre_init(int pnode, char *model_name) ...@@ -1556,19 +1555,17 @@ void sabre_init(int pnode, char *model_name)
} }
} }
p = kmalloc(sizeof(*p), GFP_ATOMIC); p = kzalloc(sizeof(*p), GFP_ATOMIC);
if (!p) { if (!p) {
prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n");
prom_halt(); prom_halt();
} }
memset(p, 0, sizeof(*p));
iommu = kmalloc(sizeof(*iommu), GFP_ATOMIC); iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
if (!iommu) { if (!iommu) {
prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
prom_halt(); prom_halt();
} }
memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = p->pbm_B.iommu = iommu; p->pbm_A.iommu = p->pbm_B.iommu = iommu;
upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);
......
...@@ -243,8 +243,8 @@ static unsigned char schizo_pil_table[] = { ...@@ -243,8 +243,8 @@ static unsigned char schizo_pil_table[] = {
/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ /*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */
/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ /*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */
/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ /*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */
/*0x18*/4, /* SCSI */ /*0x18*/5, /* SCSI */
/*0x19*/4, /* second SCSI */ /*0x19*/5, /* second SCSI */
/*0x1a*/0, /* UNKNOWN */ /*0x1a*/0, /* UNKNOWN */
/*0x1b*/0, /* UNKNOWN */ /*0x1b*/0, /* UNKNOWN */
/*0x1c*/8, /* Parallel */ /*0x1c*/8, /* Parallel */
...@@ -254,7 +254,7 @@ static unsigned char schizo_pil_table[] = { ...@@ -254,7 +254,7 @@ static unsigned char schizo_pil_table[] = {
/*0x20*/13, /* Audio Record */ /*0x20*/13, /* Audio Record */
/*0x21*/14, /* Audio Playback */ /*0x21*/14, /* Audio Playback */
/*0x22*/12, /* Serial */ /*0x22*/12, /* Serial */
/*0x23*/4, /* EBUS I2C */ /*0x23*/5, /* EBUS I2C */
/*0x24*/10, /* RTC Clock */ /*0x24*/10, /* RTC Clock */
/*0x25*/11, /* Floppy */ /*0x25*/11, /* Floppy */
/*0x26*/0, /* UNKNOWN */ /*0x26*/0, /* UNKNOWN */
...@@ -296,11 +296,11 @@ static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) ...@@ -296,11 +296,11 @@ static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = schizo_pil_table[ino]; ret = schizo_pil_table[ino];
if (ret == 0 && pdev == NULL) { if (ret == 0 && pdev == NULL) {
ret = 4; ret = 5;
} else if (ret == 0) { } else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) { switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE: case PCI_BASE_CLASS_STORAGE:
ret = 4; ret = 5;
break; break;
case PCI_BASE_CLASS_NETWORK: case PCI_BASE_CLASS_NETWORK:
...@@ -319,7 +319,7 @@ static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) ...@@ -319,7 +319,7 @@ static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
break; break;
default: default:
ret = 4; ret = 5;
break; break;
}; };
} }
...@@ -1525,7 +1525,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) ...@@ -1525,7 +1525,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
static void pbm_scan_bus(struct pci_controller_info *p, static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm) struct pci_pbm_info *pbm)
{ {
struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie) { if (!cookie) {
prom_printf("%s: Critical allocation failure.\n", pbm->name); prom_printf("%s: Critical allocation failure.\n", pbm->name);
...@@ -1533,7 +1533,6 @@ static void pbm_scan_bus(struct pci_controller_info *p, ...@@ -1533,7 +1533,6 @@ static void pbm_scan_bus(struct pci_controller_info *p,
} }
/* All we care about is the PBM. */ /* All we care about is the PBM. */
memset(cookie, 0, sizeof(*cookie));
cookie->pbm = pbm; cookie->pbm = pbm;
pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, 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,27 +2119,24 @@ static void __schizo_init(int node, char *model_name, int chip_type)
} }
} }
p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p) { if (!p) {
prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt(); prom_halt();
} }
memset(p, 0, sizeof(*p));
iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu) { if (!iommu) {
prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt(); prom_halt();
} }
memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = iommu; p->pbm_A.iommu = iommu;
iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu) { if (!iommu) {
prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt(); prom_halt();
} }
memset(iommu, 0, sizeof(*iommu));
p->pbm_B.iommu = iommu; p->pbm_B.iommu = iommu;
p->next = pci_controller_root; p->next = pci_controller_root;
......
此差异已折叠。
/* pci_sun4v.h: SUN4V specific PCI controller support.
*
* Copyright (C) 2006 David S. Miller (davem@davemloft.net)
*/
#ifndef _PCI_SUN4V_H
#define _PCI_SUN4V_H
extern long pci_sun4v_iommu_map(unsigned long devhandle,
unsigned long tsbid,
unsigned long num_ttes,
unsigned long io_attributes,
unsigned long io_page_list_pa);
extern unsigned long pci_sun4v_iommu_demap(unsigned long devhandle,
unsigned long tsbid,
unsigned long num_ttes);
extern unsigned long pci_sun4v_iommu_getmap(unsigned long devhandle,
unsigned long tsbid,
unsigned long *io_attributes,
unsigned long *real_address);
extern unsigned long pci_sun4v_config_get(unsigned long devhandle,
unsigned long pci_device,
unsigned long config_offset,
unsigned long size);
extern int pci_sun4v_config_put(unsigned long devhandle,
unsigned long pci_device,
unsigned long config_offset,
unsigned long size,
unsigned long data);
#endif /* !(_PCI_SUN4V_H) */
/* pci_sun4v_asm: Hypervisor calls for PCI support.
*
* Copyright (C) 2006 David S. Miller <davem@davemloft.net>
*/
#include <asm/hypervisor.h>
/* %o0: devhandle
* %o1: tsbid
* %o2: num ttes
* %o3: io_attributes
* %o4: io_page_list phys address
*
* returns %o0: -status if status was non-zero, else
* %o0: num pages mapped
*/
.globl pci_sun4v_iommu_map
pci_sun4v_iommu_map:
mov %o5, %g1
mov HV_FAST_PCI_IOMMU_MAP, %o5
ta HV_FAST_TRAP
brnz,pn %o0, 1f
sub %g0, %o0, %o0
mov %o1, %o0
1: retl
nop
/* %o0: devhandle
* %o1: tsbid
* %o2: num ttes
*
* returns %o0: num ttes demapped
*/
.globl pci_sun4v_iommu_demap
pci_sun4v_iommu_demap:
mov HV_FAST_PCI_IOMMU_DEMAP, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
/* %o0: devhandle
* %o1: tsbid
* %o2: &io_attributes
* %o3: &real_address
*
* returns %o0: status
*/
.globl pci_sun4v_iommu_getmap
pci_sun4v_iommu_getmap:
mov %o2, %o4
mov HV_FAST_PCI_IOMMU_GETMAP, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
stx %o2, [%o3]
retl
mov %o0, %o0
/* %o0: devhandle
* %o1: pci_device
* %o2: pci_config_offset
* %o3: size
*
* returns %o0: data
*
* If there is an error, the data will be returned
* as all 1's.
*/
.globl pci_sun4v_config_get
pci_sun4v_config_get:
mov HV_FAST_PCI_CONFIG_GET, %o5
ta HV_FAST_TRAP
brnz,a,pn %o1, 1f
mov -1, %o2
1: retl
mov %o2, %o0
/* %o0: devhandle
* %o1: pci_device
* %o2: pci_config_offset
* %o3: size
* %o4: data
*
* returns %o0: status
*
* status will be zero if the operation completed
* successfully, else -1 if not
*/
.globl pci_sun4v_config_put
pci_sun4v_config_put:
mov HV_FAST_PCI_CONFIG_PUT, %o5
ta HV_FAST_TRAP
brnz,a,pn %o1, 1f
mov -1, %o1
1: retl
mov %o1, %o0
此差异已折叠。
...@@ -124,6 +124,9 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, ...@@ -124,6 +124,9 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
{ {
BUG_ON(len > PAGE_SIZE); BUG_ON(len > PAGE_SIZE);
if (tlb_type == hypervisor)
return;
#ifdef DCACHE_ALIASING_POSSIBLE #ifdef DCACHE_ALIASING_POSSIBLE
/* If bit 13 of the kernel address we used to access the /* If bit 13 of the kernel address we used to access the
* user page is the same as the virtual address that page * user page is the same as the virtual address that page
......
此差异已折叠。
...@@ -693,11 +693,11 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) ...@@ -693,11 +693,11 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
/* SBUS SYSIO INO number to Sparc PIL level. */ /* SBUS SYSIO INO number to Sparc PIL level. */
static unsigned char sysio_ino_to_pil[] = { static unsigned char sysio_ino_to_pil[] = {
0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 0 */ 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 0 */
0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 1 */ 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 1 */
0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 2 */ 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 2 */
0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 3 */ 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 3 */
4, /* Onboard SCSI */ 5, /* Onboard SCSI */
5, /* Onboard Ethernet */ 5, /* Onboard Ethernet */
/*XXX*/ 8, /* Onboard BPP */ /*XXX*/ 8, /* Onboard BPP */
0, /* Bogon */ 0, /* Bogon */
......
此差异已折叠。
此差异已折叠。
...@@ -95,9 +95,6 @@ extern int __ashrdi3(int, int); ...@@ -95,9 +95,6 @@ extern int __ashrdi3(int, int);
extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs); extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs);
extern unsigned long phys_base;
extern unsigned long pfn_base;
extern unsigned int sys_call_table[]; extern unsigned int sys_call_table[];
extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); 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,6 +105,14 @@ extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *,
extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *,
unsigned long *, unsigned long *, unsigned long *); unsigned long *, unsigned long *, unsigned long *);
extern void xor_niagara_2(unsigned long, unsigned long *, unsigned long *);
extern void xor_niagara_3(unsigned long, unsigned long *, unsigned long *,
unsigned long *);
extern void xor_niagara_4(unsigned long, unsigned long *, unsigned long *,
unsigned long *, unsigned long *);
extern void xor_niagara_5(unsigned long, unsigned long *, unsigned long *,
unsigned long *, unsigned long *, unsigned long *);
/* Per-CPU information table */ /* Per-CPU information table */
EXPORT_PER_CPU_SYMBOL(__cpu_data); EXPORT_PER_CPU_SYMBOL(__cpu_data);
...@@ -241,10 +246,6 @@ EXPORT_SYMBOL(verify_compat_iovec); ...@@ -241,10 +246,6 @@ EXPORT_SYMBOL(verify_compat_iovec);
#endif #endif
EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(pte_alloc_one_kernel);
#ifndef CONFIG_SMP
EXPORT_SYMBOL(pgt_quicklists);
#endif
EXPORT_SYMBOL(put_fs_struct); EXPORT_SYMBOL(put_fs_struct);
/* math-emu wants this */ /* math-emu wants this */
...@@ -339,14 +340,10 @@ EXPORT_SYMBOL(copy_to_user_fixup); ...@@ -339,14 +340,10 @@ EXPORT_SYMBOL(copy_to_user_fixup);
EXPORT_SYMBOL(copy_from_user_fixup); EXPORT_SYMBOL(copy_from_user_fixup);
EXPORT_SYMBOL(copy_in_user_fixup); EXPORT_SYMBOL(copy_in_user_fixup);
EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__bzero_noasi); EXPORT_SYMBOL(__clear_user);
/* Various address conversion macros use this. */ /* Various address conversion macros use this. */
EXPORT_SYMBOL(phys_base);
EXPORT_SYMBOL(pfn_base);
EXPORT_SYMBOL(sparc64_valid_addr_bitmap); EXPORT_SYMBOL(sparc64_valid_addr_bitmap);
EXPORT_SYMBOL(page_to_pfn);
EXPORT_SYMBOL(pfn_to_page);
/* No version information on this, heavily used in inline asm, /* No version information on this, heavily used in inline asm,
* and will always be 'void __ret_efault(void)'. * and will always be 'void __ret_efault(void)'.
...@@ -392,4 +389,9 @@ EXPORT_SYMBOL(xor_vis_3); ...@@ -392,4 +389,9 @@ EXPORT_SYMBOL(xor_vis_3);
EXPORT_SYMBOL(xor_vis_4); EXPORT_SYMBOL(xor_vis_4);
EXPORT_SYMBOL(xor_vis_5); EXPORT_SYMBOL(xor_vis_5);
EXPORT_SYMBOL(xor_niagara_2);
EXPORT_SYMBOL(xor_niagara_3);
EXPORT_SYMBOL(xor_niagara_4);
EXPORT_SYMBOL(xor_niagara_5);
EXPORT_SYMBOL(prom_palette); EXPORT_SYMBOL(prom_palette);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -11,6 +11,8 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \ ...@@ -11,6 +11,8 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
VISsave.o atomic.o bitops.o \ VISsave.o atomic.o bitops.o \
U1memcpy.o U1copy_from_user.o U1copy_to_user.o \ U1memcpy.o U1copy_from_user.o U1copy_to_user.o \
U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
NGpage.o NGbzero.o \
copy_in_user.o user_fixup.o memmove.o \ copy_in_user.o user_fixup.o memmove.o \
mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册