diff --git a/Documentation/Configure.help b/Documentation/Configure.help index ed2b560..6d51d63 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -4831,6 +4831,7 @@ CONFIG_M386 - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. - "CyrixIII" for VIA Cyrix III or VIA C3. - "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above). + - "Geode GX/LX" for AMD/NSC Geode GX and AMD Geode LX. If you don't know what to do, choose "386". @@ -20200,6 +20201,22 @@ CONFIG_HW_RANDOM If unsure, say N. +AMD Geode LX HW Random Number Generator support +CONFIG_GEODE_RNG + This driver provides kernel-side support for the Random Number + Generator hardware found on the AMD Geode LX. + + It runs a timer function which automatically adds entropy directly + into the kernel pool. You may need this driver if your system runs + headless and has no other source of entropy. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read . The module will be called + hw_random. + + If unsure, say N. + Power Management support CONFIG_PM "Power Management" means that parts of your computer are shut @@ -20672,6 +20689,22 @@ CONFIG_SC1200_WDT module, say M here and read . Most people will say N. +AMD/NSC Geode Hardware Watchdog +CONFIG_GEODE_WDT + This driver enables a watchdog capability built into the + CS5535/CS5536 companion chips for the AMD Geode GX and LX + processors. This watchdog watches your kernel to make sure + it doesn't freeze, and if it does, it reboots your computer after + a certain amount of time. + + This driver depends on CONFIG_MGEODE_LX. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called geodewdt.o. If you want to compile it as a + module, say M here and read . Most + people will say N. + SuperH Watchdog CONFIG_SH_WDT This driver adds watchdog support for the integrated watchdog in the @@ -28819,6 +28852,7 @@ CONFIG_SCx200_I2C_SDA NatSemi SCx200 ACCESS.bus CONFIG_SCx200_ACB Enable the use of the ACCESS.bus controllers of a SCx200 processor. + It also enables the I2C controller found on Geode GX/LX processors. If you don't know what to do here, say N. diff --git a/Documentation/using-newer-gcc.txt b/Documentation/using-newer-gcc.txt index 7834427..a2c6593 100644 --- a/Documentation/using-newer-gcc.txt +++ b/Documentation/using-newer-gcc.txt @@ -161,12 +161,29 @@ above, or /usr/local/bin if none was specified : The compiler just has to be passed to "make" via the "CC" variable for all commands : - $ make CC=/opt/kgcc/bin/kernel-gcc -j 4 dep bzImage modules modules_install + $ make CC=/opt/kgcc/bin/kernel-gcc -j 4 dep bzImage modules + $ sudo make CC=/opt/kgcc/bin/kernel-gcc modules_install install or more simply, when you have it in your path : - $ make CC=kernel-gcc -j 4 dep bzImage modules modules_install + $ make CC=kernel-gcc -j 4 dep bzImage modules + $ sudo make CC=kernel-gcc -j 4 modules_install install +Note: make modules_install needs a 2.4-compatible depmod. If your distro is + 2.6-based and says it does not find depmod or depmod.old, it means that + either modutils or module-init-tools have not been correctly installed. + You can still force the path to depmod by passing it in the DEPMOD + variable during make modules_install if you know where to find a good + one. + + +7) I want to use a really old compiler, but compiling it breaks! +----------------------------------------------------------------- + +Tackle the problem in stages. Compile 3.x.y as above. Then use that to +compile 2.95.x (CC=/opt/kgcc/bin/kernel-gcc ./configure ...), install, +use 2.95.x to compile the next compiler in the chain, continue as +far as you'd like. Conclusion ========== diff --git a/MAINTAINERS b/MAINTAINERS index b36b3b0..1594012 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -819,7 +819,7 @@ S: Maintained I2C SUBSYSTEM P: Jean Delvare M: khali@linux-fr.org -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org W: http://www.lm-sensors.org/ S: Maintained diff --git a/Makefile b/Makefile index 48ce53d..72906b3 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 37 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index ce5a64b..ac57139 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -71,6 +71,10 @@ CFLAGS += -march=i686 CFLAGS += $(call check_gcc,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0) endif +ifdef CONFIG_MGEODE_LX +CFLAGS += -march=i686 +endif + ifdef CONFIG_MWINCHIPC6 CFLAGS += -march=i586 endif diff --git a/arch/i386/config.in b/arch/i386/config.in index 629fe41..593fab1 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -39,6 +39,7 @@ choice 'Processor family' \ Opteron/Athlon64/Hammer/K8 CONFIG_MK8 \ Elan CONFIG_MELAN \ Crusoe CONFIG_MCRUSOE \ + Geode-GX/LX CONFIG_MGEODE_LX \ Winchip-C6 CONFIG_MWINCHIPC6 \ Winchip-2 CONFIG_MWINCHIP2 \ Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ @@ -172,6 +173,17 @@ if [ "$CONFIG_MCRUSOE" = "y" ]; then define_bool CONFIG_X86_HAS_TSC y define_bool CONFIG_X86_F00F_WORKS_OK y fi +if [ "$CONFIG_MGEODE_LX" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_HAS_TSC y + define_bool CONFIG_X86_PPRO_FENCE y + define_bool CONFIG_X86_F00F_WORKS_OK y + define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y +fi if [ "$CONFIG_MWINCHIPC6" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 544b9b5..aa921e9 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -30,6 +30,11 @@ obj-y += pci-pc.o pci-irq.o endif endif +ifdef CONFIG_MGEODE_LX +obj-y += geode-mfgpt.o +export-objs += geode-mfgpt.o +endif + obj-$(CONFIG_MCA) += mca.o obj-$(CONFIG_MTRR) += mtrr.o obj-$(CONFIG_X86_MSR) += msr.o diff --git a/arch/i386/kernel/geode-mfgpt.c b/arch/i386/kernel/geode-mfgpt.c new file mode 100644 index 0000000..1ecb049 --- /dev/null +++ b/arch/i386/kernel/geode-mfgpt.c @@ -0,0 +1,224 @@ +/* Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT) + * + * Copyright (C) 2006, Advanced Micro Devices, Inc. + * Copyright (C) 2007, Andres Salomon + * Backported to 2.4 by Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* for pci_iomap/pci_iounmap */ +#include "mfgpt-compat.h" + +static void *mfgpt_iobase; + +static struct mfgpt_timer_t { + unsigned int avail:1; +} mfgpt_timers[MFGPT_MAX_TIMERS]; + +void geode_mfgpt_write(int i, u16 r, u16 v) +{ + outw(v, (unsigned long)(mfgpt_iobase + (r + (i * 8)))); +} +EXPORT_SYMBOL(geode_mfgpt_write); + +u16 geode_mfgpt_read(int i, u16 r) +{ + return inw((unsigned long)(mfgpt_iobase + (r + (i * 8)))); +} +EXPORT_SYMBOL(geode_mfgpt_read); + +int geode_mfgpt_toggle_event(int timer, int cmp, int event, int setup) +{ + u32 msr, mask, value, dummy; + int shift = (cmp == MFGPT_CMP1) ? 0 : 8; + + if (timer < 0 || timer >= MFGPT_MAX_TIMERS) + return -EIO; + + switch(event) { + case MFGPT_EVENT_RESET: + msr = MSR_MFGPT_NR; + mask = 1 << (timer + 24); + break; + + case MFGPT_EVENT_NMI: + msr = MSR_MFGPT_NR; + mask = 1 << (timer + shift); + break; + + case MFGPT_EVENT_IRQ: + msr = MSR_MFGPT_IRQ; + mask = 1 << (timer + shift); + break; + + default: + return -EIO; + } + + rdmsr(msr, value, dummy); + + if (setup) + value |= mask; + else + value &= ~mask; + + wrmsr(msr, value, dummy); + return 0; +} + +EXPORT_SYMBOL(geode_mfgpt_toggle_event); + +/* Allow for disabling of MFGPTs */ +static int disable; +static int __init mfgpt_disable(char *s) +{ + disable = 1; + return 1; +} +__setup("nomfgpt", mfgpt_disable); + +/* Reset the MFGPT timers. This is required by some broken BIOSes which already + * do the same and leave the system in an unstable state. TinyBIOS 0.98 is + * affected at least (0.99 is OK with MFGPT workaround left to off). + */ +static int __init mfgpt_fix(char *s) +{ + u32 val, dummy; + + /* The following udocumented bit resets the MFGPT timers */ + val = 0xFF; dummy = 0; + wrmsr(MSR_MFGPT_SETUP, val, dummy); + return 1; +} +__setup("mfgptfix", mfgpt_fix); + + +/* + * Check whether any MFGPTs are available for the kernel to use. In most + * cases, firmware that uses AMD's VSA code will claim all timers during + * bootup; we certainly don't want to take them if they're already in use. + * In other cases (such as with VSAless OpenFirmware), the system firmware + * leaves timers available for us to use. + */ + +static struct pci_device_id geode_sbdevs[] = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) } +}; + +static int timers = -1; + +static void geode_mfgpt_detect(void) +{ + struct pci_dev *pdev = NULL; + int i, ret, dev, count = 0; + u16 val; + + timers = 0; + + if (disable) { + printk(KERN_INFO "geode-mfgpt: MFGPT support is disabled\n"); + goto done; + } + + if (!is_geode()) { + printk(KERN_INFO "geode-mfgpt: Not a Geode GX/LX processor\n"); + goto done; + } + + for (dev = 0; dev < ARRAY_SIZE(geode_sbdevs); dev++) { + pdev = pci_find_device(geode_sbdevs[dev].vendor, + geode_sbdevs[dev].device, NULL); + + if (pdev != NULL) + break; + } + + if (pdev == NULL) { + printk(KERN_ERR "geode-mfgpt: No PCI devices found\n"); + goto done; + } + + if ((ret = pci_enable_device_bars(pdev, 1 << MFGPT_PCI_BAR))) + goto err; + + if ((ret = pci_request_region(pdev, MFGPT_PCI_BAR, "geode-mfgpt"))) + goto err; + + mfgpt_iobase = pci_iomap(pdev, MFGPT_PCI_BAR, 64); + + if (mfgpt_iobase == NULL) + goto ereq; + + for (i = 0; i < MFGPT_MAX_TIMERS; i++) { + val = geode_mfgpt_read(i, MFGPT_REG_SETUP); + if (!(val & MFGPT_SETUP_SETUP)) { + mfgpt_timers[i].avail = 1; + timers++; + } + } + + done: + printk(KERN_INFO "geode-mfgpt: %d MFGPT timers available.\n", timers); + return; + ereq: + pci_release_region(pdev, MFGPT_PCI_BAR); + err: + printk(KERN_ERR "geode-mfgpt: Error initalizing the timers\n"); + return; +} + +static int mfgpt_get(int timer) +{ + mfgpt_timers[timer].avail = 0; + printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); + return timer; +} + +int geode_mfgpt_alloc_timer(int timer, int domain) +{ + int i; + + if (timers == -1) { + /* timers haven't been detected yet */ + geode_mfgpt_detect(); + } + + if (!timers) + return -1; + + if (timer >= MFGPT_MAX_TIMERS) + return -1; + + if (timer < 0) { + /* Try to find an available timer */ + for (i = 0; i < MFGPT_MAX_TIMERS; i++) { + if (mfgpt_timers[i].avail) + return mfgpt_get(i); + + if (i == 5 && domain == MFGPT_DOMAIN_WORKING) + break; + } + } else { + /* If they requested a specific timer, try to honor that */ + if (mfgpt_timers[timer].avail) + return mfgpt_get(timer); + } + + /* No timers available - too bad */ + return -1; +} +EXPORT_SYMBOL(geode_mfgpt_alloc_timer); diff --git a/arch/i386/kernel/mfgpt-compat.h b/arch/i386/kernel/mfgpt-compat.h new file mode 100644 index 0000000..bc9ebb9 --- /dev/null +++ b/arch/i386/kernel/mfgpt-compat.h @@ -0,0 +1,251 @@ +/* compatibility layer for iomap functions used by mfgpt. + * + * This file has been extracted and inlined from linux-2.6.22/lib/iomap.c with + * the following original header and copyright : + * + * Implement the default iomap interfaces + * + * (C) Copyright 2004 Linus Torvalds + */ +#include + +/* + * Read/write from/to an (offsettable) iomem cookie. It might be a PIO + * access or a MMIO access, these functions don't care. The info is + * encoded in the hardware mapping set up by the mapping functions + * (or the cookie itself, depending on implementation and hw). + * + * The generic routines don't assume any hardware mappings, and just + * encode the PIO/MMIO as part of the cookie. They coldly assume that + * the MMIO IO mappings are not in the low address range. + * + * Architectures for which this is not true can't use this generic + * implementation and should do their own copy. + */ + +#ifndef HAVE_ARCH_PIO_SIZE +/* + * We encode the physical PIO addresses (0-0xffff) into the + * pointer by offsetting them with a constant (0x10000) and + * assuming that all the low addresses are always PIO. That means + * we can do some sanity checks on the low bits, and don't + * need to just take things for granted. + */ +#define PIO_OFFSET 0x10000UL +#define PIO_MASK 0x0ffffUL +#define PIO_RESERVED 0x40000UL +#endif + +static inline void bad_io_access(unsigned long port, const char *access) +{ + static int count = 10; + if (count) { + count--; + printk(KERN_ERR "Bad IO access at port %lx (%s)\n", port, access); + WARN_ON(1); + } +} + +/* + * Ugly macros are a way of life. + */ +#define IO_COND(addr, is_pio, is_mmio) do { \ + unsigned long port = (unsigned long)addr; \ + if (port >= PIO_RESERVED) { \ + is_mmio; \ + } else if (port > PIO_OFFSET) { \ + port &= PIO_MASK; \ + is_pio; \ + } else \ + bad_io_access(port, #is_pio ); \ +} while (0) + +#ifndef pio_read16be +#define pio_read16be(port) swab16(inw(port)) +#define pio_read32be(port) swab32(inl(port)) +#endif + +#ifndef mmio_read16be +#define mmio_read16be(addr) be16_to_cpu(__raw_readw(addr)) +#define mmio_read32be(addr) be32_to_cpu(__raw_readl(addr)) +#endif + +static inline unsigned int ioread8(void __iomem *addr) +{ + IO_COND(addr, return inb(port), return readb(addr)); + return 0xff; +} +static inline unsigned int ioread16(void __iomem *addr) +{ + IO_COND(addr, return inw(port), return readw(addr)); + return 0xffff; +} +static inline unsigned int ioread16be(void __iomem *addr) +{ + IO_COND(addr, return pio_read16be(port), return mmio_read16be(addr)); + return 0xffff; +} +static inline unsigned int ioread32(void __iomem *addr) +{ + IO_COND(addr, return inl(port), return readl(addr)); + return 0xffffffff; +} +static inline unsigned int ioread32be(void __iomem *addr) +{ + IO_COND(addr, return pio_read32be(port), return mmio_read32be(addr)); + return 0xffffffff; +} + +#ifndef pio_write16be +#define pio_write16be(val,port) outw(swab16(val),port) +#define pio_write32be(val,port) outl(swab32(val),port) +#endif + +#ifndef mmio_write16be +#define mmio_write16be(val,port) __raw_writew(be16_to_cpu(val),port) +#define mmio_write32be(val,port) __raw_writel(be32_to_cpu(val),port) +#endif + +static inline void iowrite8(u8 val, void __iomem *addr) +{ + IO_COND(addr, outb(val,port), writeb(val, addr)); +} +static inline void iowrite16(u16 val, void __iomem *addr) +{ + IO_COND(addr, outw(val,port), writew(val, addr)); +} +static inline void iowrite16be(u16 val, void __iomem *addr) +{ + IO_COND(addr, pio_write16be(val,port), mmio_write16be(val, addr)); +} +static inline void iowrite32(u32 val, void __iomem *addr) +{ + IO_COND(addr, outl(val,port), writel(val, addr)); +} +static inline void iowrite32be(u32 val, void __iomem *addr) +{ + IO_COND(addr, pio_write32be(val,port), mmio_write32be(val, addr)); +} + +/* + * These are the "repeat MMIO read/write" functions. + * Note the "__raw" accesses, since we don't want to + * convert to CPU byte order. We write in "IO byte + * order" (we also don't have IO barriers). + */ +#ifndef mmio_insb +static inline void mmio_insb(void __iomem *addr, u8 *dst, int count) +{ + while (--count >= 0) { + u8 data = __raw_readb(addr); + *dst = data; + dst++; + } +} +static inline void mmio_insw(void __iomem *addr, u16 *dst, int count) +{ + while (--count >= 0) { + u16 data = __raw_readw(addr); + *dst = data; + dst++; + } +} +static inline void mmio_insl(void __iomem *addr, u32 *dst, int count) +{ + while (--count >= 0) { + u32 data = __raw_readl(addr); + *dst = data; + dst++; + } +} +#endif + +#ifndef mmio_outsb +static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count) +{ + while (--count >= 0) { + __raw_writeb(*src, addr); + src++; + } +} +static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count) +{ + while (--count >= 0) { + __raw_writew(*src, addr); + src++; + } +} +static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count) +{ + while (--count >= 0) { + __raw_writel(*src, addr); + src++; + } +} +#endif + +static inline void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) +{ + IO_COND(addr, insb(port,dst,count), mmio_insb(addr, dst, count)); +} +static inline void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) +{ + IO_COND(addr, insw(port,dst,count), mmio_insw(addr, dst, count)); +} +static inline void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) +{ + IO_COND(addr, insl(port,dst,count), mmio_insl(addr, dst, count)); +} + +static inline void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) +{ + IO_COND(addr, outsb(port, src, count), mmio_outsb(addr, src, count)); +} +static inline void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) +{ + IO_COND(addr, outsw(port, src, count), mmio_outsw(addr, src, count)); +} +static inline void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) +{ + IO_COND(addr, outsl(port, src,count), mmio_outsl(addr, src, count)); +} + +/* Create a virtual mapping cookie for an IO port range */ +static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + if (port > PIO_MASK) + return NULL; + return (void __iomem *) (unsigned long) (port + PIO_OFFSET); +} + +static inline void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + /* What? */ + return NULL; +} + +static inline void pci_iounmap(struct pci_dev *dev, void __iomem * addr) +{ + IO_COND(addr, /* nothing */, iounmap(addr)); +} diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 6ea58bb..acfb96c 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -274,6 +274,9 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then if [ "$CONFIG_SGI_IP22" = "y" ]; then dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 fi + if [ "$CONFIG_MGEODE_LX" = "y" ]; then + tristate ' Geode GX/LX on-chip Watchdog timer' CONFIG_GEODE_WDT + fi if [ "$CONFIG_8xx" = "y" ]; then tristate ' MPC8xx Watchdog Timer' CONFIG_8xx_WDT fi @@ -305,6 +308,9 @@ if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o \ "$CONFIG_X86_64" = "y" ]; then dep_tristate 'Intel/AMD/VIA HW Random Number Generator support' CONFIG_HW_RANDOM $CONFIG_PCI fi +if [ "$CONFIG_X86" = "y" ]; then + dep_tristate 'AMD Geode Random Number Generator support' CONFIG_GEODE_RNG $CONFIG_PCI +fi dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 2f570f7..94993c0 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -263,6 +263,7 @@ obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_DS1742) += ds1742.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o obj-$(CONFIG_AMD_RNG) += amd768_rng.o +obj-$(CONFIG_GEODE_RNG) += geode-rng.o obj-$(CONFIG_HW_RANDOM) += hw_random.o obj-$(CONFIG_AMD_PM768) += amd76x_pm.o obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o @@ -322,6 +323,7 @@ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_GEODE_WDT) += geodewdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o obj-$(CONFIG_WDT_W83627) += wdt83627.o obj-$(CONFIG_W83977EF_WDT) += wdt83977.o diff --git a/drivers/char/geode-rng.c b/drivers/char/geode-rng.c new file mode 100644 index 0000000..6255289 --- /dev/null +++ b/drivers/char/geode-rng.c @@ -0,0 +1,114 @@ +/* + * RNG driver for AMD Geode RNGs + * + * Copyright 2008 Willy Tarreau + * + * Inspired by drivers/char/hw_random/geode-rng.c from kernel 2.6.25. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* We read the random generator every 50 ms */ +#define RNG_INTERVAL (HZ/20+1) + +#define GEODE_RNG_DATA_REG 0x50 +#define GEODE_RNG_STATUS_REG 0x54 + +static struct timer_list timer; +static void __iomem *rng_addr; +static u32 rng_data[2]; +static int nb_data; + +static u32 geode_rng_data_read(void) +{ + return readl(rng_addr + GEODE_RNG_DATA_REG); +} + +static int geode_rng_data_present(void) +{ + return !!(readl(rng_addr + GEODE_RNG_STATUS_REG)); +} + +static void geode_rng_timer(unsigned long data) +{ + if (!geode_rng_data_present()) + goto out; + + rng_data[nb_data] = geode_rng_data_read(); + nb_data++; + if (nb_data > 1) { + nb_data = 0; + /* We have collected 64 bits. Maybe we should reduce the + * announced entropy ? At least, check for changing data + * and refuse to feed consts. + */ + if (rng_data[0] != rng_data[1]) + batch_entropy_store(rng_data[0], rng_data[1], 64); + } + out: + timer.expires = jiffies + RNG_INTERVAL; + add_timer(&timer); +} + +static int __init geode_rng_init(void) +{ + struct pci_dev *pdev = NULL; + unsigned long rng_base; + int err = -ENODEV; + + pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, NULL); + + if (pdev == NULL) { + printk(KERN_ERR "geode-rng: AMD Geode RNG device not found\n"); + goto out; + } + + if ((err = pci_enable_device(pdev))) + goto out; + + if ((err = pci_enable_device_bars(pdev, 1))) + goto out; + + rng_base = pci_resource_start(pdev, 0); + if (rng_base == 0) + goto out; + + err = -ENOMEM; + rng_addr = ioremap(rng_base, 0x58); + if (!rng_addr) + goto out; + + printk(KERN_INFO "AMD Geode RNG detected and enabled\n"); + + init_timer(&timer); + timer.function = geode_rng_timer; + timer.data = 0; + timer.expires = jiffies + RNG_INTERVAL; + add_timer(&timer); + err = 0; +out: + return err; +} + +static void __exit geode_rng_exit(void) +{ + del_timer_sync(&timer); + iounmap(rng_addr); +} + +module_init(geode_rng_init); +module_exit(geode_rng_exit); + +MODULE_AUTHOR("Willy Tarreau"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/geodewdt.c b/drivers/char/geodewdt.c new file mode 100644 index 0000000..f53e56e --- /dev/null +++ b/drivers/char/geodewdt.c @@ -0,0 +1,255 @@ +/* Watchdog timer for the Geode GX/LX + * + * Copyright (C) 2006, Advanced Micro Devices, Inc. + * Backported to 2.4 by Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define GEODEWDT_HZ 500 +#define GEODEWDT_SCALE 6 +#define GEODEWDT_MAX_SECONDS 131 + +#define WDT_FLAGS_OPEN 1 +#define WDT_FLAGS_ORPHAN 2 + +/* The defaults for the other timers are 60, so we'll use that too */ + +static int cur_interval = 60; +MODULE_PARM(cur_interval, "i"); +MODULE_PARM_DESC(cur_interval, "Watchdog interval in seconds. 1<= interval <=131, default=60."); + +static int wdt_timer; +static unsigned long wdt_flags; +static int safe_close; + +static void geodewdt_ping(void) +{ + //printk("PING\n"); + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN); +} + +static void geodewdt_stop(void) +{ + //printk("STOP\n"); + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0); +} + +static int geodewdt_set_heartbeat(int val) +{ + if (val < 1 || val > GEODEWDT_MAX_SECONDS) + return -EINVAL; + + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ); + geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN); + + //printk("HEARTBEAT %d\n", val); + cur_interval = val; + return 0; +} + +static int +geodewdt_open(struct inode *inode, struct file *file) +{ + if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) + return -ENODEV; + + if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags)) + return -EBUSY; + + if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags)) + MOD_INC_USE_COUNT; + + geodewdt_ping(); + return 0; +} + +static int +geodewdt_release(struct inode *inode, struct file *file) +{ + if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) + return 0; + + if (safe_close) { + geodewdt_stop(); + MOD_DEC_USE_COUNT; + } + else { + printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n"); + geodewdt_ping(); + + set_bit(WDT_FLAGS_ORPHAN, &wdt_flags); + } + + clear_bit(WDT_FLAGS_OPEN, &wdt_flags); + safe_close = 0; + return 0; +} + +static ssize_t +geodewdt_write(struct file *file, const char __user *data, size_t len, + loff_t *ppos) +{ + if(len) { + size_t i; + safe_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + + if (c == 'V') + safe_close = 1; + } + } + + geodewdt_ping(); + return len; +} + +static int +geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int interval; + + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING + | WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = "Geode Watchdog", + }; + + switch(cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_KEEPALIVE: + geodewdt_ping(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(interval, p)) + return -EFAULT; + + if (geodewdt_set_heartbeat(interval)) + return -EINVAL; + +/* Fall through */ + + case WDIOC_GETTIMEOUT: + return put_user(cur_interval, p); + } + + return -ENOTTY; +} + +static int geodewdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + geodewdt_stop(); + + return NOTIFY_DONE; +} + +static struct file_operations geodewdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = geodewdt_write, + .ioctl = geodewdt_ioctl, + .open = geodewdt_open, + .release = geodewdt_release, +}; + +static struct miscdevice geodewdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &geodewdt_fops +}; + +static struct notifier_block geodewdt_notifier = { + .notifier_call = geodewdt_notify_sys +}; + +static int __init geodewdt_init(void) +{ + int ret, timer; + + timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_ANY); + + if (timer == -1) { + printk(KERN_ERR "geodewdt: No timers were available\n"); + return -ENODEV; + } + + wdt_timer = timer; + + /* Set up the timer */ + + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, + GEODEWDT_SCALE | (3 << 8)); + + /* Set up comparator 2 to reset when the event fires */ + geode_mfgpt_set_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET); + + /* Set up the initial timeout */ + + geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, + cur_interval * GEODEWDT_HZ); + + ret = misc_register(&geodewdt_miscdev); + if (ret) + return ret; + + ret = register_reboot_notifier(&geodewdt_notifier); + + if (ret) + misc_deregister(&geodewdt_miscdev); + + return ret; +} + +static void __exit +geodewdt_exit(void) +{ + misc_deregister(&geodewdt_miscdev); + unregister_reboot_notifier(&geodewdt_notifier); +} + +module_init(geodewdt_init); +module_exit(geodewdt_exit); + +MODULE_AUTHOR("Advanced Micro Devices, Inc"); +MODULE_DESCRIPTION("Geode GX/LX Watchdog Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/scx200_acb.c b/drivers/i2c/scx200_acb.c index 677186b..4091643 100644 --- a/drivers/i2c/scx200_acb.c +++ b/drivers/i2c/scx200_acb.c @@ -3,6 +3,7 @@ Copyright (c) 2001,2002 Christer Weinigel National Semiconductor SCx200 ACCESS.bus support + Also supports AMD CS5535 and AMD CS5536 Based on i2c-keywest.c which is: Copyright (c) 2001 Benjamin Herrenschmidt @@ -34,6 +35,7 @@ #include #include #include +#include #include @@ -526,24 +528,49 @@ static int __init scx200_acb_create(int base, int index) return rc; } +#define MSR_LBAR_SMB 0x5140000B + +static int scx200_add_cs553x(void) +{ + u32 low, hi; + u32 smb_base; + + /* Grab & reserve the SMB I/O range */ + rdmsr(MSR_LBAR_SMB, low, hi); + + /* Check the IO mask and whether SMB is enabled */ + if (hi != 0x0000F001) { + printk(KERN_WARNING NAME ": SMBus not enabled\n"); + return -ENODEV; + } + + /* SMBus IO size is 8 bytes */ + smb_base = low & 0x0000FFF8; + + return scx200_acb_create(smb_base, 0); +} + static int __init scx200_acb_init(void) { int i; - int rc; + int rc = -ENODEV; printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); /* Verify that this really is a SCx200 processor */ if (pci_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE, - NULL) == NULL) - return -ENODEV; - - rc = -ENXIO; + NULL)) { for (i = 0; i < MAX_DEVICES; ++i) { if (base[i] > 0) rc = scx200_acb_create(base[i], i); } + } else if (pci_find_device(PCI_VENDOR_ID_NS, + PCI_DEVICE_ID_NS_CS5535_ISA, NULL) || + pci_find_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_CS5536_ISA, NULL)) { + rc = scx200_add_cs553x(); + } if (scx200_acb_list) return 0; return rc; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 35e6f7a..d4f1a07 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1635,7 +1635,7 @@ static int chip_command(struct i2c_client *client, case VIDIOCSFREQ: { chip->mode = 0; /* automatic */ - if (desc->checkmode) { + if (desc->checkmode && desc->setmode) { desc->setmode(chip,VIDEO_SOUND_MONO); if (chip->prevmode != VIDEO_SOUND_MONO) chip->prevmode = -1; /* reset previous mode */ diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index d61b68a..c129249 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -183,11 +183,13 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_ /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - u32 next_index = tx_hash_table[index].next; - tlb_init_table_entry(&tx_hash_table[index], save_load); - index = next_index; + if (tx_hash_table) { + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; + } } tlb_init_slave(slave); /* Stratus88746: do this before unlocking */ diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index bab7893..60e58cd 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2553,7 +2553,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (id->driver_data & DEV_HAS_CHECKSUM) { np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; #ifdef NETIF_F_TSO dev->features |= NETIF_F_TSO; #endif diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index bcc2644..a63bb0c 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -106,21 +106,56 @@ static const struct pci_device_id piix_pci_tbl[] = { * list in drivers/pci/quirks.c. */ + /* 82801EB (ICH5) */ { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + /* 6300ESB (ICH5 variant with broken PCS present bits) */ { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + /* 6300ESB pretending RAID */ { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + /* 82801FB/FW (ICH6/ICH6W) */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + /* 82801FR/FRW (ICH6R/ICH6RW) */ { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, - { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented). + * Attach iff the controller is in IDE mode. */ + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich6_sata_rm }, + /* Enterprise Southbridge 2 (631xESB/632xESB) */ + { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb2_sata }, + /* 82801GB/GR/GH (ICH7, identical to ICH6) */ { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* 2801GBM/GHM (ICH7M, identical to ICH6M) */ { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller 1 IDE (ICH8) */ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller 2 IDE (ICH8) */ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* Mobile SATA Controller IDE (ICH8M) */ + { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, { 0x8086, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller IDE (ICH9) */ { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller IDE (ICH9) */ + { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller IDE (ICH9) */ { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, - { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb2_sata }, + /* SATA Controller IDE (ICH9M) */ + { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller IDE (Tolopai) */ + { 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + /* SATA Controller IDE (PCH) */ + { 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, { } /* terminate list */ }; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 593b660..1ef185c 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -63,7 +63,7 @@ static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to) return err; } -static void ext2_check_page(struct page *page) +static void ext2_check_page(struct page *page, int quiet) { struct inode *dir = page->mapping->host; struct super_block *sb = dir->i_sb; @@ -110,10 +110,10 @@ out: /* Too bad, we had an error */ Ebadsize: - ext2_error(sb, "ext2_check_page", - "size of directory #%lu is not a multiple of chunk size", - dir->i_ino - ); + if (!quiet) + ext2_error(sb, __func__, + "size of directory #%lu is not a multiple " + "of chunk size", dir->i_ino); goto fail; Eshort: error = "rec_len is smaller than minimal"; @@ -130,25 +130,29 @@ Espan: Einumber: error = "inode out of bounds"; bad_entry: - ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - " - "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", - dir->i_ino, error, (page->index<inode), - rec_len, p->name_len); + if (!quiet) + ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - " + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + dir->i_ino, error, (page->index<inode), + rec_len, p->name_len); goto fail; Eend: - p = (ext2_dirent *)(kaddr + offs); - ext2_error (sb, "ext2_check_page", - "entry in directory #%lu spans the page boundary" - "offset=%lu, inode=%lu", - dir->i_ino, (page->index<inode)); + if (!quiet) { + p = (ext2_dirent *)(kaddr + offs); + ext2_error(sb, "ext2_check_page", + "entry in directory #%lu spans the page boundary" + "offset=%lu, inode=%lu", + dir->i_ino, (page->index<inode)); + } fail: SetPageChecked(page); SetPageError(page); } -static struct page * ext2_get_page(struct inode *dir, unsigned long n) +static struct page * ext2_get_page(struct inode *dir, unsigned long n, + int quiet) { struct address_space *mapping = dir->i_mapping; struct page *page = read_cache_page(mapping, n, @@ -159,7 +163,7 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n) if (!Page_Uptodate(page)) goto fail; if (!PageChecked(page)) - ext2_check_page(page); + ext2_check_page(page, quiet); if (PageError(page)) goto fail; } @@ -257,7 +261,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) for ( ; n < npages; n++, offset = 0) { char *kaddr, *limit; ext2_dirent *de; - struct page *page = ext2_get_page(inode, n); + struct page *page = ext2_get_page(inode, n, 0); if (IS_ERR(page)) { ext2_error(sb, __FUNCTION__, @@ -320,6 +324,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, unsigned long npages = dir_pages(dir); struct page *page = NULL; ext2_dirent * de; + int dir_has_error = 0; /* OFFSET_CACHE */ *res_page = NULL; @@ -330,7 +335,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, n = start; do { char *kaddr; - page = ext2_get_page(dir, n); + page = ext2_get_page(dir, n, dir_has_error); if (!IS_ERR(page)) { kaddr = page_address(page); de = (ext2_dirent *) kaddr; @@ -341,7 +346,9 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, de = ext2_next_entry(de); } ext2_put_page(page); - } + } else + dir_has_error = 1; + if (++n >= npages) n = 0; /* next page is past the blocks we've got */ @@ -364,7 +371,7 @@ found: struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) { - struct page *page = ext2_get_page(dir, 0); + struct page *page = ext2_get_page(dir, 0, 0); ext2_dirent *de = NULL; if (!IS_ERR(page)) { @@ -431,7 +438,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode) /* We take care of directory expansion in the same loop */ for (n = 0; n <= npages; n++) { - page = ext2_get_page(dir, n); + page = ext2_get_page(dir, n, 0); err = PTR_ERR(page); if (IS_ERR(page)) goto out; @@ -571,14 +578,17 @@ int ext2_empty_dir (struct inode * inode) { struct page *page = NULL; unsigned long i, npages = dir_pages(inode); + int dir_has_error = 0; for (i = 0; i < npages; i++) { char *kaddr; ext2_dirent * de; - page = ext2_get_page(inode, i); + page = ext2_get_page(inode, i, dir_has_error); - if (IS_ERR(page)) + if (IS_ERR(page)) { + dir_has_error = 1; continue; + } kaddr = page_address(page); de = (ext2_dirent *)kaddr; diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 2084181..90d4bd0 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -76,6 +76,7 @@ static int ext3_readdir(struct file * filp, struct super_block * sb; int err; struct inode *inode = filp->f_dentry->d_inode; + int dir_has_error = 0; sb = inode->i_sb; @@ -87,9 +88,12 @@ static int ext3_readdir(struct file * filp, blk = (filp->f_pos) >> EXT3_BLOCK_SIZE_BITS(sb); bh = ext3_bread (0, inode, blk, 0, &err); if (!bh) { - ext3_error (sb, "ext3_readdir", - "directory #%lu contains a hole at offset %lu", - inode->i_ino, (unsigned long)filp->f_pos); + if (!dir_has_error) { + ext3_error (sb, __func__, "directory #%lu " + "contains a hole at offset %lld", + inode->i_ino, filp->f_pos); + dir_has_error = 1; + } filp->f_pos += sb->s_blocksize - offset; continue; } diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index a871037..cd678b1 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -129,6 +129,11 @@ int hfsplus_find_cat(struct super_block *sb, unsigned long cnid, return -EIO; } + if (be16_to_cpu(tmp.thread.nodeName.length) > 255) { + printk(KERN_ERR "hfs: catalog name length corrupted\n"); + return -EIO; + } + hfsplus_fill_cat_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID), &tmp.thread.nodeName); return hfsplus_btree_find(fd); diff --git a/fs/namei.c b/fs/namei.c index 374b767..5433162 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -296,7 +296,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i */ result = d_lookup(parent, name); if (!result) { - struct dentry * dentry = d_alloc(parent, name); + struct dentry *dentry; + + /* Don't create child dentry for a dead directory. */ + result = ERR_PTR(-ENOENT); + if (IS_DEADDIR(dir)) + goto out_unlock; + + dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); if (dentry) { lock_kernel(); @@ -307,6 +314,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i else result = dentry; } + out_unlock: up(&dir->i_sem); return result; } @@ -798,7 +806,14 @@ struct dentry * lookup_hash(struct qstr *name, struct dentry * base) dentry = cached_lookup(base, name, 0); if (!dentry) { - struct dentry *new = d_alloc(base, name); + struct dentry *new; + + /* Don't create child dentry for a dead directory. */ + dentry = ERR_PTR(-ENOENT); + if (IS_DEADDIR(inode)) + goto out; + + new = d_alloc(base, name); dentry = ERR_PTR(-ENOMEM); if (!new) goto out; diff --git a/fs/open.c b/fs/open.c index 512b60f..ca47086 100644 --- a/fs/open.c +++ b/fs/open.c @@ -109,6 +109,8 @@ int do_truncate(struct dentry *dentry, loff_t length) down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + /* Remove suid/sgid on truncate too */ + remove_suid(inode); error = notify_change(dentry, &newattrs); up(&inode->i_sem); up_write(&inode->i_alloc_sem); diff --git a/include/asm-i386/geode-mfgpt.h b/include/asm-i386/geode-mfgpt.h new file mode 100644 index 0000000..e30b231 --- /dev/null +++ b/include/asm-i386/geode-mfgpt.h @@ -0,0 +1,85 @@ +/* Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT) + * + * Copyright (C) 2006, Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#ifndef MFGPT_GEODE_H_ +#define MFGPT_GEODE_H_ + +#define MFGPT_TIMER_ANY -1 + +#define MFGPT_DOMAIN_WORKING 1 +#define MFGPT_DOMAIN_STANDBY 2 +#define MFGPT_DOMAIN_ANY (MFGPT_DOMAIN_WORKING | MFGPT_DOMAIN_STANDBY) + +#define MSR_MFGPT_IRQ 0x51400028 +#define MSR_MFGPT_NR 0x51400029 +#define MSR_MFGPT_SETUP 0x5140002B + +#define MFGPT_MAX_TIMERS 8 +#define MFGPT_PCI_BAR 2 + +#define MFGPT_CMP1 0 +#define MFGPT_CMP2 1 + +#define MFGPT_EVENT_IRQ 0 +#define MFGPT_EVENT_NMI 1 +#define MFGPT_EVENT_RESET 3 + +#define MFGPT_REG_CMP1 0 +#define MFGPT_REG_CMP2 2 +#define MFGPT_REG_COUNTER 4 +#define MFGPT_REG_SETUP 6 + +#define MFGPT_SETUP_CNTEN (1 << 15) +#define MFGPT_SETUP_CMP2 (1 << 14) +#define MFGPT_SETUP_CMP1 (1 << 13) +#define MFGPT_SETUP_SETUP (1 << 12) +#define MFGPT_SETUP_STOPEN (1 << 11) +#define MFGPT_SETUP_EXTEN (1 << 10) +#define MFGPT_SETUP_REVEN (1 << 5) +#define MFGPT_SETUP_CLKSEL (1 << 4) + +extern int geode_mfgpt_toggle_event(int, int, int, int); + +#define geode_mfgpt_set_event(t,c,e) geode_mfgpt_toggle_event(t,c,e,1) +#define geode_mfgpt_clear_event(t,c,e) geode_mfgpt_toggle_event(t,c,e,0) + +extern void geode_mfgpt_set_irq(int, int, int, int); + +#define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq(t,c,i,1) +#define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq(t,c,i,0) + +extern void geode_mfgpt_write(int, u16, u16); +extern u16 geode_mfgpt_read(int, u16); + +extern int geode_mfgpt_alloc_timer(int, int); + +/* Specific geode tests */ + +static inline int is_geode_gx(void) +{ + return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) && + (boot_cpu_data.x86 == 5) && + (boot_cpu_data.x86_model == 5)); +} + +static inline int is_geode_lx(void) +{ + return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (boot_cpu_data.x86 == 5) && + (boot_cpu_data.x86_model == 10)); +} + +static inline int is_geode(void) +{ + return (is_geode_gx() || is_geode_lx()); +} + +#endif diff --git a/include/linux/i2c.h b/include/linux/i2c.h index fae04e0..49bef85 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -379,8 +379,8 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 -#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* New I2C-like block */ -#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* transfer */ +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ I2C_FUNC_SMBUS_WRITE_BYTE) diff --git a/include/linux/mii.h b/include/linux/mii.h index c87b17f..0c1271d 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -9,7 +9,6 @@ #define __LINUX_MII_H__ #include -#include /* Generic MII registers. */ @@ -104,6 +103,19 @@ #define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ #define NWAYTEST_RESV2 0xfe00 /* Unused... */ +/* This structure is used in all SIOCxMIIxxx ioctl calls */ +struct mii_ioctl_data { + __u16 phy_id; + __u16 reg_num; + __u16 val_in; + __u16 val_out; +}; + +#ifdef __KERNEL__ + +#include + +struct ethtool_cmd; struct mii_if_info { int phy_id; @@ -119,9 +131,6 @@ struct mii_if_info { void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); }; -struct ethtool_cmd; -struct mii_ioctl_data; - extern int mii_link_ok (struct mii_if_info *mii); extern int mii_nway_restart (struct mii_if_info *mii); extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); @@ -135,16 +144,6 @@ extern int generic_mii_ioctl(struct mii_if_info *mii_if, unsigned int *duplex_changed); - -/* This structure is used in all SIOCxMIIxxx ioctl calls */ -struct mii_ioctl_data { - u16 phy_id; - u16 reg_num; - u16 val_in; - u16 val_out; -}; - - static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) { return (struct mii_ioctl_data *) &rq->ifr_ifru; @@ -202,5 +201,5 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock, return 0; } - +#endif /* __KERNEL__ */ #endif /* __LINUX_MII_H__ */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 52e1dbe..c84ec13 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -347,6 +347,7 @@ #define PCI_DEVICE_ID_NS_87560_USB 0x0012 #define PCI_DEVICE_ID_NS_83815 0x0020 #define PCI_DEVICE_ID_NS_83820 0x0022 +#define PCI_DEVICE_ID_NS_CS5535_ISA 0x002b #define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500 #define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501 #define PCI_DEVICE_ID_NS_SCx200_IDE 0x0502 @@ -434,6 +435,8 @@ #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 +#define PCI_DEVICE_ID_AMD_LX_AES 0x2082 +#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 #define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A #define PCI_DEVICE_ID_AMD_SERENADE 0x36c0 #define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 diff --git a/include/linux/sched.h b/include/linux/sched.h index 7716c40..aee6f56 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -415,6 +415,8 @@ struct task_struct { /* journalling filesystem info */ void *journal_info; + + struct list_head *scm_work_list; }; /* diff --git a/include/net/scm.h b/include/net/scm.h index e26b43f..6246dd3 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -8,8 +8,9 @@ struct scm_fp_list { - int count; - struct file *fp[SCM_MAX_FD]; + struct list_head list; + int count; + struct file *fp[SCM_MAX_FD]; }; struct scm_cookie diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 3c67e20..88f144a 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -635,7 +635,6 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ret = unregister_vlan_dev(dev, VLAN_DEV_INFO(vlandev)->vlan_id); - dev_put(vlandev); unregister_netdevice(vlandev); /* Group was destroyed? */ diff --git a/net/core/scm.c b/net/core/scm.c index 96e2fe0..b7bdc36 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -70,6 +70,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) if (!fpl) return -ENOMEM; *fplp = fpl; + INIT_LIST_HEAD(&fpl->list); fpl->count = 0; } fpp = &fpl->fp[fpl->count]; @@ -101,9 +102,25 @@ void __scm_destroy(struct scm_cookie *scm) if (fpl) { scm->fp = NULL; - for (i=fpl->count-1; i>=0; i--) - fput(fpl->fp[i]); - kfree(fpl); + if (current->scm_work_list) { + list_add_tail(&fpl->list, current->scm_work_list); + } else { + LIST_HEAD(work_list); + + current->scm_work_list = &work_list; + + list_add(&fpl->list, &work_list); + while (!list_empty(&work_list)) { + fpl = list_entry(work_list.next, struct scm_fp_list, list); + + list_del(&fpl->list); + for (i=fpl->count-1; i>=0; i--) + fput(fpl->fp[i]); + kfree(fpl); + } + + current->scm_work_list = NULL; + } } } @@ -263,6 +280,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL); if (new_fpl) { + INIT_LIST_HEAD(&new_fpl->list); for (i=fpl->count-1; i>=0; i--) get_file(fpl->fp[i]); memcpy(new_fpl, fpl, sizeof(*fpl)); diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 87d71d4..d382057 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -740,6 +740,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); if (*obj == NULL) { + kfree(p); kfree(id); if (net_ratelimit()) printk("OOM in bsalg (%d)\n", __LINE__); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3398c24..82e98f7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2814,6 +2814,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) * log. Something worked... */ sk->err_soft = 0; + tp->probes_out = 0; tp->rcv_tstamp = tcp_time_stamp; if ((prior_packets = tp->packets_out) == 0) goto no_queue; @@ -2845,8 +2846,6 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) return 1; no_queue: - tp->probes_out = 0; - /* If this ack opens up a zero window, clear backoff. It was * being used to time the probes, and is probably far higher than * it needs to be for normal retransmission. diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index 65213e9..70b7f89 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c @@ -172,8 +172,6 @@ match(const struct sk_buff *skb, hdrlen -= 2; if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ return ret; - } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { - DEBUGP("Not strict - not implemented"); } else { DEBUGP("Strict "); DEBUGP("#%d ",optinfo->optsnr); @@ -253,6 +251,10 @@ checkentry(const char *tablename, optsinfo->invflags); return 0; } + if (optsinfo->flags & IP6T_OPTS_NSTRICT) { + DEBUGP("ip6t_opts: Not strict - not implemented"); + return 0; + } return 1; } diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index b37e4ce..63f9980 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c @@ -172,8 +172,6 @@ match(const struct sk_buff *skb, hdrlen -= 2; if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ return ret; - } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { - DEBUGP("Not strict - not implemented"); } else { DEBUGP("Strict "); DEBUGP("#%d ",optinfo->optsnr); @@ -253,6 +251,10 @@ checkentry(const char *tablename, optsinfo->invflags); return 0; } + if (optsinfo->flags & IP6T_OPTS_NSTRICT) { + DEBUGP("ip6t_opts: Not strict - not implemented"); + return 0; + } return 1; }