diff options
Diffstat (limited to 'arch')
88 files changed, 2213 insertions, 1600 deletions
diff --git a/arch/alpha/config.in b/arch/alpha/config.in index df7ae01ca..d70d42421 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -126,6 +126,7 @@ if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y define_bool CONFIG_ALPHA_PYXIS y fi if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ] diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 6c538f4ba..9d87b6e0c 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -18,7 +18,7 @@ O_OBJS := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \ OX_OBJS := alpha_ksyms.o L_TARGET := rest.a -L_OBJS := irq_i8259.o irq_srm.o \ +L_OBJS := irq_i8259.o irq_srm.o irq_pyxis.o \ es1888.o smc37c669.o smc37c93x.o ns87312.o ifdef CONFIG_SMP @@ -32,7 +32,7 @@ endif ifdef CONFIG_ALPHA_GENERIC O_OBJS += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ - core_polaris.o core_pyxis.o core_t2.o core_tsunami.o \ + core_polaris.o core_t2.o core_tsunami.o \ sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \ sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ @@ -56,9 +56,6 @@ endif ifdef CONFIG_ALPHA_MCPCIA O_OBJS += core_mcpcia.o endif -ifdef CONFIG_ALPHA_PYXIS -O_OBJS += core_pyxis.o -endif ifdef CONFIG_ALPHA_T2 O_OBJS += core_t2.o endif diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 25d9583dd..0001799db 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -37,6 +37,7 @@ extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); extern spinlock_t kernel_flag; +extern spinlock_t rtc_lock; /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -106,6 +107,7 @@ EXPORT_SYMBOL(pci_map_single); EXPORT_SYMBOL(pci_unmap_single); EXPORT_SYMBOL(pci_map_sg); EXPORT_SYMBOL(pci_unmap_sg); +EXPORT_SYMBOL(pci_dma_supported); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); @@ -202,6 +204,8 @@ EXPORT_SYMBOL(__local_bh_count); EXPORT_SYMBOL(__local_irq_count); #endif /* __SMP__ */ +EXPORT_SYMBOL(rtc_lock); + /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index b8a7f18ee..481a682b1 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -6,7 +6,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1997, 1998 Jay Estabrook - * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1998, 1999, 2000 Richard Henderson * * Code common to all CIA core logic chips. */ @@ -25,6 +25,8 @@ #include <asm/core_cia.h> #undef __EXTERN_INLINE +#include <linux/bootmem.h> + #include "proto.h" #include "pci_impl.h" @@ -35,27 +37,20 @@ * handle the system transaction. Another involves timing. Ho hum. */ -/* - * BIOS32-style PCI interface: - */ - #define DEBUG_CONFIG 0 -#define DEBUG_DUMP_REGS 0 - #if DEBUG_CONFIG # define DBGC(args) printk args #else # define DBGC(args) #endif -#define vuip volatile unsigned int * +#define vip volatile int * /* * Given a bus, device, and function number, compute resulting - * configuration space address and setup the CIA_HAXR2 register - * accordingly. It is therefore not safe to have concurrent - * invocations to configuration space access routines, but there - * really shouldn't be any need for this. + * configuration space address. It is therefore not safe to have + * concurrent invocations to configuration space access routines, but + * there really shouldn't be any need for this. * * Type 0: * @@ -96,34 +91,16 @@ static int mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { - unsigned long addr; u8 bus = dev->bus->number; u8 device_fn = dev->devfn; - DBGC(("mk_conf_addr(bus=%d, device_fn=0x%x, where=0x%x, " - "pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); + *type1 = (bus != 0); + *pci_addr = (bus << 16) | (device_fn << 8) | where; - if (bus == 0) { - int device = device_fn >> 3; + DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + " returning address 0x%p\n" + bus, device_fn, where, *pci_addr)); - /* Type 0 configuration cycle. */ - - if (device > 20) { - DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n", - device)); - return -1; - } - - *type1 = 0; - addr = (device_fn << 8) | (where); - } else { - /* Type 1 configuration cycle. */ - *type1 = 1; - addr = (bus << 16) | (device_fn << 8) | (where); - } - *pci_addr = addr; - DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); return 0; } @@ -131,43 +108,37 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) { unsigned long flags; - unsigned int stat0, value; - unsigned int cia_cfg = 0; + int stat0, value; + int cia_cfg = 0; - value = 0xffffffffU; - mb(); - - __save_and_cli(flags); /* avoid getting hit by machine check */ - - DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); + DBGC(("conf_read(addr=0x%lx, type1=%d) ", addr, type1)); + __save_and_cli(flags); /* Reset status register to avoid losing errors. */ - stat0 = *(vuip)CIA_IOC_CIA_ERR; - *(vuip)CIA_IOC_CIA_ERR = stat0; + stat0 = *(vip)CIA_IOC_CIA_ERR; + *(vip)CIA_IOC_CIA_ERR = stat0; mb(); - DBGC(("conf_read: CIA ERR was 0x%x\n", stat0)); /* If Type1 access, must set CIA CFG. */ if (type1) { - cia_cfg = *(vuip)CIA_IOC_CFG; - *(vuip)CIA_IOC_CFG = cia_cfg | 1; + cia_cfg = *(vip)CIA_IOC_CFG; + *(vip)CIA_IOC_CFG = (cia_cfg & ~3) | 1; mb(); - DBGC(("conf_read: TYPE1 access\n")); + *(vip)CIA_IOC_CFG; } - mb(); draina(); mcheck_expected(0) = 1; mcheck_taken(0) = 0; mb(); /* Access configuration space. */ - value = *(vuip)addr; + value = *(vip)addr; mb(); mb(); /* magic */ if (mcheck_taken(0)) { mcheck_taken(0) = 0; - value = 0xffffffffU; + value = 0xffffffff; mb(); } mcheck_expected(0) = 0; @@ -175,13 +146,14 @@ conf_read(unsigned long addr, unsigned char type1) /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ if (type1) { - *(vuip)CIA_IOC_CFG = cia_cfg & ~1; + *(vip)CIA_IOC_CFG = cia_cfg; mb(); + *(vip)CIA_IOC_CFG; } - DBGC(("conf_read(): finished\n")); - __restore_flags(flags); + DBGC(("done\n")); + return value; } @@ -189,31 +161,31 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char type1) { unsigned long flags; - unsigned int stat0; - unsigned int cia_cfg = 0; + int stat0, cia_cfg = 0; - __save_and_cli(flags); /* avoid getting hit by machine check */ + DBGC(("conf_write(addr=0x%lx, type1=%d) ", addr, type1)); + __save_and_cli(flags); /* Reset status register to avoid losing errors. */ - stat0 = *(vuip)CIA_IOC_CIA_ERR; - *(vuip)CIA_IOC_CIA_ERR = stat0; + stat0 = *(vip)CIA_IOC_CIA_ERR; + *(vip)CIA_IOC_CIA_ERR = stat0; mb(); - DBGC(("conf_write: CIA ERR was 0x%x\n", stat0)); /* If Type1 access, must set CIA CFG. */ if (type1) { - cia_cfg = *(vuip)CIA_IOC_CFG; - *(vuip)CIA_IOC_CFG = cia_cfg | 1; + cia_cfg = *(vip)CIA_IOC_CFG; + *(vip)CIA_IOC_CFG = (cia_cfg & ~3) | 1; mb(); - DBGC(("conf_write: TYPE1 access\n")); + *(vip)CIA_IOC_CFG; } draina(); mcheck_expected(0) = 1; + mcheck_taken(0) = 0; mb(); /* Access configuration space. */ - *(vuip)addr = value; + *(vip)addr = value; mb(); mb(); /* magic */ @@ -222,12 +194,13 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ if (type1) { - *(vuip)CIA_IOC_CFG = cia_cfg & ~1; + *(vip)CIA_IOC_CFG = cia_cfg; mb(); + *(vip)CIA_IOC_CFG; } - DBGC(("conf_write(): finished\n")); __restore_flags(flags); + DBGC(("done\n")); } static int @@ -314,158 +287,442 @@ struct pci_ops cia_pci_ops = write_dword: cia_write_config_dword }; +/* + * CIA Pass 1 and PYXIS Pass 1 and 2 have a broken scatter-gather tlb. + * It cannot be invalidated. Rather than hard code the pass numbers, + * actually try the tbia to see if it works. + */ + void cia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) { wmb(); *(vip)CIA_IOC_PCI_TBIA = 3; /* Flush all locked and unlocked. */ mb(); + *(vip)CIA_IOC_PCI_TBIA; +} + +/* + * Fixup attempt number 1. + * + * Write zeros directly into the tag registers. + */ + +static void +cia_pci_tbi_try1(struct pci_controler *hose, + dma_addr_t start, dma_addr_t end) +{ + wmb(); + *(vip)CIA_IOC_TB_TAGn(0) = 0; + *(vip)CIA_IOC_TB_TAGn(1) = 0; + *(vip)CIA_IOC_TB_TAGn(2) = 0; + *(vip)CIA_IOC_TB_TAGn(3) = 0; + *(vip)CIA_IOC_TB_TAGn(4) = 0; + *(vip)CIA_IOC_TB_TAGn(5) = 0; + *(vip)CIA_IOC_TB_TAGn(6) = 0; + *(vip)CIA_IOC_TB_TAGn(7) = 0; + mb(); + *(vip)CIA_IOC_TB_TAGn(0); +} + +#if 0 +/* + * Fixup attempt number 2. This is the method NT and NetBSD use. + * + * Allocate mappings, and put the chip into DMA loopback mode to read a + * garbage page. This works by causing TLB misses, causing old entries to + * be purged to make room for the new entries coming in for the garbage page. + */ + +#define CIA_BROKEN_TBI_TRY2_BASE 0xE0000000 + +static void __init +cia_enable_broken_tbi_try2(void) +{ + unsigned long *ppte, pte; + long i; + + ppte = __alloc_bootmem(PAGE_SIZE, 32768, 0); + pte = (virt_to_phys(ppte) >> (PAGE_SHIFT - 1)) | 1; + + for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); ++i) + ppte[i] = pte; + + *(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBI_TRY2_BASE | 3; + *(vip)CIA_IOC_PCI_W3_MASK = (PAGE_SIZE - 1) & 0xfff00000; + *(vip)CIA_IOC_PCI_T3_BASE = virt_to_phys(ppte) >> 2; +} + +static void +cia_pci_tbi_try2(struct pci_controler *hose, + dma_addr_t start, dma_addr_t end) +{ + unsigned long flags; + unsigned long bus_addr; + int ctrl; + long i; + + __save_and_cli(flags); + + /* Put the chip into PCI loopback mode. */ + mb(); + ctrl = *(vip)CIA_IOC_CIA_CTRL; + *(vip)CIA_IOC_CIA_CTRL = ctrl | CIA_CTRL_PCI_LOOP_EN; + mb(); + *(vip)CIA_IOC_CIA_CTRL; + mb(); + + /* Read from PCI dense memory space at TBI_ADDR, skipping 32k on + each read. This forces SG TLB misses. NetBSD claims that the + TLB entries are not quite LRU, meaning that we need to read more + times than there are actual tags. The 2117x docs claim strict + round-robin. Oh well, we've come this far... */ + + bus_addr = cia_ioremap(CIA_BROKEN_TBI_TRY2_BASE); + for (i = 0; i < 12; ++i, bus_addr += 32768) + cia_readl(bus_addr); + + /* Restore normal PCI operation. */ + mb(); + *(vip)CIA_IOC_CIA_CTRL = ctrl; + mb(); + *(vip)CIA_IOC_CIA_CTRL; + mb(); + + __restore_flags(flags); +} +#endif + +static void __init +verify_tb_operation(void) +{ + static int page[PAGE_SIZE/4] + __attribute__((aligned(PAGE_SIZE))) + __initlocaldata = { 0 }; + + struct pci_iommu_arena *arena = pci_isa_hose->sg_isa; + int ctrl, addr0, tag0, pte0, data0; + int temp; + + /* Put the chip into PCI loopback mode. */ + mb(); + ctrl = *(vip)CIA_IOC_CIA_CTRL; + *(vip)CIA_IOC_CIA_CTRL = ctrl | CIA_CTRL_PCI_LOOP_EN; + mb(); + *(vip)CIA_IOC_CIA_CTRL; + mb(); + + /* Write a valid entry directly into the TLB registers. */ + + addr0 = arena->dma_base; + tag0 = addr0 | 1; + pte0 = (virt_to_phys(page) >> (PAGE_SHIFT - 1)) | 1; + + *(vip)CIA_IOC_TB_TAGn(0) = tag0; + *(vip)CIA_IOC_TB_TAGn(1) = 0; + *(vip)CIA_IOC_TB_TAGn(2) = 0; + *(vip)CIA_IOC_TB_TAGn(3) = 0; + *(vip)CIA_IOC_TB_TAGn(4) = 0; + *(vip)CIA_IOC_TB_TAGn(5) = 0; + *(vip)CIA_IOC_TB_TAGn(6) = 0; + *(vip)CIA_IOC_TB_TAGn(7) = 0; + *(vip)CIA_IOC_TBn_PAGEm(0,0) = pte0; + *(vip)CIA_IOC_TBn_PAGEm(0,1) = 0; + *(vip)CIA_IOC_TBn_PAGEm(0,2) = 0; + *(vip)CIA_IOC_TBn_PAGEm(0,3) = 0; + mb(); + + /* First, verify we can read back what we've written. If + this fails, we can't be sure of any of the other testing + we're going to do, so bail. */ + /* ??? Actually, we could do the work with machine checks. + By passing this register update test, we pretty much + guarantee that cia_pci_tbi_try1 works. If this test + fails, cia_pci_tbi_try2 might still work. */ + + temp = *(vip)CIA_IOC_TB_TAGn(0); + if (temp != tag0) { + printk("pci: failed tb register update test " + "(tag0 %#x != %#x)\n", temp, tag0); + goto failed; + } + temp = *(vip)CIA_IOC_TB_TAGn(1); + if (temp != 0) { + printk("pci: failed tb register update test " + "(tag1 %#x != 0)\n", temp); + goto failed; + } + temp = *(vip)CIA_IOC_TBn_PAGEm(0,0); + if (temp != pte0) { + printk("pci: failed tb register update test " + "(pte0 %#x != %#x)\n", temp, pte0); + goto failed; + } + printk("pci: passed tb register update test\n"); + + /* Second, verify we can actually do I/O through this entry. */ + + data0 = 0xdeadbeef; + page[0] = data0; + mcheck_expected(0) = 1; + mcheck_taken(0) = 0; + mb(); + temp = cia_readl(cia_ioremap(addr0)); + mb(); + mcheck_expected(0) = 0; + mb(); + if (mcheck_taken(0)) { + printk("pci: failed sg loopback i/o read test (mcheck)\n"); + goto failed; + } + if (temp != data0) { + printk("pci: failed sg loopback i/o read test " + "(%#x != %#x)\n", temp, data0); + goto failed; + } + printk("pci: passed sg loopback i/o read test\n"); + + /* Third, try to invalidate the TLB. */ + + cia_pci_tbi(arena->hose, 0, -1); + temp = *(vip)CIA_IOC_TB_TAGn(0); + if (temp & 1) { + cia_pci_tbi_try1(arena->hose, 0, -1); + + temp = *(vip)CIA_IOC_TB_TAGn(0); + if (temp & 1) { + printk("pci: failed tbia test; " + "no usable workaround\n"); + goto failed; + } + + alpha_mv.mv_pci_tbi = cia_pci_tbi_try1; + printk("pci: failed tbia test; workaround 1 succeeded\n"); + } else { + printk("pci: passed tbia test\n"); + } + + /* Fourth, verify the TLB snoops the EV5's caches when + doing a tlb fill. */ + + data0 = 0x5adda15e; + page[0] = data0; + arena->ptes[4] = pte0; + mcheck_expected(0) = 1; + mcheck_taken(0) = 0; + mb(); + temp = cia_readl(cia_ioremap(addr0 + 4*PAGE_SIZE)); + mb(); + mcheck_expected(0) = 0; + mb(); + if (mcheck_taken(0)) { + printk("pci: failed pte write cache snoop test (mcheck)\n"); + goto failed; + } + if (temp != data0) { + printk("pci: failed pte write cache snoop test " + "(%#x != %#x)\n", temp, data0); + goto failed; + } + printk("pci: passed pte write cache snoop test\n"); + + /* Fifth, verify that a previously invalid PTE entry gets + filled from the page table. */ + + data0 = 0xabcdef123; + page[0] = data0; + arena->ptes[5] = pte0; + mcheck_expected(0) = 1; + mcheck_taken(0) = 0; + mb(); + temp = cia_readl(cia_ioremap(addr0 + 5*PAGE_SIZE)); + mb(); + mcheck_expected(0) = 0; + mb(); + if (mcheck_taken(0)) { + printk("pci: failed valid tag invalid pte reload test " + "(mcheck; workaround available)\n"); + /* Work around this bug by aligning new allocations + on 4 page boundaries. */ + arena->align_entry = 4; + } else if (temp != data0) { + printk("pci: failed valid tag invalid pte reload test " + "(%#x != %#x)\n", temp, data0); + goto failed; + } else { + printk("pci: passed valid tag invalid pte reload test\n"); + } + + /* Sixth, verify machine checks are working. Test invalid + pte under the same valid tag as we used above. */ + + mcheck_expected(0) = 1; + mcheck_taken(0) = 0; + mb(); + temp = cia_readl(cia_ioremap(addr0 + 6*PAGE_SIZE)); + mb(); + mcheck_expected(0) = 0; + mb(); + printk("pci: %s pci machine check test\n", + mcheck_taken(0) ? "passed" : "failed"); + + /* Clean up after the tests. */ + arena->ptes[4] = 0; + arena->ptes[5] = 0; + alpha_mv.mv_pci_tbi(arena->hose, 0, -1); + +exit: + /* Restore normal PCI operation. */ + mb(); + *(vip)CIA_IOC_CIA_CTRL = ctrl; + mb(); + *(vip)CIA_IOC_CIA_CTRL; + mb(); + return; + +failed: + printk("pci: disabling sg translation window\n"); + *(vip)CIA_IOC_PCI_W0_BASE = 0; + alpha_mv.mv_pci_tbi = NULL; + goto exit; } -void __init -cia_init_arch(void) +static void __init +do_init_arch(int is_pyxis) { struct pci_controler *hose; - struct resource *hae_mem; - unsigned int temp; - -#if DEBUG_DUMP_REGS - temp = *(vuip)CIA_IOC_CIA_REV; mb(); - printk("cia_init: CIA_REV was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_PCI_LAT; mb(); - printk("cia_init: CIA_PCI_LAT was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CIA_CTRL; mb(); - printk("cia_init: CIA_CTRL was 0x%x\n", temp); - temp = *(vuip)0xfffffc8740000140UL; mb(); - printk("cia_init: CIA_CTRL1 was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_HAE_MEM; mb(); - printk("cia_init: CIA_HAE_MEM was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_HAE_IO; mb(); - printk("cia_init: CIA_HAE_IO was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CFG; mb(); - printk("cia_init: CIA_CFG was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CACK_EN; mb(); - printk("cia_init: CIA_CACK_EN was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CFG; mb(); - printk("cia_init: CIA_CFG was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CIA_DIAG; mb(); - printk("cia_init: CIA_DIAG was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_DIAG_CHECK; mb(); - printk("cia_init: CIA_DIAG_CHECK was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_PERF_MONITOR; mb(); - printk("cia_init: CIA_PERF_MONITOR was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_PERF_CONTROL; mb(); - printk("cia_init: CIA_PERF_CONTROL was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CIA_ERR; mb(); - printk("cia_init: CIA_ERR was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CIA_STAT; mb(); - printk("cia_init: CIA_STAT was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_MCR; mb(); - printk("cia_init: CIA_MCR was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_CIA_CTRL; mb(); - printk("cia_init: CIA_CTRL was 0x%x\n", temp); - temp = *(vuip)CIA_IOC_ERR_MASK; mb(); - printk("cia_init: CIA_ERR_MASK was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb(); - printk("cia_init: W0_BASE was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb(); - printk("cia_init: W1_BASE was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb(); - printk("cia_init: W2_BASE was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb(); - printk("cia_init: W3_BASE was 0x%x\n", temp); -#endif /* DEBUG_DUMP_REGS */ + int temp; + int cia_rev; + + cia_rev = *(vip)CIA_IOC_CIA_REV & CIA_REV_MASK; + printk("pci: cia revision %d%s\n", + cia_rev, is_pyxis ? " (pyxis)" : ""); + + /* Set up error reporting. */ + temp = *(vip)CIA_IOC_ERR_MASK; + temp &= ~(CIA_ERR_CPU_PE | CIA_ERR_MEM_NEM | CIA_ERR_PA_PTE_INV + | CIA_ERR_RCVD_MAS_ABT | CIA_ERR_RCVD_TAR_ABT); + *(vip)CIA_IOC_ERR_MASK = temp; + + /* Clear all currently pending errors. */ + *(vip)CIA_IOC_CIA_ERR = 0; + + /* Turn on mchecks. */ + temp = *(vip)CIA_IOC_CIA_CTRL; + temp |= CIA_CTRL_FILL_ERR_EN | CIA_CTRL_MCHK_ERR_EN; + *(vip)CIA_IOC_CIA_CTRL = temp; + + /* Clear the CFG register, which gets used for PCI config space + accesses. That is the way we want to use it, and we do not + want to depend on what ARC or SRM might have left behind. */ + *(vip)CIA_IOC_CFG = 0; + + /* Zero the HAEs. */ + *(vip)CIA_IOC_HAE_MEM = 0; + *(vip)CIA_IOC_HAE_IO = 0; + + /* For PYXIS, we always use BWX bus and i/o accesses. To that end, + make sure they're enabled on the controler. */ + if (is_pyxis) { + temp = *(vip)CIA_IOC_CIA_CNFG; + temp |= CIA_CNFG_IOA_BWEN; + *(vip)CIA_IOC_CIA_CNFG = temp; + } + + /* Syncronize with all previous changes. */ + mb(); + *(vip)CIA_IOC_CIA_REV; /* * Create our single hose. */ pci_isa_hose = hose = alloc_pci_controler(); - hae_mem = alloc_resource(); - hose->io_space = &ioport_resource; - hose->mem_space = hae_mem; + hose->mem_space = &iomem_resource; hose->config_space = CIA_CONF; hose->index = 0; - hae_mem->start = 0; - hae_mem->end = CIA_MEM_R1_MASK; - hae_mem->name = pci_hae0_name; - hae_mem->flags = IORESOURCE_MEM; + if (! is_pyxis) { + struct resource *hae_mem = alloc_resource(); + hose->mem_space = hae_mem; + + hae_mem->start = 0; + hae_mem->end = CIA_MEM_R1_MASK; + hae_mem->name = pci_hae0_name; + hae_mem->flags = IORESOURCE_MEM; - if (request_resource(&iomem_resource, hae_mem) < 0) - printk(KERN_ERR "Failed to request HAE_MEM\n"); + if (request_resource(&iomem_resource, hae_mem) < 0) + printk(KERN_ERR "Failed to request HAE_MEM\n"); + } /* * Set up the PCI to main memory translation windows. * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is scatter-gather 128MB at 1GB - * Window 2 is direct access 2GB at 2GB - * ??? We ought to scale window 1 with memory. + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * + * We must actually use 2 windows to direct-map the 2GB space, + * because of an idiot-syncrasy of the CYPRESS chip used on + * many PYXIS systems. It may respond to a PCI bus address in + * the last 1MB of the 4GB address range. + * + * ??? NetBSD hints that page tables must be aligned to 32K, + * possibly due to a hardware bug. This is over-aligned + * from the 8K alignment one would expect for an 8MB window. + * No description of what revisions affected. */ - /* ??? NetBSD hints that page tables must be aligned to 32K, - possibly due to a hardware bug. This is over-aligned - from the 8K alignment one would expect for an 8MB window. - No description of what CIA revisions affected. */ - hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0x8000); - hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0); - __direct_map_base = 0x80000000; + hose->sg_pci = NULL; + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768); + __direct_map_base = 0x40000000; __direct_map_size = 0x80000000; - *(vuip)CIA_IOC_PCI_W0_BASE = hose->sg_isa->dma_base | 3; - *(vuip)CIA_IOC_PCI_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000; - *(vuip)CIA_IOC_PCI_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2; - - *(vuip)CIA_IOC_PCI_W1_BASE = hose->sg_pci->dma_base | 3; - *(vuip)CIA_IOC_PCI_W1_MASK = (hose->sg_pci->size - 1) & 0xfff00000; - *(vuip)CIA_IOC_PCI_T1_BASE = virt_to_phys(hose->sg_pci->ptes) >> 2; + *(vip)CIA_IOC_PCI_W0_BASE = hose->sg_isa->dma_base | 3; + *(vip)CIA_IOC_PCI_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000; + *(vip)CIA_IOC_PCI_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2; - *(vuip)CIA_IOC_PCI_W2_BASE = __direct_map_base | 1; - *(vuip)CIA_IOC_PCI_W2_MASK = (__direct_map_size - 1) & 0xfff00000; - *(vuip)CIA_IOC_PCI_T2_BASE = 0; + *(vip)CIA_IOC_PCI_W1_BASE = 0x40000000 | 1; + *(vip)CIA_IOC_PCI_W1_MASK = (0x40000000 - 1) & 0xfff00000; + *(vip)CIA_IOC_PCI_T1_BASE = 0; - *(vuip)CIA_IOC_PCI_W3_BASE = 0; + *(vip)CIA_IOC_PCI_W2_BASE = 0x80000000 | 1; + *(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000; + *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000; - cia_pci_tbi(hose, 0, -1); + *(vip)CIA_IOC_PCI_W3_BASE = 0; +} - /* - * Set up error reporting. - */ - temp = *(vuip)CIA_IOC_CIA_ERR; - temp |= 0x180; /* master, target abort */ - *(vuip)CIA_IOC_CIA_ERR = temp; +void __init +cia_init_arch(void) +{ + do_init_arch(0); +} - temp = *(vuip)CIA_IOC_CIA_CTRL; - temp |= 0x400; /* turn on FILL_ERR to get mchecks */ - *(vuip)CIA_IOC_CIA_CTRL = temp; +void __init +pyxis_init_arch(void) +{ + do_init_arch(1); +} - /* - * Next, clear the CIA_CFG register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... - */ - *(vuip)CIA_IOC_CFG = 0; - - /* - * Zero the HAEs. - */ - *(vuip)CIA_IOC_HAE_MEM = 0; - *(vuip)CIA_IOC_HAE_IO = 0; - mb(); +void __init +cia_init_pci(void) +{ + /* Must delay this from init_arch, as we need machine checks. */ + verify_tb_operation(); + common_init_pci(); } static inline void cia_pci_clr_err(void) { - unsigned int jd; + int jd; - jd = *(vuip)CIA_IOC_CIA_ERR; - *(vuip)CIA_IOC_CIA_ERR = jd; + jd = *(vip)CIA_IOC_CIA_ERR; + *(vip)CIA_IOC_CIA_ERR = jd; mb(); - *(vuip)CIA_IOC_CIA_ERR; /* re-read to force write. */ + *(vip)CIA_IOC_CIA_ERR; /* re-read to force write. */ } void diff --git a/arch/alpha/kernel/core_pyxis.c b/arch/alpha/kernel/core_pyxis.c deleted file mode 100644 index f6106c475..000000000 --- a/arch/alpha/kernel/core_pyxis.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * linux/arch/alpha/kernel/core_pyxis.c - * - * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). - * - * Code common to all PYXIS core logic chips. - */ - -#include <linux/types.h> -#include <linux/kernel.h> - -#define __EXTERN_INLINE inline -#include <asm/io.h> -#include <asm/core_pyxis.h> -#undef __EXTERN_INLINE - -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/ptrace.h> -#include <asm/system.h> - -#include "proto.h" -#include "irq_impl.h" -#include "pci_impl.h" - - -/* NOTE: Herein are back-to-back mb instructions. They are magic. - One plausible explanation is that the I/O controller does not properly - handle the system transaction. Another involves timing. Ho hum. */ - -/* - * BIOS32-style PCI interface: - */ - -#define DEBUG_CONFIG 0 -#if DEBUG_CONFIG -# define DBG_CNF(args) printk args -#else -# define DBG_CNF(args) -#endif - - -/* - * Given a bus, device, and function number, compute resulting - * configuration space address and setup the PYXIS_HAXR2 register - * accordingly. It is therefore not safe to have concurrent - * invocations to configuration space access routines, but there - * really shouldn't be any need for this. - * - * Type 0: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:11 Device select bit. - * 10:8 Function number - * 7:2 Register number - * - * Type 1: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:24 reserved - * 23:16 bus number (8 bits = 128 possible buses) - * 15:11 Device number (5 bits) - * 10:8 function number - * 7:2 register number - * - * Notes: - * The function number selects which function of a multi-function device - * (e.g., SCSI and Ethernet). - * - * The register selects a DWORD (32 bit) register offset. Hence it - * doesn't get shifted by 2 bits as we want to "drop" the bottom two - * bits. - */ - -static int -mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, - unsigned char *type1) -{ - u8 bus = dev->bus->number; - u8 device_fn = dev->devfn; - - *type1 = (bus == 0) ? 0 : 1; - *pci_addr = (bus << 16) | (device_fn << 8) | (where); - - DBG_CNF(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," - " returning address 0x%p\n" - bus, device_fn, where, *pci_addr)); - - return 0; -} - -static unsigned int -conf_read(unsigned long addr, unsigned char type1) -{ - unsigned long flags; - unsigned int stat0, value, temp; - unsigned int pyxis_cfg = 0; - - __save_and_cli(flags); /* avoid getting hit by machine check */ - - /* Reset status register to avoid losing errors. */ - stat0 = *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = stat0; mb(); - temp = *(vuip)PYXIS_ERR; /* re-read to force write */ - - /* If Type1 access, must set PYXIS CFG. */ - if (type1) { - pyxis_cfg = *(vuip)PYXIS_CFG; - *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - mb(); - draina(); - mcheck_expected(0) = 1; - mcheck_taken(0) = 0; - mb(); - - /* Access configuration space. */ - value = *(vuip)addr; - mb(); - mb(); /* magic */ - - if (mcheck_taken(0)) { - mcheck_taken(0) = 0; - value = 0xffffffffU; - mb(); - } - mcheck_expected(0) = 0; - mb(); - - /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ - if (type1) { - *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - __restore_flags(flags); - - DBG_CNF(("conf_read(addr=0x%lx, type1=%d) = %#x\n", - addr, type1, value)); - - return value; -} - -static void -conf_write(unsigned long addr, unsigned int value, unsigned char type1) -{ - unsigned long flags; - unsigned int stat0, temp; - unsigned int pyxis_cfg = 0; - - __save_and_cli(flags); /* avoid getting hit by machine check */ - - /* Reset status register to avoid losing errors. */ - stat0 = *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = stat0; mb(); - temp = *(vuip)PYXIS_ERR; /* re-read to force write */ - - /* If Type1 access, must set PYXIS CFG. */ - if (type1) { - pyxis_cfg = *(vuip)PYXIS_CFG; - *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - mb(); - draina(); - mcheck_expected(0) = 1; - mcheck_taken(0) = 0; - mb(); - - /* Access configuration space. */ - *(vuip)addr = value; - mb(); - temp = *(vuip)addr; /* read back to force the write */ - mcheck_expected(0) = 0; - mb(); - - /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ - if (type1) { - *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - __restore_flags(flags); - - DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n", - addr, value, type1)); -} - -static int -pyxis_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x00 + PYXIS_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -pyxis_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x08 + PYXIS_CONF; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int -pyxis_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + 0x18 + PYXIS_CONF; - *value = conf_read(addr, type1); - return PCIBIOS_SUCCESSFUL; -} - -static int -pyxis_write_config(struct pci_dev *dev, int where, u32 value, long mask) -{ - unsigned long addr, pci_addr; - unsigned char type1; - - if (mk_conf_addr(dev, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = (pci_addr << 5) + mask + PYXIS_CONF; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; -} - -static int -pyxis_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return pyxis_write_config(dev, where, value, 0x00); -} - -static int -pyxis_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return pyxis_write_config(dev, where, value, 0x08); -} - -static int -pyxis_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - return pyxis_write_config(dev, where, value, 0x18); -} - -struct pci_ops pyxis_pci_ops = -{ - read_byte: pyxis_read_config_byte, - read_word: pyxis_read_config_word, - read_dword: pyxis_read_config_dword, - write_byte: pyxis_write_config_byte, - write_word: pyxis_write_config_word, - write_dword: pyxis_write_config_dword -}; - -/* Note mask bit is true for ENABLED irqs. */ -static unsigned long cached_irq_mask; - -static inline void -pyxis_update_irq_hw(unsigned long mask) -{ - *(vulp)PYXIS_INT_MASK = mask; - mb(); - *(vulp)PYXIS_INT_MASK; -} - -static inline void -pyxis_enable_irq(unsigned int irq) -{ - pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); -} - -static void -pyxis_disable_irq(unsigned int irq) -{ - pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); -} - -static unsigned int -pyxis_startup_irq(unsigned int irq) -{ - pyxis_enable_irq(irq); - return 0; -} - -static void -pyxis_end_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - pyxis_enable_irq(irq); -} - -static void -pyxis_mask_and_ack_irq(unsigned int irq) -{ - unsigned long bit = 1UL << (irq - 16); - unsigned long mask = cached_irq_mask &= ~bit; - - /* Disable the interrupt. */ - *(vulp)PYXIS_INT_MASK = mask; - wmb(); - /* Ack PYXIS PCI interrupt. */ - *(vulp)PYXIS_INT_REQ = bit; - mb(); - /* Re-read to force both writes. */ - *(vulp)PYXIS_INT_MASK; -} - -static struct hw_interrupt_type pyxis_irq_type = { - typename: "PYXIS", - startup: pyxis_startup_irq, - shutdown: pyxis_disable_irq, - enable: pyxis_enable_irq, - disable: pyxis_disable_irq, - ack: pyxis_mask_and_ack_irq, - end: pyxis_end_irq, -}; - -void -pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - - /* Read the interrupt summary register of PYXIS */ - pld = *(vulp)PYXIS_INT_REQ; - pld &= cached_irq_mask; - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 7) - isa_device_interrupt(vector, regs); - else - handle_irq(16+i, regs); - } -} - -void __init -init_pyxis_irqs(unsigned long ignore_mask) -{ - long i; - - *(vulp)PYXIS_INT_MASK = 0; /* disable all */ - *(vulp)PYXIS_INT_REQ = -1; /* flush all */ - mb(); - - /* Send -INTA pulses to clear any pending interrupts ...*/ - *(vuip) PYXIS_IACK_SC; - - for (i = 16; i < 48; ++i) { - if ((ignore_mask >> i) & 1) - continue; - irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; - irq_desc[i].handler = &pyxis_irq_type; - } - - setup_irq(16+7, &isa_cascade_irqaction); -} - -void -pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) -{ - wmb(); - *(vip)PYXIS_TBIA = 3; /* Flush all locked and unlocked. */ - mb(); -} - -/* - * Pass 1 and 2 have a broken scatter-gather tlb -- it cannot be invalidated. - * To work around this problem, we allocate mappings, and put the chip into - * DMA loopback mode to read a garbage page. This works by causing TLB - * misses, causing old entries to be purged to make room for the new entries - * coming in for the garbage page. - * - * Thanks to NetBSD sources for pointing out this bug. What a pain. - */ - -static unsigned long broken_tbi_addr; - -#define BROKEN_TBI_READS 12 - -static void -pyxis_broken_pci_tbi(struct pci_controler *hose, - dma_addr_t start, dma_addr_t end) -{ - unsigned long flags; - unsigned long bus_addr; - unsigned int ctrl; - long i; - - __save_and_cli(flags); - - /* Put the chip into PCI loopback mode. */ - mb(); - ctrl = *(vuip)PYXIS_CTRL; - *(vuip)PYXIS_CTRL = ctrl | 4; - mb(); - *(vuip)PYXIS_CTRL; - mb(); - - /* Read from PCI dense memory space at TBI_ADDR, skipping 64k - on each read. This forces SG TLB misses. It appears that - the TLB entries are "not quite LRU", meaning that we need - to read more times than there are actual tags. */ - - bus_addr = broken_tbi_addr; - for (i = 0; i < BROKEN_TBI_READS; ++i, bus_addr += 64*1024) - pyxis_readl(bus_addr); - - /* Restore normal PCI operation. */ - mb(); - *(vuip)PYXIS_CTRL = ctrl; - mb(); - *(vuip)PYXIS_CTRL; - mb(); - - __restore_flags(flags); -} - -static void __init -pyxis_enable_broken_tbi(struct pci_iommu_arena *arena) -{ - void *page; - unsigned long *ppte, ofs, pte; - long i, npages; - - page = alloc_bootmem_pages(PAGE_SIZE); - pte = (virt_to_phys(page) >> (PAGE_SHIFT - 1)) | 1; - npages = (BROKEN_TBI_READS + 1) * 64*1024 / PAGE_SIZE; - - ofs = iommu_arena_alloc(arena, npages); - ppte = arena->ptes + ofs; - for (i = 0; i < npages; ++i) - ppte[i] = pte; - - broken_tbi_addr = pyxis_ioremap(arena->dma_base + ofs*PAGE_SIZE); - alpha_mv.mv_pci_tbi = pyxis_broken_pci_tbi; - - printk("PYXIS: Enabling broken tbia workaround.\n"); -} - -void __init -pyxis_init_arch(void) -{ - struct pci_controler *hose; - unsigned int temp; - - /* Set up error reporting. Make sure CPU_PE is OFF in the mask. */ - temp = *(vuip)PYXIS_ERR_MASK; - *(vuip)PYXIS_ERR_MASK = temp & ~4; - - /* Enable master/target abort. */ - temp = *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = temp | 0x180; - - /* Clear the PYXIS_CFG register, which gets used for PCI Config - Space accesses. That is the way we want to use it, and we do - not want to depend on what ARC or SRM might have left behind. */ - *(vuip)PYXIS_CFG = 0; - - /* Zero the HAEs. */ - *(vuip)PYXIS_HAE_MEM = 0; - *(vuip)PYXIS_HAE_IO = 0; - - /* Finally, check that the PYXIS_CTRL1 has IOA_BEN set for - enabling byte/word PCI bus space(s) access. */ - temp = *(vuip)PYXIS_CTRL1; - *(vuip)PYXIS_CTRL1 = temp | 1; - - /* Syncronize with all previous changes. */ - mb(); - *(vuip)PYXIS_REV; - - /* - * Create our single hose. - */ - - hose = alloc_pci_controler(); - hose->io_space = &ioport_resource; - hose->mem_space = &iomem_resource; - hose->config_space = PYXIS_CONF; - hose->index = 0; - - /* - * Set up the PCI to main memory translation windows. - * - * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is scatter-gather 128MB at 3GB - * Window 2 is direct access 1GB at 1GB - * Window 3 is direct access 1GB at 2GB - * ??? We ought to scale window 1 with memory. - * - * We must actually use 2 windows to direct-map the 2GB space, - * because of an idiot-syncrasy of the CYPRESS chip. It may - * respond to a PCI bus address in the last 1MB of the 4GB - * address range. - */ - -#if 1 - /* ??? There's some bit of syncronization wrt writing new tlb - entries that's missing. Sometimes it works, sometimes invalid - tlb machine checks, sometimes hard lockup. And this just within - the boot sequence. - - I've tried extra memory barriers, extra alignment, pyxis - register reads, tlb flushes, and loopback tlb accesses. - - I guess the pyxis revision in the sx164 is just too buggy... */ - - hose->sg_isa = hose->sg_pci = NULL; - __direct_map_base = 0x40000000; - __direct_map_size = 0x80000000; - - *(vuip)PYXIS_W0_BASE = 0x40000000 | 1; - *(vuip)PYXIS_W0_MASK = (0x40000000 - 1) & 0xfff00000; - *(vuip)PYXIS_T0_BASE = 0; - - *(vuip)PYXIS_W1_BASE = 0x80000000 | 1; - *(vuip)PYXIS_W1_MASK = (0x40000000 - 1) & 0xfff00000; - *(vuip)PYXIS_T1_BASE = 0; - - *(vuip)PYXIS_W2_BASE = 0; - *(vuip)PYXIS_W3_BASE = 0; - - alpha_mv.mv_pci_tbi = NULL; - mb(); -#else - /* ??? NetBSD hints that page tables must be aligned to 32K, - possibly due to a hardware bug. This is over-aligned - from the 8K alignment one would expect for an 8MB window. - No description of what CIA revisions affected. */ - hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0x08000); - hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0x20000); - __direct_map_base = 0x40000000; - __direct_map_size = 0x80000000; - - *(vuip)PYXIS_W0_BASE = hose->sg_isa->dma_base | 3; - *(vuip)PYXIS_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000; - *(vuip)PYXIS_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2; - - *(vuip)PYXIS_W1_BASE = hose->sg_pci->dma_base | 3; - *(vuip)PYXIS_W1_MASK = (hose->sg_pci->size - 1) & 0xfff00000; - *(vuip)PYXIS_T1_BASE = virt_to_phys(hose->sg_pci->ptes) >> 2; - - *(vuip)PYXIS_W2_BASE = 0x40000000 | 1; - *(vuip)PYXIS_W2_MASK = (0x40000000 - 1) & 0xfff00000; - *(vuip)PYXIS_T2_BASE = 0; - - *(vuip)PYXIS_W3_BASE = 0x80000000 | 1; - *(vuip)PYXIS_W3_MASK = (0x40000000 - 1) & 0xfff00000; - *(vuip)PYXIS_T3_BASE = 0; - - /* Pass 1 and 2 (ie revision <= 1) have a broken TBIA. See the - complete description next to pyxis_broken_pci_tbi for details. */ - if ((*(vuip)PYXIS_REV & 0xff) <= 1) - pyxis_enable_broken_tbi(hose->sg_pci); - - alpha_mv.mv_pci_tbi(hose, 0, -1); -#endif -} - -static inline void -pyxis_pci_clr_err(void) -{ - unsigned int tmp; - - tmp = *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = tmp; - mb(); - *(vuip)PYXIS_ERR; /* re-read to force write */ -} - -void -pyxis_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) -{ - int expected; - - /* Clear the error before reporting anything. */ - mb(); - mb(); /* magic */ - draina(); - pyxis_pci_clr_err(); - wrmces(0x7); - mb(); - - expected = mcheck_expected(0); - if (!expected && vector == 0x660) { - struct el_common *com; - struct el_common_EV5_uncorrectable_mcheck *ev5; - struct el_PYXIS_sysdata_mcheck *pyxis; - - com = (void *)la_ptr; - ev5 = (void *)(la_ptr + com->proc_offset); - pyxis = (void *)(la_ptr + com->sys_offset); - - if (com->code == 0x202) { - printk(KERN_CRIT "PYXIS PCI machine check: err0=%08x " - "err1=%08x err2=%08x\n", - (int) pyxis->pci_err0, (int) pyxis->pci_err1, - (int) pyxis->pci_err2); - expected = 1; - } - } - process_mcheck_info(vector, la_ptr, regs, "PYXIS", expected); -} diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index 1fa5a8088..1ddcd36d1 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -363,7 +363,7 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index) pchip->wsba[3].csr = 0x80000000 | 1; pchip->wsm[3].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[3].csr = 0; + pchip->tba[3].csr = 0x40000000; tsunami_pci_tbi(hose, 0, -1); } diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 5f1a6f59a..0b9e1786d 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -8,7 +8,7 @@ #define SIGCHLD 20 -#define NR_SYSCALLS 374 +#define NR_SYSCALLS 376 /* * These offsets must match with alpha_mv in <asm/machvec.h>. @@ -991,7 +991,7 @@ sys_call_table: .quad osf_shmat .quad sys_shmctl /* 210 */ .quad sys_shmdt - .quad osf_shmget + .quad sys_shmget .quad alpha_ni_syscall .quad alpha_ni_syscall .quad alpha_ni_syscall /* 215 */ @@ -1154,4 +1154,5 @@ sys_call_table: .quad sys_setresgid .quad sys_getresgid .quad sys_ni_syscall /* sys_dipc */ - .quad sys_shmget + .quad sys_pivot_root + .quad sys_mincore /* 375 */ diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index bc8ca101a..1f454cf48 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -219,15 +219,33 @@ setup_irq(unsigned int irq, struct irqaction * new) } spin_unlock_irqrestore(&desc->lock,flags); - register_irq_proc(irq); return 0; } static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; +static struct proc_dir_entry * irq_dir[NR_IRQS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +#ifdef CONFIG_SMP +static struct proc_dir_entry * smp_affinity_entry[NR_IRQS]; +static char irq_user_affinity[NR_IRQS]; +static unsigned long irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; + +static void +select_smp_affinity(int irq) +{ + static int last_cpu; + int cpu = last_cpu + 1; + + if (! irq_desc[irq].handler->set_affinity || irq_user_affinity[irq]) + return; + + while (((cpu_present_mask >> cpu) & 1) == 0) + cpu = (cpu < NR_CPUS ? cpu + 1 : 0); + last_cpu = cpu; + + irq_affinity[irq] = 1UL << cpu; + irq_desc[irq].handler->set_affinity(irq, 1UL << cpu); +} #define HEX_DIGITS 16 @@ -290,18 +308,22 @@ irq_affinity_write_proc(struct file *file, const char *buffer, err = parse_hex_value(buffer, count, &new_value); -#if CONFIG_SMP - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - if (!(new_value & cpu_present_mask)) + /* The special value 0 means release control of the + affinity to kernel. */ + if (new_value == 0) { + irq_user_affinity[irq] = 0; + select_smp_affinity(irq); + } + /* Do not allow disabling IRQs completely - it's a too easy + way to make the system unusable accidentally :-) At least + one online CPU still has to be targeted. */ + else if (!(new_value & cpu_present_mask)) return -EINVAL; -#endif - - irq_affinity[irq] = new_value; - irq_desc[irq].handler->set_affinity(irq, new_value); + else { + irq_affinity[irq] = new_value; + irq_user_affinity[irq] = 1; + irq_desc[irq].handler->set_affinity(irq, new_value); + } return full_count; } @@ -313,7 +335,7 @@ prof_cpu_mask_read_proc(char *page, char **start, off_t off, unsigned long *mask = (unsigned long *) data; if (count < HEX_DIGITS+1) return -EINVAL; - return sprintf (page, "%08lx\n", *mask); + return sprintf (page, "%016lx\n", *mask); } static int @@ -330,6 +352,7 @@ prof_cpu_mask_write_proc(struct file *file, const char *buffer, *mask = new_value; return full_count; } +#endif /* CONFIG_SMP */ #define MAX_NAMELEN 10 @@ -348,6 +371,7 @@ register_irq_proc (unsigned int irq) /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); +#ifdef CONFIG_SMP /* create /proc/irq/1234/smp_affinity */ entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); @@ -357,6 +381,7 @@ register_irq_proc (unsigned int irq) entry->write_proc = irq_affinity_write_proc; smp_affinity_entry[irq] = entry; +#endif } unsigned long prof_cpu_mask = ~0UL; @@ -370,6 +395,7 @@ init_irq_proc (void) /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", 0); +#ifdef CONFIG_SMP /* create /proc/irq/prof_cpu_mask */ entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); @@ -377,6 +403,7 @@ init_irq_proc (void) entry->data = (void *)&prof_cpu_mask; entry->read_proc = prof_cpu_mask_read_proc; entry->write_proc = prof_cpu_mask_write_proc; +#endif /* * Create entries for all existing IRQs. @@ -426,6 +453,10 @@ request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), action->next = NULL; action->dev_id = dev_id; +#ifdef CONFIG_SMP + select_smp_affinity(irq); +#endif + retval = setup_irq(irq, action); if (retval) kfree(action); @@ -522,10 +553,10 @@ get_irq_list(char *buf) *p++ = '\n'; } #if CONFIG_SMP - p += sprintf(p, "LOC: "); + p += sprintf(p, "IPI: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10lu ", - cpu_data[cpu_logical_map(j)].smp_local_irq_count); + cpu_data[cpu_logical_map(j)].ipi_count); p += sprintf(p, "\n"); #endif p += sprintf(p, "ERR: %10lu\n", irq_err_count); diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 62ba2362f..774fcf8a6 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -6,6 +6,7 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/irq.h> +#include <linux/kernel_stat.h> #include <asm/machvec.h> #include <asm/dma.h> @@ -61,14 +62,22 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, break; case 1: #ifdef CONFIG_SMP - cpu_data[smp_processor_id()].smp_local_irq_count++; + { + long cpu; smp_percpu_timer_interrupt(®s); - if (smp_processor_id() == boot_cpuid) -#endif + cpu = smp_processor_id(); + if (cpu != boot_cpuid) { + irq_attempt(cpu, RTC_IRQ)++; + kstat.irqs[cpu][RTC_IRQ]++; + } else { handle_irq(RTC_IRQ, ®s); + } + } +#else + handle_irq(RTC_IRQ, ®s); +#endif return; case 2: - irq_err_count++; alpha_mv.machine_check(vector, la_ptr, ®s); return; case 3: diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c new file mode 100644 index 000000000..65414a7f5 --- /dev/null +++ b/arch/alpha/kernel/irq_pyxis.c @@ -0,0 +1,127 @@ +/* + * linux/arch/alpha/kernel/irq_pyxis.c + * + * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). + * + * IRQ Code common to all PYXIS core logic chips. + */ + +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/core_cia.h> + +#include "proto.h" +#include "irq_impl.h" + + +/* Note mask bit is true for ENABLED irqs. */ +static unsigned long cached_irq_mask; + +static inline void +pyxis_update_irq_hw(unsigned long mask) +{ + *(vulp)PYXIS_INT_MASK = mask; + mb(); + *(vulp)PYXIS_INT_MASK; +} + +static inline void +pyxis_enable_irq(unsigned int irq) +{ + pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); +} + +static void +pyxis_disable_irq(unsigned int irq) +{ + pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); +} + +static unsigned int +pyxis_startup_irq(unsigned int irq) +{ + pyxis_enable_irq(irq); + return 0; +} + +static void +pyxis_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + pyxis_enable_irq(irq); +} + +static void +pyxis_mask_and_ack_irq(unsigned int irq) +{ + unsigned long bit = 1UL << (irq - 16); + unsigned long mask = cached_irq_mask &= ~bit; + + /* Disable the interrupt. */ + *(vulp)PYXIS_INT_MASK = mask; + wmb(); + /* Ack PYXIS PCI interrupt. */ + *(vulp)PYXIS_INT_REQ = bit; + mb(); + /* Re-read to force both writes. */ + *(vulp)PYXIS_INT_MASK; +} + +static struct hw_interrupt_type pyxis_irq_type = { + typename: "PYXIS", + startup: pyxis_startup_irq, + shutdown: pyxis_disable_irq, + enable: pyxis_enable_irq, + disable: pyxis_disable_irq, + ack: pyxis_mask_and_ack_irq, + end: pyxis_end_irq, +}; + +void +pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + pld &= cached_irq_mask; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 7) + isa_device_interrupt(vector, regs); + else + handle_irq(16+i, regs); + } +} + +void __init +init_pyxis_irqs(unsigned long ignore_mask) +{ + long i; + + *(vulp)PYXIS_INT_MASK = 0; /* disable all */ + *(vulp)PYXIS_INT_REQ = -1; /* flush all */ + mb(); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + *(vuip) CIA_IACK_SC; + + for (i = 16; i < 48; ++i) { + if ((ignore_mask >> i) & 1) + continue; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].handler = &pyxis_irq_type; + } + + setup_irq(16+7, &isa_cascade_irqaction); +} diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c index 8b14a59fe..51806c996 100644 --- a/arch/alpha/kernel/irq_srm.c +++ b/arch/alpha/kernel/irq_srm.c @@ -6,9 +6,6 @@ #include <linux/sched.h> #include <linux/irq.h> -#include <asm/machvec.h> -#include <asm/dma.h> - #include "proto.h" #include "irq_impl.h" diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index cc55781cb..bc9c0d3de 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h @@ -77,27 +77,26 @@ mv_writew: CAT(low,_writew), \ mv_writel: CAT(low,_writel), \ mv_writeq: CAT(low,_writeq), \ - mv_ioremap: CAT(low,_ioremap), \ - mv_is_ioaddr: CAT(low,_is_ioaddr) + mv_ioremap: CAT(low,_ioremap) \ #define IO(UP,low) \ IO_LITE(UP,low), \ pci_ops: &CAT(low,_pci_ops) -/* Any assembler that can generate a GENERIC kernel can generate BWX - instructions. So always use them for PYXIS I/O. */ - #define DO_APECS_IO IO(APECS,apecs) #define DO_CIA_IO IO(CIA,cia) #define DO_IRONGATE_IO IO(IRONGATE,irongate) #define DO_LCA_IO IO(LCA,lca) #define DO_MCPCIA_IO IO(MCPCIA,mcpcia) #define DO_POLARIS_IO IO(POLARIS,polaris) -#define DO_PYXIS_IO IO(PYXIS,pyxis) #define DO_T2_IO IO(T2,t2) #define DO_TSUNAMI_IO IO(TSUNAMI,tsunami) +#define DO_PYXIS_IO IO_LITE(CIA,cia_bwx), \ + pci_ops: &CAT(cia,_pci_ops) + #define BUS(which) \ + mv_is_ioaddr: CAT(which,_is_ioaddr), \ mv_pci_tbi: CAT(which,_pci_tbi) #define DO_APECS_BUS BUS(apecs) @@ -105,7 +104,6 @@ #define DO_IRONGATE_BUS BUS(irongate) #define DO_LCA_BUS BUS(lca) #define DO_MCPCIA_BUS BUS(mcpcia) -#define DO_PYXIS_BUS BUS(pyxis) #define DO_POLARIS_BUS BUS(polaris) #define DO_T2_BUS BUS(t2) #define DO_TSUNAMI_BUS BUS(tsunami) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 091edaf37..0395f87f1 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -189,15 +189,6 @@ asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4, return prio; } - -/* - * Heh. As documented by DEC.. - */ -asmlinkage unsigned long sys_madvise(void) -{ - return 0; -} - /* * No need to acquire the kernel lock, we're local.. */ @@ -1374,8 +1365,3 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p) return ret; } - -asmlinkage long osf_shmget (key_t key, int size, int flag) -{ - return sys_shmget (key, size, flag); -} diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h index 3aee6ec34..f434b329d 100644 --- a/arch/alpha/kernel/pci_impl.h +++ b/arch/alpha/kernel/pci_impl.h @@ -138,6 +138,7 @@ struct pci_iommu_arena dma_addr_t dma_base; unsigned int size; unsigned int next_entry; + unsigned int align_entry; }; diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 9e7e13e9b..5a36aa578 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -67,6 +67,10 @@ iommu_arena_new(struct pci_controler *hose, dma_addr_t base, arena->size = window_size; arena->next_entry = 0; + /* Align allocations to a multiple of a page size. Not needed + unless there are chip bugs. */ + arena->align_entry = 1; + return arena; } @@ -74,28 +78,36 @@ long iommu_arena_alloc(struct pci_iommu_arena *arena, long n) { unsigned long flags; - unsigned long *beg, *p, *end; - long i; + unsigned long *ptes; + long i, p, nent, mask; spin_lock_irqsave(&arena->lock, flags); /* Search forward for the first sequence of N empty ptes. */ - beg = arena->ptes; - end = beg + (arena->size >> PAGE_SHIFT); - p = beg + arena->next_entry; + ptes = arena->ptes; + nent = arena->size >> PAGE_SHIFT; + mask = arena->align_entry - 1; + p = (arena->next_entry + mask) & ~mask; i = 0; - while (i < n && p < end) - i = (*p++ == 0 ? i + 1 : 0); + while (i < n && p+i < nent) { + if (ptes[p+i]) + p = (p + i + 1 + mask) & ~mask, i = 0; + else + i = i + 1; + } if (i < n) { /* Reached the end. Flush the TLB and restart the search from the beginning. */ alpha_mv.mv_pci_tbi(arena->hose, 0, -1); - p = beg; - i = 0; - while (i < n && p < end) - i = (*p++ == 0 ? i + 1 : 0); + p = 0, i = 0; + while (i < n && p+i < nent) { + if (ptes[p+i]) + p = (p + i + 1 + mask) & ~mask, i = 0; + else + i = i + 1; + } if (i < n) { spin_unlock_irqrestore(&arena->lock, flags); @@ -107,13 +119,13 @@ iommu_arena_alloc(struct pci_iommu_arena *arena, long n) bit zero is the valid bit, so write ~1 into everything. The chip specific bits will fill this in with something kosher when we return. */ - for (p = p - n, i = 0; i < n; ++i) - p[i] = ~1UL; + for (i = 0; i < n; ++i) + ptes[p+i] = ~1UL; - arena->next_entry = p - beg + n; + arena->next_entry = p + n; spin_unlock_irqrestore(&arena->lock, flags); - return p - beg; + return p; } static void @@ -238,6 +250,12 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, npages = calc_npages((dma_addr & ~PAGE_MASK) + size); iommu_arena_free(arena, dma_ofs, npages); + /* If we're freeing ptes above the `next_entry' pointer, they + may have snuck back into the TLB since the last wrap flush. + We need to flush the TLB before reallocating these. */ + if (dma_ofs >= arena->next_entry) + alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); + DBGA("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", dma_addr, size, npages, __builtin_return_address(0)); } @@ -509,6 +527,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, struct pci_iommu_arena *arena; struct scatterlist *end; dma_addr_t max_dma; + dma_addr_t fbeg, fend; if (direction == PCI_DMA_NONE) BUG(); @@ -522,9 +541,11 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, if (!arena || arena->dma_base + arena->size > max_dma) arena = hose->sg_isa; + fbeg = -1, fend = 0; for (end = sg + nents; sg < end; ++sg) { unsigned long addr, size; long npages, ofs; + dma_addr_t tend; addr = sg->dma_address; size = sg->dma_length; @@ -547,8 +568,18 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, npages = calc_npages((addr & ~PAGE_MASK) + size); ofs = (addr - arena->dma_base) >> PAGE_SHIFT; iommu_arena_free(arena, ofs, npages); + + tend = addr + size - 1; + if (fbeg > addr) fbeg = addr; + if (fend < tend) fend = tend; } + /* If we're freeing ptes above the `next_entry' pointer, they + may have snuck back into the TLB since the last wrap flush. + We need to flush the TLB before reallocating these. */ + if ((fend - arena->dma_base) >> PAGE_SHIFT >= arena->next_entry) + alpha_mv.mv_pci_tbi(hose, fbeg, fend); + DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); } diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 8e7bbcfaf..f13edeebf 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -20,7 +20,9 @@ extern void apecs_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* core_cia.c */ extern struct pci_ops cia_pci_ops; +extern void cia_init_pci(void); extern void cia_init_arch(void); +extern void pyxis_init_arch(void); extern void cia_machine_check(u64, u64, struct pt_regs *); extern void cia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); @@ -52,12 +54,6 @@ extern void polaris_init_arch(void); extern void polaris_machine_check(u64, u64, struct pt_regs *); #define polaris_pci_tbi ((void *)0) -/* core_pyxis.c */ -extern struct pci_ops pyxis_pci_ops; -extern void pyxis_init_arch(void); -extern void pyxis_machine_check(u64, u64, struct pt_regs *); -extern void pyxis_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); - /* core_t2.c */ extern struct pci_ops t2_pci_ops; extern void t2_init_arch(void); diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 615914535..49ddca2e4 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -846,6 +846,22 @@ platform_string(void) } } +static int +get_nr_processors(struct percpu_struct *cpubase, unsigned long num) +{ + struct percpu_struct *cpu; + int i, count = 0; + + for (i = 0; i < num; i++) { + cpu = (struct percpu_struct *) + ((char *)cpubase + i*hwrpb->processor_size); + if ((cpu->flags & 0x1cc) == 0x1cc) + count++; + } + return count; +} + + /* * BUFFER is PAGE_SIZE bytes long. */ @@ -865,7 +881,7 @@ int get_cpuinfo(char *buffer) char *cpu_name; char *systype_name; char *sysvariation_name; - int len; + int len, nr_processors; cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); cpu_index = (unsigned) (cpu->type - 1); @@ -876,6 +892,8 @@ int get_cpuinfo(char *buffer) get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, &systype_name, &sysvariation_name); + nr_processors = get_nr_processors(cpu, hwrpb->nr_processors); + len = sprintf(buffer, "cpu\t\t\t: Alpha\n" "cpu model\t\t: %s\n" @@ -894,7 +912,8 @@ int get_cpuinfo(char *buffer) "BogoMIPS\t\t: %lu.%02lu\n" "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" - "platform string\t\t: %s\n", + "platform string\t\t: %s\n" + "cpus detected\t\t: %d\n", cpu_name, cpu->variation, cpu->revision, (char*)cpu->serial_no, systype_name, sysvariation_name, hwrpb->sys_revision, @@ -909,7 +928,7 @@ int get_cpuinfo(char *buffer) loops_per_sec / 500000, (loops_per_sec / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va, - platform_string()); + platform_string(), nr_processors); #ifdef __SMP__ len += smp_info(buffer+len); diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index ab1fb9ab2..1ddaaf74d 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -1003,15 +1003,11 @@ flush_icache_page(struct vm_area_struct *vma, struct page *page) int smp_info(char *buffer) { - long i; - unsigned long sum = 0; - for (i = 0; i < NR_CPUS; i++) - sum += cpu_data[i].ipi_count; - - return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n", - smp_num_probed, smp_num_cpus, cpu_present_mask, sum); + return sprintf(buffer, + "cpus active\t\t: %d\n" + "cpu active mask\t\t: %016lx\n", + smp_num_cpus, cpu_present_mask); } - #if DEBUG_SPINLOCK void diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index 867d762f8..656a0a8df 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c @@ -249,7 +249,7 @@ struct alpha_machine_vector alcor_mv __initmv = { init_arch: cia_init_arch, init_irq: alcor_init_irq, init_rtc: common_init_rtc, - init_pci: common_init_pci, + init_pci: cia_init_pci, kill_arch: alcor_kill_arch, pci_map_irq: alcor_map_irq, pci_swizzle: common_swizzle, @@ -279,7 +279,7 @@ struct alpha_machine_vector xlt_mv __initmv = { init_arch: cia_init_arch, init_irq: alcor_init_irq, init_rtc: common_init_rtc, - init_pci: common_init_pci, + init_pci: cia_init_pci, kill_arch: alcor_kill_arch, pci_map_irq: alcor_map_irq, pci_swizzle: common_swizzle, diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index 8e016ada0..9b2b39d73 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1998, 1999, 2000 Richard Henderson * * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164, * PC164 and LX164. @@ -28,7 +28,6 @@ #include <asm/core_apecs.h> #include <asm/core_cia.h> #include <asm/core_lca.h> -#include <asm/core_pyxis.h> #include "proto.h" #include "irq_impl.h" @@ -223,6 +222,12 @@ cabriolet_init_pci(void) ns87312_enable_ide(0x398); } +static inline void __init +cia_cab_init_pci(void) +{ + cia_init_pci(); + ns87312_enable_ide(0x398); +} /* * The PC164 and LX164 have 19 PCI interrupts, four from each of the four @@ -286,7 +291,7 @@ alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) static inline void __init alphapc164_init_pci(void) { - common_init_pci(); + cia_init_pci(); SMC93x_Init(); } @@ -339,7 +344,7 @@ struct alpha_machine_vector eb164_mv __initmv = { init_arch: cia_init_arch, init_irq: cabriolet_init_irq, init_rtc: common_init_rtc, - init_pci: cabriolet_init_pci, + init_pci: cia_cab_init_pci, pci_map_irq: cabriolet_map_irq, pci_swizzle: common_swizzle, }; @@ -377,8 +382,8 @@ struct alpha_machine_vector lx164_mv __initmv = { DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, - DO_PYXIS_BUS, - machine_check: pyxis_machine_check, + DO_CIA_BUS, + machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 63abc109f..c10018fff 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -36,32 +36,31 @@ /* Note mask bit is true for ENABLED irqs. */ static unsigned long cached_irq_mask; /* dp264 boards handle at max four CPUs */ -static unsigned long cpu_irq_affinity[4]; +static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL }; spinlock_t dp264_irq_lock = SPIN_LOCK_UNLOCKED; static void -tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) +tsunami_update_irq_hw(unsigned long mask) { register tsunami_cchip *cchip = TSUNAMI_cchip; + unsigned long isa_enable = 1UL << 55; register int bcpu = boot_cpuid; #ifdef CONFIG_SMP register unsigned long cpm = cpu_present_mask; volatile unsigned long *dim0, *dim1, *dim2, *dim3; - unsigned long mask0, mask1, mask2, mask3, maskB, dummy; + unsigned long mask0, mask1, mask2, mask3, dummy; - mask0 = mask1 = mask2 = mask3 = mask; - maskB = mask | isa_enable; - if (bcpu == 0) mask0 = maskB; - else if (bcpu == 1) mask1 = maskB; - else if (bcpu == 2) mask2 = maskB; - else if (bcpu == 3) mask3 = maskB; + mask0 = mask & cpu_irq_affinity[0]; + mask1 = mask & cpu_irq_affinity[1]; + mask2 = mask & cpu_irq_affinity[2]; + mask3 = mask & cpu_irq_affinity[3]; - mask0 &= cpu_irq_affinity[0]; - mask1 &= cpu_irq_affinity[1]; - mask2 &= cpu_irq_affinity[2]; - mask3 &= cpu_irq_affinity[3]; + if (bcpu == 0) mask0 |= isa_enable; + else if (bcpu == 1) mask1 |= isa_enable; + else if (bcpu == 2) mask2 |= isa_enable; + else mask3 |= isa_enable; dim0 = &cchip->dim0.csr; dim1 = &cchip->dim1.csr; @@ -86,7 +85,7 @@ tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) if (bcpu == 0) dimB = &cchip->dim0.csr; else if (bcpu == 1) dimB = &cchip->dim1.csr; else if (bcpu == 2) dimB = &cchip->dim2.csr; - else if (bcpu == 3) dimB = &cchip->dim3.csr; + else dimB = &cchip->dim3.csr; *dimB = mask | isa_enable; mb(); @@ -94,24 +93,12 @@ tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) #endif } -static inline void -dp264_update_irq_hw(unsigned long mask) -{ - tsunami_update_irq_hw(mask, (1UL << 55) | 0xffff); -} - -static inline void -clipper_update_irq_hw(unsigned long mask) -{ - tsunami_update_irq_hw(mask, 1UL << 55); -} - static void dp264_enable_irq(unsigned int irq) { spin_lock(&dp264_irq_lock); cached_irq_mask |= 1UL << irq; - dp264_update_irq_hw(cached_irq_mask); + tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); } @@ -120,7 +107,7 @@ dp264_disable_irq(unsigned int irq) { spin_lock(&dp264_irq_lock); cached_irq_mask &= ~(1UL << irq); - dp264_update_irq_hw(cached_irq_mask); + tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); } @@ -142,8 +129,8 @@ static void clipper_enable_irq(unsigned int irq) { spin_lock(&dp264_irq_lock); - cached_irq_mask |= 1UL << irq; - clipper_update_irq_hw(cached_irq_mask); + cached_irq_mask |= 1UL << (irq - 16); + tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); } @@ -151,8 +138,8 @@ static void clipper_disable_irq(unsigned int irq) { spin_lock(&dp264_irq_lock); - cached_irq_mask &= ~(1UL << irq); - clipper_update_irq_hw(cached_irq_mask); + cached_irq_mask &= ~(1UL << (irq - 16)); + tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); } @@ -191,7 +178,7 @@ dp264_set_affinity(unsigned int irq, unsigned long affinity) { spin_lock(&dp264_irq_lock); cpu_set_irq_affinity(irq, affinity); - dp264_update_irq_hw(cached_irq_mask); + tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); } @@ -199,8 +186,8 @@ static void clipper_set_affinity(unsigned int irq, unsigned long affinity) { spin_lock(&dp264_irq_lock); - cpu_set_irq_affinity(irq, affinity); - clipper_update_irq_hw(cached_irq_mask); + cpu_set_irq_affinity(irq - 16, affinity); + tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); } @@ -304,12 +291,10 @@ clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) } static void __init -init_tsunami_irqs(struct hw_interrupt_type * ops) +init_tsunami_irqs(struct hw_interrupt_type * ops, int imin, int imax) { long i; - - /* Only irqs between 16 and 47 are tsunami irqs. */ - for (i = 16; i < 48; ++i) { + for (i = imin; i <= imax; ++i) { irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = ops; } @@ -318,8 +303,6 @@ init_tsunami_irqs(struct hw_interrupt_type * ops) static void __init dp264_init_irq(void) { - int cpu; - outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); @@ -328,13 +311,10 @@ dp264_init_irq(void) if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; - /* this is single threaded by design so no need of any smp lock */ - for (cpu = 0; cpu < 4; cpu++) - cpu_irq_affinity[cpu] = ~0UL; - dp264_update_irq_hw(0UL); + tsunami_update_irq_hw(0); init_i8259a_irqs(); - init_tsunami_irqs(&dp264_irq_type); + init_tsunami_irqs(&dp264_irq_type, 16, 47); } static void __init @@ -348,10 +328,10 @@ clipper_init_irq(void) if (alpha_using_srm) alpha_mv.device_interrupt = clipper_srm_device_interrupt; - clipper_update_irq_hw(0UL); + tsunami_update_irq_hw(0); init_i8259a_irqs(); - init_tsunami_irqs(&clipper_irq_type); + init_tsunami_irqs(&clipper_irq_type, 24, 63); } diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c index 9e4fbe569..4545ff0e2 100644 --- a/arch/alpha/kernel/sys_eiger.c +++ b/arch/alpha/kernel/sys_eiger.c @@ -34,10 +34,6 @@ #include "machvec_impl.h" -/* - * HACK ALERT! only the boot cpu is used for interrupts. - */ - /* Note that this interrupt code is identical to TAKARA. */ /* Note mask bit is true for DISABLED irqs. */ diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c index 0191ef91b..f54de2c87 100644 --- a/arch/alpha/kernel/sys_miata.c +++ b/arch/alpha/kernel/sys_miata.c @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1998, 1999, 2000 Richard Henderson * * Code supporting the MIATA (EV56+PYXIS). */ @@ -22,7 +22,7 @@ #include <asm/mmu_context.h> #include <asm/io.h> #include <asm/pgtable.h> -#include <asm/core_pyxis.h> +#include <asm/core_cia.h> #include "proto.h" #include "irq_impl.h" @@ -215,7 +215,7 @@ miata_swizzle(struct pci_dev *dev, u8 *pinp) static void __init miata_init_pci(void) { - common_init_pci(); + cia_init_pci(); SMC669_Init(0); /* it might be a GL (fails harmlessly if not) */ es1888_init(); } @@ -240,8 +240,8 @@ struct alpha_machine_vector miata_mv __initmv = { DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, - DO_PYXIS_BUS, - machine_check: pyxis_machine_check, + DO_CIA_BUS, + machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index a66731154..f436b4902 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -258,7 +258,7 @@ struct alpha_machine_vector mikasa_primo_mv __initmv = { init_arch: cia_init_arch, init_irq: mikasa_init_irq, init_rtc: common_init_rtc, - init_pci: common_init_pci, + init_pci: cia_init_pci, pci_map_irq: mikasa_map_irq, pci_swizzle: common_swizzle, }; diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c index 523d29853..8ef79db13 100644 --- a/arch/alpha/kernel/sys_noritake.c +++ b/arch/alpha/kernel/sys_noritake.c @@ -309,7 +309,7 @@ struct alpha_machine_vector noritake_primo_mv __initmv = { init_arch: cia_init_arch, init_irq: noritake_init_irq, init_rtc: common_init_rtc, - init_pci: common_init_pci, + init_pci: cia_init_pci, pci_map_irq: noritake_map_irq, pci_swizzle: noritake_swizzle, }; diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c index 01d80ab97..23069e06d 100644 --- a/arch/alpha/kernel/sys_ruffian.c +++ b/arch/alpha/kernel/sys_ruffian.c @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1998, 1999, 2000 Richard Henderson * * Code supporting the RUFFIAN. */ @@ -23,7 +23,7 @@ #include <asm/mmu_context.h> #include <asm/io.h> #include <asm/pgtable.h> -#include <asm/core_pyxis.h> +#include <asm/core_cia.h> #include "proto.h" #include "irq_impl.h" @@ -149,8 +149,8 @@ struct alpha_machine_vector ruffian_mv __initmv = { DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, - DO_PYXIS_BUS, - machine_check: pyxis_machine_check, + DO_CIA_BUS, + machine_check: cia_machine_check, max_dma_address: ALPHA_RUFFIAN_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, @@ -161,7 +161,7 @@ struct alpha_machine_vector ruffian_mv __initmv = { init_arch: pyxis_init_arch, init_irq: ruffian_init_irq, init_rtc: ruffian_init_rtc, - init_pci: common_init_pci, + init_pci: cia_init_pci, kill_arch: ruffian_kill_arch, pci_map_irq: ruffian_map_irq, pci_swizzle: common_swizzle, diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c index bad57d35e..b98e46028 100644 --- a/arch/alpha/kernel/sys_sx164.c +++ b/arch/alpha/kernel/sys_sx164.c @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1998, 1999, 2000 Richard Henderson * * Code supporting the SX164 (PCA56+PYXIS). */ @@ -23,7 +23,7 @@ #include <asm/mmu_context.h> #include <asm/io.h> #include <asm/pgtable.h> -#include <asm/core_pyxis.h> +#include <asm/core_cia.h> #include "proto.h" #include "irq_impl.h" @@ -107,10 +107,10 @@ sx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return COMMON_TABLE_LOOKUP; } -void __init +static void __init sx164_init_pci(void) { - common_init_pci(); + cia_init_pci(); SMC669_Init(0); } @@ -124,8 +124,8 @@ struct alpha_machine_vector sx164_mv __initmv = { DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, - DO_PYXIS_BUS, - machine_check: pyxis_machine_check, + DO_CIA_BUS, + machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c index a0bc57125..9ebba3955 100644 --- a/arch/alpha/kernel/sys_takara.c +++ b/arch/alpha/kernel/sys_takara.c @@ -258,7 +258,7 @@ takara_init_pci(void) if (alpha_using_srm) alpha_mv.pci_map_irq = takara_map_irq_srm; - common_init_pci(); + cia_init_pci(); ns87312_enable_ide(0x26e); } diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 291682e33..6119ea371 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -48,6 +48,7 @@ extern volatile unsigned long lost_ticks; /* kernel/sched.c */ static int set_rtc_mmss(unsigned long); +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; /* * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting @@ -163,7 +164,7 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, } void -common_init_rtc() +common_init_rtc(void) { unsigned char x; @@ -406,6 +407,8 @@ set_rtc_mmss(unsigned long nowtime) int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* irq are locally disabled here */ + spin_lock(&rtc_lock); /* Tell the clock it's being set */ save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -455,6 +458,7 @@ set_rtc_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 828044b24..76504a1ef 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -215,10 +215,8 @@ do_entIF(unsigned long type, unsigned long a1, /* EV4 does not implement anything except normal rounding. Everything else will come here as an illegal instruction. Emulate them. */ - if (alpha_fp_emul(regs.pc)) { - regs.pc += 4; + if (alpha_fp_emul(regs.pc-4)) return; - } } send_sig(SIGILL, current, 1); break; diff --git a/arch/arm/Makefile b/arch/arm/Makefile index ad8e9423a..ff732b8fa 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -14,7 +14,6 @@ OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S CPP := $(CC) -E -PERL := perl LINKFLAGS := -p -X -T arch/arm/vmlinux.lds ARCHCC := $(word 1,$(CC)) @@ -101,6 +100,8 @@ endif LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) +export LIBGCC + ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k ARCHDIR = arc diff --git a/arch/arm/config.in b/arch/arm/config.in index ff4f954df..2ff7f6414 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -35,9 +35,9 @@ fi if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then bool ' Include support for EBSA285' CONFIG_ARCH_EBSA285 - bool ' Include support for CATS' CONFIG_CATS + bool ' Include support for CATS' CONFIG_ARCH_CATS bool ' Include support for NetWinder' CONFIG_ARCH_NETWINDER - bool ' Include support for Compaq Personal Server' CONFIG_PERSONAL_SERVER + bool ' Include support for Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER fi if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then @@ -124,7 +124,7 @@ fi # # These machines have ISA-DMA # -if [ "$CONFIG_CATS" = "y" -o \ +if [ "$CONFIG_ARCH_CATS" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" ]; then define_bool CONFIG_ISA_DMA y @@ -171,8 +171,8 @@ source drivers/parport/Config.in if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" -o \ - "$CONFIG_PERSONAL_SERVER" = "y" -o \ - "$CONFIG_CATS" = "y" ]; then + "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \ + "$CONFIG_ARCH_CATS" = "y" ]; then string 'Initial kernel command string' CONFIG_CMDLINE fi if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ diff --git a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c index 8645497ae..536e614ff 100644 --- a/arch/arm/kernel/arch.c +++ b/arch/arm/kernel/arch.c @@ -192,6 +192,7 @@ fixup_sa1100(struct machine_desc *desc, struct param_struct *params, * in head-armv.S. */ static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.info"))) = { +#ifdef CONFIG_ARCH_EBSA110 { MACH_TYPE_EBSA110, "EBSA110", /* RMK */ @@ -199,119 +200,160 @@ static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.in NO_VIDEO, 1, 0, 1, 1, 1, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_RPC + { MACH_TYPE_RISCPC, "Acorn-RiscPC", /* RMK */ 0x10000100, NO_VIDEO, 1, 1, 0, 0, 0, fixup_acorn - }, { - 2, - "unknown", - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_NEXUSPCI + { MACH_TYPE_NEXUSPCI, "FTV/PCI", /* Philip Blundell */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_EBSA285 + { MACH_TYPE_EBSA285, "EBSA285", /* RMK */ 0x00000100, 0x000a0000, 0x000bffff, 0, 0, 0, 0, 0, fixup_ebsa285 - }, { + }, +#endif +#ifdef CONFIG_ARCH_NETWINDER + { MACH_TYPE_NETWINDER, "Rebel-NetWinder", /* RMK */ 0x00000100, 0x000a0000, 0x000bffff, 1, 0, 1, 0, 0, fixup_netwinder - }, { + }, +#endif +#ifdef CONFIG_ARCH_CATS + { MACH_TYPE_CATS, "Chalice-CATS", /* Philip Blundell */ NO_PARAMS, 0x000a0000, 0x000bffff, 0, 0, 0, 0, 1, fixup_cats - }, { + }, +#endif +#ifdef CONFIG_ARCH_TBOX + { MACH_TYPE_TBOX, "unknown-TBOX", /* Philip Blundell */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_CO285 + { MACH_TYPE_CO285, "co-EBSA285", /* Mark van Doesburg */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, fixup_coebsa285 - }, { + }, +#endif +#ifdef CONFIG_ARCH_CLPS7110 + { MACH_TYPE_CLPS7110, "CL-PS7110", /* Werner Almesberger */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_ARC + { MACH_TYPE_ARCHIMEDES, "Acorn-Archimedes",/* RMK/DAG */ 0x0207c000, NO_VIDEO, 0, 0, 0, 0, 0, fixup_acorn - }, { + }, +#endif +#ifdef CONFIG_ARCH_A5K + { MACH_TYPE_A5K, "Acorn-A5000", /* RMK/PB */ 0x0207c000, NO_VIDEO, 0, 0, 0, 0, 0, fixup_acorn - }, { + }, +#endif +#ifdef CONFIG_ARCH_ETOILE + { MACH_TYPE_ETOILE, "Etoile", /* Alex de Vries */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_LACIE_NAS + { MACH_TYPE_LACIE_NAS, "LaCie_NAS", /* Benjamin Herrenschmidt */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_CLPS7500 + { MACH_TYPE_CLPS7500, "CL-PS7500", /* Philip Blundell */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_SHARK + { MACH_TYPE_SHARK, "Shark", /* Alexander Schulz */ NO_PARAMS, 0x06000000, 0x06000000+0x001fffff, 0, 0, 0, 0, 0, NULL - }, { + }, +#endif +#ifdef CONFIG_ARCH_SA1100 + { MACH_TYPE_SA1100, "SA1100-based", /* Nicolas Pitre */ NO_PARAMS, NO_VIDEO, 0, 0, 0, 0, 0, fixup_sa1100 - }, { + }, +#endif +#ifdef CONFIG_ARCH_PERSONAL_SERVER + { MACH_TYPE_PERSONAL_SERVER, "Compaq Personal Server", NO_PARAMS, @@ -319,4 +361,5 @@ static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.in 0, 0, 0, 0, 0, NULL } +#endif }; diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 1b0a064d0..109e2f96d 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -164,7 +164,52 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) void __init pcibios_fixup_bus(struct pci_bus *bus) { struct list_head *walk = &bus->devices; + struct arm_pci_sysdata *sysdata = + (struct arm_pci_sysdata *)bus->sysdata; + struct arm_bus_sysdata *busdata; + if (bus->number < MAX_NR_BUS) + busdata = sysdata->bus + bus->number; + else + BUG(); + + /* + * Walk the devices on this bus, working out what we can + * and can't support. + */ + for (walk = walk->next; walk != &bus->devices; walk = walk->next) { + struct pci_dev *dev = pci_dev_b(walk); + u16 status; + + pci_read_config_word(dev, PCI_STATUS, &status); + + /* + * If this device does not support fast back to back + * transfers, the bus as a whole cannot support them. + */ + if (!(status & PCI_STATUS_FAST_BACK)) + busdata->features &= ~PCI_COMMAND_FAST_BACK; + + /* + * Calculate the maximum devsel latency. + */ + if (busdata->maxdevsel < (status & PCI_STATUS_DEVSEL_MASK)) + busdata->maxdevsel = (status & PCI_STATUS_DEVSEL_MASK); + + /* + * If this device is an ISA bridge, set the have_isa_bridge + * flag. We will then go looking for things like keyboard, + * etc + */ + if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA || + dev->class >> 8 == PCI_CLASS_BRIDGE_EISA) + have_isa_bridge = !0; + } + + /* + * Now walk the devices again, this time setting them up. + */ + walk = &bus->devices; for (walk = walk->next; walk != &bus->devices; walk = walk->next) { struct pci_dev *dev = pci_dev_b(walk); u16 cmd; @@ -182,25 +227,15 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) pci_write_config_dword(dev, 0x40, 0x80000000); /* - * If this device is an ISA bridge, set the have_isa_bridge - * flag. We will then go looking for things like keyboard, - * etc - */ - if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA || - dev->class >> 8 == PCI_CLASS_BRIDGE_EISA) - have_isa_bridge = !0; - - /* * Set latency timer to 32, and a cache line size to 32 bytes. - * Also, set system error enable, parity error enable, and - * fast back to back transaction enable. Disable ROM. + * Also, set system error enable, parity error enable. + * Disable ROM. */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | - PCI_COMMAND_PARITY; + cmd |= busdata->features; pci_write_config_word(dev, PCI_COMMAND, cmd); pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -254,7 +289,7 @@ static struct hw_pci ebsa285_pci __initdata = { }; #endif -#ifdef CONFIG_CATS +#ifdef CONFIG_ARCH_CATS /* cats host-specific stuff */ static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; @@ -323,7 +358,7 @@ static struct hw_pci netwinder_pci __initdata = { }; #endif -#ifdef CONFIG_PERSONAL_SERVER +#ifdef CONFIG_ARCH_PERSONAL_SERVER static int irqmap_personal_server[] __initdata = { IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0, IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI @@ -399,7 +434,7 @@ void __init pcibios_init(void) break; } #endif -#ifdef CONFIG_CATS +#ifdef CONFIG_ARCH_CATS if (machine_is_cats()) { hw_pci = &cats_pci; break; @@ -411,7 +446,7 @@ void __init pcibios_init(void) break; } #endif -#ifdef CONFIG_PERSONAL_SERVER +#ifdef CONFIG_ARCH_PERSONAL_SERVER if (machine_is_personal_server()) { hw_pci = &personal_server_pci; break; diff --git a/arch/arm/kernel/bios32.h b/arch/arm/kernel/bios32.h index 9a4380732..525af165b 100644 --- a/arch/arm/kernel/bios32.h +++ b/arch/arm/kernel/bios32.h @@ -1,9 +1,27 @@ +#define MAX_NR_BUS 2 + +struct arm_bus_sysdata { + /* + * bitmask of features we can turn. + * See PCI command register for more info. + */ + u16 features; + /* + * Maximum devsel for this bus. + */ + u16 maxdevsel; +}; + +struct arm_pci_sysdata { + struct arm_bus_sysdata bus[MAX_NR_BUS]; +}; + struct hw_pci { - void (*init)(void); + void (*init)(void); unsigned long io_start; unsigned long mem_start; - u8 (*swizzle)(struct pci_dev *dev, u8 *pin); - int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); + u8 (*swizzle)(struct pci_dev *dev, u8 *pin); + int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); }; void __init dc21285_init(void); diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c index 6158e995a..64c5861f0 100644 --- a/arch/arm/kernel/dec21285.c +++ b/arch/arm/kernel/dec21285.c @@ -206,8 +206,11 @@ static struct irqaction dc21285_error_action = { void __init dc21285_init(void) { static struct resource csrmem, csrio; - unsigned int mem_size; + struct arm_pci_sysdata sysdata; unsigned long cntl; + unsigned int mem_size, pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + int i; mem_size = (unsigned int)high_memory - PAGE_OFFSET; *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; @@ -240,25 +243,34 @@ void __init dc21285_init(void) *CSR_PCICSRIOBASE = csrio.start; *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); *CSR_PCIROMBASE = 0; - *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | - PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + *CSR_PCICMD = pci_cmd | (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); #endif printk(KERN_DEBUG "PCI: DC21285 footbridge, revision %02lX\n", *CSR_CLASSREV & 0xff); - pci_scan_bus(0, &dc21285_ops, NULL); + for (i = 0; i < MAX_NR_BUS; i++) { + sysdata.bus[i].features = PCI_COMMAND_FAST_BACK | + PCI_COMMAND_SERR | + PCI_COMMAND_PARITY; + sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST; + } + + pci_scan_bus(0, &dc21285_ops, &sysdata); + + pci_cmd |= sysdata.bus[0].features; + + printk("Fast back to back PCI transfers %sabled\n", + (sysdata.bus[0].features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); /* * Clear any existing errors - we aren't * interested in historical data... */ - cntl = *CSR_SA110_CNTL & 0xffffde07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - cntl = *CSR_PCICMD & 0x0000ffff; - *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; + cntl = *CSR_SA110_CNTL & 0xffffde07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + *CSR_PCICMD = pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; /* * Initialise PCI error IRQ after we've finished probing diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c index 8dcad0b93..f47e169c5 100644 --- a/arch/arm/kernel/hw-footbridge.c +++ b/arch/arm/kernel/hw-footbridge.c @@ -613,7 +613,7 @@ EXPORT_SYMBOL(cpld_modify); /* * CATS stuff */ -#ifdef CONFIG_CATS +#ifdef CONFIG_ARCH_CATS #define CONFIG_PORT 0x370 #define INDEX_PORT (CONFIG_PORT) @@ -698,7 +698,7 @@ void __init hw_init(void) #endif } #endif -#ifdef CONFIG_CATS +#ifdef CONFIG_ARCH_CATS if (machine_is_cats()) cats_hw_init(); #endif diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 46afd5938..6ea7916ef 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -1,7 +1,7 @@ /* * linux/arch/arm/kernel/process.c * - * Copyright (C) 1996-1999 Russell King - Converted to ARM. + * Copyright (C) 1996-2000 Russell King - Converted to ARM. * Origional Copyright (C) 1995 Linus Torvalds */ @@ -32,6 +32,7 @@ #include <asm/io.h> extern char *processor_modes[]; +extern void setup_mm_for_reboot(char mode); asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); @@ -96,15 +97,28 @@ __setup("reboot=", reboot_setup); void machine_restart(char * __unused) { /* - * Turn off caches, interrupts, etc + * Clean and disable cache, and turn off interrupts */ cpu_proc_fin(); + /* + * Tell the mm system that we are going to reboot - + * we may need it to insert some 1:1 mappings so that + * soft boot works. + */ + setup_mm_for_reboot(reboot_mode); + + /* + * Now call the architecture specific reboot code. + */ arch_reset(reboot_mode); + /* + * Whoops - the architecture was unable to reboot. + * Tell the user! + */ mdelay(1000); printk("Reboot failed -- System halted\n"); - cli(); while (1); } diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 4a23d14bd..13336c008 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -379,7 +379,8 @@ static const struct fsr_info { */ #define BUG_PROC_MSG \ KERN_DEBUG "Weird data abort (%08X).\n" \ - KERN_DEBUG "Please see http://www.arm.linux.org.uk/state.html for more information" + KERN_DEBUG "Please see http://www.arm.linux.org.uk/state.html for " \ + "more information\n" asmlinkage void do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) diff --git a/arch/arm/mm/mm-armo.c b/arch/arm/mm/mm-armo.c index a5d4cdfe8..f4bf7cad5 100644 --- a/arch/arm/mm/mm-armo.c +++ b/arch/arm/mm/mm-armo.c @@ -3,7 +3,7 @@ * * Page table sludge for older ARM processor architectures. * - * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1998-2000 Russell King */ #include <linux/sched.h> #include <linux/mm.h> @@ -135,6 +135,13 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) } /* + * No special code is required here. + */ +void setup_mm_for_reboot(char mode) +{ +} + +/* * This contains the code to setup the memory map on an ARM2/ARM250/ARM3 * machine. This is both processor & architecture specific, and requires * some more work to get it to fit into our separate processor and @@ -155,6 +162,9 @@ void __init pagetable_init(void) pgd_val(swapper_pg_dir[i]) = 0; } +/* + * We never have holes in the memmap + */ void __init create_memmap_holes(void) { } diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index ddc69089a..cb29618a3 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -3,7 +3,7 @@ * * Page table sludge for ARM v3 and v4 processor architectures. * - * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1998-2000 Russell King */ #include <linux/sched.h> #include <linux/mm.h> @@ -286,6 +286,25 @@ static void __init create_mapping(struct map_desc *md) } } +/* + * In order to soft-boot, we need to insert a 1:1 mapping in place of + * the user-mode pages. This will then ensure that we have predictable + * results when turning the mmu off + */ +void setup_mm_for_reboot(char mode) +{ + pgd_t *pgd = current->mm->pgd; + pmd_t pmd; + int i; + + for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) { + pmd_val(pmd) = (i << PGDIR_SHIFT) | + PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | + PMD_TYPE_SECT; + set_pmd(pmd_offset(pgd + i, i << PGDIR_SHIFT), pmd); + } +} + void __init pagetable_init(void) { struct map_desc *init_maps, *p, *q; diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S index 9814d2a9c..dd039f208 100644 --- a/arch/arm/mm/proc-arm6,7.S +++ b/arch/arm/mm/proc-arm6,7.S @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/proc-arm6,7.S: MMU functions for ARM6 * - * (C) 1997-1999 Russell King + * (C) 1997-2000 Russell King * * These are the low level assembler for performing cache and TLB * functions on the ARM6 & ARM7. @@ -342,15 +342,17 @@ ENTRY(cpu_arm7_set_pte) /* * Function: _arm6_7_reset - * + * Params : r0 = address to jump to * Notes : This sets up everything for a reset */ ENTRY(cpu_arm6_reset) ENTRY(cpu_arm7_reset) - mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ flush cache - mcr p15, 0, r0, c5, c0, 0 @ flush TLB - mov pc, lr + mov r1, #0 + mcr p15, 0, r1, c7, c0, 0 @ flush cache + mcr p15, 0, r1, c5, c0, 0 @ flush TLB + mov r1, #0x30 + mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc + mov pc, r0 cpu_armvlsi_name: .asciz "ARM/VLSI" diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index 933408451..9800643d9 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/proc-sa110.S: MMU functions for SA110 * - * (C) 1997-1999 Russell King + * (C) 1997-2000 Russell King * * These are the low level assembler for performing cache and TLB * functions on the StrongARM-110 and StrongARM-1100 @@ -225,9 +225,9 @@ ENTRY(cpu_sa1100_flush_ram_page) .align 5 ENTRY(cpu_sa110_flush_tlb_all) ENTRY(cpu_sa1100_flush_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ flush I & D tlbs + mov ip, #0 + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ flush I & D tlbs mov pc, lr /* @@ -421,16 +421,18 @@ ENTRY(cpu_sa1100_proc_init) ENTRY(cpu_sa110_proc_fin) ENTRY(cpu_sa1100_proc_fin) + stmfd sp!, {r1, lr} mrs r0, cpsr orr r0, r0, #F_BIT | I_BIT msr cpsr, r0 + bl cpu_sa110_flush_cache_all @ clean caches mov r0, #0 mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching mrc p15, 0, r0, c1, c0, 0 - bic r0, r0, #0x1100 @ ...i...s........ + bic r0, r0, #0x1000 @ ...i............ bic r0, r0, #0x000e @ ............wca. mcr p15, 0, r0, c1, c0, 0 @ disable caches - mov pc, lr + ldmfd sp!, {r1, pc} .align 5 ENTRY(cpu_sa110_do_idle) @@ -448,18 +450,21 @@ ENTRY(cpu_sa1100_do_idle) /* * Function: sa110_reset + * Params : r0 = address to jump to * Notes : This sets up everything for a reset */ + .align 5 ENTRY(cpu_sa110_reset) ENTRY(cpu_sa1100_reset) - stmfd sp!, {r1, lr} - bl cpu_sa110_flush_cache_all - bl cpu_sa110_flush_tlb_all + mov ip, #0 mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches - mrc p15, 0, r0, c1, c0, 0 @ ctrl register - bic r0, r0, #0x000f @ ............wcam - bic r0, r0, #0x1100 @ ...i...s........ - ldmfd sp!, {r1, pc} + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ flush I & D tlbs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 /* * Purpose : Function pointers used to access above functions - all calls * come through these diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 2a84bf05f..0e16a45b6 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -30,7 +30,8 @@ CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/nul CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi) ifdef CONFIG_M386 -CFLAGS := $(CFLAGS) -m386 -DCPU=386 +CFLAGS := $(CFLAGS) -DCPU=386 +CFLAGS += $(shell if $(CC) -march=i386 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i386"; else echo "-m386"; fi) AFLAGS := $(AFLAGS) -DCPU=386 endif @@ -65,7 +66,7 @@ AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_MK7 -CFLAGS := $(CFLAGS) -DCPU=686 -march=pentiumpro -mpentiumpro -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations +CFLAGS := $(CFLAGS) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations -DCPU=686 CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) AFLAGS := $(AFLAGS) -DCPU=686 endif diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S index 51e0fc893..102850b74 100644 --- a/arch/i386/boot/compressed/head.S +++ b/arch/i386/boot/compressed/head.S @@ -33,10 +33,10 @@ startup_32: cld cli movl $(__KERNEL_DS),%eax - movl %ax,%ds - movl %ax,%es - movl %ax,%fs - movl %ax,%gs + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs lss SYMBOL_NAME(stack_start),%esp xorl %eax,%eax diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 0f3f5cb8a..33f2d3cb1 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -179,7 +179,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_IDEDMA_PCI_AUTO is not set # CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_AUTO is not set # CONFIG_IDEDMA_PCI_EXPERIMENTAL is not set # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set @@ -208,6 +207,7 @@ CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set CONFIG_BLK_DEV_IDE_MODES=y # diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 8efa2832a..f9410f3fd 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -488,13 +488,13 @@ static int __init acpi_find_tables(void) if (!rsdt) { printk(KERN_ERR "ACPI: missing RSDT at 0x%p\n", (void*) rsdp->rsdt); - return -ENODEV; + return -EINVAL; } else if (rsdt->signature != ACPI_RSDT_SIG) { printk(KERN_ERR "ACPI: bad RSDT at 0x%p (%08x)\n", (void*) rsdp->rsdt, (unsigned) rsdt->signature); acpi_unmap_table(rsdt); - return -ENODEV; + return -EINVAL; } // search RSDT for FACP acpi_facp.table = NULL; @@ -532,7 +532,7 @@ static int __init acpi_find_tables(void) if (!acpi_facp.table) { printk(KERN_ERR "ACPI: missing FACP\n"); - return -ENODEV; + return -EINVAL; } return 0; } @@ -1461,8 +1461,19 @@ static int __init acpi_init(void) switch (acpi_enabled) { case ACPI_ENABLED: - if (acpi_find_tables() && acpi_find_chipset()) + switch (acpi_find_tables()) { + case 0: + // found valid ACPI tables + break; + case -ENODEV: + // found no ACPI tables, try chipset-specific + if (acpi_find_chipset()) + return -ENODEV; + break; + default: + // found broken ACPI tables return -ENODEV; + } break; case ACPI_TABLES_ONLY: if (acpi_find_tables()) @@ -1478,6 +1489,12 @@ static int __init acpi_init(void) facp = (struct acpi_facp*) acpi_facp.table; + if (PM_IS_ACTIVE()) { + printk(KERN_NOTICE "acpi: APM is already active.\n"); + goto err_out; + } + pm_active = 1; + /* * Internally we always keep latencies in timer * ticks, which is simpler and more consistent (what is @@ -1516,8 +1533,6 @@ static int __init acpi_init(void) pm_power_off = acpi_power_off; - pm_active = 1; - /* * Set up the ACPI idle function. Note that we can't really * do this with multiple CPU's, we'd need a per-CPU ACPI @@ -1549,7 +1564,6 @@ static void __exit acpi_exit(void) struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table; pm_idle = NULL; - pm_active = 0; pm_power_off = NULL; unregister_sysctl_table(acpi_sysctl); @@ -1563,6 +1577,8 @@ static void __exit acpi_exit(void) if (pci_driver_registered) pci_unregister_driver(&acpi_driver); + + pm_active = 0; } /* diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 3340946be..7a8a17b63 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -58,10 +58,19 @@ startup_32: * New page tables may be in 4Mbyte page mode and may * be using the global pages. * + * NOTE! If we are on a 486 we may have no cr4 at all! + * So we do not try to touch it unless we really have + * some bits in it to set. This won't work if the BSP + * implements cr4 but this AP does not -- very unlikely + * but be warned! The same applies to the pse feature + * if not equally supported. --macro + * * NOTE! We have to correct for the fact that we're * not yet offset PAGE_OFFSET.. */ #define cr4_bits mmu_cr4_features-__PAGE_OFFSET + cmpl $0,cr4_bits + je 1f movl %cr4,%eax # Turn on 4Mb pages orl cr4_bits,%eax movl %eax,%cr4 @@ -219,7 +228,6 @@ is386: pushl %ecx # restore original EFLAGS orl $2,%eax # set MP 2: movl %eax,%cr0 call check_x87 -4: #ifdef __SMP__ incb ready #endif diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index e21c33b6f..5327f24a4 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -25,6 +25,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); +extern spinlock_t rtc_lock; #ifdef CONFIG_SMP extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); @@ -131,3 +132,5 @@ EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(irq_stat); + +EXPORT_SYMBOL(rtc_lock); diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c index 6dd0a4306..942de9c79 100644 --- a/arch/i386/kernel/pci-i386.c +++ b/arch/i386/kernel/pci-i386.c @@ -323,3 +323,17 @@ int pcibios_enable_resources(struct pci_dev *dev) } return 0; } + +/* + * If we set up a device for bus mastering, we need to check the latency + * timer as certain crappy BIOSes forget to set it properly. + */ +void pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) { + printk("PCI: Increasing latency timer of device %s to 64\n", dev->slot_name); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + } +} diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index e51e96e43..b588642cc 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -1103,9 +1103,9 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r { struct irq_info *q; struct pci_dev *router; - int i, pirq, newirq; + int i, pirq, newirq, reg; u32 rtrid, mask; - u8 x; + u8 x, y; char *msg = NULL; pin--; @@ -1169,14 +1169,44 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r DBG(" -> [PIIX] set to %02x\n", newirq); pci_write_config_byte(router, pirq, newirq); msg = "PIIX-NEW"; - } else - DBG(" -> [PIIX] sink\n"); + } else DBG(" -> [PIIX] sink\n"); break; case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533): newirq = ali_set_irq(router, pirq-1, newirq); if (newirq) msg = "ALI"; break; + case ID(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596): + case ID(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686): + reg = 0x55 + (pirq >> 1); + pci_read_config_byte(router, reg, &x); + y = (pirq & 1) ? (x >> 4) : (x & 0x0f); + if (y) { + DBG(" -> [VIA] %02x\n", y); + newirq = y; + msg = "VIA"; + } else if (newirq) { + DBG(" -> [VIA] set to %02x\n", newirq); + x = (pirq & 1) ? ((x & 0x0f) | (newirq << 4)) : ((x & 0xf0) | newirq); + pci_write_config_byte(router, reg, y); + msg = "VIA-NEW"; + } else DBG(" -> [VIA] sink\n"); + break; + case ID(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700): + reg = 0xb8 + (pirq >> 5); + pci_read_config_byte(router, reg, &x); + y = (pirq & 0x10) ? (x >> 4) : (x & 0x0f); + if (y) { + DBG(" -> [OPTI] %02x\n", y); + newirq = y; + msg = "OPTI"; + } else if (newirq) { + DBG(" -> [OPTI] set to %02x\n", newirq); + x = (pirq & 0x10) ? ((x & 0x0f) | (newirq << 4)) : ((x & 0xf0) | newirq); + pci_write_config_byte(router, reg, y); + msg = "OPTI-NEW"; + } else DBG(" -> [OPTI] sink\n"); + break; default: DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device); if (newirq && mask == (1 << newirq)) { diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index a12b6b73d..46292496d 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -793,7 +793,7 @@ static int __init get_model_name(struct cpuinfo_x86 *c) unsigned int n, dummy, *v, ecx, edx; /* Actually we must have cpuid or we could never have - * figured out that this was AMD from the vendor info :-). + * figured out that this was AMD/Cyrix from the vendor info :-). */ cpuid(0x80000000, &n, &dummy, &dummy, &dummy); @@ -806,23 +806,27 @@ static int __init get_model_name(struct cpuinfo_x86 *c) cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); c->x86_model_id[48] = 0; /* Set MTRR capability flag if appropriate */ - if(boot_cpu_data.x86 == 5) { - if((boot_cpu_data.x86_model == 9) || - ((boot_cpu_data.x86_model == 8) && - (boot_cpu_data.x86_mask >= 8))) - c->x86_capability |= X86_FEATURE_MTRR; - } - - if (n >= 0x80000005){ - cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); - printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", - ecx>>24, edx>>24); - c->x86_cache_size=(ecx>>24)+(edx>>24); - } - if (n >= 0x80000006){ - cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); - printk("CPU: L2 Cache: %dK\n", ecx>>16); - c->x86_cache_size=(ecx>>16); + + if(c->x86_vendor==X86_VENDOR_AMD) + { + if(boot_cpu_data.x86 == 5) { + if((boot_cpu_data.x86_model == 9) || + ((boot_cpu_data.x86_model == 8) && + (boot_cpu_data.x86_mask >= 8))) + c->x86_capability |= X86_FEATURE_MTRR; + } + + if (n >= 0x80000005){ + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", + ecx>>24, edx>>24); + c->x86_cache_size=(ecx>>24)+(edx>>24); + } + if (n >= 0x80000006){ + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + printk("CPU: L2 Cache: %dK\n", ecx>>16); + c->x86_cache_size=(ecx>>16); + } } return 1; } @@ -1034,6 +1038,8 @@ static void __init cyrix_model(struct cpuinfo_x86 *c) printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n"); isa_dma_bridge_buggy = 2; #endif + c->x86_cache_size=16; /* Yep 16K integrated cache thats it */ + /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { get_model_name(c); /* get CPU marketing name */ @@ -1546,7 +1552,7 @@ void __init cpu_init (void) cpus_initialized++; printk("Initializing CPU#%d\n", nr); - if (cpu_has_pse) + if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index b4a7753b8..bcec04401 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -79,6 +79,9 @@ static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ unsigned long fast_gettimeoffset_quotient=0; extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; + +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; static inline unsigned long do_fast_gettimeoffset(void) { @@ -113,6 +116,8 @@ static inline unsigned long do_fast_gettimeoffset(void) #ifndef CONFIG_X86_TSC +spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; + /* This function must be called with interrupts disabled * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs * @@ -157,6 +162,8 @@ static unsigned long do_slow_gettimeoffset(void) */ unsigned long jiffies_t; + /* gets recalled with irq locally disabled */ + spin_lock(&i8253_lock); /* timer count may underflow right here */ outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -215,6 +222,7 @@ static unsigned long do_slow_gettimeoffset(void) } } else jiffies_p = jiffies_t; + spin_unlock(&i8253_lock); count_p = count; @@ -238,7 +246,6 @@ static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; */ void do_gettimeofday(struct timeval *tv) { - extern volatile unsigned long lost_ticks; unsigned long flags; unsigned long usec, sec; @@ -272,6 +279,7 @@ void do_settimeofday(struct timeval *tv) * would have done, and then undo it! */ tv->tv_usec -= do_gettimeoffset(); + tv->tv_usec -= lost_ticks * (1000000 / HZ); while (tv->tv_usec < 0) { tv->tv_usec += 1000000; @@ -302,6 +310,8 @@ static int set_rtc_mmss(unsigned long nowtime) int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* gets recalled with irq locally disabled */ + spin_lock(&rtc_lock); save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -347,6 +357,7 @@ static int set_rtc_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } @@ -448,10 +459,19 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) rdtscl(last_tsc_low); +#if 0 /* + * SUBTLE: this is not necessary from here because it's implicit in the + * write xtime_lock. + */ + spin_lock(&i8253_lock); +#endif outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; +#if 0 + spin_unlock(&i8253_lock); +#endif count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation index 0eda6e9fc..7bef250f8 100644 --- a/arch/mips/defconfig-decstation +++ b/arch/mips/defconfig-decstation @@ -76,12 +76,8 @@ CONFIG_TC=y # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # # Additional Block Devices @@ -90,10 +86,6 @@ CONFIG_TC=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -151,6 +143,13 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_PHONE_IXJ is not set # +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# # SCSI support # CONFIG_SCSI=y diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 35055ac68..47947bbf0 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -1,4 +1,4 @@ -/* $Id: irixelf.c,v 1.26 2000/03/07 15:45:28 ralf Exp $ +/* $Id: irixelf.c,v 1.27 2000/03/19 01:28:43 ralf Exp $ * * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. @@ -43,7 +43,7 @@ #undef DEBUG_ELF static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); -static int load_irix_library(int fd); +static int load_irix_library(struct file *); static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file); extern int dump_fpu (elf_fpregset_t *); @@ -829,7 +829,7 @@ out_free_ph: /* This is really simpleminded and specialized - we are loading an * a.out library that is given an ELF header. */ -static inline int do_load_irix_library(struct file *file) +static int load_irix_library(struct file *file) { struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; @@ -843,8 +843,6 @@ static inline int do_load_irix_library(struct file *file) int i,j, k; len = 0; - if (!file->f_op) - return -EACCES; dentry = file->f_dentry; inode = dentry->d_inode; elf_bss = 0; @@ -897,16 +895,18 @@ static inline int do_load_irix_library(struct file *file) while(elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ + down(¤t->mm->mmap_sem); error = do_mmap(file, elf_phdata->p_vaddr & 0xfffff000, elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, elf_phdata->p_offset & 0xfffff000); + up(¤t->mm->mmap_sem); k = elf_phdata->p_vaddr + elf_phdata->p_filesz; - if(k > elf_bss) elf_bss = k; - + if (k > elf_bss) elf_bss = k; + if (error != (elf_phdata->p_vaddr & 0xfffff000)) { kfree(elf_phdata); return error; @@ -921,19 +921,6 @@ static inline int do_load_irix_library(struct file *file) kfree(elf_phdata); return 0; } - -static int load_irix_library(int fd) -{ - int retval = -EACCES; - struct file *file; - - file = fget(fd); - if (file) { - retval = do_load_irix_library(file); - fput(file); - } - return retval; -} /* Called through irix_syssgi() to map an elf image given an FD, * a phdr ptr USER_PHDRP in userspace, and a count CNT telling how many diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index a5de95ca5..414d98df6 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -53,12 +53,8 @@ CONFIG_BINFMT_ELF=y # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # # Additional Block Devices @@ -67,10 +63,6 @@ CONFIG_BINFMT_ELF=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -102,6 +94,7 @@ CONFIG_SKB_LARGE=y # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # # Telephony Support @@ -110,6 +103,13 @@ CONFIG_SKB_LARGE=y # CONFIG_PHONE_IXJ is not set # +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# # SCSI support # # CONFIG_SCSI is not set @@ -225,7 +225,6 @@ CONFIG_VT_CONSOLE=y # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set # # Video For Linux diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 73a6c2bf7..30595e694 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -756,7 +756,7 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id) id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->word92 = __le16_to_cpu(id->word92); id->hw_config = __le16_to_cpu(id->hw_config); - for (i=0; i<34; i++) + for (i=0; i<32; i++) id->words94_125[i] = __le16_to_cpu(id->words94_125[i]); id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index dec2105d8..6725e8cfe 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -49,6 +49,8 @@ SUBDIRS += arch/sparc/boot CORE_FILES_NO_BTFIX := $(CORE_FILES) CORE_FILES += arch/sparc/boot/btfix.o +export CORE_FILES_NO_BTFIX + archclean: rm -f $(TOPDIR)/vmlinux.aout -$(MAKE) -C arch/sparc/boot clean diff --git a/arch/sparc/config.in b/arch/sparc/config.in index adb0ebe4c..e67a43022 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.88 2000/03/13 03:40:27 davem Exp $ +# $Id: config.in,v 1.90 2000/03/17 05:18:02 anton Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -19,18 +19,6 @@ define_bool CONFIG_VT_CONSOLE y bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP -bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 -if [ "$CONFIG_SUN4" != "y" ]; then - bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI - source drivers/pci/Config.in -fi - -mainmenu_option next_comment -comment 'Console drivers' -bool 'PROM console' CONFIG_PROM_CONSOLE -source drivers/video/Config.in -endmenu - # Global things across all Sun machines. define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y @@ -43,9 +31,11 @@ define_bool CONFIG_SUN_KEYBOARD y define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y + +bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 if [ "$CONFIG_SUN4" != "y" ]; then - source drivers/sbus/char/Config.in - source drivers/sbus/audio/Config.in + bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI + source drivers/pci/Config.in fi tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS @@ -74,15 +64,27 @@ fi endmenu mainmenu_option next_comment -comment 'Floppy and other block devices' +comment 'Console drivers' +bool 'PROM console' CONFIG_PROM_CONSOLE +source drivers/video/Config.in +endmenu + +if [ "$CONFIG_SUN4" != "y" ]; then + source drivers/sbus/char/Config.in + source drivers/sbus/audio/Config.in +fi + +mainmenu_option next_comment +comment 'Block devices' bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD + bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED - tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING - tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 +# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING +# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM @@ -99,16 +101,6 @@ if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi -mainmenu_option next_comment -comment 'ISDN subsystem' - -tristate 'ISDN support' CONFIG_ISDN -if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in -fi -endmenu - - define_bool CONFIG_IDE n define_bool CONFIG_BLK_DEV_IDE_MODES n define_bool CONFIG_BLK_DEV_HD n @@ -127,6 +119,15 @@ define_bool CONFIG_BLK_DEV_HD n # endmenu mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu + +mainmenu_option next_comment comment 'SCSI support' tristate 'SCSI support' CONFIG_SCSI @@ -196,12 +197,16 @@ if [ "$CONFIG_NET" = "y" ]; then fi tristate ' Sun LANCE support' CONFIG_SUNLANCE tristate ' Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL - tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC + fi tristate ' Sun QuadEthernet support' CONFIG_SUNQE tristate ' MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS + # bool ' FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then # fi + if [ "$CONFIG_ATM" = "y" ]; then source drivers/atm/Config.in fi diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index de483af6e..b39da1989 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -14,8 +14,42 @@ CONFIG_EXPERIMENTAL=y CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_SMP is not set +CONFIG_SBUS=y +CONFIG_SBUSCHAR=y +CONFIG_BUSMOUSE=y +CONFIG_SUN_MOUSE=y +CONFIG_SERIAL=y +CONFIG_SUN_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SUN_KEYBOARD=y +CONFIG_SUN_CONSOLE=y +CONFIG_SUN_AUXIO=y +CONFIG_SUN_IO=y # CONFIG_SUN4 is not set # CONFIG_PCI is not set +CONFIG_SUN_OPENPROMFS=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_SUNOS_EMUL=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_PRINTER is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y # # Console drivers @@ -42,17 +76,6 @@ CONFIG_FBCON_CFB8=y CONFIG_FBCON_FONTWIDTH8_ONLY=y CONFIG_FONT_SUN8x16=y # CONFIG_FBCON_FONTS is not set -CONFIG_SBUS=y -CONFIG_SBUSCHAR=y -CONFIG_BUSMOUSE=y -CONFIG_SUN_MOUSE=y -CONFIG_SERIAL=y -CONFIG_SUN_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -CONFIG_SUN_KEYBOARD=y -CONFIG_SUN_CONSOLE=y -CONFIG_SUN_AUXIO=y -CONFIG_SUN_IO=y # # Misc Linux/SPARC drivers @@ -73,39 +96,14 @@ CONFIG_SUN_AURORA=m # CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DBRI is not set # CONFIG_SPARCAUDIO_DUMMY is not set -CONFIG_SUN_OPENPROMFS=m -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_KCORE_ELF=y -CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=m -CONFIG_SUNOS_EMUL=y # -# Parallel port support -# -# CONFIG_PARPORT is not set -# CONFIG_PRINTER is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# -# Floppy, IDE, and other block devices +# Block devices # CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=m CONFIG_MD_STRIPED=m -CONFIG_MD_MIRRORING=m -CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m @@ -162,6 +160,9 @@ CONFIG_DECNET_SIOCGIFCONF=y # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set # # ISDN subsystem @@ -169,11 +170,6 @@ CONFIG_DECNET_SIOCGIFCONF=y # CONFIG_ISDN is not set # -# ATA/IDE/MFM/RLL support -# -# CONFIG_IDE is not set - -# # SCSI support # CONFIG_SCSI=y diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index e9b506e10..b1ed3c2af 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.35 2000/02/27 08:16:25 davem Exp $ +/* $Id: ioport.c,v 1.36 2000/03/16 08:22:53 anton Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -745,6 +745,10 @@ void ioport_init(void) halt(); }; +} + +void register_proc_sparc_ioport(void) +{ #ifdef CONFIG_PROC_FS create_proc_read_entry("io_map",0,0,_sparc_io_get_info,&sparc_iomap); create_proc_read_entry("dvma_map",0,0,_sparc_io_get_info,&_sparc_dvma); diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index d4ac34932..5966e04d7 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.115 2000/02/26 04:24:31 davem Exp $ +/* $Id: setup.c,v 1.116 2000/03/15 23:26:22 anton Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -268,8 +268,6 @@ extern void sun_serial_setup(void); extern unsigned short root_flags; extern unsigned short root_dev; extern unsigned short ram_flags; -extern unsigned sparc_ramdisk_image; -extern unsigned sparc_ramdisk_size; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 @@ -382,42 +380,9 @@ void __init setup_arch(char **cmdline_p) rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif -#ifdef CONFIG_BLK_DEV_INITRD -// FIXME needs to do the new bootmem alloc stuff - if (sparc_ramdisk_image) { - initrd_start = sparc_ramdisk_image; - if (initrd_start < KERNBASE) initrd_start += KERNBASE; - initrd_end = initrd_start + sparc_ramdisk_size; - if (initrd_end > *memory_end_p) { - printk(KERN_CRIT "initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,*memory_end_p); - initrd_start = 0; - } - if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) { - initrd_below_start_ok = 1; - *memory_start_p = PAGE_ALIGN (initrd_end); - } else if (initrd_start && sparc_ramdisk_image < KERNBASE) { - switch (sparc_cpu_model) { - case sun4m: - case sun4d: - initrd_start -= KERNBASE; - initrd_end -= KERNBASE; - break; - default: - break; - } - } - } -#endif + prom_setsync(prom_sync_me); -#ifdef CONFIG_SUN_SERIAL -#if 0 - /* XXX We can't do this until the bootmem allocator is working. */ - sun_serial_setup(); /* set this up ASAP */ -#endif -#endif { #if !CONFIG_SUN_SERIAL serial_console = 0; diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index e0bb41045..7b7a0eb61 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.94 2000/02/28 04:00:53 anton Exp $ +/* $Id: sparc_ksyms.c,v 1.96 2000/03/16 09:12:49 jj Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -68,6 +68,8 @@ extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); extern int __ashldi3(int, int); extern int __lshrdi3(int, int); +extern int __muldi3(int, int); +extern int __divdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); @@ -85,10 +87,10 @@ extern int __sparc_dot_ ## sym (int) __asm__("." #sym); \ __EXPORT_SYMBOL(__sparc_dot_ ## sym, "." #sym) #define EXPORT_SYMBOL_PRIVATE(sym) \ -extern int __sparc_priv_ ## sym (int) __asm__("__" ## #sym); \ +extern int __sparc_priv_ ## sym (int) __asm__("__" #sym); \ const struct module_symbol __export_priv_##sym \ __attribute__((section("__ksymtab"))) = \ -{ (unsigned long) &__sparc_priv_ ## sym, "__" ## #sym } +{ (unsigned long) &__sparc_priv_ ## sym, "__" #sym } /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); @@ -273,6 +275,8 @@ EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(__ashldi3); EXPORT_SYMBOL_NOVERS(__lshrdi3); +EXPORT_SYMBOL_NOVERS(__muldi3); +EXPORT_SYMBOL_NOVERS(__divdi3); EXPORT_SYMBOL_DOT(rem); EXPORT_SYMBOL_DOT(urem); diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c index 8a9d54913..eb79c344c 100644 --- a/arch/sparc/kernel/sys_solaris.c +++ b/arch/sparc/kernel/sys_solaris.c @@ -14,6 +14,7 @@ #include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/module.h> /* CHECKME: this stuff looks rather bogus */ asmlinkage int diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 262f6afdd..0a8a5827c 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.115 2000/03/13 21:57:23 davem Exp $ +/* $Id: sys_sunos.c,v 1.117 2000/03/15 02:43:32 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -267,35 +267,6 @@ asmlinkage void sunos_vadvise(unsigned long strategy) unlock_kernel(); } -/* Same as vadvise, and just as bogus, but for a range of virtual - * process address space. - */ -#define MADV_NORMAL 0 /* Nothing special... */ -#define MADV_RANDOM 1 /* I am emacs... */ -#define MADV_SEQUENTIAL 2 /* I am researcher code... */ -#define MADV_WILLNEED 3 /* Pages in this range will be needed */ -#define MADV_DONTNEED 4 /* Pages in this range won't be needed */ - -static char *mstrings[] = { - "MADV_NORMAL", - "MADV_RANDOM", - "MADV_SEQUENTIAL", - "MADV_WILLNEED", - "MADV_DONTNEED", -}; - -asmlinkage void sunos_madvise(unsigned long address, unsigned long len, - unsigned long strategy) -{ - /* I wanna see who uses this... */ - lock_kernel(); - printk("%s: Advises us to use %s paging strategy for addr<%08lx> len<%08lx>\n", - current->comm, - strategy <= 4 ? mstrings[strategy] : "BOGUS", - address, len); - unlock_kernel(); -} - /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE * resource limit and is for backwards compatibility with older sunos * revs. @@ -733,7 +704,6 @@ static int get_default (int value, int def_value) asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) { - int ret = -ENODEV; int server_fd; char *the_name; struct nfs_mount_data linux_nfs_mount; diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 42c072164..431f03daf 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.95 2000/03/13 21:57:23 davem Exp $ +/* $Id: systbls.S,v 1.96 2000/03/15 02:43:32 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -33,7 +33,7 @@ sys_call_table: /*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize /*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_geteuid /*70*/ .long sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect -/*75*/ .long sys_nis_syscall, sys_vhangup, sys_truncate64, sys_mincore, sys_getgroups16 +/*75*/ .long sys_madvise, sys_vhangup, sys_truncate64, sys_mincore, sys_getgroups16 /*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64 /*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid /*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid @@ -103,7 +103,7 @@ sunos_sys_table: .long sys_msync, sys_vfork, sunos_nosys .long sunos_nosys, sunos_sbrk, sunos_sstk .long sunos_mmap, sunos_vadvise, sys_munmap - .long sys_mprotect, sunos_madvise, sys_vhangup + .long sys_mprotect, sys_madvise, sys_vhangup .long sunos_nosys, sys_mincore, sys_getgroups16 .long sys_setgroups16, sys_getpgrp, sunos_setpgrp .long sys_setitimer, sunos_nosys, sys_swapon diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c index 592a2a4c0..2f051a6aa 100644 --- a/arch/sparc/kernel/unaligned.c +++ b/arch/sparc/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.20 2000/01/21 11:38:42 jj Exp $ +/* $Id: unaligned.c,v 1.21 2000/03/15 08:50:16 anton Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -106,6 +106,26 @@ static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) return win->locals[reg - 16]; /* yes, I know what this does... */ } +static inline unsigned long safe_fetch_reg(unsigned int reg, struct pt_regs *regs) +{ + struct reg_window *win; + unsigned long ret; + + if(reg < 16) + return (!reg ? 0 : regs->u_regs[reg]); + + /* Ho hum, the slightly complicated case. */ + win = (struct reg_window *) regs->u_regs[UREG_FP]; + + if ((unsigned long)win & 3) + return -1; + + if (get_user(ret, &win->locals[reg - 16])) + return -1; + + return ret; +} + static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) { struct reg_window *win; @@ -132,6 +152,22 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs, } } +static inline unsigned long safe_compute_effective_address(struct pt_regs *regs, + unsigned int insn) +{ + unsigned int rs1 = (insn >> 14) & 0x1f; + unsigned int rs2 = insn & 0x1f; + unsigned int rd = (insn >> 25) & 0x1f; + + if(insn & 0x2000) { + maybe_flush_windows(rs1, 0, rd); + return (safe_fetch_reg(rs1, regs) + sign_extend_imm13(insn)); + } else { + maybe_flush_windows(rs1, rs2, rd); + return (safe_fetch_reg(rs1, regs) + safe_fetch_reg(rs2, regs)); + } +} + /* This is just to make gcc think panic does return... */ static void unaligned_panic(char *str) { @@ -427,7 +463,7 @@ void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRALN; - info.si_addr = (void *)compute_effective_address(regs, insn); + info.si_addr = (void *)safe_compute_effective_address(regs, insn); info.si_trapno = 0; send_sig_info(SIGBUS, &info, current); } diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index d269e148b..8c3e8e4a9 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.32 2000/02/28 04:00:48 anton Exp $ +# $Id: Makefile,v 1.33 2000/03/16 00:52:07 anton Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,7 @@ OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \ - ashldi3.o rwsem.o + ashldi3.o rwsem.o muldi3.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/sparc/lib/muldi3.S b/arch/sparc/lib/muldi3.S new file mode 100644 index 000000000..7f17872d0 --- /dev/null +++ b/arch/sparc/lib/muldi3.S @@ -0,0 +1,76 @@ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + .text + .align 4 + .globl __muldi3 +__muldi3: + save %sp, -104, %sp + wr %g0, %i1, %y + sra %i3, 0x1f, %g2 + and %i1, %g2, %g2 + andcc %g0, 0, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, 0, %g1 + add %g1, %g2, %l2 + rd %y, %o1 + mov %o1, %l3 + mov %i1, %o0 + call .umul + mov %i2, %o1 + mov %o0, %l0 + mov %i0, %o0 + call .umul + mov %i3, %o1 + add %l0, %o0, %l0 + mov %l2, %i0 + add %l2, %l0, %i0 + ret + restore %g0, %l3, %o1 diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index d92fbbb0b..2fa3a2c56 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.83 2000/03/07 23:12:35 anton Exp $ +/* $Id: init.c,v 1.84 2000/03/15 23:26:26 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -43,7 +43,11 @@ unsigned long sparc_unmapped_base; struct pgtable_cache_struct pgt_quicklists = { 0, 0, 0, 0, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED }; /* References to section boundaries */ -extern char __init_begin, __init_end, _start, end, etext , edata; +extern char __init_begin, __init_end, _start, _end, etext , edata; + +/* Initial ramdisk setup */ +extern unsigned int sparc_ramdisk_image; +extern unsigned int sparc_ramdisk_size; unsigned long totalram_pages = 0; @@ -118,6 +122,7 @@ unsigned long __init bootmem_init(void) { unsigned long bootmap_size, start_pfn, end_pfn; unsigned long end_of_phys_memory = 0UL; + unsigned long bootmap_pfn; int i; /* Limit maximum memory until we implement highmem for sparc */ @@ -160,7 +165,7 @@ unsigned long __init bootmem_init(void) /* Start with page aligned address of last symbol in kernel * image. */ - start_pfn = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &end)); + start_pfn = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end)); /* Adjust up to the physical address where the kernel begins. */ start_pfn += phys_base; @@ -168,14 +173,36 @@ unsigned long __init bootmem_init(void) /* Now shift down to get the real physical page frame number. */ start_pfn >>= PAGE_SHIFT; + bootmap_pfn = start_pfn; + end_pfn = end_of_phys_memory >> PAGE_SHIFT; +#ifdef CONFIG_BLK_DEV_INITRD + /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ + if (sparc_ramdisk_image) { + if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE) + sparc_ramdisk_image -= KERNBASE; + initrd_start = sparc_ramdisk_image + phys_base; + initrd_end = initrd_start + sparc_ramdisk_size; + if (initrd_end > end_of_phys_memory) { + printk(KERN_CRIT "initrd extends beyond end of memory " + "(0x%016lx > 0x%016lx)\ndisabling initrd\n", + initrd_end, end_of_phys_memory); + initrd_start = 0; + } + if (initrd_start) { + if (initrd_start >= (start_pfn << PAGE_SHIFT) && + initrd_start < (start_pfn << PAGE_SHIFT) + 2 * PAGE_SIZE) + bootmap_pfn = PAGE_ALIGN (initrd_end) >> PAGE_SHIFT; + } + } +#endif /* Initialize the boot-time allocator. */ #ifdef DEBUG_BOOTMEM - prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n", - start_pfn, end_pfn); + prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],epfn[%lx])\n", + start_pfn, bootmap_pfn, end_pfn); #endif - bootmap_size = init_bootmem(start_pfn, end_pfn); + bootmap_size = init_bootmem(bootmap_pfn, end_pfn); /* Now register the available physical memory with the * allocator. @@ -190,15 +217,27 @@ unsigned long __init bootmem_init(void) sp_banks[i].num_bytes); } - /* Reserve the kernel text/data/bss and the bootmem bitmap. */ + /* Reserve the kernel text/data/bss, the bootmem bitmap and initrd. */ #ifdef DEBUG_BOOTMEM +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + initrd_start, initrd_end - initrd_start); +#endif prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - phys_base, - (start_pfn << PAGE_SHIFT) + - bootmap_size + PAGE_SIZE-1 - phys_base); + phys_base, (start_pfn << PAGE_SHIFT) - phys_base); + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + (bootmap_pfn << PAGE_SHIFT), bootmap_size); #endif - reserve_bootmem(phys_base, (start_pfn << PAGE_SHIFT) + - bootmap_size + PAGE_SIZE-1 - phys_base); +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + reserve_bootmem(initrd_start, initrd_end - initrd_start); + initrd_start += PAGE_OFFSET; + initrd_end += PAGE_OFFSET; + } +#endif + reserve_bootmem(phys_base, (start_pfn << PAGE_SHIFT) - phys_base); + reserve_bootmem((bootmap_pfn << PAGE_SHIFT), bootmap_size); #ifdef DEBUG_BOOTMEM prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn); @@ -371,18 +410,6 @@ void __init mem_init(void) } memset(sparc_valid_addr_bitmap, 0, i << 2); - /* fix this */ -#ifdef CONFIG_BLK_DEV_INITRD - addr = __va(phys_base); - last = PAGE_ALIGN((unsigned long)&end) + phys_base; - while(addr < last) { - if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) - mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved); - else - addr += PAGE_SIZE; - } -#endif - taint_real_pages(); max_mapnr = last_valid_pfn; @@ -446,6 +473,22 @@ void free_initmem (void) printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (start < end) + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { + struct page *p = mem_map + MAP_NR(start); + + ClearPageReserved(p); + set_page_count(p, 1); + __free_page(p); + num_physpages++; + } +} +#endif + void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index a1fb222c1..b4d7e5da9 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.101 2000/03/13 05:49:55 jj Exp $ +# $Id: config.in,v 1.104 2000/03/15 15:02:28 jj Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -32,16 +32,6 @@ define_bool CONFIG_SUN_IO y bool 'PCI support' CONFIG_PCI source drivers/pci/Config.in -mainmenu_option next_comment -comment 'Console drivers' -bool 'PROM console' CONFIG_PROM_CONSOLE -bool 'Support Frame buffer devices' CONFIG_FB -source drivers/video/Config.in -endmenu - -source drivers/sbus/char/Config.in -source drivers/sbus/audio/Config.in - tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -78,7 +68,17 @@ fi endmenu mainmenu_option next_comment -comment 'Floppy, IDE, and other block devices' +comment 'Console drivers' +bool 'PROM console' CONFIG_PROM_CONSOLE +bool 'Support Frame buffer devices' CONFIG_FB +source drivers/video/Config.in +endmenu + +source drivers/sbus/char/Config.in +source drivers/sbus/audio/Config.in + +mainmenu_option next_comment +comment 'Block devices' bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD @@ -86,8 +86,8 @@ bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED - tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING - tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 +# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING +# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM @@ -98,6 +98,8 @@ fi tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP tristate 'Network block device support' CONFIG_BLK_DEV_NBD +endmenu + if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi @@ -224,6 +226,7 @@ if [ "$CONFIG_NET" = "y" ]; then tristate ' Sun QuadEthernet support' CONFIG_SUNQE if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 + tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX tristate 'RealTek RTL-8139 support' CONFIG_8139TOO tristate 'PCI NE2000 support' CONFIG_NE2K_PCI diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index db85cfe1e..2f1d42a19 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -26,6 +26,42 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y CONFIG_PCI_NAMES=y +CONFIG_SUN_OPENPROMFS=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +CONFIG_SPARC32_COMPAT=y +CONFIG_BINFMT_ELF32=y +# CONFIG_BINFMT_AOUT32 is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +# CONFIG_SUNOS_EMUL is not set +CONFIG_SOLARIS_EMUL=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y +CONFIG_PRINTER=m +CONFIG_ENVCTRL=m + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y # # Console drivers @@ -84,44 +120,9 @@ CONFIG_SPARCAUDIO=y CONFIG_SPARCAUDIO_CS4231=y # CONFIG_SPARCAUDIO_DBRI is not set # CONFIG_SPARCAUDIO_DUMMY is not set -CONFIG_SUN_OPENPROMFS=m -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_KCORE_ELF=y -CONFIG_SPARC32_COMPAT=y -CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_AOUT32 is not set -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=m -# CONFIG_SUNOS_EMUL is not set -CONFIG_SOLARIS_EMUL=m - -# -# Parallel port support -# -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_PARPORT_PC_FIFO=y -# CONFIG_PARPORT_AMIGA is not set -# CONFIG_PARPORT_MFC3 is not set -# CONFIG_PARPORT_ATARI is not set -# CONFIG_PARPORT_SUNBPP is not set -# CONFIG_PARPORT_OTHER is not set -CONFIG_PARPORT_1284=y -CONFIG_PRINTER=m -CONFIG_ENVCTRL=m - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y # -# Floppy, IDE, and other block devices +# Block devices # CONFIG_BLK_DEV_FD=y # CONFIG_BLK_DEV_MD is not set @@ -331,6 +332,7 @@ CONFIG_HAPPYMEAL=y CONFIG_SUNBMAC=m CONFIG_SUNQE=m CONFIG_DE4X5=m +CONFIG_TULIP=m CONFIG_VORTEX=m CONFIG_8139TOO=m CONFIG_NE2K_PCI=m diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 3e95ed9cf..3504533d1 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -33,7 +33,7 @@ #include <asm/pgalloc.h> static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); -static int load_aout32_library(int fd); +static int load_aout32_library(struct file*); static int aout32_core_dump(long signr, struct pt_regs * regs, struct file *file); extern void dump_thread(struct pt_regs *, struct user *); @@ -343,9 +343,8 @@ beyond_if: } /* N.B. Move to .h file and use code in fs/binfmt_aout.c? */ -static int load_aout32_library(int fd) +static int load_aout32_library(struct file *file) { - struct file * file; struct inode * inode; unsigned long bss, start_addr, len; unsigned long error; @@ -353,12 +352,6 @@ static int load_aout32_library(int fd) loff_t offset = 0; struct exec ex; - retval = -EACCES; - file = fget(fd); - if (!file) - goto out; - if (!file->f_op) - goto out_putf; inode = file->f_dentry->d_inode; retval = -ENOEXEC; @@ -367,23 +360,23 @@ static int load_aout32_library(int fd) error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset); set_fs(USER_DS); if (error != sizeof(ex)) - goto out_putf; + goto out; /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { - goto out_putf; + goto out; } if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); - goto out_putf; + goto out; } if (N_FLAGS(ex)) - goto out_putf; + goto out; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ @@ -391,13 +384,15 @@ static int load_aout32_library(int fd) start_addr = ex.a_entry & 0xfffff000; /* Now use mmap to map the library into memory. */ + down(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); + up(¤t->mm->mmap_sem); retval = error; if (error != start_addr) - goto out_putf; + goto out; len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; @@ -405,12 +400,9 @@ static int load_aout32_library(int fd) error = do_brk(start_addr + len, bss - len); retval = error; if (error != start_addr + len) - goto out_putf; + goto out; } retval = 0; - -out_putf: - fput(file); out: return retval; } diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index d3a3814a8..0ba88adf6 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.82 2000/03/13 21:57:27 davem Exp $ +/* $Id: ioctl32.c,v 1.83 2000/03/14 07:31:25 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -8,6 +8,7 @@ * ioctls. */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -44,6 +45,14 @@ #include <linux/raw.h> #include <linux/smb_fs.h> #include <linux/blkpg.h> +#include <linux/blk.h> +#include <linux/elevator.h> +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +/* Ugh. This header really is not clean */ +#define min min +#define max max +#include <linux/lvm.h> +#endif /* LVM */ #include <scsi/scsi.h> /* Ugly hack. */ @@ -1980,6 +1989,353 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) return -EINVAL; } +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +/* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */ +typedef struct { + uint8_t vg_name[NAME_LEN]; + uint32_t vg_number; + uint32_t vg_access; + uint32_t vg_status; + uint32_t lv_max; + uint32_t lv_cur; + uint32_t lv_open; + uint32_t pv_max; + uint32_t pv_cur; + uint32_t pv_act; + uint32_t dummy; + uint32_t vgda; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + uint32_t pvg_total; + u32 proc; + u32 pv[ABS_MAX_PV + 1]; + u32 lv[ABS_MAX_LV + 1]; +} vg32_t; + +typedef struct { + uint8_t id[2]; + uint16_t version; + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_namelist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; + kdev_t pv_dev; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + uint32_t pe_stale; + u32 pe; + u32 inode; +} pv32_t; + +typedef struct { + char lv_name[NAME_LEN]; + u32 lv; +} lv_req32_t; + +typedef struct { + u32 lv_index; + u32 lv; +} lv_status_byindex_req32_t; + +typedef struct { + uint8_t lv_name[NAME_LEN]; + kdev_t old_dev; + kdev_t new_dev; + u32 old_pe; + u32 new_pe; +} le_remap_req32_t; + +typedef struct { + char pv_name[NAME_LEN]; + u32 pv; +} pv_status_req32_t; + +typedef struct { + uint8_t lv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint32_t lv_access; + uint32_t lv_status; + uint32_t lv_open; + kdev_t lv_dev; + uint32_t lv_number; + uint32_t lv_mirror_copies; + uint32_t lv_recovery; + uint32_t lv_schedule; + uint32_t lv_size; + u32 lv_current_pe; + uint32_t lv_current_le; + uint32_t lv_allocated_le; + uint32_t lv_stripes; + uint32_t lv_stripesize; + uint32_t lv_badblock; + uint32_t lv_allocation; + uint32_t lv_io_timeout; + uint32_t lv_read_ahead; + /* delta to version 1 starts here */ + u32 lv_snapshot_org; + u32 lv_snapshot_prev; + u32 lv_snapshot_next; + u32 lv_block_exception; + uint32_t lv_remap_ptr; + uint32_t lv_remap_end; + uint32_t lv_chunk_size; + uint32_t lv_snapshot_minor; + char dummy[200]; +} lv32_t; + +typedef struct { + u32 hash[2]; + u32 rsector_org; + kdev_t rdev_org; + u32 rsector_new; + kdev_t rdev_new; +} lv_block_exception32_t; + +static void put_lv_t(lv_t *l) +{ + if (l->lv_current_pe) vfree(l->lv_current_pe); + if (l->lv_block_exception) vfree(l->lv_block_exception); + kfree(l); +} + +static lv_t *get_lv_t(u32 p, int *errp) +{ + int err, i; + u32 ptr1, ptr2; + size_t size; + lv_block_exception32_t *lbe32; + lv_block_exception_t *lbe; + lv32_t *ul = (lv32_t *)A(p); + lv_t *l = (lv_t *)kmalloc(sizeof(lv_t), GFP_KERNEL); + if (!l) { + *errp = -ENOMEM; + return NULL; + } + memset(l, 0, sizeof(lv_t)); + err = copy_from_user(l, ul, (long)&((lv32_t *)0)->lv_current_pe); + err |= __copy_from_user(&l->lv_current_le, &ul->lv_current_le, + ((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le)); + err |= __copy_from_user(&l->lv_remap_ptr, &ul->lv_remap_ptr, + ((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr)); + err |= __get_user(ptr1, &ul->lv_current_pe); + err |= __get_user(ptr2, &ul->lv_block_exception); + if (err) { + kfree(l); + *errp = -EFAULT; + return NULL; + } + if (ptr1) { + size = l->lv_allocated_le * sizeof(pe_t); + l->lv_current_pe = vmalloc(size); + if (l->lv_current_pe) + err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size); + } + if (!err && ptr2) { + size = l->lv_remap_end * sizeof(lv_block_exception_t); + l->lv_block_exception = lbe = vmalloc(size); + if (l->lv_block_exception) { + lbe32 = (lv_block_exception32_t *)A(ptr2); + memset(lbe, 0, size); + for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) { + err |= get_user(lbe->rsector_org, &lbe32->rsector_org); + err |= __get_user(lbe->rdev_org, &lbe32->rdev_org); + err |= __get_user(lbe->rsector_new, &lbe32->rsector_new); + err |= __get_user(lbe->rdev_new, &lbe32->rdev_new); + } + } + } + if (err || (ptr1 && !l->lv_current_pe) || (ptr2 && !l->lv_block_exception)) { + if (!err) + *errp = -ENOMEM; + else + *errp = -EFAULT; + put_lv_t(l); + return NULL; + } + return l; +} + +static int copy_lv_t(u32 ptr, lv_t *l) +{ + int err; + lv32_t *ul = (lv32_t *)A(ptr); + u32 ptr1; + size_t size; + + err = get_user(ptr1, &ul->lv_current_pe); + if (err) + return -EFAULT; + err = copy_to_user(ul, l, (long)&((lv32_t *)0)->lv_current_pe); + err |= __copy_to_user(&ul->lv_current_le, &l->lv_current_le, + ((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le)); + err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr, + ((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr)); + size = l->lv_allocated_le * sizeof(pe_t); + err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size); + return -EFAULT; +} + +static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + vg_t *v; + union { + lv_req_t lv_req; + le_remap_req_t le_remap; + lv_status_byindex_req_t lv_byindex; + pv_status_req32_t pv_status; + } u; + pv_t p; + int err; + u32 ptr = 0; + int i; + mm_segment_t old_fs; + void *karg = &u; + + switch (cmd) { + case VG_STATUS: + v = kmalloc(sizeof(vg_t), GFP_KERNEL); + if (!v) return -ENOMEM; + karg = v; + break; + case VG_CREATE: + v = kmalloc(sizeof(vg_t), GFP_KERNEL); + if (!v) return -ENOMEM; + if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) || + __get_user(v->proc, &((vg32_t *)arg)->proc)) { + kfree(v); + return -EFAULT; + } + karg = v; + memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv)); + if (v->pv_max > ABS_MAX_PV || v->lv_max == ABS_MAX_LV) return -EPERM; + for (i = 0; i < v->pv_max; i++) { + err = __get_user(ptr, &((vg32_t *)arg)->pv[i]); + if (err) break; + if (ptr) { + v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL); + if (!v->pv[i]) { + err = -ENOMEM; + break; + } + err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8); + if (err) { + err = -EFAULT; + break; + } + v->pv[i]->pe = NULL; v->pv[i]->inode = NULL; + } + } + if (!err) { + for (i = 0; i < v->lv_max; i++) { + err = __get_user(ptr, &((vg32_t *)arg)->lv[i]); + if (err) break; + if (ptr) { + v->lv[i] = get_lv_t(ptr, &err); + if (err) break; + } + } + } + break; + case LV_CREATE: + case LV_EXTEND: + case LV_REDUCE: + case LV_REMOVE: + case LV_STATUS_BYNAME: + err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); + if (err) return -EFAULT; + if (cmd != LV_REMOVE) { + err = __get_user(ptr, &((lv_req32_t *)arg)->lv); + if (err) return err; + u.lv_req.lv = get_lv_t(ptr, &err); + } else + u.lv_req.lv = NULL; + break; + case LV_STATUS_BYINDEX: + err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index); + err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv); + if (err) return err; + u.lv_byindex.lv = get_lv_t(ptr, &err); + break; + case VG_EXTEND: + err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8); + if (err) return -EFAULT; + p.pe = NULL; p.inode = NULL; + karg = &p; + break; + case LE_REMAP: + err = copy_from_user(&u.le_remap, (void *)arg, sizeof(le_remap_req32_t)); + if (err) return -EFAULT; + u.le_remap.new_pe = ((le_remap_req32_t *)&u.le_remap)->new_pe; + u.le_remap.old_pe = ((le_remap_req32_t *)&u.le_remap)->old_pe; + break; + case PV_CHANGE: + case PV_STATUS: + err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name)); + if (err) return -EFAULT; + err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv); + if (err) return err; + u.pv_status.pv = &p; + if (cmd == PV_CHANGE) { + err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8); + if (err) return -EFAULT; + p.pe = NULL; p.inode = NULL; + } + break; + } + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)karg); + set_fs (old_fs); + switch (cmd) { + case VG_STATUS: + if (!err) { + if (copy_to_user((void *)arg, v, (long)&((vg32_t *)0)->proc) || + clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc)) + err = -EFAULT; + } + kfree(v); + break; + case VG_CREATE: + for (i = 0; i < v->pv_max; i++) + if (v->pv[i]) kfree(v->pv[i]); + for (i = 0; i < v->lv_max; i++) + if (v->lv[i]) put_lv_t(v->lv[i]); + kfree(v); + break; + case LV_STATUS_BYNAME: + if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv); + /* Fall through */ + case LV_CREATE: + case LV_EXTEND: + case LV_REDUCE: + if (u.lv_req.lv) put_lv_t(u.lv_req.lv); + break; + case LV_STATUS_BYINDEX: + if (u.lv_byindex.lv) { + if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv); + put_lv_t(u.lv_byindex.lv); + } + case PV_STATUS: + if (!err) { + err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8); + if (err) return -EFAULT; + } + break; + } + return err; +} +#endif + static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) { return -EINVAL; @@ -2027,6 +2383,39 @@ static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioc return err; } +typedef struct blkelv_ioctl32_arg_s { + u32 queue_ID; + int read_latency; + int write_latency; + int max_bomb_segments; +} blkelv_ioctl32_arg_t; + +static int do_blkelv_ioctl(unsigned int fd, unsigned int cmd, blkelv_ioctl32_arg_t *arg) +{ + blkelv_ioctl_arg_t b; + int err; + mm_segment_t old_fs = get_fs(); + + if (cmd == BLKELVSET) { + err = get_user((long)b.queue_ID, &arg->queue_ID); + err |= __get_user(b.read_latency, &arg->read_latency); + err |= __get_user(b.write_latency, &arg->write_latency); + err |= __get_user(b.max_bomb_segments, &arg->max_bomb_segments); + if (err) return err; + } + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&b); + set_fs (old_fs); + if (cmd == BLKELVGET && !err) { + err = put_user((long)b.queue_ID, &arg->queue_ID); + err |= __put_user(b.read_latency, &arg->read_latency); + err |= __put_user(b.write_latency, &arg->write_latency); + err |= __put_user(b.max_bomb_segments, &arg->max_bomb_segments); + if (err) return err; + } + return err; +} + static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) { return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); @@ -2548,6 +2937,24 @@ COMPATIBLE_IOCTL(ATMTCP_CREATE) COMPATIBLE_IOCTL(ATMTCP_REMOVE) COMPATIBLE_IOCTL(ATMMPC_CTRL) COMPATIBLE_IOCTL(ATMMPC_DATA) +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +/* 0xfe - lvm */ +COMPATIBLE_IOCTL(VG_SET_EXTENDABLE) +COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT) +COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST) +COMPATIBLE_IOCTL(VG_REMOVE) +COMPATIBLE_IOCTL(VG_REDUCE) +COMPATIBLE_IOCTL(PE_LOCK_UNLOCK) +COMPATIBLE_IOCTL(PV_FLUSH) +COMPATIBLE_IOCTL(LVM_LOCK_LVM) +COMPATIBLE_IOCTL(LVM_GET_IOP_VERSION) +#ifdef LVM_TOTAL_RESET +COMPATIBLE_IOCTL(LVM_RESET) +#endif +COMPATIBLE_IOCTL(LV_SET_ACCESS) +COMPATIBLE_IOCTL(LV_SET_STATUS) +COMPATIBLE_IOCTL(LV_SET_ALLOCATION) +#endif /* LVM */ /* And these ioctls need translation */ HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) @@ -2594,6 +3001,8 @@ HANDLE_IOCTL(0x1260, broken_blkgetsize) HANDLE_IOCTL(BLKFRAGET, w_long) HANDLE_IOCTL(BLKSECTGET, w_long) HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) +HANDLE_IOCTL(BLKELVGET, do_blkelv_ioctl) +HANDLE_IOCTL(BLKELVSET, do_blkelv_ioctl) HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap) HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap) HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor) @@ -2677,6 +3086,20 @@ HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl) +HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl) +HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl) +HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl) +HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl) +HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl) +HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl) +HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl) +HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl) +HANDLE_IOCTL(LE_REMAP, do_lvm_ioctl) +HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl) +HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl) +#endif /* LVM */ IOCTL_TABLE_END unsigned int ioctl32_hash_table[1024]; diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 0d1b968fa..f0c9460fa 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.52 2000/03/03 23:48:41 davem Exp $ +/* $Id: setup.c,v 1.53 2000/03/15 14:42:52 jj Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -431,8 +431,6 @@ extern void panic_setup(char *, int *); extern unsigned short root_flags; extern unsigned short root_dev; extern unsigned short ram_flags; -extern unsigned int sparc_ramdisk_image; -extern unsigned int sparc_ramdisk_size; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 @@ -512,29 +510,6 @@ void __init setup_arch(char **cmdline_p) rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif -#ifdef CONFIG_BLK_DEV_INITRD -// FIXME needs to do the new bootmem alloc stuff - if (sparc_ramdisk_image) { - unsigned long start = 0; - - if (sparc_ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE) - sparc_ramdisk_image -= KERNBASE; - initrd_start = sparc_ramdisk_image + phys_base + PAGE_OFFSET; - initrd_end = initrd_start + sparc_ramdisk_size; - if (initrd_end > *memory_end_p) { - printk(KERN_CRIT "initrd extends beyond end of memory " - "(0x%016lx > 0x%016lx)\ndisabling initrd\n", - initrd_end,*memory_end_p); - initrd_start = 0; - } - if (initrd_start) - start = sparc_ramdisk_image + KERNBASE; - if (start >= *memory_start_p && start < *memory_start_p + 2 * PAGE_SIZE) { - initrd_below_start_ok = 1; - *memory_start_p = PAGE_ALIGN (start + sparc_ramdisk_size); - } - } -#endif /* Due to stack alignment restrictions and assumptions... */ init_mm.mmap->vm_page_prot = PAGE_SHARED; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index b4ee5625e..0d5f615cf 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -528,7 +528,7 @@ static unsigned long penguins_are_doing_time = 0; void smp_capture(void) { if (smp_processors_ready) { - int result = atomic_add_return(1, &smp_capture_depth); + int result = __atomic_add(1, &smp_capture_depth); membar("#StoreStore | #LoadStore"); if(result == 1) { @@ -596,18 +596,21 @@ void smp_promstop_others(void) smp_cross_call(&xcall_promstop, 0, 0, 0); } -static inline void sparc64_do_profile(unsigned long pc, unsigned long g3) +static inline void sparc64_do_profile(unsigned long pc, unsigned long o7) { if (prof_buffer && current->pid) { extern int _stext; extern int rwlock_impl_begin, rwlock_impl_end; extern int atomic_impl_begin, atomic_impl_end; + extern int __memcpy_begin, __memcpy_end; - if ((pc >= (unsigned long) &rwlock_impl_begin && + if ((pc >= (unsigned long) &atomic_impl_begin && + pc < (unsigned long) &atomic_impl_end) || + (pc >= (unsigned long) &rwlock_impl_begin && pc < (unsigned long) &rwlock_impl_end) || - (pc >= (unsigned long) &atomic_impl_begin && - pc < (unsigned long) &atomic_impl_end)) - pc = g3; + (pc >= (unsigned long) &__memcpy_begin && + pc < (unsigned long) &__memcpy_end)) + pc = o7; pc -= (unsigned long) &_stext; pc >>= prof_shift; @@ -646,7 +649,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) clear_softint((1UL << 0)); do { if(!user) - sparc64_do_profile(regs->tpc, regs->u_regs[UREG_G3]); + sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]); if(!--prof_counter(cpu)) { if (cpu == boot_cpu_id) { diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index f798358ce..26e11085d 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.75 2000/02/21 15:50:08 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.79 2000/03/17 14:41:18 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -109,10 +109,10 @@ extern unsigned long phys_base; */ #define EXPORT_SYMBOL_PRIVATE(sym) \ -extern int __sparc_priv_ ## sym (int) __asm__("__" ## #sym); \ +extern int __sparc_priv_ ## sym (int) __asm__("__" #sym); \ const struct module_symbol __export_priv_##sym \ __attribute__((section("__ksymtab"))) = \ -{ (unsigned long) &__sparc_priv_ ## sym, "__" ## #sym } +{ (unsigned long) &__sparc_priv_ ## sym, "__" #sym } /* used by various drivers */ #ifdef __SMP__ @@ -142,6 +142,8 @@ EXPORT_SYMBOL(cpu_data); /* Misc SMP information */ EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(__cpu_number_map); +EXPORT_SYMBOL(__cpu_logical_map); /* Spinlock debugging library, optional. */ #ifdef SPIN_LOCK_DEBUG @@ -207,6 +209,7 @@ EXPORT_SYMBOL(pci_map_sg); EXPORT_SYMBOL(pci_unmap_sg); EXPORT_SYMBOL(pci_dma_sync_single); EXPORT_SYMBOL(pci_dma_sync_sg); +EXPORT_SYMBOL(pci_dma_supported); #endif /* Solaris/SunOS binary compatibility */ @@ -288,6 +291,9 @@ EXPORT_SYMBOL(move_addr_to_user); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(clear_page); +EXPORT_SYMBOL(copy_page); +EXPORT_SYMBOL(clear_user_page); +EXPORT_SYMBOL(copy_user_page); EXPORT_SYMBOL(__bzero); EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 81b4c4de1..82aedbb08 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.36 2000/02/16 07:31:35 davem Exp $ +/* $Id: sys_sparc.c,v 1.37 2000/03/17 05:48:46 anton Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -348,9 +348,10 @@ asmlinkage int solaris_syscall(struct pt_regs *regs) lock_kernel(); regs->tpc = regs->tnpc; regs->tnpc += 4; - if(++count <= 20) + if(++count <= 5) { printk ("For Solaris binary emulation you need solaris module loaded\n"); - show_regs (regs); + show_regs (regs); + } send_sig(SIGSEGV, current, 1); unlock_kernel(); return -ENOSYS; diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index d4ecb0f4f..763acdc0f 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.136 2000/03/13 21:57:29 davem Exp $ +/* $Id: sys_sparc32.c,v 1.139 2000/03/16 20:37:57 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1746,70 +1746,58 @@ static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) return 0; } -extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void *data); +extern long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page, + unsigned long new_flags, unsigned long data_page); #define SMBFS_NAME "smbfs" #define NCPFS_NAME "ncpfs" asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data) { - unsigned long type_page; + unsigned long type_page = 0; + unsigned long data_page = 0; int err, is_smb, is_ncp; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; is_smb = is_ncp = 0; + + lock_kernel(); err = copy_mount_stuff_to_kernel((const void *)type, &type_page); - if(err) - return err; - if(type_page) { - is_smb = !strcmp((char *)type_page, SMBFS_NAME); - is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + if (err) + goto out; + + if (!type_page) { + err = -EINVAL; + goto out; } - if(!is_smb && !is_ncp) { - if(type_page) - free_page(type_page); - return sys_mount(dev_name, dir_name, type, new_flags, (void *)AA(data)); - } else { - unsigned long dev_page, dir_page, data_page; - mm_segment_t old_fs; - err = copy_mount_stuff_to_kernel((const void *)dev_name, &dev_page); - if(err) - goto out; - err = copy_mount_stuff_to_kernel((const void *)dir_name, &dir_page); - if(err) - goto dev_out; - err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page); - if(err) - goto dir_out; - if(is_ncp) + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + + err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page); + if (err) + goto type_out; + + if (!is_smb && !is_ncp) { + err = do_sys_mount(dev_name, dir_name, type_page, new_flags, + data_page); + } else { + if (is_ncp) do_ncp_super_data_conv((void *)data_page); - else if(is_smb) - do_smb_super_data_conv((void *)data_page); else - panic("The problem is here..."); - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_mount((char *)dev_page, (char *)dir_page, - (char *)type_page, new_flags, - (void *)data_page); - set_fs(old_fs); + do_smb_super_data_conv((void *)data_page); - if(data_page) - free_page(data_page); - dir_out: - if(dir_page) - free_page(dir_page); - dev_out: - if(dev_page) - free_page(dev_page); - out: - if(type_page) - free_page(type_page); - return err; + err = do_sys_mount(dev_name, dir_name, type_page, new_flags, + data_page); } + + free_page(data_page); + +type_out: + free_page(type_page); + +out: + unlock_kernel(); + return err; } struct rusage32 { @@ -3071,7 +3059,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0])); lock_kernel(); - dentry = open_namei(filename, 0, 0); + dentry = open_namei(filename); unlock_kernel(); retval = PTR_ERR(dentry); @@ -4166,7 +4154,7 @@ asmlinkage long sparc32_open(const char * filename, int flags, int mode) if (fd >= 0) { struct file * f; lock_kernel(); - f = filp_open(tmp, flags, mode); + f = filp_open(tmp, flags, mode, NULL); unlock_kernel(); error = PTR_ERR(f); if (IS_ERR(f)) @@ -4218,12 +4206,3 @@ out_sem: out: return ret; } - -extern asmlinkage long sys_mincore(unsigned long start, size_t len, unsigned char *vec); - -asmlinkage long sys32_mincore(unsigned long start, u32 __len, unsigned char *vec) -{ - size_t len = (size_t) __len; - - return sys_mincore(start, len, vec); -} diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index f7f5964e9..a572e4976 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.41 2000/03/13 21:57:31 davem Exp $ +/* $Id: sys_sunos32.c,v 1.42 2000/03/15 02:43:35 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -225,33 +225,6 @@ asmlinkage void sunos_vadvise(u32 strategy) unlock_kernel(); } -/* Same as vadvise, and just as bogus, but for a range of virtual - * process address space. - */ -#define MADV_NORMAL 0 /* Nothing special... */ -#define MADV_RANDOM 1 /* I am emacs... */ -#define MADV_SEQUENTIAL 2 /* I am researcher code... */ -#define MADV_WILLNEED 3 /* Pages in this range will be needed */ -#define MADV_DONTNEED 4 /* Pages in this range won't be needed */ - -static char *mstrings[] = { - "MADV_NORMAL", - "MADV_RANDOM", - "MADV_SEQUENTIAL", - "MADV_WILLNEED", - "MADV_DONTNEED", -}; - -asmlinkage void sunos_madvise(u32 address, u32 len, u32 strategy) -{ - /* I wanna see who uses this... */ - lock_kernel(); - printk("%s: Advises us to use %s paging strategy for addr<%08x> len<%08x>\n", - current->comm, strategy <= 4 ? mstrings[strategy] : "BOGUS", - address, len); - unlock_kernel(); -} - /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE * resource limit and is for backwards compatibility with older sunos * revs. diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 0a0edbf82..d86649bf7 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.69 2000/03/13 21:57:28 davem Exp $ +/* $Id: systbls.S,v 1.71 2000/03/15 02:43:36 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -34,7 +34,7 @@ sys_call_table32: /*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_fstat64, sys_getpagesize .word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_geteuid /*70*/ .word sys_getegid, sys32_mmap, sys_setreuid, sys_munmap, sys_mprotect - .word sys_nis_syscall, sys_vhangup, sys32_truncate64, sys32_mincore, sys32_getgroups16 + .word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16 /*80*/ .word sys32_setgroups16, sys_getpgrp, sys_setgroups, sys32_setitimer, sys32_ftruncate64 .word sys_swapon, sys32_getitimer, sys_setuid, sys_sethostname, sys_setgid /*90*/ .word sys_dup2, sys_setfsuid, sys32_fcntl, sys32_select, sys_setfsgid @@ -93,7 +93,7 @@ sys_call_table: /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize .word sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys64_munmap, sys_mprotect - .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_mincore, sys_getgroups + .word sys_madvise, sys_vhangup, sys_nis_syscall, sys_mincore, sys_getgroups /*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall /*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall @@ -163,8 +163,8 @@ sunos_sys_table: .word sys_msync, sys_vfork, sunos_nosys .word sunos_nosys, sunos_sbrk, sunos_sstk .word sunos_mmap, sunos_vadvise, sys_munmap - .word sys_mprotect, sunos_madvise, sys_vhangup - .word sunos_nosys, sys32_mincore, sys32_getgroups16 + .word sys_mprotect, sys_madvise, sys_vhangup + .word sunos_nosys, sys_mincore, sys32_getgroups16 .word sys32_setgroups16, sys_getpgrp, sunos_setpgrp .word sys32_setitimer, sunos_nosys, sys_swapon .word sys32_getitimer, sys_gethostname, sys_sethostname diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 792334336..989e965a9 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.18 1999/08/02 08:39:44 davem Exp $ +/* $Id: unaligned.c,v 1.19 2000/03/16 11:53:05 jj Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -590,9 +590,19 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs) maybe_flush_windows(0, 0, rd, from_kernel); reg = fetch_reg_addr(rd, regs); - if ((insn & 0x780000) == 0x180000) - reg[1] = 0; - reg[0] = 0; + if (from_kernel || rd < 16) { + reg[0] = 0; + if ((insn & 0x780000) == 0x180000) + reg[1] = 0; + } else if (current->thread.flags & SPARC_FLAG_32BIT) { + put_user(0, (int *)reg); + if ((insn & 0x780000) == 0x180000) + put_user(0, ((int *)reg) + 1); + } else { + put_user(0, reg); + if ((insn & 0x780000) == 0x180000) + put_user(0, reg + 1); + } advance(regs); } diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S index 57cf6b0f1..e20118648 100644 --- a/arch/sparc64/lib/VIScopy.S +++ b/arch/sparc64/lib/VIScopy.S @@ -1,4 +1,4 @@ -/* $Id: VIScopy.S,v 1.21 1999/07/30 09:35:35 davem Exp $ +/* $Id: VIScopy.S,v 1.22 2000/03/16 16:44:38 davem Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * @@ -304,6 +304,9 @@ .type bcopy,@function #ifdef __KERNEL__ + .globl __memcpy_begin +__memcpy_begin: + .globl __memcpy .type __memcpy,@function @@ -1001,6 +1004,9 @@ fpu_retl: FPU_RETL #ifdef __KERNEL__ + .globl __memcpy_end +__memcpy_end: + .section .fixup .align 4 VIScopyfixup_reto2: diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S index cac9d15dd..35a34ebbf 100644 --- a/arch/sparc64/lib/atomic.S +++ b/arch/sparc64/lib/atomic.S @@ -1,4 +1,4 @@ -/* $Id: atomic.S,v 1.2 1999/08/23 05:15:58 davem Exp $ +/* $Id: atomic.S,v 1.3 2000/03/16 16:44:37 davem Exp $ * atomic.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -13,24 +13,24 @@ .globl __atomic_add atomic_impl_begin: -__atomic_add: - lduw [%g1], %g5 - add %g5, %g2, %g7 - cas [%g1], %g5, %g7 +__atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ + lduw [%o1], %g5 + add %g5, %o0, %g7 + cas [%o1], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __atomic_add nop - jmpl %g3 + 8, %g0 - add %g7, %g2, %g2 + retl + add %g7, %o0, %o0 .globl __atomic_sub -__atomic_sub: - lduw [%g1], %g5 - sub %g5, %g2, %g7 - cas [%g1], %g5, %g7 +__atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */ + lduw [%o1], %g5 + sub %g5, %o0, %g7 + cas [%o1], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __atomic_sub nop - jmpl %g3 + 8, %g0 - sub %g7, %g2, %g2 + retl + sub %g7, %o0, %o0 atomic_impl_end: diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index 1cdbf09da..b4a91b97c 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,8 +1,8 @@ -/* $Id: blockops.S,v 1.20 2000/03/03 23:48:38 davem Exp $ +/* $Id: blockops.S,v 1.22 2000/03/15 07:18:55 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * - * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1997 Jakub Jelinek (jakub@redhat.com) */ #include "VIS.h" @@ -24,23 +24,63 @@ #define TLBTEMP_ENTSZ (1 << 3) .text + .align 32 .globl copy_page .type copy_page,@function copy_page: /* %o0=dest, %o1=src */ VISEntry - ldx [%g6 + AOFF_task_active_mm], %o2 + membar #LoadStore | #StoreStore | #StoreLoad + ldda [%o1] ASI_BLK_P, %f0 + add %o1, 0x40, %o1 + ldda [%o1] ASI_BLK_P, %f16 + add %o1, 0x40, %o1 + sethi %hi(8192), %o2 +1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14) + ldda [%o1] ASI_BLK_P, %f32 + add %o1, 0x40, %o1 + sub %o2, 0x40, %o2 + stda %f48, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + TOUCH(f16, f18, f20, f22, f24, f26, f28, f30) + ldda [%o1] ASI_BLK_P, %f0 + add %o1, 0x40, %o1 + sub %o2, 0x40, %o2 + stda %f48, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + TOUCH(f32, f34, f36, f38, f40, f42, f44, f46) + ldda [%o1] ASI_BLK_P, %f16 + add %o1, 0x40, %o1 + sub %o2, 0x40, %o2 + stda %f48, [%o0] ASI_BLK_P + cmp %o2, 0x80 + bne,pt %xcc, 1b + add %o0, 0x40, %o0 + membar #Sync + stda %f0, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + stda %f16, [%o0] ASI_BLK_P + membar #Sync + VISExit + retl + nop + + .globl copy_user_page + .type copy_user_page,@function +copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ + VISEntry + sethi %hi(PAGE_SIZE), %g3 sub %o0, %g4, %g1 + and %o2, %g3, %o0 + sethi %hi(TLBTEMP_BASE), %o3 sethi %uhi(_PAGE_VALID), %g3 sub %o1, %g4, %g2 sllx %g3, 32, %g3 - ldx [%o2 + AOFF_mm_segments], %o0 + mov TLB_TAG_ACCESS, %o2 or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 + sethi %hi(DCACHE_SIZE), %o1 or %g1, %g3, %g1 or %g2, %g3, %g2 - mov TLB_TAG_ACCESS, %o2 - sethi %hi(TLBTEMP_BASE), %o3 - sethi %hi(DCACHE_SIZE), %o1 add %o0, %o3, %o0 add %o0, %o1, %o1 sethi %hi(TLBTEMP_ENT1), %o3 @@ -129,17 +169,25 @@ copy_page: /* %o0=dest, %o1=src */ .align 32 .globl clear_page .type clear_page,@function -clear_page: /* %o0=dest */ +clear_page: /* %o0=dest */ VISEntryHalf - ldx [%g6 + AOFF_task_active_mm], %o2 + ba,pt %xcc, clear_page_common + clr %o4 + + .align 32 + .globl clear_user_page + .type clear_user_page,@function +clear_user_page: /* %o0=dest, %o1=vaddr */ + VISEntryHalf + sethi %hi(PAGE_SIZE), %g3 sub %o0, %g4, %g1 + and %o1, %g3, %o0 + mov TLB_TAG_ACCESS, %o2 sethi %uhi(_PAGE_VALID), %g3 + sethi %hi(TLBTEMP_BASE), %o3 sllx %g3, 32, %g3 or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 - ldx [%o2 + AOFF_mm_segments], %o0 or %g1, %g3, %g1 - mov TLB_TAG_ACCESS, %o2 - sethi %hi(TLBTEMP_BASE), %o3 add %o0, %o3, %o0 sethi %hi(TLBTEMP_ENT2), %o3 rdpr %pstate, %g3 @@ -162,6 +210,9 @@ clear_page: /* %o0=dest */ stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS membar #Sync + mov 1, %o4 + +clear_page_common: fzero %f0 ! FPA Group mov 32, %o1 ! IEU0 fzero %f2 ! FPA Group @@ -187,7 +238,13 @@ clear_page: /* %o0=dest */ membar #Sync ! LSU Group VISExitHalf - stxa %g5, [%o2] ASI_DMMU + brnz,pt %o4, 1f + nop + + retl + nop + +1: stxa %g5, [%o2] ASI_DMMU stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS membar #Sync jmpl %o7 + 0x8, %g0 diff --git a/arch/sparc64/lib/rwlock.S b/arch/sparc64/lib/rwlock.S index 74360bf68..03f3bfe59 100644 --- a/arch/sparc64/lib/rwlock.S +++ b/arch/sparc64/lib/rwlock.S @@ -1,4 +1,4 @@ -/* $Id: rwlock.S,v 1.2 1999/08/23 05:15:58 davem Exp $ +/* $Id: rwlock.S,v 1.3 2000/03/16 16:44:38 davem Exp $ * rwlocks.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -12,34 +12,33 @@ /* The non-contention read lock usage is 2 cache lines. */ .globl __read_lock, __read_unlock - /* g1=lock, g3=retpc, g5/g7=scratch */ rwlock_impl_begin: -__read_lock: - ldsw [%g1], %g5 +__read_lock: /* %o0 = lock_ptr */ + ldsw [%o0], %g5 brlz,pn %g5, __read_wait_for_writer 4: add %g5, 1, %g7 - cas [%g1], %g5, %g7 + cas [%o0], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __read_lock membar #StoreLoad | #StoreStore -99: jmpl %g3 + 8, %g0 +99: retl nop -__read_unlock: - lduw [%g1], %g5 +__read_unlock: /* %o0 = lock_ptr */ + lduw [%o0], %g5 sub %g5, 1, %g7 - cas [%g1], %g5, %g7 + cas [%o0], %g5, %g7 cmp %g5, %g7 be,pt %xcc, 99b membar #StoreLoad | #StoreStore b,a,pt %xcc, __read_unlock __read_wait_for_writer: - ldsw [%g1], %g5 + ldsw [%o0], %g5 brlz,pt %g5, __read_wait_for_writer membar #LoadLoad b,a,pt %xcc, 4b __write_wait_for_writer: - ldsw [%g1], %g5 + ldsw [%o0], %g5 brlz,pt %g5, __write_wait_for_writer membar #LoadLoad b,a,pt %xcc, 4f @@ -48,24 +47,23 @@ __write_wait_for_writer: .align 64 .globl __write_unlock - /* g1=lock, g3=retpc, g2/g5/g7=scratch */ -__write_unlock: +__write_unlock: /* %o0 = lock_ptr */ sethi %hi(0x80000000), %g2 -1: lduw [%g1], %g5 +1: lduw [%o0], %g5 andn %g5, %g2, %g7 - cas [%g1], %g5, %g7 + cas [%o0], %g5, %g7 cmp %g5, %g7 be,pt %icc, 99b membar #StoreLoad | #StoreStore b,a,pt %xcc, 1b .globl __write_lock -__write_lock: +__write_lock: /* %o0 = lock_ptr */ sethi %hi(0x80000000), %g2 -1: ldsw [%g1], %g5 +1: ldsw [%o0], %g5 4: brnz,pn %g5, 5f or %g5, %g2, %g7 - cas [%g1], %g5, %g7 + cas [%o0], %g5, %g7 cmp %g5, %g7 be,pt %icc, 99b membar #StoreLoad | #StoreStore @@ -73,10 +71,10 @@ __write_lock: b,a,pt %xcc, 1b 5: brlz %g5, __write_wait_for_writer or %g5, %g2, %g7 - cas [%g1], %g5, %g7 + cas [%o0], %g5, %g7 cmp %g5, %g7 bne,pn %icc, 5b -8: ldsw [%g1], %g5 +8: ldsw [%o0], %g5 cmp %g5, %g2 be,pn %icc, 99b membar #LoadLoad diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 226246980..6063d002e 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.42 2000/01/21 11:39:13 jj Exp $ +/* $Id: fault.c,v 1.43 2000/03/14 03:59:46 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -245,7 +245,7 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - current->mm->segments = (void *) (address & PAGE_SIZE); + { int fault = handle_mm_fault(current, vma, address, write); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index d09ac451b..1d2049b5f 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.148 2000/03/07 07:08:31 anton Exp $ +/* $Id: init.c,v 1.149 2000/03/15 14:42:58 jj Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -48,6 +48,10 @@ unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; /* References to section boundaries */ extern char __init_begin, __init_end, _start, _end, etext, edata; +/* Initial ramdisk setup */ +extern unsigned int sparc_ramdisk_image; +extern unsigned int sparc_ramdisk_size; + int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -808,6 +812,7 @@ unsigned long __init bootmem_init(void) { unsigned long bootmap_size, start_pfn, end_pfn; unsigned long end_of_phys_memory = 0UL; + unsigned long bootmap_pfn; int i; /* XXX It is a bit ambiguous here, whether we should @@ -855,15 +860,37 @@ unsigned long __init bootmem_init(void) /* Now shift down to get the real physical page frame number. */ start_pfn >>= PAGE_SHIFT; + + bootmap_pfn = start_pfn; end_pfn = end_of_phys_memory >> PAGE_SHIFT; +#ifdef CONFIG_BLK_DEV_INITRD + /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ + if (sparc_ramdisk_image) { + if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE) + sparc_ramdisk_image -= KERNBASE; + initrd_start = sparc_ramdisk_image + phys_base; + initrd_end = initrd_start + sparc_ramdisk_size; + if (initrd_end > end_of_phys_memory) { + printk(KERN_CRIT "initrd extends beyond end of memory " + "(0x%016lx > 0x%016lx)\ndisabling initrd\n", + initrd_end, end_of_phys_memory); + initrd_start = 0; + } + if (initrd_start) { + if (initrd_start >= (start_pfn << PAGE_SHIFT) && + initrd_start < (start_pfn << PAGE_SHIFT) + 2 * PAGE_SIZE) + bootmap_pfn = PAGE_ALIGN (initrd_end) >> PAGE_SHIFT; + } + } +#endif /* Initialize the boot-time allocator. */ #ifdef DEBUG_BOOTMEM - prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n", - start_pfn, end_pfn); + prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],epfn[%lx])\n", + start_pfn, bootmap_pfn, end_pfn); #endif - bootmap_size = init_bootmem(start_pfn, end_pfn); + bootmap_size = init_bootmem(bootmap_pfn, end_pfn); /* Now register the available physical memory with the * allocator. @@ -878,15 +905,27 @@ unsigned long __init bootmem_init(void) sp_banks[i].num_bytes); } - /* Reserve the kernel text/data/bss and the bootmem bitmap. */ + /* Reserve the kernel text/data/bss, the bootmem bootmap and initrd. */ #ifdef DEBUG_BOOTMEM +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + initrd_start, initrd_end - initrd_start); +#endif + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + phys_base, (start_pfn << PAGE_SHIFT) - phys_base); prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - phys_base, - (((start_pfn << PAGE_SHIFT) + - bootmap_size) - phys_base)); + (bootmap_pfn << PAGE_SHIFT), bootmap_size); +#endif +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + reserve_bootmem(initrd_start, initrd_end - initrd_start); + initrd_start += PAGE_OFFSET; + initrd_end += PAGE_OFFSET; + } #endif - reserve_bootmem(phys_base, (((start_pfn << PAGE_SHIFT) + - bootmap_size) - phys_base)); + reserve_bootmem(phys_base, (start_pfn << PAGE_SHIFT) - phys_base); + reserve_bootmem((bootmap_pfn << PAGE_SHIFT), bootmap_size); #ifdef DEBUG_BOOTMEM prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn); @@ -1234,11 +1273,6 @@ void __init mem_init(void) ((unsigned long) &empty_zero_page); last += PAGE_OFFSET + phys_base; while (addr < last) { -#ifdef CONFIG_BLK_DEV_INITRD -// FIXME to use bootmem scheme... - if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) - mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved); -#endif set_bit(__pa(addr) >> 22, sparc64_valid_addr_bitmap); addr += PAGE_SIZE; } @@ -1319,6 +1353,22 @@ void free_initmem (void) } } +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (start < end) + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { + struct page *p = mem_map + MAP_NR(start); + + ClearPageReserved(p); + set_page_count(p, 1); + __free_page(p); + num_physpages++; + } +} +#endif + void si_meminfo(struct sysinfo *val) { val->totalram = num_physpages; |