From 980c3cbbda53c695479023e74620fdb06ebb6cf9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:21:28 -0500 Subject: [PATCH] Linux 2.2.16 The following security problems are fixed by this release o Setuid applications. even when correctly checking for failures of setuid() calls could fail to drop priviledges if the invoker had made certain adjustments to the capability sets o Opening a socket and issuing multiple connects on it could be used to hang the box o Readv/writev might misbehave on some very large inputs o Potentially remote exploitable hole in the sunrpc code o User causable oopses in Appletalk and Socket code o Obscure exploitable bugs in the Sparc kernel The full list of enhancements and other bug fixes will follow later. Recommendations: You should consider updating your 2.2 kernel to 2.2.16 if o You have untrusted users on your system o You have publically accessible kernel sunrpc services Other major bug fixes include o The tcp retransmit crash on very high load o Poor VM performance under some load patterns o Fix for 3com 3c590 8K card stalls --- MAINTAINERS | 4 +- Makefile | 2 +- arch/alpha/boot/bootp.c | 3 +- arch/alpha/boot/main.c | 13 ++- arch/alpha/kernel/bios32.c | 141 ++++++++++++++++++++++++------ arch/alpha/kernel/core_irongate.c | 2 +- arch/alpha/kernel/core_mcpcia.c | 60 +++++++++++++ arch/alpha/kernel/irq.c | 7 ++ arch/alpha/kernel/proto.h | 5 ++ arch/alpha/kernel/setup.c | 118 +++++++++++++++++++++---- arch/alpha/kernel/sys_dp264.c | 7 +- arch/alpha/kernel/sys_mikasa.c | 21 +++-- arch/alpha/kernel/sys_nautilus.c | 9 +- arch/alpha/kernel/time.c | 28 ++++-- arch/alpha/kernel/traps.c | 2 +- arch/alpha/lib/Makefile | 7 +- arch/alpha/lib/callback_init.c | 83 ++++++++++++++++++ arch/alpha/lib/callback_srm.S | 102 +++++++++++++++++++++ arch/alpha/lib/copy_user.S | 2 +- arch/alpha/lib/srm_dispatch.S | 43 --------- arch/alpha/lib/srm_fixup.S | 42 --------- arch/alpha/lib/srm_printk.c | 27 +++++- arch/alpha/lib/srm_puts.c | 35 +++----- arch/alpha/mm/extable.c | 39 ++++++++- arch/alpha/mm/fault.c | 6 +- arch/alpha/mm/init.c | 74 ++++++++-------- arch/alpha/vmlinux.lds | 3 +- drivers/block/ide.c | 1 + drivers/i2o/i2o_block.c | 2 +- drivers/i2o/i2o_config.c | 20 +++-- drivers/i2o/i2o_core.c | 110 +++++++++++------------ drivers/net/dgrs.c | 8 +- drivers/net/via-rhine.c | 4 +- fs/ncpfs/dir.c | 8 +- fs/ncpfs/inode.c | 6 +- fs/ufs/inode.c | 1 + include/asm-alpha/console.h | 23 ++++- include/asm-alpha/core_tsunami.h | 1 + include/asm-alpha/hwrpb.h | 2 + include/asm-alpha/pgtable.h | 4 +- include/asm-alpha/system.h | 3 + include/asm-alpha/uaccess.h | 2 +- 42 files changed, 752 insertions(+), 328 deletions(-) create mode 100644 arch/alpha/lib/callback_init.c create mode 100644 arch/alpha/lib/callback_srm.S delete mode 100644 arch/alpha/lib/srm_dispatch.S delete mode 100644 arch/alpha/lib/srm_fixup.S diff --git a/MAINTAINERS b/MAINTAINERS index 8bad2b8ff8f3..b03d881b69fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -257,7 +257,7 @@ S: Maintained DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson -M: rick@dgii.com +M: rick@remotepoint.com L: linux-net@vger.rutgers.edu W: http://www.dgii.com/linux/ S: Maintained @@ -414,7 +414,7 @@ S: Supported IDE DRIVER [GENERAL] P: Andre Hedrick -M: hedrick@astro.dyer.vanderbilt.edu +M: andre@linux-ide.org L: linux-kernel@vger.rutgers.edu S: Maintained diff --git a/Makefile b/Makefile index 88db2995999f..a4dc55a42b33 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 16 -EXTRAVERSION = pre8 +EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c index 90fccb766cba..480d10995f8b 100644 --- a/arch/alpha/boot/bootp.c +++ b/arch/alpha/boot/bootp.c @@ -171,8 +171,7 @@ start_kernel(void) srm_printk("Initrd positioned at %#lx\n", initrd_start); #endif - nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envval, sizeof(envval)); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0 || nbytes >= sizeof(envval)) { nbytes = 0; } diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c index c97896e8bef5..86254172fb5e 100644 --- a/arch/alpha/boot/main.c +++ b/arch/alpha/boot/main.c @@ -107,15 +107,15 @@ static inline long openboot(void) char bootdev[256]; long result; - result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255); + result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255); if (result < 0) return result; - return srm_dispatch(CCB_OPEN, bootdev, result & 255); + return callback_open(bootdev, result & 255); } static inline long close(long dev) { - return srm_dispatch(CCB_CLOSE, dev); + return callback_close(dev); } static inline long load(long dev, unsigned long addr, unsigned long count) @@ -124,7 +124,7 @@ static inline long load(long dev, unsigned long addr, unsigned long count) extern char _end; long result, boot_size = &_end - (char *) BOOT_ADDR; - result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); + result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255); if (result < 0) return result; result &= 255; @@ -132,7 +132,7 @@ static inline long load(long dev, unsigned long addr, unsigned long count) if (result) srm_printk("Boot file specification (%s) not implemented\n", bootfile); - return srm_dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1); + return callback_read(dev, count, addr, boot_size/512 + 1); } /* @@ -176,8 +176,7 @@ void start_kernel(void) return; } - nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envval, sizeof(envval)); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0) { nbytes = 0; } diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 42d6aef3f017..adc7dcfa377e 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -327,6 +327,28 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) */ #define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) +static short __inline__ +__disable_dev(struct pci_dev *dev) +{ + unsigned short cmd, orig_cmd; + + pcibios_read_config_word(dev->bus->number, dev->devfn, + PCI_COMMAND, &cmd); + + orig_cmd = cmd; + cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); + + pcibios_write_config_word(dev->bus->number, dev->devfn, + PCI_COMMAND, cmd); + return orig_cmd; +} + +static void __inline__ +__enable_dev(struct pci_dev *dev, short orig_cmd) +{ + pcibios_write_config_word(dev->bus->number, dev->devfn, + PCI_COMMAND, orig_cmd); +} /* * The following structure records initial configuration of devices @@ -344,6 +366,7 @@ struct srm_io_reset { struct srm_io_reset *next; struct pci_dev *dev; u32 io; + short cmd; u8 reg; } *srm_io_resets; @@ -354,6 +377,7 @@ reset_for_srm(void) { struct srm_irq_reset *qreset; struct srm_io_reset *ireset; + struct pci_dev *last_dev; /* Reset any IRQs that we changed. */ for (qreset = srm_irq_resets; qreset ; qreset = qreset->next) { @@ -370,6 +394,15 @@ reset_for_srm(void) #endif } + /* Disable any devices which had IO addresses that we changed. */ + last_dev = NULL; + for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { + if (ireset->dev != last_dev) { + ireset->cmd = __disable_dev(ireset->dev); + last_dev = ireset->dev; + } + } + /* Reset any IO addresses that we changed. */ for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { pcibios_write_config_dword(ireset->dev->bus->number, @@ -383,31 +416,40 @@ reset_for_srm(void) ireset->io); #endif } + + /* Re-enable any devices which had IO addresses that we changed. */ + last_dev = NULL; + for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { + if (ireset->dev != last_dev) { + __enable_dev(ireset->dev, ireset->cmd); + last_dev = ireset->dev; + } + } } static void new_irq_reset(struct pci_dev *dev, u8 irq) { - struct srm_irq_reset *n; - n = kmalloc(sizeof(*n), GFP_KERNEL); + struct srm_irq_reset *new; + new = kmalloc(sizeof(*new), GFP_KERNEL); - n->next = srm_irq_resets; - n->dev = dev; - n->irq = irq; - srm_irq_resets = n; + new->next = srm_irq_resets; + new->dev = dev; + new->irq = irq; + srm_irq_resets = new; } static void new_io_reset(struct pci_dev *dev, u8 reg, u32 io) { - struct srm_io_reset *n; - n = kmalloc(sizeof(*n), GFP_KERNEL); - - n->next = srm_io_resets; - n->dev = dev; - n->reg = reg; - n->io = io; - srm_io_resets = n; + struct srm_io_reset *new; + new = kmalloc(sizeof(*new), GFP_KERNEL); + + new->next = srm_io_resets; + new->dev = dev; + new->reg = reg; + new->io = io; + srm_io_resets = new; } @@ -418,9 +460,6 @@ new_io_reset(struct pci_dev *dev, u8 reg, u32 io) static void __init disable_dev(struct pci_dev *dev) { - struct pci_bus *bus; - unsigned short cmd; - /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -442,10 +481,11 @@ disable_dev(struct pci_dev *dev) /* * We don't have code that will init the CYPRESS bridge correctly * so we do the next best thing, and depend on the previous - * console code to do the right thing, and ignore it here... :-\ + * console code to do the right thing, and ignore it mostly... :-\ */ if (dev->vendor == PCI_VENDOR_ID_CONTAQ && - dev->device == PCI_DEVICE_ID_CONTAQ_82C693) { + dev->device == PCI_DEVICE_ID_CONTAQ_82C693 && + PCI_FUNC(dev->devfn) == 0) { DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n")); return; } @@ -463,12 +503,7 @@ disable_dev(struct pci_dev *dev) DBG_DEVS(("disable_dev: disabling %04x:%04x\n", dev->vendor, dev->device)); - bus = dev->bus; - pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); - - /* hack, turn it off first... */ - cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); - pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd); + (void)__disable_dev(dev); } @@ -489,6 +524,7 @@ layout_dev(struct pci_dev *dev) unsigned int orig_base; unsigned int alignto; unsigned long handle; + int start_idx = 0; /* * HACK: the PCI-to-EISA bridge does not seem to identify @@ -511,18 +547,24 @@ layout_dev(struct pci_dev *dev) /* * We don't have code that will init the CYPRESS bridge correctly * so we do the next best thing, and depend on the previous - * console code to do the right thing, and ignore it here... :-\ + * console code to do the right thing, and ignore it mostly... :-\ */ if (dev->vendor == PCI_VENDOR_ID_CONTAQ && dev->device == PCI_DEVICE_ID_CONTAQ_82C693) { + int func = PCI_FUNC(dev->devfn); + if (func == 0) { DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n")); return; + } + if (func == 1 || func == 2) { + start_idx = 4; /* bypass BAR 0 - 3 for the IDE devs */ + } } bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); - for (idx = 0; idx <= 5; idx++) { + for (idx = start_idx; idx <= 5; idx++) { off = PCI_BASE_ADDRESS_0 + 4*idx; /* * Figure out how much space and of what type this @@ -713,6 +755,46 @@ layout_dev(struct pci_dev *dev) dev->device, dev->class, cmd|PCI_COMMAND_MASTER)); } +/* We must save away the current bridge settings for restore during exit. */ +static void __init +save_bridge_setup(struct pci_dev *bridge) +{ + unsigned int dword; + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_IO_BASE, &dword); + new_io_reset(bridge, PCI_IO_BASE, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_IO_BASE_UPPER16, &dword); + new_io_reset(bridge, PCI_IO_BASE_UPPER16, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_PREF_BASE_UPPER32, &dword); + new_io_reset(bridge, PCI_PREF_BASE_UPPER32, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_PREF_LIMIT_UPPER32, &dword); + new_io_reset(bridge, PCI_PREF_LIMIT_UPPER32, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_MEMORY_BASE, &dword); + new_io_reset(bridge, PCI_MEMORY_BASE, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_PREF_MEMORY_BASE, &dword); + new_io_reset(bridge, PCI_PREF_MEMORY_BASE, dword); + + /* Must use dword that contains PCI_BRIDGE_CONTROL. */ + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_INTERRUPT_LINE, &dword); + new_io_reset(bridge, PCI_INTERRUPT_LINE, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_COMMAND, &dword); + new_io_reset(bridge, PCI_COMMAND, dword); +} + static int __init layout_bus(struct pci_bus *bus) { @@ -764,6 +846,7 @@ layout_bus(struct pci_bus *bus) if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) found_vga = 1; } + /* * Recursively allocate space for all of the sub-buses: */ @@ -772,6 +855,7 @@ layout_bus(struct pci_bus *bus) for (child = bus->children; child; child = child->next) { found_vga += layout_bus(child); } + /* * Align the current bases on 4K and 1MB boundaries: */ @@ -783,6 +867,8 @@ layout_bus(struct pci_bus *bus) DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number)); + save_bridge_setup(bridge); + /* * Set up the top and bottom of the PCI I/O segment * for this bus. @@ -1364,7 +1450,6 @@ static void __init layout_hoses(void) { struct linux_hose_info * hose; - int i; /* On multiple bus machines, we play games with pci_root in order that all of the busses are probed as part of the normal PCI diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c index 0408e76a78bd..ba226c2e8fd6 100644 --- a/arch/alpha/kernel/core_irongate.c +++ b/arch/alpha/kernel/core_irongate.c @@ -295,7 +295,7 @@ irongate_register_dump(const char *function_name) IRONGATE0->agpmode); } #else -#define irongate_register_dump(x) 1 +#define irongate_register_dump(x) #endif void __init diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index e2583bfd74ad..d75711c0179e 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -661,6 +661,65 @@ mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout) frame->ld_lock); } +void +mcpcia_print_system_area(unsigned long la_ptr) +{ + struct el_common *frame; + int i; + + struct IOD_subpacket { + unsigned long base; + unsigned int whoami; + unsigned int rsvd1; + unsigned int pci_rev; + unsigned int cap_ctrl; + unsigned int hae_mem; + unsigned int hae_io; + unsigned int int_ctl; + unsigned int int_reg; + unsigned int int_mask0; + unsigned int int_mask1; + unsigned int mc_err0; + unsigned int mc_err1; + unsigned int cap_err; + unsigned int rsvd2; + unsigned int pci_err1; + unsigned int mdpa_stat; + unsigned int mdpa_syn; + unsigned int mdpb_stat; + unsigned int mdpb_syn; + unsigned int rsvd3; + unsigned int rsvd4; + unsigned int rsvd5; + } *iodpp; + + frame = (struct el_common *)la_ptr; + + iodpp = (struct IOD_subpacket *) (la_ptr + frame->sys_offset); + + for (i = 0; i < hose_count; i++, iodpp++) { + printk("IOD %d Register Subpacket - Bridge Base Address %16lx\n", + i, iodpp->base); + printk(" WHOAMI = %8x\n", iodpp->whoami); + printk(" PCI_REV = %8x\n", iodpp->pci_rev); + printk(" CAP_CTRL = %8x\n", iodpp->cap_ctrl); + printk(" HAE_MEM = %8x\n", iodpp->hae_mem); + printk(" HAE_IO = %8x\n", iodpp->hae_io); + printk(" INT_CTL = %8x\n", iodpp->int_ctl); + printk(" INT_REG = %8x\n", iodpp->int_reg); + printk(" INT_MASK0 = %8x\n", iodpp->int_mask0); + printk(" INT_MASK1 = %8x\n", iodpp->int_mask1); + printk(" MC_ERR0 = %8x\n", iodpp->mc_err0); + printk(" MC_ERR1 = %8x\n", iodpp->mc_err1); + printk(" CAP_ERR = %8x\n", iodpp->cap_err); + printk(" PCI_ERR1 = %8x\n", iodpp->pci_err1); + printk(" MDPA_STAT = %8x\n", iodpp->mdpa_stat); + printk(" MDPA_SYN = %8x\n", iodpp->mdpa_syn); + printk(" MDPB_STAT = %8x\n", iodpp->mdpb_stat); + printk(" MDPB_SYN = %8x\n", iodpp->mdpb_syn); + } +} + void mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) @@ -709,6 +768,7 @@ halt(); if (vector != 0x620 && vector != 0x630 && ! MCPCIA_mcheck_expected[cpu]) { mcpcia_print_uncorrectable(mchk_logout); + mcpcia_print_system_area(la_ptr); } } diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index aa33e330e749..776b9ca4ce9b 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -896,7 +896,14 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, unsigned long __init init_IRQ(unsigned long memory) { wrent(entInt, 0); + alpha_mv.init_irq(); + + /* If we had wanted SRM console printk echoing early, undo it now. */ + if (alpha_using_srm && srmcons_output) { + unregister_srm_console(); + } + return memory; } diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index dcddc3504227..9cfeb0021d61 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -60,6 +60,7 @@ extern int irongate_hose_write_config_dword (u8, u8, u8, u32 value, struct linux_hose_info *hose); extern void irongate_init_arch(unsigned long *, unsigned long *); extern void irongate_machine_check(u64, u64, struct pt_regs *); +extern int irongate_pci_clr_err(void); /* core_lca.c */ extern int lca_hose_read_config_byte (u8, u8, u8, u8 *value, @@ -164,6 +165,9 @@ extern void tsunami_machine_check(u64, u64, struct pt_regs *); /* setup.c */ extern unsigned long srm_hae; +extern int srmcons_output; +extern void register_srm_console(void); +extern void unregister_srm_console(void); /* smp.c */ extern void setup_smp(void); @@ -219,6 +223,7 @@ extern int ptrace_set_bpt (struct task_struct *child); extern int ptrace_cancel_bpt (struct task_struct *child); /* ../mm/init.c */ +extern void switch_to_system_map(void); void srm_paging_stop(void); /* irq.c */ diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 4f927bdee26f..cd61bde288ac 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -40,7 +40,7 @@ #include #include #include - +#include #include "proto.h" @@ -52,6 +52,15 @@ struct alpha_machine_vector alpha_mv; int alpha_using_srm, alpha_use_srm_setup; #endif +/* Using SRM callbacks for initial console output. This works from + setup_arch() time through the end of init_IRQ(), as those places + are under our control. + + By default, OFF; set it with a bootcommand arg of "srmcons". +*/ +int srmcons_output = 0; + +/* For PS/2 presence */ unsigned char aux_device_present = 0xaa; #define N(a) (sizeof(a)/sizeof(a[0])) @@ -144,23 +153,31 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { - extern char _end[]; - struct alpha_machine_vector *vec = NULL; struct percpu_struct *cpu; char *type_name, *var_name, *p; unsigned long memory_end_override = 0; + extern char _end; + void *kernel_end = &_end; /* End of the kernel. */ hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); +#ifdef CONFIG_ALPHA_GENERIC + /* Assume that we've booted from SRM if we havn't booted from MILO. + Detect the later by looking for "MILO" in the system serial nr. */ + alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; +#endif + + kernel_end = callback_init(kernel_end); + /* - * Locate the command line. - */ + Process the command line. - /* Hack for Jensen... since we're restricted to 8 or 16 chars for + Hack for Jensen... since we're restricted to 8 or 16 chars for boot flags depending on the boot mode, we need some shorthand. This should do for installation. Later we'll add other - abbreviations as well... */ + abbreviations as well... + */ if (strcmp(COMMAND_LINE, "INSTALL") == 0) { strcpy(command_line, "root=/dev/fd0 load_ramdisk=1"); } else { @@ -198,11 +215,20 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, memory_end_override = get_memory_end_override(p+4); continue; } + if (strncmp(p, "srmcons", 7) == 0) { + srmcons_output = 1; + continue; + } } /* Replace the command line, not that we've killed it with strtok. */ strcpy(command_line, saved_command_line); + /* If we want SRM console printk echoing early, do it now. */ + if (alpha_using_srm && srmcons_output) { + register_srm_console(); + } + /* * Indentify and reconfigure for the current system. */ @@ -228,12 +254,6 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, alpha_mv = *vec; } -#ifdef CONFIG_ALPHA_GENERIC - /* Assume that we've booted from SRM if we havn't booted from MILO. - Detect the later by looking for "MILO" in the system serial nr. */ - alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; -#endif - printk("%s on %s%s%s using machine vector %s from %s\n", #ifdef CONFIG_ALPHA_GENERIC "Booting GENERIC", @@ -258,7 +278,7 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, wrmces(0x7); /* Find our memory. */ - *memory_start_p = (unsigned long) _end; + *memory_start_p = (unsigned long)kernel_end; *memory_end_p = find_end_memory(); if (memory_end_override && memory_end_override < *memory_end_p) { printk("Overriding memory size from %luMB to %luMB\n", @@ -342,7 +362,7 @@ find_end_memory(void) struct memdesc_struct * memdesc; memdesc = (struct memdesc_struct *) - (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); + (hwrpb->mddt_offset + (unsigned long)hwrpb); cluster = memdesc->cluster; for (i = memdesc->numclusters ; i > 0; i--, cluster++) { @@ -421,7 +441,7 @@ static char rawhide_names[][16] = { static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; static char tsunami_names[][16] = { - "0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper", + "EarlyMonet", "DP264", "Warhol", "Windjammer", "Monet", "Clipper", "Goldrush", "Webbrick", "Catamaran" }; static int tsunami_indices[] = {0,1,2,3,4,5,6,7,8}; @@ -508,7 +528,7 @@ get_sysvec(long type, long variation, long cpu) static struct alpha_machine_vector *tsunami_vecs[] __initlocaldata = { - NULL, + &monet_mv, /* HACK for early Monets */ &dp264_mv, /* dp264 */ &dp264_mv, /* warhol */ &dp264_mv, /* windjammer */ @@ -543,7 +563,7 @@ get_sysvec(long type, long variation, long cpu) if (!vec) { /* Member ID is a bit-field. */ - long member = (variation >> 10) & 0x3f; + long member = HWRPB_MEMBER_ID(variation); switch (type) { case ST_DEC_ALCOR: @@ -832,3 +852,65 @@ int get_cpuinfo(char *buffer) return len; } + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) +/* + * Manage the SRM callbacks as a "console". + */ +static struct console srmcons; + +void __init register_srm_console(void) +{ + register_console(&srmcons); +} + +void __init unregister_srm_console(void) +{ + unregister_console(&srmcons); +} + +static void srm_console_write(struct console *co, const char *s, + unsigned count) +{ + srm_printk(s); +} + +static kdev_t srm_console_device(struct console *c) +{ + /* Huh? */ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static int srm_console_wait_key(struct console *co) +{ + /* Huh? */ + return 1; +} + +static int __init srm_console_setup(struct console *co, char *options) +{ + return 1; +} + +static struct console srmcons = { + "srm0", + srm_console_write, + NULL, + srm_console_device, + srm_console_wait_key, + NULL, + srm_console_setup, + CON_PRINTBUFFER | CON_ENABLED, /* fake it out */ + -1, + 0, + NULL +}; + +#else +void __init register_srm_console(void) +{ +} +void __init unregister_srm_console(void) +{ +} +#endif diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index e80e364f3420..8beaa9503caf 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -393,7 +393,12 @@ monet_pci_fixup(void) layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(monet_map_irq, monet_swizzle); SMC669_Init(1); - es1888_init(); + + /* HACK: early Monets had a member ID of 0 and the ES1888 + located in a non-standard spot, so do this only for + official Monets */ + if (HWRPB_MEMBER_ID(hwrpb->sys_variation) != 0) + es1888_init(); } static void __init diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index 9952c311fd48..fa438dfb9a03 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -155,13 +155,14 @@ static void mikasa_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { -#define MCHK_NO_DEVSEL 0x205L -#define MCHK_NO_TABT 0x204L +#define MCHK_NO_DEVSEL 0x205U +#define MCHK_NO_TABT 0x204U struct el_common *mchk_header; struct el_apecs_procdata *mchk_procdata; struct el_apecs_mikasa_sysdata_mcheck *mchk_sysdata; unsigned long *ptr; + unsigned int code; /* workaround EGCS problem */ int i; mchk_header = (struct el_common *)la_ptr; @@ -193,9 +194,11 @@ mikasa_machine_check(unsigned long vector, unsigned long la_ptr, * ignore the machine check. */ - if (apecs_mcheck_expected - && ((unsigned int)mchk_header->code == MCHK_NO_DEVSEL - || (unsigned int)mchk_header->code == MCHK_NO_TABT)) { + code = mchk_header->code; /* workaround EGCS problem */ + + if (apecs_mcheck_expected && + (code == MCHK_NO_DEVSEL || code == MCHK_NO_TABT)) + { apecs_mcheck_expected = 0; apecs_mcheck_taken = 1; mb(); @@ -214,9 +217,9 @@ mikasa_machine_check(unsigned long vector, unsigned long la_ptr, vector); } else { - printk(KERN_CRIT "APECS machine check:\n"); - printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr); + printk(KERN_CRIT "MIKASA APECS machine check:\n"); + printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx code=0x%x\n", + vector, la_ptr, code); printk(KERN_CRIT " pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", regs->pc, mchk_header->size, mchk_header->proc_offset, @@ -274,7 +277,7 @@ struct alpha_machine_vector mikasa_primo_mv __initmv = { DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: mikasa_machine_check, + machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, nr_irqs: 32, diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c index 95539f811416..d495b000cb49 100644 --- a/arch/alpha/kernel/sys_nautilus.c +++ b/arch/alpha/kernel/sys_nautilus.c @@ -94,7 +94,7 @@ nautilus_kill_arch (int mode, char *restart_cmd) { unsigned char control; - cli(); + __cli(); /* Reset periodic interrupt frequency. */ CMOS_WRITE(0x26, RTC_FREQ_SELECT); @@ -105,7 +105,7 @@ nautilus_kill_arch (int mode, char *restart_cmd) CMOS_WRITE(control, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - sti(); + __sti(); } #endif @@ -115,7 +115,7 @@ nautilus_kill_arch (int mode, char *restart_cmd) break; case LINUX_REBOOT_CMD_RESTART: { - int v; + unsigned char v; irongate_hose_read_config_byte(0, 0x07<<3, 0x43, &v, 0); irongate_hose_write_config_byte(0, 0x07<<3, 0x43, v | 0x80, 0); outb(1, 0x92); @@ -504,7 +504,8 @@ void nautilus_machine_check(unsigned long vector, unsigned long la_ptr, break; } - printk(KERN_CRIT "> NAUTILUS Machine check 0x%x [%s]\n", vector, mchk_class); + printk(KERN_CRIT "> NAUTILUS Machine check 0x%lx [%s]\n", + vector, mchk_class); if ( cpu_analysis ) ev6_cpu_machine_check( vector, diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 06da880679f0..ebe39e330e69 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -236,7 +236,7 @@ time_init(void) { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq, one_percent; + unsigned long cycle_freq, ppm_error; long diff; /* @@ -261,17 +261,29 @@ time_init(void) cc1 = cc2; } - /* If the given value is within 1% of what we calculated, - accept it. Otherwise, use what we found. */ - cycle_freq = hwrpb->cycle_freq; - one_percent = cycle_freq / 100; + /* This code used to check for a 1% error. + * PWS600au reports 598802395 which is way off. (ntpd has problems.) + * So I tightened down the check. Hal Murray, Feb 27, 2000. + * + * HWRPB cycle_freq may be 0 (uninitialized) due to MILO, so make + * sure that we handle this case by forcing use of est_cycle_freq. + */ + if (!(cycle_freq = hwrpb->cycle_freq)) + cycle_freq = est_cycle_freq; + diff = cycle_freq - est_cycle_freq; if (diff < 0) diff = -diff; - if (diff > one_percent) { + ppm_error = (diff * 1000000L) / cycle_freq; +#if 0 + printk("Alpha clock init: HWRPB %lu, Measured %lu, error=%lu ppm.\n", + hwrpb->cycle_freq, est_cycle_freq, ppm_error); +#endif + if (ppm_error > 1000) { + printk("HWRPB cycle frequency (%lu) seems inaccurate -" + " using the measured value of %lu Hz\n", + cycle_freq, est_cycle_freq); cycle_freq = est_cycle_freq; - printk("HWRPB cycle frequency bogus. Estimated %lu Hz\n", - cycle_freq); } else { est_cycle_freq = 0; diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 03225a5d6ae6..655582653f67 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -652,7 +652,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg, got_exception: /* Ok, we caught the exception, but we don't want it. Is there someone to pass it along to? */ - if ((fixup = search_exception_table(pc)) != 0) { + if ((fixup = search_exception_table(pc, regs.gp)) != 0) { unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 400adf0e1de2..dba908e863a5 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -2,13 +2,18 @@ # Makefile for alpha-specific library files.. # +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \ checksum.o csum_partial_copy.o strlen.o \ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ csum_ipv6_magic.o strcasecmp.o semaphore.o \ - srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o + callback_srm.o callback_init.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/alpha/lib/callback_init.c b/arch/alpha/lib/callback_init.c new file mode 100644 index 000000000000..b9c185f6ef14 --- /dev/null +++ b/arch/alpha/lib/callback_init.c @@ -0,0 +1,83 @@ +/* + * arch/alpha/lib/callback_init.c + */ + +#include +#include +#include +#include +#include + +#include "../kernel/proto.h" + +int callback_init_done = 0; + +/* This is the SRM version. Maybe there will be a DBM version. */ + +void * __init callback_init(void * kernel_end) +{ + int i, j; + unsigned long vaddr = CONSOLE_REMAP_START; + struct crb_struct * crb; + pgd_t * pgd = pgd_offset_k(vaddr); + pmd_t * pmd; + void * two_pte_pages; + + /* Always page align the end of the kernel. */ + kernel_end = (void *) + (((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK); + + if (!alpha_using_srm) { + switch_to_system_map(); + return kernel_end; + } + + /* Allocate some memory for the pages. */ + two_pte_pages = kernel_end; + kernel_end = two_pte_pages + 2*PAGE_SIZE; + memset(two_pte_pages, 0, 2*PAGE_SIZE); + + /* Starting at the HWRPB, locate the CRB. */ + crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset); + + /* Tell the console whither the console is to be remapped. */ + if (srm_fixup(vaddr, (unsigned long)hwrpb)) + __halt(); /* "We're boned." --Bender */ + + /* Edit the procedure descriptors for DISPATCH and FIXUP. */ + crb->dispatch_va = (struct procdesc_struct *) + (vaddr + (unsigned long)crb->dispatch_va - crb->map[0].va); + crb->fixup_va = (struct procdesc_struct *) + (vaddr + (unsigned long)crb->fixup_va - crb->map[0].va); + + switch_to_system_map(); + + /* + * Set up the first and second level PTEs for console callbacks. + * There is an assumption here that only one of each is needed, + * and this allows for 8MB. Currently (late 1999), big consoles + * are still under 3MB. + */ + pgd_set(pgd, (pmd_t *)two_pte_pages); + pmd = pmd_offset(pgd, vaddr); + pmd_set(pmd, (pte_t *)(two_pte_pages + PAGE_SIZE)); + + /* + * Set up the third level PTEs and update the virtual addresses + * of the CRB entries. + */ + for (i = 0; i < crb->map_entries; ++i) { + unsigned long paddr = crb->map[i].pa; + crb->map[i].va = vaddr; + for (j = 0; j < crb->map[i].count; ++j) { + set_pte(pte_offset(pmd, vaddr), + mk_pte_phys(paddr, PAGE_KERNEL)); + paddr += PAGE_SIZE; + vaddr += PAGE_SIZE; + } + } + + callback_init_done = 1; + return kernel_end; +} + diff --git a/arch/alpha/lib/callback_srm.S b/arch/alpha/lib/callback_srm.S new file mode 100644 index 000000000000..9d6d8afeb987 --- /dev/null +++ b/arch/alpha/lib/callback_srm.S @@ -0,0 +1,102 @@ +/* + * arch/alpha/lib/callback_srm.S + */ + +#include +#include + +.text +#define HWRPB_CRB_OFFSET 0xc0 + +#if defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) +.align 4 +srm_dispatch: +#if defined(CONFIG_ALPHA_GENERIC) + ldl $4,alpha_using_srm + beq $4,nosrm +#endif + ldq $0,hwrpb # gp is set up by CALLBACK macro. + ldl $25,0($25) # Pick up the wrapper data. + mov $20,$21 # Shift arguments right. + mov $19,$20 + ldq $1,HWRPB_CRB_OFFSET($0) + mov $18,$19 + mov $17,$18 + mov $16,$17 + addq $0,$1,$2 # CRB address + ldq $27,0($2) # DISPATCH procedure descriptor (VMS call std) + extwl $25,0,$16 # SRM callback function code + ldq $3,8($27) # call address + extwl $25,2,$25 # argument information (VMS calling std) + jmp ($3) # Return directly to caller of wrapper. + +.align 4 +.globl srm_fixup +.ent srm_fixup +srm_fixup: + ldgp $29,0($27) +#if defined(CONFIG_ALPHA_GENERIC) + ldl $4,alpha_using_srm + beq $4,nosrm +#endif + ldq $0,hwrpb + ldq $1,HWRPB_CRB_OFFSET($0) + addq $0,$1,$2 # CRB address + ldq $27,16($2) # VA of FIXUP procedure descriptor + ldq $3,8($27) # call address + lda $25,2($31) # two integer arguments + jmp ($3) # Return directly to caller of srm_fixup. +.end srm_fixup + +#if defined(CONFIG_ALPHA_GENERIC) +.align 3 +nosrm: + lda $0,-1($31) + ret +#endif + +#define CALLBACK(NAME, CODE, ARG_CNT) \ +.align 4; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \ +ldgp $29,0($27); br $25,srm_dispatch; .word CODE, ARG_CNT; .end callback_##NAME + +#else /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */ + +#define CALLBACK(NAME, CODE, ARG_CNT) \ +.align 3; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \ +lda $0,-1($31); ret; .end callback_##NAME + +.align 3 +.globl srm_fixup +.ent srm_fixup +srm_fixup: + lda $0,-1($31) + ret +.end srm_fixup +#endif /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */ + +CALLBACK(puts, CCB_PUTS, 4) +CALLBACK(open, CCB_OPEN, 3) +CALLBACK(close, CCB_CLOSE, 2) +CALLBACK(read, CCB_READ, 5) +CALLBACK(getenv, CCB_GET_ENV, 4) +CALLBACK(setenv, CCB_SET_ENV, 4) +CALLBACK(getc, CCB_GETC, 2) +CALLBACK(reset_term, CCB_RESET_TERM, 2) +CALLBACK(term_int, CCB_SET_TERM_INT, 3) +CALLBACK(term_ctl, CCB_SET_TERM_CTL, 3) +CALLBACK(process_keycode, CCB_PROCESS_KEYCODE, 3) +CALLBACK(ioctl, CCB_IOCTL, 6) +CALLBACK(write, CCB_WRITE, 5) +CALLBACK(reset_env, CCB_RESET_ENV, 4) +CALLBACK(save_env, CCB_SAVE_ENV, 1) +CALLBACK(pswitch, CCB_PSWITCH, 3) +CALLBACK(bios_emul, CCB_BIOS_EMUL, 5) + +.data +__alpha_using_srm: # For use by bootpheader + .long 7 # value is not 1 for link debugging + .weak alpha_using_srm; alpha_using_srm = __alpha_using_srm +__callback_init_done: # For use by bootpheader + .long 7 # value is not 1 for link debugging + .weak callback_init_done; callback_init_done = __callback_init_done + diff --git a/arch/alpha/lib/copy_user.S b/arch/alpha/lib/copy_user.S index 7cc7382ab314..d8f1a24cfedd 100644 --- a/arch/alpha/lib/copy_user.S +++ b/arch/alpha/lib/copy_user.S @@ -80,7 +80,7 @@ $50: extql $3,$7,$3 extqh $2,$7,$1 bis $3,$1,$1 - stq $1,0($6) + EXO( stq $1,0($6) ) addq $7,8,$7 subq $0,8,$0 addq $6,8,$6 diff --git a/arch/alpha/lib/srm_dispatch.S b/arch/alpha/lib/srm_dispatch.S deleted file mode 100644 index 2bcea3073aae..000000000000 --- a/arch/alpha/lib/srm_dispatch.S +++ /dev/null @@ -1,43 +0,0 @@ -/* - * arch/alpha/lib/srm_dispatch.S - */ - -.globl srm_dispatch -.ent srm_dispatch -srm_dispatch: - .frame $30,30,$26 - subq $30,80,$30 - stq $26,0($30) - stq $8,8($30) - stq $9,16($30) - stq $10,24($30) - stq $11,32($30) - stq $12,40($30) - stq $13,48($30) - stq $14,56($30) - stq $15,64($30) - stq $29,72($30) - .mask 0x2400FF00, -80 - .prologue 0 - - ldq $1,hwrpb - ldq $2,0xc0($1) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,0($2) /* dispatch procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $8,8($30) - ldq $9,16($30) - ldq $10,24($30) - ldq $11,32($30) - ldq $12,40($30) - ldq $13,48($30) - ldq $14,56($30) - ldq $15,64($30) - ldq $29,72($30) - addq $30,80,$30 - ret $31,($26),1 -.end srm_dispatch diff --git a/arch/alpha/lib/srm_fixup.S b/arch/alpha/lib/srm_fixup.S deleted file mode 100644 index 9cf2d78c294f..000000000000 --- a/arch/alpha/lib/srm_fixup.S +++ /dev/null @@ -1,42 +0,0 @@ -/* - * arch/alpha/lib/srm_fixup.S - */ - -.globl srm_fixup -.ent srm_fixup -srm_fixup: - .frame $30,30,$26 - subq $30,80,$30 - stq $26,0($30) - stq $8,8($30) - stq $9,16($30) - stq $10,24($30) - stq $11,32($30) - stq $12,40($30) - stq $13,48($30) - stq $14,56($30) - stq $15,64($30) - stq $29,72($30) - .mask 0x2400FF00, -80 - .prologue 0 - - ldq $2,0xc0($17) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,16($2) /* fixup procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $8,8($30) - ldq $9,16($30) - ldq $10,24($30) - ldq $11,32($30) - ldq $12,40($30) - ldq $13,48($30) - ldq $14,56($30) - ldq $15,64($30) - ldq $29,72($30) - addq $30,80,$30 - ret $31,($26),1 -.end srm_fixup diff --git a/arch/alpha/lib/srm_printk.c b/arch/alpha/lib/srm_printk.c index b5baee15ffd2..547bc9f8a17f 100644 --- a/arch/alpha/lib/srm_printk.c +++ b/arch/alpha/lib/srm_printk.c @@ -10,12 +10,31 @@ srm_printk(const char *fmt, ...) { static char buf[1024]; va_list args; - long i; + long len, num_lf; + char *src, *dst; va_start(args, fmt); - i = vsprintf(buf,fmt,args); + len = vsprintf(buf, fmt, args); va_end(args); - srm_puts(buf); - return i; + /* Count number of linefeeds in string. */ + num_lf = 0; + for (src = buf; *src; ++src) { + if (*src == '\n') { + ++num_lf; + } + } + + /* Expand each linefeed into carriage-return/linefeed. */ + if (num_lf) { + for (dst = src + num_lf; src >= buf; ) { + if (*src == '\n') { + *dst-- = '\r'; + } + *dst-- = *src--; + } + } + + srm_puts(buf, num_lf+len); + return len; } diff --git a/arch/alpha/lib/srm_puts.c b/arch/alpha/lib/srm_puts.c index 87b1d11559a4..caded3e1b95b 100644 --- a/arch/alpha/lib/srm_puts.c +++ b/arch/alpha/lib/srm_puts.c @@ -5,30 +5,19 @@ #include #include -void -srm_puts(const char *str) +long +srm_puts(const char *str, long len) { - /* Expand \n to \r\n as we go. */ + long remaining, written; - while (*str) { - long len; - const char *e = str; + if (!callback_init_done) + return len; - if (*str == '\n') { - if (srm_dispatch(CCB_PUTS, 0, "\r", 1) < 0) - return; - ++e; - } - - e = strchr(e, '\n') ? : strchr(e, '\0'); - len = e - str; - - while (len > 0) { - long written = srm_dispatch(CCB_PUTS, 0, str, len); - if (written < 0) - return; - len -= written & 0xffffffff; - str += written & 0xffffffff; - } - } + for (remaining = len; remaining > 0; remaining -= written) + { + written = callback_puts(0, str, remaining); + written &= 0xffffffff; + str += written; + } + return len; } diff --git a/arch/alpha/mm/extable.c b/arch/alpha/mm/extable.c index b0cb627ad697..acbc394cb6d7 100644 --- a/arch/alpha/mm/extable.c +++ b/arch/alpha/mm/extable.c @@ -36,8 +36,8 @@ search_one_table(const struct exception_table_entry *first, register unsigned long gp __asm__("$29"); -unsigned -search_exception_table(unsigned long addr) +static unsigned +search_exception_table_without_gp(unsigned long addr) { unsigned ret; @@ -60,3 +60,38 @@ search_exception_table(unsigned long addr) return 0; } + +unsigned +search_exception_table(unsigned long addr, unsigned long exc_gp) +{ + unsigned ret; + +#ifndef CONFIG_MODULES + ret = search_one_table(__start___ex_table, __stop___ex_table - 1, + addr - exc_gp); + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + for (mp = module_list; mp ; mp = mp->next) { + if (!mp->ex_table_start) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end - 1, addr - exc_gp); + if (ret) return ret; + } +#endif + + /* + * The search failed with the exception gp. To be safe, try the + * old method before giving up. + */ + ret = search_exception_table_without_gp(addr); + if (ret) { + printk(KERN_ALERT, "%s: [%lx] EX_TABLE search fail with" + "exc frame GP, success with raw GP\n", + current->comm, addr); + return ret; + } + return 0; +} diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index f0c0fc7bc2a1..6e0ed901f550 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -147,11 +147,11 @@ bad_area: no_context: /* Are we prepared to handle this fault as an exception? */ - if ((fixup = search_exception_table(regs->pc)) != 0) { + if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); -#if 0 - printk("%s: Exception at [<%lx>] (%lx)\n", +#if 1 + printk("%s: Exception at [<%lx>] (%lx) handled successfully.\n", current->comm, regs->pc, newpc); #endif regs->pc = newpc; diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 606fe1e5a920..b6a1d2ffff90 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -182,6 +182,44 @@ load_PCB(struct thread_struct * pcb) return (struct thread_struct *) __reload_tss(pcb); } +void +switch_to_system_map(void) +{ + unsigned long newptbr; + struct thread_struct *original_pcb_ptr; + + memset(swapper_pg_dir, 0, PAGE_SIZE); + newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; + pgd_val(swapper_pg_dir[1023]) = + (newptbr << 32) | pgprot_val(PAGE_KERNEL); + + + /* Also set up the real kernel PCB while we're at it. */ + init_task.tss.ptbr = newptbr; + init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ + init_task.tss.flags = 0; + + hwrpb->vptb = 0xfffffffe00000000; + hwrpb_update_checksum(hwrpb); + + wrvptptr(0xfffffffe00000000); + original_pcb_ptr = load_PCB(&init_task.tss); + tbia(); + + /* Save off the contents of the original PCB so that we can + restore the original console's page tables for a clean reboot. + + Note that the PCB is supposed to be a physical address, but + since KSEG values also happen to work, folks get confused. + Check this here. */ + + if ((unsigned long)original_pcb_ptr < PAGE_OFFSET) { + original_pcb_ptr = (struct thread_struct *) + phys_to_virt((unsigned long) original_pcb_ptr); + } + original_pcb = *original_pcb_ptr; +} + /* * paging_init() sets up the page tables: in the alpha version this actually * unmaps the bootup page table (as we're now in KSEG, so we don't need it). @@ -190,10 +228,8 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) { int i; - unsigned long newptbr; struct memclust_struct * cluster; struct memdesc_struct * memdesc; - struct thread_struct *original_pcb_ptr; /* initialize mem_map[] */ start_mem = free_area_init(start_mem, end_mem); @@ -221,41 +257,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem) clear_bit(PG_reserved, &mem_map[pfn++].flags); } - /* Initialize the kernel's page tables. Linux puts the vptb in - the last slot of the L1 page table. */ memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE); - memset(swapper_pg_dir, 0, PAGE_SIZE); - newptbr = MAP_NR(swapper_pg_dir); - pgd_val(swapper_pg_dir[1023]) = - (newptbr << 32) | pgprot_val(PAGE_KERNEL); - - /* Set the vptb. This is often done by the bootloader, but - shouldn't be required. */ - if (hwrpb->vptb != 0xfffffffe00000000) { - wrvptptr(0xfffffffe00000000); - hwrpb->vptb = 0xfffffffe00000000; - hwrpb_update_checksum(hwrpb); - } - - /* Also set up the real kernel PCB while we're at it. */ - init_task.tss.ptbr = newptbr; - init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ - init_task.tss.flags = 0; - original_pcb_ptr = load_PCB(&init_task.tss); - tbia(); - - /* Save off the contents of the original PCB so that we can - restore the original console's page tables for a clean reboot. - - Note that the PCB is supposed to be a physical address, but - since KSEG values also happen to work, folks get confused. - Check this here. */ - - if ((unsigned long)original_pcb_ptr < PAGE_OFFSET) { - original_pcb_ptr = (struct thread_struct *) - phys_to_virt((unsigned long) original_pcb_ptr); - } - original_pcb = *original_pcb_ptr; return start_mem; } diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds index 0fb2276eabd7..6e7117a48dcd 100644 --- a/arch/alpha/vmlinux.lds +++ b/arch/alpha/vmlinux.lds @@ -1,10 +1,11 @@ OUTPUT_FORMAT("elf64-alpha") ENTRY(__start) +PHDRS { kernel PT_LOAD ; } SECTIONS { . = 0xfffffc0000310000; _text = .; - .text : { *(.text) } + .text : { *(.text) } :kernel .text2 : { *(.text2) } _etext = .; diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 8ec52dcf893b..7f9ec34addcb 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -274,6 +274,7 @@ int drive_is_flashcard (ide_drive_t *drive) if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ || !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */ + || !strncmp(id->model, "ATA_FLASH", 9) /* Simple Tech */ || !strncmp(id->model, "HAGIWARA HPC", 12)) /* Hagiwara */ { return 1; /* yes, it is a flash memory card */ diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c index 6d91e7187d9f..b31425264df1 100644 --- a/drivers/i2o/i2o_block.c +++ b/drivers/i2o/i2o_block.c @@ -1289,7 +1289,7 @@ void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d) * so we just sleep for a little while and let it do it's thing */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(3*HZ); + schedule_timeout(5*HZ); if(i2o_claim_device(d, &i2o_block_handler)) { diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c index d00dd8dbde68..fc6ab62e06ee 100644 --- a/drivers/i2o/i2o_config.c +++ b/drivers/i2o/i2o_config.c @@ -42,7 +42,8 @@ static int i2o_cfg_context = -1; static void *page_buf; static void *i2o_buffer; -static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t i2o_queue_lock = SPIN_LOCK_UNLOCKED; + struct wait_queue *i2o_wait_queue; #define MODINC(x,y) (x = x++ % y) @@ -144,7 +145,7 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc (unsigned char *)(msg + 5), inf->event_q[inf->q_in].data_size); - spin_lock(&i2o_config_lock); + spin_lock(&i2o_queue_lock); MODINC(inf->q_in, I2O_EVT_Q_LEN); if(inf->q_len == I2O_EVT_Q_LEN) { @@ -156,7 +157,7 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc // Keep I2OEVTGET on another CPU from touching this inf->q_len++; } - spin_unlock(&i2o_config_lock); + spin_unlock(&i2o_queue_lock); // printk(KERN_INFO "File %p w/id %d has %d events\n", @@ -808,11 +809,12 @@ static int ioctl_evt_get(unsigned long arg, struct file *fp) memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); MODINC(p->q_out, I2O_EVT_Q_LEN); - spin_lock_irqsave(&i2o_config_lock, flags); + spin_lock_irqsave(&i2o_queue_lock, flags); + /* FIXME - ought to lock the q_ values here!! */ p->q_len--; kget.pending = p->q_len; kget.lost = p->q_lost; - spin_unlock_irqrestore(&i2o_config_lock, flags); + spin_unlock_irqrestore(&i2o_queue_lock, flags); __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)); @@ -838,9 +840,9 @@ static int cfg_open(struct inode *inode, struct file *file) tmp->q_lost = 0; tmp->next = open_files; - spin_lock_irqsave(&i2o_config_lock, flags); + spin_lock_irqsave(&i2o_queue_lock, flags); open_files = tmp; - spin_unlock_irqrestore(&i2o_config_lock, flags); + spin_unlock_irqrestore(&i2o_queue_lock, flags); MOD_INC_USE_COUNT; return 0; @@ -854,7 +856,7 @@ static int cfg_release(struct inode *inode, struct file *file) p1 = p2 = NULL; - spin_lock_irqsave(&i2o_config_lock, flags); + spin_lock_irqsave(&i2o_queue_lock, flags); for(p1 = open_files; p1; ) { if(p1->q_id == id) @@ -873,7 +875,7 @@ static int cfg_release(struct inode *inode, struct file *file) p2 = p1; p1 = p1->next; } - spin_unlock_irqrestore(&i2o_config_lock, flags); + spin_unlock_irqrestore(&i2o_queue_lock, flags); MOD_DEC_USE_COUNT; return 0; diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index d00ac40009b9..8c7a693c2b95 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -180,11 +180,11 @@ static int evt_q_len = 0; #define MODINC(x,y) (x = x++ % y) /* - * I2O configuration spinlock. This isnt a big deal for contention + * I2O configuration semaphore. This isnt a big deal for contention * so we have one only */ -static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; +static struct semaphore i2o_configuration_lock = MUTEX; /* @@ -317,18 +317,18 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, int i2o_install_handler(struct i2o_handler *h) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;icontext = i; i2o_handlers[i]=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOSPC; } @@ -348,7 +348,7 @@ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; @@ -358,7 +358,7 @@ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } @@ -431,11 +431,11 @@ int i2o_delete_device(struct i2o_device *d) { int ret; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); ret = __i2o_delete_device(d); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return ret; } @@ -447,7 +447,7 @@ int i2o_delete_device(struct i2o_device *d) int i2o_install_controller(struct i2o_controller *c) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;iname, "i2o/iop%d", i); i2o_num_controllers++; sema_init(&c->lct_sem, 0); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } printk(KERN_ERR "No free i2o controller slots.\n"); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } @@ -488,12 +488,12 @@ int i2o_delete_controller(struct i2o_controller *c) if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) i2o_event_register(c, core_context, 0, 0, 0); - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users); c->bus_disable(c); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } while(c->devices) @@ -502,7 +502,7 @@ int i2o_delete_controller(struct i2o_controller *c) { /* Shouldnt happen */ c->bus_disable(c); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } } @@ -541,7 +541,7 @@ int i2o_delete_controller(struct i2o_controller *c) c->destructor(c); *p=c->next; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); if(c->page_frame) kfree(c->page_frame); @@ -565,7 +565,7 @@ int i2o_delete_controller(struct i2o_controller *c) } p=&((*p)->next); } - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); return -ENOENT; } @@ -582,11 +582,11 @@ struct i2o_controller *i2o_find_controller(int n) if(n<0 || n>=MAX_I2O_CONTROLLERS) return NULL; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); c=i2o_controllers[n]; if(c!=NULL) atomic_inc(&c->users); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return c; } @@ -597,23 +597,23 @@ struct i2o_controller *i2o_find_controller(int n) */ int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) { - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if(d->owner) { printk(KERN_INFO "issue claim called, but dev has owner!"); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } if(i2o_issue_claim(d->controller,d->lct_data.tid, h->context, 1, I2O_CLAIM_PRIMARY)) { - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } d->owner=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } @@ -621,10 +621,10 @@ int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if(d->owner != h) { - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOENT; } @@ -636,7 +636,7 @@ int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) d->owner = NULL; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return err; } @@ -1178,7 +1178,7 @@ static int i2o_reset_controller(struct i2o_controller *c) u32 *msg; long time; - printk("begin RESET\n"); + dprintk(("begin RESET\n")); /* Quiesce all IOPs first */ for (iop = i2o_controller_chain; iop; iop = iop->next) @@ -1484,13 +1484,13 @@ rebuild_sys_tab: * as we can't init the IOPs w/o a system table */ - printk("SYSTAB\n"); + dprintk(("SYSTAB\n")); if (i2o_build_sys_table() < 0) { i2o_sys_shutdown(); return; } - printk("ONLINE\n"); + dprintk(("ONLINE\n")); /* If IOP don't get online, we need to rebuild the System table */ for (iop = i2o_controller_chain; iop; iop = niop) { @@ -1499,7 +1499,7 @@ rebuild_sys_tab: goto rebuild_sys_tab; } - printk("ACTIVE\n"); + dprintk(("ACTIVE\n")); /* Active IOPs now in OPERATIONAL state * @@ -1522,7 +1522,7 @@ rebuild_sys_tab: i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF); } - printk("DONE\n"); + dprintk(("DONE\n")); } /* @@ -1548,9 +1548,8 @@ int i2o_activate_controller(struct i2o_controller *iop) { /* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */ /* In READY state, Get status */ - u32 m; - printk("ACTIVATE\n"); + dprintk(("ACTIVATE\n")); if (i2o_status_get(iop) < 0) { printk(KERN_INFO "Unable to obtain status of IOP, attempting a reset.\n"); @@ -1575,42 +1574,30 @@ int i2o_activate_controller(struct i2o_controller *iop) { dprintk((KERN_INFO "%s: already running...trying to reset\n", iop->name)); - printk("Outbound q2\n"); - - if (i2o_init_outbound_q(iop) < 0) { - i2o_reset_controller(iop); + dprintk(("Outbound q2\n")); - if (i2o_status_get(iop) < 0 || - iop->status_block->iop_state != ADAPTER_STATE_RESET) - { - printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name); - i2o_delete_controller(iop); - return -1; - } - if (i2o_init_outbound_q(iop) < 0) { - i2o_delete_controller(iop); - return -1; - } - } - } - else - { - printk("Outbound q\n"); - - if (i2o_init_outbound_q(iop) < 0) { + i2o_reset_controller(iop); + if (i2o_status_get(iop) < 0 || iop->status_block->iop_state != ADAPTER_STATE_RESET) + { + printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name); i2o_delete_controller(iop); return -1; } } + if (i2o_init_outbound_q(iop) < 0) { + i2o_delete_controller(iop); + return -1; + } + /* In HOLD state */ - printk("HRT\n"); + dprintk("HRT\n"); if (i2o_hrt_get(iop) < 0) { i2o_delete_controller(iop); return -1; } - printk("DONE\n"); + dprintk("DONE\n"); return 0; } @@ -2150,9 +2137,9 @@ static int i2o_core_evt(void *reply_data) { if(i2o_handlers[i] && i2o_handlers[i]->new_dev_notify && (i2o_handlers[i]->class&d->lct_data.class_id)) { - spin_lock(&i2o_dev_lock); + spin_lock_irqsave(&i2o_dev_lock, flags); i2o_handlers[i]->new_dev_notify(c,d); - spin_unlock(&i2o_dev_lock); + spin_unlock_irqrestore(&i2o_dev_lock, flags); } } @@ -2214,6 +2201,7 @@ static int i2o_dyn_lct(void *foo) void *tmp; char name[16]; struct fs_struct *fs; + unsigned long flags; lock_kernel(); @@ -2283,9 +2271,9 @@ static int i2o_dyn_lct(void *foo) if(!found) { dprintk((KERN_INFO "Deleted device!\n")); - spin_lock(&i2o_dev_lock); + spin_lock_irqsave(&i2o_dev_lock,flags); i2o_delete_device(d); - spin_unlock(&i2o_dev_lock); + spin_unlock_irqrestore(&i2o_dev_lock,flags); } d = d1; } diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 5227b3956390..3fb5ef4a55f5 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -4,7 +4,7 @@ * The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and * a NIC on an internal board. * - * Author: Rick Richardson, rick@dgii.com, rick_richardson@dgii.com + * Author: Rick Richardson, rick@remotepoint.com * Derived from the SVR4.2 (UnixWare) driver for the same card. * * Copyright 1995-1996 Digi International Inc. @@ -73,7 +73,7 @@ * */ -static char *version = "$Id: dgrs.c,v 1.12 1996/12/21 13:43:58 rick Exp $"; +static char *version = "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; #include #include @@ -209,7 +209,7 @@ typedef struct I596_RFD *rfdp; /* Current RFD list */ I596_RBD *rbdp; /* Current RBD list */ - int intrcnt; /* Count of interrupts */ + volatile int intrcnt; /* Count of interrupts */ /* * SE-4 (EISA) board variables @@ -1193,7 +1193,7 @@ dgrs_probe1(struct device *dev)) */ if (priv->plxreg) OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1); - rc = request_irq(dev->irq, &dgrs_intr, 0, "RightSwitch", dev); + rc = request_irq(dev->irq, &dgrs_intr, SA_SHIRQ, "RightSwitch", dev); if (rc) return (rc); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 50b517c8fa56..f7f42ba344bf 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -508,7 +508,9 @@ static int pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[]) #ifndef MODULE int via_rhine_probe(struct device *dev) { - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + static int did_version = 0; + if (!did_version++) + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); return pci_etherdev_probe(dev, pci_tbl); } #endif diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 3dcea50a905a..63bb0650fa59 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -1018,9 +1018,9 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n"); error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); #ifdef CONFIG_NCPFS_STRONG - /* 9C is Invalid path.. It should be 8F, 90 - read only, but - it is not :-( */ - if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */ + /* 9C is Invalid path, used by traditional NW filesystem... + 8F, 90 is Some/All read-only and is used by NSS :-( */ + if ((error == 0x9C || error == 0x8F || error == 0x90) && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */ error = ncp_force_unlink(dir, dentry); } #endif @@ -1085,7 +1085,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, old_dir, _old_name, new_dir, _new_name); #ifdef CONFIG_NCPFS_STRONG - if ((error == 0x90 || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */ + if ((error == 0x90 || error == 0x8B || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */ error = ncp_force_rename(old_dir, old_dentry, _old_name, new_dir, new_dentry, _new_name); } diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 0d565a44e764..0d498e65bbf3 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -105,8 +105,7 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo) switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { case aHIDDEN: if (server->m.flags & NCP_MOUNT_SYMLINKS) { - if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE) - && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { + if (inode->i_size <= NCP_MAX_SYMLINK_SIZE) { inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; break; } @@ -168,8 +167,7 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo) switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { case aHIDDEN: if (server->m.flags & NCP_MOUNT_SYMLINKS) { - if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE) - && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { + if (inode->i_size <= NCP_MAX_SYMLINK_SIZE) { inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; break; } diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index c22297f6507a..74baa4de70b2 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -336,6 +336,7 @@ repeat: goto repeat; } else { + brelse (bh); return NULL; } } diff --git a/include/asm-alpha/console.h b/include/asm-alpha/console.h index 89f39911f337..44ea5535bd79 100644 --- a/include/asm-alpha/console.h +++ b/include/asm-alpha/console.h @@ -22,6 +22,8 @@ #define CCB_GET_ENV 0x22 #define CCB_SAVE_ENV 0x23 +#define CCB_PSWITCH 0x30 +#define CCB_BIOS_EMUL 0x32 /* * Environment variable numbers */ @@ -36,20 +38,33 @@ #define ENV_BOOT_RESET 0x09 #define ENV_DUMP_DEV 0x0A #define ENV_ENABLE_AUDIT 0x0B -#define ENV_LICENCE 0x0C +#define ENV_LICENSE 0x0C #define ENV_CHAR_SET 0x0D #define ENV_LANGUAGE 0x0E #define ENV_TTY_DEV 0x0F +#define NO_SRM_CONSOLE -1L + #ifdef __KERNEL__ -extern long srm_dispatch(long code, ...); -extern void srm_puts(const char *); +#ifndef __ASSEMBLY__ +extern long callback_puts(long unit, const char *s, long length); +extern long callback_open(const char *device, long length); +extern long callback_close(long unit); +extern long callback_read(long channel, long count, const char *buf, long lbn); +extern long callback_getenv(long id, const char *buf, unsigned long buf_size); + +extern int srm_fixup(unsigned long new_callback_addr, + unsigned long new_hwrpb_addr); +extern long srm_puts(const char *, long len); extern long srm_printk(const char *, ...) __attribute__ ((format (printf, 1, 2))); struct crb_struct; struct hwrpb_struct; -extern long srm_fixup(struct crb_struct *, struct hwrpb_struct *); + +extern int callback_init_done; +extern void * callback_init(void *); +#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* __AXP_CONSOLE_H */ diff --git a/include/asm-alpha/core_tsunami.h b/include/asm-alpha/core_tsunami.h index a1a7c2429ccf..3bccc03c17bf 100644 --- a/include/asm-alpha/core_tsunami.h +++ b/include/asm-alpha/core_tsunami.h @@ -80,6 +80,7 @@ typedef struct { tsunami_64 mpr2; tsunami_64 mpr3; tsunami_64 mctl; + tsunami_64 __pad1; tsunami_64 ttr; tsunami_64 tdr; tsunami_64 dim2; diff --git a/include/asm-alpha/hwrpb.h b/include/asm-alpha/hwrpb.h index ec65678bb88f..b225f3e7a730 100644 --- a/include/asm-alpha/hwrpb.h +++ b/include/asm-alpha/hwrpb.h @@ -190,6 +190,8 @@ struct hwrpb_struct { unsigned long dsr_offset; /* "Dynamic System Recognition Data Block Table" */ }; +#define HWRPB_MEMBER_ID(v) (((v) >> 10) & 0x3f) + #ifdef __KERNEL__ extern struct hwrpb_struct *hwrpb; diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h index 889737c82494..b881d0e16b0a 100644 --- a/include/asm-alpha/pgtable.h +++ b/include/asm-alpha/pgtable.h @@ -9,6 +9,7 @@ * in (currently 8192). */ #include +#include #include #include /* For TASK_SIZE */ @@ -219,7 +220,8 @@ extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long); /* Number of pointers that fit on a page: this will go away. */ #define PTRS_PER_PAGE (1UL << (PAGE_SHIFT-3)) -#define VMALLOC_START 0xFFFFFE0000000000 +#define CONSOLE_REMAP_START 0xFFFFFE0000000000 +#define VMALLOC_START (CONSOLE_REMAP_START + PMD_SIZE) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END (~0UL) diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index 17268460fe8c..d6881efc79b5 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -137,6 +137,9 @@ __asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory") #define draina() \ __asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory") +#define __halt() \ +__asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt)) + enum implver_enum { IMPLVER_EV4, IMPLVER_EV5, diff --git a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h index 80d1efcbd6cf..177732abbb1e 100644 --- a/include/asm-alpha/uaccess.h +++ b/include/asm-alpha/uaccess.h @@ -530,7 +530,7 @@ struct exception_table_entry }; /* Returns 0 if exception not found and fixup.unit otherwise. */ -extern unsigned search_exception_table(unsigned long); +extern unsigned search_exception_table(unsigned long, unsigned long); /* Returns the new pc */ #define fixup_exception(map_reg, fixup_unit, pc) \ -- 2.39.5