From b468356b8a207900e7ac5e05f5fc047f72e0e101 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:17:29 -0500 Subject: [PATCH] Linux 2.1.131pre2 There's a pre-131-2 patch there on ftp.kernel.org in the testing directory. This should have the NFS locking issues worked out (please test), and also has a rather subtle but potentially very nasty deadlock due to incorrect semaphore ordering with rmdir() hopefully fixed for good. Alan, the regparm patches are also there. Linus nfs: write back everything whenever some lock is changed (not just for unlock), and always invalidates the caches. --- CREDITS | 10 +- Documentation/Configure.help | 26 ++- Makefile | 2 +- arch/alpha/config.in | 8 - arch/alpha/kernel/bios32.c | 127 ++++++---- arch/alpha/kernel/process.c | 15 +- arch/alpha/kernel/setup.c | 81 ++++--- arch/alpha/kernel/sys_dp264.c | 60 ++--- arch/i386/boot/setup.S | 22 +- arch/i386/config.in | 1 + arch/i386/kernel/apm.c | 315 ++++++++++++++++--------- arch/i386/kernel/process.c | 67 ++---- arch/i386/kernel/signal.c | 2 +- arch/i386/kernel/vm86.c | 2 +- arch/i386/mm/init.c | 9 +- arch/i386/mm/ioremap.c | 15 +- drivers/char/keyboard.c | 7 +- drivers/char/lp.c | 384 +++++++++++++++++++++---------- drivers/char/tty_io.c | 8 +- drivers/scsi/ChangeLog.ncr53c8xx | 16 ++ drivers/scsi/README.ncr53c8xx | 4 +- drivers/scsi/ncr53c8xx.c | 95 +++++--- drivers/scsi/ncr53c8xx.h | 9 +- drivers/scsi/scsi_obsolete.c | 7 +- drivers/sound/sb_common.c | 1 + drivers/video/atyfb.c | 28 +++ fs/affs/namei.c | 2 - fs/ext2/namei.c | 4 - fs/minix/namei.c | 2 - fs/namei.c | 88 +++---- fs/nfs/file.c | 25 +- fs/nfs/write.c | 9 - fs/nfsd/vfs.c | 5 + fs/open.c | 4 +- fs/qnx4/namei.c | 3 - fs/sysv/namei.c | 2 - fs/ufs/namei.c | 4 - fs/umsdos/README-WIP.txt | 34 ++- fs/umsdos/check.c | 80 +++---- fs/umsdos/dir.c | 1 - fs/umsdos/inode.c | 21 +- fs/umsdos/namei.c | 6 - fs/umsdos/rdir.c | 34 +-- include/asm-i386/semaphore.h | 6 +- include/linux/apm_bios.h | 1 + include/linux/linkage.h | 10 +- include/linux/lp.h | 18 +- include/linux/nfs_fs.h | 1 - include/linux/pci.h | 1 + include/linux/swap.h | 4 +- include/linux/umsdos_fs.h | 4 +- include/linux/umsdos_fs.p | 1 - init/main.c | 8 + kernel/fork.c | 2 +- mm/filemap.c | 14 +- mm/swap.c | 4 +- mm/vmscan.c | 2 +- net/ipv4/Config.in | 26 ++- net/ipv4/tcp_ipv4.c | 2 +- 59 files changed, 1054 insertions(+), 695 deletions(-) diff --git a/CREDITS b/CREDITS index ab7398163af7..f17f3ef6ea6b 100644 --- a/CREDITS +++ b/CREDITS @@ -1116,11 +1116,11 @@ E: Kai.Makisara@metla.fi D: SCSI Tape Driver N: Hamish Macdonald -E: hamish@border.ocunix.on.ca +E: hamish_macdonald@westendsys.com D: Linux/68k port -S: 102-B Valleystream Drive -S: Nepean, Ontario -S: Canada K2H-9E1 +S: 32 Clydesdale Avenue +S: Kanata, Ontario +S: Canada K2M-2G7 N: Peter MacDonald D: SLS distribution @@ -2074,7 +2074,7 @@ S: San Jose, California 95148 S: USA N: Marc Zyngier -E: maz@gloups.fdn.fr +E: maz@wild-wind.fr.eu.org D: MD driver S: 11 rue Victor HUGO S: 95560 Montsoult diff --git a/Documentation/Configure.help b/Documentation/Configure.help index d8176d3a4475..6fcb85efc9a4 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2397,9 +2397,6 @@ CONFIG_IP_MASQUERADE information on the WWW at http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. - If you say Y here, you should also say Y to "IP: always defragment", - below. - If you say Y here, then the modules ip_masq_ftp.o (for ftp file transfers), ip_masq_irc.o (for irc chats), ip_masq_quake.o (you guessed it), ip_masq_vdolive.o (for VDOLive video connections), @@ -2503,7 +2500,7 @@ CONFIG_IP_MASQUERADE_IPMARKFW The module will be called ip_masq_markfw.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -IP: always defragment +IP: always defragment (required for masquerading) CONFIG_IP_ALWAYS_DEFRAG If you say Y here, then all incoming fragments (parts of IP packets that arose when some host between origin and destination decided @@ -2511,18 +2508,13 @@ CONFIG_IP_ALWAYS_DEFRAG reassembled (defragmented) before being processed, even if they are about to be forwarded. - This option is highly recommended if you have said Y to "IP: - masquerading" because that facility requires that second and further - fragments can be related to TCP or UDP port numbers, which are only - stored in the first fragment. + You must say Y here if you want to enable "IP: masquerading" or "IP: + transparent proxying". When using "IP: firewalling" support, you might also want to say Y here, to have a more reliable firewall (otherwise second and further fragments must be dealt with by the firewall, which can be tricky). - When using "IP: transparent proxying", this option is implicit, - although it is safe to say Y here. - Only say Y here if running either a firewall that is the sole link to your network or a transparent proxy; never ever say Y here for a normal router or host. @@ -3868,7 +3860,7 @@ CONFIG_SCSI_NCR53C7xx_DISCONNECT NCR53C8XX SCSI support CONFIG_SCSI_NCR53C8XX - This is the BSD ncr driver adapted to linux for the NCR53C8XX family + This is the BSD ncr driver adapted to Linux for the NCR53C8XX family of PCI-SCSI controllers. This driver supports parity checking, tagged command queuing and fast synchronous data transfers up to 80 MB/s with wide FAST-40 LVD devices and controllers. @@ -8328,6 +8320,16 @@ CONFIG_APM_IGNORE_MULTIPLE_SUSPEND ignored. Without this the Thinkpad 560 has troubles with the user level daemon apmd, and with the PCMCIA package pcmcia-cs. +Ignore multiple suspend/resume cycles +CONFIG_APM_IGNORE_SUSPEND_BOUNCE + This option is necessary on the Dell Inspiron 3200, but should be + safe for all other laptops. When enabled, a system suspend event + that occurs within one second of a resume is ignored. Without this + the Inspiron will shut itself off a few seconds after you open the + lid, requiring you to press the power button to resume it a second + time. + Say Y. + Watchdog Timer Support CONFIG_WATCHDOG If you say Y here (and to one of the following options) and create a diff --git a/Makefile b/Makefile index c3b95e1f1df7..78dea7f6319c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 130 +SUBLEVEL = 131 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/config.in b/arch/alpha/config.in index 8b17580b541e..48e924fd7968 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -22,14 +22,6 @@ endmenu mainmenu_option next_comment comment 'General setup' -unset CONFIG_CROSSCOMPILE CONFIG_NATIVE - -if [ "`uname`" != "Linux" ]; then - define_bool CONFIG_CROSSCOMPILE y -else - define_bool CONFIG_NATIVE y -fi - choice 'Alpha system type' \ "Generic CONFIG_ALPHA_GENERIC \ Alcor/Alpha-XLT CONFIG_ALPHA_ALCOR \ diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 8f25f7020c82..1c7823397b7f 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -296,60 +296,82 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, * on SRM. It is more trouble than it iw worth to conditionalize this. */ -static struct { - struct reset_irq { - struct pci_dev *dev; - u8 irq; - } irq[16]; - int irq_count; - - struct reset_io { - struct pci_dev *dev; - u8 reg; - u32 io; - } io[16]; - int io_count; -} srm_resets; +struct srm_irq_reset { + struct srm_irq_reset *next; + struct pci_dev *dev; + u8 irq; +} *srm_irq_resets; + +struct srm_io_reset { + struct srm_io_reset *next; + struct pci_dev *dev; + u32 io; + u8 reg; +} *srm_io_resets; /* Apply the collected reset modifications. */ void reset_for_srm(void) { - struct pci_dev *dev; - int i; + struct srm_irq_reset *qreset; + struct srm_io_reset *ireset; /* Reset any IRQs that we changed. */ - for (i = 0; i < srm_resets.irq_count; i++) { - dev = srm_resets.irq[i].dev; - - pcibios_write_config_byte(dev->bus->number, dev->devfn, + for (qreset = srm_irq_resets; qreset ; qreset = qreset->next) { + pcibios_write_config_byte(qreset->dev->bus->number, + qreset->dev->devfn, PCI_INTERRUPT_LINE, - srm_resets.irq[i].irq); + qreset->irq); #if 1 printk("reset_for_srm: bus %d slot 0x%x " "SRM IRQ 0x%x changed back from 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - srm_resets.irq[i].irq, dev->irq); + qreset->dev->bus->number, + PCI_SLOT(qreset->dev->devfn), + qreset->irq, qreset->dev->irq); #endif } /* Reset any IO addresses that we changed. */ - for (i = 0; i < srm_resets.io_count; i++) { - dev = srm_resets.io[i].dev; - - pcibios_write_config_byte(dev->bus->number, dev->devfn, - srm_resets.io[i].reg, - srm_resets.io[i].io); + for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { + pcibios_write_config_dword(ireset->dev->bus->number, + ireset->dev->devfn, + ireset->reg, ireset->io); #if 1 printk("reset_for_srm: bus %d slot 0x%x " - "SRM IO restored to 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - srm_resets.io[i].io); + "SRM MEM/IO restored to 0x%x\n", + ireset->dev->bus->number, + PCI_SLOT(ireset->dev->devfn), + ireset->io); #endif } } +static void +new_irq_reset(struct pci_dev *dev, u8 irq) +{ + struct srm_irq_reset *n; + n = kmalloc(sizeof(*n), GFP_KERNEL); + + n->next = srm_irq_resets; + n->dev = dev; + n->irq = irq; + srm_irq_resets = n; +} + +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; +} + /* * Disable PCI device DEV so that it does not respond to I/O or memory @@ -426,6 +448,7 @@ layout_dev(struct pci_dev *dev) struct pci_bus *bus; unsigned short cmd; unsigned int base, mask, size, off, idx; + unsigned int orig_base; unsigned int alignto; unsigned long handle; @@ -467,6 +490,8 @@ layout_dev(struct pci_dev *dev) * Figure out how much space and of what type this * device wants. */ + pcibios_read_config_dword(bus->number, dev->devfn, off, + &orig_base); pcibios_write_config_dword(bus->number, dev->devfn, off, 0xffffffff); pcibios_read_config_dword(bus->number, dev->devfn, off, &base); @@ -504,8 +529,10 @@ layout_dev(struct pci_dev *dev) alignto = MAX(0x800, size); base = ALIGN(io_base, alignto); io_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, off, base | 0x1); + new_io_reset(dev, off, orig_base); handle = PCI_HANDLE(bus->number) | base | 1; dev->base_address[idx] = handle; @@ -582,8 +609,11 @@ layout_dev(struct pci_dev *dev) } } mem_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, off, base); + new_io_reset(dev, off, orig_base); + handle = PCI_HANDLE(bus->number) | base; dev->base_address[idx] = handle; @@ -596,9 +626,16 @@ layout_dev(struct pci_dev *dev) * addresses to be used. */ if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) { - pcibios_write_config_dword(bus->number, - dev->devfn, - off+4, 0); + unsigned int orig_base2; + pcibios_read_config_dword(bus->number, + dev->devfn, + off+4, &orig_base2); + if (0 != orig_base2) { + pcibios_write_config_dword(bus->number, + dev->devfn, + off+4, 0); + new_io_reset (dev, off+4, orig_base2); + } /* Bypass hi reg in the loop. */ dev->base_address[++idx] = 0; @@ -720,10 +757,9 @@ layout_bus(struct pci_bus *bus) PCI_IO_BASE, l); /* - * Also: - * clear out the upper 16 bits of IO base/limit. - * clear out the upper 32 bits of PREF base/limit. - */ + * Clear out the upper 16 bits of IO base/limit. + * Clear out the upper 32 bits of PREF base/limit. + */ pcibios_write_config_dword(bridge->bus->number, bridge->devfn, PCI_IO_BASE_UPPER16, 0); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, @@ -738,6 +774,7 @@ layout_bus(struct pci_bus *bus) l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, PCI_MEMORY_BASE, l); + /* * Turn off downstream PF memory address range, unless * there is a VGA behind this bridge, in which case, we @@ -839,7 +876,6 @@ check_behind_io(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; unsigned int reg, orig_base, new_base, found_one = 0; - struct reset_io *ior; for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { /* Read the current setting, check for I/O space and >= 64K */ @@ -870,10 +906,7 @@ printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n", pcibios_write_config_dword(bus->number, dev->devfn, reg, new_base); - ior = &srm_resets.io[srm_resets.io_count++]; - ior->dev = dev; - ior->reg = reg; - ior->io = orig_base; + new_io_reset(dev, reg, orig_base); found_one++; } @@ -990,8 +1023,6 @@ common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin), &irq_orig); if (irq_orig != dev->irq) { - struct reset_irq *r; - DBG_DEVS(("common_pci_fixup: bus %d " "slot 0x%x SRM IRQ 0x%x " "changed to 0x%x\n", @@ -999,9 +1030,7 @@ common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin), PCI_SLOT(dev->devfn), irq_orig, dev->irq)); - r = &srm_resets.irq[srm_resets.irq_count++]; - r->dev = dev; - r->irq = irq_orig; + new_irq_reset(dev, irq_orig); } } diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 0f6c843bc058..562778366da8 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -133,18 +133,15 @@ generic_kill_arch (int mode, char *restart_cmd) strncpy((char *)cpup->ipc_buffer, restart_cmd, sizeof(cpup->ipc_buffer)); } - } - else { + } else { flags |= 0x00040000UL; /* "remain halted" */ } cpup->flags = flags; mb(); - if (alpha_use_srm_setup) { - reset_for_srm(); - set_hae(srm_hae); - } + reset_for_srm(); + set_hae(srm_hae); #ifdef CONFIG_DUMMY_CONSOLE /* This has the effect of reseting the VGA video origin. */ @@ -156,10 +153,8 @@ generic_kill_arch (int mode, char *restart_cmd) /* Reset rtc to defaults. */ { unsigned char control; - unsigned long flags; - /* I'm not sure if i really need to disable interrupts here. */ - save_and_cli(flags); + cli(); /* Reset periodic interrupt frequency. */ CMOS_WRITE(0x26, RTC_FREQ_SELECT); @@ -170,7 +165,7 @@ generic_kill_arch (int mode, char *restart_cmd) CMOS_WRITE(control, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + sti(); } #endif diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index a94bd6bcaec5..f357830e34e0 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -43,12 +43,6 @@ #include "proto.h" -#if 1 -# define DBG_SRM(args) printk args -#else -# define DBG_SRM(args) -#endif - struct hwrpb_struct *hwrpb; unsigned long srm_hae; @@ -114,6 +108,7 @@ extern struct alpha_machine_vector lx164_mv; extern struct alpha_machine_vector miata_mv; extern struct alpha_machine_vector mikasa_mv; extern struct alpha_machine_vector mikasa_primo_mv; +extern struct alpha_machine_vector monet_mv; extern struct alpha_machine_vector noname_mv; extern struct alpha_machine_vector noritake_mv; extern struct alpha_machine_vector noritake_primo_mv; @@ -127,6 +122,34 @@ extern struct alpha_machine_vector sx164_mv; extern struct alpha_machine_vector takara_mv; extern struct alpha_machine_vector xl_mv; extern struct alpha_machine_vector xlt_mv; +#pragma weak alcor_mv +#pragma weak alphabook1_mv +#pragma weak avanti_mv +#pragma weak cabriolet_mv +#pragma weak dp264_mv +#pragma weak eb164_mv +#pragma weak eb64p_mv +#pragma weak eb66_mv +#pragma weak eb66p_mv +#pragma weak jensen_mv +#pragma weak lx164_mv +#pragma weak miata_mv +#pragma weak mikasa_mv +#pragma weak mikasa_primo_mv +#pragma weak monet_mv +#pragma weak noname_mv +#pragma weak noritake_mv +#pragma weak noritake_primo_mv +#pragma weak p2k_mv +#pragma weak pc164_mv +#pragma weak rawhide_mv +#pragma weak ruffian_mv +#pragma weak sable_mv +#pragma weak sable_gamma_mv +#pragma weak sx164_mv +#pragma weak takara_mv +#pragma weak xl_mv +#pragma weak xlt_mv void __init @@ -197,26 +220,18 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, cpu->type); } -#ifdef CONFIG_ALPHA_GENERIC if (!vec) { panic("Unsupported system type: %s%s%s (%ld %ld)\n", type_name, (*var_name ? " variation " : ""), var_name, hwrpb->sys_type, hwrpb->sys_variation); } - alpha_mv = *vec; + if (vec != &alpha_mv) + 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; -#else - /* Once we're sure we can reliably identify systems, we should - simply panic as we do above. */ - if (vec != &alpha_mv) { - printk("WARNING: Not configured for system type: %s%s%s " - "(%ld %ld)\nContinuing with trepidation...\n", - type_name, (*var_name ? " variation " : ""), var_name, - hwrpb->sys_type, hwrpb->sys_variation); - } #endif printk("Booting on %s%s%s using machine vector %s\n", @@ -361,7 +376,6 @@ static int tsunami_indices[] = {0,1,2,3,4,5,6,7,8}; static struct alpha_machine_vector * __init get_sysvec(long type, long variation, long cpu) { -#ifdef CONFIG_ALPHA_GENERIC static struct alpha_machine_vector *systype_vecs[] __initlocaldata = { NULL, /* 0 */ @@ -398,7 +412,7 @@ get_sysvec(long type, long variation, long cpu) NULL, /* XXM */ &takara_mv, NULL, /* Yukon */ - &dp264_mv, + NULL, /* Tsunami -- see variation. */ NULL, /* Wildfire */ NULL, /* CUSCO */ }; @@ -432,6 +446,19 @@ get_sysvec(long type, long variation, long cpu) &eb66p_mv }; + static struct alpha_machine_vector *tsunami_vecs[] __initlocaldata = + { + NULL, + &dp264_mv, /* dp164 */ + &dp264_mv, /* warhol */ + &dp264_mv, /* windjammer */ + &monet_mv, /* monet */ + &dp264_mv, /* clipper */ + &dp264_mv, /* goldrush */ + &dp264_mv, /* webbrick */ + &dp264_mv, /* catamaran */ + }; + /* ??? Do we need to distinguish between Rawhides? */ struct alpha_machine_vector *vec; @@ -472,6 +499,10 @@ get_sysvec(long type, long variation, long cpu) if (member < N(eb66_indices)) vec = eb66_vecs[eb66_indices[member]]; break; + case ST_DEC_TSUNAMI: + if (member < N(tsunami_indices)) + vec = tsunami_vecs[tsunami_indices[member]]; + break; case ST_DEC_1000: cpu &= 0xffffffff; if (cpu == EV5_CPU || cpu == EV56_CPU) @@ -496,17 +527,11 @@ get_sysvec(long type, long variation, long cpu) } } return vec; -#else - /* TODO: verify that the system is of the type for which we - were configured. For now, cop out and return success. */ - return &alpha_mv; -#endif /* GENERIC */ } static struct alpha_machine_vector * __init get_sysvec_byname(const char *name) { -#ifdef CONFIG_ALPHA_GENERIC static struct alpha_machine_vector *all_vecs[] __initlocaldata = { &alcor_mv, @@ -523,6 +548,7 @@ get_sysvec_byname(const char *name) &miata_mv, &mikasa_mv, &mikasa_primo_mv, + &monet_mv, &noname_mv, &noritake_mv, &noritake_primo_mv, @@ -545,11 +571,6 @@ get_sysvec_byname(const char *name) return mv; } return NULL; -#else - if (strcasecmp(alpha_mv.vector_name, name) == 0) - return &alpha_mv; - return NULL; -#endif } static void diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index a398c24c9359..9ac7abb3648e 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -32,16 +32,6 @@ #include "bios32.h" #include "machvec.h" -struct hwrpb_struct *hwrpb; - -/* hwrpb->sys_variation helpers */ -#define MEMBER_ID(x) (((x)>>10)&0x3f) - -#define DP264_ID 1 -#define MONET_ID 4 -#define GOLDRUSH_ID 6 -#define WEBBRICK_ID 7 - #define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index) /* @@ -301,28 +291,22 @@ static void __init dp264_pci_fixup(void) { layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(dp264_map_irq, common_swizzle); + SMC669_Init(); +} - /* must do map and/or swizzle different on some */ - switch (MEMBER_ID(hwrpb->sys_variation)) { - case MONET_ID: - common_pci_fixup(monet_map_irq, monet_swizzle); - /* es1888_init(); */ /* later? */ - break; - - case DP264_ID: - case GOLDRUSH_ID: - case WEBBRICK_ID: - default: - common_pci_fixup(dp264_map_irq, common_swizzle); - break; - } /* end MEMBER_ID switch */ - +static void __init +monet_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(monet_map_irq, monet_swizzle); + /* es1888_init(); */ /* later? */ SMC669_Init(); } /* - * The System Vector + * The System Vectors */ struct alpha_machine_vector dp264_mv __initmv = { @@ -347,3 +331,27 @@ struct alpha_machine_vector dp264_mv __initmv = { kill_arch: generic_kill_arch, }; ALIAS_MV(dp264) + +struct alpha_machine_vector monet_mv __initmv = { + vector_name: "Monet", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_TSUNAMI_IO, + DO_TSUNAMI_BUS, + machine_check: tsunami_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 64, + irq_probe_mask: _PROBE_MASK(64), + update_irq_hw: dp264_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: dp264_device_interrupt, + + init_arch: tsunami_init_arch, + init_irq: dp264_init_irq, + init_pit: generic_init_pit, + pci_fixup: monet_pci_fixup, + kill_arch: generic_kill_arch, +}; +/* No alpha_mv alias for monet, since we compile it in unconditionally + with DP264; setup_arch knows how to cope. */ diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index a5805750d992..a2c8ecb37b93 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -396,8 +396,6 @@ no_psmouse: cmp bx,#0x0504d ! check for "PM" signature jne done_apm_bios ! no signature -> no APM BIOS - mov [64],ax ! record the APM BIOS version - mov [76],cx ! and flags and cx,#0x02 ! Is 32 bit supported? je done_apm_bios ! no ... @@ -416,6 +414,26 @@ no_psmouse: mov [74],dx ! BIOS data segment mov [78],esi ! BIOS code segment length mov [82],di ! BIOS data segment length +! +! Redo the installation check as the 32 bit connect +! modifies the flags returned on some BIOSs +! + mov ax,#0x05300 ! APM BIOS installation check + xor bx,bx + int 0x15 + jc apm_disconnect ! error -> should not happen, tidy up + + cmp bx,#0x0504d ! check for "PM" signature + jne apm_disconnect ! no signature -> should not happen, tidy up + + mov [64],ax ! record the APM BIOS version + mov [76],cx ! and flags + jmp done_apm_bios + +apm_disconnect: + mov ax,#0x05304 ! Disconnect + xor bx,bx + int 0x15 ! ignore return code jmp done_apm_bios no_32_apm_bios: diff --git a/arch/i386/config.in b/arch/i386/config.in index 54448e7a3068..a22692bcab5e 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -72,6 +72,7 @@ if [ "$CONFIG_APM" = "y" ]; then bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK bool ' Power off on shutdown' CONFIG_APM_POWER_OFF bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE fi endmenu diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 88670e68d6cc..1cbc824f51d4 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -30,6 +30,7 @@ * Feb 1998, Version 1.4 * Aug 1998, Version 1.5 * Sep 1998, Version 1.6 + * Nov 1998, Version 1.7 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -60,6 +61,17 @@ * Fix OOPS at power off with no APM BIOS by Jan Echternach * * Stephen Rothwell + * 1.7: Modify driver's cached copy of the disabled/disengaged flags + * to reflect current state of APM BIOS. + * Chris Rankin + * Reset interrupt 0 timer to 100Hz after suspend + * Chad Miller + * Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE + * Richard Gooch + * Allow boot time disabling of APM + * Make boot messages far less verbose by default + * Make asm safer + * Stephen Rothwell * * APM 1.1 Reference: * @@ -167,7 +179,7 @@ extern unsigned long get_cmos_time(void); * * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant * [Confirmed by TI representative] - * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification + * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification * [Confirmed by BIOS disassembly] * [This may work now ...] * P: Toshiba 1950S: battery life information only gets updated after resume @@ -214,6 +226,19 @@ extern unsigned long get_cmos_time(void); */ #define APM_RELAX_SEGMENTS +/* + * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. + * This patched by Chad Miller , orig code by David + * Chen + */ +#undef INIT_TIMER_AFTER_SUSPEND + +#ifdef INIT_TIMER_AFTER_SUSPEND +#include +#include +#include +#endif + /* * Need to poll the APM BIOS every second */ @@ -267,13 +292,15 @@ static int waiting_for_resume = 0; static long clock_cmos_diff; static int got_clock_diff = 0; +static int debug = 0; +static int apm_disabled = 0; static struct wait_queue * process_list = NULL; static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; -static char driver_version[] = "1.6"; /* no spaces */ +static char driver_version[] = "1.7"; /* no spaces */ #ifdef APM_DEBUG static char * apm_event_name[] = { @@ -393,7 +420,7 @@ static const lookup_t error_table[] = { # define APM_DO_RESTORE_SEGS #endif -static inline u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in, +static u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi) { unsigned int saved_fs; @@ -404,13 +431,17 @@ static inline u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in, APM_DO_CLI; APM_DO_SAVE_SEGS; __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%al\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" APM_DO_POP_SEGS - : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx), - "=S" (*esi) + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx), + "=S" (*esi) : "a" (eax_in), "b" (ebx_in), "c" (ecx_in) - : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory", "cc"); + : "memory", "cc"); APM_DO_RESTORE_SEGS; __restore_flags(flags); return *eax & 0xff; @@ -420,7 +451,7 @@ static inline u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in, * This version only returns one value (usually an error code) */ -static inline u8 apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in, +static u8 apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in, u32 *eax) { u8 error; @@ -431,13 +462,22 @@ static inline u8 apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in, __save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; - __asm__ __volatile__(APM_DO_ZERO_SEGS - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" - "setc %%bl\n\t" - APM_DO_POP_SEGS - : "=a" (*eax), "=b" (error) - : "a" (eax_in), "b" (ebx_in), "c" (ecx_in) - : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory", "cc"); + { + int cx, dx, si; + + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "setc %%bl\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx), + "=S" (si) + : "a" (eax_in), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + } APM_DO_RESTORE_SEGS; __restore_flags(flags); return error; @@ -470,7 +510,7 @@ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) return APM_SUCCESS; } -static inline int set_power_state(u_short what, u_short state) +static int set_power_state(u_short what, u_short state) { u32 eax; @@ -499,7 +539,6 @@ static int apm_set_display_power_state(u_short state) #endif #ifdef CONFIG_APM_DO_ENABLE -/* Called by apm_setup if apm_enabled will be true. */ static int apm_enable_power_management(void) { u32 eax; @@ -508,6 +547,7 @@ static int apm_enable_power_management(void) (apm_bios_info.version > 0x100) ? 0x0001 : 0xffff, 1, &eax)) return (eax >> 8) & 0xff; + apm_bios_info.flags &= ~APM_BIOS_DISABLED; return APM_SUCCESS; } #endif @@ -574,9 +614,10 @@ static void apm_error(char *str, int err) for (i = 0; i < ERROR_COUNT; i++) if (error_table[i].key == err) break; if (i < ERROR_COUNT) - printk(KERN_NOTICE "apm_bios: %s: %s\n", str, error_table[i].msg); + printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg); else - printk(KERN_NOTICE "apm_bios: %s: unknown error code %#2.2x\n", str, err); + printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n", + str, err); } /* Called from console driver -- must make sure apm_enabled. */ @@ -629,7 +670,6 @@ void apm_unregister_callback(int (*callback)(apm_event_t)) callback_list_t ** ptr; callback_list_t * old; - ptr = &callback_list; for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next) if ((*ptr)->callback == callback) break; @@ -663,7 +703,7 @@ static int queue_event(apm_event_t event, struct apm_bios_struct *sender) static int notified; if (notified == 0) { - printk( "apm_bios: an event queue overflowed\n" ); + printk(KERN_ERR "apm: an event queue overflowed\n"); notified = 1; } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; @@ -719,6 +759,18 @@ static void suspend(void) err = apm_set_power_state(APM_STATE_SUSPEND); if (err) apm_error("suspend", err); +#ifdef INIT_TIMER_AFTER_SUSPEND + save_flags(flags); + cli(); + /* set the clock to 100 Hz */ + outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + udelay(10); + outb_p(LATCH & 0xff , 0x40); /* LSB */ + udelay(10); + outb(LATCH >> 8 , 0x40); /* MSB */ + udelay(10); + restore_flags(flags); +#endif set_time(); } @@ -771,24 +823,27 @@ static void send_event(apm_event_t event, apm_event_t undo, static void check_events(void) { - apm_event_t event; + apm_event_t event; +#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE + static unsigned long last_resume = 0; + static int did_resume = 0; +#endif while ((event = get_event()) != 0) { #ifdef APM_DEBUG if (event <= NR_APM_EVENT_NAME) - printk(KERN_DEBUG "APM BIOS received %s notify\n", + printk(KERN_DEBUG "apm: received %s notify\n", apm_event_name[event - 1]); else - printk(KERN_DEBUG "APM BIOS received unknown " + printk(KERN_DEBUG "apm: received unknown " "event 0x%02x\n", event); #endif switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND - if (waiting_for_resume) { - return; - } + if (waiting_for_resume) + return; waiting_for_resume = 1; #endif send_event(event, APM_STANDBY_RESUME, NULL); @@ -803,10 +858,13 @@ static void check_events(void) break; #endif case APM_SYS_SUSPEND: +#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE + if (did_resume && ((jiffies - last_resume) < HZ)) + break; +#endif #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND - if (waiting_for_resume) { - return; - } + if (waiting_for_resume) + return; waiting_for_resume = 1; #endif send_event(event, APM_NORMAL_RESUME, NULL); @@ -819,6 +877,10 @@ static void check_events(void) case APM_STANDBY_RESUME: #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 0; +#endif +#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE + last_resume = jiffies; + did_resume = 1; #endif set_time(); send_event(event, 0, NULL); @@ -905,7 +967,7 @@ void apm_do_busy(void) static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func) { if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { - printk(KERN_ERR "apm_bios: %s passed bad filp", func); + printk(KERN_ERR "apm: %s passed bad filp", func); return 1; } return 0; @@ -1041,7 +1103,7 @@ static int do_release(struct inode * inode, struct file * filp) as1 = as1->next) ; if (as1 == NULL) - printk(KERN_ERR "apm_bios: filp not in user list"); + printk(KERN_ERR "apm: filp not in user list"); else as1->next = as->next; } @@ -1055,7 +1117,7 @@ static int do_open(struct inode * inode, struct file * filp) as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL); if (as == NULL) { - printk(KERN_ERR "apm_bios: cannot allocate struct of size %d bytes", + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes", sizeof(*as)); return -ENOMEM; } @@ -1168,6 +1230,26 @@ int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy) } #endif +void __init apm_setup(char *str, int *dummy) +{ + int invert; + + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + apm_disabled = 1; + if (strncmp(str, "on", 2) == 0) + apm_disabled = 0; + invert = (strncmp(str, "no-", 3) == 0); + if (invert) + str += 3; + if (strncmp(str, "debug", 5) == 0) + debug = !invert; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } +} + void __init apm_bios_init(void) { unsigned short bx; @@ -1178,23 +1260,18 @@ void __init apm_bios_init(void) char * bat_stat; static struct proc_dir_entry *ent; -#ifdef __SMP__ - if (smp_num_cpus > 1) { - printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n"); - return; - } -#endif if (apm_bios_info.version == 0) { - printk(KERN_INFO "APM BIOS not found.\n"); + printk(KERN_INFO "apm: BIOS not found.\n"); return; } - printk(KERN_INFO "APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n", - ((apm_bios_info.version >> 8) & 0xff) + '0', - (apm_bios_info.version & 0xff) + '0', - apm_bios_info.flags, - driver_version); + printk(KERN_INFO + "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", + ((apm_bios_info.version >> 8) & 0xff), + (apm_bios_info.version & 0xff), + apm_bios_info.flags, + driver_version); if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { - printk(KERN_INFO " No 32 bit BIOS support\n"); + printk(KERN_INFO "apm: no 32 bit BIOS support\n"); return; } @@ -1209,14 +1286,28 @@ void __init apm_bios_init(void) if (apm_bios_info.version < 0x102) apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */ - printk(KERN_INFO " Entry %x:%lx cseg16 %x dseg %x", - apm_bios_info.cseg, apm_bios_info.offset, - apm_bios_info.cseg_16, apm_bios_info.dseg); - if (apm_bios_info.version > 0x100) - printk(" cseg len %x, cseg16 len %x, dseg len %x", - apm_bios_info.cseg_len, apm_bios_info.cseg_16_len, - apm_bios_info.dseg_len); - printk("\n"); + if (debug) { + printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x", + apm_bios_info.cseg, apm_bios_info.offset, + apm_bios_info.cseg_16, apm_bios_info.dseg); + if (apm_bios_info.version > 0x100) + printk(" cseg len %x, cseg16 len %x, dseg len %x", + apm_bios_info.cseg_len, + apm_bios_info.cseg_16_len, + apm_bios_info.dseg_len); + printk("\n"); + } + + if (apm_disabled) { + printk(KERN_NOTICE "apm: disabled on user request.\n"); + return; + } +#ifdef __SMP__ + if (smp_num_cpus > 1) { + printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + return; + } +#endif /* * Set up a segment that references the real mode segment 0x40 @@ -1253,74 +1344,78 @@ void __init apm_bios_init(void) set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len); set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len); #endif - /* The APM 1.2 docs state that the apm_driver_version - * call can fail if we try to connect as 1.2 to a 1.1 bios. + /* + * We only support BIOSs up to version 1.2 */ - apm_bios_info.version = 0x0102; - error = apm_driver_version(&apm_bios_info.version); - if (error != APM_SUCCESS) { /* Fall back to an APM 1.1 connection. */ - apm_bios_info.version = 0x0101; - error = apm_driver_version(&apm_bios_info.version); - } - if (error != APM_SUCCESS) /* Fall back to an APM 1.0 connection. */ + if (apm_bios_info.version > 0x0102) + apm_bios_info.version = 0x0102; + if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) { + /* Fall back to an APM 1.0 connection. */ apm_bios_info.version = 0x100; - else { - apm_engage_power_management(0x0001); - printk( " Connection version %d.%d\n", - (apm_bios_info.version >> 8) & 0xff, - apm_bios_info.version & 0xff ); } } - - error = apm_get_power_status(&bx, &cx, &dx); - if (error) - printk(KERN_INFO " Power status not available\n"); - else { - switch ((bx >> 8) & 0xff) { - case 0: power_stat = "off line"; break; - case 1: power_stat = "on line"; break; - case 2: power_stat = "on backup power"; break; - default: power_stat = "unknown"; break; - } - switch (bx & 0xff) { - case 0: bat_stat = "high"; break; - case 1: bat_stat = "low"; break; - case 2: bat_stat = "critical"; break; - case 3: bat_stat = "charging"; break; - default: bat_stat = "unknown"; break; - } - printk(KERN_INFO " AC %s, battery status %s, battery life ", - power_stat, bat_stat); - if ((cx & 0xff) == 0xff) - printk("unknown\n"); - else - printk("%d%%\n", cx & 0xff); - if (apm_bios_info.version > 0x100) { - printk(" battery flag 0x%02x, battery life ", - (cx >> 8) & 0xff); - if (dx == 0xffff) + if (debug) { + printk(KERN_INFO "apm: onnection version %d.%d\n", + (apm_bios_info.version >> 8) & 0xff, + apm_bios_info.version & 0xff ); + + error = apm_get_power_status(&bx, &cx, &dx); + if (error) + printk(KERN_INFO "apm: power status not available\n"); + else { + switch ((bx >> 8) & 0xff) { + case 0: power_stat = "off line"; break; + case 1: power_stat = "on line"; break; + case 2: power_stat = "on backup power"; break; + default: power_stat = "unknown"; break; + } + switch (bx & 0xff) { + case 0: bat_stat = "high"; break; + case 1: bat_stat = "low"; break; + case 2: bat_stat = "critical"; break; + case 3: bat_stat = "charging"; break; + default: bat_stat = "unknown"; break; + } + printk(KERN_INFO "apm: AC %s, battery status %s, battery life ", + power_stat, bat_stat); + if ((cx & 0xff) == 0xff) printk("unknown\n"); - else { - if ((dx & 0x8000)) - printk("%d minutes\n", dx & 0x7ffe ); - else - printk("%d seconds\n", dx & 0x7fff ); + else + printk("%d%%\n", cx & 0xff); + if (apm_bios_info.version > 0x100) { + printk("apm: battery flag 0x%02x, battery life ", + (cx >> 8) & 0xff); + if (dx == 0xffff) + printk("unknown\n"); + else { + if ((dx & 0x8000)) + printk("%d minutes\n", dx & 0x7ffe ); + else + printk("%d seconds\n", dx & 0x7fff ); + } } } } #ifdef CONFIG_APM_DO_ENABLE - /* - * This call causes my NEC UltraLite Versa 33/C to hang if it is - * booted with PM disabled but not in the docking station. - * Unfortunate ... - */ - error = apm_enable_power_management(); - if (error) - apm_error("enable power management", error); - if (error == APM_DISABLED) - return; + if (apm_bios_info.flags & APM_BIOS_DISABLED) { + /* + * This call causes my NEC UltraLite Versa 33/C to hang if it + * is booted with PM disabled but not in the docking station. + * Unfortunate ... + */ + error = apm_enable_power_management(); + if (error) { + apm_error("enable power management", error); + return; + } + } #endif + if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0) + && (apm_bios_info.version > 0x0100)) { + if (apm_engage_power_management(0x0001) == APM_SUCCESS) + apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + } init_timer(&apm_timer); apm_timer.function = do_apm_timer; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 4ddefa931b2e..00f39d4ed5ed 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -102,44 +102,25 @@ static void hard_idle(void) /* * The idle loop on a uniprocessor i386.. - */ - -asmlinkage int sys_idle(void) + */ +static int cpu_idle(void *unused) { - unsigned long start_idle = 0; - int ret = -EPERM; + unsigned long start_idle = jiffies; - lock_kernel(); - if (current->pid != 0) - goto out; /* endless idle loop with no priority at all */ - current->priority = 0; - current->counter = 0; for (;;) { - /* - * We are locked at this point. So we can safely call - * the APM bios knowing only one CPU at a time will do - * so. - */ - if (!start_idle) { - check_pgt_cache(); - start_idle = jiffies; - } if (jiffies - start_idle > HARD_IDLE_TIMEOUT) hard_idle(); else { if (boot_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) __asm__("hlt"); } - run_task_queue(&tq_scheduler); if (current->need_resched) - start_idle = 0; + start_idle = jiffies; + current->policy = SCHED_YIELD; schedule(); + check_pgt_cache(); } - ret = 0; -out: - unlock_kernel(); - return ret; } #else @@ -150,21 +131,19 @@ out: int cpu_idle(void *unused) { - current->priority = 0; - while(1) - { - if(current_cpu_data.hlt_works_ok && - !hlt_counter && !current->need_resched) - __asm("hlt"); - check_pgt_cache(); - run_task_queue(&tq_scheduler); - /* endless idle loop with no priority at all */ - current->counter = 0; + /* endless idle loop with no priority at all */ + while(1) { + if (current_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) + __asm__("hlt"); + current->policy = SCHED_YIELD; schedule(); + check_pgt_cache(); } } +#endif + asmlinkage int sys_idle(void) { if (current->pid != 0) @@ -173,8 +152,6 @@ asmlinkage int sys_idle(void) return 0; } -#endif - /* * This routine reboots the machine by asking the keyboard * controller to pulse the reset-line low. We try that for a while, @@ -509,23 +486,27 @@ void release_segments(struct mm_struct *mm) */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { - long retval; + long retval, d0; __asm__ __volatile__( "movl %%esp,%%esi\n\t" "int $0x80\n\t" /* Linux/i386 system call */ "cmpl %%esp,%%esi\n\t" /* child or parent? */ "je 1f\n\t" /* parent - jump */ - "pushl %3\n\t" /* push argument */ - "call *%4\n\t" /* call fn */ - "movl %2,%0\n\t" /* exit */ + /* Load the argument into eax, and push it. That way, it does + * not matter whether the called function is compiled with + * -mregparm or not. */ + "movl %4,%%eax\n\t" + "pushl %%eax\n\t" + "call *%5\n\t" /* call fn */ + "movl %3,%0\n\t" /* exit */ "int $0x80\n" "1:\t" - :"=a" (retval) + :"=&a" (retval), "=&S" (d0) :"0" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), "b" (flags | CLONE_VM) - :"si"); + : "memory"); return retval; } diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index e6ed37c3b330..c0aa02d66956 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -592,7 +592,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) +int do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; struct k_sigaction *ka; diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 5b3908cddf4a..d181dc6994bd 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -63,7 +63,7 @@ #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1) asmlinkage struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); -asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) +struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) { struct pt_regs *ret; unsigned long tmp; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index aed7ecc55917..693072b1a5d5 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -293,11 +293,18 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ * extended bios data area. * * there is a real-mode segmented pointer pointing to the - * 4K EBDA area at 0x40E, calculate and scan it here: + * 4K EBDA area at 0x40E, calculate and scan it here. + * + * NOTE! There are Linux loaders that will corrupt the EBDA + * area, and as such this kind of SMP config may be less + * trustworthy, simply because the SMP table may have been + * stomped on during early boot. */ address = *(unsigned short *)phys_to_virt(0x40E); address<<=4; smp_scan_config(address, 0x1000); + if (smp_found_config) + printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n"); } #endif start_mem = PAGE_ALIGN(start_mem); diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 740f4551fbbb..28250b0bd206 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -84,11 +84,16 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, * Remap an arbitrary physical address space into the kernel virtual * address space. Needed when the kernel wants to access high addresses * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. */ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { void * addr; struct vm_struct * area; + unsigned long offset; /* * Don't remap the low PCI/ISA area, it's always mapped.. @@ -105,9 +110,9 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag /* * Mappings have to be page-aligned */ - if (phys_addr & ~PAGE_MASK) - return NULL; - size = PAGE_ALIGN(size); + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(size + offset); /* * Don't allow mappings that wrap.. @@ -126,11 +131,11 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag vfree(addr); return NULL; } - return addr; + return (void *) (offset + (char *)addr); } void iounmap(void *addr) { if (addr > high_memory) - return vfree(addr); + return vfree((void *) (PAGE_MASK & (unsigned long) addr)); } diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 65d2f77477f7..38042ee458f6 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -201,7 +201,12 @@ void handle_scancode(unsigned char scancode) add_keyboard_randomness(scancode); tty = ttytab? ttytab[fg_console]: NULL; - kbd = kbd_table + fg_console; + if (tty && (!tty->driver_data)) { + /* This is to workaround ugly bug in tty_io.c, which + does not do locking when it should */ + tty = NULL; + } + kbd = kbd_table + fg_console; if ((raw_mode = (kbd->kbdmode == VC_RAW))) { put_queue(scancode); /* we do not return yet, because we want to maintain diff --git a/drivers/char/lp.c b/drivers/char/lp.c index baec5e4cb11d..ae769f619570 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -16,8 +16,17 @@ * Parport sharing hacking by Andrea Arcangeli * Fixed kernel_(to/from)_user memory copy to check for errors * by Riccardo Facchetti - * Interrupt handling workaround for printers with buggy handshake - * by Andrea Arcangeli, 11 May 98 + * Redesigned interrupt handling for handle printers with buggy handshake + * by Andrea Arcangeli, 11 May 1998 + * Full efficient handling of printer with buggy irq handshake (now I have + * understood the meaning of the strange handshake). This is done sending new + * characters if the interrupt is just happened, even if the printer say to + * be still BUSY. This is needed at least with Epson Stylus Color. To enable + * the new TRUST_IRQ mode read the `LP OPTIMIZATION' section below... + * Fixed the irq on the rising edge of the strobe case. + * Obsoleted the CAREFUL flag since a printer that doesn' t work with + * CAREFUL will block a bit after in lp_check_status(). + * Andrea Arcangeli, 15 Oct 1998 */ /* This driver should, in theory, work with any parallel port that has an @@ -49,6 +58,74 @@ * # insmod lp.o reset=1 */ +/* + * LP OPTIMIZATIONS + * + * - TRUST_IRQ flag + * + * Epson Stylus Color, HP and many other new printers want the TRUST_IRQ flag + * set when printing with interrupts. This is a long story. Such printers + * use a broken handshake (see the timing graph below) when printing with + * interrupts. The lp driver as default is just able to handle such bogus + * handshake, but setting such flag cause lp to go faster and probably do + * what such printers want (even if not documented). + * + * NOTE that setting the TRUST_IRQ flag in some printer can cause the irq + * printing to fail completly. You must try, to know if your printer + * will handle it. I suggest a graphics printing to force a major flow of + * characters to the printer for do the test. NOTE also that the TRUST_IRQ + * flag _should_ be fine everywhere but there is a lot of buggy hardware out + * there, so I am forced to implement it as a not-default thing. + * WARNING: before to do the test, be sure to have not played with the + * `-w' parameter of tunelp! + * + * Note also that lp automagically warn you (with a KERN_WARNING) if it + * detects that you could _try_ to set the TRUST_IRQ flag to speed up the + * printing and decrease the CPU load. + * + * To set the TRUST_IRQ flag you can use this command: + * + * tunelp /dev/lp? -T on + * + * If you have an old tunelp executable you can (hack and) use this simple + * C lazy proggy to set the flag in the lp driver: + +-------------------------- cut here ------------------------------------- +#include +#include + +#define LPTRUSTIRQ 0x060f + +int main(int argc, char **argv) +{ + int fd = open("/dev/lp0", O_RDONLY); + ioctl(fd, LPTRUSTIRQ, argc - 1); + if (argc - 1) + printf("trusting the irq\n"); + else + printf("untrusting the irq\n"); + return 0; +} +-------------------------- cut here ------------------------------------- + + * - LP_WAIT time + * + * You can use this setting if your printer is fast enough and/or your + * machine is slow enough ;-). + * + * tunelp /dev/lp? -w 0 + * + * - LP_CHAR tries + * + * If you print with irqs probably you can decrease the CPU load a lot using + * this setting. This is not the default because the printing is reported to + * be jerky somewhere... + * + * tunelp /dev/lp? -c 1 + * + * 11 Nov 1998, Andrea Arcangeli + */ + /* COMPATIBILITY WITH OLD KERNELS * * Under Linux 2.0 and previous versions, lp devices were bound to ports at @@ -79,6 +156,12 @@ * ftp://e-mind.com/pub/linux/pscan/ * * 11 May 98, Andrea Arcangeli + * + * My printer scanner run on an Epson Stylus Color show that such printer + * generates the irq on the _rising_ edge of the STROBE. Now lp handle + * this case fine too. + * + * 15 Oct 1998, Andrea Arcangeli */ #include @@ -95,7 +178,6 @@ #include #undef LP_STATS -#undef LP_NEED_CAREFUL #include #include @@ -115,16 +197,14 @@ struct lp_struct lp_table[LP_NO] = NULL, 0, 0, 0} }; -/* Test if printer is ready (and optionally has no error conditions) */ -#ifdef LP_NEED_CAREFUL -#define LP_READY(minor, status) \ - ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : ((status) & LP_PBUSY)) -#define _LP_CAREFUL_READY(status) \ - ((status) & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ - (LP_PBUSY|LP_PSELECD|LP_PERRORP) -#else -#define LP_READY(minor, status) ((status) & LP_PBUSY) -#endif +/* Test if printer is ready */ +#define LP_READY(status) ((status) & LP_PBUSY) +/* Test if the printer is not acking the strobe */ +#define LP_NO_ACKING(status) ((status) & LP_PACK) +/* Test if the printer has error conditions */ +#define LP_NO_ERROR(status) \ + (((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ + (LP_PSELECD|LP_PERRORP)) #undef LP_DEBUG #undef LP_READ_DEBUG @@ -187,60 +267,124 @@ static int lp_reset(int minor) return retval; } +#define lp_wait(minor) udelay(LP_WAIT(minor)) + static inline int lp_char(char lpchar, int minor) { - unsigned int wait = 0; unsigned long count = 0; #ifdef LP_STATS struct lp_stats *stats; #endif + if (signal_pending(current)) + return 0; + for (;;) { + unsigned char status; + int irq_ok = 0; + + /* + * Give a chance to other pardevice to run in the meantime. + */ lp_yield(minor); - if (LP_READY(minor, r_str(minor))) - break; - if (++count == LP_CHAR(minor) || signal_pending(current)) - return 0; + + status = r_str(minor); + if (LP_NO_ERROR(status)) + { + if (LP_READY(status)) + break; + + /* + * This is a crude hack that should be well known + * at least by Epson device driver developers. -arca + */ + irq_ok = (!LP_POLLED(minor) && + LP_NO_ACKING(status) && + lp_table[minor].irq_detected); + if ((LP_F(minor) & LP_TRUST_IRQ) && irq_ok) + break; + } + /* + * NOTE: if you run with irqs you _must_ use + * `tunelp /dev/lp? -c 1' to be rasonable efficient! + */ + if (++count == LP_CHAR(minor)) + { + if (irq_ok) + { + static int first_time = 1; + /* + * The printer is using a buggy handshake, so + * revert to polling to not overload the + * machine and warn the user that its printer + * could get optimized trusting the irq. -arca + */ + lp_table[minor].irq_missed = 1; + if (first_time) + { + first_time = 0; + printk(KERN_WARNING "lp%d: the " + "printing could be optimized " + "using the TRUST_IRQ flag, " + "see the top of " + "linux/drivers/char/lp.c\n", + minor); + } + } + return 0; + } } w_dtr(minor, lpchar); + #ifdef LP_STATS stats = &LP_STAT(minor); stats->chars++; #endif + /* must wait before taking strobe high, and after taking strobe low, according spec. Some printers need it, others don't. */ -#ifndef __sparc__ - while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */ - wait++; -#else - udelay(1); -#endif + lp_wait(minor); + /* control port takes strobe high */ - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE); -#ifndef __sparc__ - while (wait) /* FIXME: should be a udelay() */ - wait--; -#else - udelay(1); -#endif - /* take strobe low */ if (LP_POLLED(minor)) - /* take strobe low */ - w_ctr(minor, LP_PSELECP | LP_PINITP); - else { + w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE); + lp_wait(minor); + w_ctr(minor, LP_PSELECP | LP_PINITP); + } else { + /* + * Epson Stylus Color generate the IRQ on the rising edge of + * strobe so clean the irq's information before playing with + * the strobe. -arca + */ lp_table[minor].irq_detected = 0; lp_table[minor].irq_missed = 0; + /* + * Be sure that the CPU doesn' t reorder instructions. -arca + */ + mb(); + w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN); + lp_wait(minor); w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); } + /* + * Give to the printer a chance to put BUSY low. Really we could + * remove this because we could _guess_ that we are slower to reach + * again lp_char() than the printer to put BUSY low, but I' d like + * to remove this variable from the function I go solve + * when I read bug reports ;-). -arca + */ + lp_wait(minor); + #ifdef LP_STATS /* update waittime statistics */ if (count > stats->maxwait) { #ifdef LP_DEBUG - printk(KERN_DEBUG "lp%d success after %d counts.\n", minor, count); + printk(KERN_DEBUG "lp%d success after %d counts.\n", + minor, count); #endif stats->maxwait = count; } @@ -325,7 +469,10 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count) lp_table[minor].irq_detected = 0; lp_table[minor].irq_missed = 1; - w_ctr(minor, LP_PSELECP | LP_PINITP); + if (LP_POLLED(minor)) + w_ctr(minor, LP_PSELECP | LP_PINITP); + else + w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); do { bytes_written = 0; @@ -396,9 +543,7 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count) goto lp_polling; } if (!lp_table[minor].irq_detected) - { interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT); - } sti(); } } @@ -453,101 +598,97 @@ static int lp_read_nibble(int minor) return (i & 0x0f); } -static inline void lp_select_in_high(int minor) -{ - parport_frob_control(lp_table[minor].dev->port, 8, 8); +static void lp_read_terminate(struct parport *port) { + parport_write_control(port, (parport_read_control(port) & ~2) | 8); + /* SelectIN high, AutoFeed low */ + if (parport_wait_peripheral(port, 0x80, 0)) + /* timeout, SelectIN high, Autofeed low */ + return; + parport_write_control(port, parport_read_control(port) | 2); + /* AutoFeed high */ + parport_wait_peripheral(port, 0x80, 0x80); + /* no timeout possible, Autofeed low, SelectIN high */ + parport_write_control(port, (parport_read_control(port) & ~2) | 8); } /* Status readback confirming to ieee1284 */ static ssize_t lp_read(struct file * file, char * buf, - size_t count, loff_t *ppos) + size_t length, loff_t *ppos) { - unsigned char z=0, Byte=0, status; - char *temp; - ssize_t retval; - unsigned int counter=0; - unsigned int i; + int i; unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); - - /* Claim Parport or sleep until it becomes available - */ - lp_parport_claim (minor); + char *temp = buf; + ssize_t count = 0; + unsigned char z = 0; + unsigned char Byte = 0; + struct parport *port = lp_table[minor].dev->port; - temp=buf; -#ifdef LP_READ_DEBUG - printk(KERN_INFO "lp%d: read mode\n", minor); -#endif + lp_parport_claim (minor); - retval = verify_area(VERIFY_WRITE, buf, count); - if (retval) - return retval; - if (parport_ieee1284_nibble_mode_ok(lp_table[minor].dev->port, 0)==0) { -#ifdef LP_READ_DEBUG - printk(KERN_INFO "lp%d: rejected IEEE1284 negotiation.\n", - minor); -#endif - lp_select_in_high(minor); - parport_release(lp_table[minor].dev); - return temp-buf; /* End of file */ + switch (parport_ieee1284_nibble_mode_ok(port, 0)) + { + case 0: + /* Handshake failed. */ + lp_read_terminate(port); + lp_parport_release (minor); + return -EIO; + case 1: + /* No data. */ + lp_read_terminate(port); + lp_parport_release (minor); + return 0; + default: + /* Data available. */ + + /* Hack: Wait 10ms (between events 6 and 7) */ + schedule_timeout((HZ+99)/100); + break; } - for (i=0; i<=(count*2); i++) { - parport_frob_control(lp_table[minor].dev->port, 2, 2); /* AutoFeed high */ - do { - status = (r_str(minor) & 0x40); - udelay(50); - counter++; - if (current->need_resched) - schedule (); - } while ((status == 0x40) && (counter < 20)); - if (counter == 20) { - /* Timeout */ + + for (i=0; ; i++) { + parport_frob_control(port, 2, 2); /* AutoFeed high */ + if (parport_wait_peripheral(port, 0x40, 0)) { #ifdef LP_READ_DEBUG - printk(KERN_DEBUG "lp_read: (Autofeed high) timeout\n"); + /* Some peripherals just time out when they've sent + all their data. */ + printk("%s: read1 timeout.\n", port->name); #endif - parport_frob_control(lp_table[minor].dev->port, 2, 0); - lp_select_in_high(minor); - parport_release(lp_table[minor].dev); - return temp-buf; /* end the read at timeout */ + parport_frob_control(port, 2, 0); /* AutoFeed low */ + break; } - counter=0; z = lp_read_nibble(minor); - parport_frob_control(lp_table[minor].dev->port, 2, 0); /* AutoFeed low */ - do { - status=(r_str(minor) & 0x40); - udelay(20); - counter++; - if (current->need_resched) - schedule (); - } while ( (status == 0) && (counter < 20) ); - if (counter == 20) { /* Timeout */ -#ifdef LP_READ_DEBUG - printk(KERN_DEBUG "lp_read: (Autofeed low) timeout\n"); -#endif - if (signal_pending(current)) { - lp_select_in_high(minor); - parport_release(lp_table[minor].dev); - if (temp !=buf) - return temp-buf; - else - return -EINTR; - } - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(LP_TIME(minor)); + parport_frob_control(port, 2, 0); /* AutoFeed low */ + if (parport_wait_peripheral(port, 0x40, 0x40)) { + printk("%s: read2 timeout.\n", port->name); + break; } + if ((i & 1) != 0) { + Byte |= (z<<4); + if (temp) { + if (__put_user (Byte, temp)) + { + count = -EFAULT; + temp = NULL; + } else { + temp++; - counter=0; - - if (( i & 1) != 0) { - Byte= (Byte | z<<4); - if (__put_user(Byte, (char *)temp)) - return -EFAULT; - temp++; - } else Byte=z; + if (++count == length) + temp = NULL; + } + } + /* Does the error line indicate end of data? */ + if ((parport_read_status(port) & LP_PERRORP) == + LP_PERRORP) + break; + } else + Byte=z; } - lp_select_in_high(minor); - lp_parport_release(minor); - return temp-buf; + lp_read_terminate(port); + + lp_parport_release (minor); + + return count; } #endif @@ -645,7 +786,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, else LP_F(minor) &= ~LP_ABORTOPEN; break; -#ifdef LP_NEED_CAREFUL +#ifdef OBSOLETED case LPCAREFUL: if (arg) LP_F(minor) |= LP_CAREFUL; @@ -653,6 +794,12 @@ static int lp_ioctl(struct inode *inode, struct file *file, LP_F(minor) &= ~LP_CAREFUL; break; #endif + case LPTRUSTIRQ: + if (arg) + LP_F(minor) |= LP_TRUST_IRQ; + else + LP_F(minor) &= ~LP_TRUST_IRQ; + break; case LPWAIT: LP_WAIT(minor) = arg; break; @@ -696,7 +843,6 @@ static int lp_ioctl(struct inode *inode, struct file *file, return retval; } - static struct file_operations lp_fops = { lp_lseek, #ifdef CONFIG_PRINTER_READBACK diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6fe15f239d05..ee2e7e099a27 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -868,7 +868,13 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty) * Failures after this point use release_mem to clean up, so * there's no need to null out the local pointers. */ - driver->table[idx] = tty; + driver->table[idx] = tty; /* FIXME: this is broken and + probably causes ^D bug. tty->private_date does not (yet) point + to a console, if keypress comes now, await armagedon. + + also, driver->table is accessed from interrupt for vt case, + and this does not look like atomic access at all. */ + if (!*tp_loc) *tp_loc = tp; if (!*ltp_loc) diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx index c3a2550d198f..e7af08c0cf3a 100644 --- a/drivers/scsi/ChangeLog.ncr53c8xx +++ b/drivers/scsi/ChangeLog.ncr53c8xx @@ -1,3 +1,19 @@ +Thu Nov 26 22:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.1d + - The SISL RAID change requires now remap_pci_mem() stuff to be + compiled for __i386__ when normal IOs are used. + - Minor spelling fixes in doc files. + +Sat Nov 21 18:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.1c + - Ignore chips that are driven by SISL RAID (DAC 960). + Change sent by Leonard Zubkoff and slightly reworked. + - Still a buglet in the tags initial settings that needed to be fixed. + It was not possible to disable TGQ at system startup for devices + that claim TGQ support. The driver used at least 2 for the queue + depth but did'nt keep track of user settings for tags depth lower + than 2. + Wed Nov 11 10:00 1998 Gerard Roudier (groudier@club-internet.fr) * revision 3.1b - The driver was unhappy when configured with default_tags > MAX_TAGS diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx index eb11ccb39fb2..409967d0ee6c 100644 --- a/drivers/scsi/README.ncr53c8xx +++ b/drivers/scsi/README.ncr53c8xx @@ -4,7 +4,7 @@ Written by Gerard Roudier 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -18 October 1998 +22 November 1998 =============================================================================== 1. Introduction @@ -853,7 +853,7 @@ SCSI_NCR_SETUP_SPECIAL_FEATURES (default: defined) For 810A, 860, 825A, 875 and 895 scsi chips, this option enables support of features that reduce load of PCI bus and memory accesses during scsi transfer processing: burst op-code fetch, read multiple, - read line, prefetch, cache line line, write and invalidate, + read line, prefetch, cache line, write and invalidate, burst 128 (875 only), large dma fifo (875 only), offset 16 (875 only). Can be changed by the following boot setup command: ncr53c8xx=specf:n diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index dbfe1b177676..7057b75359ea 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -73,7 +73,7 @@ */ /* -** November 11 1998, version 3.1b +** November 26 1998, version 3.1d ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -582,7 +582,7 @@ static spinlock_t driver_lock; #define bus_dvma_to_mem(p) (p) #endif -#ifndef NCR_IOMAPPED +#if defined(__i386__) || !defined(NCR_IOMAPPED) __initfunc( static vm_offset_t remap_pci_mem(u_long base, u_long size) ) @@ -601,7 +601,7 @@ static void unmap_pci_mem(vm_offset_t vaddr, u_long size) if (vaddr) iounmap((void *) (vaddr & PAGE_MASK)); } -#endif /* !NCR_IOMAPPED */ +#endif /* __i386__ || !NCR_IOMAPPED */ /* ** Insert a delay in micro-seconds and milli-seconds. @@ -2145,7 +2145,6 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); static void ncr_script_fill (struct script * scr, struct scripth * scripth); static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); -static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags); static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); @@ -5837,7 +5836,7 @@ void ncr_complete (ncb_p np, ccb_p cp) ** If tags was reduced due to queue full, ** increase tags if 1000 good status received. */ - if (lp && lp->numtags < lp->maxtags) { + if (lp && lp->usetags && lp->numtags < lp->maxtags) { ++lp->num_good; if (lp->num_good >= 1000) { lp->num_good = 0; @@ -6537,24 +6536,6 @@ static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack) **========================================================== */ -static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags) -{ - if (numtags > tp->usrtags) - numtags = tp->usrtags; - - if (tp) { - int ln; - for (ln = 0; ln < MAX_LUN; ln++) { - lcb_p lp = tp->lp[ln]; - - if (!lp) - continue; - lp->maxtags = lp->numtags = numtags; - ncr_setup_tags (np, (tp - np->target), ln); - } - } -} - static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln) { tcb_p tp = &np->target[tn]; @@ -6671,10 +6652,17 @@ static void ncr_usercmd (ncb_p np) case UC_SETTAGS: for (t=0; tuser.target>>t)&1)) continue; np->target[t].usrtags = np->user.data; - ncr_setmaxtags (np, &np->target[t], np->user.data); - }; + for (ln = 0; ln < MAX_LUN; ln++) { + lcb_p lp = np->target[t].lp[ln]; + if (!lp) + continue; + lp->maxtags = lp->numtags = np->user.data; + ncr_setup_tags (np, t, ln); + } + }; break; case UC_SETDEBUG: @@ -7824,7 +7812,7 @@ void ncr_int_sir (ncb_p np) ** field of the controller's struct ncb. ** ** Possible cases: hs sir msg_in value send goto -** We try try to negotiate: +** We try to negotiate: ** -> target doesnt't msgin NEG FAIL noop defa. - dispatch ** -> target rejected our msg NEG FAIL reject defa. - dispatch ** -> target answered (ok) NEG SYNC sdtr set - clrack @@ -8718,7 +8706,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) */ if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) { lp->inq_byte7 = inq_byte7; - lp->numtags = tp->usrtags; + lp->numtags = lp->maxtags; ncr_setup_tags (np, tn, ln); } @@ -9622,8 +9610,6 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, #endif ncr_chip *chip; - printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n", - bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7); /* * Read info from the PCI config space. * pcibios_read_config_xxx() functions are assumed to be used for @@ -9650,6 +9636,11 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, PCI_BASE_ADDRESS_1, &base); (void) pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, &base_2); + + /* Handle 64bit base adresses for 53C896. */ + if ((base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) + (void) pcibios_read_config_dword(bus, device_fn, + PCI_BASE_ADDRESS_3, &base_2); (void) pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq); #endif @@ -9674,6 +9665,34 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, chip->revision_id = revision; break; } + +#if defined(__i386__) + /* + * Ignore Symbios chips controlled by SISL RAID controller. + */ + if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) { + unsigned int ScriptsSize, MagicValue; + vm_offset_t ScriptsRAM; + + if (chip->features & FE_RAM8K) + ScriptsSize = 8192; + else + ScriptsSize = 4096; + + ScriptsRAM = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK, + ScriptsSize); + if (ScriptsRAM) { + MagicValue = readl(ScriptsRAM + ScriptsSize - 16); + unmap_pci_mem(ScriptsRAM, ScriptsSize); + if (MagicValue == 0x52414944) + return -1; + } + } +#endif + + printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n", + bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7); + if (!chip) { printk("ncr53c8xx: not initializing, device not supported\n"); return -1; @@ -10069,6 +10088,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de ncb_p np; tcb_p tp; lcb_p lp; + int numtags; if (device->host != host) continue; @@ -10080,15 +10100,16 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de /* ** Select queue depth from driver setup. ** Donnot use more than configured by user. - ** Use 2 for devices that donnot support tags. ** Use at least 2. ** Donnot use more than our maximum. */ - device->queue_depth = - device_queue_depth(np, device->id, device->lun); - if (device->queue_depth > tp->usrtags) - device->queue_depth = tp->usrtags; - if (!device->tagged_supported || device->queue_depth < 2) + numtags = device_queue_depth(np, device->id, device->lun); + if (numtags > tp->usrtags) + numtags = tp->usrtags; + if (!device->tagged_supported) + numtags = 1; + device->queue_depth = numtags; + if (device->queue_depth < 2) device->queue_depth = 2; if (device->queue_depth > SCSI_NCR_MAX_TAGS) device->queue_depth = SCSI_NCR_MAX_TAGS; @@ -10098,8 +10119,10 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de ** we need to know this value in order not to ** announce stupid things to user. */ - if (lp) + if (lp) { + lp->numtags = lp->maxtags = numtags; lp->scdev_depth = device->queue_depth; + } ncr_setup_tags (np, device->id, device->lun); #ifdef DEBUG_NCR53C8XX diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index 8c513279b7d7..a84f8d53aefe 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -45,7 +45,7 @@ /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1b" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1d" /* ** Check supported Linux versions @@ -424,6 +424,10 @@ typedef struct { #define FE_LDSTR (1<<13) #define FE_RAM (1<<14) #define FE_CLK80 (1<<15) +#define FE_RAM8K (1<<16) +#define FE_64BIT (1<<17) +#define FE_IO256 (1<<18) +#define FE_NOPM (1<<19) #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) #define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM) @@ -484,7 +488,8 @@ typedef struct { FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ , \ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \ - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\ + FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM}\ } /* diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c index 1ec38a9dcd35..064785074f51 100644 --- a/drivers/scsi/scsi_obsolete.c +++ b/drivers/scsi/scsi_obsolete.c @@ -607,10 +607,9 @@ void scsi_old_done (Scsi_Cmnd * SCpnt) if ((++SCpnt->retries) < SCpnt->allowed) { if ((SCpnt->retries >= (SCpnt->allowed >> 1)) - /* FIXME: last_reset == 0 is allowed - * && !(SCpnt->host->last_reset > 0 */ && - time_before(jiffies, SCpnt->host->last_reset - + MIN_RESET_PERIOD) + /* FIXME: last_reset == 0 is allowed */ + && time_after(jiffies, SCpnt->host->last_reset + + MIN_RESET_PERIOD) && !(SCpnt->flags & WAS_RESET)) { printk("scsi%d channel %d : resetting for second half of retries.\n", diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index a64e180cdbb9..34f82ff701db 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -878,6 +878,7 @@ int sb_dsp_init(struct address_info *hw_config) if(!sb16_set_dma_hw(devc)) { free_irq(devc->irq, devc); + release_region(hw_config->io_base, 16); return 0; } diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 12eeaf20451f..e3f1b1d8d3a1 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -973,6 +973,11 @@ aty_init_cursor(struct fb_info_aty *fb)) #endif #endif + if (! cursor->ram) { + kfree(cursor); + return NULL; + } + if (curblink) { init_timer(cursor->timer); cursor->timer->expires = jiffies + (HZ / 50); @@ -2917,6 +2922,11 @@ __initfunc(void atyfb_init(void)) info->ati_regbase = (unsigned long) ioremap(info->ati_regbase_phys, 0x1000); + if(!info->ati_regbase) { + kfree(info); + return; + } + info->ati_regbase_phys += 0xc00; info->ati_regbase += 0xc00; @@ -2939,6 +2949,11 @@ __initfunc(void atyfb_init(void)) info->frame_buffer_phys = addr; info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + if(!info->frame_buffer) { + kfree(info); + return; + } + #endif /* __sparc__ */ if (!aty_init(info, "PCI")) { @@ -3046,6 +3061,13 @@ __initfunc(void atyfb_of_init(struct device_node *dp)) info->ati_regbase_phys = 0x7ff000+addr; info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys, 0x1000); + + if(! info->ati_regbase) { + printk("atyfb_init: ioremap() returned NULL\n"); + kfree(info); + return; + } + info->ati_regbase_phys += 0xc00; info->ati_regbase += 0xc00; @@ -3067,6 +3089,12 @@ __initfunc(void atyfb_of_init(struct device_node *dp)) info->frame_buffer_phys = addr; info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + if(! info->frame_buffer) { + printk("atyfb_init: ioremap() returned NULL\n"); + kfree(info); + return; + } + if (!aty_init(info, dp->full_name)) { kfree(info); return; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 74d62f54e133..b89906f189bf 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -242,8 +242,6 @@ affs_unlink(struct inode *dir, struct dentry *dentry) inode = dentry->d_inode; retval = -EPERM; - if (S_ISDIR(inode->i_mode)) - goto unlink_done; if (current->fsuid != inode->i_uid && current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto unlink_done; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 4621e02f5a7c..6ae3a91cd812 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -661,7 +661,6 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) if (le32_to_cpu(de->inode) != inode->i_ino) goto end_rmdir; - down(&inode->i_sem); /* * Prune any child dentries so that this dentry becomes negative. */ @@ -686,7 +685,6 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) retval = ext2_delete_entry (de, bh); dir->i_version = ++event; } - up(&inode->i_sem); if (retval) goto end_rmdir; mark_buffer_dirty(bh, 1); @@ -733,8 +731,6 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry) DQUOT_INIT(inode); retval = -EPERM; - if (S_ISDIR(inode->i_mode)) - goto end_unlink; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto end_unlink; if ((dir->i_mode & S_ISVTX) && diff --git a/fs/minix/namei.c b/fs/minix/namei.c index fdf699f9c4ea..a7cb9a49e472 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -490,8 +490,6 @@ repeat: inode = dentry->d_inode; retval = -EPERM; - if (S_ISDIR(inode->i_mode)) - goto end_unlink; if (de->inode != inode->i_ino) { brelse(bh); current->counter = 0; diff --git a/fs/namei.c b/fs/namei.c index b6843aaf6914..b8348f13a648 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -834,6 +834,37 @@ asmlinkage int sys_mkdir(const char * pathname, int mode) return error; } +/* + * Whee.. Deadlock country. Happily there are only two VFS + * operations that do this.. + */ +static inline void double_lock(struct dentry *d1, struct dentry *d2) +{ + struct semaphore *s1 = &d1->d_inode->i_sem; + struct semaphore *s2 = &d2->d_inode->i_sem; + + if (s1 != s2) { + if ((unsigned long) s1 < (unsigned long) s2) { + struct semaphore *tmp = s2; + s2 = s1; s1 = tmp; + } + down(s1); + } + down(s2); +} + +static inline void double_unlock(struct dentry *d1, struct dentry *d2) +{ + struct semaphore *s1 = &d1->d_inode->i_sem; + struct semaphore *s2 = &d2->d_inode->i_sem; + + up(s1); + if (s1 != s2) + up(s2); + dput(d1); + dput(d2); +} + static inline int do_rmdir(const char * name) { int error; @@ -845,13 +876,21 @@ static inline int do_rmdir(const char * name) if (IS_ERR(dentry)) goto exit; - dir = lock_parent(dentry); - error = PTR_ERR(dir); - if (IS_ERR(dir)) - goto exit_dput; + dir = dget(dentry->d_parent); error = -ENOENT; if (!dentry->d_inode) + goto exit; + + /* + * The dentry->d_count stuff confuses d_delete() enough to + * not kill the inode from under us while it is locked. This + * wouldn't be needed, except the dentry semaphore is really + * in the inode, not in the dentry.. + */ + dentry->d_count++; + double_lock(dir, dentry); + if (dentry->d_parent != dir) goto exit_lock; error = -EROFS; @@ -886,9 +925,8 @@ static inline int do_rmdir(const char * name) error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry); exit_lock: - unlock_dir(dir); -exit_dput: - dput(dentry); + dentry->d_count--; + double_unlock(dentry, dir); exit: return error; } @@ -943,13 +981,16 @@ static inline int do_unlink(const char * name) goto exit_lock; /* + * A directory can't be unlink'ed. * A file cannot be removed from an append-only directory. */ error = -EPERM; + if (S_ISDIR(dentry->d_inode->i_mode)) + goto exit_lock; + if (IS_APPEND(dir->d_inode)) goto exit_lock; - error = -EPERM; if (!dir->d_inode->i_op || !dir->d_inode->i_op->unlink) goto exit_lock; @@ -1144,37 +1185,6 @@ asmlinkage int sys_link(const char * oldname, const char * newname) return error; } -/* - * Whee.. Deadlock country. Happily there is only one VFS - * operation that does this.. - */ -static inline void double_lock(struct dentry *d1, struct dentry *d2) -{ - struct semaphore *s1 = &d1->d_inode->i_sem; - struct semaphore *s2 = &d2->d_inode->i_sem; - - if (s1 != s2) { - if ((unsigned long) s1 < (unsigned long) s2) { - struct semaphore *tmp = s2; - s2 = s1; s1 = tmp; - } - down(s1); - } - down(s2); -} - -static inline void double_unlock(struct dentry *d1, struct dentry *d2) -{ - struct semaphore *s1 = &d1->d_inode->i_sem; - struct semaphore *s2 = &d2->d_inode->i_sem; - - up(s1); - if (s1 != s2) - up(s2); - dput(d1); - dput(d2); -} - static inline int do_rename(const char * oldname, const char * newname) { int error; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 3f9c0ea005ae..25caa03d32ab 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -240,22 +240,21 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) if (!fl->fl_owner || (fl->fl_flags & (FL_POSIX|FL_BROKEN)) != FL_POSIX) return -ENOLCK; - /* If unlocking a file region, flush dirty pages (unless we've - * been killed by a signal, that is). */ - if (cmd == F_SETLK && fl->fl_type == F_UNLCK - && !signal_pending(current)) { - status = nfs_wb_area(inode, /* current->pid ?*/ - fl->fl_start, fl->fl_end == NLM_OFFSET_MAX? 0 : - fl->fl_end - fl->fl_start + 1); - if (status < 0) - return status; - } + /* + * Flush all pending writes before doing anything + * with locks.. + */ + status = nfs_wb_all(inode); + if (status < 0) + return status; if ((status = nlmclnt_proc(inode, cmd, fl)) < 0) return status; - /* Here, we could turn off write-back of pages in the - * locked file region */ - + /* + * Make sure we re-validate anything we've got cached. + * This makes locking act as a cache coherency point. + */ + NFS_CACHEINV(inode); return 0; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 82f213c55fc3..6ee83a82577e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -583,15 +583,6 @@ nfs_wb_pid(struct inode *inode, pid_t pid) NFS_WB(inode, req->wb_pid == pid); } -/* - * Write back everything in a specific area for locking purposes.. - */ -int -nfs_wb_area(struct inode *inode, off_t offset, off_t len) -{ - NFS_WB(inode, 1); -} - /* * Write back and invalidate. Sometimes we can't leave the stuff * hanging if we can't write it out. diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d8a463befb66..72d67a13ae5c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1072,6 +1072,11 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, if (IS_ERR(rdentry)) goto out_nfserr; + /* + * FIXME!! + * + * This should do a double-lock on both rdentry and the parent + */ err = fh_lock_parent(fhp, rdentry); if (err) goto out; diff --git a/fs/open.c b/fs/open.c index 6f110d12667f..05d8f9ea4350 100644 --- a/fs/open.c +++ b/fs/open.c @@ -797,11 +797,11 @@ int close_fp(struct file *filp, fl_owner_t id) printk("VFS: Close: file count is 0\n"); return 0; } - if (dentry->d_inode) - locks_remove_posix(filp, id); retval = 0; if (filp->f_op && filp->f_op->flush) retval = filp->f_op->flush(filp); + if (dentry->d_inode) + locks_remove_posix(filp, id); fput(filp); return retval; } diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index 99cbf05eb764..564fa66b28e1 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -245,9 +245,6 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry) goto end_unlink; } retval = -EPERM; - if (S_ISDIR(inode->i_mode)) { - goto end_unlink; - } if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) { diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 626cc08a9e7a..fdae5c38c5a6 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -476,8 +476,6 @@ repeat: inode = dentry->d_inode; retval = -EPERM; - if (S_ISDIR(inode->i_mode)) - goto end_unlink; if (de->inode != inode->i_ino) { brelse(bh); current->counter = 0; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index bebfe1f66bee..130d53bb5c85 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -701,7 +701,6 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry) if (SWAB32(de->d_ino) != inode->i_ino) goto end_rmdir; - down(&inode->i_sem); /* * Prune any child dentries so that this dentry becomes negative. */ @@ -727,7 +726,6 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry) retval = ufs_delete_entry (dir, de, bh); dir->i_version = ++event; } - up(&inode->i_sem); if (retval) goto end_rmdir; mark_buffer_dirty(bh, 1); @@ -784,8 +782,6 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry) inode->i_sb->dq_op->initialize (inode, -1); retval = -EPERM; - if (S_ISDIR(inode->i_mode)) - goto end_unlink; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto end_unlink; if ((dir->i_mode & S_ISVTX) && diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt index 0f7ba34c1ce2..4535ec6abc42 100644 --- a/fs/umsdos/README-WIP.txt +++ b/fs/umsdos/README-WIP.txt @@ -2,21 +2,19 @@ Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing (started by Peter T. Waltenberg ) (Final conversion to dentries Bill Hawes ) ----------- WARNING --------- WARNING --------- WARNING ----------- There is no warning any more. Both read-only and read-write stuff is fixed, both in msdos-compatibile mode, and in umsdos EMD mode, and it seems stable. -There are still few symlink/hardlink nuisances, but those are not fatal. +There are still few hardlink nuisances, but those are not fatal. -I'd call it wide beta, and ask for as many people as possible to +I'd call it pre-release, and ask for as many people as possible to come and test it! See notes below for some more information, or if you are trying to use UMSDOS as root partition. ----------- WARNING --------- WARNING --------- WARNING ----------- Legend: those lines marked with '+' on the beggining of line indicates it passed all of my tests, and performed perfect in all of them. -Current status (981018) - UMSDOS dentry-Beta 0.83: +Current status (981129) - UMSDOS dentry-pre 0.84: (1) pure MSDOS (no --linux-.--- EMD file): @@ -51,13 +49,13 @@ READ: + resolve symlink - works + dereference symlink - works + dangling symlink - works -- hard links - seems to work mostly ++ hard links - works + special files (block/char devices, FIFOs, sockets...) - works -- various umsdos ioctls - works ++ various umsdos ioctls - works WRITE: -- create symlink - works mostly, but see WARNING below ++ create symlink - works - create hardlink - works, but see portability WARNING below + create file - works + create special file - works @@ -66,16 +64,16 @@ WRITE: + rename file (dif. dir) - works - rename hardlink (same dir) - - rename hardlink (dif. dir) - -- rename symlink (same dir) - -- rename symlink (dif. dir) - problems sometimes. see warning below. ++ rename symlink (same dir) - works ++ rename symlink (dif. dir) - works + rename dir (same dir) - works + rename dir (dif. dir) - works + delete file - works + notify_change (chown,perms) - works + delete hardlink - works + mkdir - works -- rmdir - HMMM. see with clean --linux-.--- files... -- umssyncing (many ioctls) - works ++ rmdir - works ++ umssyncing (many ioctls) - works - CVF-FAT stuff (compressed DOS filesystem) - there is some support from Frank @@ -91,13 +89,6 @@ in filesystems that might be externally modified like umsdos. There is example is specs file about it. Specifically, moving directory which contains hardlinks will break them. -Warning: moving symlinks around may break them until umount/remount. - -Warning: I seem to able to reproduce one problem with creting symlink after -I rm -rf directory: it is manifested as symlink apperantly being regular -file instead of symlink until next umount/mount pair. Tracking this one -down... - Note: (about pseudoroot) If you are currently trying to use UMSDOS as root partition (with linux installed in c:\linux) it will boot, but there are some problems. Volunteers ready to test pseudoroot are needed (preferably @@ -105,7 +96,8 @@ ones with working backups or unimportant data). There are problems with different interpretation of hard links in normal in pseudo-root modes, resulting is 'silent delete' of them sometimes. Also, '/DOS' pseudo directory is only partially re-implemented and buggy. It works most of the -time, though. +time, though. Update: should work ok in 0.84, although it still does not +work correctly in combination with initrd featere. Working on this! Warning: (about creating hardlinks in pseudoroot mode) - hardlinks created in pseudoroot mode are not compatibile with 'normal' hardlinks, and vice versa. @@ -114,6 +106,8 @@ That is because harlink which is /foo in pseudoroot mode, becomes people either always use pseudoroot, or always use normal umsdos filesystem, this is no showstopper. +Warning: (about hardlinks) - modifying hardlinks (esp. if there are in +different directories) are currently somewhat broken, I'm working on it. ------------------------------------------------------------------------------ diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c index ab983212e2a8..41740fd42588 100644 --- a/fs/umsdos/check.c +++ b/fs/umsdos/check.c @@ -66,10 +66,10 @@ void check_page_tables (void) void check_sb (struct super_block *sb, const char c) { if (sb) { - Printk ((" (has %c_sb=%d, %d)", - c, MAJOR (sb->s_dev), MINOR (sb->s_dev))); + printk (" (has %c_sb=%d, %d)", + c, MAJOR (sb->s_dev), MINOR (sb->s_dev)); } else { - Printk ((" (%c_sb is NULL)", c)); + printk (" (%c_sb is NULL)", c); } } @@ -81,35 +81,37 @@ extern struct inode_operations umsdos_rdir_inode_operations; void check_inode (struct inode *inode) { if (inode) { - Printk ((KERN_DEBUG "* inode is %lu (i_count=%d)", - inode->i_ino, inode->i_count)); + printk (KERN_DEBUG "* inode is %lu (i_count=%d)", + inode->i_ino, inode->i_count); check_sb (inode->i_sb, 'i'); if (inode->i_dentry.next) { /* FIXME: does this work ? */ - Printk ((" (has i_dentry)")); + printk (" (has i_dentry)"); } else { - Printk ((" (NO i_dentry)")); + printk (" (NO i_dentry)"); } + printk (" (i_patched=%d)", inode->u.umsdos_i.i_patched); + if (inode->i_op == NULL) { - Printk ((" (i_op is NULL)\n")); + printk (" (i_op is NULL)\n"); } else if (inode->i_op == &umsdos_dir_inode_operations) { - Printk ((" (i_op is umsdos_dir_inode_operations)\n")); + printk (" (i_op is umsdos_dir_inode_operations)\n"); } else if (inode->i_op == &umsdos_file_inode_operations) { - Printk ((" (i_op is umsdos_file_inode_operations)\n")); + printk (" (i_op is umsdos_file_inode_operations)\n"); } else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) { - Printk ((" (i_op is umsdos_file_inode_operations_no_bmap)\n")); + printk (" (i_op is umsdos_file_inode_operations_no_bmap)\n"); } else if (inode->i_op == &umsdos_file_inode_operations_readpage) { - Printk ((" (i_op is umsdos_file_inode_operations_readpage)\n")); + printk (" (i_op is umsdos_file_inode_operations_readpage)\n"); } else if (inode->i_op == &umsdos_rdir_inode_operations) { - Printk ((" (i_op is umsdos_rdir_inode_operations)\n")); + printk (" (i_op is umsdos_rdir_inode_operations)\n"); } else if (inode->i_op == &umsdos_symlink_inode_operations) { - Printk ((" (i_op is umsdos_symlink_inode_operations)\n")); + printk (" (i_op is umsdos_symlink_inode_operations)\n"); } else { - Printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op)); + printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op)); } } else { - Printk ((KERN_DEBUG "* inode is NULL\n")); + printk (KERN_DEBUG "* inode is NULL\n"); } } @@ -127,40 +129,40 @@ void checkd_inode (struct inode *inode) return; } - Printk ((KERN_DEBUG "checkd_inode: inode %lu\n", inode->i_ino)); + printk (KERN_DEBUG "checkd_inode: inode %lu\n", inode->i_ino); cur = inode->i_dentry.next; while (count++ < 10) { PRINTK (("1...")); if (!cur) { - Printk ((KERN_ERR "checkd_inode: *** NULL reached. exit.\n")); + printk (KERN_ERR "checkd_inode: *** NULL reached. exit.\n"); return; } PRINTK (("2...")); ret = list_entry (cur, struct dentry, d_alias); PRINTK (("3...")); if (cur == cur->next) { - Printk ((KERN_DEBUG "checkd_inode: *** cur=cur->next: normal exit.\n")); + printk (KERN_DEBUG "checkd_inode: *** cur=cur->next: normal exit.\n"); return; } PRINTK (("4...")); if (!ret) { - Printk ((KERN_ERR "checkd_inode: *** ret dentry is NULL. exit.\n")); + printk (KERN_ERR "checkd_inode: *** ret dentry is NULL. exit.\n"); return; } PRINTK (("5... (ret=%p)...", ret)); PRINTK (("5.1.. (ret->d_dname=%p)...", &(ret->d_name))); PRINTK (("5.1.1. (ret->d_dname.len=%d)...", (int) ret->d_name.len)); PRINTK (("5.1.2. (ret->d_dname.name=%c)...", ret->d_name.name)); - Printk ((KERN_DEBUG "checkd_inode: i_dentry is %.*s\n", (int) ret->d_name.len, ret->d_name.name)); + printk (KERN_DEBUG "checkd_inode: i_dentry is %.*s\n", (int) ret->d_name.len, ret->d_name.name); PRINTK (("6...")); cur = cur->next; PRINTK (("7...")); #if 1 - Printk ((KERN_DEBUG "checkd_inode: *** finished after count 1 (operator forced)\n")); + printk (KERN_DEBUG "checkd_inode: *** finished after count 1 (operator forced)\n"); return; #endif } - Printk ((KERN_ERR "checkd_inode: *** OVER LIMIT (loop?) !\n")); + printk (KERN_ERR "checkd_inode: *** OVER LIMIT (loop?) !\n"); return; } @@ -172,19 +174,19 @@ void checkd_inode (struct inode *inode) void check_dent_int (struct dentry *dentry, int parent) { if (parent) { - Printk ((KERN_DEBUG "* parent(%d) dentry: %.*s\n", - parent, (int) dentry->d_name.len, dentry->d_name.name)); + printk (KERN_DEBUG "* parent(%d) dentry: %.*s\n", + parent, (int) dentry->d_name.len, dentry->d_name.name); } else { - Printk ((KERN_DEBUG "* checking dentry: %.*s\n", - (int) dentry->d_name.len, dentry->d_name.name)); + printk (KERN_DEBUG "* checking dentry: %.*s\n", + (int) dentry->d_name.len, dentry->d_name.name); } check_inode (dentry->d_inode); - Printk ((KERN_DEBUG "* d_count=%d", dentry->d_count)); + printk (KERN_DEBUG "* d_count=%d", dentry->d_count); check_sb (dentry->d_sb, 'd'); if (dentry->d_op == NULL) { - Printk ((" (d_op is NULL)\n")); + printk (" (d_op is NULL)\n"); } else { - Printk ((" (d_op is UNKNOWN: %p)\n", dentry->d_op)); + printk (" (d_op is UNKNOWN: %p)\n", dentry->d_op); } } @@ -196,35 +198,35 @@ void check_dent_int (struct dentry *dentry, int parent) void check_dentry_path (struct dentry *dentry, const char *desc) { int count=0; - Printk ((KERN_DEBUG "*** check_dentry_path: %.60s\n", desc)); + printk (KERN_DEBUG "*** check_dentry_path: %.60s\n", desc); if (!dentry) { - Printk ((KERN_DEBUG "*** checking dentry... it is NULL !\n")); + printk (KERN_DEBUG "*** checking dentry... it is NULL !\n"); return; } if (IS_ERR(dentry)) { - Printk ((KERN_DEBUG "*** checking dentry... it is ERR(%ld) !\n", - PTR_ERR(dentry))); + printk (KERN_DEBUG "*** checking dentry... it is ERR(%ld) !\n", + PTR_ERR(dentry)); return; } while (dentry && count < 10) { check_dent_int (dentry, count++); if (dentry == dentry->d_parent) { - Printk ((KERN_DEBUG "*** end checking dentry (root reached ok)\n")); + printk (KERN_DEBUG "*** end checking dentry (root reached ok)\n"); break; } dentry = dentry->d_parent; } if (count >= 10) { /* if infinite loop detected */ - Printk ((KERN_ERR - "*** WARNING ! INFINITE LOOP ! check_dentry_path aborted !\n")); + printk (KERN_ERR + "*** WARNING ! INFINITE LOOP ! check_dentry_path aborted !\n"); } if (!dentry) { - Printk ((KERN_ERR - "*** WARNING ! NULL dentry ! check_dentry_path aborted !\n")); + printk (KERN_ERR + "*** WARNING ! NULL dentry ! check_dentry_path aborted !\n"); } } #else diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index 1291163e9de7..6ab276ac4426 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -383,7 +383,6 @@ void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info) if (inode->u.umsdos_i.i_patched) goto out; inode->u.umsdos_i.i_patched = 1; - if (S_ISREG (entry->mode)) entry->mtime = inode->i_mtime; inode->i_mode = entry->mode; diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 4b8e1bfcc68c..ef6e56dc3d7a 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -60,6 +60,7 @@ void UMSDOS_put_inode (struct inode *inode) " Notify jacques@solucorp.qc.ca\n"); } + inode->u.umsdos_i.i_patched = 0; fat_put_inode (inode); } @@ -125,15 +126,6 @@ void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos) } -/* - * Tells if an Umsdos inode has been "patched" once. - * Return != 0 if so. - */ -int umsdos_isinit (struct inode *inode) -{ - return 0; /* inode->u.umsdos_i.i_emd_owner != 0; */ -} - /* * Connect the proper tables in the inode and add some info. @@ -200,7 +192,7 @@ dentry, f_pos)); */ void UMSDOS_read_inode (struct inode *inode) { - PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", + Printk ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", inode, inode->i_ino)); msdos_read_inode (inode); @@ -235,8 +227,8 @@ int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr) struct file filp; struct umsdos_dirent entry; -Printk(("UMSDOS_notify_change: entering for %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name)); +Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n", +dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched)); ret = inode_change_ok (inode, attr); if (ret) { @@ -348,7 +340,8 @@ void UMSDOS_write_inode (struct inode *inode) * But it has the side effect to re"dirt" the inode. */ /* - * internal_notify_change (inode, &newattrs); + * UMSDOS_notify_change (inode, &newattrs); + * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work. We need to remove ourselves from list on dirty inodes. /mn/ */ } @@ -385,7 +378,7 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, if (!res) goto out_fail; - printk (KERN_INFO "UMSDOS dentry-Beta 0.83 " + printk (KERN_INFO "UMSDOS dentry-pre 0.84 " "(compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index b0163041eee3..f7b8a8d077f1 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -1020,11 +1020,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name); goto out; } - /* - * Lock the directory, then check whether it's empty. - */ - down(&dentry->d_inode->i_sem); - /* check whether the EMD is empty */ ret = -ENOTEMPTY; empty = umsdos_isempty (dentry); @@ -1050,7 +1045,6 @@ demd->d_parent->d_name.name, demd->d_name.name, err); } } else if (empty == 2) ret = 0; - up(&dentry->d_inode->i_sem); if (ret) goto out; diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index de0cfbeffdb6..317d8ac2cfaa 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -83,17 +83,17 @@ int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) { int ret; - /* N.B. this won't work ... lookups of `..' are done by VFS */ -#ifdef BROKEN_TO_BITS - if (pseudo_root && len == 2 && name[0] == '.' && name[1] == '.' && - dir == saved_root->d_inode) { -printk (KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"); - pseudo_root->i_count++; - d_add(dentry, pseudo_root); - ret = 0; + if (saved_root && dir == saved_root->d_inode && !nopseudo && + dentry->d_name.len == UMSDOS_PSDROOT_LEN && + memcmp (dentry->d_name.name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) == 0) { + /* #Specification: pseudo root / DOS/linux + * Even in the real root directory (c:\), the directory + * /linux won't show + */ + + ret = -ENOENT; goto out; } -#endif ret = msdos_lookup (dir, dentry); if (ret) { @@ -111,20 +111,6 @@ Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name)); umsdos_patch_dentry_inode(dentry, 0); - /* N.B. Won't work -- /linux dentry will already have - * an inode, so we'll never get called here. - */ -#ifdef BROKEN_TO_BITS - if (dentry->d_inode == pseudo_root && !nopseudo) { - /* #Specification: pseudo root / DOS/linux - * Even in the real root directory (c:\), the directory - * /linux won't show - */ -printk(KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"); - /* make the dentry negative */ - d_delete(dentry); - } -#endif } out: /* always install our dentry ops ... */ @@ -180,7 +166,6 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) if (ret != -ENOTEMPTY) goto out; - down(&dentry->d_inode->i_sem); empty = umsdos_isempty (dentry); if (empty == 1) { struct dentry *demd; @@ -194,7 +179,6 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) dput(demd); } } - up(&dentry->d_inode->i_sem); if (ret) goto out; diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index 17ed1200f835..2cb1b891c0cf 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -36,9 +36,9 @@ asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); asmlinkage void __up_wakeup(void /* special register calling convention */); -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern void __up(struct semaphore * sem); +asmlinkage void __down(struct semaphore * sem); +asmlinkage int __down_interruptible(struct semaphore * sem); +asmlinkage void __up(struct semaphore * sem); extern spinlock_t semaphore_wake_lock; diff --git a/include/linux/apm_bios.h b/include/linux/apm_bios.h index 86a5fb1217be..a478c0c66f03 100644 --- a/include/linux/apm_bios.h +++ b/include/linux/apm_bios.h @@ -77,6 +77,7 @@ struct apm_bios_struct { extern struct apm_bios_info apm_bios_info; extern void apm_bios_init(void); +extern void apm_setup(char *, int *); extern int apm_register_callback(int (*callback)(apm_event_t)); extern void apm_unregister_callback(int (*callback)(apm_event_t)); diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 5ac782d40d7a..190202f05899 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -2,9 +2,15 @@ #define _LINUX_LINKAGE_H #ifdef __cplusplus -#define asmlinkage extern "C" +#define CPP_ASMLINKAGE extern "C" #else -#define asmlinkage +#define CPP_ASMLINKAGE +#endif + +#if defined __i386__ && (__GNUC__ > 2 || __GNUC_MINOR__ > 7) +#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) +#else +#define asmlinkage CPP_ASMLINKAGE #endif #define SYMBOL_NAME_STR(X) #X diff --git a/include/linux/lp.h b/include/linux/lp.h index b5b4e7393137..a60d29860a31 100644 --- a/include/linux/lp.h +++ b/include/linux/lp.h @@ -25,10 +25,9 @@ #define LP_NOPA 0x0010 #define LP_ERR 0x0020 #define LP_ABORT 0x0040 -#ifdef LP_NEED_CAREFUL -#define LP_CAREFUL 0x0080 -#endif +#define LP_CAREFUL 0x0080 /* obsoleted -arca */ #define LP_ABORTOPEN 0x0100 +#define LP_TRUST_IRQ 0x0200 /* timeout for each character. This is relative to bus cycles -- it * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you @@ -41,13 +40,10 @@ #define LP_INIT_CHAR 1000 /* The parallel port specs apparently say that there needs to be - * a .5usec wait before and after the strobe. Since there are wildly - * different computers running linux, I can't come up with a perfect - * value so if 20 is not good for you use `tunelp /dev/lp? -w ?`. - * You can also set it to 0 if your printer handle that. + * a .5usec wait before and after the strobe. */ -#define LP_INIT_WAIT 20 +#define LP_INIT_WAIT 1 /* This is the amount of time that the driver waits for the printer to * catch up when the printer's buffer appears to be filled. If you @@ -70,11 +66,10 @@ or 0 for polling (no IRQ) */ #define LPGETIRQ 0x0606 /* get the current IRQ number */ #define LPWAIT 0x0608 /* corresponds to LP_INIT_WAIT */ -#ifdef LP_NEED_CAREFUL +/* NOTE: LPCAREFUL is obsoleted and it' s always the default right now -arca */ #define LPCAREFUL 0x0609 /* call with TRUE arg to require out-of-paper, off- line, and error indicators good on all writes, FALSE to ignore them. Default is ignore. */ -#endif #define LPABORTOPEN 0x060a /* call with TRUE arg to abort open() on error, FALSE to ignore error. Default is ignore. */ #define LPGETSTATUS 0x060b /* return LP_S(minor) */ @@ -83,6 +78,7 @@ #define LPGETSTATS 0x060d /* get statistics (struct lp_stats) */ #endif #define LPGETFLAGS 0x060e /* get status flags */ +#define LPTRUSTIRQ 0x060f /* set/unset the LP_TRUST_IRQ flag */ /* timeout for printk'ing a timeout, in jiffies (100ths of a second). This is also used for re-checking error conditions if LP_ABORT is @@ -96,7 +92,7 @@ #define LP_TIME(minor) lp_table[(minor)].time /* wait time */ #define LP_WAIT(minor) lp_table[(minor)].wait /* strobe wait */ #define LP_IRQ(minor) lp_table[(minor)].dev->port->irq /* interrupt # */ - /* 0 means polled */ + /* PARPORT_IRQ_NONE means polled */ #ifdef LP_STATS #define LP_STAT(minor) lp_table[(minor)].stats /* statistics area */ #endif diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 03e4c25e75f1..cc66279acce4 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -222,7 +222,6 @@ extern int nfs_check_error(struct inode *); extern int nfs_wb_all(struct inode *); extern int nfs_wb_page(struct inode *, struct page *); extern int nfs_wb_pid(struct inode *, pid_t); -extern int nfs_wb_area(struct inode *, off_t, off_t); /* * Invalidate write-backs, possibly trying to write them diff --git a/include/linux/pci.h b/include/linux/pci.h index fac8a9397004..ce29e37d5778 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -615,6 +615,7 @@ #define PCI_DEVICE_ID_MADGE_C155S 0x1001 #define PCI_VENDOR_ID_3COM 0x10b7 +#define PCI_DEVICE_ID_3COM_3C985 0x0001 #define PCI_DEVICE_ID_3COM_3C339 0x3390 #define PCI_DEVICE_ID_3COM_3C590 0x5900 #define PCI_DEVICE_ID_3COM_3C595TX 0x5950 diff --git a/include/linux/swap.h b/include/linux/swap.h index 20b8f72f3f87..d4fcf03b8ce8 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -107,8 +107,8 @@ struct swap_list_t { int next; /* swapfile to be used next */ }; extern struct swap_list_t swap_list; -int sys_swapoff(const char *); -int sys_swapon(const char *, int); +asmlinkage int sys_swapoff(const char *); +asmlinkage int sys_swapon(const char *, int); /* * vm_ops not present page codes for shared memory. diff --git a/include/linux/umsdos_fs.h b/include/linux/umsdos_fs.h index 7a170c11540e..14bdb829d4cd 100644 --- a/include/linux/umsdos_fs.h +++ b/include/linux/umsdos_fs.h @@ -1,7 +1,9 @@ #ifndef LINUX_UMSDOS_FS_H #define LINUX_UMSDOS_FS_H -/* #define UMSDOS_DEBUG 1 */ + +#define UMS_DEBUG 1 /* define for check_* functions */ +/*#define UMSDOS_DEBUG 1*/ #define UMSDOS_PARANOIA 1 #define UMSDOS_VERSION 0 diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p index 0da0ca36701d..1bf76e56051a 100644 --- a/include/linux/umsdos_fs.p +++ b/include/linux/umsdos_fs.p @@ -57,7 +57,6 @@ void UMSDOS_put_super (struct super_block *); void umsdos_setup_dir(struct dentry *); void umsdos_set_dirinfo_new(struct dentry *, off_t); -int umsdos_isinit (struct inode *inode); void umsdos_patch_dentry_inode (struct dentry *, off_t); int umsdos_get_dirowner (struct inode *inode, struct inode **result); diff --git a/init/main.c b/init/main.c index e41ba1fa0d32..aaee2d2c74e6 100644 --- a/init/main.c +++ b/init/main.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,10 @@ # include #endif +#ifdef CONFIG_APM +#include +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -864,6 +869,9 @@ static struct kernel_param raw_params[] __initdata = { #endif #ifdef CONFIG_PARIDE_PG { "pg.", pg_setup }, +#endif +#ifdef CONFIG_APM + { "apm=", apm_setup }, #endif { 0, 0 } }; diff --git a/kernel/fork.c b/kernel/fork.c index 7a259cb5702d..a625aaba38e7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -137,7 +137,7 @@ static inline struct task_struct ** find_empty_process(void) { struct task_struct **tslot = NULL; - if (!current->uid || (nr_tasks < NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT)) + if ((nr_tasks < NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) || !current->uid) tslot = get_free_taskslot(); return tslot; } diff --git a/mm/filemap.c b/mm/filemap.c index e2fd16518d4b..227bcd5a9ce7 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -200,8 +200,8 @@ int shrink_mmap(int priority, int gfp_mask) struct page * page; int count_max, count_min; - count_max = (limit<<1) >> (priority>>1); - count_min = (limit<<1) >> (priority); + count_max = limit; + count_min = (limit<<2) >> (priority); page = mem_map + clock; do { @@ -214,7 +214,15 @@ int shrink_mmap(int priority, int gfp_mask) if (shrink_one_page(page, gfp_mask)) return 1; count_max--; - if (page->inode || page->buffers) + /* + * If the page we looked at was recyclable but we didn't + * reclaim it (presumably due to PG_referenced), don't + * count it as scanned. This way, the more referenced + * page cache pages we encounter, the more rapidly we + * will age them. + */ + if (atomic_read(&page->count) != 1 || + (!page->inode && !page->buffers)) count_min--; page++; clock++; diff --git a/mm/swap.c b/mm/swap.c index ff5e0f71dfcb..1e2d8c36b279 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -62,13 +62,13 @@ swapstat_t swapstats = {0}; buffer_mem_t buffer_mem = { 5, /* minimum percent buffer */ - 25, /* borrow percent buffer */ + 10, /* borrow percent buffer */ 60 /* maximum percent buffer */ }; buffer_mem_t page_cache = { 5, /* minimum percent page cache */ - 30, /* borrow percent page cache */ + 15, /* borrow percent page cache */ 75 /* maximum */ }; diff --git a/mm/vmscan.c b/mm/vmscan.c index a93fdf6d2f5b..c5efa52a2050 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -431,7 +431,7 @@ static int do_try_to_free_page(int gfp_mask) kmem_cache_reap(gfp_mask); if (buffer_over_borrow() || pgcache_over_borrow()) - shrink_mmap(i, gfp_mask); + state = 0; switch (state) { do { diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index 06f4e308bc15..e0379e69b1c6 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -31,21 +31,23 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then define_bool CONFIG_NETLINK_DEV y fi fi - bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY - bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG + bool 'IP: always defragment (required for masquerading)' CONFIG_IP_ALWAYS_DEFRAG fi fi if [ "$CONFIG_IP_FIREWALL" = "y" ]; then - bool 'IP: masquerading' CONFIG_IP_MASQUERADE - if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then - comment 'Protocol-specific masquerading support will be built as modules.' - bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP - comment 'Protocol-specific masquerading support will be built as modules.' - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'IP: masquerading special modules support' CONFIG_IP_MASQUERADE_MOD - if [ "$CONFIG_IP_MASQUERADE_MOD" = "y" ]; then - tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW - tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW + if [ "$CONFIG_IP_ALWAYS_DEFRAG" != "n" ]; then + bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY + bool 'IP: masquerading' CONFIG_IP_MASQUERADE + if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then + comment 'Protocol-specific masquerading support will be built as modules.' + bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP + comment 'Protocol-specific masquerading support will be built as modules.' + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'IP: masquerading special modules support' CONFIG_IP_MASQUERADE_MOD + if [ "$CONFIG_IP_MASQUERADE_MOD" = "y" ]; then + tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW + tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW + fi fi fi fi diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 75de39dec892..f486852d1075 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -265,7 +265,7 @@ unsigned short tcp_good_socknum(void) struct tcp_bind_bucket *tb; int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; - int remaining = high - low; + int remaining = high - low + 1; int rover; SOCKHASH_LOCK(); -- 2.39.5