## Automatically generated incremental diff ## From: linux-2.6.4-rc2 ## To: linux-2.6.4-rc3 ## Robot: $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $ diff -urN linux-2.6.4-rc2/Documentation/cdrom/ide-cd linux-2.6.4-rc3/Documentation/cdrom/ide-cd --- linux-2.6.4-rc2/Documentation/cdrom/ide-cd 2004-02-17 19:58:48.000000000 -0800 +++ linux-2.6.4-rc3/Documentation/cdrom/ide-cd 2004-03-09 16:36:20.000000000 -0800 @@ -74,7 +74,7 @@ 3. The CDROM drive should be connected to the host on an IDE interface. Each interface on a system is defined by an I/O port address and an IRQ number, the standard assignments being - 0x170 and 14 for the primary interface and 0x1f0 and 15 for the + 0x1f0 and 14 for the primary interface and 0x170 and 15 for the secondary interface. Each interface can control up to two devices, where each device can be a hard drive, a CDROM drive, a floppy drive, or a tape drive. The two devices on an interface are called `master' @@ -268,8 +268,8 @@ - Double-check your hardware configuration to make sure that the IRQ number of your IDE interface matches what the driver expects. - (The usual assignments are 14 for the primary (0x170) interface - and 15 for the secondary (0x1f0) interface.) Also be sure that + (The usual assignments are 14 for the primary (0x1f0) interface + and 15 for the secondary (0x170) interface.) Also be sure that you don't have some other hardware which might be conflicting with the IRQ you're using. Also check the BIOS setup for your system; some have the ability to disable individual IRQ levels, and I've diff -urN linux-2.6.4-rc2/Documentation/crypto/api-intro.txt linux-2.6.4-rc3/Documentation/crypto/api-intro.txt --- linux-2.6.4-rc2/Documentation/crypto/api-intro.txt 2004-03-09 16:36:13.000000000 -0800 +++ linux-2.6.4-rc3/Documentation/crypto/api-intro.txt 2004-03-09 16:36:20.000000000 -0800 @@ -186,6 +186,7 @@ Dag Arne Osvik (Serpent) Brian Gladman (AES) Kartikey Mahendra Bhatt (CAST6) + Jon Oberheide (ARC4) SHA1 algorithm contributors: Jean-Francois Dive diff -urN linux-2.6.4-rc2/Documentation/kernel-parameters.txt linux-2.6.4-rc3/Documentation/kernel-parameters.txt --- linux-2.6.4-rc2/Documentation/kernel-parameters.txt 2004-03-09 16:36:13.000000000 -0800 +++ linux-2.6.4-rc3/Documentation/kernel-parameters.txt 2004-03-09 16:36:20.000000000 -0800 @@ -90,10 +90,13 @@ Format: , default is 13 acpi= [HW,ACPI] Advanced Configuration and Power Interface - Format: { force | off | ht } + Format: { force | off | ht | strict } force -- enables ACPI for systems with default off off -- disabled ACPI for systems with default on ht -- run only enough ACPI to enable Hyper Threading + strict -- Be less tolerant of platforms that are not + strictly ACPI specification compliant. + See also Documentation/pm.txt. acpi_pic_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode diff -urN linux-2.6.4-rc2/MAINTAINERS linux-2.6.4-rc3/MAINTAINERS --- linux-2.6.4-rc2/MAINTAINERS 2004-03-09 16:36:13.000000000 -0800 +++ linux-2.6.4-rc3/MAINTAINERS 2004-03-09 16:36:20.000000000 -0800 @@ -172,7 +172,7 @@ P: Len Brown M: len.brown@intel.com L: acpi-devel@lists.sourceforge.net -W: http://sf.net/projects/acpi/ +W: http://acpi.sourceforge.net/ S: Maintained AD1816 SOUND DRIVER diff -urN linux-2.6.4-rc2/Makefile linux-2.6.4-rc3/Makefile --- linux-2.6.4-rc2/Makefile 2004-03-09 16:36:13.000000000 -0800 +++ linux-2.6.4-rc3/Makefile 2004-03-09 16:36:20.000000000 -0800 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 4 -EXTRAVERSION =-rc2 +EXTRAVERSION =-rc3 NAME=Feisty Dunnart # *DOCUMENTATION* diff -urN linux-2.6.4-rc2/arch/alpha/kernel/ptrace.c linux-2.6.4-rc3/arch/alpha/kernel/ptrace.c --- linux-2.6.4-rc2/arch/alpha/kernel/ptrace.c 2004-02-17 19:59:24.000000000 -0800 +++ linux-2.6.4-rc3/arch/alpha/kernel/ptrace.c 2004-03-09 16:36:20.000000000 -0800 @@ -369,8 +369,8 @@ /* Mark single stepping. */ child->thread_info->bpt_nsaved = -1; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - wake_up_process(child); child->exit_code = data; + wake_up_process(child); /* give it a chance to run. */ ret = 0; goto out; diff -urN linux-2.6.4-rc2/arch/arm/Makefile linux-2.6.4-rc3/arch/arm/Makefile --- linux-2.6.4-rc2/arch/arm/Makefile 2004-03-09 16:36:13.000000000 -0800 +++ linux-2.6.4-rc3/arch/arm/Makefile 2004-03-09 16:36:20.000000000 -0800 @@ -23,6 +23,11 @@ AS += -EB LD += -EB AFLAGS += -mbig-endian +else +CFLAGS += -mlittle-endian +AS += -EL +LD += -EL +AFLAGS += -mlittle-endian endif comma = , diff -urN linux-2.6.4-rc2/arch/arm/kernel/armksyms.c linux-2.6.4-rc3/arch/arm/kernel/armksyms.c --- linux-2.6.4-rc2/arch/arm/kernel/armksyms.c 2004-03-09 16:36:13.000000000 -0800 +++ linux-2.6.4-rc3/arch/arm/kernel/armksyms.c 2004-03-09 16:36:21.000000000 -0800 @@ -187,6 +187,7 @@ EXPORT_SYMBOL(__arch_copy_to_user); EXPORT_SYMBOL(__arch_clear_user); EXPORT_SYMBOL(__arch_strnlen_user); +EXPORT_SYMBOL(__arch_strncpy_from_user); /* consistent area handling */ EXPORT_SYMBOL(consistent_alloc); diff -urN linux-2.6.4-rc2/arch/arm/mm/Kconfig linux-2.6.4-rc3/arch/arm/mm/Kconfig --- linux-2.6.4-rc2/arch/arm/mm/Kconfig 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/arm/mm/Kconfig 2004-03-09 16:36:21.000000000 -0800 @@ -347,7 +347,7 @@ help Say Y if you plan on running a kernel in big-endian mode. Note that your board must be properly built and your board - port must properly enable and big-endian related features + port must properly enable any big-endian related features of your chipset/board/processor. config CPU_ICACHE_DISABLE diff -urN linux-2.6.4-rc2/arch/i386/Kconfig linux-2.6.4-rc3/arch/i386/Kconfig --- linux-2.6.4-rc2/arch/i386/Kconfig 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/Kconfig 2004-03-09 16:36:21.000000000 -0800 @@ -1068,12 +1068,16 @@ PCI-based systems don't have any BIOS at all. Linux can also try to detect the PCI hardware directly without using the BIOS. - With this option, you can specify how Linux should detect the PCI - devices. If you choose "BIOS", the BIOS will be used, if you choose - "Direct", the BIOS won't be used, and if you choose "Any", the - kernel will try the direct access method and falls back to the BIOS - if that doesn't work. If unsure, go with the default, which is - "Any". + With this option, you can specify how Linux should detect the + PCI devices. If you choose "BIOS", the BIOS will be used, + if you choose "Direct", the BIOS won't be used, and if you + choose "MMConfig", then PCI Express MMCONFIG will be used. + If you choose "Any", the kernel will try MMCONFIG, then the + direct access method and falls back to the BIOS if that doesn't + work. If unsure, go with the default, which is "Any". + +config PCI_GOMMCONFIG + bool "MMConfig" config PCI_GODIRECT bool "Direct" @@ -1093,6 +1097,12 @@ depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS) default y +config PCI_MMCONFIG + bool + depends on PCI && (PCI_GOMMCONFIG || PCI_GOANY) + select ACPI_BOOT + default y + config PCI_USE_VECTOR bool "Vector-based interrupt indexing (MSI)" depends on X86_LOCAL_APIC && X86_IO_APIC diff -urN linux-2.6.4-rc2/arch/i386/kernel/acpi/boot.c linux-2.6.4-rc3/arch/i386/kernel/acpi/boot.c --- linux-2.6.4-rc2/arch/i386/kernel/acpi/boot.c 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/acpi/boot.c 2004-03-09 16:36:21.000000000 -0800 @@ -35,7 +35,7 @@ #include #include -#if defined (CONFIG_X86_LOCAL_APIC) +#ifdef CONFIG_X86_LOCAL_APIC #include #include #include @@ -43,17 +43,26 @@ #define PREFIX "ACPI: " -int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +int acpi_noirq __initdata; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ int acpi_lapic; int acpi_ioapic; +int acpi_strict; + +#ifdef CONFIG_X86_LOCAL_APIC +static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; +#endif /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ -enum acpi_irq_model_id acpi_irq_model; +/* + * The default interrupt routing model is PIC (8259). This gets + * overriden if IOAPICs are enumerated (below). + */ +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC; /* * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, @@ -96,11 +105,32 @@ } -#ifdef CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_PCI_MMCONFIG +static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_mcfg *mcfg; -static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#endif /* CONFIG_PCI_MMCONFIG */ +#ifdef CONFIG_X86_LOCAL_APIC static int __init acpi_parse_madt ( unsigned long phys_addr, @@ -117,11 +147,12 @@ return -ENODEV; } - if (madt->lapic_address) + if (madt->lapic_address) { acpi_lapic_addr = (u64) madt->lapic_address; - printk(KERN_INFO PREFIX "Local APIC address 0x%08x\n", - madt->lapic_address); + printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", + madt->lapic_address); + } acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); @@ -251,7 +282,7 @@ return 0; } -#endif /*CONFIG_X86_IO_APIC*/ +#endif /* CONFIG_X86_IO_APIC */ #ifdef CONFIG_ACPI_BUS /* @@ -259,7 +290,7 @@ * programs the PIC-mode SCI to Level Trigger. * (NO-OP if the BIOS set Level Trigger already) * - * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's * it may require Edge Trigger -- use "acpi_pic_sci=edge" * (NO-OP if the BIOS set Edge Trigger already) * @@ -347,6 +378,25 @@ return 0; } +static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_sbf *sb; + + if (!phys_addr || !size) + return -EINVAL; + + sb = (struct acpi_table_sbf *) __acpi_map_table(phys_addr, size); + if (!sb) { + printk(KERN_WARNING PREFIX "Unable to map SBF\n"); + return -ENODEV; + } + + sbf_port = sb->sbf_cmos; /* Save CMOS port */ + + return 0; +} + + #ifdef CONFIG_HPET_TIMER extern unsigned long hpet_address; @@ -429,126 +479,61 @@ return rsdp_phys; } +#ifdef CONFIG_X86_LOCAL_APIC /* - * acpi_boot_init() - * called from setup_arch(), always. - * 1. maps ACPI tables for later use - * 2. enumerates lapics - * 3. enumerates io-apics - * - * side effects: - * acpi_lapic = 1 if LAPIC found - * acpi_ioapic = 1 if IOAPIC found - * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; - * if acpi_blacklisted() acpi_disabled = 1; - * acpi_irq_model=... - * ... - * - * return value: (currently ignored) - * 0: success - * !0: failure + * Parse LAPIC entries in MADT + * returns 0 on success, < 0 on error */ - -int __init -acpi_boot_init (void) +static int __init +acpi_parse_madt_lapic_entries(void) { - int result = 0; - - if (acpi_disabled && !acpi_ht) - return 1; - - /* - * The default interrupt routing model is PIC (8259). This gets - * overriden if IOAPICs are enumerated (below). - */ - acpi_irq_model = ACPI_IRQ_MODEL_PIC; - - /* - * Initialize the ACPI boot-time table parser. - */ - result = acpi_table_init(); - if (result) { - acpi_disabled = 1; - return result; - } - - result = acpi_blacklisted(); - if (result) { - printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); - acpi_disabled = 1; - return result; - } - -#ifdef CONFIG_X86_PM_TIMER - acpi_table_parse(ACPI_FADT, acpi_parse_fadt); -#endif - -#ifdef CONFIG_X86_LOCAL_APIC - - /* - * MADT - * ---- - * Parse the Multiple APIC Description Table (MADT), if exists. - * Note that this table provides platform SMP configuration - * information -- the successor to MPS tables. - */ - - result = acpi_table_parse(ACPI_APIC, acpi_parse_madt); - if (!result) { - return 0; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing MADT\n"); - return result; - } - else if (result > 1) - printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n"); + int count; /* - * Local APIC - * ---------- * Note that the LAPIC address is obtained from the MADT (32-bit value) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); - if (result < 0) { + count = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); + if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - return result; + return count; } mp_register_lapic_address(acpi_lapic_addr); - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, MAX_APICS); - if (!result) { + if (!count) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); /* TBD: Cleanup to allow fallback to MPS */ return -ENODEV; } - else if (result < 0) { + else if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ - return result; + return count; } - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); - if (result < 0) { + count = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); + if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ - return result; + return count; } - - acpi_lapic = 1; - -#endif /*CONFIG_X86_LOCAL_APIC*/ + return 0; +} +#endif /* CONFIG_X86_LOCAL_APIC */ #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER) - - /* - * I/O APIC - * -------- - */ +/* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error + */ +static int __init +acpi_parse_madt_ioapic_entries(void) +{ + int count; /* * ACPI interpreter is required to complete interrupt setup, @@ -557,7 +542,7 @@ * otherwise the system will stay in PIC mode */ if (acpi_disabled || acpi_noirq) { - return 1; + return -ENODEV; } /* @@ -566,54 +551,152 @@ if (ioapic_setup_disabled()) { printk(KERN_INFO PREFIX "Skipping IOAPIC probe " "due to 'noapic' option.\n"); - return 1; + return -ENODEV; } - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); - if (!result) { + count = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!count) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); return -ENODEV; } - else if (result < 0) { + else if (count < 0) { printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n"); - return result; + return count; } /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); - if (result < 0) { + count = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); + if (count < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); /* TBD: Cleanup to allow fallback to MPS */ - return result; + return count; } - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS); - if (result < 0) { + count = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS); + if (count < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ - return result; + return count; } - acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + return 0; +} +#else +static inline int acpi_parse_madt_ioapic_entries(void) +{ + return -1; +} +#endif /* !(CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER) */ - acpi_irq_balance_set(NULL); - acpi_ioapic = 1; +static void __init +acpi_process_madt(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + int count, error; -#endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */ + count = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + if (count == 1) { -#ifdef CONFIG_X86_LOCAL_APIC - if (acpi_lapic && acpi_ioapic) { - smp_found_config = 1; - clustered_apic_check(); + /* + * Parse MADT LAPIC entries + */ + error = acpi_parse_madt_lapic_entries(); + if (!error) { + acpi_lapic = 1; + + /* + * Parse MADT IO-APIC entries + */ + error = acpi_parse_madt_ioapic_entries(); + if (!error) { + acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; + + smp_found_config = 1; + clustered_apic_check(); + } + } } #endif + return; +} + +/* + * acpi_boot_init() + * called from setup_arch(), always. + * 1. checksums all tables + * 2. enumerates lapics + * 3. enumerates io-apics + * + * side effects: + * acpi_lapic = 1 if LAPIC found + * acpi_ioapic = 1 if IOAPIC found + * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; + * if acpi_blacklisted() acpi_disabled = 1; + * acpi_irq_model=... + * ... + * + * return value: (currently ignored) + * 0: success + * !0: failure + */ + +int __init +acpi_boot_init (void) +{ + int error; + + /* + * If acpi_disabled, bail out + * One exception: acpi=ht continues far enough to enumerate LAPICs + */ + if (acpi_disabled && !acpi_ht) + return 1; + + /* + * Initialize the ACPI boot-time table parser. + */ + error = acpi_table_init(); + if (error) { + acpi_disabled = 1; + return error; + } + + (void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + + /* + * blacklist may disable ACPI entirely + */ + error = acpi_blacklisted(); + if (error) { + printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); + acpi_disabled = 1; + return error; + } + + /* + * Process the Multiple APIC Description Table (MADT), if present + */ + acpi_process_madt(); + +#ifdef CONFIG_X86_PM_TIMER + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); +#endif #ifdef CONFIG_HPET_TIMER - acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + (void) acpi_table_parse(ACPI_HPET, acpi_parse_hpet); +#endif + +#ifdef CONFIG_PCI_MMCONFIG + error = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if (error) + printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", error); #endif return 0; } + diff -urN linux-2.6.4-rc2/arch/i386/kernel/bootflag.c linux-2.6.4-rc3/arch/i386/kernel/bootflag.c --- linux-2.6.4-rc2/arch/i386/kernel/bootflag.c 2004-02-17 19:59:06.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/bootflag.c 2004-03-09 16:36:21.000000000 -0800 @@ -1,6 +1,5 @@ /* - * Implement 'Simple Boot Flag Specification 1.0' - * + * Implement 'Simple Boot Flag Specification 2.0' */ @@ -11,6 +10,7 @@ #include #include #include +#include #include #include @@ -23,56 +23,8 @@ #define SBF_PARITY (1<<7) -struct sbf_boot -{ - u8 sbf_signature[4]; - u32 sbf_len; - u8 sbf_revision __attribute((packed)); - u8 sbf_csum __attribute((packed)); - u8 sbf_oemid[6] __attribute((packed)); - u8 sbf_oemtable[8] __attribute((packed)); - u8 sbf_revdata[4] __attribute((packed)); - u8 sbf_creator[4] __attribute((packed)); - u8 sbf_crearev[4] __attribute((packed)); - u8 sbf_cmos __attribute((packed)); - u8 sbf_spare[3] __attribute((packed)); -}; - - -static int sbf_port __initdata = -1; - -static int __init sbf_struct_valid(unsigned long tptr) -{ - u8 *ap; - u8 v; - unsigned int i; - struct sbf_boot sb; - - memcpy_fromio(&sb, (void *)tptr, sizeof(sb)); - - if(sb.sbf_len != 40 && sb.sbf_len != 39) - // 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19). - return 0; - - ap = (u8 *)&sb; - v= 0; - - for(i=0;i1) - rsdtlen = *(u32 *)(p+20); - else - rsdtlen = 36; - - if(rsdtlen < 36 || rsdtlen > 1024) - continue; - break; - } - if(i>0xFFFE0) - return 0; - - - rsdt = ioremap(rsdtbase, rsdtlen); - if(rsdt == 0) - return 0; - - i = readl(rsdt + 4); - - /* - * Remap if needed - */ - - if(i > rsdtlen) - { - rsdtlen = i; - iounmap(rsdt); - rsdt = ioremap(rsdtbase, rsdtlen); - if(rsdt == 0) - return 0; - } - - for(n = 0; n < i; n++) - sum += readb(rsdt + n); - - if(sum) - { - iounmap(rsdt); - return 0; - } - - /* Ok the RSDT checksums too */ - - for(n = 36; n+3 < i; n += 4) - { - unsigned long rp = readl(rsdt+n); - int len = 4096; - - if(rp > 0xFFFFFFFFUL - len) - len = 0xFFFFFFFFUL - rp; - - /* Too close to the end!! */ - if(len < 20) - continue; - rp = (unsigned long)ioremap(rp, 4096); - if(rp == 0) - continue; - if(sbf_struct_valid(rp)) - { - /* Found the BOOT table and processed it */ - printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n"); - } - iounmap((void *)rp); - } - iounmap(rsdt); - sbf_bootup(); return 0; } diff -urN linux-2.6.4-rc2/arch/i386/kernel/cpu/centaur.c linux-2.6.4-rc3/arch/i386/kernel/cpu/centaur.c --- linux-2.6.4-rc2/arch/i386/kernel/cpu/centaur.c 2004-02-17 19:58:32.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/cpu/centaur.c 2004-03-09 16:36:21.000000000 -0800 @@ -246,7 +246,15 @@ lo&=~0x1C0; /* blank bits 8-6 */ wrmsr(MSR_IDT_MCR_CTRL, lo, hi); } -#endif +#endif /* CONFIG_X86_OOSTORE */ + +#define ACE_PRESENT (1 << 6) +#define ACE_ENABLED (1 << 7) +#define ACE_FCR (1 << 28) /* MSR_VIA_FCR */ + +#define RNG_PRESENT (1 << 2) +#define RNG_ENABLED (1 << 3) +#define RNG_ENABLE (1 << 6) /* MSR_VIA_RNG */ static void __init init_c3(struct cpuinfo_x86 *c) { @@ -254,6 +262,24 @@ /* Test for Centaur Extended Feature Flags presence */ if (cpuid_eax(0xC0000000) >= 0xC0000001) { + u32 tmp = cpuid_edx(0xC0000001); + + /* enable ACE unit, if present and disabled */ + if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) { + rdmsr (MSR_VIA_FCR, lo, hi); + lo |= ACE_FCR; /* enable ACE unit */ + wrmsr (MSR_VIA_FCR, lo, hi); + printk(KERN_INFO "CPU: Enabled ACE h/w crypto\n"); + } + + /* enable RNG unit, if present and disabled */ + if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) { + rdmsr (MSR_VIA_RNG, lo, hi); + lo |= RNG_ENABLE; /* enable RNG unit */ + wrmsr (MSR_VIA_RNG, lo, hi); + printk(KERN_INFO "CPU: Enabled h/w RNG\n"); + } + /* store Centaur Extended Feature Flags as * word 5 of the CPU capability bit array */ diff -urN linux-2.6.4-rc2/arch/i386/kernel/cpu/proc.c linux-2.6.4-rc3/arch/i386/kernel/cpu/proc.c --- linux-2.6.4-rc2/arch/i386/kernel/cpu/proc.c 2004-02-17 19:59:23.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/cpu/proc.c 2004-03-09 16:36:21.000000000 -0800 @@ -50,7 +50,7 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* VIA/Cyrix/Centaur-defined */ - NULL, NULL, "xstore", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff -urN linux-2.6.4-rc2/arch/i386/kernel/io_apic.c linux-2.6.4-rc3/arch/i386/kernel/io_apic.c --- linux-2.6.4-rc2/arch/i386/kernel/io_apic.c 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/io_apic.c 2004-03-09 16:36:21.000000000 -0800 @@ -694,7 +694,7 @@ #endif /* CONFIG_IRQBALANCE */ #ifndef CONFIG_SMP -void send_IPI_self(int vector) +void fastcall send_IPI_self(int vector) { unsigned int cfg; diff -urN linux-2.6.4-rc2/arch/i386/kernel/mpparse.c linux-2.6.4-rc3/arch/i386/kernel/mpparse.c --- linux-2.6.4-rc2/arch/i386/kernel/mpparse.c 2004-02-17 19:57:21.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/mpparse.c 2004-03-09 16:36:21.000000000 -0800 @@ -1156,7 +1156,7 @@ continue; } if ((1<irq = acpi_irq_to_vector(irq); continue; diff -urN linux-2.6.4-rc2/arch/i386/kernel/process.c linux-2.6.4-rc3/arch/i386/kernel/process.c --- linux-2.6.4-rc2/arch/i386/kernel/process.c 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/process.c 2004-03-09 16:36:21.000000000 -0800 @@ -493,7 +493,7 @@ * the task-switch, and shows up in ret_from_fork in entry.S, * for example. */ -struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; diff -urN linux-2.6.4-rc2/arch/i386/kernel/setup.c linux-2.6.4-rc3/arch/i386/kernel/setup.c --- linux-2.6.4-rc2/arch/i386/kernel/setup.c 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/setup.c 2004-03-09 16:36:21.000000000 -0800 @@ -569,6 +569,11 @@ acpi_disabled = 0; } + /* acpi=strict disables out-of-spec workarounds */ + else if (!memcmp(from, "acpi=strict", 11)) { + acpi_strict = 1; + } + /* Limit ACPI just to boot-time to enable HT */ else if (!memcmp(from, "acpi=ht", 7)) { acpi_ht = 1; diff -urN linux-2.6.4-rc2/arch/i386/kernel/signal.c linux-2.6.4-rc3/arch/i386/kernel/signal.c --- linux-2.6.4-rc2/arch/i386/kernel/signal.c 2004-02-17 19:57:47.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/signal.c 2004-03-09 16:36:21.000000000 -0800 @@ -551,7 +551,7 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -int do_signal(struct pt_regs *regs, sigset_t *oldset) +int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; int signr; diff -urN linux-2.6.4-rc2/arch/i386/kernel/smp.c linux-2.6.4-rc3/arch/i386/kernel/smp.c --- linux-2.6.4-rc2/arch/i386/kernel/smp.c 2004-02-17 19:57:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/smp.c 2004-03-09 16:36:21.000000000 -0800 @@ -150,7 +150,7 @@ apic_write_around(APIC_ICR, cfg); } -void send_IPI_self(int vector) +void fastcall send_IPI_self(int vector) { __send_IPI_shortcut(APIC_DEST_SELF, vector); } diff -urN linux-2.6.4-rc2/arch/i386/kernel/vm86.c linux-2.6.4-rc3/arch/i386/kernel/vm86.c --- linux-2.6.4-rc2/arch/i386/kernel/vm86.c 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/kernel/vm86.c 2004-03-09 16:36:21.000000000 -0800 @@ -95,7 +95,7 @@ #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1) struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); -struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) +struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs) { struct tss_struct *tss; struct pt_regs *ret; diff -urN linux-2.6.4-rc2/arch/i386/mm/extable.c linux-2.6.4-rc3/arch/i386/mm/extable.c --- linux-2.6.4-rc2/arch/i386/mm/extable.c 2004-02-17 19:59:51.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/mm/extable.c 2004-03-09 16:36:21.000000000 -0800 @@ -12,7 +12,7 @@ const struct exception_table_entry *fixup; #ifdef CONFIG_PNPBIOS - if (unlikely((regs->xcs | 8) == 0x88)) /* 0x80 or 0x88 */ + if (unlikely((regs->xcs & ~15) == (GDT_ENTRY_PNPBIOS_BASE << 3))) { extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; extern u32 pnp_bios_is_utter_crap; @@ -21,7 +21,7 @@ __asm__ volatile( "movl %0, %%esp\n\t" "jmp *%1\n\t" - : "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip)); + : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip)); panic("do_trap: can't hit this"); } #endif diff -urN linux-2.6.4-rc2/arch/i386/pci/Makefile linux-2.6.4-rc3/arch/i386/pci/Makefile --- linux-2.6.4-rc2/arch/i386/pci/Makefile 2004-02-17 19:58:12.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/pci/Makefile 2004-03-09 16:36:21.000000000 -0800 @@ -1,6 +1,7 @@ obj-y := i386.o obj-$(CONFIG_PCI_BIOS) += pcbios.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o obj-$(CONFIG_PCI_DIRECT) += direct.o pci-y := fixup.o diff -urN linux-2.6.4-rc2/arch/i386/pci/common.c linux-2.6.4-rc3/arch/i386/pci/common.c --- linux-2.6.4-rc2/arch/i386/pci/common.c 2004-02-17 19:57:31.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/pci/common.c 2004-03-09 16:36:21.000000000 -0800 @@ -20,7 +20,8 @@ extern void pcibios_sort(void); #endif -unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; +unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | + PCI_PROBE_MMCONF; int pcibios_last_bus = -1; struct pci_bus *pci_root_bus = NULL; @@ -198,6 +199,12 @@ return NULL; } #endif +#ifdef CONFIG_PCI_MMCONFIG + else if (!strcmp(str, "nommconf")) { + pci_probe &= ~PCI_PROBE_MMCONF; + return NULL; + } +#endif else if (!strcmp(str, "noacpi")) { acpi_noirq_set(); return NULL; diff -urN linux-2.6.4-rc2/arch/i386/pci/mmconfig.c linux-2.6.4-rc3/arch/i386/pci/mmconfig.c --- linux-2.6.4-rc2/arch/i386/pci/mmconfig.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/pci/mmconfig.c 2004-03-09 16:36:21.000000000 -0800 @@ -0,0 +1,109 @@ +/* + * mmconfig.c - Low-level direct PCI config space access via MMCONFIG + */ + +#include +#include +#include "pci.h" + +/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ +u32 pci_mmcfg_base_addr; + +#define mmcfg_virt_addr (fix_to_virt(FIX_PCIE_MCFG)) + +/* The base address of the last MMCONFIG device accessed */ +static u32 mmcfg_last_accessed_device; + +/* + * Functions for accessing PCI configuration space with MMCONFIG accesses + */ + +static inline void pci_exp_set_dev_base(int bus, int devfn) +{ + u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12); + if (dev_base != mmcfg_last_accessed_device) { + mmcfg_last_accessed_device = dev_base; + set_fixmap(FIX_PCIE_MCFG, dev_base); + } +} + +static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value) +{ + unsigned long flags; + + if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + pci_exp_set_dev_base(bus, devfn); + + switch (len) { + case 1: + *value = readb(mmcfg_virt_addr + reg); + break; + case 2: + *value = readw(mmcfg_virt_addr + reg); + break; + case 4: + *value = readl(mmcfg_virt_addr + reg); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value) +{ + unsigned long flags; + + if ((bus > 255) || (devfn > 255) || (reg > 4095)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + pci_exp_set_dev_base(bus, devfn); + + switch (len) { + case 1: + writeb(value, mmcfg_virt_addr + reg); + break; + case 2: + writew(value, mmcfg_virt_addr + reg); + break; + case 4: + writel(value, mmcfg_virt_addr + reg); + break; + } + + /* Dummy read to flush PCI write */ + readl(mmcfg_virt_addr); + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static struct pci_raw_ops pci_mmcfg = { + .read = pci_mmcfg_read, + .write = pci_mmcfg_write, +}; + +static int __init pci_mmcfg_init(void) +{ + if ((pci_probe & PCI_PROBE_MMCONF) == 0) + goto out; + if (!pci_mmcfg_base_addr) + goto out; + + printk(KERN_INFO "PCI: Using MMCONFIG\n"); + raw_pci_ops = &pci_mmcfg; + pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; + + out: + return 0; +} + +arch_initcall(pci_mmcfg_init); diff -urN linux-2.6.4-rc2/arch/i386/pci/pci.h linux-2.6.4-rc3/arch/i386/pci/pci.h --- linux-2.6.4-rc2/arch/i386/pci/pci.h 2004-02-17 19:58:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/i386/pci/pci.h 2004-03-09 16:36:21.000000000 -0800 @@ -15,6 +15,9 @@ #define PCI_PROBE_BIOS 0x0001 #define PCI_PROBE_CONF1 0x0002 #define PCI_PROBE_CONF2 0x0004 +#define PCI_PROBE_MMCONF 0x0008 +#define PCI_PROBE_MASK 0x000f + #define PCI_NO_SORT 0x0100 #define PCI_BIOS_SORT 0x0200 #define PCI_NO_CHECKS 0x0400 diff -urN linux-2.6.4-rc2/arch/mips/kernel/ioctl32.c linux-2.6.4-rc3/arch/mips/kernel/ioctl32.c --- linux-2.6.4-rc2/arch/mips/kernel/ioctl32.c 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/mips/kernel/ioctl32.c 2004-03-09 16:36:22.000000000 -0800 @@ -1277,20 +1277,6 @@ COMPATIBLE_IOCTL(SBPROF_ZBWAITFULL) #endif /* CONFIG_SIBYTE_TBPROF */ -#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) -COMPATIBLE_IOCTL(DM_VERSION) -COMPATIBLE_IOCTL(DM_REMOVE_ALL) -COMPATIBLE_IOCTL(DM_DEV_CREATE) -COMPATIBLE_IOCTL(DM_DEV_REMOVE) -COMPATIBLE_IOCTL(DM_DEV_RELOAD) -COMPATIBLE_IOCTL(DM_DEV_SUSPEND) -COMPATIBLE_IOCTL(DM_DEV_RENAME) -COMPATIBLE_IOCTL(DM_DEV_DEPS) -COMPATIBLE_IOCTL(DM_DEV_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_WAIT) -#endif /* CONFIG_BLK_DEV_DM */ - COMPATIBLE_IOCTL(MTIOCTOP) /* mtio.h ioctls */ HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) diff -urN linux-2.6.4-rc2/arch/ppc/kernel/head.S linux-2.6.4-rc3/arch/ppc/kernel/head.S --- linux-2.6.4-rc2/arch/ppc/kernel/head.S 2004-02-17 19:58:10.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc/kernel/head.S 2004-03-09 16:36:23.000000000 -0800 @@ -1492,22 +1492,22 @@ * seems that doesn't affect our ability to actually * write to these SPRs. */ - mtspr SPRN_DBAT4U,r20 - mtspr SPRN_DBAT4L,r20 - mtspr SPRN_DBAT5U,r20 - mtspr SPRN_DBAT5L,r20 - mtspr SPRN_DBAT6U,r20 - mtspr SPRN_DBAT6L,r20 - mtspr SPRN_DBAT7U,r20 - mtspr SPRN_DBAT7L,r20 - mtspr SPRN_IBAT4U,r20 - mtspr SPRN_IBAT4L,r20 - mtspr SPRN_IBAT5U,r20 - mtspr SPRN_IBAT5L,r20 - mtspr SPRN_IBAT6U,r20 - mtspr SPRN_IBAT6L,r20 - mtspr SPRN_IBAT7U,r20 - mtspr SPRN_IBAT7L,r20 + mtspr SPRN_DBAT4U,r10 + mtspr SPRN_DBAT4L,r10 + mtspr SPRN_DBAT5U,r10 + mtspr SPRN_DBAT5L,r10 + mtspr SPRN_DBAT6U,r10 + mtspr SPRN_DBAT6L,r10 + mtspr SPRN_DBAT7U,r10 + mtspr SPRN_DBAT7L,r10 + mtspr SPRN_IBAT4U,r10 + mtspr SPRN_IBAT4L,r10 + mtspr SPRN_IBAT5U,r10 + mtspr SPRN_IBAT5L,r10 + mtspr SPRN_IBAT6U,r10 + mtspr SPRN_IBAT6L,r10 + mtspr SPRN_IBAT7U,r10 + mtspr SPRN_IBAT7L,r10 END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) blr diff -urN linux-2.6.4-rc2/arch/ppc64/Kconfig linux-2.6.4-rc3/arch/ppc64/Kconfig --- linux-2.6.4-rc2/arch/ppc64/Kconfig 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/Kconfig 2004-03-09 16:36:23.000000000 -0800 @@ -300,10 +300,6 @@ If you are running Linux on an IBM iSeries system and you want to read a CD drive owned by OS/400, say Y here. -config VIOCD_AZTECH - bool "iSeries Virtual CD Aztech emulation" - depends on VIOCD - config VIOTAPE tristate "iSeries Virtual Tape Support" help diff -urN linux-2.6.4-rc2/arch/ppc64/kernel/iSeries_iommu.c linux-2.6.4-rc3/arch/ppc64/kernel/iSeries_iommu.c --- linux-2.6.4-rc2/arch/ppc64/kernel/iSeries_iommu.c 2004-03-09 16:36:14.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/kernel/iSeries_iommu.c 2004-03-09 16:36:23.000000000 -0800 @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -58,11 +59,6 @@ static struct pci_dev _veth_dev = { .sysdata = &veth_dev_node }; static struct pci_dev _vio_dev = { .sysdata = &vio_dev_node, .dev.bus = &pci_bus_type }; -/* - * I wonder what the deal is with these. Nobody uses them. Why do they - * exist? Why do we export them to modules? Why is this comment here, and - * why didn't I just delete them? - */ struct pci_dev *iSeries_veth_dev = &_veth_dev; struct device *iSeries_vio_dev = &_vio_dev.dev; diff -urN linux-2.6.4-rc2/arch/ppc64/kernel/mf.c linux-2.6.4-rc3/arch/ppc64/kernel/mf.c --- linux-2.6.4-rc2/arch/ppc64/kernel/mf.c 2004-02-17 19:58:50.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/kernel/mf.c 2004-03-09 16:36:23.000000000 -0800 @@ -38,10 +38,9 @@ #include #include #include -#include +#include #include - -extern struct pci_dev *iSeries_vio_dev; +#include /* * This is the structure layout for the Machine Facilites LPAR event @@ -791,7 +790,8 @@ { struct VspCmdData myVspCmd; dma_addr_t dma_addr = 0; - char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr); + char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr, + GFP_ATOMIC); if (page == NULL) { printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n"); @@ -809,7 +809,7 @@ mb(); (void)signal_vsp_instruction(&myVspCmd); - pci_free_consistent(iSeries_vio_dev, size, page, dma_addr); + dma_free_coherent(iSeries_vio_dev, size, page, dma_addr); } int mf_getCmdLine(char *cmdline, int *size, u64 side) @@ -819,8 +819,8 @@ int len = *size; dma_addr_t dma_addr; - dma_addr = pci_map_single(iSeries_vio_dev, cmdline, len, - PCI_DMA_FROMDEVICE); + dma_addr = dma_map_single(iSeries_vio_dev, cmdline, len, + DMA_FROM_DEVICE); memset(cmdline, 0, len); memset(&myVspCmd, 0, sizeof(myVspCmd)); myVspCmd.cmd = 33; @@ -840,7 +840,7 @@ #endif } - pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE); + dma_unmap_single(iSeries_vio_dev, dma_addr, *size, DMA_FROM_DEVICE); return len; } @@ -851,7 +851,8 @@ struct VspCmdData myVspCmd; int rc; dma_addr_t dma_addr = 0; - char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr); + char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr, + GFP_ATOMIC); if (page == NULL) { printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); @@ -876,7 +877,7 @@ rc = -ENOMEM; } - pci_free_consistent(iSeries_vio_dev, size, page, dma_addr); + dma_free_coherent(iSeries_vio_dev, size, page, dma_addr); return rc; } @@ -888,8 +889,8 @@ int len = *size; dma_addr_t dma_addr; - dma_addr = pci_map_single(iSeries_vio_dev, buffer, len, - PCI_DMA_FROMDEVICE); + dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, + DMA_FROM_DEVICE); memset(buffer, 0, len); memset(&myVspCmd, 0, sizeof(myVspCmd)); myVspCmd.cmd = 32; @@ -907,7 +908,7 @@ rc = -ENOMEM; } - pci_unmap_single(iSeries_vio_dev, dma_addr, len, PCI_DMA_FROMDEVICE); + dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); return rc; } diff -urN linux-2.6.4-rc2/arch/ppc64/kernel/stab.c linux-2.6.4-rc3/arch/ppc64/kernel/stab.c --- linux-2.6.4-rc2/arch/ppc64/kernel/stab.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/kernel/stab.c 2004-03-09 16:36:23.000000000 -0800 @@ -184,13 +184,13 @@ /* Kernel or user address? */ if (REGION_ID(ea) >= KERNEL_REGION_ID) { vsid = get_kernel_vsid(ea); - context = REGION_ID(ea); + context = KERNEL_CONTEXT(ea); } else { if (!current->mm) return 1; context = current->mm->context; - vsid = get_vsid(context, ea); + vsid = get_vsid(context.id, ea); } esid = GET_ESID(ea); @@ -223,7 +223,7 @@ if (!IS_VALID_EA(pc) || (REGION_ID(pc) >= KERNEL_REGION_ID)) return; - vsid = get_vsid(mm->context, pc); + vsid = get_vsid(mm->context.id, pc); __ste_allocate(pc_esid, vsid); if (pc_esid == stack_esid) @@ -231,7 +231,7 @@ if (!IS_VALID_EA(stack) || (REGION_ID(stack) >= KERNEL_REGION_ID)) return; - vsid = get_vsid(mm->context, stack); + vsid = get_vsid(mm->context.id, stack); __ste_allocate(stack_esid, vsid); if (pc_esid == unmapped_base_esid || stack_esid == unmapped_base_esid) @@ -240,7 +240,7 @@ if (!IS_VALID_EA(unmapped_base) || (REGION_ID(unmapped_base) >= KERNEL_REGION_ID)) return; - vsid = get_vsid(mm->context, unmapped_base); + vsid = get_vsid(mm->context.id, unmapped_base); __ste_allocate(unmapped_base_esid, vsid); /* Order update */ @@ -406,14 +406,14 @@ /* Kernel or user address? */ if (REGION_ID(ea) >= KERNEL_REGION_ID) { - context = REGION_ID(ea); + context = KERNEL_CONTEXT(ea); vsid = get_kernel_vsid(ea); } else { if (unlikely(!current->mm)) return 1; context = current->mm->context; - vsid = get_vsid(context, ea); + vsid = get_vsid(context.id, ea); } esid = GET_ESID(ea); @@ -444,7 +444,7 @@ if (!IS_VALID_EA(pc) || (REGION_ID(pc) >= KERNEL_REGION_ID)) return; - vsid = get_vsid(mm->context, pc); + vsid = get_vsid(mm->context.id, pc); __slb_allocate(pc_esid, vsid, mm->context); if (pc_esid == stack_esid) @@ -452,7 +452,7 @@ if (!IS_VALID_EA(stack) || (REGION_ID(stack) >= KERNEL_REGION_ID)) return; - vsid = get_vsid(mm->context, stack); + vsid = get_vsid(mm->context.id, stack); __slb_allocate(stack_esid, vsid, mm->context); if (pc_esid == unmapped_base_esid || stack_esid == unmapped_base_esid) @@ -461,7 +461,7 @@ if (!IS_VALID_EA(unmapped_base) || (REGION_ID(unmapped_base) >= KERNEL_REGION_ID)) return; - vsid = get_vsid(mm->context, unmapped_base); + vsid = get_vsid(mm->context.id, unmapped_base); __slb_allocate(unmapped_base_esid, vsid, mm->context); } diff -urN linux-2.6.4-rc2/arch/ppc64/kernel/viopath.c linux-2.6.4-rc3/arch/ppc64/kernel/viopath.c --- linux-2.6.4-rc2/arch/ppc64/kernel/viopath.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/kernel/viopath.c 2004-03-09 16:36:23.000000000 -0800 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -49,8 +48,6 @@ #include #include -extern struct device *iSeries_vio_dev; - /* Status of the path to each other partition in the system. * This is overkill, since we will only ever establish connections * to our hosting partition and the primary partition on the system. diff -urN linux-2.6.4-rc2/arch/ppc64/mm/hash_utils.c linux-2.6.4-rc3/arch/ppc64/mm/hash_utils.c --- linux-2.6.4-rc2/arch/ppc64/mm/hash_utils.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/mm/hash_utils.c 2004-03-09 16:36:23.000000000 -0800 @@ -265,7 +265,7 @@ if (mm == NULL) return 1; - vsid = get_vsid(mm->context, ea); + vsid = get_vsid(mm->context.id, ea); break; case IO_REGION_ID: mm = &ioremap_mm; diff -urN linux-2.6.4-rc2/arch/ppc64/mm/hugetlbpage.c linux-2.6.4-rc3/arch/ppc64/mm/hugetlbpage.c --- linux-2.6.4-rc2/arch/ppc64/mm/hugetlbpage.c 2004-02-17 19:57:59.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/mm/hugetlbpage.c 2004-03-09 16:36:23.000000000 -0800 @@ -244,7 +244,7 @@ struct vm_area_struct *vma; unsigned long addr; - if (mm->context & CONTEXT_LOW_HPAGES) + if (mm->context.low_hpages) return 0; /* The window is already open */ /* Check no VMAs are in the region */ @@ -281,7 +281,7 @@ /* FIXME: do we need to scan for PTEs too? */ - mm->context |= CONTEXT_LOW_HPAGES; + mm->context.low_hpages = 1; /* the context change must make it to memory before the slbia, * so that further SLB misses do the right thing. */ @@ -589,7 +589,6 @@ } } - unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) @@ -778,7 +777,7 @@ BUG_ON(hugepte_bad(pte)); BUG_ON(!in_hugepage_area(context, ea)); - vsid = get_vsid(context, ea); + vsid = get_vsid(context.id, ea); va = (vsid << 28) | (ea & 0x0fffffff); vpn = va >> LARGE_PAGE_SHIFT; diff -urN linux-2.6.4-rc2/arch/ppc64/mm/init.c linux-2.6.4-rc3/arch/ppc64/mm/init.c --- linux-2.6.4-rc2/arch/ppc64/mm/init.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/mm/init.c 2004-03-09 16:36:23.000000000 -0800 @@ -794,7 +794,7 @@ if (!ptep) return; - vsid = get_vsid(vma->vm_mm->context, ea); + vsid = get_vsid(vma->vm_mm->context.id, ea); tmp = cpumask_of_cpu(smp_processor_id()); if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) diff -urN linux-2.6.4-rc2/arch/ppc64/mm/tlb.c linux-2.6.4-rc3/arch/ppc64/mm/tlb.c --- linux-2.6.4-rc2/arch/ppc64/mm/tlb.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/mm/tlb.c 2004-03-09 16:36:23.000000000 -0800 @@ -62,7 +62,7 @@ addr = ptep_to_address(ptep); if (REGION_ID(addr) == USER_REGION_ID) - context = mm->context; + context = mm->context.id; i = batch->index; /* diff -urN linux-2.6.4-rc2/arch/ppc64/xmon/xmon.c linux-2.6.4-rc3/arch/ppc64/xmon/xmon.c --- linux-2.6.4-rc2/arch/ppc64/xmon/xmon.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/ppc64/xmon/xmon.c 2004-03-09 16:36:23.000000000 -0800 @@ -344,7 +344,7 @@ #endif /* CONFIG_SMP */ set_msrd(msr); /* restore interrupt enable */ - return 0; + return 1; } int diff -urN linux-2.6.4-rc2/arch/sparc/Kconfig linux-2.6.4-rc3/arch/sparc/Kconfig --- linux-2.6.4-rc2/arch/sparc/Kconfig 2004-02-17 19:57:11.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/Kconfig 2004-03-09 16:36:24.000000000 -0800 @@ -380,11 +380,32 @@ menu "Kernel hacking" +config DEBUG_KERNEL + bool "Kernel debugging" + help + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + config DEBUG_SLAB bool "Debug memory allocations" + depends on DEBUG_KERNEL + help + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. config MAGIC_SYSRQ bool "Magic SysRq key" + depends on DEBUG_KERNEL help If you say Y here, you will have some control over the system even if the system crashes for example during kernel debugging (e.g., you @@ -398,22 +419,30 @@ config DEBUG_SPINLOCK bool "Spinlock debugging" + depends on DEBUG_KERNEL + help + Say Y here and build SMP to catch missing spinlock initialization + and certain other kinds of spinlock errors commonly made. This is + best used in conjunction with the NMI watchdog so that spinlock + deadlocks are also debuggable. config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM help - This options enables addition error checking for high memory systems. - Disable for production systems. + This options enables additional error checking for high memory + systems. Disable for production systems. config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" + depends on DEBUG_KERNEL help If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. config DEBUG_BUGVERBOSE bool "Verbose BUG() reporting (adds 70K)" + depends on DEBUG_KERNEL help Say Y here to make BUG() panics output the file name and line number of the BUG call as well as the EIP and oops trace. This aids diff -urN linux-2.6.4-rc2/arch/sparc/kernel/sparc_ksyms.c linux-2.6.4-rc3/arch/sparc/kernel/sparc_ksyms.c --- linux-2.6.4-rc2/arch/sparc/kernel/sparc_ksyms.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/kernel/sparc_ksyms.c 2004-03-09 16:36:24.000000000 -0800 @@ -157,7 +157,6 @@ #ifdef CONFIG_SMP /* IRQ implementation. */ -EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(synchronize_irq); /* Misc SMP information */ diff -urN linux-2.6.4-rc2/arch/sparc/kernel/sys_sunos.c linux-2.6.4-rc3/arch/sparc/kernel/sys_sunos.c --- linux-2.6.4-rc2/arch/sparc/kernel/sys_sunos.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/kernel/sys_sunos.c 2004-03-09 16:36:24.000000000 -0800 @@ -682,8 +682,8 @@ static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) { - int server_fd; - char *the_name; + int server_fd, err; + char *the_name, *mount_page; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args sunos_mount; @@ -736,7 +736,16 @@ sizeof(linux_nfs_mount.hostname)); putname (the_name); - return do_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount); + mount_page = (char *) get_zeroed_page(GFP_KERNEL); + if (!mount_page) + return -ENOMEM; + + memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount)); + + err = do_mount("", dir_name, "nfs", linux_flags, mount_page); + + free_page((unsigned long) mount_page); + return err; } asmlinkage int diff -urN linux-2.6.4-rc2/arch/sparc/kernel/trampoline.S linux-2.6.4-rc3/arch/sparc/kernel/trampoline.S --- linux-2.6.4-rc2/arch/sparc/kernel/trampoline.S 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/kernel/trampoline.S 2004-03-09 16:36:24.000000000 -0800 @@ -13,6 +13,7 @@ #include #include #include +#include .globl sun4m_cpu_startup, __smp4m_processor_id .globl sun4d_cpu_startup, __smp4d_processor_id diff -urN linux-2.6.4-rc2/arch/sparc/mm/nosun4c.c linux-2.6.4-rc3/arch/sparc/mm/nosun4c.c --- linux-2.6.4-rc2/arch/sparc/mm/nosun4c.c 2004-02-17 19:59:57.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/mm/nosun4c.c 2004-03-09 16:36:24.000000000 -0800 @@ -57,6 +57,11 @@ return NULL; } +pte_t *sun4c_pte_offset_kernel(pmd_t *dir, unsigned long address) +{ + return NULL; +} + void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) { } diff -urN linux-2.6.4-rc2/arch/sparc/mm/srmmu.c linux-2.6.4-rc3/arch/sparc/mm/srmmu.c --- linux-2.6.4-rc2/arch/sparc/mm/srmmu.c 2004-02-17 19:58:16.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/mm/srmmu.c 2004-03-09 16:36:24.000000000 -0800 @@ -627,8 +627,16 @@ */ struct thread_info *srmmu_alloc_thread_info(void) { - return (struct thread_info *) - __get_free_pages(GFP_KERNEL, THREAD_INFO_ORDER); + struct thread_info *ret; + + ret = (struct thread_info *)__get_free_pages(GFP_KERNEL, + THREAD_INFO_ORDER); +#ifdef CONFIG_DEBUG_STACK_USAGE + if (ret) + memset(ret, 0, PAGE_SIZE << THREAD_INFO_ORDER); +#endif /* DEBUG_STACK_USAGE */ + + return ret; } static void srmmu_free_thread_info(struct thread_info *ti) diff -urN linux-2.6.4-rc2/arch/sparc/mm/sun4c.c linux-2.6.4-rc3/arch/sparc/mm/sun4c.c --- linux-2.6.4-rc2/arch/sparc/mm/sun4c.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc/mm/sun4c.c 2004-03-09 16:36:24.000000000 -0800 @@ -1058,6 +1058,11 @@ #ifndef CONFIG_SUN4 sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE)); #endif + +#ifdef CONFIG_DEBUG_STACK_USAGE + memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER); +#endif /* DEBUG_STACK_USAGE */ + return (struct thread_info *) addr; } diff -urN linux-2.6.4-rc2/arch/sparc64/defconfig linux-2.6.4-rc3/arch/sparc64/defconfig --- linux-2.6.4-rc2/arch/sparc64/defconfig 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc64/defconfig 2004-03-09 16:36:24.000000000 -0800 @@ -100,19 +100,19 @@ CONFIG_PRINTER=m CONFIG_ENVCTRL=m CONFIG_DISPLAY7SEG=m -CONFIG_WATCHDOG_CP1XXX=m -CONFIG_WATCHDOG_RIO=m # CONFIG_CMDLINE_BOOL is not set # # Generic Driver Options # CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set # # Graphics support # CONFIG_FB=y +# CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set # CONFIG_FB_IMSTT is not set # CONFIG_FB_BW2 is not set @@ -211,7 +211,6 @@ CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set -CONFIG_DCSSBLK=m # # ATA/ATAPI/MFM/RLL support @@ -407,6 +406,8 @@ # # CONFIG_IEEE1394_VERBOSEDEBUG is not set CONFIG_IEEE1394_OUI_DB=y +CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y +CONFIG_IEEE1394_CONFIG_ROM_IP1394=y # # Device Drivers @@ -1638,6 +1639,8 @@ # Watchdog Device Drivers # CONFIG_SOFT_WATCHDOG=m +CONFIG_WATCHDOG_CP1XXX=m +CONFIG_WATCHDOG_RIO=m # # PCI-based Watchdog Cards @@ -1647,6 +1650,11 @@ CONFIG_WDT_501_PCI=y # +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# # Profiling support # CONFIG_PROFILING=y @@ -1691,6 +1699,7 @@ CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_TEST=m diff -urN linux-2.6.4-rc2/arch/sparc64/kernel/ioctl32.c linux-2.6.4-rc3/arch/sparc64/kernel/ioctl32.c --- linux-2.6.4-rc2/arch/sparc64/kernel/ioctl32.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc64/kernel/ioctl32.c 2004-03-09 16:36:24.000000000 -0800 @@ -1117,34 +1117,6 @@ COMPATIBLE_IOCTL(BNEPCONNDEL) COMPATIBLE_IOCTL(BNEPGETCONNLIST) COMPATIBLE_IOCTL(BNEPGETCONNINFO) -/* device-mapper */ -#if defined(CONFIG_DM_IOCTL_V4) -COMPATIBLE_IOCTL(DM_VERSION) -COMPATIBLE_IOCTL(DM_REMOVE_ALL) -COMPATIBLE_IOCTL(DM_LIST_DEVICES) -COMPATIBLE_IOCTL(DM_DEV_CREATE) -COMPATIBLE_IOCTL(DM_DEV_REMOVE) -COMPATIBLE_IOCTL(DM_DEV_RENAME) -COMPATIBLE_IOCTL(DM_DEV_SUSPEND) -COMPATIBLE_IOCTL(DM_DEV_STATUS) -COMPATIBLE_IOCTL(DM_DEV_WAIT) -COMPATIBLE_IOCTL(DM_TABLE_LOAD) -COMPATIBLE_IOCTL(DM_TABLE_CLEAR) -COMPATIBLE_IOCTL(DM_TABLE_DEPS) -COMPATIBLE_IOCTL(DM_TABLE_STATUS) -#else -COMPATIBLE_IOCTL(DM_VERSION) -COMPATIBLE_IOCTL(DM_REMOVE_ALL) -COMPATIBLE_IOCTL(DM_DEV_CREATE) -COMPATIBLE_IOCTL(DM_DEV_REMOVE) -COMPATIBLE_IOCTL(DM_DEV_RELOAD) -COMPATIBLE_IOCTL(DM_DEV_SUSPEND) -COMPATIBLE_IOCTL(DM_DEV_RENAME) -COMPATIBLE_IOCTL(DM_DEV_DEPS) -COMPATIBLE_IOCTL(DM_DEV_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_WAIT) -#endif /* And these ioctls need translation */ /* NCPFS */ HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest) diff -urN linux-2.6.4-rc2/arch/sparc64/kernel/smp.c linux-2.6.4-rc3/arch/sparc64/kernel/smp.c --- linux-2.6.4-rc2/arch/sparc64/kernel/smp.c 2004-02-17 19:57:11.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc64/kernel/smp.c 2004-03-09 16:36:24.000000000 -0800 @@ -46,7 +46,6 @@ static unsigned char boot_cpu_id; cpumask_t cpu_online_map = CPU_MASK_NONE; -atomic_t sparc64_num_cpus_possible = ATOMIC_INIT(0); cpumask_t phys_cpu_present_map = CPU_MASK_NONE; static cpumask_t smp_commenced_mask; static cpumask_t cpu_callout_map; @@ -1236,20 +1235,17 @@ instance = 0; while (!cpu_find_by_instance(instance, NULL, &mid)) { - if (mid < max_cpus) { + if (mid < max_cpus) cpu_set(mid, phys_cpu_present_map); - atomic_inc(&sparc64_num_cpus_possible); - } instance++; } - if (atomic_read(&sparc64_num_cpus_possible) > max_cpus) { + if (num_possible_cpus() > max_cpus) { instance = 0; while (!cpu_find_by_instance(instance, NULL, &mid)) { if (mid != boot_cpu_id) { cpu_clear(mid, phys_cpu_present_map); - atomic_dec(&sparc64_num_cpus_possible); - if (atomic_read(&sparc64_num_cpus_possible) <= max_cpus) + if (num_possible_cpus() <= max_cpus) break; } instance++; diff -urN linux-2.6.4-rc2/arch/sparc64/kernel/sparc64_ksyms.c linux-2.6.4-rc3/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.6.4-rc2/arch/sparc64/kernel/sparc64_ksyms.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc64/kernel/sparc64_ksyms.c 2004-03-09 16:36:24.000000000 -0800 @@ -145,7 +145,6 @@ /* CPU online map and active count. */ EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(phys_cpu_present_map); -EXPORT_SYMBOL(sparc64_num_cpus_possible); /* Spinlock debugging library, optional. */ #ifdef CONFIG_DEBUG_SPINLOCK diff -urN linux-2.6.4-rc2/arch/sparc64/kernel/sys_sunos32.c linux-2.6.4-rc3/arch/sparc64/kernel/sys_sunos32.c --- linux-2.6.4-rc2/arch/sparc64/kernel/sys_sunos32.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/sparc64/kernel/sys_sunos32.c 2004-03-09 16:36:24.000000000 -0800 @@ -650,8 +650,8 @@ /* XXXXXXXXXXXXXXXXXXXX */ static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) { - int server_fd; - char *the_name; + int server_fd, err; + char *the_name, *mount_page; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args sunos_mount; @@ -704,7 +704,16 @@ sizeof(linux_nfs_mount.hostname)); putname (the_name); - return do_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount); + mount_page = (char *) get_zeroed_page(GFP_KERNEL); + if (!mount_page) + return -ENOMEM; + + memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount)); + + err = do_mount("", dir_name, "nfs", linux_flags, mount_page); + + free_page((unsigned long) mount_page); + return err; } /* XXXXXXXXXXXXXXXXXXXX */ diff -urN linux-2.6.4-rc2/arch/x86_64/kernel/acpi/boot.c linux-2.6.4-rc3/arch/x86_64/kernel/acpi/boot.c --- linux-2.6.4-rc2/arch/x86_64/kernel/acpi/boot.c 2004-02-17 19:57:19.000000000 -0800 +++ linux-2.6.4-rc3/arch/x86_64/kernel/acpi/boot.c 2004-03-09 16:36:24.000000000 -0800 @@ -48,11 +48,12 @@ #define PREFIX "ACPI: " -int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +int acpi_noirq __initdata; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ int acpi_lapic; int acpi_ioapic; +int acpi_strict; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -264,7 +265,7 @@ * programs the PIC-mode SCI to Level Trigger. * (NO-OP if the BIOS set Level Trigger already) * - * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's * it may require Edge Trigger -- use "acpi_pic_sci=edge" * (NO-OP if the BIOS set Edge Trigger already) * diff -urN linux-2.6.4-rc2/arch/x86_64/kernel/mpparse.c linux-2.6.4-rc3/arch/x86_64/kernel/mpparse.c --- linux-2.6.4-rc2/arch/x86_64/kernel/mpparse.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/arch/x86_64/kernel/mpparse.c 2004-03-09 16:36:24.000000000 -0800 @@ -996,7 +996,7 @@ continue; } if ((1< + * + * 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 + +#define ARC4_MIN_KEY_SIZE 1 +#define ARC4_MAX_KEY_SIZE 256 +#define ARC4_BLOCK_SIZE 1 + +struct arc4_ctx { + u8 S[256]; + u8 x, y; +}; + +static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) +{ + struct arc4_ctx *ctx = ctx_arg; + int i, j = 0, k = 0; + + ctx->x = 1; + ctx->y = 0; + + for(i = 0; i < 256; i++) + ctx->S[i] = i; + + for(i = 0; i < 256; i++) + { + u8 a = ctx->S[i]; + j = (j + in_key[k] + a) & 0xff; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = a; + if(++k >= key_len) + k = 0; + } + + /* TODO: dump the first 768 bytes generated as recommended + by Ilya Mironov (http://eprint.iacr.org/2002/067/) to + increase the statistical strength of the state table */ + + return 0; +} + +static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in) +{ + struct arc4_ctx *ctx = ctx_arg; + + u8 *const S = ctx->S; + u8 x = ctx->x; + u8 y = ctx->y; + u8 a, b; + + a = S[x]; + y = (y + a) & 0xff; + b = S[y]; + S[x] = b; + S[y] = a; + x = (x + 1) & 0xff; + *out++ = *in ^ S[(a + b) & 0xff]; + + ctx->x = x; + ctx->y = y; +} + +static struct crypto_alg arc4_alg = { + .cra_name = "arc4", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = ARC4_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct arc4_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = ARC4_MIN_KEY_SIZE, + .cia_max_keysize = ARC4_MAX_KEY_SIZE, + .cia_setkey = arc4_set_key, + .cia_encrypt = arc4_crypt, + .cia_decrypt = arc4_crypt } } +}; + +static int __init arc4_init(void) +{ + return crypto_register_alg(&arc4_alg); +} + + +static void __exit arc4_exit(void) +{ + crypto_unregister_alg(&arc4_alg); +} + +module_init(arc4_init); +module_exit(arc4_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); +MODULE_AUTHOR("Jon Oberheide "); diff -urN linux-2.6.4-rc2/crypto/tcrypt.c linux-2.6.4-rc3/crypto/tcrypt.c --- linux-2.6.4-rc2/crypto/tcrypt.c 2004-02-17 19:59:11.000000000 -0800 +++ linux-2.6.4-rc3/crypto/tcrypt.c 2004-03-09 16:36:24.000000000 -0800 @@ -61,7 +61,7 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", - "deflate", NULL + "arc4", "deflate", NULL }; static void @@ -556,6 +556,10 @@ test_cipher ("cast6", MODE_ECB, ENCRYPT, cast6_enc_tv_template, CAST6_ENC_TEST_VECTORS); test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS); + //ARC4 + test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS); + test_cipher ("arc4x", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_deflate(); @@ -638,6 +642,11 @@ test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS); break; + case 16: + test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS); + test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS); + break; + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); diff -urN linux-2.6.4-rc2/crypto/tcrypt.h linux-2.6.4-rc3/crypto/tcrypt.h --- linux-2.6.4-rc2/crypto/tcrypt.h 2004-02-17 19:59:27.000000000 -0800 +++ linux-2.6.4-rc3/crypto/tcrypt.h 2004-03-09 16:36:24.000000000 -0800 @@ -1488,6 +1488,147 @@ }, }; +/* + * ARC4 test vectors from OpenSSL + */ +#define ARC4_ENC_TEST_VECTORS 7 +#define ARC4_DEC_TEST_VECTORS 7 + +struct cipher_testvec arc4_enc_tv_template[] = +{ + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .ilen = 8, + .result = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }, + .rlen = 8, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79 }, + .rlen = 8, + }, { + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a }, + .rlen = 8, + }, { + .key = { 0xef, 0x01, 0x23, 0x45}, + .klen = 4, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .ilen = 20, + .result = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61, 0x5a, 0x11, 0x62, 0xe1, 0xc7, 0xba, + 0x36, 0xb6, 0x78, 0x58 }, + .rlen = 20, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78 }, + .ilen = 28, + .result = { 0x66, 0xa0, 0x94, 0x9f, 0x8a, 0xf7, 0xd6, 0x89, + 0x1f, 0x7f, 0x83, 0x2b, 0xa8, 0x33, 0xc0, 0x0c, + 0x89, 0x2e, 0xbe, 0x30, 0x14, 0x3c, 0xe2, 0x87, + 0x40, 0x01, 0x1e, 0xcf }, + .rlen = 28, + }, { + .key = { 0xef, 0x01, 0x23, 0x45 }, + .klen = 4, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }, + .ilen = 10, + .result = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61 }, + .rlen = 10, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + .ilen = 8, + .result = { 0x69, 0x72, 0x36, 0x59, 0x1B, 0x52, 0x42, 0xB1 }, + .rlen = 8, + }, +}; + +struct cipher_testvec arc4_dec_tv_template[] = +{ + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }, + .ilen = 8, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .rlen = 8, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79 }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .input = { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0xef, 0x01, 0x23, 0x45}, + .klen = 4, + .input = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61, 0x5a, 0x11, 0x62, 0xe1, 0xc7, 0xba, + 0x36, 0xb6, 0x78, 0x58 }, + .ilen = 20, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .rlen = 20, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x66, 0xa0, 0x94, 0x9f, 0x8a, 0xf7, 0xd6, 0x89, + 0x1f, 0x7f, 0x83, 0x2b, 0xa8, 0x33, 0xc0, 0x0c, + 0x89, 0x2e, 0xbe, 0x30, 0x14, 0x3c, 0xe2, 0x87, + 0x40, 0x01, 0x1e, 0xcf }, + .ilen = 28, + .result = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78 }, + .rlen = 28, + }, { + .key = { 0xef, 0x01, 0x23, 0x45 }, + .klen = 4, + .input = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61 }, + .ilen = 10, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }, + .rlen = 10, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0x69, 0x72, 0x36, 0x59, 0x1B, 0x52, 0x42, 0xB1 }, + .ilen = 8, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + .rlen = 8, + }, +}; + + /* * Compression stuff. */ diff -urN linux-2.6.4-rc2/drivers/acpi/Kconfig linux-2.6.4-rc3/drivers/acpi/Kconfig --- linux-2.6.4-rc2/drivers/acpi/Kconfig 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/Kconfig 2004-03-09 16:36:24.000000000 -0800 @@ -251,18 +251,6 @@ This driver will enable your system to shut down using ACPI, and dump your ACPI DSDT table using /proc/acpi/dsdt. -config ACPI_RELAXED_AML - bool "Relaxed AML" - depends on ACPI_INTERPRETER - depends on !IA64_SGI_SN - default n - help - If you say `Y' here, the ACPI interpreter will relax its checking - for valid AML and will ignore some AML mistakes, such as off-by-one - errors in region sizes. Some laptops may require this option. In - particular, many Toshiba laptops require this for correct operation - of the AC module. - config X86_PM_TIMER bool "Power Management Timer Support" depends on X86 && ACPI diff -urN linux-2.6.4-rc2/drivers/acpi/executer/exfldio.c linux-2.6.4-rc3/drivers/acpi/executer/exfldio.c --- linux-2.6.4-rc2/drivers/acpi/executer/exfldio.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/executer/exfldio.c 2004-03-09 16:36:24.000000000 -0800 @@ -154,8 +154,7 @@ field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); - #ifdef CONFIG_ACPI_RELAXED_AML - { + if (!acpi_strict) { /* * Allow access to the field if it is within the region size * rounded up to a multiple of the access byte width. This @@ -186,9 +185,9 @@ return_ACPI_STATUS (AE_OK); } } - #else + else { return_ACPI_STATUS (AE_AML_REGION_LIMIT); - #endif + } } return_ACPI_STATUS (AE_OK); diff -urN linux-2.6.4-rc2/drivers/acpi/hardware/hwgpe.c linux-2.6.4-rc3/drivers/acpi/hardware/hwgpe.c --- linux-2.6.4-rc2/drivers/acpi/hardware/hwgpe.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/hardware/hwgpe.c 2004-03-09 16:36:24.000000000 -0800 @@ -528,6 +528,14 @@ /* Examine each GPE register within the block */ for (i = 0; i < gpe_block->register_count; i++) { + /* Clear the entire status register */ + + status = acpi_hw_low_level_write (8, 0xFF, + &gpe_block->register_info[i].status_address); + if (ACPI_FAILURE (status)) { + return (status); + } + /* * We previously stored the enabled status of all GPEs. * Blast them back in. diff -urN linux-2.6.4-rc2/drivers/acpi/hardware/hwregs.c linux-2.6.4-rc3/drivers/acpi/hardware/hwregs.c --- linux-2.6.4-rc2/drivers/acpi/hardware/hwregs.c 2004-02-17 19:59:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/hardware/hwregs.c 2004-03-09 16:36:24.000000000 -0800 @@ -152,11 +152,11 @@ /* * Evaluate the namespace object containing the values for this state */ - status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_db_sleep_states[sleep_state], + status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], NULL, &obj_desc); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", - acpi_format_exception (status), acpi_gbl_db_sleep_states[sleep_state])); + acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); return_ACPI_STATUS (status); } @@ -201,7 +201,7 @@ if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_db_sleep_states[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); + acpi_gbl_sleep_state_names[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); } acpi_ut_remove_reference (obj_desc); diff -urN linux-2.6.4-rc2/drivers/acpi/hardware/hwsleep.c linux-2.6.4-rc3/drivers/acpi/hardware/hwsleep.c --- linux-2.6.4-rc2/drivers/acpi/hardware/hwsleep.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/hardware/hwsleep.c 2004-03-09 16:36:24.000000000 -0800 @@ -48,6 +48,19 @@ ACPI_MODULE_NAME ("hwsleep") +#define METHOD_NAME__BFS "\\_BFS" +#define METHOD_NAME__GTS "\\_GTS" +#define METHOD_NAME__PTS "\\_PTS" +#define METHOD_NAME__SST "\\_SI._SST" +#define METHOD_NAME__WAK "\\_WAK" + +#define ACPI_SST_INDICATOR_OFF 0 +#define ACPI_SST_WORKING 1 +#define ACPI_SST_WAKING 2 +#define ACPI_SST_SLEEPING 3 +#define ACPI_SST_SLEEP_CONTEXT 4 + + /****************************************************************************** * * FUNCTION: acpi_set_firmware_waking_vector @@ -171,19 +184,41 @@ /* Run the _PTS and _GTS methods */ - status = acpi_evaluate_object (NULL, "\\_PTS", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__PTS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { return_ACPI_STATUS (status); } - status = acpi_evaluate_object (NULL, "\\_GTS", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__GTS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { return_ACPI_STATUS (status); } + /* Setup the argument to _SST */ + + switch (sleep_state) { + case ACPI_STATE_S0: + arg.integer.value = ACPI_SST_WORKING; + break; + + case ACPI_STATE_S1: + case ACPI_STATE_S2: + case ACPI_STATE_S3: + arg.integer.value = ACPI_SST_SLEEPING; + break; + + case ACPI_STATE_S4: + arg.integer.value = ACPI_SST_SLEEP_CONTEXT; + break; + + default: + arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */ + break; + } + /* Set the system indicators to show the desired sleep state. */ - status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); } @@ -477,19 +512,19 @@ /* Ignore any errors from these methods */ - arg.integer.value = 0; - status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL); + arg.integer.value = ACPI_SST_WAKING; + status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); } arg.integer.value = sleep_state; - status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); } - status = acpi_evaluate_object (NULL, "\\_WAK", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status))); } @@ -501,8 +536,25 @@ return_ACPI_STATUS (status); } + /* Enable power button */ + + acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + 1, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + 1, ACPI_MTX_DO_NOT_LOCK); + /* Enable BM arbitration */ status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + arg.integer.value = ACPI_SST_WORKING; + status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); + if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + } + return_ACPI_STATUS (status); } diff -urN linux-2.6.4-rc2/drivers/acpi/namespace/nseval.c linux-2.6.4-rc3/drivers/acpi/namespace/nseval.c --- linux-2.6.4-rc2/drivers/acpi/namespace/nseval.c 2004-02-17 19:57:30.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/namespace/nseval.c 2004-03-09 16:36:24.000000000 -0800 @@ -110,7 +110,7 @@ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } prefix_node = acpi_ns_map_handle_to_node (handle); @@ -197,7 +197,7 @@ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } /* Lookup the name in the namespace */ diff -urN linux-2.6.4-rc2/drivers/acpi/namespace/nsutils.c linux-2.6.4-rc3/drivers/acpi/namespace/nsutils.c --- linux-2.6.4-rc2/drivers/acpi/namespace/nsutils.c 2004-02-17 19:57:57.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/namespace/nsutils.c 2004-03-09 16:36:24.000000000 -0800 @@ -918,7 +918,7 @@ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } /* Setup lookup scope (search starting point) */ @@ -936,10 +936,10 @@ internal_path, acpi_format_exception (status))); } - /* Cleanup */ - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); +cleanup: + /* Cleanup */ if (internal_path) { ACPI_MEM_FREE (internal_path); } diff -urN linux-2.6.4-rc2/drivers/acpi/namespace/nsxfname.c linux-2.6.4-rc3/drivers/acpi/namespace/nsxfname.c --- linux-2.6.4-rc2/drivers/acpi/namespace/nsxfname.c 2004-02-17 19:57:20.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/namespace/nsxfname.c 2004-03-09 16:36:24.000000000 -0800 @@ -326,6 +326,13 @@ info.valid |= ACPI_VALID_ADR; } + /* Execute the Device._sx_d methods */ + + status = acpi_ut_execute_sxds (node, info.highest_dstates); + if (ACPI_SUCCESS (status)) { + info.valid |= ACPI_VALID_STA; + } + status = AE_OK; } diff -urN linux-2.6.4-rc2/drivers/acpi/pci_link.c linux-2.6.4-rc3/drivers/acpi/pci_link.c --- linux-2.6.4-rc2/drivers/acpi/pci_link.c 2004-02-17 19:57:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/pci_link.c 2004-03-09 16:36:24.000000000 -0800 @@ -768,7 +768,6 @@ static int __init acpi_irq_nobalance_set(char *str) { -printk("ACPI STATIC SET\n"); acpi_irq_balance = 0; return(1); } @@ -776,7 +775,6 @@ int __init acpi_irq_balance_set(char *str) { -printk("ACPI BALANCE SET\n"); acpi_irq_balance = 1; return(1); } diff -urN linux-2.6.4-rc2/drivers/acpi/resources/rsxface.c linux-2.6.4-rc3/drivers/acpi/resources/rsxface.c --- linux-2.6.4-rc2/drivers/acpi/resources/rsxface.c 2004-02-17 19:58:43.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/resources/rsxface.c 2004-03-09 16:36:24.000000000 -0800 @@ -239,6 +239,7 @@ acpi_status status; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *resource; + struct acpi_resource *buffer_end; ACPI_FUNCTION_TRACE ("acpi_walk_resources"); @@ -255,7 +256,13 @@ return_ACPI_STATUS (status); } - resource = (struct acpi_resource *) buffer.pointer; + /* Setup pointers */ + + resource = (struct acpi_resource *) buffer.pointer; + buffer_end = (struct acpi_resource *) ((u8 *) buffer.pointer + buffer.length); + + /* Walk the resource list */ + for (;;) { if (!resource || resource->id == ACPI_RSTYPE_END_TAG) { break; @@ -268,6 +275,7 @@ case AE_CTRL_DEPTH: /* Just keep going */ + status = AE_OK; break; @@ -285,7 +293,15 @@ goto cleanup; } + /* Get the next resource descriptor */ + resource = ACPI_NEXT_RESOURCE (resource); + + /* Check for end-of-buffer */ + + if (resource >= buffer_end) { + goto cleanup; + } } cleanup: diff -urN linux-2.6.4-rc2/drivers/acpi/tables.c linux-2.6.4-rc3/drivers/acpi/tables.c --- linux-2.6.4-rc2/drivers/acpi/tables.c 2004-02-17 19:57:30.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/tables.c 2004-03-09 16:36:24.000000000 -0800 @@ -58,6 +58,7 @@ [ACPI_SSDT] = "SSDT", [ACPI_SPMI] = "SPMI", [ACPI_HPET] = "HPET", + [ACPI_MCFG] = "MCFG", }; static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; @@ -550,6 +551,14 @@ return 0; } +/* + * acpi_table_init() + * + * find RSDP, find and checksum SDT/XSDT. + * checksum all tables, print SDT/XSDT + * + * result: sdt_entry[] is initialized + */ int __init acpi_table_init (void) diff -urN linux-2.6.4-rc2/drivers/acpi/utilities/uteval.c linux-2.6.4-rc3/drivers/acpi/utilities/uteval.c --- linux-2.6.4-rc2/drivers/acpi/utilities/uteval.c 2004-02-17 19:57:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/utilities/uteval.c 2004-03-09 16:36:24.000000000 -0800 @@ -562,3 +562,63 @@ acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); } + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_Sxds + * + * PARAMETERS: device_node - Node for the device + * *Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + u32 i; + + + ACPI_FUNCTION_TRACE ("ut_execute_Sxds"); + + + for (i = 0; i < 4; i++) { + highest[i] = 0xFF; + status = acpi_ut_evaluate_object (device_node, + (char *) acpi_gbl_highest_dstate_names[i], + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE (status)) { + if (status != AE_NOT_FOUND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s on Device %4.4s, %s\n", + (char *) acpi_gbl_highest_dstate_names[i], + acpi_ut_get_node_name (device_node), + acpi_format_exception (status))); + + return_ACPI_STATUS (status); + } + } + else { + /* Extract the Dstate value */ + + highest[i] = (u8) obj_desc->integer.value; + + /* Delete the return object */ + + acpi_ut_remove_reference (obj_desc); + } + } + + return_ACPI_STATUS (AE_OK); +} diff -urN linux-2.6.4-rc2/drivers/acpi/utilities/utglobal.c linux-2.6.4-rc3/drivers/acpi/utilities/utglobal.c --- linux-2.6.4-rc2/drivers/acpi/utilities/utglobal.c 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/acpi/utilities/utglobal.c 2004-03-09 16:36:24.000000000 -0800 @@ -171,7 +171,7 @@ const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; -const char *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT] = { +const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S0_", "\\_S1_", "\\_S2_", @@ -179,6 +179,11 @@ "\\_S4_", "\\_S5_"}; +const char *acpi_gbl_highest_dstate_names[4] = { + "_S1D", + "_S2D", + "_S3D", + "_S4D"}; /****************************************************************************** * diff -urN linux-2.6.4-rc2/drivers/block/Kconfig linux-2.6.4-rc3/drivers/block/Kconfig --- linux-2.6.4-rc2/drivers/block/Kconfig 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/block/Kconfig 2004-03-09 16:36:24.000000000 -0800 @@ -321,6 +321,7 @@ config BLK_DEV_INITRD bool "Initial RAM disk (initrd) support" + depends on BLK_DEV_RAM && BLK_DEV_RAM!=m help The initial RAM disk is a RAM disk that is loaded by the boot loader (loadlin or lilo) and that is mounted as root before the normal boot diff -urN linux-2.6.4-rc2/drivers/block/floppy.c linux-2.6.4-rc3/drivers/block/floppy.c --- linux-2.6.4-rc2/drivers/block/floppy.c 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/block/floppy.c 2004-03-09 16:36:25.000000000 -0800 @@ -4242,6 +4242,15 @@ disks[i] = alloc_disk(1); if (!disks[i]) goto Enomem; + + disks[i]->major = FLOPPY_MAJOR; + disks[i]->first_minor = TOMINOR(i); + disks[i]->fops = &floppy_fops; + sprintf(disks[i]->disk_name, "fd%d", i); + + init_timer(&motor_off_timer[i]); + motor_off_timer[i].data = i; + motor_off_timer[i].function = motor_off_callback; } devfs_mk_dir ("floppy"); @@ -4255,13 +4264,6 @@ goto fail_queue; } - for (i=0; imajor = FLOPPY_MAJOR; - disks[i]->first_minor = TOMINOR(i); - disks[i]->fops = &floppy_fops; - sprintf(disks[i]->disk_name, "fd%d", i); - } - blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE, floppy_find, NULL, NULL); @@ -4366,9 +4368,6 @@ } for (drive = 0; drive < N_DRIVE; drive++) { - init_timer(&motor_off_timer[drive]); - motor_off_timer[drive].data = drive; - motor_off_timer[drive].function = motor_off_callback; if (!(allowed_drive_mask & (1 << drive))) continue; if (fdc_state[FDC(drive)].version == FDC_NONE) diff -urN linux-2.6.4-rc2/drivers/block/ll_rw_blk.c linux-2.6.4-rc3/drivers/block/ll_rw_blk.c --- linux-2.6.4-rc2/drivers/block/ll_rw_blk.c 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/block/ll_rw_blk.c 2004-03-09 16:36:25.000000000 -0800 @@ -1188,13 +1188,23 @@ * Description: * blk_start_queue() will clear the stop flag on the queue, and call * the request_fn for the queue if it was in a stopped state when - * entered. Also see blk_stop_queue(). Must not be called from driver - * request function due to recursion issues. Queue lock must be held. + * entered. Also see blk_stop_queue(). Queue lock must be held. **/ void blk_start_queue(request_queue_t *q) { clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); - schedule_work(&q->unplug_work); + + /* + * one level of recursion is ok and is much faster than kicking + * the unplug handling + */ + if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { + q->request_fn(q); + clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags); + } else { + blk_plug_device(q); + schedule_work(&q->unplug_work); + } } EXPORT_SYMBOL(blk_start_queue); @@ -1737,9 +1747,9 @@ /* * If command is tagged, release the tag */ - if(reinsert) { + if (reinsert) blk_requeue_request(q, rq); - } else { + else { int where = ELEVATOR_INSERT_BACK; if (at_head) @@ -1751,7 +1761,10 @@ drive_stat_acct(rq, rq->nr_sectors, 1); __elv_add_request(q, rq, where, 0); } - q->request_fn(q); + if (blk_queue_plugged(q)) + __generic_unplug_device(q); + else + q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } diff -urN linux-2.6.4-rc2/drivers/block/rd.c linux-2.6.4-rc3/drivers/block/rd.c --- linux-2.6.4-rc2/drivers/block/rd.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/block/rd.c 2004-03-09 16:36:25.000000000 -0800 @@ -316,6 +316,7 @@ } del_gendisk(rd_disks[i]); put_disk(rd_disks[i]); + blk_cleanup_queue(rd_queue[i]); } devfs_remove("rd"); unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); @@ -379,8 +380,10 @@ out_queue: unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); out: - while (i--) + while (i--) { put_disk(rd_disks[i]); + blk_cleanup_queue(rd_queue[i]); + } return err; } diff -urN linux-2.6.4-rc2/drivers/block/viodasd.c linux-2.6.4-rc3/drivers/block/viodasd.c --- linux-2.6.4-rc2/drivers/block/viodasd.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/block/viodasd.c 2004-03-09 16:36:25.000000000 -0800 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -77,8 +76,6 @@ #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) -extern struct device *iSeries_vio_dev; - struct open_data { u64 disk_size; u16 max_disk; diff -urN linux-2.6.4-rc2/drivers/bluetooth/hci_usb.c linux-2.6.4-rc3/drivers/bluetooth/hci_usb.c --- linux-2.6.4-rc2/drivers/bluetooth/hci_usb.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/bluetooth/hci_usb.c 2004-03-09 16:36:25.000000000 -0800 @@ -31,7 +31,7 @@ * * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $ */ -#define VERSION "2.4" +#define VERSION "2.5" #include #include @@ -70,12 +70,6 @@ static struct usb_driver hci_usb_driver; static struct usb_device_id bluetooth_ids[] = { - /* Broadcom BCM2033 without firmware */ - { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, - - /* Digianswer device */ - { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, - /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, @@ -93,6 +87,19 @@ MODULE_DEVICE_TABLE (usb, bluetooth_ids); +static struct usb_device_id blacklist_ids[] = { + /* Broadcom BCM2033 without firmware */ + { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, + + /* Broadcom BCM2035 */ + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET }, + + /* Digianswer device */ + { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, + + { } /* Terminating entry */ +}; + struct _urb *_urb_alloc(int isoc, int gfp) { struct _urb *_urb = kmalloc(sizeof(struct _urb) + @@ -644,7 +651,7 @@ #endif } BT_DBG("new packet len %d", len); - + skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) { BT_ERR("%s no memory for the packet", husb->hdev->name); @@ -790,6 +797,13 @@ BT_DBG("udev %p ifnum %d", udev, ifnum); + if (!id->driver_info) { + const struct usb_device_id *match; + match = usb_match_id(intf, blacklist_ids); + if (match) + id = match; + } + iface = udev->actconfig->interface[0]; if (id->driver_info & HCI_IGNORE) @@ -928,6 +942,9 @@ hdev->owner = THIS_MODULE; + if (id->driver_info & HCI_RESET) + set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); @@ -994,6 +1011,6 @@ module_init(hci_usb_init); module_exit(hci_usb_cleanup); -MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_AUTHOR("Maxim Krasnyansky , Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); MODULE_LICENSE("GPL"); diff -urN linux-2.6.4-rc2/drivers/bluetooth/hci_usb.h linux-2.6.4-rc3/drivers/bluetooth/hci_usb.h --- linux-2.6.4-rc2/drivers/bluetooth/hci_usb.h 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/bluetooth/hci_usb.h 2004-03-09 16:36:25.000000000 -0800 @@ -38,7 +38,8 @@ #define HCI_DIGI_REQ 0x40 #define HCI_IGNORE 0x01 -#define HCI_DIGIANSWER 0x02 +#define HCI_RESET 0x02 +#define HCI_DIGIANSWER 0x04 #define HCI_MAX_IFACE_NUM 3 diff -urN linux-2.6.4-rc2/drivers/cdrom/Makefile linux-2.6.4-rc3/drivers/cdrom/Makefile --- linux-2.6.4-rc2/drivers/cdrom/Makefile 2004-02-17 19:57:48.000000000 -0800 +++ linux-2.6.4-rc3/drivers/cdrom/Makefile 2004-03-09 16:36:25.000000000 -0800 @@ -20,3 +20,4 @@ obj-$(CONFIG_SBPCD) += sbpcd.o cdrom.o obj-$(CONFIG_SJCD) += sjcd.o obj-$(CONFIG_CDU535) += sonycd535.o +obj-$(CONFIG_VIOCD) += viocd.o cdrom.o diff -urN linux-2.6.4-rc2/drivers/cdrom/viocd.c linux-2.6.4-rc3/drivers/cdrom/viocd.c --- linux-2.6.4-rc2/drivers/cdrom/viocd.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.4-rc3/drivers/cdrom/viocd.c 2004-03-09 16:36:25.000000000 -0800 @@ -0,0 +1,656 @@ +/* -*- linux-c -*- + * drivers/cdrom/viocd.c + * + * iSeries Virtual CD Rom + * + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * Stephen Rothwell + * + * (C) Copyright 2000-2004 IBM Corporation + * + * 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) anyu later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This routine provides access to CD ROM drives owned and managed by an + * OS/400 partition running on the same box as this Linux partition. + * + * All operations are performed by sending messages back and forth to + * the OS/400 partition. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#define VIOCD_DEVICE "iseries/vcd" +#define VIOCD_DEVICE_DEVFS "iseries/vcd" + +#define VIOCD_VERS "1.06" + +#define VIOCD_KERN_WARNING KERN_WARNING "viocd: " +#define VIOCD_KERN_INFO KERN_INFO "viocd: " + +struct viocdlpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + u32 token; + u64 offset; /* On open, max number of disks */ + u64 len; /* On open, size of the disk */ + u32 block_size; /* Only set on open */ + u32 media_size; /* Only set on open */ +}; + +enum viocdsubtype { + viocdopen = 0x0001, + viocdclose = 0x0002, + viocdread = 0x0003, + viocdwrite = 0x0004, + viocdlockdoor = 0x0005, + viocdgetinfo = 0x0006, + viocdcheck = 0x0007 +}; + +/* + * Should probably make this a module parameter....sigh + */ +#define VIOCD_MAX_CD 8 + +static const struct vio_error_entry viocd_err_table[] = { + {0x0201, EINVAL, "Invalid Range"}, + {0x0202, EINVAL, "Invalid Token"}, + {0x0203, EIO, "DMA Error"}, + {0x0204, EIO, "Use Error"}, + {0x0205, EIO, "Release Error"}, + {0x0206, EINVAL, "Invalid CD"}, + {0x020C, EROFS, "Read Only Device"}, + {0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"}, + {0x020E, EIO, "Optical System Error (Varied Off?)"}, + {0x02FF, EIO, "Internal Error"}, + {0x3010, EIO, "Changed Volume"}, + {0xC100, EIO, "Optical System Error"}, + {0x0000, 0, NULL}, +}; + +/* + * This is the structure we use to exchange info between driver and interrupt + * handler + */ +struct viocd_waitevent { + struct completion com; + int rc; + u16 sub_result; + int changed; +}; + +/* this is a lookup table for the true capabilities of a device */ +struct capability_entry { + char *type; + int capability; +}; + +static struct capability_entry capability_table[] __initdata = { + { "6330", CDC_LOCK | CDC_DVD_RAM }, + { "6321", CDC_LOCK }, + { "632B", 0 }, + { NULL , CDC_LOCK }, +}; + +/* These are our internal structures for keeping track of devices */ +static int viocd_numdev; + +struct cdrom_info { + char rsrcname[10]; + char type[4]; + char model[3]; +}; +static struct cdrom_info viocd_unitinfo[VIOCD_MAX_CD]; + +struct disk_info { + struct gendisk *viocd_disk; + struct cdrom_device_info viocd_info; +}; +static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; + +#define DEVICE_NR(di) ((di) - &viocd_diskinfo[0]) +#define VIOCDI viocd_diskinfo[deviceno].viocd_info + +static request_queue_t *viocd_queue; +static spinlock_t viocd_reqlock; + +#define MAX_CD_REQ 1 + +static int viocd_blk_open(struct inode *inode, struct file *file) +{ + struct disk_info *di = inode->i_bdev->bd_disk->private_data; + return cdrom_open(&di->viocd_info, inode, file); +} + +static int viocd_blk_release(struct inode *inode, struct file *file) +{ + struct disk_info *di = inode->i_bdev->bd_disk->private_data; + return cdrom_release(&di->viocd_info, file); +} + +static int viocd_blk_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + struct disk_info *di = inode->i_bdev->bd_disk->private_data; + return cdrom_ioctl(&di->viocd_info, inode, cmd, arg); +} + +static int viocd_blk_media_changed(struct gendisk *disk) +{ + struct disk_info *di = disk->private_data; + return cdrom_media_changed(&di->viocd_info); +} + +struct block_device_operations viocd_fops = { + .owner = THIS_MODULE, + .open = viocd_blk_open, + .release = viocd_blk_release, + .ioctl = viocd_blk_ioctl, + .media_changed = viocd_blk_media_changed, +}; + +/* Get info on CD devices from OS/400 */ +static void __init get_viocd_info(void) +{ + dma_addr_t dmaaddr; + HvLpEvent_Rc hvrc; + int i; + struct viocd_waitevent we; + + dmaaddr = dma_map_single(iSeries_vio_dev, viocd_unitinfo, + sizeof(viocd_unitinfo), DMA_FROM_DEVICE); + if (dmaaddr == (dma_addr_t)-1) { + printk(VIOCD_KERN_WARNING "error allocating tce\n"); + return; + } + + init_completion(&we.com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdgetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, dmaaddr, 0, + sizeof(viocd_unitinfo), 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", + (int)hvrc); + return; + } + + wait_for_completion(&we.com); + + dma_unmap_single(iSeries_vio_dev, dmaaddr, sizeof(viocd_unitinfo), + DMA_FROM_DEVICE); + + if (we.rc) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, we.sub_result); + printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", + we.rc, we.sub_result, err->msg); + return; + } + + for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) + viocd_numdev++; +} + +static int viocd_open(struct cdrom_device_info *cdi, int purpose) +{ + struct disk_info *diskinfo = cdi->handle; + int device_no = DEVICE_NR(diskinfo); + HvLpEvent_Rc hvrc; + struct viocd_waitevent we; + + init_completion(&we.com); + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), + 0, 0, 0); + if (hvrc != 0) { + printk(VIOCD_KERN_WARNING + "bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); + return -EIO; + } + + wait_for_completion(&we.com); + + if (we.rc) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, we.sub_result); + printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on open: %s\n", + we.rc, we.sub_result, err->msg); + return -err->errno; + } + + return 0; +} + +static void viocd_release(struct cdrom_device_info *cdi) +{ + int device_no = DEVICE_NR((struct disk_info *)cdi->handle); + HvLpEvent_Rc hvrc; + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), 0, + VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0); + if (hvrc != 0) + printk(VIOCD_KERN_WARNING + "bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); +} + +/* Send a read or write request to OS/400 */ +static int send_request(struct request *req) +{ + HvLpEvent_Rc hvrc; + struct disk_info *diskinfo = req->rq_disk->private_data; + u64 len; + dma_addr_t dmaaddr; + struct scatterlist sg; + + BUG_ON(req->nr_phys_segments > 1); + BUG_ON(rq_data_dir(req) != READ); + + if (blk_rq_map_sg(req->q, req, &sg) == 0) { + printk(VIOCD_KERN_WARNING + "error setting up scatter/gather list\n"); + return -1; + } + + if (dma_map_sg(iSeries_vio_dev, &sg, 1, DMA_FROM_DEVICE) == 0) { + printk(VIOCD_KERN_WARNING "error allocating sg tce\n"); + return -1; + } + dmaaddr = sg_dma_address(&sg); + len = sg_dma_len(&sg); + if (dmaaddr == (dma_addr_t)-1) { + printk(VIOCD_KERN_WARNING "error allocating tce\n"); + return -1; + } + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdread, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)req, VIOVERSION << 16, + ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, + (u64)req->sector * 512, len, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc); + return -1; + } + + return 0; +} + + +static int rwreq; + +static void do_viocd_request(request_queue_t *q) +{ + struct request *req; + + while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { + /* check for any kind of error */ + if (send_request(req) < 0) { + printk(VIOCD_KERN_WARNING + "unable to send message to OS/400!"); + end_request(req, 0); + } else + rwreq++; + } +} + +static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr) +{ + struct viocd_waitevent we; + HvLpEvent_Rc hvrc; + int device_no = DEVICE_NR((struct disk_info *)cdi->handle); + + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdcheck, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), + 0, 0, 0); + if (hvrc != 0) { + printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); + return -EIO; + } + + wait_for_completion(&we.com); + + /* Check the return code. If bad, assume no change */ + if (we.rc) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, we.sub_result); + printk(VIOCD_KERN_WARNING + "bad rc %d:0x%04X on check_change: %s; Assuming no change\n", + we.rc, we.sub_result, err->msg); + return 0; + } + + return we.changed; +} + +static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) +{ + HvLpEvent_Rc hvrc; + u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle); + /* NOTE: flags is 1 or 0 so it won't overwrite the device_no */ + u64 flags = !!locking; + struct viocd_waitevent we; + + init_completion(&we.com); + + /* Send the lockdoor event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdlockdoor, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, + (device_no << 48) | (flags << 32), 0, 0, 0); + if (hvrc != 0) { + printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); + return -EIO; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) + return -EIO; + return 0; +} + +/* This routine handles incoming CD LP events */ +static void vio_handle_cd_event(struct HvLpEvent *event) +{ + struct viocdlpevent *bevent; + struct viocd_waitevent *pwe; + struct disk_info *di; + unsigned long flags; + struct request *req; + + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (event->xFlags.xFunction == HvLpEvent_Function_Int) { + printk(VIOCD_KERN_WARNING + "Yikes! got an int in viocd event handler!\n"); + if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } + + bevent = (struct viocdlpevent *)event; + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viocdopen: + if (event->xRc == 0) { + di = &viocd_diskinfo[bevent->disk]; + blk_queue_hardsect_size(viocd_queue, + bevent->block_size); + set_capacity(di->viocd_disk, + bevent->media_size * + bevent->block_size / 512); + } + /* FALLTHROUGH !! */ + case viocdgetinfo: + case viocdlockdoor: + pwe = (struct viocd_waitevent *)event->xCorrelationToken; +return_complete: + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + + case viocdcheck: + pwe = (struct viocd_waitevent *)event->xCorrelationToken; + pwe->changed = bevent->flags; + goto return_complete; + + case viocdclose: + break; + + case viocdread: + /* + * Since this is running in interrupt mode, we need to + * make sure we're not stepping on any global I/O operations + */ + spin_lock_irqsave(&viocd_reqlock, flags); + dma_unmap_single(iSeries_vio_dev, bevent->token, bevent->len, + DMA_FROM_DEVICE); + req = (struct request *)bevent->event.xCorrelationToken; + rwreq--; + + if (event->xRc != HvLpEvent_Rc_Good) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, + bevent->sub_result); + printk(VIOCD_KERN_WARNING "request %p failed " + "with rc %d:0x%04X: %s\n", + req, event->xRc, + bevent->sub_result, err->msg); + end_request(req, 0); + } else + end_request(req, 1); + + /* restart handling of incoming requests */ + spin_unlock_irqrestore(&viocd_reqlock, flags); + blk_run_queue(viocd_queue); + break; + + default: + printk(VIOCD_KERN_WARNING + "message with invalid subtype %0x04X!\n", + event->xSubtype & VIOMINOR_SUBTYPE_MASK); + if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static struct cdrom_device_ops viocd_dops = { + .open = viocd_open, + .release = viocd_release, + .media_changed = viocd_media_changed, + .lock_door = viocd_lock_door, + .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM +}; + +static int __init find_capability(const char *type) +{ + struct capability_entry *entry; + + for(entry = capability_table; entry->type; ++entry) + if(!strncmp(entry->type, type, 4)) + break; + return entry->capability; +} + +static int __init viocd_init(void) +{ + struct gendisk *gendisk; + int deviceno; + int ret = 0; + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + /* If we don't have a host, bail out */ + if (viopath_hostLp == HvLpIndexInvalid) + return -ENODEV; + } + + printk(VIOCD_KERN_INFO "vers " VIOCD_VERS ", hosting partition %d\n", + viopath_hostLp); + + if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) { + printk(VIOCD_KERN_WARNING + "Unable to get major %d for %s\n", + VIOCD_MAJOR, VIOCD_DEVICE); + return -EIO; + } + + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, + MAX_CD_REQ + 2); + if (ret) { + printk(VIOCD_KERN_WARNING + "error opening path to host partition %d\n", + viopath_hostLp); + goto out_unregister; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); + + get_viocd_info(); + if (viocd_numdev == 0) + goto out_undo_vio; + + ret = -ENOMEM; + spin_lock_init(&viocd_reqlock); + viocd_queue = blk_init_queue(do_viocd_request, &viocd_reqlock); + if (viocd_queue == NULL) + goto out_unregister; + blk_queue_max_hw_segments(viocd_queue, 1); + blk_queue_max_phys_segments(viocd_queue, 1); + blk_queue_max_sectors(viocd_queue, 4096 / 512); + + /* initialize units */ + for (deviceno = 0; deviceno < viocd_numdev; deviceno++) { + struct disk_info *d = &viocd_diskinfo[deviceno]; + struct cdrom_device_info *c = &d->viocd_info; + struct cdrom_info *ci = &viocd_unitinfo[deviceno]; + + c->ops = &viocd_dops; + c->speed = 4; + c->capacity = 1; + c->handle = d; + c->mask = ~find_capability(ci->type); + sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); + + if (register_cdrom(c) != 0) { + printk(VIOCD_KERN_WARNING + "Cannot register viocd CD-ROM %s!\n", + c->name); + continue; + } + printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " + "type %4.4s, model %3.3s\n", + c->name, ci->rsrcname, ci->type, ci->model); + gendisk = alloc_disk(1); + if (gendisk == NULL) { + printk(VIOCD_KERN_WARNING + "Cannot create gendisk for %s!\n", + c->name); + unregister_cdrom(&VIOCDI); + continue; + } + gendisk->major = VIOCD_MAJOR; + gendisk->first_minor = deviceno; + strncpy(gendisk->disk_name, c->name, + sizeof(gendisk->disk_name)); + snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name), + VIOCD_DEVICE_DEVFS "%d", deviceno); + gendisk->queue = viocd_queue; + gendisk->fops = &viocd_fops; + gendisk->flags = GENHD_FL_CD; + set_capacity(gendisk, 0); + gendisk->private_data = d; + d->viocd_disk = gendisk; + add_disk(gendisk); + } + + return 0; + +out_undo_vio: + vio_clearHandler(viomajorsubtype_cdio); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); +out_unregister: + unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); + return ret; +} + +static void __exit viocd_exit(void) +{ + int deviceno; + + for (deviceno = 0; deviceno < viocd_numdev; deviceno++) { + struct disk_info *d = &viocd_diskinfo[deviceno]; + if (unregister_cdrom(&d->viocd_info) != 0) + printk(VIOCD_KERN_WARNING + "Cannot unregister viocd CD-ROM %s!\n", + d->viocd_info.name); + del_gendisk(d->viocd_disk); + put_disk(d->viocd_disk); + } + blk_cleanup_queue(viocd_queue); + + viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); + vio_clearHandler(viomajorsubtype_cdio); + unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); +} + +module_init(viocd_init); +module_exit(viocd_exit); +MODULE_LICENSE("GPL"); diff -urN linux-2.6.4-rc2/drivers/char/drm/r128_state.c linux-2.6.4-rc3/drivers/char/drm/r128_state.c --- linux-2.6.4-rc2/drivers/char/drm/r128_state.c 2004-02-17 19:57:17.000000000 -0800 +++ linux-2.6.4-rc3/drivers/char/drm/r128_state.c 2004-03-09 16:36:25.000000000 -0800 @@ -915,6 +915,9 @@ DRM_DEBUG( "\n" ); count = depth->n; + if (count > 4096 || count <= 0) + return -EMSGSIZE; + if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { return DRM_ERR(EFAULT); } @@ -1008,6 +1011,8 @@ DRM_DEBUG( "\n" ); count = depth->n; + if (count > 4096 || count <= 0) + return -EMSGSIZE; xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); @@ -1125,6 +1130,9 @@ DRM_DEBUG( "\n" ); count = depth->n; + if (count > 4096 || count <= 0) + return -EMSGSIZE; + if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { return DRM_ERR(EFAULT); } @@ -1167,6 +1175,9 @@ DRM_DEBUG( "%s\n", __FUNCTION__ ); count = depth->n; + if (count > 4096 || count <= 0) + return -EMSGSIZE; + if ( count > dev_priv->depth_pitch ) { count = dev_priv->depth_pitch; } diff -urN linux-2.6.4-rc2/drivers/char/hw_random.c linux-2.6.4-rc3/drivers/char/hw_random.c --- linux-2.6.4-rc2/drivers/char/hw_random.c 2004-02-17 19:57:26.000000000 -0800 +++ linux-2.6.4-rc3/drivers/char/hw_random.c 2004-03-09 16:36:25.000000000 -0800 @@ -454,11 +454,7 @@ static void via_cleanup(void) { - u32 lo, hi; - - rdmsr(MSR_VIA_RNG, lo, hi); - lo &= ~VIA_RNG_ENABLE; - wrmsr(MSR_VIA_RNG, lo, hi); + /* do nothing */ } diff -urN linux-2.6.4-rc2/drivers/char/rio/rioctrl.c linux-2.6.4-rc3/drivers/char/rio/rioctrl.c --- linux-2.6.4-rc2/drivers/char/rio/rioctrl.c 2004-02-17 19:57:31.000000000 -0800 +++ linux-2.6.4-rc3/drivers/char/rio/rioctrl.c 2004-03-09 16:36:25.000000000 -0800 @@ -522,7 +522,7 @@ else { rio_dprintk (RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %x not added\n", (int) arg); - return 1; + return -ENOMEM; } return 0; } @@ -1593,12 +1593,12 @@ case RIO_NO_MESG: if ( su ) p->RIONoMessage = 1; - return su ? 0 : EPERM; + return su ? 0 : -EPERM; case RIO_MESG: if ( su ) p->RIONoMessage = 0; - return su ? 0 : EPERM; + return su ? 0 : -EPERM; case RIO_WHAT_MESG: if ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, diff -urN linux-2.6.4-rc2/drivers/i2c/busses/i2c-elv.c linux-2.6.4-rc3/drivers/i2c/busses/i2c-elv.c --- linux-2.6.4-rc2/drivers/i2c/busses/i2c-elv.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/i2c/busses/i2c-elv.c 2004-03-09 16:36:25.000000000 -0800 @@ -152,7 +152,7 @@ return -ENODEV; } } - pr_debug("i2c-elv: found device at %#x.\n",base); + pr_debug("i2c-elv: found device at %#lx.\n",base); return 0; } diff -urN linux-2.6.4-rc2/drivers/i2c/busses/i2c-velleman.c linux-2.6.4-rc3/drivers/i2c/busses/i2c-velleman.c --- linux-2.6.4-rc2/drivers/i2c/busses/i2c-velleman.c 2004-03-09 16:36:15.000000000 -0800 +++ linux-2.6.4-rc3/drivers/i2c/busses/i2c-velleman.c 2004-03-09 16:36:25.000000000 -0800 @@ -138,7 +138,7 @@ return -ENODEV; } } - pr_debug("i2c-velleman: found device at %#x.\n",base); + pr_debug("i2c-velleman: found device at %#lx.\n",base); return 0; } diff -urN linux-2.6.4-rc2/drivers/ide/Kconfig linux-2.6.4-rc3/drivers/ide/Kconfig --- linux-2.6.4-rc2/drivers/ide/Kconfig 2004-02-17 19:57:50.000000000 -0800 +++ linux-2.6.4-rc3/drivers/ide/Kconfig 2004-03-09 16:36:25.000000000 -0800 @@ -699,8 +699,8 @@ config PDC202XX_BURST bool "Special UDMA Feature" - depends on BLK_DEV_PDC202XX_OLD=y - ---help--- + depends on BLK_DEV_PDC202XX_OLD + help This option causes the pdc202xx driver to enable UDMA modes on the PDC202xx even when the PDC202xx BIOS has not done so. @@ -720,7 +720,7 @@ # FIXME - probably wants to be one for old and for new config PDC202XX_FORCE bool "Enable controller even if disabled by BIOS" - depends on BLK_DEV_PDC202XX_NEW=y + depends on BLK_DEV_PDC202XX_NEW help Enable the PDC202xx controller even if it has been disabled in the BIOS setup. diff -urN linux-2.6.4-rc2/drivers/md/Kconfig linux-2.6.4-rc3/drivers/md/Kconfig --- linux-2.6.4-rc2/drivers/md/Kconfig 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/md/Kconfig 2004-03-09 16:36:26.000000000 -0800 @@ -162,14 +162,6 @@ If unsure, say N. -config DM_IOCTL_V4 - bool "ioctl interface version 4" - depends on BLK_DEV_DM - default y - ---help--- - Recent tools use a new version of the ioctl interface, only - select this option if you intend using such tools. - config DM_CRYPT tristate "Crypt target support" depends on BLK_DEV_DM && EXPERIMENTAL diff -urN linux-2.6.4-rc2/drivers/md/dm-ioctl-v1.c linux-2.6.4-rc3/drivers/md/dm-ioctl-v1.c --- linux-2.6.4-rc2/drivers/md/dm-ioctl-v1.c 2004-02-17 19:59:47.000000000 -0800 +++ linux-2.6.4-rc3/drivers/md/dm-ioctl-v1.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1159 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. - * - * This file is released under the GPL. - */ - -#include "dm.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DM_DRIVER_EMAIL "dm@uk.sistina.com" - -/*----------------------------------------------------------------- - * The ioctl interface needs to be able to look up devices by - * name or uuid. - *---------------------------------------------------------------*/ -struct hash_cell { - struct list_head name_list; - struct list_head uuid_list; - - char *name; - char *uuid; - struct mapped_device *md; -}; - -#define NUM_BUCKETS 64 -#define MASK_BUCKETS (NUM_BUCKETS - 1) -static struct list_head _name_buckets[NUM_BUCKETS]; -static struct list_head _uuid_buckets[NUM_BUCKETS]; - -void dm_hash_remove_all(void); - -/* - * Guards access to all three tables. - */ -static DECLARE_RWSEM(_hash_lock); - -static void init_buckets(struct list_head *buckets) -{ - unsigned int i; - - for (i = 0; i < NUM_BUCKETS; i++) - INIT_LIST_HEAD(buckets + i); -} - -int dm_hash_init(void) -{ - init_buckets(_name_buckets); - init_buckets(_uuid_buckets); - devfs_mk_dir(DM_DIR); - return 0; -} - -void dm_hash_exit(void) -{ - dm_hash_remove_all(); - devfs_remove(DM_DIR); -} - -/*----------------------------------------------------------------- - * Hash function: - * We're not really concerned with the str hash function being - * fast since it's only used by the ioctl interface. - *---------------------------------------------------------------*/ -static unsigned int hash_str(const char *str) -{ - const unsigned int hash_mult = 2654435387U; - unsigned int h = 0; - - while (*str) - h = (h + (unsigned int) *str++) * hash_mult; - - return h & MASK_BUCKETS; -} - -/*----------------------------------------------------------------- - * Code for looking up a device by name - *---------------------------------------------------------------*/ -static struct hash_cell *__get_name_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _name_buckets + h) { - hc = list_entry(tmp, struct hash_cell, name_list); - if (!strcmp(hc->name, str)) - return hc; - } - - return NULL; -} - -static struct hash_cell *__get_uuid_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _uuid_buckets + h) { - hc = list_entry(tmp, struct hash_cell, uuid_list); - if (!strcmp(hc->uuid, str)) - return hc; - } - - return NULL; -} - -/*----------------------------------------------------------------- - * Inserting, removing and renaming a device. - *---------------------------------------------------------------*/ -static inline char *kstrdup(const char *str) -{ - char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); - if (r) - strcpy(r, str); - return r; -} - -static struct hash_cell *alloc_cell(const char *name, const char *uuid, - struct mapped_device *md) -{ - struct hash_cell *hc; - - hc = kmalloc(sizeof(*hc), GFP_KERNEL); - if (!hc) - return NULL; - - hc->name = kstrdup(name); - if (!hc->name) { - kfree(hc); - return NULL; - } - - if (!uuid) - hc->uuid = NULL; - - else { - hc->uuid = kstrdup(uuid); - if (!hc->uuid) { - kfree(hc->name); - kfree(hc); - return NULL; - } - } - - INIT_LIST_HEAD(&hc->name_list); - INIT_LIST_HEAD(&hc->uuid_list); - hc->md = md; - return hc; -} - -static void free_cell(struct hash_cell *hc) -{ - if (hc) { - kfree(hc->name); - kfree(hc->uuid); - kfree(hc); - } -} - -/* - * devfs stuff. - */ -static int register_with_devfs(struct hash_cell *hc) -{ - struct gendisk *disk = dm_disk(hc->md); - - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - DM_DIR "/%s", hc->name); - return 0; -} - -static int unregister_with_devfs(struct hash_cell *hc) -{ - devfs_remove(DM_DIR"/%s", hc->name); - return 0; -} - -/* - * The kdev_t and uuid of a device can never change once it is - * initially inserted. - */ -int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) -{ - struct hash_cell *cell; - - /* - * Allocate the new cells. - */ - cell = alloc_cell(name, uuid, md); - if (!cell) - return -ENOMEM; - - /* - * Insert the cell into all three hash tables. - */ - down_write(&_hash_lock); - if (__get_name_cell(name)) - goto bad; - - list_add(&cell->name_list, _name_buckets + hash_str(name)); - - if (uuid) { - if (__get_uuid_cell(uuid)) { - list_del(&cell->name_list); - goto bad; - } - list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); - } - register_with_devfs(cell); - dm_get(md); - up_write(&_hash_lock); - - return 0; - - bad: - up_write(&_hash_lock); - free_cell(cell); - return -EBUSY; -} - -void __hash_remove(struct hash_cell *hc) -{ - /* remove from the dev hash */ - list_del(&hc->uuid_list); - list_del(&hc->name_list); - unregister_with_devfs(hc); - dm_put(hc->md); - free_cell(hc); -} - -void dm_hash_remove_all(void) -{ - int i; - struct hash_cell *hc; - struct list_head *tmp, *n; - - down_write(&_hash_lock); - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_safe (tmp, n, _name_buckets + i) { - hc = list_entry(tmp, struct hash_cell, name_list); - __hash_remove(hc); - } - } - up_write(&_hash_lock); -} - -int dm_hash_rename(const char *old, const char *new) -{ - char *new_name, *old_name; - struct hash_cell *hc; - - /* - * duplicate new. - */ - new_name = kstrdup(new); - if (!new_name) - return -ENOMEM; - - down_write(&_hash_lock); - - /* - * Is new free ? - */ - hc = __get_name_cell(new); - if (hc) { - DMWARN("asked to rename to an already existing name %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -EBUSY; - } - - /* - * Is there such a device as 'old' ? - */ - hc = __get_name_cell(old); - if (!hc) { - DMWARN("asked to rename a non existent device %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -ENXIO; - } - - /* - * rename and move the name cell. - */ - unregister_with_devfs(hc); - - list_del(&hc->name_list); - old_name = hc->name; - hc->name = new_name; - list_add(&hc->name_list, _name_buckets + hash_str(new_name)); - - /* rename the device node in devfs */ - register_with_devfs(hc); - - up_write(&_hash_lock); - kfree(old_name); - return 0; -} - - -/*----------------------------------------------------------------- - * Implementation of the ioctl commands - *---------------------------------------------------------------*/ - -/* - * All the ioctl commands get dispatched to functions with this - * prototype. - */ -typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); - -/* - * Check a string doesn't overrun the chunk of - * memory we copied from userland. - */ -static int valid_str(char *str, void *begin, void *end) -{ - while (((void *) str >= begin) && ((void *) str < end)) - if (!*str++) - return 0; - - return -EINVAL; -} - -static int next_target(struct dm_target_spec *last, uint32_t next, - void *begin, void *end, - struct dm_target_spec **spec, char **params) -{ - *spec = (struct dm_target_spec *) - ((unsigned char *) last + next); - *params = (char *) (*spec + 1); - - if (*spec < (last + 1) || ((void *) *spec > end)) - return -EINVAL; - - return valid_str(*params, begin, end); -} - -static int populate_table(struct dm_table *table, struct dm_ioctl *args) -{ - int r, first = 1; - unsigned int i = 0; - struct dm_target_spec *spec; - char *params; - void *begin, *end; - - if (!args->target_count) { - DMWARN("populate_table: no targets specified"); - return -EINVAL; - } - - begin = (void *) args; - end = begin + args->data_size; - - for (i = 0; i < args->target_count; i++) { - - if (first) - r = next_target((struct dm_target_spec *) args, - args->data_start, - begin, end, &spec, ¶ms); - else - r = next_target(spec, spec->next, begin, end, - &spec, ¶ms); - - if (r) { - DMWARN("unable to find target"); - return -EINVAL; - } - - r = dm_table_add_target(table, spec->target_type, - (sector_t) spec->sector_start, - (sector_t) spec->length, - params); - if (r) { - DMWARN("internal error adding target to table"); - return -EINVAL; - } - - first = 0; - } - - return dm_table_complete(table); -} - -/* - * Round up the ptr to the next 'align' boundary. Obviously - * 'align' must be a power of 2. - */ -static inline void *align_ptr(void *ptr, unsigned int align) -{ - align--; - return (void *) (((unsigned long) (ptr + align)) & ~align); -} - -/* - * Copies a dm_ioctl and an optional additional payload to - * userland. - */ -static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, - void *data, uint32_t len) -{ - int r; - void *ptr = NULL; - - if (data) { - ptr = align_ptr(user + 1, sizeof(unsigned long)); - param->data_start = ptr - (void *) user; - } - - /* - * The version number has already been filled in, so we - * just copy later fields. - */ - r = copy_to_user(&user->data_size, ¶m->data_size, - sizeof(*param) - sizeof(param->version)); - if (r) - return -EFAULT; - - if (data) { - if (param->data_start + len > param->data_size) - return -ENOSPC; - - if (copy_to_user(ptr, data, len)) - r = -EFAULT; - } - - return r; -} - -/* - * Fills in a dm_ioctl structure, ready for sending back to - * userland. - */ -static int __info(struct mapped_device *md, struct dm_ioctl *param) -{ - struct dm_table *table; - struct block_device *bdev; - struct gendisk *disk = dm_disk(md); - - param->flags = DM_EXISTS_FLAG; - if (dm_suspended(md)) - param->flags |= DM_SUSPEND_FLAG; - - bdev = bdget_disk(disk, 0); - if (!bdev) - return -ENXIO; - - param->dev = old_encode_dev(bdev->bd_dev); - param->open_count = bdev->bd_openers; - bdput(bdev); - - if (disk->policy) - param->flags |= DM_READONLY_FLAG; - - table = dm_get_table(md); - param->target_count = dm_table_get_num_targets(table); - dm_table_put(table); - - return 0; -} - -/* - * Always use UUID for lookups if it's present, otherwise use name. - */ -static inline struct mapped_device *find_device(struct dm_ioctl *param) -{ - struct hash_cell *hc; - struct mapped_device *md = NULL; - - down_read(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (hc) { - md = hc->md; - - /* - * Sneakily write in both the name and the uuid - * while we have the cell. - */ - strlcpy(param->name, hc->name, sizeof(param->name)); - if (hc->uuid) - strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); - else - param->uuid[0] = '\0'; - - dm_get(md); - } - up_read(&_hash_lock); - - return md; -} - -#define ALIGNMENT sizeof(int) -static void *_align(void *ptr, unsigned int a) -{ - register unsigned long align = --a; - - return (void *) (((unsigned long) ptr + align) & ~align); -} - -/* - * Copies device info back to user space, used by - * the create and info ioctls. - */ -static int info(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - - param->flags = 0; - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - __info(md, param); - dm_put(md); - - out: - return results_to_user(user, param, NULL, 0); -} - -static inline int get_mode(struct dm_ioctl *param) -{ - int mode = FMODE_READ | FMODE_WRITE; - - if (param->flags & DM_READONLY_FLAG) - mode = FMODE_READ; - - return mode; -} - -static int check_name(const char *name) -{ - if (name[0] == '/') { - DMWARN("invalid device name"); - return -EINVAL; - } - - return 0; -} - -static int create(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct dm_table *t; - struct mapped_device *md; - - r = check_name(param->name); - if (r) - return r; - - r = dm_table_create(&t, get_mode(param), param->target_count); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_put(t); - return r; - } - - if (param->flags & DM_PERSISTENT_DEV_FLAG) - r = dm_create_with_minor(MINOR(old_decode_dev(param->dev)), &md); - else - r = dm_create(&md); - - if (r) { - dm_table_put(t); - return r; - } - - /* suspend the device */ - r = dm_suspend(md); - if (r) { - DMWARN("suspend failed"); - dm_table_put(t); - dm_put(md); - return r; - } - /* swap in the table */ - r = dm_swap_table(md, t); - if (r) { - DMWARN("table swap failed"); - dm_table_put(t); - dm_put(md); - return r; - } - - /* resume the device */ - r = dm_resume(md); - if (r) { - DMWARN("resume failed"); - dm_table_put(t); - dm_put(md); - return r; - } - - dm_table_put(t); /* md will have grabbed its own reference */ - - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); - dm_put(md); - - return r ? r : info(param, user); -} - -/* - * Build up the status struct for each target - */ -static int __status(struct mapped_device *md, struct dm_ioctl *param, - char *outbuf, size_t *len) -{ - unsigned int i, num_targets; - struct dm_target_spec *spec; - char *outptr; - status_type_t type; - struct dm_table *table = dm_get_table(md); - - if (param->flags & DM_STATUS_TABLE_FLAG) - type = STATUSTYPE_TABLE; - else - type = STATUSTYPE_INFO; - - outptr = outbuf; - - /* Get all the target info */ - num_targets = dm_table_get_num_targets(table); - for (i = 0; i < num_targets; i++) { - struct dm_target *ti = dm_table_get_target(table, i); - - if (outptr - outbuf + - sizeof(struct dm_target_spec) > param->data_size) { - dm_table_put(table); - return -ENOMEM; - } - - spec = (struct dm_target_spec *) outptr; - - spec->status = 0; - spec->sector_start = ti->begin; - spec->length = ti->len; - strlcpy(spec->target_type, ti->type->name, - sizeof(spec->target_type)); - - outptr += sizeof(struct dm_target_spec); - - /* Get the status/table string from the target driver */ - if (ti->type->status) - ti->type->status(ti, type, outptr, - outbuf + param->data_size - outptr); - else - outptr[0] = '\0'; - - outptr += strlen(outptr) + 1; - _align(outptr, ALIGNMENT); - spec->next = outptr - outbuf; - } - - param->target_count = num_targets; - *len = outptr - outbuf; - dm_table_put(table); - - return 0; -} - -/* - * Return the status of a device as a text string for each - * target. - */ -static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - size_t len = 0; - int ret; - char *outbuf = NULL; - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - /* We haven't a clue how long the resultant data will be so - just allocate as much as userland has allowed us and make sure - we don't overun it */ - outbuf = kmalloc(param->data_size, GFP_KERNEL); - if (!outbuf) - goto out; - /* - * Get the status of all targets - */ - __status(md, param, outbuf, &len); - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - out: - if (md) - dm_put(md); - - ret = results_to_user(user, param, outbuf, len); - - if (outbuf) - kfree(outbuf); - - return ret; -} - -/* - * Wait for a device to report an event - */ -static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - DECLARE_WAITQUEUE(wq, current); - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - /* - * Wait for a notification event - */ - set_current_state(TASK_INTERRUPTIBLE); - if (!dm_add_wait_queue(md, &wq, dm_get_event_nr(md))) { - schedule(); - dm_remove_wait_queue(md, &wq); - } - set_current_state(TASK_RUNNING); - dm_put(md); - - out: - return results_to_user(user, param, NULL, 0); -} - -/* - * Retrieves a list of devices used by a particular dm device. - */ -static int dep(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - unsigned int count; - struct mapped_device *md; - struct list_head *tmp; - size_t len = 0; - struct dm_target_deps *deps = NULL; - struct dm_table *table; - - md = find_device(param); - if (!md) - goto out; - table = dm_get_table(md); - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - /* - * Count the devices. - */ - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) - count++; - - /* - * Allocate a kernel space version of the dm_target_status - * struct. - */ - if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; - } - - len = sizeof(*deps) + (sizeof(*deps->dev) * count); - deps = kmalloc(len, GFP_KERNEL); - if (!deps) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; - } - - /* - * Fill in the devices. - */ - deps->count = count; - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - deps->dev[count++] = old_encode_dev(dd->bdev->bd_dev); - } - dm_table_put(table); - dm_put(md); - - out: - r = results_to_user(user, param, deps, len); - - kfree(deps); - return r; -} - -static int remove(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct hash_cell *hc; - - down_write(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -EINVAL; - } - - /* - * You may ask the interface to drop its reference to an - * in use device. This is no different to unlinking a - * file that someone still has open. The device will not - * actually be destroyed until the last opener closes it. - * The name and uuid of the device (both are interface - * properties) will be available for reuse immediately. - * - * You don't want to drop a _suspended_ device from the - * interface, since that will leave you with no way of - * resuming it. - */ - if (dm_suspended(hc->md)) { - DMWARN("refusing to remove a suspended device."); - up_write(&_hash_lock); - return -EPERM; - } - - __hash_remove(hc); - up_write(&_hash_lock); - return 0; -} - -static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) -{ - dm_hash_remove_all(); - return 0; -} - -static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct mapped_device *md; - - md = find_device(param); - if (!md) - return -ENXIO; - - if (param->flags & DM_SUSPEND_FLAG) - r = dm_suspend(md); - else - r = dm_resume(md); - - dm_put(md); - return r; -} - -static int reload(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct mapped_device *md; - struct dm_table *t; - - r = dm_table_create(&t, get_mode(param), param->target_count); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_put(t); - return r; - } - - md = find_device(param); - if (!md) { - dm_table_put(t); - return -ENXIO; - } - - r = dm_swap_table(md, t); - if (r) { - dm_put(md); - dm_table_put(t); - return r; - } - dm_table_put(t); /* md will have taken its own reference */ - - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - dm_put(md); - - r = info(param, user); - return r; -} - -static int rename(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - char *new_name = (char *) param + param->data_start; - - if (valid_str(new_name, (void *) param, - (void *) param + param->data_size)) { - DMWARN("Invalid new logical volume name supplied."); - return -EINVAL; - } - - r = check_name(new_name); - if (r) - return r; - - return dm_hash_rename(param->name, new_name); -} - - -/*----------------------------------------------------------------- - * Implementation of open/close/ioctl on the special char - * device. - *---------------------------------------------------------------*/ -static ioctl_fn lookup_ioctl(unsigned int cmd) -{ - static struct { - int cmd; - ioctl_fn fn; - } _ioctls[] = { - {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ - {DM_REMOVE_ALL_CMD, remove_all}, - {DM_DEV_CREATE_CMD, create}, - {DM_DEV_REMOVE_CMD, remove}, - {DM_DEV_RELOAD_CMD, reload}, - {DM_DEV_RENAME_CMD, rename}, - {DM_DEV_SUSPEND_CMD, suspend}, - {DM_DEV_DEPS_CMD, dep}, - {DM_DEV_STATUS_CMD, info}, - {DM_TARGET_STATUS_CMD, get_status}, - {DM_TARGET_WAIT_CMD, wait_device_event}, - }; - - return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; -} - -/* - * As well as checking the version compatibility this always - * copies the kernel interface version out. - */ -static int check_version(unsigned int cmd, struct dm_ioctl *user) -{ - uint32_t version[3]; - int r = 0; - - if (copy_from_user(version, user->version, sizeof(version))) - return -EFAULT; - - if ((DM_VERSION_MAJOR != version[0]) || - (DM_VERSION_MINOR < version[1])) { - DMWARN("ioctl interface mismatch: " - "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", - DM_VERSION_MAJOR, DM_VERSION_MINOR, - DM_VERSION_PATCHLEVEL, - version[0], version[1], version[2], cmd); - r = -EINVAL; - } - - /* - * Fill in the kernel version. - */ - version[0] = DM_VERSION_MAJOR; - version[1] = DM_VERSION_MINOR; - version[2] = DM_VERSION_PATCHLEVEL; - if (copy_to_user(user->version, version, sizeof(version))) - return -EFAULT; - - return r; -} - -static void free_params(struct dm_ioctl *param) -{ - vfree(param); -} - -static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) -{ - struct dm_ioctl tmp, *dmi; - - if (copy_from_user(&tmp, user, sizeof(tmp))) - return -EFAULT; - - if (tmp.data_size < sizeof(tmp)) - return -EINVAL; - - dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); - if (!dmi) - return -ENOMEM; - - if (copy_from_user(dmi, user, tmp.data_size)) { - vfree(dmi); - return -EFAULT; - } - - *param = dmi; - return 0; -} - -static int validate_params(uint cmd, struct dm_ioctl *param) -{ - /* Ignores parameters */ - if (cmd == DM_REMOVE_ALL_CMD) - return 0; - - /* Unless creating, either name of uuid but not both */ - if (cmd != DM_DEV_CREATE_CMD) { - if ((!*param->uuid && !*param->name) || - (*param->uuid && *param->name)) { - DMWARN("one of name or uuid must be supplied"); - return -EINVAL; - } - } - - /* Ensure strings are terminated */ - param->name[DM_NAME_LEN - 1] = '\0'; - param->uuid[DM_UUID_LEN - 1] = '\0'; - - return 0; -} - -static int ctl_ioctl(struct inode *inode, struct file *file, - uint command, ulong u) -{ - int r = 0; - unsigned int cmd; - struct dm_ioctl *param; - struct dm_ioctl *user = (struct dm_ioctl *) u; - ioctl_fn fn = NULL; - - /* only root can play with this */ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (_IOC_TYPE(command) != DM_IOCTL) - return -ENOTTY; - - cmd = _IOC_NR(command); - - /* - * Check the interface version passed in. This also - * writes out the kernels interface version. - */ - r = check_version(cmd, user); - if (r) - return r; - - /* - * Nothing more to do for the version command. - */ - if (cmd == DM_VERSION_CMD) - return 0; - - fn = lookup_ioctl(cmd); - if (!fn) { - DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); - return -ENOTTY; - } - - /* - * Copy the parameters into kernel space. - */ - r = copy_params(user, ¶m); - if (r) - return r; - - r = validate_params(cmd, param); - if (r) { - free_params(param); - return r; - } - - r = fn(param, user); - free_params(param); - return r; -} - -static struct file_operations _ctl_fops = { - .ioctl = ctl_ioctl, - .owner = THIS_MODULE, -}; - -static struct miscdevice _dm_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = DM_NAME, - .devfs_name = "mapper/control", - .fops = &_ctl_fops -}; - -/* - * Create misc character device and link to DM_DIR/control. - */ -int __init dm_interface_init(void) -{ - int r; - - r = dm_hash_init(); - if (r) - return r; - - r = misc_register(&_dm_misc); - if (r) { - DMERR("misc_register failed for control device"); - dm_hash_exit(); - return r; - } - - DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, - DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, - DM_DRIVER_EMAIL); - return 0; - - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - dm_hash_exit(); - return r; -} - -void dm_interface_exit(void) -{ - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - dm_hash_exit(); -} diff -urN linux-2.6.4-rc2/drivers/md/dm-ioctl-v4.c linux-2.6.4-rc3/drivers/md/dm-ioctl-v4.c --- linux-2.6.4-rc2/drivers/md/dm-ioctl-v4.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/drivers/md/dm-ioctl-v4.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1264 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. - * - * This file is released under the GPL. - */ - -#include "dm.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DM_DRIVER_EMAIL "dm@uk.sistina.com" - -/*----------------------------------------------------------------- - * The ioctl interface needs to be able to look up devices by - * name or uuid. - *---------------------------------------------------------------*/ -struct hash_cell { - struct list_head name_list; - struct list_head uuid_list; - - char *name; - char *uuid; - struct mapped_device *md; - struct dm_table *new_map; -}; - -#define NUM_BUCKETS 64 -#define MASK_BUCKETS (NUM_BUCKETS - 1) -static struct list_head _name_buckets[NUM_BUCKETS]; -static struct list_head _uuid_buckets[NUM_BUCKETS]; - -void dm_hash_remove_all(void); - -/* - * Guards access to both hash tables. - */ -static DECLARE_RWSEM(_hash_lock); - -static void init_buckets(struct list_head *buckets) -{ - unsigned int i; - - for (i = 0; i < NUM_BUCKETS; i++) - INIT_LIST_HEAD(buckets + i); -} - -int dm_hash_init(void) -{ - init_buckets(_name_buckets); - init_buckets(_uuid_buckets); - devfs_mk_dir(DM_DIR); - return 0; -} - -void dm_hash_exit(void) -{ - dm_hash_remove_all(); - devfs_remove(DM_DIR); -} - -/*----------------------------------------------------------------- - * Hash function: - * We're not really concerned with the str hash function being - * fast since it's only used by the ioctl interface. - *---------------------------------------------------------------*/ -static unsigned int hash_str(const char *str) -{ - const unsigned int hash_mult = 2654435387U; - unsigned int h = 0; - - while (*str) - h = (h + (unsigned int) *str++) * hash_mult; - - return h & MASK_BUCKETS; -} - -/*----------------------------------------------------------------- - * Code for looking up a device by name - *---------------------------------------------------------------*/ -static struct hash_cell *__get_name_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _name_buckets + h) { - hc = list_entry(tmp, struct hash_cell, name_list); - if (!strcmp(hc->name, str)) - return hc; - } - - return NULL; -} - -static struct hash_cell *__get_uuid_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _uuid_buckets + h) { - hc = list_entry(tmp, struct hash_cell, uuid_list); - if (!strcmp(hc->uuid, str)) - return hc; - } - - return NULL; -} - -/*----------------------------------------------------------------- - * Inserting, removing and renaming a device. - *---------------------------------------------------------------*/ -static inline char *kstrdup(const char *str) -{ - char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); - if (r) - strcpy(r, str); - return r; -} - -static struct hash_cell *alloc_cell(const char *name, const char *uuid, - struct mapped_device *md) -{ - struct hash_cell *hc; - - hc = kmalloc(sizeof(*hc), GFP_KERNEL); - if (!hc) - return NULL; - - hc->name = kstrdup(name); - if (!hc->name) { - kfree(hc); - return NULL; - } - - if (!uuid) - hc->uuid = NULL; - - else { - hc->uuid = kstrdup(uuid); - if (!hc->uuid) { - kfree(hc->name); - kfree(hc); - return NULL; - } - } - - INIT_LIST_HEAD(&hc->name_list); - INIT_LIST_HEAD(&hc->uuid_list); - hc->md = md; - hc->new_map = NULL; - return hc; -} - -static void free_cell(struct hash_cell *hc) -{ - if (hc) { - kfree(hc->name); - kfree(hc->uuid); - kfree(hc); - } -} - -/* - * devfs stuff. - */ -static int register_with_devfs(struct hash_cell *hc) -{ - struct gendisk *disk = dm_disk(hc->md); - - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - DM_DIR "/%s", hc->name); - return 0; -} - -static int unregister_with_devfs(struct hash_cell *hc) -{ - devfs_remove(DM_DIR"/%s", hc->name); - return 0; -} - -/* - * The kdev_t and uuid of a device can never change once it is - * initially inserted. - */ -int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) -{ - struct hash_cell *cell; - - /* - * Allocate the new cells. - */ - cell = alloc_cell(name, uuid, md); - if (!cell) - return -ENOMEM; - - /* - * Insert the cell into both hash tables. - */ - down_write(&_hash_lock); - if (__get_name_cell(name)) - goto bad; - - list_add(&cell->name_list, _name_buckets + hash_str(name)); - - if (uuid) { - if (__get_uuid_cell(uuid)) { - list_del(&cell->name_list); - goto bad; - } - list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); - } - register_with_devfs(cell); - dm_get(md); - up_write(&_hash_lock); - - return 0; - - bad: - up_write(&_hash_lock); - free_cell(cell); - return -EBUSY; -} - -void __hash_remove(struct hash_cell *hc) -{ - /* remove from the dev hash */ - list_del(&hc->uuid_list); - list_del(&hc->name_list); - unregister_with_devfs(hc); - dm_put(hc->md); - if (hc->new_map) - dm_table_put(hc->new_map); - free_cell(hc); -} - -void dm_hash_remove_all(void) -{ - int i; - struct hash_cell *hc; - struct list_head *tmp, *n; - - down_write(&_hash_lock); - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_safe (tmp, n, _name_buckets + i) { - hc = list_entry(tmp, struct hash_cell, name_list); - __hash_remove(hc); - } - } - up_write(&_hash_lock); -} - -int dm_hash_rename(const char *old, const char *new) -{ - char *new_name, *old_name; - struct hash_cell *hc; - - /* - * duplicate new. - */ - new_name = kstrdup(new); - if (!new_name) - return -ENOMEM; - - down_write(&_hash_lock); - - /* - * Is new free ? - */ - hc = __get_name_cell(new); - if (hc) { - DMWARN("asked to rename to an already existing name %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -EBUSY; - } - - /* - * Is there such a device as 'old' ? - */ - hc = __get_name_cell(old); - if (!hc) { - DMWARN("asked to rename a non existent device %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -ENXIO; - } - - /* - * rename and move the name cell. - */ - unregister_with_devfs(hc); - - list_del(&hc->name_list); - old_name = hc->name; - hc->name = new_name; - list_add(&hc->name_list, _name_buckets + hash_str(new_name)); - - /* rename the device node in devfs */ - register_with_devfs(hc); - - up_write(&_hash_lock); - kfree(old_name); - return 0; -} - -/*----------------------------------------------------------------- - * Implementation of the ioctl commands - *---------------------------------------------------------------*/ -/* - * All the ioctl commands get dispatched to functions with this - * prototype. - */ -typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size); - -static int remove_all(struct dm_ioctl *param, size_t param_size) -{ - dm_hash_remove_all(); - param->data_size = 0; - return 0; -} - -/* - * Round up the ptr to an 8-byte boundary. - */ -#define ALIGN_MASK 7 -static inline void *align_ptr(void *ptr) -{ - return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK); -} - -/* - * Retrieves the data payload buffer from an already allocated - * struct dm_ioctl. - */ -static void *get_result_buffer(struct dm_ioctl *param, size_t param_size, - size_t *len) -{ - param->data_start = align_ptr(param + 1) - (void *) param; - - if (param->data_start < param_size) - *len = param_size - param->data_start; - else - *len = 0; - - return ((void *) param) + param->data_start; -} - -static int list_devices(struct dm_ioctl *param, size_t param_size) -{ - unsigned int i; - struct hash_cell *hc; - size_t len, needed = 0; - struct gendisk *disk; - struct dm_name_list *nl, *old_nl = NULL; - - down_write(&_hash_lock); - - /* - * Loop through all the devices working out how much - * space we need. - */ - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_entry (hc, _name_buckets + i, name_list) { - needed += sizeof(struct dm_name_list); - needed += strlen(hc->name); - needed += ALIGN_MASK; - } - } - - /* - * Grab our output buffer. - */ - nl = get_result_buffer(param, param_size, &len); - if (len < needed) { - param->flags |= DM_BUFFER_FULL_FLAG; - goto out; - } - param->data_size = param->data_start + needed; - - nl->dev = 0; /* Flags no data */ - - /* - * Now loop through filling out the names. - */ - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_entry (hc, _name_buckets + i, name_list) { - if (old_nl) - old_nl->next = (uint32_t) ((void *) nl - - (void *) old_nl); - disk = dm_disk(hc->md); - nl->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); - nl->next = 0; - strcpy(nl->name, hc->name); - - old_nl = nl; - nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1); - } - } - - out: - up_write(&_hash_lock); - return 0; -} - -static int check_name(const char *name) -{ - if (strchr(name, '/')) { - DMWARN("invalid device name"); - return -EINVAL; - } - - return 0; -} - -/* - * Fills in a dm_ioctl structure, ready for sending back to - * userland. - */ -static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) -{ - struct gendisk *disk = dm_disk(md); - struct dm_table *table; - struct block_device *bdev; - - param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | - DM_ACTIVE_PRESENT_FLAG); - - if (dm_suspended(md)) - param->flags |= DM_SUSPEND_FLAG; - - bdev = bdget_disk(disk, 0); - if (!bdev) - return -ENXIO; - - param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); - - /* - * Yes, this will be out of date by the time it gets back - * to userland, but it is still very useful ofr - * debugging. - */ - param->open_count = bdev->bd_openers; - bdput(bdev); - - if (disk->policy) - param->flags |= DM_READONLY_FLAG; - - param->event_nr = dm_get_event_nr(md); - - table = dm_get_table(md); - if (table) { - param->flags |= DM_ACTIVE_PRESENT_FLAG; - param->target_count = dm_table_get_num_targets(table); - dm_table_put(table); - } else - param->target_count = 0; - - return 0; -} - -static int dev_create(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct mapped_device *md; - - r = check_name(param->name); - if (r) - return r; - - if (param->flags & DM_PERSISTENT_DEV_FLAG) - r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md); - else - r = dm_create(&md); - - if (r) - return r; - - r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); - if (r) { - dm_put(md); - return r; - } - - param->flags &= ~DM_INACTIVE_PRESENT_FLAG; - - r = __dev_status(md, param); - dm_put(md); - - return r; -} - -/* - * Always use UUID for lookups if it's present, otherwise use name. - */ -static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) -{ - return *param->uuid ? - __get_uuid_cell(param->uuid) : __get_name_cell(param->name); -} - -static inline struct mapped_device *find_device(struct dm_ioctl *param) -{ - struct hash_cell *hc; - struct mapped_device *md = NULL; - - down_read(&_hash_lock); - hc = __find_device_hash_cell(param); - if (hc) { - md = hc->md; - - /* - * Sneakily write in both the name and the uuid - * while we have the cell. - */ - strncpy(param->name, hc->name, sizeof(param->name)); - if (hc->uuid) - strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); - else - param->uuid[0] = '\0'; - - if (hc->new_map) - param->flags |= DM_INACTIVE_PRESENT_FLAG; - else - param->flags &= ~DM_INACTIVE_PRESENT_FLAG; - - dm_get(md); - } - up_read(&_hash_lock); - - return md; -} - -static int dev_remove(struct dm_ioctl *param, size_t param_size) -{ - struct hash_cell *hc; - - down_write(&_hash_lock); - hc = __find_device_hash_cell(param); - - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -ENXIO; - } - - __hash_remove(hc); - up_write(&_hash_lock); - param->data_size = 0; - return 0; -} - -/* - * Check a string doesn't overrun the chunk of - * memory we copied from userland. - */ -static int invalid_str(char *str, void *end) -{ - while ((void *) str < end) - if (!*str++) - return 0; - - return -EINVAL; -} - -static int dev_rename(struct dm_ioctl *param, size_t param_size) -{ - int r; - char *new_name = (char *) param + param->data_start; - - if (new_name < (char *) (param + 1) || - invalid_str(new_name, (void *) param + param_size)) { - DMWARN("Invalid new logical volume name supplied."); - return -EINVAL; - } - - r = check_name(new_name); - if (r) - return r; - - param->data_size = 0; - return dm_hash_rename(param->name, new_name); -} - -static int do_suspend(struct dm_ioctl *param) -{ - int r = 0; - struct mapped_device *md; - - md = find_device(param); - if (!md) - return -ENXIO; - - if (!dm_suspended(md)) - r = dm_suspend(md); - - if (!r) - r = __dev_status(md, param); - - dm_put(md); - return r; -} - -static int do_resume(struct dm_ioctl *param) -{ - int r = 0; - struct hash_cell *hc; - struct mapped_device *md; - struct dm_table *new_map; - - down_write(&_hash_lock); - - hc = __find_device_hash_cell(param); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -ENXIO; - } - - md = hc->md; - dm_get(md); - - new_map = hc->new_map; - hc->new_map = NULL; - param->flags &= ~DM_INACTIVE_PRESENT_FLAG; - - up_write(&_hash_lock); - - /* Do we need to load a new map ? */ - if (new_map) { - /* Suspend if it isn't already suspended */ - if (!dm_suspended(md)) - dm_suspend(md); - - r = dm_swap_table(md, new_map); - if (r) { - dm_put(md); - dm_table_put(new_map); - return r; - } - - if (dm_table_get_mode(new_map) & FMODE_WRITE) - set_disk_ro(dm_disk(md), 0); - else - set_disk_ro(dm_disk(md), 1); - - dm_table_put(new_map); - } - - if (dm_suspended(md)) - r = dm_resume(md); - - if (!r) - r = __dev_status(md, param); - - dm_put(md); - return r; -} - -/* - * Set or unset the suspension state of a device. - * If the device already is in the requested state we just return its status. - */ -static int dev_suspend(struct dm_ioctl *param, size_t param_size) -{ - if (param->flags & DM_SUSPEND_FLAG) - return do_suspend(param); - - return do_resume(param); -} - -/* - * Copies device info back to user space, used by - * the create and info ioctls. - */ -static int dev_status(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct mapped_device *md; - - md = find_device(param); - if (!md) - return -ENXIO; - - r = __dev_status(md, param); - dm_put(md); - return r; -} - -/* - * Build up the status struct for each target - */ -static void retrieve_status(struct dm_table *table, - struct dm_ioctl *param, size_t param_size) -{ - unsigned int i, num_targets; - struct dm_target_spec *spec; - char *outbuf, *outptr; - status_type_t type; - size_t remaining, len, used = 0; - - outptr = outbuf = get_result_buffer(param, param_size, &len); - - if (param->flags & DM_STATUS_TABLE_FLAG) - type = STATUSTYPE_TABLE; - else - type = STATUSTYPE_INFO; - - /* Get all the target info */ - num_targets = dm_table_get_num_targets(table); - for (i = 0; i < num_targets; i++) { - struct dm_target *ti = dm_table_get_target(table, i); - - remaining = len - (outptr - outbuf); - if (remaining < sizeof(struct dm_target_spec)) { - param->flags |= DM_BUFFER_FULL_FLAG; - break; - } - - spec = (struct dm_target_spec *) outptr; - - spec->status = 0; - spec->sector_start = ti->begin; - spec->length = ti->len; - strncpy(spec->target_type, ti->type->name, - sizeof(spec->target_type)); - - outptr += sizeof(struct dm_target_spec); - remaining = len - (outptr - outbuf); - - /* Get the status/table string from the target driver */ - if (ti->type->status) { - if (ti->type->status(ti, type, outptr, remaining)) { - param->flags |= DM_BUFFER_FULL_FLAG; - break; - } - } else - outptr[0] = '\0'; - - outptr += strlen(outptr) + 1; - used = param->data_start + (outptr - outbuf); - - align_ptr(outptr); - spec->next = outptr - outbuf; - } - - if (used) - param->data_size = used; - - param->target_count = num_targets; -} - -/* - * Wait for a device to report an event - */ -static int dev_wait(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct mapped_device *md; - struct dm_table *table; - DECLARE_WAITQUEUE(wq, current); - - md = find_device(param); - if (!md) - return -ENXIO; - - /* - * Wait for a notification event - */ - set_current_state(TASK_INTERRUPTIBLE); - if (!dm_add_wait_queue(md, &wq, param->event_nr)) { - schedule(); - dm_remove_wait_queue(md, &wq); - } - set_current_state(TASK_RUNNING); - - /* - * The userland program is going to want to know what - * changed to trigger the event, so we may as well tell - * him and save an ioctl. - */ - r = __dev_status(md, param); - if (r) - goto out; - - table = dm_get_table(md); - if (table) { - retrieve_status(table, param, param_size); - dm_table_put(table); - } - - out: - dm_put(md); - return r; -} - -static inline int get_mode(struct dm_ioctl *param) -{ - int mode = FMODE_READ | FMODE_WRITE; - - if (param->flags & DM_READONLY_FLAG) - mode = FMODE_READ; - - return mode; -} - -static int next_target(struct dm_target_spec *last, uint32_t next, void *end, - struct dm_target_spec **spec, char **target_params) -{ - *spec = (struct dm_target_spec *) ((unsigned char *) last + next); - *target_params = (char *) (*spec + 1); - - if (*spec < (last + 1)) - return -EINVAL; - - return invalid_str(*target_params, end); -} - -static int populate_table(struct dm_table *table, - struct dm_ioctl *param, size_t param_size) -{ - int r; - unsigned int i = 0; - struct dm_target_spec *spec = (struct dm_target_spec *) param; - uint32_t next = param->data_start; - void *end = (void *) param + param_size; - char *target_params; - - if (!param->target_count) { - DMWARN("populate_table: no targets specified"); - return -EINVAL; - } - - for (i = 0; i < param->target_count; i++) { - - r = next_target(spec, next, end, &spec, &target_params); - if (r) { - DMWARN("unable to find target"); - return r; - } - - r = dm_table_add_target(table, spec->target_type, - (sector_t) spec->sector_start, - (sector_t) spec->length, - target_params); - if (r) { - DMWARN("error adding target to table"); - return r; - } - - next = spec->next; - } - - return dm_table_complete(table); -} - -static int table_load(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct hash_cell *hc; - struct dm_table *t; - - r = dm_table_create(&t, get_mode(param), param->target_count); - if (r) - return r; - - r = populate_table(t, param, param_size); - if (r) { - dm_table_put(t); - return r; - } - - down_write(&_hash_lock); - hc = __find_device_hash_cell(param); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -ENXIO; - } - - if (hc->new_map) - dm_table_put(hc->new_map); - hc->new_map = t; - param->flags |= DM_INACTIVE_PRESENT_FLAG; - - r = __dev_status(hc->md, param); - up_write(&_hash_lock); - return r; -} - -static int table_clear(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct hash_cell *hc; - - down_write(&_hash_lock); - - hc = __find_device_hash_cell(param); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -ENXIO; - } - - if (hc->new_map) { - dm_table_put(hc->new_map); - hc->new_map = NULL; - } - - param->flags &= ~DM_INACTIVE_PRESENT_FLAG; - - r = __dev_status(hc->md, param); - up_write(&_hash_lock); - return r; -} - -/* - * Retrieves a list of devices used by a particular dm device. - */ -static void retrieve_deps(struct dm_table *table, - struct dm_ioctl *param, size_t param_size) -{ - unsigned int count = 0; - struct list_head *tmp; - size_t len, needed; - struct dm_target_deps *deps; - - deps = get_result_buffer(param, param_size, &len); - - /* - * Count the devices. - */ - list_for_each(tmp, dm_table_get_devices(table)) - count++; - - /* - * Check we have enough space. - */ - needed = sizeof(*deps) + (sizeof(*deps->dev) * count); - if (len < needed) { - param->flags |= DM_BUFFER_FULL_FLAG; - return; - } - - /* - * Fill in the devices. - */ - deps->count = count; - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev); - } - - param->data_size = param->data_start + needed; -} - -static int table_deps(struct dm_ioctl *param, size_t param_size) -{ - int r = 0; - struct mapped_device *md; - struct dm_table *table; - - md = find_device(param); - if (!md) - return -ENXIO; - - r = __dev_status(md, param); - if (r) - goto out; - - table = dm_get_table(md); - if (table) { - retrieve_deps(table, param, param_size); - dm_table_put(table); - } - - out: - dm_put(md); - return r; -} - -/* - * Return the status of a device as a text string for each - * target. - */ -static int table_status(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct mapped_device *md; - struct dm_table *table; - - md = find_device(param); - if (!md) - return -ENXIO; - - r = __dev_status(md, param); - if (r) - goto out; - - table = dm_get_table(md); - if (table) { - retrieve_status(table, param, param_size); - dm_table_put(table); - } - - out: - dm_put(md); - return r; -} - -/*----------------------------------------------------------------- - * Implementation of open/close/ioctl on the special char - * device. - *---------------------------------------------------------------*/ -static ioctl_fn lookup_ioctl(unsigned int cmd) -{ - static struct { - int cmd; - ioctl_fn fn; - } _ioctls[] = { - {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ - {DM_REMOVE_ALL_CMD, remove_all}, - {DM_LIST_DEVICES_CMD, list_devices}, - - {DM_DEV_CREATE_CMD, dev_create}, - {DM_DEV_REMOVE_CMD, dev_remove}, - {DM_DEV_RENAME_CMD, dev_rename}, - {DM_DEV_SUSPEND_CMD, dev_suspend}, - {DM_DEV_STATUS_CMD, dev_status}, - {DM_DEV_WAIT_CMD, dev_wait}, - - {DM_TABLE_LOAD_CMD, table_load}, - {DM_TABLE_CLEAR_CMD, table_clear}, - {DM_TABLE_DEPS_CMD, table_deps}, - {DM_TABLE_STATUS_CMD, table_status} - }; - - return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; -} - -/* - * As well as checking the version compatibility this always - * copies the kernel interface version out. - */ -static int check_version(unsigned int cmd, struct dm_ioctl *user) -{ - uint32_t version[3]; - int r = 0; - - if (copy_from_user(version, user->version, sizeof(version))) - return -EFAULT; - - if ((DM_VERSION_MAJOR != version[0]) || - (DM_VERSION_MINOR < version[1])) { - DMWARN("ioctl interface mismatch: " - "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", - DM_VERSION_MAJOR, DM_VERSION_MINOR, - DM_VERSION_PATCHLEVEL, - version[0], version[1], version[2], cmd); - r = -EINVAL; - } - - /* - * Fill in the kernel version. - */ - version[0] = DM_VERSION_MAJOR; - version[1] = DM_VERSION_MINOR; - version[2] = DM_VERSION_PATCHLEVEL; - if (copy_to_user(user->version, version, sizeof(version))) - return -EFAULT; - - return r; -} - -static void free_params(struct dm_ioctl *param) -{ - vfree(param); -} - -static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) -{ - struct dm_ioctl tmp, *dmi; - - if (copy_from_user(&tmp, user, sizeof(tmp))) - return -EFAULT; - - if (tmp.data_size < sizeof(tmp)) - return -EINVAL; - - dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); - if (!dmi) - return -ENOMEM; - - if (copy_from_user(dmi, user, tmp.data_size)) { - vfree(dmi); - return -EFAULT; - } - - *param = dmi; - return 0; -} - -static int validate_params(uint cmd, struct dm_ioctl *param) -{ - /* Always clear this flag */ - param->flags &= ~DM_BUFFER_FULL_FLAG; - - /* Ignores parameters */ - if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD) - return 0; - - /* Unless creating, either name or uuid but not both */ - if (cmd != DM_DEV_CREATE_CMD) { - if ((!*param->uuid && !*param->name) || - (*param->uuid && *param->name)) { - DMWARN("one of name or uuid must be supplied, cmd(%u)", - cmd); - return -EINVAL; - } - } - - /* Ensure strings are terminated */ - param->name[DM_NAME_LEN - 1] = '\0'; - param->uuid[DM_UUID_LEN - 1] = '\0'; - - return 0; -} - -static int ctl_ioctl(struct inode *inode, struct file *file, - uint command, ulong u) -{ - int r = 0; - unsigned int cmd; - struct dm_ioctl *param; - struct dm_ioctl *user = (struct dm_ioctl *) u; - ioctl_fn fn = NULL; - size_t param_size; - - /* only root can play with this */ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (_IOC_TYPE(command) != DM_IOCTL) - return -ENOTTY; - - cmd = _IOC_NR(command); - - /* - * Check the interface version passed in. This also - * writes out the kernel's interface version. - */ - r = check_version(cmd, user); - if (r) - return r; - - /* - * Nothing more to do for the version command. - */ - if (cmd == DM_VERSION_CMD) - return 0; - - fn = lookup_ioctl(cmd); - if (!fn) { - DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); - return -ENOTTY; - } - - /* - * Trying to avoid low memory issues when a device is - * suspended. - */ - current->flags |= PF_MEMALLOC; - - /* - * Copy the parameters into kernel space. - */ - r = copy_params(user, ¶m); - if (r) { - current->flags &= ~PF_MEMALLOC; - return r; - } - - /* - * FIXME: eventually we will remove the PF_MEMALLOC flag - * here. However the tools still do nasty things like - * 'load' while a device is suspended. - */ - - r = validate_params(cmd, param); - if (r) - goto out; - - param_size = param->data_size; - param->data_size = sizeof(*param); - r = fn(param, param_size); - - /* - * Copy the results back to userland. - */ - if (!r && copy_to_user(user, param, param->data_size)) - r = -EFAULT; - - out: - free_params(param); - current->flags &= ~PF_MEMALLOC; - return r; -} - -static struct file_operations _ctl_fops = { - .ioctl = ctl_ioctl, - .owner = THIS_MODULE, -}; - -static struct miscdevice _dm_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = DM_NAME, - .devfs_name = "mapper/control", - .fops = &_ctl_fops -}; - -/* - * Create misc character device and link to DM_DIR/control. - */ -int __init dm_interface_init(void) -{ - int r; - - r = dm_hash_init(); - if (r) - return r; - - r = misc_register(&_dm_misc); - if (r) { - DMERR("misc_register failed for control device"); - dm_hash_exit(); - return r; - } - - DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, - DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, - DM_DRIVER_EMAIL); - return 0; -} - -void dm_interface_exit(void) -{ - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - - dm_hash_exit(); -} diff -urN linux-2.6.4-rc2/drivers/md/dm-ioctl.c linux-2.6.4-rc3/drivers/md/dm-ioctl.c --- linux-2.6.4-rc2/drivers/md/dm-ioctl.c 2004-02-17 19:57:21.000000000 -0800 +++ linux-2.6.4-rc3/drivers/md/dm-ioctl.c 2004-03-09 16:36:26.000000000 -0800 @@ -1,13 +1,1264 @@ /* - * Copyright (C) 2003 Sistina Software (UK) Limited. + * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. * * This file is released under the GPL. */ +#include "dm.h" + +#include +#include +#include +#include +#include +#include +#include #include -#ifdef CONFIG_DM_IOCTL_V4 -#include "dm-ioctl-v4.c" -#else -#include "dm-ioctl-v1.c" -#endif +#include + +#define DM_DRIVER_EMAIL "dm@uk.sistina.com" + +/*----------------------------------------------------------------- + * The ioctl interface needs to be able to look up devices by + * name or uuid. + *---------------------------------------------------------------*/ +struct hash_cell { + struct list_head name_list; + struct list_head uuid_list; + + char *name; + char *uuid; + struct mapped_device *md; + struct dm_table *new_map; +}; + +#define NUM_BUCKETS 64 +#define MASK_BUCKETS (NUM_BUCKETS - 1) +static struct list_head _name_buckets[NUM_BUCKETS]; +static struct list_head _uuid_buckets[NUM_BUCKETS]; + +void dm_hash_remove_all(void); + +/* + * Guards access to both hash tables. + */ +static DECLARE_RWSEM(_hash_lock); + +static void init_buckets(struct list_head *buckets) +{ + unsigned int i; + + for (i = 0; i < NUM_BUCKETS; i++) + INIT_LIST_HEAD(buckets + i); +} + +int dm_hash_init(void) +{ + init_buckets(_name_buckets); + init_buckets(_uuid_buckets); + devfs_mk_dir(DM_DIR); + return 0; +} + +void dm_hash_exit(void) +{ + dm_hash_remove_all(); + devfs_remove(DM_DIR); +} + +/*----------------------------------------------------------------- + * Hash function: + * We're not really concerned with the str hash function being + * fast since it's only used by the ioctl interface. + *---------------------------------------------------------------*/ +static unsigned int hash_str(const char *str) +{ + const unsigned int hash_mult = 2654435387U; + unsigned int h = 0; + + while (*str) + h = (h + (unsigned int) *str++) * hash_mult; + + return h & MASK_BUCKETS; +} + +/*----------------------------------------------------------------- + * Code for looking up a device by name + *---------------------------------------------------------------*/ +static struct hash_cell *__get_name_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _name_buckets + h) { + hc = list_entry(tmp, struct hash_cell, name_list); + if (!strcmp(hc->name, str)) + return hc; + } + + return NULL; +} + +static struct hash_cell *__get_uuid_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _uuid_buckets + h) { + hc = list_entry(tmp, struct hash_cell, uuid_list); + if (!strcmp(hc->uuid, str)) + return hc; + } + + return NULL; +} + +/*----------------------------------------------------------------- + * Inserting, removing and renaming a device. + *---------------------------------------------------------------*/ +static inline char *kstrdup(const char *str) +{ + char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); + if (r) + strcpy(r, str); + return r; +} + +static struct hash_cell *alloc_cell(const char *name, const char *uuid, + struct mapped_device *md) +{ + struct hash_cell *hc; + + hc = kmalloc(sizeof(*hc), GFP_KERNEL); + if (!hc) + return NULL; + + hc->name = kstrdup(name); + if (!hc->name) { + kfree(hc); + return NULL; + } + + if (!uuid) + hc->uuid = NULL; + + else { + hc->uuid = kstrdup(uuid); + if (!hc->uuid) { + kfree(hc->name); + kfree(hc); + return NULL; + } + } + + INIT_LIST_HEAD(&hc->name_list); + INIT_LIST_HEAD(&hc->uuid_list); + hc->md = md; + hc->new_map = NULL; + return hc; +} + +static void free_cell(struct hash_cell *hc) +{ + if (hc) { + kfree(hc->name); + kfree(hc->uuid); + kfree(hc); + } +} + +/* + * devfs stuff. + */ +static int register_with_devfs(struct hash_cell *hc) +{ + struct gendisk *disk = dm_disk(hc->md); + + devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + DM_DIR "/%s", hc->name); + return 0; +} + +static int unregister_with_devfs(struct hash_cell *hc) +{ + devfs_remove(DM_DIR"/%s", hc->name); + return 0; +} + +/* + * The kdev_t and uuid of a device can never change once it is + * initially inserted. + */ +int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) +{ + struct hash_cell *cell; + + /* + * Allocate the new cells. + */ + cell = alloc_cell(name, uuid, md); + if (!cell) + return -ENOMEM; + + /* + * Insert the cell into both hash tables. + */ + down_write(&_hash_lock); + if (__get_name_cell(name)) + goto bad; + + list_add(&cell->name_list, _name_buckets + hash_str(name)); + + if (uuid) { + if (__get_uuid_cell(uuid)) { + list_del(&cell->name_list); + goto bad; + } + list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); + } + register_with_devfs(cell); + dm_get(md); + up_write(&_hash_lock); + + return 0; + + bad: + up_write(&_hash_lock); + free_cell(cell); + return -EBUSY; +} + +void __hash_remove(struct hash_cell *hc) +{ + /* remove from the dev hash */ + list_del(&hc->uuid_list); + list_del(&hc->name_list); + unregister_with_devfs(hc); + dm_put(hc->md); + if (hc->new_map) + dm_table_put(hc->new_map); + free_cell(hc); +} + +void dm_hash_remove_all(void) +{ + int i; + struct hash_cell *hc; + struct list_head *tmp, *n; + + down_write(&_hash_lock); + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_safe (tmp, n, _name_buckets + i) { + hc = list_entry(tmp, struct hash_cell, name_list); + __hash_remove(hc); + } + } + up_write(&_hash_lock); +} + +int dm_hash_rename(const char *old, const char *new) +{ + char *new_name, *old_name; + struct hash_cell *hc; + + /* + * duplicate new. + */ + new_name = kstrdup(new); + if (!new_name) + return -ENOMEM; + + down_write(&_hash_lock); + + /* + * Is new free ? + */ + hc = __get_name_cell(new); + if (hc) { + DMWARN("asked to rename to an already existing name %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -EBUSY; + } + + /* + * Is there such a device as 'old' ? + */ + hc = __get_name_cell(old); + if (!hc) { + DMWARN("asked to rename a non existent device %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -ENXIO; + } + + /* + * rename and move the name cell. + */ + unregister_with_devfs(hc); + + list_del(&hc->name_list); + old_name = hc->name; + hc->name = new_name; + list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + + /* rename the device node in devfs */ + register_with_devfs(hc); + + up_write(&_hash_lock); + kfree(old_name); + return 0; +} + +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size); + +static int remove_all(struct dm_ioctl *param, size_t param_size) +{ + dm_hash_remove_all(); + param->data_size = 0; + return 0; +} + +/* + * Round up the ptr to an 8-byte boundary. + */ +#define ALIGN_MASK 7 +static inline void *align_ptr(void *ptr) +{ + return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK); +} + +/* + * Retrieves the data payload buffer from an already allocated + * struct dm_ioctl. + */ +static void *get_result_buffer(struct dm_ioctl *param, size_t param_size, + size_t *len) +{ + param->data_start = align_ptr(param + 1) - (void *) param; + + if (param->data_start < param_size) + *len = param_size - param->data_start; + else + *len = 0; + + return ((void *) param) + param->data_start; +} + +static int list_devices(struct dm_ioctl *param, size_t param_size) +{ + unsigned int i; + struct hash_cell *hc; + size_t len, needed = 0; + struct gendisk *disk; + struct dm_name_list *nl, *old_nl = NULL; + + down_write(&_hash_lock); + + /* + * Loop through all the devices working out how much + * space we need. + */ + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_entry (hc, _name_buckets + i, name_list) { + needed += sizeof(struct dm_name_list); + needed += strlen(hc->name); + needed += ALIGN_MASK; + } + } + + /* + * Grab our output buffer. + */ + nl = get_result_buffer(param, param_size, &len); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + goto out; + } + param->data_size = param->data_start + needed; + + nl->dev = 0; /* Flags no data */ + + /* + * Now loop through filling out the names. + */ + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_entry (hc, _name_buckets + i, name_list) { + if (old_nl) + old_nl->next = (uint32_t) ((void *) nl - + (void *) old_nl); + disk = dm_disk(hc->md); + nl->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); + nl->next = 0; + strcpy(nl->name, hc->name); + + old_nl = nl; + nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1); + } + } + + out: + up_write(&_hash_lock); + return 0; +} + +static int check_name(const char *name) +{ + if (strchr(name, '/')) { + DMWARN("invalid device name"); + return -EINVAL; + } + + return 0; +} + +/* + * Fills in a dm_ioctl structure, ready for sending back to + * userland. + */ +static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) +{ + struct gendisk *disk = dm_disk(md); + struct dm_table *table; + struct block_device *bdev; + + param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | + DM_ACTIVE_PRESENT_FLAG); + + if (dm_suspended(md)) + param->flags |= DM_SUSPEND_FLAG; + + bdev = bdget_disk(disk, 0); + if (!bdev) + return -ENXIO; + + param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); + + /* + * Yes, this will be out of date by the time it gets back + * to userland, but it is still very useful ofr + * debugging. + */ + param->open_count = bdev->bd_openers; + bdput(bdev); + + if (disk->policy) + param->flags |= DM_READONLY_FLAG; + + param->event_nr = dm_get_event_nr(md); + + table = dm_get_table(md); + if (table) { + param->flags |= DM_ACTIVE_PRESENT_FLAG; + param->target_count = dm_table_get_num_targets(table); + dm_table_put(table); + } else + param->target_count = 0; + + return 0; +} + +static int dev_create(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + + r = check_name(param->name); + if (r) + return r; + + if (param->flags & DM_PERSISTENT_DEV_FLAG) + r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md); + else + r = dm_create(&md); + + if (r) + return r; + + r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); + if (r) { + dm_put(md); + return r; + } + + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(md, param); + dm_put(md); + + return r; +} + +/* + * Always use UUID for lookups if it's present, otherwise use name. + */ +static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) +{ + return *param->uuid ? + __get_uuid_cell(param->uuid) : __get_name_cell(param->name); +} + +static inline struct mapped_device *find_device(struct dm_ioctl *param) +{ + struct hash_cell *hc; + struct mapped_device *md = NULL; + + down_read(&_hash_lock); + hc = __find_device_hash_cell(param); + if (hc) { + md = hc->md; + + /* + * Sneakily write in both the name and the uuid + * while we have the cell. + */ + strncpy(param->name, hc->name, sizeof(param->name)); + if (hc->uuid) + strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); + else + param->uuid[0] = '\0'; + + if (hc->new_map) + param->flags |= DM_INACTIVE_PRESENT_FLAG; + else + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + dm_get(md); + } + up_read(&_hash_lock); + + return md; +} + +static int dev_remove(struct dm_ioctl *param, size_t param_size) +{ + struct hash_cell *hc; + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); + + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + __hash_remove(hc); + up_write(&_hash_lock); + param->data_size = 0; + return 0; +} + +/* + * Check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int invalid_str(char *str, void *end) +{ + while ((void *) str < end) + if (!*str++) + return 0; + + return -EINVAL; +} + +static int dev_rename(struct dm_ioctl *param, size_t param_size) +{ + int r; + char *new_name = (char *) param + param->data_start; + + if (new_name < (char *) (param + 1) || + invalid_str(new_name, (void *) param + param_size)) { + DMWARN("Invalid new logical volume name supplied."); + return -EINVAL; + } + + r = check_name(new_name); + if (r) + return r; + + param->data_size = 0; + return dm_hash_rename(param->name, new_name); +} + +static int do_suspend(struct dm_ioctl *param) +{ + int r = 0; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + if (!dm_suspended(md)) + r = dm_suspend(md); + + if (!r) + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +static int do_resume(struct dm_ioctl *param) +{ + int r = 0; + struct hash_cell *hc; + struct mapped_device *md; + struct dm_table *new_map; + + down_write(&_hash_lock); + + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + md = hc->md; + dm_get(md); + + new_map = hc->new_map; + hc->new_map = NULL; + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + up_write(&_hash_lock); + + /* Do we need to load a new map ? */ + if (new_map) { + /* Suspend if it isn't already suspended */ + if (!dm_suspended(md)) + dm_suspend(md); + + r = dm_swap_table(md, new_map); + if (r) { + dm_put(md); + dm_table_put(new_map); + return r; + } + + if (dm_table_get_mode(new_map) & FMODE_WRITE) + set_disk_ro(dm_disk(md), 0); + else + set_disk_ro(dm_disk(md), 1); + + dm_table_put(new_map); + } + + if (dm_suspended(md)) + r = dm_resume(md); + + if (!r) + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +/* + * Set or unset the suspension state of a device. + * If the device already is in the requested state we just return its status. + */ +static int dev_suspend(struct dm_ioctl *param, size_t param_size) +{ + if (param->flags & DM_SUSPEND_FLAG) + return do_suspend(param); + + return do_resume(param); +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int dev_status(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + dm_put(md); + return r; +} + +/* + * Build up the status struct for each target + */ +static void retrieve_status(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + unsigned int i, num_targets; + struct dm_target_spec *spec; + char *outbuf, *outptr; + status_type_t type; + size_t remaining, len, used = 0; + + outptr = outbuf = get_result_buffer(param, param_size, &len); + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + /* Get all the target info */ + num_targets = dm_table_get_num_targets(table); + for (i = 0; i < num_targets; i++) { + struct dm_target *ti = dm_table_get_target(table, i); + + remaining = len - (outptr - outbuf); + if (remaining < sizeof(struct dm_target_spec)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = ti->begin; + spec->length = ti->len; + strncpy(spec->target_type, ti->type->name, + sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + remaining = len - (outptr - outbuf); + + /* Get the status/table string from the target driver */ + if (ti->type->status) { + if (ti->type->status(ti, type, outptr, remaining)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + } else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + used = param->data_start + (outptr - outbuf); + + align_ptr(outptr); + spec->next = outptr - outbuf; + } + + if (used) + param->data_size = used; + + param->target_count = num_targets; +} + +/* + * Wait for a device to report an event + */ +static int dev_wait(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + struct dm_table *table; + DECLARE_WAITQUEUE(wq, current); + + md = find_device(param); + if (!md) + return -ENXIO; + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!dm_add_wait_queue(md, &wq, param->event_nr)) { + schedule(); + dm_remove_wait_queue(md, &wq); + } + set_current_state(TASK_RUNNING); + + /* + * The userland program is going to want to know what + * changed to trigger the event, so we may as well tell + * him and save an ioctl. + */ + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_status(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + +static int next_target(struct dm_target_spec *last, uint32_t next, void *end, + struct dm_target_spec **spec, char **target_params) +{ + *spec = (struct dm_target_spec *) ((unsigned char *) last + next); + *target_params = (char *) (*spec + 1); + + if (*spec < (last + 1)) + return -EINVAL; + + return invalid_str(*target_params, end); +} + +static int populate_table(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + int r; + unsigned int i = 0; + struct dm_target_spec *spec = (struct dm_target_spec *) param; + uint32_t next = param->data_start; + void *end = (void *) param + param_size; + char *target_params; + + if (!param->target_count) { + DMWARN("populate_table: no targets specified"); + return -EINVAL; + } + + for (i = 0; i < param->target_count; i++) { + + r = next_target(spec, next, end, &spec, &target_params); + if (r) { + DMWARN("unable to find target"); + return r; + } + + r = dm_table_add_target(table, spec->target_type, + (sector_t) spec->sector_start, + (sector_t) spec->length, + target_params); + if (r) { + DMWARN("error adding target to table"); + return r; + } + + next = spec->next; + } + + return dm_table_complete(table); +} + +static int table_load(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct hash_cell *hc; + struct dm_table *t; + + r = dm_table_create(&t, get_mode(param), param->target_count); + if (r) + return r; + + r = populate_table(t, param, param_size); + if (r) { + dm_table_put(t); + return r; + } + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + if (hc->new_map) + dm_table_put(hc->new_map); + hc->new_map = t; + param->flags |= DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); + up_write(&_hash_lock); + return r; +} + +static int table_clear(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct hash_cell *hc; + + down_write(&_hash_lock); + + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + if (hc->new_map) { + dm_table_put(hc->new_map); + hc->new_map = NULL; + } + + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); + up_write(&_hash_lock); + return r; +} + +/* + * Retrieves a list of devices used by a particular dm device. + */ +static void retrieve_deps(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + unsigned int count = 0; + struct list_head *tmp; + size_t len, needed; + struct dm_target_deps *deps; + + deps = get_result_buffer(param, param_size, &len); + + /* + * Count the devices. + */ + list_for_each(tmp, dm_table_get_devices(table)) + count++; + + /* + * Check we have enough space. + */ + needed = sizeof(*deps) + (sizeof(*deps->dev) * count); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + return; + } + + /* + * Fill in the devices. + */ + deps->count = count; + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev); + } + + param->data_size = param->data_start + needed; +} + +static int table_deps(struct dm_ioctl *param, size_t param_size) +{ + int r = 0; + struct mapped_device *md; + struct dm_table *table; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_deps(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +/* + * Return the status of a device as a text string for each + * target. + */ +static int table_status(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + struct dm_table *table; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_status(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_LIST_DEVICES_CMD, list_devices}, + + {DM_DEV_CREATE_CMD, dev_create}, + {DM_DEV_REMOVE_CMD, dev_remove}, + {DM_DEV_RENAME_CMD, dev_rename}, + {DM_DEV_SUSPEND_CMD, dev_suspend}, + {DM_DEV_STATUS_CMD, dev_status}, + {DM_DEV_WAIT_CMD, dev_wait}, + + {DM_TABLE_LOAD_CMD, table_load}, + {DM_TABLE_CLEAR_CMD, table_clear}, + {DM_TABLE_DEPS_CMD, table_deps}, + {DM_TABLE_STATUS_CMD, table_status} + }; + + return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(unsigned int cmd, struct dm_ioctl *user) +{ + uint32_t version[3]; + int r = 0; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; + } + + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; + + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; + } + + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Always clear this flag */ + param->flags &= ~DM_BUFFER_FULL_FLAG; + + /* Ignores parameters */ + if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD) + return 0; + + /* Unless creating, either name or uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied, cmd(%u)", + cmd); + return -EINVAL; + } + } + + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; + + return 0; +} + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ + int r = 0; + unsigned int cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; + size_t param_size; + + /* only root can play with this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; + + cmd = _IOC_NR(command); + + /* + * Check the interface version passed in. This also + * writes out the kernel's interface version. + */ + r = check_version(cmd, user); + if (r) + return r; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + fn = lookup_ioctl(cmd); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); + return -ENOTTY; + } + + /* + * Trying to avoid low memory issues when a device is + * suspended. + */ + current->flags |= PF_MEMALLOC; + + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) { + current->flags &= ~PF_MEMALLOC; + return r; + } + + /* + * FIXME: eventually we will remove the PF_MEMALLOC flag + * here. However the tools still do nasty things like + * 'load' while a device is suspended. + */ + + r = validate_params(cmd, param); + if (r) + goto out; + + param_size = param->data_size; + param->data_size = sizeof(*param); + r = fn(param, param_size); + + /* + * Copy the results back to userland. + */ + if (!r && copy_to_user(user, param, param->data_size)) + r = -EFAULT; + + out: + free_params(param); + current->flags &= ~PF_MEMALLOC; + return r; +} + +static struct file_operations _ctl_fops = { + .ioctl = ctl_ioctl, + .owner = THIS_MODULE, +}; + +static struct miscdevice _dm_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DM_NAME, + .devfs_name = "mapper/control", + .fops = &_ctl_fops +}; + +/* + * Create misc character device and link to DM_DIR/control. + */ +int __init dm_interface_init(void) +{ + int r; + + r = dm_hash_init(); + if (r) + return r; + + r = misc_register(&_dm_misc); + if (r) { + DMERR("misc_register failed for control device"); + dm_hash_exit(); + return r; + } + + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); + return 0; +} + +void dm_interface_exit(void) +{ + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + + dm_hash_exit(); +} diff -urN linux-2.6.4-rc2/drivers/media/video/v4l1-compat.c linux-2.6.4-rc3/drivers/media/video/v4l1-compat.c --- linux-2.6.4-rc2/drivers/media/video/v4l1-compat.c 2004-02-17 19:58:10.000000000 -0800 +++ linux-2.6.4-rc3/drivers/media/video/v4l1-compat.c 2004-03-09 16:36:26.000000000 -0800 @@ -503,10 +503,11 @@ int *on = arg; if (0 == *on) { + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* dirty hack time. But v4l1 has no STREAMOFF * equivalent in the API, and this one at * least comes close ... */ - drv(inode, file, VIDIOC_STREAMOFF, NULL); + drv(inode, file, VIDIOC_STREAMOFF, &type); } err = drv(inode, file, VIDIOC_OVERLAY, arg); if (err < 0) @@ -857,6 +858,7 @@ case VIDIOCMCAPTURE: /* capture a frame */ { struct video_mmap *mm = arg; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL); memset(&buf2,0,sizeof(buf2)); @@ -897,7 +899,7 @@ dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err); break; } - err = drv(inode, file, VIDIOC_STREAMON, NULL); + err = drv(inode, file, VIDIOC_STREAMON, &type); if (err < 0) dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err); break; diff -urN linux-2.6.4-rc2/drivers/message/i2o/Kconfig linux-2.6.4-rc3/drivers/message/i2o/Kconfig --- linux-2.6.4-rc2/drivers/message/i2o/Kconfig 2004-02-17 19:57:13.000000000 -0800 +++ linux-2.6.4-rc3/drivers/message/i2o/Kconfig 2004-03-09 16:36:26.000000000 -0800 @@ -39,7 +39,10 @@ depends on I2O help Include support for the I2O Block OSM. The Block OSM presents disk - and other structured block devices to the operating system. + and other structured block devices to the operating system. If you + are using an RAID controller, you could access the array only by + the Block OSM driver. But it is possible to access the single disks + by the SCSI OSM driver, for example to monitor the disks. To compile this support as a module, choose M here: the module will be called i2o_block. @@ -50,7 +53,8 @@ help Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel I2O controller. You can use both the SCSI and Block OSM together if - you wish. + you wish. To access a RAID array, you must use the Block OSM driver. + But you could use the SCSI OSM driver to monitor the single disks. To compile this support as a module, choose M here: the module will be called i2o_scsi. diff -urN linux-2.6.4-rc2/drivers/message/i2o/i2o_block.c linux-2.6.4-rc3/drivers/message/i2o/i2o_block.c --- linux-2.6.4-rc2/drivers/message/i2o/i2o_block.c 2004-02-17 19:58:47.000000000 -0800 +++ linux-2.6.4-rc3/drivers/message/i2o/i2o_block.c 2004-03-09 16:36:26.000000000 -0800 @@ -50,9 +50,11 @@ * Properly attach/detach I2O gendisk structure from the system * gendisk list. The I2O block devices now appear in * /proc/partitions. + * Markus Lidel : + * Minor bugfixes for 2.6. * - * To do: - * Serial number scanning to find duplicates for FC multipathing + * To do: + * Serial number scanning to find duplicates for FC multipathing */ #include @@ -109,25 +111,6 @@ I2O_EVT_IND_BSA_SCSI_SMART ) -/* - * I2O Block Error Codes - should be in a header file really... - */ -#define I2O_BSA_DSC_SUCCESS 0x0000 -#define I2O_BSA_DSC_MEDIA_ERROR 0x0001 -#define I2O_BSA_DSC_ACCESS_ERROR 0x0002 -#define I2O_BSA_DSC_DEVICE_FAILURE 0x0003 -#define I2O_BSA_DSC_DEVICE_NOT_READY 0x0004 -#define I2O_BSA_DSC_MEDIA_NOT_PRESENT 0x0005 -#define I2O_BSA_DSC_MEDIA_LOCKED 0x0006 -#define I2O_BSA_DSC_MEDIA_FAILURE 0x0007 -#define I2O_BSA_DSC_PROTOCOL_FAILURE 0x0008 -#define I2O_BSA_DSC_BUS_FAILURE 0x0009 -#define I2O_BSA_DSC_ACCESS_VIOLATION 0x000A -#define I2O_BSA_DSC_WRITE_PROTECTED 0x000B -#define I2O_BSA_DSC_DEVICE_RESET 0x000C -#define I2O_BSA_DSC_VOLUME_CHANGED 0x000D -#define I2O_BSA_DSC_TIMEOUT 0x000E - #define I2O_LOCK(unit) (i2ob_dev[(unit)].req_queue->queue_lock) /* @@ -1091,6 +1074,28 @@ d->lct_data.tid, unit); /* + * If this is the first I2O block device found on this IOP, + * we need to initialize all the queue data structures + * before any I/O can be performed. If it fails, this + * device is useless. + */ + if(!i2ob_queues[unit]) { + if(i2ob_init_iop(unit)) + return 1; + } + + /* + * This will save one level of lookup/indirection in critical + * code so that we can directly get the queue ptr from the + * device instead of having to go the IOP data structure. + */ + dev->req_queue = i2ob_queues[unit]->req_queue; + + /* initialize gendik structure */ + i2ob_disk[unit>>4]->private_data = dev; + i2ob_disk[unit>>4]->queue = dev->req_queue; + + /* * Ask for the current media data. If that isn't supported * then we ask for the device capacity data */ @@ -1148,6 +1153,7 @@ } strcpy(d->dev_name, i2ob_disk[unit>>4]->disk_name); + strcpy(i2ob_disk[unit>>4]->devfs_name, i2ob_disk[unit>>4]->disk_name); printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n", d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, i2ob_max_sectors[unit]<<9); @@ -1193,28 +1199,6 @@ printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", d->dev_name, i2ob_max_sectors[unit]); - /* - * If this is the first I2O block device found on this IOP, - * we need to initialize all the queue data structures - * before any I/O can be performed. If it fails, this - * device is useless. - */ - if(!i2ob_queues[c->unit]) { - if(i2ob_init_iop(c->unit)) - return 1; - } - - /* - * This will save one level of lookup/indirection in critical - * code so that we can directly get the queue ptr from the - * device instead of having to go the IOP data structure. - */ - dev->req_queue = i2ob_queues[c->unit]->req_queue; - - /* Register a size before we register for events - otherwise we - might miss and overwrite an event */ - set_capacity(i2ob_disk[unit>>4], size>>9); - /* * Register for the events we're interested in and that the * device actually supports. @@ -1251,6 +1235,7 @@ i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0]; atomic_set(&i2ob_queues[unit]->queue_depth, 0); + i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED; i2ob_queues[unit]->req_queue = blk_init_queue(i2ob_request, &i2ob_queues[unit]->lock); if (!i2ob_queues[unit]->req_queue) { kfree(i2ob_queues[unit]); @@ -1336,6 +1321,8 @@ continue; } + i2o_release_device(d, &i2o_block_handler); + if(scan_unit>4); } - i2o_release_device(d, &i2o_block_handler); } i2o_unlock_controller(c); } @@ -1699,9 +1685,9 @@ if(evt_running) { printk(KERN_INFO "Killing I2O block threads..."); - i = kill_proc(evt_pid, SIGTERM, 1); + i = kill_proc(evt_pid, SIGKILL, 1); if(!i) { - printk("waiting..."); + printk("waiting...\n"); } /* Be sure it died */ wait_for_completion(&i2ob_thread_dead); diff -urN linux-2.6.4-rc2/drivers/message/i2o/i2o_core.c linux-2.6.4-rc3/drivers/message/i2o/i2o_core.c --- linux-2.6.4-rc2/drivers/message/i2o/i2o_core.c 2004-02-17 19:58:33.000000000 -0800 +++ linux-2.6.4-rc3/drivers/message/i2o/i2o_core.c 2004-03-09 16:36:26.000000000 -0800 @@ -13,15 +13,16 @@ * A lot of the I2O message side code from this is taken from the * Red Creek RCPCI45 adapter driver by Red Creek Communications * - * Fixes by: - * Philipp Rumpf - * Juha Sievänen - * Auvo Häkkinen - * Deepak Saxena - * Boji T Kannanthanam - * - * Ported to Linux 2.5 by - * Alan Cox + * Fixes/additions: + * Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen + * Deepak Saxena + * Boji T Kannanthanam + * Alan Cox : + * Ported to Linux 2.5. + * Markus Lidel : + * Minor fixes for 2.6. * */ @@ -502,6 +503,7 @@ c->unit = i; c->page_frame = NULL; c->hrt = NULL; + c->hrt_len = 0; c->lct = NULL; c->status_block = NULL; sprintf(c->name, "i2o/iop%d", i); @@ -564,7 +566,7 @@ * If this is shutdown time, the thread's already been killed */ if(c->lct_running) { - stat = kill_proc(c->lct_pid, SIGTERM, 1); + stat = kill_proc(c->lct_pid, SIGKILL, 1); if(!stat) { int count = 10 * 100; while(c->lct_running && --count) { @@ -1861,31 +1863,36 @@ { u32 msg[6]; int ret, size = sizeof(i2o_hrt); + int loops = 3; /* we only try 3 times to get the HRT, this should be + more then enough. Worst case should be 2 times.*/ /* First read just the header to figure out the real size */ do { + /* first we allocate the memory for the HRT */ if (c->hrt == NULL) { c->hrt=pci_alloc_consistent(c->pdev, size, &c->hrt_phys); if (c->hrt == NULL) { printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); return -ENOMEM; } + c->hrt_len = size; } msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; msg[3]= 0; - msg[4]= (0xD0000000 | size); /* Simple transaction */ + msg[4]= (0xD0000000 | c->hrt_len); /* Simple transaction */ msg[5]= c->hrt_phys; /* Dump it here */ - ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL, c->hrt_phys, 0, size, 0); + ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL, c->hrt_phys, 0, c->hrt_len, 0); if(ret == -ETIMEDOUT) { /* The HRT block we used is in limbo somewhere. When the iop wakes up we will recover it */ c->hrt = NULL; + c->hrt_len = 0; return ret; } @@ -1896,13 +1903,20 @@ return ret; } - if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) { - int new_size = c->hrt->num_entries * c->hrt->entry_len << 2; - pci_free_consistent(c->pdev, size, c->hrt, c->hrt_phys); - size = new_size; + if (c->hrt->num_entries * c->hrt->entry_len << 2 > c->hrt_len) { + size = c->hrt->num_entries * c->hrt->entry_len << 2; + pci_free_consistent(c->pdev, c->hrt_len, c->hrt, c->hrt_phys); + c->hrt_len = 0; c->hrt = NULL; } - } while (c->hrt == NULL); + loops --; + } while (c->hrt == NULL && loops > 0); + + if(c->hrt == NULL) + { + printk(KERN_ERR "%s: Unable to get HRT after three tries, giving up\n", c->name); + return -1; + } i2o_parse_hrt(c); // just for debugging @@ -3628,8 +3642,6 @@ return 0; } -static int dpt; - /** * i2o_pci_scan - Scan the pci bus for controllers * @@ -3654,14 +3666,7 @@ { if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) continue; - if(dev->vendor == PCI_VENDOR_ID_DPT && !dpt) - { - if(dev->device == 0xA501 || dev->device == 0xA511) - { - printk(KERN_INFO "i2o: Skipping Adaptec/DPT I2O raid with preferred native driver.\n"); - continue; - } - } + if((dev->class&0xFF)>1) { printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n"); @@ -3735,22 +3740,19 @@ */ if(evt_running) { printk("Terminating i2o threads..."); - stat = kill_proc(evt_pid, SIGTERM, 1); + stat = kill_proc(evt_pid, SIGKILL, 1); if(!stat) { - printk("waiting..."); + printk("waiting...\n"); wait_for_completion(&evt_dead); } printk("done.\n"); } i2o_remove_handler(&i2o_core_handler); - unregister_reboot_notifier(&i2o_reboot_notifier); } module_init(i2o_core_init); module_exit(i2o_core_exit); -MODULE_PARM(dpt, "i"); -MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o"); MODULE_PARM(verbose, "i"); MODULE_PARM_DESC(verbose, "Verbose diagnostics"); diff -urN linux-2.6.4-rc2/drivers/message/i2o/i2o_scsi.c linux-2.6.4-rc3/drivers/message/i2o/i2o_scsi.c --- linux-2.6.4-rc2/drivers/message/i2o/i2o_scsi.c 2004-02-17 19:59:07.000000000 -0800 +++ linux-2.6.4-rc3/drivers/message/i2o/i2o_scsi.c 2004-03-09 16:36:26.000000000 -0800 @@ -29,12 +29,15 @@ * In general the firmware wants to help. Where its help isn't performance * useful we just ignore the aid. Its not worth the code in truth. * - * Fixes: - * Steve Ralston : Scatter gather now works + * Fixes/additions: + * Steve Ralston: + * Scatter gather now works + * Markus Lidel : + * Minor fixes for 2.6. * - * To Do - * 64bit cleanups - * Fix the resource management problems. + * To Do: + * 64bit cleanups + * Fix the resource management problems. */ @@ -66,7 +69,13 @@ #define VERSION_STRING "Version 0.1.2" -#define dprintk(x) +//#define DRIVERDEBUG + +#ifdef DRIVERDEBUG +#define dprintk(s, args...) printk(s, ## args) +#else +#define dprintk(s, args...) +#endif #define I2O_SCSI_CAN_QUEUE 4 #define MAXHOSTS 32 @@ -252,15 +261,15 @@ as=(u8)le32_to_cpu(m[4]>>8); st=(u8)le32_to_cpu(m[4]>>24); - dprintk(("i2o got a scsi reply %08X: ", m[0])); - dprintk(("m[2]=%08X: ", m[2])); - dprintk(("m[4]=%08X\n", m[4])); + dprintk(KERN_INFO "i2o got a scsi reply %08X: ", m[0]); + dprintk(KERN_INFO "m[2]=%08X: ", m[2]); + dprintk(KERN_INFO "m[4]=%08X\n", m[4]); if(m[2]&0x80000000) { if(m[2]&0x40000000) { - dprintk(("Event.\n")); + dprintk(KERN_INFO "Event.\n"); lun_done=1; return; } @@ -280,12 +289,12 @@ if(current_command==NULL) { if(st) - dprintk(("SCSI abort: %08X", m[4])); - dprintk(("SCSI abort completed.\n")); + dprintk(KERN_WARNING "SCSI abort: %08X", m[4]); + dprintk(KERN_INFO "SCSI abort completed.\n"); return; } - dprintk(("Completed %ld\n", current_command->serial_number)); + dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number); atomic_dec(&queue_depth); @@ -308,7 +317,7 @@ { /* An error has occurred */ - dprintk((KERN_DEBUG "SCSI error %08X", m[4])); + dprintk(KERN_WARNING "SCSI error %08X", m[4]); if (as == 0x0E) /* SCSI Reset */ @@ -368,7 +377,7 @@ *lun=reply[1]; - dprintk(("SCSI (%d,%d)\n", *target, *lun)); + dprintk(KERN_INFO "SCSI (%d,%d)\n", *target, *lun); return 0; } @@ -401,8 +410,8 @@ for(unit=c->devices;unit!=NULL;unit=unit->next) { - dprintk(("Class %03X, parent %d, want %d.\n", - unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid)); + dprintk(KERN_INFO "Class %03X, parent %d, want %d.\n", + unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid); /* Only look at scsi and fc devices */ if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) @@ -411,19 +420,19 @@ continue; /* On our bus ? */ - dprintk(("Found a disk (%d).\n", unit->lct_data.tid)); + dprintk(KERN_INFO "Found a disk (%d).\n", unit->lct_data.tid); if ((unit->lct_data.parent_tid == d->lct_data.tid) || (unit->lct_data.parent_tid == d->lct_data.parent_tid) ) { u16 limit; - dprintk(("Its ours.\n")); + dprintk(KERN_INFO "Its ours.\n"); if(i2o_find_lun(c, unit, &target, &lun)==-1) { printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); continue; } - dprintk(("Found disk %d %d.\n", target, lun)); + dprintk(KERN_INFO "Found disk %d %d.\n", target, lun); h->task[target][lun]=unit->lct_data.tid; h->tagclock[target][lun]=jiffies; @@ -439,8 +448,8 @@ shpnt->sg_tablesize = limit; - dprintk(("i2o_scsi: set scatter-gather to %d.\n", - shpnt->sg_tablesize)); + dprintk(KERN_INFO "i2o_scsi: set scatter-gather to %d.\n", + shpnt->sg_tablesize); } } } @@ -558,6 +567,9 @@ del_timer(&retry_timer); i2o_remove_handler(&i2o_scsi_handler); } + + scsi_unregister(host); + return 0; } @@ -624,7 +636,7 @@ tid = hostdata->task[SCpnt->device->id][SCpnt->device->lun]; - dprintk(("qcmd: Tid = %d\n", tid)); + dprintk(KERN_INFO "qcmd: Tid = %d\n", tid); current_command = SCpnt; /* set current command */ current_command->scsi_done = done; /* set ptr to done function */ @@ -641,7 +653,7 @@ return 0; } - dprintk(("Real scsi messages.\n")); + dprintk(KERN_INFO "Real scsi messages.\n"); /* * Obtain an I2O message. If there are none free then @@ -821,8 +833,8 @@ } else { - dprintk(("non sg for %p, %d\n", SCpnt->request_buffer, - SCpnt->request_bufflen)); + dprintk(KERN_INFO "non sg for %p, %d\n", SCpnt->request_buffer, + SCpnt->request_bufflen); i2o_raw_writel(len = SCpnt->request_bufflen, lenptr); if(len == 0) { @@ -861,7 +873,7 @@ } mb(); - dprintk(("Issued %ld\n", current_command->serial_number)); + dprintk(KERN_INFO "Issued %ld\n", current_command->serial_number); return 0; } diff -urN linux-2.6.4-rc2/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.6.4-rc3/drivers/mtd/chips/cfi_cmdset_0020.c --- linux-2.6.4-rc2/drivers/mtd/chips/cfi_cmdset_0020.c 2004-02-17 19:57:22.000000000 -0800 +++ linux-2.6.4-rc3/drivers/mtd/chips/cfi_cmdset_0020.c 2004-03-09 16:36:26.000000000 -0800 @@ -1460,3 +1460,5 @@ module_init(cfi_staa_init); module_exit(cfi_staa_exit); + +MODULE_LICENSE("GPL"); diff -urN linux-2.6.4-rc2/drivers/mtd/maps/map_funcs.c linux-2.6.4-rc3/drivers/mtd/maps/map_funcs.c --- linux-2.6.4-rc2/drivers/mtd/maps/map_funcs.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/drivers/mtd/maps/map_funcs.c 2004-03-09 16:36:26.000000000 -0800 @@ -93,3 +93,4 @@ } EXPORT_SYMBOL(simple_map_init); +MODULE_LICENSE("GPL"); diff -urN linux-2.6.4-rc2/drivers/net/e100.c linux-2.6.4-rc3/drivers/net/e100.c --- linux-2.6.4-rc2/drivers/net/e100.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/e100.c 2004-03-09 16:36:27.000000000 -0800 @@ -158,7 +158,7 @@ #define DRV_NAME "e100" -#define DRV_VERSION "3.0.15" +#define DRV_VERSION "3.0.16" #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" #define PFX DRV_NAME ": " @@ -1032,8 +1032,9 @@ nic->phy = (u32)id_hi << 16 | (u32)id_lo; DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy); - /* Handle National tx phy */ - if(nic->phy == phy_nsc_tx) { + /* Handle National tx phys */ +#define NCS_PHY_MODEL_MASK 0xFFF0FFFF + if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) { /* Disable congestion control */ cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG); cong |= NSC_CONG_TXREADY; diff -urN linux-2.6.4-rc2/drivers/net/hp100.c linux-2.6.4-rc3/drivers/net/hp100.c --- linux-2.6.4-rc2/drivers/net/hp100.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/hp100.c 2004-03-09 16:36:27.000000000 -0800 @@ -2862,7 +2862,7 @@ SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &edev->dev); - err = hp100_probe1(dev, edev->base_addr, HP100_BUS_EISA, NULL); + err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL); if (err) goto out1; diff -urN linux-2.6.4-rc2/drivers/net/irda/stir4200.c linux-2.6.4-rc3/drivers/net/irda/stir4200.c --- linux-2.6.4-rc2/drivers/net/irda/stir4200.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/irda/stir4200.c 2004-03-09 16:36:27.000000000 -0800 @@ -49,12 +49,14 @@ #include #include #include +#include #include #include #include #include #include -#include +#include +#include MODULE_AUTHOR("Stephen Hemminger "); MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200"); @@ -72,15 +74,11 @@ module_param(tx_power, int, 0); MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)"); -static int rx_interval = 5; /* milliseconds */ -module_param(rx_interval, int, 0); -MODULE_PARM_DESC(rx_interval, "Receive polling interval (ms)"); - #define STIR_IRDA_HEADER 4 #define CTRL_TIMEOUT 100 /* milliseconds */ #define TRANSMIT_TIMEOUT 200 /* milliseconds */ #define STIR_FIFO_SIZE 4096 -#define NUM_RX_URBS 2 +#define FIFO_REGS_SIZE 3 enum FirChars { FIR_CE = 0x7d, @@ -167,36 +165,26 @@ TEST_TSTOSC = 0x0F, }; -enum StirState { - STIR_STATE_RECEIVING=0, - STIR_STATE_TXREADY, -}; - struct stir_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ struct net_device_stats stats; /* network statistics */ struct qos_info qos; - unsigned long state; unsigned speed; /* Current speed */ wait_queue_head_t thr_wait; /* transmit thread wakeup */ struct completion thr_exited; pid_t thr_pid; - unsigned int tx_bulkpipe; - void *tx_data; /* wrapped data out */ - unsigned tx_len; - unsigned tx_newspeed; - unsigned tx_mtt; + struct sk_buff *tx_pending; + void *io_buf; /* transmit/receive buffer */ + __u8 *fifo_status; - unsigned int rx_intpipe; iobuff_t rx_buff; /* receive unwrap state machine */ - struct timespec rx_time; - - struct urb *rx_urbs[NUM_RX_URBS]; - void *rx_data[NUM_RX_URBS]; + struct timeval rx_time; + int receiving; + struct urb *rx_urb; }; @@ -209,9 +197,6 @@ MODULE_DEVICE_TABLE(usb, dongles); -static int fifo_txwait(struct stir_cb *stir, unsigned space); -static void stir_usb_receive(struct urb *urb, struct pt_regs *regs); - /* Send control message to set dongle register */ static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value) { @@ -239,6 +224,11 @@ MSECS_TO_JIFFIES(CTRL_TIMEOUT)); } +static inline int isfir(u32 speed) +{ + return (speed == 4000000); +} + /* * Prepare a FIR IrDA frame for transmission to the USB dongle. The * FIR transmit frame is documented in the datasheet. It consists of @@ -333,8 +323,8 @@ { iobuff_t *rx_buff = &stir->rx_buff; int len = rx_buff->len - 4; + struct sk_buff *skb, *nskb; __u32 fcs; - struct sk_buff *nskb; if (unlikely(len <= 0)) { pr_debug("%s: short frame len %d\n", @@ -345,41 +335,46 @@ return; } - fcs = rx_buff->data[len] | - rx_buff->data[len+1] << 8 | - rx_buff->data[len+2] << 16 | - rx_buff->data[len+3] << 24; - - if (unlikely(fcs != ~(crc32_le(~0, rx_buff->data, len)))) { - pr_debug("%s: crc error\n", stir->netdev->name); - irda_device_set_media_busy(stir->netdev, TRUE); + fcs = ~(crc32_le(~0, rx_buff->data, len)); + if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) { + pr_debug("crc error calc 0x%x len %d\n", fcs, len); stir->stats.rx_errors++; stir->stats.rx_crc_errors++; return; } - /* If can't get new buffer, just drop and reuse */ - nskb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (unlikely(!nskb)) - ++stir->stats.rx_dropped; - else { - struct sk_buff *oskb = rx_buff->skb; + /* if frame is short then just copy it */ + if (len < IRDA_RX_COPY_THRESHOLD) { + nskb = dev_alloc_skb(len + 1); + if (unlikely(!nskb)) { + ++stir->stats.rx_dropped; + return; + } + skb_reserve(nskb, 1); + skb = nskb; + memcpy(nskb->data, rx_buff->data, len); + } else { + nskb = dev_alloc_skb(rx_buff->truesize); + if (unlikely(!nskb)) { + ++stir->stats.rx_dropped; + return; + } skb_reserve(nskb, 1); + skb = rx_buff->skb; + rx_buff->skb = nskb; + rx_buff->head = nskb->data; + } - /* Set correct length in socket buffer */ - skb_put(oskb, len); + skb_put(skb, len); - oskb->mac.raw = oskb->data; - oskb->protocol = htons(ETH_P_IRDA); - oskb->dev = stir->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + skb->dev = stir->netdev; - netif_rx(oskb); + netif_rx(skb); - stir->stats.rx_packets++; - stir->stats.rx_bytes += len; - rx_buff->skb = nskb; - rx_buff->head = nskb->data; - } + stir->stats.rx_packets++; + stir->stats.rx_bytes += len; rx_buff->data = rx_buff->head; rx_buff->len = 0; @@ -402,7 +397,6 @@ continue; /* Now receiving frame */ rx_buff->state = BEGIN_FRAME; - rx_buff->in_frame = TRUE; /* Time to initialize receive buffer */ rx_buff->data = rx_buff->head; @@ -424,6 +418,7 @@ if (byte == FIR_EOF) continue; rx_buff->state = INSIDE_FRAME; + rx_buff->in_frame = TRUE; /* fall through */ case INSIDE_FRAME: @@ -461,7 +456,6 @@ error_recovery: ++stir->stats.rx_errors; - irda_device_set_media_busy(stir->netdev, TRUE); rx_buff->state = OUTSIDE_FRAME; rx_buff->in_frame = FALSE; } @@ -478,11 +472,6 @@ &stir->rx_buff, bytes[i]); } -static inline int isfir(u32 speed) -{ - return (speed == 4000000); -} - static inline void unwrap_chars(struct stir_cb *stir, const __u8 *bytes, int length) { @@ -519,25 +508,31 @@ int i, err; __u8 mode; - pr_debug("%s: change speed %d\n", stir->netdev->name, speed); for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) { if (speed == stir_modes[i].speed) goto found; } - ERROR("%s: invalid speed %d\n", stir->netdev->name, speed); + warn("%s: invalid speed %d", stir->netdev->name, speed); return -EINVAL; found: - pr_debug("%s: speed change from %d to %d\n", - stir->netdev->name, stir->speed, speed); + pr_debug("speed change from %d to %d\n", stir->speed, speed); + + /* sometimes needed to get chip out of stuck state */ + err = usb_reset_device(stir->usbdev); + if (err) + goto out; + + /* Reset modulator */ + err = write_reg(stir, REG_CTRL1, CTRL1_SRESET); + if (err) + goto out; - /* Make sure any previous Tx is really finished. This happens - * when we answer an incomming request ; the ua:rsp and the - * speed change are bundled together, so we need to wait until - * the packet we just submitted has been sent. Jean II */ - if (fifo_txwait(stir, 0)) - return -EIO; + /* Undocumented magic to tweak the DPLL */ + err = write_reg(stir, REG_DPLL, 0x15); + if (err) + goto out; /* Set clock */ err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk); @@ -564,33 +559,13 @@ goto out; err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1); - - out: - stir->speed = speed; - return err; -} - -static int stir_reset(struct stir_cb *stir) -{ - int err; - - /* reset state */ - stir->rx_buff.in_frame = FALSE; - stir->rx_buff.state = OUTSIDE_FRAME; - stir->speed = -1; - - /* Undocumented magic to tweak the DPLL */ - err = write_reg(stir, REG_DPLL, 0x15); if (err) goto out; /* Reset sensitivity */ err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5); - if (err) - goto out; - - err = change_speed(stir, 9600); out: + stir->speed = speed; return err; } @@ -606,48 +581,62 @@ /* the IRDA wrapping routines don't deal with non linear skb */ SKB_LINEAR_ASSERT(skb); - if (unlikely(skb->len) == 0) /* speed change only */ - stir->tx_len = 0; - else if (isfir(stir->speed)) - stir->tx_len = wrap_fir_skb(skb, stir->tx_data); - else - stir->tx_len = wrap_sir_skb(skb, stir->tx_data); - - stir->stats.tx_packets++; - stir->stats.tx_bytes += skb->len; - - stir->tx_mtt = irda_get_mtt(skb); - stir->tx_newspeed = irda_get_next_speed(skb); - - if (!test_and_set_bit(STIR_STATE_TXREADY, &stir->state)) - wake_up(&stir->thr_wait); + skb = xchg(&stir->tx_pending, skb); + wake_up(&stir->thr_wait); + + /* this should never happen unless stop/wakeup problem */ + if (unlikely(skb)) { + WARN_ON(1); + dev_kfree_skb(skb); + } - dev_kfree_skb(skb); return 0; } /* * Wait for the transmit FIFO to have space for next data + * + * If space < 0 then wait till FIFO completely drains. + * FYI: can take up to 13 seconds at 2400baud. */ -static int fifo_txwait(struct stir_cb *stir, unsigned space) +static int fifo_txwait(struct stir_cb *stir, int space) { int err; - unsigned count; - __u8 regs[3]; - unsigned long timeout = jiffies + HZ/10; + unsigned long count, status; + /* Read FIFO status and count */ for(;;) { - /* Read FIFO status and count */ - err = read_reg(stir, REG_FIFOCTL, regs, 3); - if (unlikely(err != 3)) { - WARNING("%s: FIFO register read error: %d\n", - stir->netdev->name, err); + err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, + FIFO_REGS_SIZE); + if (unlikely(err != FIFO_REGS_SIZE)) { + warn("%s: FIFO register read error: %d", + stir->netdev->name, err); + return err; } + status = stir->fifo_status[0]; + count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8 + | stir->fifo_status[1]; + + pr_debug("fifo status 0x%lx count %lu\n", status, count); + + /* error when receive/transmit fifo gets confused */ + if (status & FIFOCTL_RXERR) { + stir->stats.rx_fifo_errors++; + stir->stats.rx_errors++; + break; + } + + if (status & FIFOCTL_TXERR) { + stir->stats.tx_fifo_errors++; + stir->stats.tx_errors++; + break; + } + /* is fifo receiving already, or empty */ - if (!(regs[0] & FIFOCTL_DIR) - || (regs[0] & FIFOCTL_EMPTY)) + if (!(status & FIFOCTL_DIR) + || (status & FIFOCTL_EMPTY)) return 0; if (signal_pending(current)) @@ -658,40 +647,37 @@ || !netif_device_present(stir->netdev)) return -ESHUTDOWN; - count = (unsigned)(regs[2] & 0x1f) << 8 | regs[1]; - - pr_debug("%s: fifo status 0x%x count %u\n", - stir->netdev->name, regs[0], count); - /* only waiting for some space */ - if (space && STIR_FIFO_SIZE - 4 > space + count) + if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count) return 0; - if (time_after(jiffies, timeout)) { - WARNING("%s: transmit fifo timeout status=0x%x count=%d\n", - stir->netdev->name, regs[0], count); - ++stir->stats.tx_errors; - irda_device_set_media_busy(stir->netdev, TRUE); - return -ETIMEDOUT; - } - /* estimate transfer time for remaining chars */ wait_ms((count * 8000) / stir->speed); } + + err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR); + if (err) + return err; + err = write_reg(stir, REG_FIFOCTL, 0); + if (err) + return err; + + return 0; } /* Wait for turnaround delay before starting transmit. */ -static void turnaround_delay(long us, const struct timespec *last) +static void turnaround_delay(const struct stir_cb *stir, long us) { long ticks; - struct timespec now = CURRENT_TIME; + struct timeval now; if (us <= 0) return; - us -= (now.tv_sec - last->tv_sec) * USEC_PER_SEC; - us -= (now.tv_nsec - last->tv_nsec) / NSEC_PER_USEC; + do_gettimeofday(&now); + us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC; + us -= now.tv_usec - stir->rx_time.tv_usec; if (us < 10) return; @@ -707,77 +693,60 @@ * Start receiver by submitting a request to the receive pipe. * If nothing is available it will return after rx_interval. */ -static void receive_start(struct stir_cb *stir) +static int receive_start(struct stir_cb *stir) { - int i; - - if (test_and_set_bit(STIR_STATE_RECEIVING, &stir->state)) - return; - - if (fifo_txwait(stir, 0)) - return; - - for (i = 0; i < NUM_RX_URBS; i++) { - struct urb *urb = stir->rx_urbs[i]; - - usb_fill_int_urb(urb, stir->usbdev, stir->rx_intpipe, - stir->rx_data[i], STIR_FIFO_SIZE, - stir_usb_receive, stir, rx_interval); - - if (usb_submit_urb(urb, GFP_KERNEL)) - urb->status = -EINVAL; - } + /* reset state */ + stir->receiving = 1; - if (i == 0) { - /* if nothing got queued, then just retry next time */ - if (net_ratelimit()) - WARNING("%s: no receive buffers avaiable\n", - stir->netdev->name); + stir->rx_buff.in_frame = FALSE; + stir->rx_buff.state = OUTSIDE_FRAME; - clear_bit(STIR_STATE_RECEIVING, &stir->state); - } + stir->rx_urb->status = 0; + return usb_submit_urb(stir->rx_urb, GFP_KERNEL); } /* Stop all pending receive Urb's */ static void receive_stop(struct stir_cb *stir) { - int i; + stir->receiving = 0; + usb_unlink_urb(stir->rx_urb); - for (i = 0; i < NUM_RX_URBS; i++) { - struct urb *urb = stir->rx_urbs[i]; - usb_unlink_urb(urb); - } + if (stir->rx_buff.in_frame) + stir->stats.collisions++; } - -/* Send wrapped data (in tx_data) to device */ -static void stir_send(struct stir_cb *stir) +/* + * Wrap data in socket buffer and send it. + */ +static void stir_send(struct stir_cb *stir, struct sk_buff *skb) { - int rc; + unsigned wraplen; + int first_frame = 0; - if (test_and_clear_bit(STIR_STATE_RECEIVING, &stir->state)) { + /* if receiving, need to turnaround */ + if (stir->receiving) { receive_stop(stir); - - turnaround_delay(stir->tx_mtt, &stir->rx_time); - - if (stir->rx_buff.in_frame) - ++stir->stats.collisions; + turnaround_delay(stir, irda_get_mtt(skb)); + first_frame = 1; } - else if (fifo_txwait(stir, stir->tx_len)) - return; /* shutdown or major errors */ + if (isfir(stir->speed)) + wraplen = wrap_fir_skb(skb, stir->io_buf); + else + wraplen = wrap_sir_skb(skb, stir->io_buf); + + /* check for space available in fifo */ + if (!first_frame) + fifo_txwait(stir, wraplen); + + stir->stats.tx_packets++; + stir->stats.tx_bytes += skb->len; stir->netdev->trans_start = jiffies; + pr_debug("send %d (%d)\n", skb->len, wraplen); - pr_debug("%s: send %d\n", stir->netdev->name, stir->tx_len); - rc = usb_bulk_msg(stir->usbdev, - stir->tx_bulkpipe, - stir->tx_data, stir->tx_len, - NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT)); - - if (unlikely(rc)) { - WARNING("%s: usb bulk message failed %d\n", - stir->netdev->name, rc); + if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1), + stir->io_buf, wraplen, + NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT))) stir->stats.tx_errors++; - } } /* @@ -787,7 +756,7 @@ { struct stir_cb *stir = arg; struct net_device *dev = stir->netdev; - DECLARE_WAITQUEUE(wait, current); + struct sk_buff *skb; daemonize("%s", dev->name); allow_signal(SIGTERM); @@ -796,44 +765,58 @@ && netif_device_present(dev) && !signal_pending(current)) { - /* make swsusp happy with our thread */ + /* if suspending, then power off and wait */ if (current->flags & PF_FREEZE) { - receive_stop(stir); + if (stir->receiving) + receive_stop(stir); + else + fifo_txwait(stir, -1); write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); refrigerator(PF_IOTHREAD); - stir_reset(stir); + if (change_speed(stir, stir->speed)) + break; } /* if something to send? */ - if (test_and_clear_bit(STIR_STATE_TXREADY, &stir->state)) { - unsigned new_speed = stir->tx_newspeed; - - /* Note that we may both send a packet and - * change speed in some cases. Jean II */ - - if (stir->tx_len != 0) - stir_send(stir); - - if (stir->speed != new_speed) - change_speed(stir, new_speed); - - netif_wake_queue(stir->netdev); + skb = xchg(&stir->tx_pending, NULL); + if (skb) { + unsigned new_speed = irda_get_next_speed(skb); + netif_wake_queue(dev); + + if (skb->len > 0) + stir_send(stir, skb); + dev_kfree_skb(skb); + + if (stir->speed != new_speed) { + if (fifo_txwait(stir, -1) || + change_speed(stir, new_speed)) + break; + } continue; } - if (irda_device_txqueue_empty(dev)) - receive_start(stir); + /* nothing to send? start receiving */ + if (!stir->receiving + && irda_device_txqueue_empty(dev)) { + /* Wait otherwise chip gets confused. */ + if (fifo_txwait(stir, -1)) + break; + + if (unlikely(receive_start(stir))) { + if (net_ratelimit()) + info("%s: receive usb submit failed", + stir->netdev->name); + stir->receiving = 0; + wait_ms(10); + continue; + } + } - set_task_state(current, TASK_INTERRUPTIBLE); - add_wait_queue(&stir->thr_wait, &wait); - if (test_bit(STIR_STATE_TXREADY, &stir->state)) - __set_task_state(current, TASK_RUNNING); - else - schedule_timeout(HZ/10); - remove_wait_queue(&stir->thr_wait, &wait); + /* sleep if nothing to send */ + wait_event_interruptible(stir->thr_wait, stir->tx_pending); } complete_and_exit (&stir->thr_exited, 0); @@ -841,48 +824,34 @@ /* - * Receive wrapped data into rx_data buffer. - * This chip doesn't block until data is available, we just have - * to read the FIFO perodically (ugh). + * USB bulk receive completion callback. + * Wakes up every ms (usb round trip) with wrapped + * data. */ -static void stir_usb_receive(struct urb *urb, struct pt_regs *regs) +static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs) { struct stir_cb *stir = urb->context; int err; + /* in process of stopping, just drop data */ if (!netif_running(stir->netdev)) return; - switch (urb->status) { - case 0: - if(urb->actual_length > 0) { - pr_debug("%s: receive %d\n", - stir->netdev->name, urb->actual_length); - unwrap_chars(stir, urb->transfer_buffer, - urb->actual_length); - - stir->netdev->last_rx = jiffies; - stir->rx_time = CURRENT_TIME; - } - break; - - case -ECONNRESET: /* killed but pending */ - case -ENOENT: /* killed but not in use */ - case -ESHUTDOWN: - /* These are normal errors when URB is cancelled */ - stir->rx_buff.in_frame = FALSE; - stir->rx_buff.state = OUTSIDE_FRAME; + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) return; - default: - WARNING("%s: received status %d\n", stir->netdev->name, - urb->status); - stir->stats.rx_errors++; - urb->status = 0; + if (urb->actual_length > 0) { + pr_debug("receive %d\n", urb->actual_length); + unwrap_chars(stir, urb->transfer_buffer, + urb->actual_length); + + stir->netdev->last_rx = jiffies; + do_gettimeofday(&stir->rx_time); } /* kernel thread is stopping receiver don't resubmit */ - if (!test_bit(STIR_STATE_RECEIVING, &stir->state)) + if (!stir->receiving) return; /* resubmit existing urb */ @@ -890,14 +859,13 @@ /* in case of error, the kernel thread will restart us */ if (err) { - WARNING("%s: usb receive submit error: %d\n", + warn("%s: usb receive submit error: %d", stir->netdev->name, err); - urb->status = -ENOENT; + stir->receiving = 0; wake_up(&stir->thr_wait); } } - /* * Function stir_net_open (dev) * @@ -906,50 +874,50 @@ static int stir_net_open(struct net_device *netdev) { struct stir_cb *stir = netdev->priv; - int i, err; - char hwname[16]; + int err; + char hwname[16]; - err = stir_reset(stir); + err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1)); + if (err) + goto err_out1; + err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2)); if (err) goto err_out1; - err = -ENOMEM; - - /* Note: Max SIR frame possible is 4273 */ - stir->tx_data = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); - if (!stir->tx_data) { - ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__); + err = change_speed(stir, 9600); + if (err) goto err_out1; - } + + err = -ENOMEM; /* Initialize for SIR/FIR to copy data directly into skb. */ + stir->receiving = 0; stir->rx_buff.truesize = IRDA_SKB_MAX_MTU; stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!stir->rx_buff.skb) { - ERROR("%s(), dev_alloc_skb() failed for rxbuf!\n", - __FUNCTION__); - goto err_out2; - } + if (!stir->rx_buff.skb) + goto err_out1; + skb_reserve(stir->rx_buff.skb, 1); stir->rx_buff.head = stir->rx_buff.skb->data; - stir->rx_time = CURRENT_TIME; + do_gettimeofday(&stir->rx_time); - /* Allocate N receive buffer's and urbs */ - for (i = 0; i < NUM_RX_URBS; i++) { - stir->rx_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!stir->rx_urbs[i]){ - ERROR("%s(), usb_alloc_urb failed\n", __FUNCTION__); - goto err_out3; - } + stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!stir->rx_urb) + goto err_out2; - stir->rx_data[i] = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); - if (!stir->rx_data) { - usb_free_urb(stir->rx_urbs[i]); - ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__); - goto err_out3; - } - } + stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); + if (!stir->io_buf) + goto err_out3; + usb_fill_bulk_urb(stir->rx_urb, stir->usbdev, + usb_rcvbulkpipe(stir->usbdev, 2), + stir->io_buf, STIR_FIFO_SIZE, + stir_rcv_irq, stir); + + stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL); + if (!stir->fifo_status) + goto err_out4; + /* * Now that everything should be initialized properly, * Open new IrLAP layer instance to take care of us... @@ -958,8 +926,8 @@ sprintf(hwname, "usb#%d", stir->usbdev->devnum); stir->irlap = irlap_open(netdev, &stir->qos, hwname); if (!stir->irlap) { - ERROR("%s(): irlap_open failed\n", __FUNCTION__); - goto err_out3; + err("irlap_open failed"); + goto err_out5; } /** Start kernel thread for transmit. */ @@ -967,25 +935,24 @@ CLONE_FS|CLONE_FILES); if (stir->thr_pid < 0) { err = stir->thr_pid; - WARNING("%s: unable to start kernel thread\n", - stir->netdev->name); - goto err_out4; + err("unable to start kernel thread"); + goto err_out6; } netif_start_queue(netdev); return 0; - err_out4: + err_out6: irlap_close(stir->irlap); + err_out5: + kfree(stir->fifo_status); + err_out4: + kfree(stir->io_buf); err_out3: - while(--i >= 0) { - usb_free_urb(stir->rx_urbs[i]); - kfree(stir->rx_data[i]); - } - kfree_skb(stir->rx_buff.skb); + usb_free_urb(stir->rx_urb); err_out2: - kfree(stir->tx_data); + kfree_skb(stir->rx_buff.skb); err_out1: return err; } @@ -999,7 +966,6 @@ static int stir_net_close(struct net_device *netdev) { struct stir_cb *stir = netdev->priv; - int i; /* Stop transmit processing */ netif_stop_queue(netdev); @@ -1007,15 +973,13 @@ /* Kill transmit thread */ kill_proc(stir->thr_pid, SIGTERM, 1); wait_for_completion(&stir->thr_exited); - kfree(stir->tx_data); - - clear_bit(STIR_STATE_RECEIVING, &stir->state); - receive_stop(stir); + kfree(stir->fifo_status); - for (i = 0; i < NUM_RX_URBS; i++) { - usb_free_urb(stir->rx_urbs[i]); - kfree(stir->rx_data[i]); - } + /* Mop up receive urb's */ + usb_unlink_urb(stir->rx_urb); + + kfree(stir->io_buf); + usb_free_urb(stir->rx_urb); kfree_skb(stir->rx_buff.skb); /* Stop and remove instance of IrLAP */ @@ -1057,7 +1021,7 @@ case SIOCGRECEIVING: /* Only approximately true */ - irq->ifr_receiving = test_bit(STIR_STATE_RECEIVING, &stir->state); + irq->ifr_receiving = stir->receiving; break; default: @@ -1077,53 +1041,6 @@ } /* - * Parse the various endpoints and find the one we need. - * - * The endpoint are the pipes used to communicate with the USB device. - * The spec defines 2 endpoints of type bulk transfer, one in, and one out. - * These are used to pass frames back and forth with the dongle. - */ -static int stir_setup_usb(struct stir_cb *stir, struct usb_interface *intf) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - const struct usb_host_interface *interface - = &intf->altsetting[intf->act_altsetting]; - const struct usb_endpoint_descriptor *ep_in = NULL; - const struct usb_endpoint_descriptor *ep_out = NULL; - int i; - - if (interface->desc.bNumEndpoints != 2) { - WARNING("%s: expected two endpoints\n", __FUNCTION__); - return -ENODEV; - } - - for(i = 0; i < interface->desc.bNumEndpoints; i++) { - const struct usb_endpoint_descriptor *ep - = &interface->endpoint[i].desc; - - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) { - /* We need to find an IN and an OUT */ - if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) - ep_in = ep; - else - ep_out = ep; - } else - WARNING("%s: unknown endpoint type 0x%x\n", - __FUNCTION__, ep->bmAttributes); - } - - if (!ep_in || !ep_out) - return -EIO; - - stir->tx_bulkpipe = usb_sndbulkpipe(usbdev, - ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - stir->rx_intpipe = usb_rcvintpipe(usbdev, - ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - return 0; -} - -/* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in * this case start handling it. @@ -1149,9 +1066,9 @@ stir->netdev = net; stir->usbdev = dev; - ret = stir_setup_usb(stir, intf); + ret = usb_reset_configuration(dev); if (ret != 0) { - ERROR("%s(), Bogus endpoints...\n", __FUNCTION__); + err("usb reset configuration failed"); goto err_out2; } @@ -1180,10 +1097,6 @@ net->get_stats = stir_net_get_stats; net->do_ioctl = stir_net_ioctl; - ret = stir_reset(stir); - if (ret) - goto err_out2; - ret = register_netdev(net); if (ret != 0) goto err_out2; @@ -1206,23 +1119,14 @@ static void stir_disconnect(struct usb_interface *intf) { struct stir_cb *stir = usb_get_intfdata(intf); - struct net_device *net; - usb_set_intfdata(intf, NULL); if (!stir) return; - /* Stop transmitter */ - net = stir->netdev; - netif_device_detach(net); - - /* Remove netdevice */ - unregister_netdev(net); - - /* No longer attached to USB bus */ - stir->usbdev = NULL; + unregister_netdev(stir->netdev); + free_netdev(stir->netdev); - free_netdev(net); + usb_set_intfdata(intf, NULL); } diff -urN linux-2.6.4-rc2/drivers/net/ns83820.c linux-2.6.4-rc3/drivers/net/ns83820.c --- linux-2.6.4-rc2/drivers/net/ns83820.c 2004-02-17 19:59:44.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/ns83820.c 2004-03-09 16:36:27.000000000 -0800 @@ -598,7 +598,7 @@ } static void FASTCALL(rx_refill_atomic(struct net_device *ndev)); -static void rx_refill_atomic(struct net_device *ndev) +static void fastcall rx_refill_atomic(struct net_device *ndev) { rx_refill(ndev, GFP_ATOMIC); } @@ -620,7 +620,7 @@ } static void FASTCALL(phy_intr(struct net_device *ndev)); -static void phy_intr(struct net_device *ndev) +static void fastcall phy_intr(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; @@ -807,7 +807,7 @@ } static void FASTCALL(ns83820_rx_kick(struct net_device *ndev)); -static void ns83820_rx_kick(struct net_device *ndev) +static void fastcall ns83820_rx_kick(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { @@ -829,7 +829,7 @@ * */ static void FASTCALL(rx_irq(struct net_device *ndev)); -static void rx_irq(struct net_device *ndev) +static void fastcall rx_irq(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); struct rx_info *info = &dev->rx_info; diff -urN linux-2.6.4-rc2/drivers/net/pcnet32.c linux-2.6.4-rc3/drivers/net/pcnet32.c --- linux-2.6.4-rc2/drivers/net/pcnet32.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/pcnet32.c 2004-03-09 16:36:27.000000000 -0800 @@ -1452,11 +1452,12 @@ status = 0x8300; entry = (lp->cur_tx - lp->dirty_tx) & TX_RING_MOD_MASK; if ((lp->ltint) && - ((entry == TX_RING_SIZE/2) || + ((entry == TX_RING_SIZE/3) || + (entry == (TX_RING_SIZE*2)/3) || (entry >= TX_RING_SIZE-2))) { /* Enable Successful-TxDone interrupt if we have - * 1/2 of, or nearly all of, our ring buffer Tx'd + * 1/3, 2/3 or nearly all of, our ring buffer Tx'd * but not yet cleaned up. Thus, most of the time, * we will not enable Successful-TxDone interrupts. */ diff -urN linux-2.6.4-rc2/drivers/net/tg3.c linux-2.6.4-rc3/drivers/net/tg3.c --- linux-2.6.4-rc2/drivers/net/tg3.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/tg3.c 2004-03-09 16:36:27.000000000 -0800 @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "2.8" -#define DRV_MODULE_RELDATE "February 23, 2004" +#define DRV_MODULE_VERSION "2.9" +#define DRV_MODULE_RELDATE "March 8, 2004" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -215,6 +215,21 @@ } } +static void _tw32_flush(struct tg3 *tp, u32 off, u32 val) +{ + if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { + unsigned long flags; + + spin_lock_irqsave(&tp->indirect_lock, flags); + pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); + spin_unlock_irqrestore(&tp->indirect_lock, flags); + } else { + unsigned long dest = tp->regs + off; + writel(val, dest); + readl(dest); /* always flush PCI write */ + } +} static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val) { @@ -239,6 +254,7 @@ #define tw32_tx_mbox(reg, val) _tw32_tx_mbox(tp, reg, val) #define tw32(reg,val) tg3_write_indirect_reg32(tp,(reg),(val)) +#define tw32_f(reg,val) _tw32_flush(tp,(reg),(val)) #define tw16(reg,val) writew(((val) & 0xffff), tp->regs + (reg)) #define tw8(reg,val) writeb(((val) & 0xff), tp->regs + (reg)) #define tr32(reg) readl(tp->regs + (reg)) @@ -325,18 +341,15 @@ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { - tw32(TG3PCI_CLOCK_CTRL, + tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK)); - tr32(TG3PCI_CLOCK_CTRL); udelay(40); - tw32(TG3PCI_CLOCK_CTRL, + tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_ALTCLK)); - tr32(TG3PCI_CLOCK_CTRL); udelay(40); } - tw32(TG3PCI_CLOCK_CTRL, clock_ctrl); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl); udelay(40); } @@ -348,9 +361,8 @@ int loops, ret; if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, + tw32_f(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); - tr32(MAC_MI_MODE); udelay(40); } @@ -362,8 +374,7 @@ MI_COM_REG_ADDR_MASK); frame_val |= (MI_COM_CMD_READ | MI_COM_START); - tw32(MAC_MI_COM, frame_val); - tr32(MAC_MI_COM); + tw32_f(MAC_MI_COM, frame_val); loops = PHY_BUSY_LOOPS; while (loops-- > 0) { @@ -384,8 +395,7 @@ } if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); } @@ -398,9 +408,8 @@ int loops, ret; if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, + tw32_f(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); - tr32(MAC_MI_MODE); udelay(40); } @@ -411,8 +420,7 @@ frame_val |= (val & MI_COM_DATA_MASK); frame_val |= (MI_COM_CMD_WRITE | MI_COM_START); - tw32(MAC_MI_COM, frame_val); - tr32(MAC_MI_COM); + tw32_f(MAC_MI_COM, frame_val); loops = PHY_BUSY_LOOPS; while (loops-- > 0) { @@ -430,8 +438,7 @@ ret = 0; if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); } @@ -714,45 +721,41 @@ (tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); } else { if (tp_peer != tp && (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) return; - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); } } else { @@ -762,27 +765,24 @@ (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) return; - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE1)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); } } } -static int tg3_setup_phy(struct tg3 *); +static int tg3_setup_phy(struct tg3 *, int); static int tg3_set_power_state(struct tg3 *tp, int state) { @@ -808,8 +808,7 @@ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - tr32(GRC_LOCAL_CTRL); + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); return 0; @@ -850,7 +849,7 @@ tp->link_config.speed = SPEED_10; tp->link_config.duplex = DUPLEX_HALF; tp->link_config.autoneg = AUTONEG_ENABLE; - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); @@ -876,12 +875,10 @@ (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))) mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; - tw32(MAC_MODE, mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, mac_mode); udelay(100); - tw32(MAC_RX_MODE, RX_MODE_ENABLE); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, RX_MODE_ENABLE); udelay(10); } @@ -894,10 +891,9 @@ base_val |= (CLOCK_CTRL_RXCLK_DISABLE | CLOCK_CTRL_TXCLK_DISABLE); - tw32(TG3PCI_CLOCK_CTRL, base_val | + tw32_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); - tr32(TG3PCI_CLOCK_CTRL); udelay(40); } else { u32 newbits1, newbits2; @@ -916,12 +912,10 @@ newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE; } - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1); udelay(40); - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2); udelay(40); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { @@ -936,8 +930,8 @@ newbits3 = CLOCK_CTRL_44MHZ_CORE; } - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits3); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, + tp->pci_clock_ctrl | newbits3); udelay(40); } } @@ -1051,7 +1045,7 @@ }; } -static int tg3_phy_copper_begin(struct tg3 *tp, int wait_for_link) +static int tg3_phy_copper_begin(struct tg3 *tp) { u32 new_adv; int i; @@ -1169,7 +1163,7 @@ tg3_readphy(tp, MII_BMCR, &orig_bmcr); if (bmcr != orig_bmcr) { tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK); - for (i = 0; i < 15000; i++) { + for (i = 0; i < 1500; i++) { u32 tmp; udelay(10); @@ -1188,27 +1182,6 @@ BMCR_ANENABLE | BMCR_ANRESTART); } - if (wait_for_link) { - tp->link_config.active_speed = SPEED_INVALID; - tp->link_config.active_duplex = DUPLEX_INVALID; - for (i = 0; i < 300000; i++) { - u32 tmp; - - udelay(10); - tg3_readphy(tp, MII_BMSR, &tmp); - tg3_readphy(tp, MII_BMSR, &tmp); - if (!(tmp & BMSR_LSTATUS)) - continue; - - tg3_readphy(tp, MII_TG3_AUX_STAT, &tmp); - tg3_aux_stat_to_speed_duplex(tp, tmp, - &tp->link_config.active_speed, - &tp->link_config.active_duplex); - } - if (tp->link_config.active_speed == SPEED_INVALID) - return -EINVAL; - } - return 0; } @@ -1239,7 +1212,7 @@ return err; } -static int tg3_setup_copper_phy(struct tg3 *tp) +static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) { int current_link_up; u32 bmsr, dummy; @@ -1249,17 +1222,15 @@ tw32(MAC_EVENT, 0); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED | MAC_STATUS_MI_COMPLETION | MAC_STATUS_LNKSTATE_CHANGED)); - tr32(MAC_STATUS); udelay(40); tp->mi_mode = MAC_MI_MODE_BASE; - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); @@ -1274,8 +1245,10 @@ tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); if (!(bmsr & BMSR_LSTATUS)) - tg3_phy_reset(tp, 1); + force_reset = 1; } + if (force_reset) + tg3_phy_reset(tp, 1); if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); @@ -1411,7 +1384,7 @@ if (current_link_up == 0) { u32 tmp; - tg3_phy_copper_begin(tp, 0); + tg3_phy_copper_begin(tp); tg3_readphy(tp, MII_BMSR, &tmp); tg3_readphy(tp, MII_BMSR, &tmp); @@ -1451,24 +1424,19 @@ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 && tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) { tp->mi_mode |= MAC_MI_MODE_AUTO_POLL; - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); } - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - if (tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES)) { + if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES)) { /* Polled via timer. */ - tw32(MAC_EVENT, 0); + tw32_f(MAC_EVENT, 0); } else { - tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); } - tr32(MAC_EVENT); udelay(40); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && @@ -1477,10 +1445,9 @@ ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) || (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) { udelay(120); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); udelay(40); tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, @@ -1642,8 +1609,7 @@ ap->txconfig = 0; tw32(MAC_TX_AUTO_NEG, 0); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ret = ANEG_TIMER_ENAB; @@ -1668,8 +1634,7 @@ ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1); tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ap->state = ANEG_STATE_ABILITY_DETECT; @@ -1685,8 +1650,7 @@ ap->txconfig |= ANEG_CFG_ACK; tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ap->state = ANEG_STATE_ACK_DETECT; @@ -1772,8 +1736,7 @@ case ANEG_STATE_IDLE_DETECT_INIT: ap->link_time = ap->cur_time; tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ap->state = ANEG_STATE_IDLE_DETECT; @@ -1814,7 +1777,7 @@ return ret; } -static int tg3_setup_fiber_phy(struct tg3 *tp) +static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) { u32 orig_pause_cfg; u16 orig_active_speed; @@ -1830,8 +1793,7 @@ tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); /* Reset when initting first time or we have a link. */ @@ -1879,10 +1841,9 @@ /* Enable link change interrupt unless serdes polling. */ if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES)) - tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); else - tw32(MAC_EVENT, 0); - tr32(MAC_EVENT); + tw32_f(MAC_EVENT, 0); udelay(40); current_link_up = 0; @@ -1900,12 +1861,10 @@ tw32(MAC_TX_AUTO_NEG, 0); tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); udelay(40); - tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); udelay(40); aninfo.state = ANEG_STATE_UNKNOWN; @@ -1921,8 +1880,7 @@ } tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); if (status == ANEG_DONE && @@ -1946,10 +1904,9 @@ } for (i = 0; i < 60; i++) { udelay(20); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); udelay(40); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | @@ -1967,8 +1924,7 @@ } tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); tp->hw_status->status = @@ -1977,10 +1933,9 @@ for (i = 0; i < 100; i++) { udelay(20); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); udelay(40); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | @@ -2016,12 +1971,10 @@ } if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { - tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); udelay(40); if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); } } @@ -2029,14 +1982,14 @@ return 0; } -static int tg3_setup_phy(struct tg3 *tp) +static int tg3_setup_phy(struct tg3 *tp, int force_reset) { int err; if (tp->phy_id == PHY_ID_SERDES) { - err = tg3_setup_fiber_phy(tp); + err = tg3_setup_fiber_phy(tp, force_reset); } else { - err = tg3_setup_copper_phy(tp); + err = tg3_setup_copper_phy(tp, force_reset); } if (tp->link_config.active_speed == SPEED_1000 && @@ -2399,7 +2352,7 @@ if (sblk->status & SD_STATUS_LINK_CHG) { sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } } @@ -3349,8 +3302,7 @@ val = tr32(ofs); val &= ~enable_bit; - tw32(ofs, val); - tr32(ofs); + tw32_f(ofs, val); for (i = 0; i < MAX_WAIT_CNT; i++) { udelay(100); @@ -3377,8 +3329,7 @@ tg3_disable_ints(tp); tp->rx_mode &= ~RX_MODE_ENABLE; - tw32(MAC_RX_MODE, tp->rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); err = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE); @@ -3399,13 +3350,11 @@ goto out; tp->mac_mode &= ~MAC_MODE_TDE_ENABLE; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); tp->tx_mode &= ~TX_MODE_ENABLE; - tw32(MAC_TX_MODE, tp->tx_mode); - tr32(MAC_TX_MODE); + tw32_f(MAC_TX_MODE, tp->tx_mode); for (i = 0; i < MAX_WAIT_CNT; i++) { udelay(100); @@ -3731,8 +3680,7 @@ } tw32(offset + CPU_STATE, 0xffffffff); - tw32(offset + CPU_MODE, CPU_MODE_HALT); - tr32(offset + CPU_MODE); + tw32_f(offset + CPU_MODE, CPU_MODE_HALT); udelay(10); } else { for (i = 0; i < 10000; i++) { @@ -3855,20 +3803,14 @@ /* Now startup only the RX cpu. */ tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); - tw32(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); + tw32_f(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); - /* Flush posted writes. */ - tr32(RX_CPU_BASE + CPU_PC); for (i = 0; i < 5; i++) { if (tr32(RX_CPU_BASE + CPU_PC) == TG3_FW_TEXT_ADDR) break; tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT); - tw32(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); - - /* Flush posted writes. */ - tr32(RX_CPU_BASE + CPU_PC); - + tw32_f(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); udelay(1000); } if (i >= 5) { @@ -3879,10 +3821,7 @@ return -ENODEV; } tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); - tw32(RX_CPU_BASE + CPU_MODE, 0x00000000); - - /* Flush posted writes. */ - tr32(RX_CPU_BASE + CPU_MODE); + tw32_f(RX_CPU_BASE + CPU_MODE, 0x00000000); return 0; } @@ -4440,20 +4379,14 @@ /* Now startup the cpu. */ tw32(cpu_base + CPU_STATE, 0xffffffff); - tw32(cpu_base + CPU_PC, info.text_base); + tw32_f(cpu_base + CPU_PC, info.text_base); - /* Flush posted writes. */ - tr32(cpu_base + CPU_PC); for (i = 0; i < 5; i++) { if (tr32(cpu_base + CPU_PC) == info.text_base) break; tw32(cpu_base + CPU_STATE, 0xffffffff); tw32(cpu_base + CPU_MODE, CPU_MODE_HALT); - tw32(cpu_base + CPU_PC, info.text_base); - - /* Flush posted writes. */ - tr32(cpu_base + CPU_PC); - + tw32_f(cpu_base + CPU_PC, info.text_base); udelay(1000); } if (i >= 5) { @@ -4464,11 +4397,7 @@ return -ENODEV; } tw32(cpu_base + CPU_STATE, 0xffffffff); - tw32(cpu_base + CPU_MODE, 0x00000000); - - /* Flush posted writes. */ - tr32(cpu_base + CPU_MODE); - + tw32_f(cpu_base + CPU_MODE, 0x00000000); return 0; } @@ -4515,9 +4444,6 @@ struct tg3 *tp = dev->priv; struct sockaddr *addr = p; - if (netif_running(dev)) - return -EBUSY; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&tp->lock); @@ -4577,10 +4503,9 @@ NIC_SRAM_FIRMWARE_MBOX_MAGIC1); if (tp->phy_id == PHY_ID_SERDES) { tp->mac_mode = MAC_MODE_PORT_MODE_TBI; - tw32(MAC_MODE, tp->mac_mode); + tw32_f(MAC_MODE, tp->mac_mode); } else - tw32(MAC_MODE, 0); - tr32(MAC_MODE); + tw32_f(MAC_MODE, 0); udelay(40); /* Wait for firmware initialization to complete. */ @@ -4610,8 +4535,7 @@ * other revision. */ tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { @@ -4955,24 +4879,21 @@ tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE | MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE; - tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); udelay(40); tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - tr32(GRC_LOCAL_CTRL); + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); tr32(MAILBOX_INTERRUPT_0); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { - tw32(DMAC_MODE, DMAC_MODE_ENABLE); - tr32(DMAC_MODE); + tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); } @@ -4985,8 +4906,7 @@ (tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) != 0 && !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) val |= WDMAC_MODE_RX_ACCEL; - tw32(WDMAC_MODE, val); - tr32(WDMAC_MODE); + tw32_f(WDMAC_MODE, val); udelay(40); if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) { @@ -5004,8 +4924,7 @@ tw32(TG3PCI_X_CAPS, val); } - tw32(RDMAC_MODE, rdmac_mode); - tr32(RDMAC_MODE); + tw32_f(RDMAC_MODE, rdmac_mode); udelay(40); tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); @@ -5034,13 +4953,11 @@ #endif tp->tx_mode = TX_MODE_ENABLE; - tw32(MAC_TX_MODE, tp->tx_mode); - tr32(MAC_TX_MODE); + tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); tp->rx_mode = RX_MODE_ENABLE; - tw32(MAC_RX_MODE, tp->rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); if (tp->link_config.phy_is_low_power) { @@ -5051,19 +4968,16 @@ } tp->mi_mode = MAC_MI_MODE_BASE; - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); tw32(MAC_LED_CTRL, 0); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); if (tp->phy_id == PHY_ID_SERDES) { - tw32(MAC_RX_MODE, RX_MODE_RESET); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, RX_MODE_RESET); udelay(10); } - tw32(MAC_RX_MODE, tp->rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) @@ -5072,10 +4986,9 @@ /* Prevent chip from dropping frames when flow control * is enabled. */ - tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2); - tr32(MAC_LOW_WMARK_MAX_RX_FRAME); + tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2); - err = tg3_setup_phy(tp); + err = tg3_setup_phy(tp, 1); if (err) return err; @@ -5257,7 +5170,7 @@ phy_event = 1; if (phy_event) - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } else if (tp->tg3_flags & TG3_FLAG_POLL_SERDES) { u32 mac_stat = tr32(MAC_STATUS); int need_setup = 0; @@ -5271,15 +5184,13 @@ need_setup = 1; } if (need_setup) { - tw32(MAC_MODE, + tw32_f(MAC_MODE, (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK)); - tr32(MAC_MODE); udelay(40); - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } } @@ -5832,8 +5743,7 @@ if (rx_mode != tp->rx_mode) { tp->rx_mode = rx_mode; - tw32(MAC_RX_MODE, rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, rx_mode); udelay(10); } } @@ -5961,7 +5871,7 @@ struct tg3 *tp = dev->priv; if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || - tp->link_config.phy_is_low_power) + tp->link_config.phy_is_low_power) return -EAGAIN; spin_lock_irq(&tp->lock); @@ -5977,7 +5887,7 @@ tp->link_config.duplex = cmd->duplex; } - tg3_setup_phy(tp); + tg3_setup_phy(tp, 1); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); @@ -6302,7 +6212,7 @@ if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) return; - tw32(GRC_EEPROM_ADDR, + tw32_f(GRC_EEPROM_ADDR, (EEPROM_ADDR_FSM_RESET | (EEPROM_DEFAULT_CLOCK_PERIOD << EEPROM_ADDR_CLKPERD_SHIFT))); @@ -6312,9 +6222,8 @@ udelay(10); /* Enable seeprom accesses. */ - tw32(GRC_LOCAL_CTRL, + tw32_f(GRC_LOCAL_CTRL, tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM); - tr32(GRC_LOCAL_CTRL); udelay(100); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && @@ -6943,8 +6852,7 @@ tp->coalesce_mode |= HOSTCC_MODE_32BYTE; /* Initialize MAC MI mode, polling disabled. */ - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); /* Initialize data/descriptor byte/word swapping. */ @@ -7219,14 +7127,12 @@ if (to_device) { test_desc.cqid_sqid = (13 << 8) | 2; - tw32(RDMAC_MODE, RDMAC_MODE_ENABLE); - tr32(RDMAC_MODE); + tw32_f(RDMAC_MODE, RDMAC_MODE_ENABLE); udelay(40); } else { test_desc.cqid_sqid = (16 << 8) | 7; - tw32(WDMAC_MODE, WDMAC_MODE_ENABLE); - tr32(WDMAC_MODE); + tw32_f(WDMAC_MODE, WDMAC_MODE_ENABLE); udelay(40); } test_desc.flags = 0x00000005; diff -urN linux-2.6.4-rc2/drivers/net/tulip/interrupt.c linux-2.6.4-rc3/drivers/net/tulip/interrupt.c --- linux-2.6.4-rc2/drivers/net/tulip/interrupt.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/tulip/interrupt.c 2004-03-09 16:36:27.000000000 -0800 @@ -211,7 +211,7 @@ if (tp->rx_buffers[entry].mapping != le32_to_cpu(tp->rx_ring[entry].buffer1)) { printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in tulip_rx: %08x vs. %llx %p / %p.\n", + "do not match in tulip_rx: %08x vs. %08llx %p / %p.\n", dev->name, le32_to_cpu(tp->rx_ring[entry].buffer1), (unsigned long long)tp->rx_buffers[entry].mapping, diff -urN linux-2.6.4-rc2/drivers/net/wan/wanxl.c linux-2.6.4-rc3/drivers/net/wan/wanxl.c --- linux-2.6.4-rc2/drivers/net/wan/wanxl.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/net/wan/wanxl.c 2004-03-09 16:36:27.000000000 -0800 @@ -31,7 +31,7 @@ #include "wanxl.h" -static const char* version = "wanXL serial card driver version: 0.47"; +static const char* version = "wanXL serial card driver version: 0.48"; #define PLX_CTL_RESET 0x40000000 /* adapter reset */ @@ -73,12 +73,11 @@ u8 *plx; /* PLX PCI9060 virtual base address */ struct pci_dev *pdev; /* for pdev->slot_name */ - port_t *ports[4]; int rx_in; struct sk_buff *rx_skbs[RX_QUEUE_LENGTH]; card_status_t *status; /* shared between host and card */ dma_addr_t status_address; - port_t __ports[0]; + port_t ports[0]; /* 1 - 4 port_t structures follow */ }card_t; @@ -89,18 +88,6 @@ } -static inline struct net_device *port_to_dev(port_t* port) -{ - return port->dev; -} - - -static inline const char* port_name(port_t *port) -{ - return port_to_dev(port)->name; -} - - static inline const char* card_name(struct pci_dev *pdev) { return pdev->slot_name; @@ -165,9 +152,9 @@ dte = (value & STATUS_CABLE_DCE) ? " DCE" : " DTE"; } printk(KERN_INFO "%s: %s%s module, %s cable%s%s\n", - port_name(port), pm, dte, cable, dsr, dcd); + port->dev->name, pm, dte, cable, dsr, dcd); - hdlc_set_carrier(value & STATUS_CABLE_DCD, port_to_dev(port)); + hdlc_set_carrier(value & STATUS_CABLE_DCD, port->dev); } @@ -175,7 +162,7 @@ /* Transmit complete interrupt service */ static inline void wanxl_tx_intr(port_t *port) { - struct net_device *dev = port_to_dev(port); + struct net_device *dev = port->dev; struct net_device_stats *stats = hdlc_stats(dev); while (1) { desc_t *desc = &get_status(port)->tx_descs[port->tx_in]; @@ -210,47 +197,49 @@ static inline void wanxl_rx_intr(card_t *card) { desc_t *desc; - while(desc = &card->status->rx_descs[card->rx_in], - desc->stat != PACKET_EMPTY) { - struct sk_buff *skb = card->rx_skbs[card->rx_in]; - port_t *port = card->ports[desc->stat & PACKET_PORT_MASK]; - struct net_device *dev = port_to_dev(port); - struct net_device_stats *stats = hdlc_stats(dev); - + while (desc = &card->status->rx_descs[card->rx_in], + desc->stat != PACKET_EMPTY) { if ((desc->stat & PACKET_PORT_MASK) > card->n_ports) printk(KERN_CRIT "wanXL %s: received packet for" " nonexistent port\n", card_name(card->pdev)); - - else if (!skb) - stats->rx_dropped++; - else { - pci_unmap_single(card->pdev, desc->address, - BUFFER_LENGTH, PCI_DMA_FROMDEVICE); - skb_put(skb, desc->length); + struct sk_buff *skb = card->rx_skbs[card->rx_in]; + port_t *port = &card->ports[desc->stat & + PACKET_PORT_MASK]; + struct net_device *dev = port->dev; + struct net_device_stats *stats = hdlc_stats(dev); + + if (!skb) + stats->rx_dropped++; + else { + pci_unmap_single(card->pdev, desc->address, + BUFFER_LENGTH, + PCI_DMA_FROMDEVICE); + skb_put(skb, desc->length); #ifdef DEBUG_PKT - printk(KERN_DEBUG "%s RX(%i):", port_name(port), - skb->len); - debug_frame(skb); -#endif - stats->rx_packets++; - stats->rx_bytes += skb->len; - skb->mac.raw = skb->data; - skb->dev = dev; - dev->last_rx = jiffies; - skb->protocol = hdlc_type_trans(skb, dev); - netif_rx(skb); - skb = NULL; - } - - if (!skb) { - skb = dev_alloc_skb(BUFFER_LENGTH); - desc->address = skb ? - pci_map_single(card->pdev, skb->data, - BUFFER_LENGTH, - PCI_DMA_FROMDEVICE) : 0; - card->rx_skbs[card->rx_in] = skb; + printk(KERN_DEBUG "%s RX(%i):", dev->name, + skb->len); + debug_frame(skb); +#endif + stats->rx_packets++; + stats->rx_bytes += skb->len; + skb->mac.raw = skb->data; + skb->dev = dev; + dev->last_rx = jiffies; + skb->protocol = hdlc_type_trans(skb, dev); + netif_rx(skb); + skb = NULL; + } + + if (!skb) { + skb = dev_alloc_skb(BUFFER_LENGTH); + desc->address = skb ? + pci_map_single(card->pdev, skb->data, + BUFFER_LENGTH, + PCI_DMA_FROMDEVICE) : 0; + card->rx_skbs[card->rx_in] = skb; + } } desc->stat = PACKET_EMPTY; /* Free descriptor */ card->rx_in = (card->rx_in + 1) % RX_QUEUE_LENGTH; @@ -273,9 +262,9 @@ for (i = 0; i < card->n_ports; i++) { if (stat & (1 << (DOORBELL_FROM_CARD_TX_0 + i))) - wanxl_tx_intr(card->ports[i]); + wanxl_tx_intr(&card->ports[i]); if (stat & (1 << (DOORBELL_FROM_CARD_CABLE_0 + i))) - wanxl_cable_intr(card->ports[i]); + wanxl_cable_intr(&card->ports[i]); } if (stat & (1 << DOORBELL_FROM_CARD_RX)) wanxl_rx_intr(card); @@ -297,8 +286,7 @@ if (desc->stat != PACKET_EMPTY) { /* should never happen - previous xmit should stop queue */ #ifdef DEBUG_PKT - printk(KERN_DEBUG "%s: transmitter buffer full\n", - port_name(port)); + printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); #endif netif_stop_queue(dev); spin_unlock_irq(&port->lock); @@ -306,7 +294,7 @@ } #ifdef DEBUG_PKT - printk(KERN_DEBUG "%s TX(%i):", port_name(port), skb->len); + printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); debug_frame(skb); #endif @@ -324,8 +312,7 @@ if (get_status(port)->tx_descs[port->tx_out].stat != PACKET_EMPTY) { netif_stop_queue(dev); #ifdef DEBUG_PKT - printk(KERN_DEBUG "%s: transmitter buffer full\n", - port_name(port)); + printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); #endif } @@ -417,7 +404,7 @@ int i; if (get_status(port)->open) { - printk(KERN_ERR "%s: port already open\n", port_name(port)); + printk(KERN_ERR "%s: port already open\n", dev->name); return -EIO; } if ((i = hdlc_open(dev)) != 0) @@ -435,7 +422,7 @@ return 0; while (time_after(timeout, jiffies)); - printk(KERN_ERR "%s: unable to open port\n", port_name(port)); + printk(KERN_ERR "%s: unable to open port\n", dev->name); /* ask the card to close the port, should it be still alive */ writel(1 << (DOORBELL_TO_CARD_CLOSE_0 + port->node), dbr); return -EFAULT; @@ -461,7 +448,7 @@ while (time_after(timeout, jiffies)); if (get_status(port)->open) - printk(KERN_ERR "%s: unable to close port\n", port_name(port)); + printk(KERN_ERR "%s: unable to close port\n", dev->name); for (i = 0; i < TX_BUFFERS; i++) { desc_t *desc = &get_status(port)->tx_descs[i]; @@ -528,11 +515,10 @@ card_t *card = pci_get_drvdata(pdev); int i; - for (i = 0; i < 4; i++) - if (card->ports[i]) { - struct net_device *dev = port_to_dev(card->ports[i]); - unregister_hdlc_device(dev); - } + for (i = 0; i < card->n_ports; i++) { + unregister_hdlc_device(card->ports[i].dev); + free_netdev(card->ports[i].dev); + } /* unregister and free all host resources */ if (card->irq) @@ -555,13 +541,10 @@ pci_free_consistent(pdev, sizeof(card_status_t), card->status, card->status_address); - for (i = 0; i < card->n_ports; i++) - if (card->__ports[i].dev) - free_netdev(card->__ports[i].dev); - + pci_release_regions(pdev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); kfree(card); - pci_release_regions(pdev); } @@ -599,13 +582,15 @@ work on most platforms */ if (pci_set_consistent_dma_mask(pdev, 0x0FFFFFFF) || pci_set_dma_mask(pdev, 0x0FFFFFFF)) { - printk(KERN_ERR "No usable DMA configuration\n"); + printk(KERN_ERR "wanXL: No usable DMA configuration\n"); return -EIO; } i = pci_request_regions(pdev, "wanXL"); - if (i) + if (i) { + pci_disable_device(pdev); return i; + } switch (pdev->device) { case PCI_DEVICE_ID_SBE_WANXL100: ports = 1; break; @@ -619,23 +604,13 @@ printk(KERN_ERR "wanXL %s: unable to allocate memory\n", card_name(pdev)); pci_release_regions(pdev); + pci_disable_device(pdev); return -ENOBUFS; } memset(card, 0, alloc_size); pci_set_drvdata(pdev, card); card->pdev = pdev; - card->n_ports = ports; - - for (i = 0; i < ports; i++) { - card->__ports[i].dev = alloc_hdlcdev(&card->__ports[i]); - if (!card->__ports[i].dev) { - printk(KERN_ERR "wanXL %s: unable to allocate memory\n", - card_name(pdev)); - wanxl_pci_remove_one(pdev); - return -ENOMEM; - } - } card->status = pci_alloc_consistent(pdev, sizeof(card_status_t), &card->status_address); @@ -655,7 +630,7 @@ to indicate the card can do 32-bit DMA addressing */ if (pci_set_consistent_dma_mask(pdev, 0xFFFFFFFF) || pci_set_dma_mask(pdev, 0xFFFFFFFF)) { - printk(KERN_ERR "No usable DMA configuration\n"); + printk(KERN_ERR "wanXL: No usable DMA configuration\n"); wanxl_pci_remove_one(pdev); return -EIO; } @@ -767,17 +742,11 @@ ramsize = stat; #endif - printk(KERN_INFO "wanXL %s: at 0x%X, %u KB of RAM at 0x%X, irq" - " %u\n" KERN_INFO "wanXL %s: port", card_name(pdev), - plx_phy, ramsize / 1024, mem_phy, pdev->irq, card_name(pdev)); - - for (i = 0; i < ports; i++) - printk("%s #%i: %s", i ? "," : "", i, - port_name(card->ports[i])); - printk("\n"); + printk(KERN_INFO "wanXL %s: at 0x%X, %u KB of RAM at 0x%X, irq %u\n", + card_name(pdev), plx_phy, ramsize / 1024, mem_phy, pdev->irq); /* Allocate IRQ */ - if(request_irq(pdev->irq, wanxl_intr, SA_SHIRQ, "wanXL", card)) { + if (request_irq(pdev->irq, wanxl_intr, SA_SHIRQ, "wanXL", card)) { printk(KERN_WARNING "wanXL %s: could not allocate IRQ%i.\n", card_name(pdev), pdev->irq); wanxl_pci_remove_one(pdev); @@ -786,9 +755,18 @@ card->irq = pdev->irq; for (i = 0; i < ports; i++) { - port_t *port = &card->__ports[i]; - struct net_device *dev = port_to_dev(port); - hdlc_device *hdlc = dev_to_hdlc(dev); + hdlc_device *hdlc; + port_t *port = &card->ports[i]; + struct net_device *dev = alloc_hdlcdev(port); + if (!dev) { + printk(KERN_ERR "wanXL %s: unable to allocate" + " memory\n", card_name(pdev)); + wanxl_pci_remove_one(pdev); + return -ENOMEM; + } + + port->dev = dev; + hdlc = dev_to_hdlc(dev); spin_lock_init(&port->lock); SET_MODULE_OWNER(dev); dev->tx_queue_len = 50; @@ -797,7 +775,6 @@ dev->stop = wanxl_close; hdlc->attach = wanxl_attach; hdlc->xmit = wanxl_xmit; - card->ports[i] = port; dev->get_stats = wanxl_get_stats; port->card = card; port->node = i; @@ -805,12 +782,22 @@ if (register_hdlc_device(dev)) { printk(KERN_ERR "wanXL %s: unable to register hdlc" " device\n", card_name(pdev)); - card->ports[i] = NULL; + free_netdev(dev); wanxl_pci_remove_one(pdev); return -ENOBUFS; } + card->n_ports++; } + printk(KERN_INFO "wanXL %s: port", card_name(pdev)); + for (i = 0; i < ports; i++) + printk("%s #%i: %s", i ? "," : "", i, + card->ports[i].dev->name); + printk("\n"); + + for (i = 0; i < ports; i++) + wanxl_cable_intr(&card->ports[i]); /* get carrier status etc.*/ + return 0; } diff -urN linux-2.6.4-rc2/drivers/parport/parport_sunbpp.c linux-2.6.4-rc3/drivers/parport/parport_sunbpp.c --- linux-2.6.4-rc2/drivers/parport/parport_sunbpp.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/parport/parport_sunbpp.c 2004-03-09 16:36:27.000000000 -0800 @@ -44,9 +44,10 @@ #define dprintk(x) #endif -static void parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { parport_generic_irq(irq, (struct parport *) dev_id, regs); + return IRQ_HANDLED; } static void parport_sunbpp_disable_irq(struct parport *p) @@ -384,7 +385,7 @@ static void __exit parport_sunbpp_exit(void) { - while (!list_empty(port_list)) { + while (!list_empty(&port_list)) { Node *node = list_entry(port_list.next, Node, list); struct parport *p = node->port; struct parport_operations *ops = p->ops; diff -urN linux-2.6.4-rc2/drivers/pci/pci.ids linux-2.6.4-rc3/drivers/pci/pci.ids --- linux-2.6.4-rc2/drivers/pci/pci.ids 2004-02-17 19:58:02.000000000 -0800 +++ linux-2.6.4-rc3/drivers/pci/pci.ids 2004-03-09 16:36:27.000000000 -0800 @@ -5601,6 +5601,8 @@ 14da National Aerospace Laboratories 14db AFAVLAB Technology Inc 2120 TK9902 + 2180 P028 + 2182 P030 14dc Amplicon Liveline Ltd 0000 PCI230 0001 PCI242 diff -urN linux-2.6.4-rc2/drivers/sbus/char/vfc_dev.c linux-2.6.4-rc3/drivers/sbus/char/vfc_dev.c --- linux-2.6.4-rc2/drivers/sbus/char/vfc_dev.c 2004-02-17 19:58:12.000000000 -0800 +++ linux-2.6.4-rc3/drivers/sbus/char/vfc_dev.c 2004-03-09 16:36:27.000000000 -0800 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff -urN linux-2.6.4-rc2/drivers/scsi/ata_piix.c linux-2.6.4-rc3/drivers/scsi/ata_piix.c --- linux-2.6.4-rc2/drivers/scsi/ata_piix.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/scsi/ata_piix.c 2004-03-09 16:36:27.000000000 -0800 @@ -28,12 +28,13 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "1.00" +#define DRV_VERSION "1.01" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ ICH5_PCS = 0x92, /* port control and status */ + PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ PIIX_COMB_PRI = (1 << 0), /* combined mode, PATA primary */ @@ -163,7 +164,8 @@ /* ich5_pata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + PIIX_FLAG_CHECKINTR, .pio_mask = 0x03, /* pio3-4 */ .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, @@ -172,8 +174,8 @@ /* ich5_sata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED | - ATA_FLAG_SRST, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, .pio_mask = 0x03, /* pio3-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &piix_sata_ops, @@ -518,6 +520,18 @@ *mask |= PIIX_COMB_PRI; } +/* move to PCI layer, integrate w/ MSI stuff */ +static void pci_enable_intx(struct pci_dev *pdev) +{ + u16 pci_command; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (pci_command & PCI_COMMAND_INTX_DISABLE) { + pci_command &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } +} + /** * piix_init_one - Register PIIX ATA PCI device with kernel services * @pdev: PCI device to register @@ -552,6 +566,15 @@ if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) piix_probe_combined(pdev, &combined); + /* On ICH5, some BIOSen disable the interrupt using the + * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. + * On ICH6, this bit has the same effect, but only when + * MSI is disabled (and it is disabled, as we don't use + * message-signalled interrupts currently). + */ + if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR) + pci_enable_intx(pdev); + if (combined & PIIX_COMB_PRI) sata_comb = 1; else if (combined & PIIX_COMB_SEC) diff -urN linux-2.6.4-rc2/drivers/scsi/libata-core.c linux-2.6.4-rc3/drivers/scsi/libata-core.c --- linux-2.6.4-rc2/drivers/scsi/libata-core.c 2004-03-09 16:36:16.000000000 -0800 +++ linux-2.6.4-rc3/drivers/scsi/libata-core.c 2004-03-09 16:36:28.000000000 -0800 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "scsi.h" #include "hosts.h" @@ -2600,6 +2601,10 @@ if (signal_pending (current)) flush_signals(current); + + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); + if ((timeout < 0) || (ap->time_to_die)) break; diff -urN linux-2.6.4-rc2/drivers/scsi/qlogicfc.c linux-2.6.4-rc3/drivers/scsi/qlogicfc.c --- linux-2.6.4-rc2/drivers/scsi/qlogicfc.c 2004-02-17 19:58:49.000000000 -0800 +++ linux-2.6.4-rc3/drivers/scsi/qlogicfc.c 2004-03-09 16:36:28.000000000 -0800 @@ -411,7 +411,7 @@ if that mbox should be copied as input. For example 0x2 would mean only copy mbox1. */ -const u_char mbox_param[] = +static const u_char mbox_param[] = { 0x01, /* MBOX_NO_OP */ 0x1f, /* MBOX_LOAD_RAM */ diff -urN linux-2.6.4-rc2/drivers/scsi/qlogicpti.c linux-2.6.4-rc3/drivers/scsi/qlogicpti.c --- linux-2.6.4-rc2/drivers/scsi/qlogicpti.c 2004-02-17 19:58:42.000000000 -0800 +++ linux-2.6.4-rc3/drivers/scsi/qlogicpti.c 2004-03-09 16:36:28.000000000 -0800 @@ -54,7 +54,7 @@ #define PACKB(a, b) (((a)<<4)|(b)) -const u_char mbox_param[] = { +static const u_char mbox_param[] = { PACKB(1, 1), /* MBOX_NO_OP */ PACKB(5, 5), /* MBOX_LOAD_RAM */ PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ diff -urN linux-2.6.4-rc2/drivers/scsi/sata_promise.c linux-2.6.4-rc3/drivers/scsi/sata_promise.c --- linux-2.6.4-rc2/drivers/scsi/sata_promise.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/drivers/scsi/sata_promise.c 2004-03-09 16:36:28.000000000 -0800 @@ -35,7 +35,7 @@ #include #define DRV_NAME "sata_promise" -#define DRV_VERSION "0.90" +#define DRV_VERSION "0.91" enum { @@ -1014,6 +1014,14 @@ goto out; } + /* hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + qc->scsidone = scsi_finish_command; + switch (qc->tf.protocol) { case ATA_PROT_DMA_READ: case ATA_PROT_DMA_WRITE: diff -urN linux-2.6.4-rc2/drivers/serial/8250.c linux-2.6.4-rc3/drivers/serial/8250.c --- linux-2.6.4-rc2/drivers/serial/8250.c 2004-02-17 19:57:14.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/8250.c 2004-03-09 16:36:28.000000000 -0800 @@ -16,12 +16,8 @@ * * A note about mapbase / membase * - * mapbase is the physical address of the IO port. Currently, we don't - * support this very well, and it may well be dropped from this driver - * in future. As such, mapbase should be NULL. - * - * membase is an 'ioremapped' cookie. This is compatible with the old - * serial.c driver, and is currently the preferred form. + * mapbase is the physical address of the IO port. + * membase is an 'ioremapped' cookie. */ #include #include @@ -1976,6 +1972,8 @@ if (co->index >= UART_NR) co->index = 0; port = &serial8250_ports[co->index].port; + if (!port->ops) + return -ENODEV; /* * Temporary fix. @@ -2007,6 +2005,14 @@ } console_initcall(serial8250_console_init); +static int __init serial8250_late_console_init(void) +{ + if (!(serial8250_console.flags & CON_ENABLED)) + register_console(&serial8250_console); + return 0; +} +late_initcall(serial8250_late_console_init); + #define SERIAL8250_CONSOLE &serial8250_console #else #define SERIAL8250_CONSOLE NULL diff -urN linux-2.6.4-rc2/drivers/serial/8250_pci.c linux-2.6.4-rc3/drivers/serial/8250_pci.c --- linux-2.6.4-rc2/drivers/serial/8250_pci.c 2004-02-17 19:59:04.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/8250_pci.c 2004-03-09 16:36:28.000000000 -0800 @@ -145,8 +145,10 @@ bar = FL_GET_BASE(board->flags); if (idx < 4) bar += idx; - else + else { + bar = 4; offset += (idx - 4) * board->uart_offset; + } return setup_port(dev, req, bar, offset, board->reg_shift); } @@ -1772,7 +1774,7 @@ pbn_b0_4_115200 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_2_115200 }, + pbn_b0_bt_2_921600 }, /* * Digitan DS560-558, from jimd@esoft.com @@ -1891,6 +1893,9 @@ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_8_115200 }, + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, diff -urN linux-2.6.4-rc2/drivers/serial/Kconfig linux-2.6.4-rc3/drivers/serial/Kconfig --- linux-2.6.4-rc2/drivers/serial/Kconfig 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/Kconfig 2004-03-09 16:36:28.000000000 -0800 @@ -250,12 +250,6 @@ your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_CLPS711X_OLD_NAME - bool "Use the old 2.4 names for CLPS711X serial port" - depends on SERIAL_CLPS711X=y - help - ::: To be written ::: - config SERIAL_DZ bool "DECstation DZ serial driver" depends on DECSTATION diff -urN linux-2.6.4-rc2/drivers/serial/clps711x.c linux-2.6.4-rc3/drivers/serial/clps711x.c --- linux-2.6.4-rc2/drivers/serial/clps711x.c 2004-02-17 19:57:21.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/clps711x.c 2004-03-09 16:36:28.000000000 -0800 @@ -49,19 +49,10 @@ #define UART_NR 2 -#ifndef CONFIG_SERIAL_CLPS711X_OLD_NAME #define SERIAL_CLPS711X_MAJOR 204 #define SERIAL_CLPS711X_MINOR 40 #define SERIAL_CLPS711X_NR UART_NR -#else -#warning The old names/device number for this driver if compatabity is needed -#define SERIAL_CLPS711X_MAJOR 204 -#define SERIAL_CLPS711X_MINOR 16 -#define SERIAL_CLPS711X_NR UART_NR - -#endif - /* * We use the relevant SYSCON register as a base address for these ports. */ diff -urN linux-2.6.4-rc2/drivers/serial/pmac_zilog.c linux-2.6.4-rc3/drivers/serial/pmac_zilog.c --- linux-2.6.4-rc2/drivers/serial/pmac_zilog.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/pmac_zilog.c 2004-03-09 16:36:28.000000000 -0800 @@ -31,10 +31,11 @@ * * TODO: - Add DMA support * - Defer port shutdown to a few seconds after close - * - maybe put something right into up->clk_divisor + * - maybe put something right into uap->clk_divisor */ #undef DEBUG +#undef DEBUG_HARD #include #include @@ -61,21 +62,17 @@ #include #include #include +#include #include #include #include "pmac_zilog.h" -#if defined(CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_PPC64) -#define HAS_SCCDBG -extern int sccdbg; -#endif - /* Not yet implemented */ #undef HAS_DBDMA -static char version[] __initdata = "pmac_zilog.c 0.5a (Benjamin Herrenschmidt )"; +static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt )"; MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the PowerMac serial ports."); MODULE_LICENSE("GPL"); @@ -89,6 +86,15 @@ */ static struct uart_pmac_port pmz_ports[MAX_ZS_PORTS]; static int pmz_ports_count; +static DECLARE_MUTEX(pmz_irq_sem); + +static struct uart_driver pmz_uart_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyS", + .devfs_name = "tts/", + .dev_name = "ttyS", + .major = TTY_MAJOR, +}; /* @@ -96,71 +102,78 @@ * This function must only be called when the TX is not busy. The UART * port lock must be held and local interrupts disabled. */ -static void pmz_load_zsregs(struct uart_pmac_port *up, u8 *regs) +static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs) { int i; + if (ZS_IS_ASLEEP(uap)) + return; + /* Let pending transmits finish. */ for (i = 0; i < 1000; i++) { - unsigned char stat = read_zsreg(up, R1); + unsigned char stat = read_zsreg(uap, R1); if (stat & ALL_SNT) break; udelay(100); } - ZS_CLEARERR(up); - zssync(up); - ZS_CLEARFIFO(up); - zssync(up); - ZS_CLEARERR(up); + ZS_CLEARERR(uap); + zssync(uap); + ZS_CLEARFIFO(uap); + zssync(uap); + ZS_CLEARERR(uap); /* Disable all interrupts. */ - write_zsreg(up, R1, + write_zsreg(uap, R1, regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); /* Set parity, sync config, stop bits, and clock divisor. */ - write_zsreg(up, R4, regs[R4]); + write_zsreg(uap, R4, regs[R4]); /* Set misc. TX/RX control bits. */ - write_zsreg(up, R10, regs[R10]); + write_zsreg(uap, R10, regs[R10]); /* Set TX/RX controls sans the enable bits. */ - write_zsreg(up, R3, regs[R3] & ~RxENABLE); - write_zsreg(up, R5, regs[R5] & ~TxENABLE); + write_zsreg(uap, R3, regs[R3] & ~RxENABLE); + write_zsreg(uap, R5, regs[R5] & ~TxENABLE); + + /* now set R7 "prime" on ESCC */ + write_zsreg(uap, R15, regs[R15] | EN85C30); + write_zsreg(uap, R7, regs[R7P]); + + /* make sure we use R7 "non-prime" on ESCC */ + write_zsreg(uap, R15, regs[R15] & ~EN85C30); /* Synchronous mode config. */ - write_zsreg(up, R6, regs[R6]); - write_zsreg(up, R7, regs[R7]); + write_zsreg(uap, R6, regs[R6]); + write_zsreg(uap, R7, regs[R7]); /* Disable baud generator. */ - write_zsreg(up, R14, regs[R14] & ~BRENAB); + write_zsreg(uap, R14, regs[R14] & ~BRENAB); /* Clock mode control. */ - write_zsreg(up, R11, regs[R11]); + write_zsreg(uap, R11, regs[R11]); /* Lower and upper byte of baud rate generator divisor. */ - write_zsreg(up, R12, regs[R12]); - write_zsreg(up, R13, regs[R13]); + write_zsreg(uap, R12, regs[R12]); + write_zsreg(uap, R13, regs[R13]); /* Now rewrite R14, with BRENAB (if set). */ - write_zsreg(up, R14, regs[R14]); - - /* External status interrupt control. */ - write_zsreg(up, R15, regs[R15]); + write_zsreg(uap, R14, regs[R14]); /* Reset external status interrupts. */ - write_zsreg(up, R0, RES_EXT_INT); - write_zsreg(up, R0, RES_EXT_INT); + write_zsreg(uap, R0, RES_EXT_INT); + write_zsreg(uap, R0, RES_EXT_INT); /* Rewrite R3/R5, this time without enables masked. */ - write_zsreg(up, R3, regs[R3]); - write_zsreg(up, R5, regs[R5]); + write_zsreg(uap, R3, regs[R3]); + write_zsreg(uap, R5, regs[R5]); /* Rewrite R1, this time without IRQ enabled masked. */ - write_zsreg(up, R1, regs[R1]); + write_zsreg(uap, R1, regs[R1]); /* Enable interrupts */ - write_zsreg(up, R9, regs[R9]); + write_zsreg(uap, R9, regs[R9]); } /* @@ -171,63 +184,110 @@ * * The UART port lock must be held and local interrupts disabled. */ -static void pmz_maybe_update_regs(struct uart_pmac_port *up) +static void pmz_maybe_update_regs(struct uart_pmac_port *uap) { - if (!ZS_REGS_HELD(up)) { - if (ZS_TX_ACTIVE(up)) { - up->flags |= PMACZILOG_FLAG_REGS_HELD; + if (!ZS_REGS_HELD(uap)) { + if (ZS_TX_ACTIVE(uap)) { + uap->flags |= PMACZILOG_FLAG_REGS_HELD; } else { - pr_debug("pmz: maybe_update_regs: updating\n"); - pmz_load_zsregs(up, up->curregs); + pmz_debug("pmz: maybe_update_regs: updating\n"); + pmz_load_zsregs(uap, uap->curregs); } } } -static void pmz_receive_chars(struct uart_pmac_port *up, struct pt_regs *regs) +static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap, + struct pt_regs *regs) { - struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */ + struct tty_struct *tty = NULL; + unsigned char ch, r1, drop, error; + int loops = 0; + + retry: + /* The interrupt can be enabled when the port isn't open, typically + * that happens when using one port is open and the other closed (stale + * interrupt) or when one port is used as a console. + */ + if (!ZS_IS_OPEN(uap)) { + pmz_debug("pmz: draining input\n"); + /* Port is closed, drain input data */ + for (;;) { + if ((++loops) > 1000) + goto flood; + (void)read_zsreg(uap, R1); + write_zsreg(uap, R0, ERR_RES); + (void)read_zsdata(uap); + ch = read_zsreg(uap, R0); + if (!(ch & Rx_CH_AV)) + break; + } + return NULL; + } + + /* Sanity check, make sure the old bug is no longer happening */ + if (uap->port.info == NULL || uap->port.info->tty == NULL) { + WARN_ON(1); + (void)read_zsdata(uap); + return NULL; + } + tty = uap->port.info->tty; while (1) { - unsigned char ch, r1; + error = 0; + drop = 0; if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { + /* Have to drop the lock here */ + pmz_debug("pmz: flip overflow\n"); + spin_unlock(&uap->port.lock); tty->flip.work.func((void *)tty); + spin_lock(&uap->port.lock); if (tty->flip.count >= TTY_FLIPBUF_SIZE) - /* XXX Ignores SysRq when we need it most. Fix. */ - return; + drop = 1; + if (ZS_IS_ASLEEP(uap)) + return 0; + if (!ZS_IS_OPEN(uap)) + goto retry; } - r1 = read_zsreg(up, R1); + r1 = read_zsreg(uap, R1); + ch = read_zsdata(uap); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - write_zsreg(up, R0, ERR_RES); - zssync(up); + write_zsreg(uap, R0, ERR_RES); + zssync(uap); } - ch = read_zsdata(up); - ch &= up->parity_mask; - if (ch == 0 && up->prev_status & BRK_ABRT) { + ch &= uap->parity_mask; + if (ch == 0 && uap->prev_status & BRK_ABRT) r1 |= BRK_ABRT; - printk("rx break\n"); - } /* A real serial line, record the character and status. */ + if (drop) + goto next_char; + *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = TTY_NORMAL; - up->port.icount.rx++; + uap->port.icount.rx++; + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) { + error = 1; if (r1 & BRK_ABRT) { + pmz_debug("pmz: got break !\n"); r1 &= ~(PAR_ERR | CRC_ERR); - up->port.icount.brk++; - if (uart_handle_break(&up->port)) + uap->port.icount.brk++; + if (uart_handle_break(&uap->port)) { + pmz_debug("pmz: do handle break !\n"); goto next_char; + } } else if (r1 & PAR_ERR) - up->port.icount.parity++; + uap->port.icount.parity++; else if (r1 & CRC_ERR) - up->port.icount.frame++; + uap->port.icount.frame++; if (r1 & Rx_OVR) - up->port.icount.overrun++; - r1 &= up->port.read_status_mask; + uap->port.icount.overrun++; + r1 &= uap->port.read_status_mask; if (r1 & BRK_ABRT) *tty->flip.flag_buf_ptr = TTY_BREAK; else if (r1 & PAR_ERR) @@ -235,11 +295,13 @@ else if (r1 & CRC_ERR) *tty->flip.flag_buf_ptr = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&uap->port, ch, regs)) { + pmz_debug("pmz: sysrq swallowed the char\n"); goto next_char; + } - if (up->port.ignore_status_mask == 0xff || - (r1 & up->port.ignore_status_mask) == 0) { + if (uap->port.ignore_status_mask == 0xff || + (r1 & uap->port.ignore_status_mask) == 0) { tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; @@ -252,58 +314,66 @@ tty->flip.count++; } next_char: - ch = read_zsreg(up, R0); + /* We can get stuck in an infinite loop getting char 0 when the + * line is in a wrong HW state, we break that here. + * When that happens, I disable the receive side of the driver. + * Note that what I've been experiencing is a real irq loop where + * I'm getting flooded regardless of the actual port speed. + * Something stange is going on with the HW + */ + if ((++loops) > 1000) + goto flood; + ch = read_zsreg(uap, R0); if (!(ch & Rx_CH_AV)) break; } - tty_flip_buffer_push(tty); + return tty; + flood: + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + write_zsreg(uap, R1, uap->curregs[R1]); + zssync(uap); + dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n"); + return tty; } -static void pmz_status_handle(struct uart_pmac_port *up, struct pt_regs *regs) +static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs) { unsigned char status; - status = read_zsreg(up, R0); - write_zsreg(up, R0, RES_EXT_INT); - zssync(up); - -#ifdef HAS_SCCDBG - if (sccdbg && (status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) { -#ifdef CONFIG_XMON - extern void xmon(struct pt_regs *); - xmon(regs); -#endif - } -#endif /* HAS_SCCDBG */ + status = read_zsreg(uap, R0); + write_zsreg(uap, R0, RES_EXT_INT); + zssync(uap); - if (ZS_WANTS_MODEM_STATUS(up)) { + if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) { if (status & SYNC_HUNT) - up->port.icount.dsr++; + uap->port.icount.dsr++; /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. * But it does not tell us which bit has changed, we have to keep * track of this ourselves. */ - if ((status & DCD) ^ up->prev_status) - uart_handle_dcd_change(&up->port, + if ((status & DCD) ^ uap->prev_status) + uart_handle_dcd_change(&uap->port, (status & DCD)); - if ((status & CTS) ^ up->prev_status) - uart_handle_cts_change(&up->port, + if ((status & CTS) ^ uap->prev_status) + uart_handle_cts_change(&uap->port, (status & CTS)); - wake_up_interruptible(&up->port.info->delta_msr_wait); + wake_up_interruptible(&uap->port.info->delta_msr_wait); } - up->prev_status = status; + uap->prev_status = status; } -static void pmz_transmit_chars(struct uart_pmac_port *up) +static void pmz_transmit_chars(struct uart_pmac_port *uap) { struct circ_buf *xmit; - if (ZS_IS_CONS(up)) { - unsigned char status = read_zsreg(up, R0); + if (ZS_IS_ASLEEP(uap)) + return; + if (ZS_IS_CONS(uap)) { + unsigned char status = read_zsreg(uap, R0); /* TX still busy? Just wait for the next TX done interrupt. * @@ -317,115 +387,128 @@ return; } - up->flags &= ~PMACZILOG_FLAG_TX_ACTIVE; + uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE; - if (ZS_REGS_HELD(up)) { - pmz_load_zsregs(up, up->curregs); - up->flags &= ~PMACZILOG_FLAG_REGS_HELD; + if (ZS_REGS_HELD(uap)) { + pmz_load_zsregs(uap, uap->curregs); + uap->flags &= ~PMACZILOG_FLAG_REGS_HELD; } - if (ZS_TX_STOPPED(up)) { - up->flags &= ~PMACZILOG_FLAG_TX_STOPPED; + if (ZS_TX_STOPPED(uap)) { + uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; goto ack_tx_int; } - if (up->port.x_char) { - up->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(up, up->port.x_char); - zssync(up); - up->port.icount.tx++; - up->port.x_char = 0; + if (uap->port.x_char) { + uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; + write_zsdata(uap, uap->port.x_char); + zssync(uap); + uap->port.icount.tx++; + uap->port.x_char = 0; return; } - if (up->port.info == NULL) + if (uap->port.info == NULL) goto ack_tx_int; - xmit = &up->port.info->xmit; + xmit = &uap->port.info->xmit; if (uart_circ_empty(xmit)) { - uart_write_wakeup(&up->port); + uart_write_wakeup(&uap->port); goto ack_tx_int; } - if (uart_tx_stopped(&up->port)) + if (uart_tx_stopped(&uap->port)) goto ack_tx_int; - up->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(up, xmit->buf[xmit->tail]); - zssync(up); + uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; + write_zsdata(uap, xmit->buf[xmit->tail]); + zssync(uap); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; + uap->port.icount.tx++; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); + uart_write_wakeup(&uap->port); return; ack_tx_int: - write_zsreg(up, R0, RES_Tx_P); - zssync(up); + write_zsreg(uap, R0, RES_Tx_P); + zssync(uap); } /* Hrm... we register that twice, fixme later.... */ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct uart_pmac_port *up = dev_id; - struct uart_pmac_port *up_a; - struct uart_pmac_port *up_b; + struct uart_pmac_port *uap = dev_id; + struct uart_pmac_port *uap_a; + struct uart_pmac_port *uap_b; int rc = IRQ_NONE; + struct tty_struct *tty; u8 r3; - up_a = ZS_IS_CHANNEL_A(up) ? up : up->mate; - up_b = up_a->mate; + uap_a = pmz_get_port_A(uap); + uap_b = uap_a->mate; - spin_lock(&up_a->port.lock); - r3 = read_zsreg(up, R3); - pr_debug("pmz_irq: %x\n", r3); + spin_lock(&uap_a->port.lock); + r3 = read_zsreg(uap_a, R3); +#ifdef DEBUG_HARD + pmz_debug("irq, r3: %x\n", r3); +#endif /* Channel A */ + tty = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - write_zsreg(up_a, R0, RES_H_IUS); - zssync(up_a); - pr_debug("pmz: irq channel A: %x\n", r3); + write_zsreg(uap_a, R0, RES_H_IUS); + zssync(uap_a); if (r3 & CHAEXT) - pmz_status_handle(up_a, regs); + pmz_status_handle(uap_a, regs); if (r3 & CHARxIP) - pmz_receive_chars(up_a, regs); + tty = pmz_receive_chars(uap_a, regs); if (r3 & CHATxIP) - pmz_transmit_chars(up_a); + pmz_transmit_chars(uap_a); rc = IRQ_HANDLED; } - spin_unlock(&up_a->port.lock); - - spin_lock(&up_b->port.lock); + spin_unlock(&uap_a->port.lock); + if (tty != NULL) + tty_flip_buffer_push(tty); + + if (uap_b->node == NULL) + goto out; + + spin_lock(&uap_b->port.lock); + tty = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - write_zsreg(up_b, R0, RES_H_IUS); - zssync(up_b); - pr_debug("pmz: irq channel B: %x\n", r3); + write_zsreg(uap_b, R0, RES_H_IUS); + zssync(uap_b); if (r3 & CHBEXT) - pmz_status_handle(up_b, regs); + pmz_status_handle(uap_b, regs); if (r3 & CHBRxIP) - pmz_receive_chars(up_b, regs); + pmz_receive_chars(uap_b, regs); if (r3 & CHBTxIP) - pmz_transmit_chars(up_b); + pmz_transmit_chars(uap_b); rc = IRQ_HANDLED; } - spin_unlock(&up_b->port.lock); - + spin_unlock(&uap_b->port.lock); + if (tty != NULL) + tty_flip_buffer_push(tty); + out: +#ifdef DEBUG_HARD + pmz_debug("irq done.\n"); +#endif return rc; } /* * Peek the status register, lock not held by caller */ -static inline u8 pmz_peek_status(struct uart_pmac_port *up) +static inline u8 pmz_peek_status(struct uart_pmac_port *uap) { unsigned long flags; u8 status; - spin_lock_irqsave(&up->port.lock, flags); - status = read_zsreg(up, R0); - spin_unlock_irqrestore(&up->port.lock, flags); + spin_lock_irqsave(&uap->port.lock, flags); + status = read_zsreg(uap, R0); + spin_unlock_irqrestore(&uap->port.lock, flags); return status; } @@ -436,8 +519,12 @@ */ static unsigned int pmz_tx_empty(struct uart_port *port) { + struct uart_pmac_port *uap = to_pmz(port); unsigned char status; + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return TIOCSER_TEMT; + status = pmz_peek_status(to_pmz(port)); if (status & Tx_BUF_EMP) return TIOCSER_TEMT; @@ -452,16 +539,20 @@ */ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); unsigned char set_bits, clear_bits; /* Do nothing for irda for now... */ - if (ZS_IS_IRDA(up)) + if (ZS_IS_IRDA(uap)) + return; + /* We get called during boot with a port not up yet */ + if (ZS_IS_ASLEEP(uap) || + !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap))) return; set_bits = clear_bits = 0; - if (ZS_IS_INTMODEM(up)) { + if (ZS_IS_INTMODEM(uap)) { if (mctrl & TIOCM_RTS) set_bits |= RTS; else @@ -473,10 +564,14 @@ clear_bits |= DTR; /* NOTE: Not subject to 'transmitter active' rule. */ - up->curregs[R5] |= set_bits; - up->curregs[R5] &= ~clear_bits; - write_zsreg(up, R5, up->curregs[R5]); - zssync(up); + uap->curregs[R5] |= set_bits; + uap->curregs[R5] &= ~clear_bits; + if (ZS_IS_ASLEEP(uap)) + return; + write_zsreg(uap, R5, uap->curregs[R5]); + pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n", + set_bits, clear_bits, uap->curregs[R5]); + zssync(uap); } /* @@ -486,9 +581,13 @@ */ static unsigned int pmz_get_mctrl(struct uart_port *port) { + struct uart_pmac_port *uap = to_pmz(port); unsigned char status; unsigned int ret; + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return 0; + status = pmz_peek_status(to_pmz(port)); ret = 0; @@ -519,15 +618,18 @@ */ static void pmz_start_tx(struct uart_port *port, unsigned int tty_start) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); unsigned char status; - pr_debug("pmz: start_tx()\n"); + pmz_debug("pmz: start_tx()\n"); + + uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; + uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; - up->flags |= PMACZILOG_FLAG_TX_ACTIVE; - up->flags &= ~PMACZILOG_FLAG_TX_STOPPED; + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return; - status = read_zsreg(up, R0); + status = read_zsreg(uap, R0); /* TX busy? Just wait for the TX done interrupt. */ if (!(status & Tx_BUF_EMP)) @@ -537,43 +639,44 @@ * IRQ sending engine. */ if (port->x_char) { - write_zsdata(up, port->x_char); - zssync(up); + write_zsdata(uap, port->x_char); + zssync(uap); port->icount.tx++; port->x_char = 0; } else { struct circ_buf *xmit = &port->info->xmit; - write_zsdata(up, xmit->buf[xmit->tail]); - zssync(up); + write_zsdata(uap, xmit->buf[xmit->tail]); + zssync(uap); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); + uart_write_wakeup(&uap->port); } - pr_debug("pmz: start_tx() done.\n"); + pmz_debug("pmz: start_tx() done.\n"); } /* * Stop Rx side, basically disable emitting of - * Rx interrupts on the port + * Rx interrupts on the port. We don't disable the rx + * side of the chip proper though * The port lock is held. */ static void pmz_stop_rx(struct uart_port *port) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); - if (ZS_IS_CONS(up)) + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) return; - pr_debug("pmz: stop_rx()()\n"); + pmz_debug("pmz: stop_rx()()\n"); /* Disable all RX interrupts. */ - up->curregs[R1] &= ~RxINT_MASK; - pmz_maybe_update_regs(up); + uap->curregs[R1] &= ~RxINT_MASK; + pmz_maybe_update_regs(uap); - pr_debug("pmz: stop_rx() done.\n"); + pmz_debug("pmz: stop_rx() done.\n"); } /* @@ -582,15 +685,19 @@ */ static void pmz_enable_ms(struct uart_port *port) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); unsigned char new_reg; - new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE); - if (new_reg != up->curregs[R15]) { - up->curregs[R15] = new_reg; + if (ZS_IS_IRDA(uap) || uap->node == NULL) + return; + new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE); + if (new_reg != uap->curregs[R15]) { + uap->curregs[R15] = new_reg; + if (ZS_IS_ASLEEP(uap)) + return; /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(up, R15, up->curregs[R15]); + write_zsreg(uap, R15, uap->curregs[R15]); } } @@ -600,10 +707,12 @@ */ static void pmz_break_ctl(struct uart_port *port, int break_state) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); unsigned char set_bits, clear_bits, new_reg; unsigned long flags; + if (uap->node == NULL) + return; set_bits = clear_bits = 0; if (break_state) @@ -613,12 +722,14 @@ spin_lock_irqsave(&port->lock, flags); - new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; - if (new_reg != up->curregs[R5]) { - up->curregs[R5] = new_reg; + new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != uap->curregs[R5]) { + uap->curregs[R5] = new_reg; /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(up, R5, up->curregs[R5]); + if (ZS_IS_ASLEEP(uap)) + return; + write_zsreg(uap, R5, uap->curregs[R5]); } spin_unlock_irqrestore(&port->lock, flags); @@ -630,38 +741,38 @@ * Returns the number of milliseconds we should wait before * trying to use the port. */ -static int pmz_set_scc_power(struct uart_pmac_port *up, int state) +static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) { int delay = 0; + int rc; if (state) { - pmac_call_feature( - PMAC_FTR_SCC_ENABLE, up->node, up->port_type, 1); - if (ZS_IS_INTMODEM(up)) { - pmac_call_feature( - PMAC_FTR_MODEM_ENABLE, up->node, 0, 1); + rc = pmac_call_feature( + PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1); + pmz_debug("port power on result: %d\n", rc); + if (ZS_IS_INTMODEM(uap)) { + rc = pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1); delay = 2500; /* wait for 2.5s before using */ - } else if (ZS_IS_IRDA(up)) - mdelay(50); /* Do better here once the problems - * with blocking have been ironed out - */ + pmz_debug("modem power result: %d\n", rc); + } } else { /* TODO: Make that depend on a timer, don't power down * immediately */ - if (ZS_IS_INTMODEM(up)) { - pmac_call_feature( - PMAC_FTR_MODEM_ENABLE, up->node, 0, 0); + if (ZS_IS_INTMODEM(uap)) { + rc = pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0); + pmz_debug("port power off result: %d\n", rc); } - pmac_call_feature( - PMAC_FTR_SCC_ENABLE, up->node, up->port_type, 0); + pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0); } return delay; } /* * FixZeroBug....Works around a bug in the SCC receving channel. - * Taken from Darwin code, 15 Sept. 2000 -DanM + * Inspired from Darwin code, 15 Sept. 2000 -DanM * * The following sequence prevents a problem that is seen with O'Hare ASICs * (most versions -- also with some Heathrow and Hydra ASICs) where a zero @@ -679,44 +790,41 @@ * the SCC in synchronous loopback mode with a fast clock before programming * any of the asynchronous modes. */ -static void pmz_fix_zero_bug_scc(struct uart_pmac_port *up) +static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap) { - write_zsreg(up, 9, ZS_IS_CHANNEL_A(up) ? CHRA : CHRB); - zssync(up); + write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); + zssync(uap); udelay(10); - write_zsreg(up, 9, (ZS_IS_CHANNEL_A(up) ? CHRA : CHRB) | NV); - zssync(up); - - write_zsreg(up, 4, (X1CLK | EXTSYNC)); + write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV); + zssync(uap); - /* I think this is wrong....but, I just copying code.... - */ - write_zsreg(up, 3, (8 & ~RxENABLE)); - - write_zsreg(up, 5, (8 & ~TxENABLE)); - write_zsreg(up, 9, NV); /* Didn't we already do this? */ - write_zsreg(up, 11, (RCBR | TCBR)); - write_zsreg(up, 12, 0); - write_zsreg(up, 13, 0); - write_zsreg(up, 14, (LOOPBAK | SSBR)); - write_zsreg(up, 14, (LOOPBAK | SSBR | BRENAB)); - write_zsreg(up, 3, (8 | RxENABLE)); - write_zsreg(up, 0, RES_EXT_INT); - write_zsreg(up, 0, RES_EXT_INT); /* to kill some time */ + write_zsreg(uap, 4, X1CLK | MONSYNC); + write_zsreg(uap, 3, Rx8); + write_zsreg(uap, 5, Tx8 | RTS); + write_zsreg(uap, 9, NV); /* Didn't we already do this? */ + write_zsreg(uap, 11, RCBR | TCBR); + write_zsreg(uap, 12, 0); + write_zsreg(uap, 13, 0); + write_zsreg(uap, 14, (LOOPBAK | BRSRC)); + write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB)); + write_zsreg(uap, 3, Rx8 | RxENABLE); + write_zsreg(uap, 0, RES_EXT_INT); + write_zsreg(uap, 0, RES_EXT_INT); + write_zsreg(uap, 0, RES_EXT_INT); /* to kill some time */ /* The channel should be OK now, but it is probably receiving * loopback garbage. * Switch to asynchronous mode, disable the receiver, * and discard everything in the receive buffer. */ - write_zsreg(up, 9, NV); - write_zsreg(up, 4, PAR_ENAB); - write_zsreg(up, 3, (8 & ~RxENABLE)); - - while (read_zsreg(up, 0) & Rx_CH_AV) { - (void)read_zsreg(up, 8); - write_zsreg(up, 0, RES_EXT_INT); - write_zsreg(up, 0, ERR_RES); + write_zsreg(uap, 9, NV); + write_zsreg(uap, 4, X16CLK | SB_MASK); + write_zsreg(uap, 3, Rx8); + + while (read_zsreg(uap, 0) & Rx_CH_AV) { + (void)read_zsreg(uap, 8); + write_zsreg(uap, 0, RES_EXT_INT); + write_zsreg(uap, 0, ERR_RES); } } @@ -726,352 +834,518 @@ * actually using the port, this is typically the internal modem * powerup delay. This routine expect the lock to be taken. */ -static int __pmz_startup(struct uart_pmac_port *up) +static int __pmz_startup(struct uart_pmac_port *uap) { int pwr_delay = 0; - memset(&up->curregs, 0, sizeof(up->curregs)); + memset(&uap->curregs, 0, sizeof(uap->curregs)); /* Power up the SCC & underlying hardware (modem/irda) */ - pwr_delay = pmz_set_scc_power(up, 1); + pwr_delay = pmz_set_scc_power(uap, 1); /* Nice buggy HW ... */ - pmz_fix_zero_bug_scc(up); + pmz_fix_zero_bug_scc(uap); - /* Reset the chip */ - write_zsreg(up, 9, ZS_IS_CHANNEL_A(up) ? CHRA : CHRB); - zssync(up); + /* Reset the channel */ + uap->curregs[R9] = 0; + write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); + zssync(uap); udelay(10); - write_zsreg(up, 9, 0); - zssync(up); + write_zsreg(uap, 9, 0); + zssync(uap); /* Clear the interrupt registers */ - write_zsreg(up, R1, 0); - write_zsreg(up, R0, ERR_RES); - write_zsreg(up, R0, ERR_RES); - write_zsreg(up, R0, RES_H_IUS); - write_zsreg(up, R0, RES_H_IUS); + write_zsreg(uap, R1, 0); + write_zsreg(uap, R0, ERR_RES); + write_zsreg(uap, R0, ERR_RES); + write_zsreg(uap, R0, RES_H_IUS); + write_zsreg(uap, R0, RES_H_IUS); + + /* Setup some valid baud rate */ + uap->curregs[R4] = X16CLK | SB1; + uap->curregs[R3] = Rx8; + uap->curregs[R5] = Tx8 | RTS; + if (!ZS_IS_IRDA(uap)) + uap->curregs[R5] |= DTR; + uap->curregs[R12] = 0; + uap->curregs[R13] = 0; + uap->curregs[R14] = BRENAB; - /* Remember status for DCD/CTS changes */ - up->prev_status = read_zsreg(up, R0); + /* Clear handshaking */ + uap->curregs[R15] = 0; + + /* Master interrupt enable */ + uap->curregs[R9] |= NV | MIE; + + pmz_load_zsregs(uap, uap->curregs); /* Enable receiver and transmitter. */ - up->curregs[R3] |= RxENABLE; - up->curregs[R5] |= TxENABLE | RTS | DTR; + write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE); + write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE); - /* Master interrupt enable */ - up->curregs[R9] |= NV | MIE; + /* Remember status for DCD/CTS changes */ + uap->prev_status = read_zsreg(uap, R0); - up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - pmz_maybe_update_regs(up); return pwr_delay; } +static void pmz_irda_reset(struct uart_pmac_port *uap) +{ + uap->curregs[R5] |= DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + mdelay(110); + uap->curregs[R5] &= ~DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + mdelay(10); +} + /* * This is the "normal" startup routine, using the above one * wrapped with the lock and doing a schedule delay */ static int pmz_startup(struct uart_port *port) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; int pwr_delay = 0; - pr_debug("pmz: startup()\n"); + pmz_debug("pmz: startup()\n"); + + if (ZS_IS_ASLEEP(uap)) + return -EAGAIN; + if (uap->node == NULL) + return -ENODEV; + + down(&pmz_irq_sem); + + uap->flags |= PMACZILOG_FLAG_IS_OPEN; - /* A console is never powered down */ - if (!ZS_IS_CONS(up)) { + /* A console is never powered down. Else, power up and + * initialize the chip + */ + if (!ZS_IS_CONS(uap)) { spin_lock_irqsave(&port->lock, flags); - pwr_delay = __pmz_startup(up); + pwr_delay = __pmz_startup(uap); spin_unlock_irqrestore(&port->lock, flags); - } - - if (request_irq(up->port.irq, pmz_interrupt, SA_SHIRQ, "PowerMac Zilog", up)) { - printk(KERN_ERR "Unable to register zs interrupt handler.\n"); - pmz_set_scc_power(up, 0); + } + + pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; + if (request_irq(uap->port.irq, pmz_interrupt, SA_SHIRQ, "PowerMac Zilog", uap)) { + dev_err(&uap->dev->ofdev.dev, + "Unable to register zs interrupt handler.\n"); + pmz_set_scc_power(uap, 0); + up(&pmz_irq_sem); return -ENXIO; } + up(&pmz_irq_sem); + /* Right now, we deal with delay by blocking here, I'll be * smarter later on */ if (pwr_delay != 0) { - pr_debug("pmz: delaying %d ms\n", pwr_delay); + pmz_debug("pmz: delaying %d ms\n", pwr_delay); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((pwr_delay * HZ)/1000); } - pr_debug("pmz: startup() done.\n"); + /* IrDA reset is done now */ + if (ZS_IS_IRDA(uap)) + pmz_irda_reset(uap); + + /* Enable interrupts emission from the chip */ + spin_lock_irqsave(&port->lock, flags); + uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[R1] |= EXT_INT_ENAB; + write_zsreg(uap, R1, uap->curregs[R1]); + spin_unlock_irqrestore(&port->lock, flags); + + pmz_debug("pmz: startup() done.\n"); return 0; } static void pmz_shutdown(struct uart_port *port) { - struct uart_pmac_port *up = to_pmz(port); + struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; - pr_debug("pmz: shutdown()\n"); - - /* Release interrupt handler */ - free_irq(up->port.irq, up); + pmz_debug("pmz: shutdown()\n"); - if (ZS_IS_CONS(up)) + if (uap->node == NULL) return; + down(&pmz_irq_sem); + + /* Release interrupt handler */ + free_irq(uap->port.irq, uap); + spin_lock_irqsave(&port->lock, flags); + uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; + + if (!ZS_IS_OPEN(uap->mate)) + pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; + + /* Disable interrupts */ + if (!ZS_IS_ASLEEP(uap)) { + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + write_zsreg(uap, R1, uap->curregs[R1]); + zssync(uap); + } + + if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) { + spin_unlock_irqrestore(&port->lock, flags); + up(&pmz_irq_sem); + return; + } + /* Disable receiver and transmitter. */ - up->curregs[R3] &= ~RxENABLE; - up->curregs[R5] &= ~TxENABLE; + uap->curregs[R3] &= ~RxENABLE; + uap->curregs[R5] &= ~TxENABLE; /* Disable all interrupts and BRK assertion. */ - up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - up->curregs[R5] &= ~SND_BRK; - pmz_maybe_update_regs(up); + uap->curregs[R5] &= ~SND_BRK; + pmz_maybe_update_regs(uap); /* Shut the chip down */ - pmz_set_scc_power(up, 0); + pmz_set_scc_power(uap, 0); spin_unlock_irqrestore(&port->lock, flags); - pr_debug("pmz: shutdown() done.\n"); + up(&pmz_irq_sem); + + pmz_debug("pmz: shutdown() done.\n"); } /* Shared by TTY driver and serial console setup. The port lock is held * and local interrupts are disabled. */ -static void -pmz_convert_to_zs(struct uart_pmac_port *up, unsigned int cflag, - unsigned int iflag, int baud) +static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, + unsigned int iflag, unsigned long baud) { int brg; - switch (baud) { - case ZS_CLOCK/16: /* 230400 */ - up->curregs[R4] = X16CLK; - up->curregs[R11] = 0; - break; - case ZS_CLOCK/32: /* 115200 */ - up->curregs[R4] = X32CLK; - up->curregs[R11] = 0; - break; - default: - up->curregs[R4] = X16CLK; - up->curregs[R11] = TCBR | RCBR; - brg = BPS_TO_BRG(baud, ZS_CLOCK / 16); - up->curregs[R12] = (brg & 255); - up->curregs[R13] = ((brg >> 8) & 255); - up->curregs[R14] = BRENAB; + + /* Switch to external clocking for IrDA high clock rates. That + * code could be re-used for Midi interfaces with different + * multipliers + */ + if (baud >= 115200 && ZS_IS_IRDA(uap)) { + uap->curregs[R4] = X1CLK; + uap->curregs[R11] = RCTRxCP | TCTRxCP; + uap->curregs[R14] = 0; /* BRG off */ + uap->curregs[R12] = 0; + uap->curregs[R13] = 0; + uap->flags |= PMACZILOG_FLAG_IS_EXTCLK; + } else { + switch (baud) { + case ZS_CLOCK/16: /* 230400 */ + uap->curregs[R4] = X16CLK; + uap->curregs[R11] = 0; + uap->curregs[R14] = 0; + break; + case ZS_CLOCK/32: /* 115200 */ + uap->curregs[R4] = X32CLK; + uap->curregs[R11] = 0; + uap->curregs[R14] = 0; + break; + default: + uap->curregs[R4] = X16CLK; + uap->curregs[R11] = TCBR | RCBR; + brg = BPS_TO_BRG(baud, ZS_CLOCK / 16); + uap->curregs[R12] = (brg & 255); + uap->curregs[R13] = ((brg >> 8) & 255); + uap->curregs[R14] = BRENAB; + } + uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK; } /* Character size, stop bits, and parity. */ - up->curregs[3] &= ~RxN_MASK; - up->curregs[5] &= ~TxN_MASK; + uap->curregs[3] &= ~RxN_MASK; + uap->curregs[5] &= ~TxN_MASK; switch (cflag & CSIZE) { case CS5: - up->curregs[3] |= Rx5; - up->curregs[5] |= Tx5; - up->parity_mask = 0x1f; + uap->curregs[3] |= Rx5; + uap->curregs[5] |= Tx5; + uap->parity_mask = 0x1f; break; case CS6: - up->curregs[3] |= Rx6; - up->curregs[5] |= Tx6; - up->parity_mask = 0x3f; + uap->curregs[3] |= Rx6; + uap->curregs[5] |= Tx6; + uap->parity_mask = 0x3f; break; case CS7: - up->curregs[3] |= Rx7; - up->curregs[5] |= Tx7; - up->parity_mask = 0x7f; + uap->curregs[3] |= Rx7; + uap->curregs[5] |= Tx7; + uap->parity_mask = 0x7f; break; case CS8: default: - up->curregs[3] |= Rx8; - up->curregs[5] |= Tx8; - up->parity_mask = 0xff; + uap->curregs[3] |= Rx8; + uap->curregs[5] |= Tx8; + uap->parity_mask = 0xff; break; }; - up->curregs[4] &= ~(SB_MASK); + uap->curregs[4] &= ~(SB_MASK); if (cflag & CSTOPB) - up->curregs[4] |= SB2; + uap->curregs[4] |= SB2; else - up->curregs[4] |= SB1; + uap->curregs[4] |= SB1; if (cflag & PARENB) - up->curregs[4] |= PAR_ENAB; + uap->curregs[4] |= PAR_ENAB; else - up->curregs[4] &= ~PAR_ENAB; + uap->curregs[4] &= ~PAR_ENAB; if (!(cflag & PARODD)) - up->curregs[4] |= PAR_EVEN; + uap->curregs[4] |= PAR_EVEN; else - up->curregs[4] &= ~PAR_EVEN; + uap->curregs[4] &= ~PAR_EVEN; - up->port.read_status_mask = Rx_OVR; + uap->port.read_status_mask = Rx_OVR; if (iflag & INPCK) - up->port.read_status_mask |= CRC_ERR | PAR_ERR; + uap->port.read_status_mask |= CRC_ERR | PAR_ERR; if (iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= BRK_ABRT; + uap->port.read_status_mask |= BRK_ABRT; - up->port.ignore_status_mask = 0; + uap->port.ignore_status_mask = 0; if (iflag & IGNPAR) - up->port.ignore_status_mask |= CRC_ERR | PAR_ERR; + uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR; if (iflag & IGNBRK) { - up->port.ignore_status_mask |= BRK_ABRT; + uap->port.ignore_status_mask |= BRK_ABRT; if (iflag & IGNPAR) - up->port.ignore_status_mask |= Rx_OVR; + uap->port.ignore_status_mask |= Rx_OVR; } if ((cflag & CREAD) == 0) - up->port.ignore_status_mask = 0xff; + uap->port.ignore_status_mask = 0xff; } -static void pmz_irda_rts_pulses(struct uart_pmac_port *up, int w) -{ - udelay(w); - write_zsreg(up, 5, Tx8 | TxENABLE); - zssync(up); - udelay(2); - write_zsreg(up, 5, Tx8 | TxENABLE | RTS); - zssync(up); - udelay(8); - write_zsreg(up, 5, Tx8 | TxENABLE); - zssync(up); - udelay(4); - write_zsreg(up, 5, Tx8 | TxENABLE | RTS); - zssync(up); -} /* * Set the irda codec on the imac to the specified baud rate. */ -static void pmz_irda_setup(struct uart_pmac_port *up, int cflags) +static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) { - int code, speed, t; + u8 cmdbyte; + int t, version; - speed = cflags & CBAUD; - if (speed < B2400 || speed > B115200) - return; - code = 0x4d + B115200 - speed; - - /* disable serial interrupts and receive DMA */ - write_zsreg(up, 1, up->curregs[1] & ~0x9f); + switch (*baud) { + /* SIR modes */ + case 2400: + cmdbyte = 0x53; + break; + case 4800: + cmdbyte = 0x52; + break; + case 9600: + cmdbyte = 0x51; + break; + case 19200: + cmdbyte = 0x50; + break; + case 38400: + cmdbyte = 0x4f; + break; + case 57600: + cmdbyte = 0x4e; + break; + case 115200: + cmdbyte = 0x4d; + break; + /* The FIR modes aren't really supported at this point, how + * do we select the speed ? via the FCR on KeyLargo ? + */ + case 1152000: + cmdbyte = 0; + break; + case 4000000: + cmdbyte = 0; + break; + default: /* 9600 */ + cmdbyte = 0x51; + *baud = 9600; + break; + } - /* wait for transmitter to drain */ + /* Wait for transmitter to drain */ t = 10000; - while ((read_zsreg(up, R0) & Tx_BUF_EMP) == 0 - || (read_zsreg(up, R1) & ALL_SNT) == 0) { + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0 + || (read_zsreg(uap, R1) & ALL_SNT) == 0) { if (--t <= 0) { - printk(KERN_ERR "transmitter didn't drain\n"); + dev_err(&uap->dev->ofdev.dev, "transmitter didn't drain\n"); return; } udelay(10); } - udelay(100); - /* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */ - write_zsreg(up, R4, X16CLK | SB1); - write_zsreg(up, R11, TCBR | RCBR); - t = BPS_TO_BRG(19200, ZS_CLOCK/16); - write_zsreg(up, R12, t); - write_zsreg(up, R13, t >> 8); - write_zsreg(up, R14, BRENAB); - write_zsreg(up, R3, Rx8 | RxENABLE); - write_zsreg(up, R5, Tx8 | TxENABLE | RTS); - zssync(up); - - /* set TxD low for ~104us and pulse RTS */ - udelay(1000); - write_zsdata(up, 0xfe); - pmz_irda_rts_pulses(up, 150); - pmz_irda_rts_pulses(up, 180); - pmz_irda_rts_pulses(up, 50); - udelay(100); - - /* assert DTR, wait 30ms, talk to the chip */ - write_zsreg(up, R5, Tx8 | TxENABLE | RTS | DTR); - zssync(up); - mdelay(30); - while (read_zsreg(up, R0) & Rx_CH_AV) - read_zsdata(up); - - write_zsdata(up, 1); - t = 1000; - while ((read_zsreg(up, R0) & Rx_CH_AV) == 0) { + /* Drain the receiver too */ + t = 100; + (void)read_zsdata(uap); + (void)read_zsdata(uap); + (void)read_zsdata(uap); + mdelay(10); + while (read_zsreg(uap, R0) & Rx_CH_AV) { + read_zsdata(uap); + mdelay(10); if (--t <= 0) { - printk(KERN_ERR "irda_setup timed out on 1st byte\n"); + dev_err(&uap->dev->ofdev.dev, "receiver didn't drain\n"); + return; + } + } + + /* Switch to command mode */ + uap->curregs[R5] |= DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + mdelay(1); + + /* Switch SCC to 19200 */ + pmz_convert_to_zs(uap, CS8, 0, 19200); + pmz_load_zsregs(uap, uap->curregs); + mdelay(1); + + /* Write get_version command byte */ + write_zsdata(uap, 1); + t = 5000; + while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { + if (--t <= 0) { + dev_err(&uap->dev->ofdev.dev, + "irda_setup timed out on get_version byte\n"); goto out; } udelay(10); } - t = read_zsdata(up); - if (t != 4) - printk(KERN_ERR "irda_setup 1st byte = %x\n", t); - - write_zsdata(up, code); - t = 1000; - while ((read_zsreg(up, R0) & Rx_CH_AV) == 0) { + version = read_zsdata(uap); + + if (version < 4) { + dev_info(&uap->dev->ofdev.dev, "IrDA: dongle version %d not supported\n", + version); + goto out; + } + + /* Send speed mode */ + write_zsdata(uap, cmdbyte); + t = 5000; + while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { if (--t <= 0) { - printk(KERN_ERR "irda_setup timed out on 2nd byte\n"); + dev_err(&uap->dev->ofdev.dev, + "irda_setup timed out on speed mode byte\n"); goto out; } udelay(10); } - t = read_zsdata(up); - if (t != code) - printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code); + t = read_zsdata(uap); + if (t != cmdbyte) + dev_err(&uap->dev->ofdev.dev, + "irda_setup speed mode byte = %x (%x)\n", t, cmdbyte); + + dev_info(&uap->dev->ofdev.dev, "IrDA setup for %ld bps, dongle version: %d\n", + *baud, version); + + (void)read_zsdata(uap); + (void)read_zsdata(uap); + (void)read_zsdata(uap); - /* Drop DTR again and do some more RTS pulses */ out: - udelay(100); - write_zsreg(up, R5, Tx8 | TxENABLE | RTS); - pmz_irda_rts_pulses(up, 80); - - /* We should be right to go now. We assume that load_zsregs - will get called soon to load up the correct baud rate etc. */ - up->curregs[R5] = (up->curregs[R5] | RTS) & ~DTR; + /* Switch back to data mode */ + uap->curregs[R5] &= ~DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + + (void)read_zsdata(uap); + (void)read_zsdata(uap); + (void)read_zsdata(uap); } -/* The port lock is not held. */ -static void -pmz_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) -{ - struct uart_pmac_port *up = to_pmz(port); - unsigned long flags; - int baud; - pr_debug("pmz: set_termios()\n"); +static void __pmz_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned long baud; - baud = uart_get_baud_rate(port, termios, old, 1200, 230400); + pmz_debug("pmz: set_termios()\n"); - spin_lock_irqsave(&up->port.lock, flags); + if (ZS_IS_ASLEEP(uap)) + return; - pmz_convert_to_zs(up, termios->c_cflag, termios->c_iflag, baud); + memcpy(&uap->termios_cache, termios, sizeof(struct termios)); - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) { - up->curregs[R15] |= DCDIE | SYNCIE | CTSIE; - up->flags |= PMACZILOG_FLAG_MODEM_STATUS; + /* XXX Check which revs of machines actually allow 1 and 4Mb speeds + * on the IR dongle. Note that the IRTTY driver currently doesn't know + * about the FIR mode and high speed modes. So these are unused. For + * implementing proper support for these, we should probably add some + * DMA as well, at least on the Rx side, which isn't a simple thing + * at this point. + */ + if (ZS_IS_IRDA(uap)) { + /* Calc baud rate */ + baud = uart_get_baud_rate(port, termios, old, 1200, 4000000); + pmz_debug("pmz: switch IRDA to %ld bauds\n", baud); + /* Cet the irda codec to the right rate */ + pmz_irda_setup(uap, &baud); + /* Set final baud rate */ + pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud); + pmz_load_zsregs(uap, uap->curregs); + zssync(uap); } else { - up->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE); - up->flags &= ~PMACZILOG_FLAG_MODEM_STATUS; - } + baud = uart_get_baud_rate(port, termios, old, 1200, 230400); + pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud); + /* Make sure modem status interrupts are correctly configured */ + if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) { + uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE; + uap->flags |= PMACZILOG_FLAG_MODEM_STATUS; + } else { + uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE); + uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS; + } - /* set the irda codec to the right rate */ - if (ZS_IS_IRDA(up)) - pmz_irda_setup(up, termios->c_cflag); + /* Load registers to the chip */ + pmz_maybe_update_regs(uap); + } + pmz_debug("pmz: set_termios() done.\n"); +} - /* Load registers to the chip */ - pmz_maybe_update_regs(up); +/* The port lock is not held. */ +static void pmz_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned long flags; - spin_unlock_irqrestore(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); - pr_debug("pmz: set_termios() done.\n"); + /* Disable IRQs on the port */ + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + write_zsreg(uap, R1, uap->curregs[R1]); + + /* Setup new port configuration */ + __pmz_set_termios(port, termios, old); + + /* Re-enable IRQs on the port */ + if (ZS_IS_OPEN(uap)) { + uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[R1] |= EXT_INT_ENAB; + write_zsreg(uap, R1, uap->curregs[R1]); + } + spin_unlock_irqrestore(&port->lock, flags); } static const char *pmz_type(struct uart_port *port) { - return "PowerMac Zilog"; + struct uart_pmac_port *uap = to_pmz(port); + + if (ZS_IS_IRDA(uap)) + return "Z85c30 ESCC - Infrared port"; + else if (ZS_IS_INTMODEM(uap)) + return "Z85c30 ESCC - Internal modem"; + return "Z85c30 ESCC - Serial port"; } /* We do not request/release mappings of the registers here, this @@ -1121,9 +1395,9 @@ * Unlike sunzilog, we don't need to pre-init the spinlock as we don't * register our console before uart_add_one_port() is called */ -static int __init pmz_init_port(struct uart_pmac_port *up) +static int __init pmz_init_port(struct uart_pmac_port *uap) { - struct device_node *np = up->node; + struct device_node *np = uap->node; char *conn; struct slot_names_prop { int count; @@ -1134,35 +1408,35 @@ /* * Request & map chip registers */ - up->port.mapbase = np->addrs[0].address; - up->port.membase = ioremap(up->port.mapbase, 0x1000); + uap->port.mapbase = np->addrs[0].address; + uap->port.membase = ioremap(uap->port.mapbase, 0x1000); - up->control_reg = (volatile u8 *)up->port.membase; - up->data_reg = up->control_reg + 0x10; + uap->control_reg = (volatile u8 *)uap->port.membase; + uap->data_reg = uap->control_reg + 0x10; /* * Request & map DBDMA registers */ #ifdef HAS_DBDMA if (np->n_addrs >= 3 && np->n_intrs >= 3) - up->flags |= PMACZILOG_FLAG_HAS_DMA; + uap->flags |= PMACZILOG_FLAG_HAS_DMA; #endif - if (ZS_HAS_DMA(up)) { - up->tx_dma_regs = (volatile struct dbdma_regs *) + if (ZS_HAS_DMA(uap)) { + uap->tx_dma_regs = (volatile struct dbdma_regs *) ioremap(np->addrs[np->n_addrs - 2].address, 0x1000); - if (up->tx_dma_regs == NULL) { - up->flags &= ~PMACZILOG_FLAG_HAS_DMA; + if (uap->tx_dma_regs == NULL) { + uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; goto no_dma; } - up->rx_dma_regs = (volatile struct dbdma_regs *) + uap->rx_dma_regs = (volatile struct dbdma_regs *) ioremap(np->addrs[np->n_addrs - 1].address, 0x1000); - if (up->rx_dma_regs == NULL) { - iounmap((void *)up->tx_dma_regs); - up->flags &= ~PMACZILOG_FLAG_HAS_DMA; + if (uap->rx_dma_regs == NULL) { + iounmap((void *)uap->tx_dma_regs); + uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; goto no_dma; } - up->tx_dma_irq = np->intrs[1].line; - up->rx_dma_irq = np->intrs[2].line; + uap->tx_dma_irq = np->intrs[1].line; + uap->rx_dma_irq = np->intrs[2].line; } no_dma: @@ -1170,22 +1444,22 @@ * Detect port type */ if (device_is_compatible(np, "cobalt")) - up->flags |= PMACZILOG_FLAG_IS_INTMODEM; + uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; conn = get_property(np, "AAPL,connector", &len); if (conn && (strcmp(conn, "infrared") == 0)) - up->flags |= PMACZILOG_FLAG_IS_IRDA; - up->port_type = PMAC_SCC_ASYNC; + uap->flags |= PMACZILOG_FLAG_IS_IRDA; + uap->port_type = PMAC_SCC_ASYNC; /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(np, "slot-names", &len); if (slots && slots->count > 0) { if (strcmp(slots->name, "IrDA") == 0) - up->flags |= PMACZILOG_FLAG_IS_IRDA; + uap->flags |= PMACZILOG_FLAG_IS_IRDA; else if (strcmp(slots->name, "Modem") == 0) - up->flags |= PMACZILOG_FLAG_IS_INTMODEM; + uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; } - if (ZS_IS_IRDA(up)) - up->port_type = PMAC_SCC_IRDA; - if (ZS_IS_INTMODEM(up)) { + if (ZS_IS_IRDA(uap)) + uap->port_type = PMAC_SCC_IRDA; + if (ZS_IS_INTMODEM(uap)) { struct device_node* i2c_modem = find_devices("i2c-modem"); if (i2c_modem) { char* mid = get_property(i2c_modem, "modem-id", NULL); @@ -1196,7 +1470,7 @@ case 0x08 : case 0x0b : case 0x0c : - up->port_type = PMAC_SCC_I2S1; + uap->port_type = PMAC_SCC_I2S1; } printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n", mid ? (*mid) : 0); @@ -1208,13 +1482,19 @@ /* * Init remaining bits of "port" structure */ - up->port.iotype = SERIAL_IO_MEM; - up->port.irq = np->intrs[0].line; - up->port.uartclk = ZS_CLOCK; - up->port.fifosize = 1; - up->port.ops = &pmz_pops; - up->port.type = PORT_PMAC_ZILOG; - up->port.flags = 0; + uap->port.iotype = SERIAL_IO_MEM; + uap->port.irq = np->intrs[0].line; + uap->port.uartclk = ZS_CLOCK; + uap->port.fifosize = 1; + uap->port.ops = &pmz_pops; + uap->port.type = PORT_PMAC_ZILOG; + uap->port.flags = 0; + + /* Setup some valid baud rate information in the register + * shadows so we don't write crap there before baud rate is + * first initialized. + */ + pmz_convert_to_zs(uap, CS8, 0, 9600); return 0; } @@ -1222,13 +1502,13 @@ /* * Get rid of a port on module removal */ -static void pmz_dispose_port(struct uart_pmac_port *up) +static void pmz_dispose_port(struct uart_pmac_port *uap) { struct device_node *np; - iounmap((void *)up->control_reg); - np = up->node; - up->node = NULL; + iounmap((void *)uap->control_reg); + np = uap->node; + uap->node = NULL; of_node_put(np); } @@ -1243,15 +1523,16 @@ */ for (i = 0; i < MAX_ZS_PORTS; i++) if (pmz_ports[i].node == mdev->ofdev.node) { - struct uart_pmac_port *up = &pmz_ports[i]; + struct uart_pmac_port *uap = &pmz_ports[i]; - up->dev = mdev; - dev_set_drvdata(&mdev->ofdev.dev, up); - if (macio_request_resources(up->dev, "pmac_zilog")) - printk(KERN_WARNING "%s: Failed to request resource, port still active\n", - up->node->name); + uap->dev = mdev; + dev_set_drvdata(&mdev->ofdev.dev, uap); + if (macio_request_resources(uap->dev, "pmac_zilog")) + printk(KERN_WARNING "%s: Failed to request resource" + ", port still active\n", + uap->node->name); else - up->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; + uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; return 0; } return -ENODEV; @@ -1263,18 +1544,135 @@ */ static int pmz_detach(struct macio_dev *mdev) { - struct uart_pmac_port *up = dev_get_drvdata(&mdev->ofdev.dev); + struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - if (!up) + if (!uap) return -ENODEV; - if (up->flags & PMACZILOG_FLAG_RSRC_REQUESTED) { - macio_release_resources(up->dev); - up->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED; + if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) { + macio_release_resources(uap->dev); + uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED; } dev_set_drvdata(&mdev->ofdev.dev, NULL); - up->dev = NULL; + uap->dev = NULL; + + return 0; +} + + +static int pmz_suspend(struct macio_dev *mdev, u32 pm_state) +{ + struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); + struct uart_state *state = pmz_uart_reg.state + uap->port.line; + unsigned long flags; + + if (uap == NULL) + return 0; + + if (pm_state == mdev->ofdev.dev.power_state || pm_state < 2) + return 0; + + down(&pmz_irq_sem); + down(&state->sem); + + spin_lock_irqsave(&uap->port.lock, flags); + + if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) { + /* Disable receiver and transmitter. */ + uap->curregs[R3] &= ~RxENABLE; + uap->curregs[R5] &= ~TxENABLE; + + /* Disable all interrupts and BRK assertion. */ + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + uap->curregs[R5] &= ~SND_BRK; + pmz_load_zsregs(uap, uap->curregs); + uap->flags |= PMACZILOG_FLAG_IS_ASLEEP; + mb(); + } + + spin_unlock_irqrestore(&uap->port.lock, flags); + + if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate)) + if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { + pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; + disable_irq(uap->port.irq); + } + + if (ZS_IS_CONS(uap)) + uap->port.cons->flags &= ~CON_ENABLED; + + /* Shut the chip down */ + pmz_set_scc_power(uap, 0); + + up(&state->sem); + up(&pmz_irq_sem); + + mdev->ofdev.dev.power_state = pm_state; + + return 0; +} + + +static int pmz_resume(struct macio_dev *mdev) +{ + struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); + struct uart_state *state = pmz_uart_reg.state + uap->port.line; + unsigned long flags; + int pwr_delay; + + if (uap == NULL) + return 0; + + if (mdev->ofdev.dev.power_state == 0) + return 0; + down(&pmz_irq_sem); + down(&state->sem); + + spin_lock_irqsave(&uap->port.lock, flags); + if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) { + spin_unlock_irqrestore(&uap->port.lock, flags); + goto bail; + } + pwr_delay = __pmz_startup(uap); + + /* Take care of config that may have changed while asleep */ + __pmz_set_termios(&uap->port, &uap->termios_cache, NULL); + + if (ZS_IS_OPEN(uap)) { + /* Enable interrupts */ + uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[R1] |= EXT_INT_ENAB; + write_zsreg(uap, R1, uap->curregs[R1]); + } + + spin_unlock_irqrestore(&uap->port.lock, flags); + + if (ZS_IS_CONS(uap)) + uap->port.cons->flags |= CON_ENABLED; + + /* Re-enable IRQ on the controller */ + if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { + pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; + enable_irq(uap->port.irq); + } + + up(&state->sem); + up(&pmz_irq_sem); + + /* Right now, we deal with delay by blocking here, I'll be + * smarter later on + */ + if (pwr_delay != 0) { + pmz_debug("pmz: delaying %d ms\n", pwr_delay); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((pwr_delay * HZ)/1000); + } + + bail: + mdev->ofdev.dev.power_state = 0; + return 0; } @@ -1307,7 +1705,7 @@ else if (strncmp(np->name, "ch-b", 4) == 0) node_b = of_node_get(np); } - if (!node_a || !node_b) { + if (!node_a && !node_b) { of_node_put(node_a); of_node_put(node_b); printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n", @@ -1330,7 +1728,7 @@ * Setup the ports for real */ rc = pmz_init_port(&pmz_ports[count]); - if (rc == 0) + if (rc == 0 && node_b != NULL) rc = pmz_init_port(&pmz_ports[count+1]); if (rc != 0) { of_node_put(node_a); @@ -1348,14 +1746,6 @@ return 0; } -static struct uart_driver pmz_uart_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyS", - .devfs_name = "tts/", - .dev_name = "ttyS", - .major = TTY_MAJOR, -}; - #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE static void pmz_console_write(struct console *con, const char *s, unsigned int count); @@ -1400,6 +1790,7 @@ */ for (i = 0; i < pmz_ports_count; i++) { struct uart_pmac_port *uport = &pmz_ports[i]; + /* NULL node may happen on wallstreet */ if (uport->node != NULL) uart_add_one_port(&pmz_uart_reg, &uport->port); } @@ -1428,13 +1819,13 @@ .match_table = pmz_match, .probe = pmz_attach, .remove = pmz_detach, -// .suspend = pmz_suspend, *** NYI -// .resume = pmz_resume, *** NYI + .suspend = pmz_suspend, + .resume = pmz_resume, }; static int __init init_pmz(void) { - printk(KERN_DEBUG "%s\n", version); + printk(KERN_INFO "%s\n", version); /* * First, we need to do a direct OF-based probe pass. We @@ -1490,33 +1881,33 @@ */ static void pmz_console_write(struct console *con, const char *s, unsigned int count) { - struct uart_pmac_port *up = &pmz_ports[con->index]; + struct uart_pmac_port *uap = &pmz_ports[con->index]; unsigned long flags; int i; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&uap->port.lock, flags); /* Turn of interrupts and enable the transmitter. */ - write_zsreg(up, R1, up->curregs[1] & ~TxINT_ENAB); - write_zsreg(up, R5, up->curregs[5] | TxENABLE | RTS | DTR); + write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB); + write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR); for (i = 0; i < count; i++) { /* Wait for the transmit buffer to empty. */ - while ((read_zsreg(up, R0) & Tx_BUF_EMP) == 0) + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) udelay(5); - write_zsdata(up, s[i]); + write_zsdata(uap, s[i]); if (s[i] == 10) { - while ((read_zsreg(up, R0) & Tx_BUF_EMP) == 0) + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) udelay(5); - write_zsdata(up, R13); + write_zsdata(uap, R13); } } /* Restore the values in the registers. */ - write_zsreg(up, R1, up->curregs[1]); + write_zsreg(uap, R1, uap->curregs[1]); /* Don't disable the transmitter. */ - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&uap->port.lock, flags); } /* @@ -1524,6 +1915,7 @@ */ static int __init pmz_console_setup(struct console *co, char *options) { + struct uart_pmac_port *uap; struct uart_port *port; int baud = 38400; int bits = 8; @@ -1535,7 +1927,8 @@ * XServe's default to 57600 bps */ if (machine_is_compatible("RackMac1,1") - || machine_is_compatible("RackMac1,2")) + || machine_is_compatible("RackMac1,2") + || machine_is_compatible("MacRISC4")) baud = 57600; /* @@ -1545,12 +1938,15 @@ */ if (co->index >= pmz_ports_count) co->index = 0; - port = &pmz_ports[co->index].port; + uap = &pmz_ports[co->index]; + if (uap->node == NULL) + return -ENODEV; + port = &uap->port; /* * Mark port as beeing a console */ - port->flags |= PMACZILOG_FLAG_IS_CONS; + uap->flags |= PMACZILOG_FLAG_IS_CONS; /* * Temporary fix for uart layer who didn't setup the spinlock yet @@ -1560,7 +1956,7 @@ /* * Enable the hardware */ - pwr_delay = __pmz_startup(&pmz_ports[co->index]); + pwr_delay = __pmz_startup(uap); if (pwr_delay) mdelay(pwr_delay); diff -urN linux-2.6.4-rc2/drivers/serial/pmac_zilog.h linux-2.6.4-rc3/drivers/serial/pmac_zilog.h --- linux-2.6.4-rc2/drivers/serial/pmac_zilog.h 2004-02-17 19:58:11.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/pmac_zilog.h 2004-03-09 16:36:28.000000000 -0800 @@ -1,6 +1,8 @@ #ifndef __PMAC_ZILOG_H__ #define __PMAC_ZILOG_H__ +#define pmz_debug(fmt,arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg) + /* * At most 2 ESCCs with 2 ports each */ @@ -9,7 +11,7 @@ /* * We wrap our port structure around the generic uart_port. */ -#define NUM_ZSREGS 16 +#define NUM_ZSREGS 17 struct uart_pmac_port { struct uart_port port; @@ -41,6 +43,10 @@ #define PMACZILOG_FLAG_IS_INTMODEM 0x00000200 #define PMACZILOG_FLAG_HAS_DMA 0x00000400 #define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800 +#define PMACZILOG_FLAG_IS_ASLEEP 0x00001000 +#define PMACZILOG_FLAG_IS_OPEN 0x00002000 +#define PMACZILOG_FLAG_IS_IRQ_ON 0x00004000 +#define PMACZILOG_FLAG_IS_EXTCLK 0x00008000 unsigned char parity_mask; unsigned char prev_status; @@ -52,10 +58,19 @@ unsigned int rx_dma_irq; volatile struct dbdma_regs *tx_dma_regs; volatile struct dbdma_regs *rx_dma_regs; + + struct termios termios_cache; }; #define to_pmz(p) ((struct uart_pmac_port *)(p)) +static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap) +{ + if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A) + return uap; + return uap->mate; +} + /* * Register acessors. Note that we don't need to enforce a recovery * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip, @@ -120,6 +135,7 @@ #define R13 13 #define R14 14 #define R15 15 +#define R7P 16 #define NULLCODE 0 /* Null Code */ #define POINT_HIGH 0x8 /* Select upper half of registers */ @@ -357,5 +373,9 @@ #define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA) #define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM) #define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA) +#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP) +#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN) +#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON) +#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK) #endif /* __PMAC_ZILOG_H__ */ diff -urN linux-2.6.4-rc2/drivers/serial/serial_core.c linux-2.6.4-rc3/drivers/serial/serial_core.c --- linux-2.6.4-rc2/drivers/serial/serial_core.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/drivers/serial/serial_core.c 2004-03-09 16:36:28.000000000 -0800 @@ -175,8 +175,6 @@ uart_circ_clear(&info->xmit); } - port->mctrl = 0; - retval = port->ops->startup(port); if (retval == 0) { if (init_hw) { @@ -1874,9 +1872,6 @@ if (flow == 'r') termios.c_cflag |= CRTSCTS; - if (!port->ops) - return 0; /* "console=" on ia64 */ - port->ops->set_termios(port, &termios, NULL); co->cflag = termios.c_cflag; diff -urN linux-2.6.4-rc2/drivers/usb/gadget/inode.c linux-2.6.4-rc3/drivers/usb/gadget/inode.c --- linux-2.6.4-rc2/drivers/usb/gadget/inode.c 2004-02-17 19:58:48.000000000 -0800 +++ linux-2.6.4-rc3/drivers/usb/gadget/inode.c 2004-03-09 16:36:28.000000000 -0800 @@ -1812,7 +1812,6 @@ return -ENOMEM; inode->i_op = &simple_dir_inode_operations; if (!(d = d_alloc_root (inode))) { -enomem: iput (inode); return -ENOMEM; } @@ -1823,12 +1822,15 @@ */ dev = dev_new (); if (!dev) - goto enomem; + return -ENOMEM; + dev->sb = sb; if (!(inode = gadgetfs_create_file (sb, CHIP, dev, &dev_init_operations, - &dev->dentry))) - goto enomem; + &dev->dentry))) { + put_dev(dev); + return -ENOMEM; + } /* other endpoint files are available after hardware setup, * from binding to a controller. @@ -1849,8 +1851,10 @@ gadgetfs_kill_sb (struct super_block *sb) { kill_litter_super (sb); - put_dev (the_device); - the_device = 0; + if (the_device) { + put_dev (the_device); + the_device = 0; + } } /*----------------------------------------------------------------------*/ diff -urN linux-2.6.4-rc2/drivers/usb/serial/safe_serial.c linux-2.6.4-rc3/drivers/usb/serial/safe_serial.c --- linux-2.6.4-rc2/drivers/usb/serial/safe_serial.c 2004-02-17 19:57:20.000000000 -0800 +++ linux-2.6.4-rc3/drivers/usb/serial/safe_serial.c 2004-03-09 16:36:28.000000000 -0800 @@ -93,6 +93,7 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_LICENSE("GPL"); #if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) #abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" diff -urN linux-2.6.4-rc2/drivers/video/aty/radeon_base.c linux-2.6.4-rc3/drivers/video/aty/radeon_base.c --- linux-2.6.4-rc2/drivers/video/aty/radeon_base.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/drivers/video/aty/radeon_base.c 2004-03-09 16:36:28.000000000 -0800 @@ -135,7 +135,7 @@ CHIP_DEF(PCI_CHIP_R200_QM, R200, CHIP_HAS_CRTC2), /* Mobility M7 */ CHIP_DEF(PCI_CHIP_RADEON_LW, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), - CHIP_DEF(PCI_CHIP_RADEON_LW, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RADEON_LX, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), /* 7500 */ CHIP_DEF(PCI_CHIP_RV200_QW, RV200, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_RV200_QX, RV200, CHIP_HAS_CRTC2), diff -urN linux-2.6.4-rc2/drivers/video/ffb.c linux-2.6.4-rc3/drivers/video/ffb.c --- linux-2.6.4-rc2/drivers/video/ffb.c 2004-02-17 20:00:00.000000000 -0800 +++ linux-2.6.4-rc3/drivers/video/ffb.c 2004-03-09 16:36:28.000000000 -0800 @@ -466,6 +466,7 @@ static void ffb_switch_from_graph(struct ffb_par *par) { struct ffb_fbc *fbc = par->fbc; + struct ffb_dac *dac = par->dac; unsigned long flags; spin_lock_irqsave(&par->lock, flags); @@ -482,6 +483,14 @@ upa_writel(par->fg_cache, &fbc->fg); upa_writel(par->bg_cache, &fbc->bg); FFBWait(par); + + /* Disable cursor. */ + upa_writel(0x100, &dac->type2); + if (par->dac_rev <= 2) + upa_writel(0, &dac->value2); + else + upa_writel(3, &dac->value2); + spin_unlock_irqrestore(&par->lock, flags); } diff -urN linux-2.6.4-rc2/fs/adfs/super.c linux-2.6.4-rc3/fs/adfs/super.c --- linux-2.6.4-rc2/fs/adfs/super.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/fs/adfs/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -333,6 +333,7 @@ struct object_info root_obj; unsigned char *b_data; struct adfs_sb_info *asb; + struct inode *root; asb = kmalloc(sizeof(*asb), GFP_KERNEL); if (!asb) @@ -443,10 +444,11 @@ asb->s_namelen = ADFS_F_NAME_LEN; } - sb->s_root = d_alloc_root(adfs_iget(sb, &root_obj)); + root = adfs_iget(sb, &root_obj); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { int i; - + iput(root); for (i = 0; i < asb->s_map_size; i++) brelse(asb->s_map[i].dm_bh); kfree(asb->s_map); diff -urN linux-2.6.4-rc2/fs/afs/super.c linux-2.6.4-rc3/fs/afs/super.c --- linux-2.6.4-rc2/fs/afs/super.c 2004-02-17 19:57:30.000000000 -0800 +++ linux-2.6.4-rc3/fs/afs/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -280,7 +280,6 @@ return 0; error: - dput(root); iput(inode); afs_put_volume(as->volume); kfree(as); diff -urN linux-2.6.4-rc2/fs/aio.c linux-2.6.4-rc3/fs/aio.c --- linux-2.6.4-rc2/fs/aio.c 2004-02-17 19:57:48.000000000 -0800 +++ linux-2.6.4-rc3/fs/aio.c 2004-03-09 16:36:28.000000000 -0800 @@ -312,7 +312,7 @@ /* wait_on_sync_kiocb: * Waits on the given sync kiocb to complete. */ -ssize_t wait_on_sync_kiocb(struct kiocb *iocb) +ssize_t fastcall wait_on_sync_kiocb(struct kiocb *iocb) { while (iocb->ki_users) { set_current_state(TASK_UNINTERRUPTIBLE); @@ -331,7 +331,7 @@ * go away, they will call put_ioctx and release any pinned memory * associated with the request (held via struct page * references). */ -void exit_aio(struct mm_struct *mm) +void fastcall exit_aio(struct mm_struct *mm) { struct kioctx *ctx = mm->ioctx_list; mm->ioctx_list = NULL; @@ -356,7 +356,7 @@ * Called when the last user of an aio context has gone away, * and the struct needs to be freed. */ -void __put_ioctx(struct kioctx *ctx) +void fastcall __put_ioctx(struct kioctx *ctx) { unsigned nr_events = ctx->max_reqs; @@ -383,7 +383,7 @@ * req (after submitting it) and aio_complete() freeing the req. */ static struct kiocb *FASTCALL(__aio_get_req(struct kioctx *ctx)); -static struct kiocb *__aio_get_req(struct kioctx *ctx) +static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) { struct kiocb *req = NULL; struct aio_ring *ring; @@ -509,7 +509,7 @@ * Returns true if this put was the last user of the kiocb, * false if the request is still in use. */ -int aio_put_req(struct kiocb *req) +int fastcall aio_put_req(struct kiocb *req) { struct kioctx *ctx = req->ki_ctx; int ret; @@ -596,7 +596,7 @@ unuse_mm(ctx->mm); } -void kick_iocb(struct kiocb *iocb) +void fastcall kick_iocb(struct kiocb *iocb) { struct kioctx *ctx = iocb->ki_ctx; @@ -622,7 +622,7 @@ * Returns true if this is the last user of the request. The * only other user of the request can be the cancellation code. */ -int aio_complete(struct kiocb *iocb, long res, long res2) +int fastcall aio_complete(struct kiocb *iocb, long res, long res2) { struct kioctx *ctx = iocb->ki_ctx; struct aio_ring_info *info; @@ -985,7 +985,7 @@ return -EINVAL; } -int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, +int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, struct iocb *iocb) { struct kiocb *req; diff -urN linux-2.6.4-rc2/fs/autofs4/inode.c linux-2.6.4-rc3/fs/autofs4/inode.c --- linux-2.6.4-rc2/fs/autofs4/inode.c 2004-02-17 19:58:50.000000000 -0800 +++ linux-2.6.4-rc3/fs/autofs4/inode.c 2004-03-09 16:36:28.000000000 -0800 @@ -213,6 +213,9 @@ * Get the root inode and dentry, but defer checking for errors. */ root_inode = autofs4_get_inode(s, autofs4_mkroot(sbi)); + if (!root_inode) + goto fail_free; + root_inode->i_op = &autofs4_root_inode_operations; root_inode->i_fop = &autofs4_root_operations; root = d_alloc_root(root_inode); @@ -264,22 +267,13 @@ */ fail_fput: printk("autofs: pipe file descriptor does not contain proper ops\n"); - /* - * fput() can block, so we clear the super block first. - */ fput(pipe); /* fall through */ fail_dput: - /* - * dput() can block, so we clear the super block first. - */ dput(root); goto fail_free; fail_iput: printk("autofs: get root dentry failed\n"); - /* - * iput() can block, so we clear the super block first. - */ iput(root_inode); fail_free: kfree(sbi); diff -urN linux-2.6.4-rc2/fs/befs/linuxvfs.c linux-2.6.4-rc3/fs/befs/linuxvfs.c --- linux-2.6.4-rc2/fs/befs/linuxvfs.c 2004-02-17 19:57:40.000000000 -0800 +++ linux-2.6.4-rc3/fs/befs/linuxvfs.c 2004-03-09 16:36:28.000000000 -0800 @@ -789,6 +789,7 @@ struct buffer_head *bh; befs_sb_info *befs_sb; befs_super_block *disk_sb; + struct inode *root; const unsigned long sb_block = 0; const off_t x86_sb_off = 512; @@ -863,9 +864,10 @@ /* Set real blocksize of fs */ sb_set_blocksize(sb, (ulong) befs_sb->block_size); sb->s_op = (struct super_operations *) &befs_sops; - sb->s_root = - d_alloc_root(iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)))); + root = iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { + iput(root); befs_error(sb, "get root inode failed"); goto unaquire_priv_sbp; } diff -urN linux-2.6.4-rc2/fs/buffer.c linux-2.6.4-rc3/fs/buffer.c --- linux-2.6.4-rc2/fs/buffer.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/buffer.c 2004-03-09 16:36:28.000000000 -0800 @@ -97,7 +97,7 @@ } EXPORT_SYMBOL(wake_up_buffer); -void unlock_buffer(struct buffer_head *bh) +void fastcall unlock_buffer(struct buffer_head *bh) { /* * unlock_buffer against a zero-count bh is a bug, if the page @@ -404,7 +404,7 @@ struct inode *bd_inode = bdev->bd_inode; struct address_space *bd_mapping = bd_inode->i_mapping; struct buffer_head *ret = NULL; - unsigned long index; + pgoff_t index; struct buffer_head *bh; struct buffer_head *head; struct page *page; @@ -1093,7 +1093,7 @@ */ static void init_page_buffers(struct page *page, struct block_device *bdev, - int block, int size) + sector_t block, int size) { struct buffer_head *head = page_buffers(page); struct buffer_head *bh = head; @@ -1121,8 +1121,8 @@ * This is user purely for blockdev mappings. */ static struct page * -grow_dev_page(struct block_device *bdev, unsigned long block, - unsigned long index, int size) +grow_dev_page(struct block_device *bdev, sector_t block, + pgoff_t index, int size) { struct inode *inode = bdev->bd_inode; struct page *page; @@ -1178,10 +1178,10 @@ * grow_dev_page() will go BUG() if this happens. */ static inline int -grow_buffers(struct block_device *bdev, unsigned long block, int size) +grow_buffers(struct block_device *bdev, sector_t block, int size) { struct page *page; - unsigned long index; + pgoff_t index; int sizebits; /* Size must be multiple of hard sectorsize */ @@ -1256,7 +1256,7 @@ * mark_buffer_dirty() is atomic. It takes bh->b_page->mapping->private_lock, * mapping->page_lock and the global inode_lock. */ -void mark_buffer_dirty(struct buffer_head *bh) +void fastcall mark_buffer_dirty(struct buffer_head *bh) { if (!buffer_uptodate(bh)) buffer_error(); @@ -1738,8 +1738,8 @@ get_block_t *get_block, struct writeback_control *wbc) { int err; - unsigned long block; - unsigned long last_block; + sector_t block; + sector_t last_block; struct buffer_head *bh, *head; int nr_underway = 0; @@ -2207,7 +2207,7 @@ struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; struct page *new_page; - unsigned long pgpos; + pgoff_t pgpos; long status; unsigned zerofrom; unsigned blocksize = 1 << inode->i_blkbits; @@ -2317,6 +2317,28 @@ return 0; } + +/* + * nobh_prepare_write()'s prereads are special: the buffer_heads are freed + * immediately, while under the page lock. So it needs a special end_io + * handler which does not touch the bh after unlocking it. + * + * Note: unlock_buffer() sort-of does touch the bh after unlocking it, but + * a race there is benign: unlock_buffer() only use the bh's address for + * hashing after unlocking the buffer, so it doesn't actually touch the bh + * itself. + */ +static void end_buffer_read_nobh(struct buffer_head *bh, int uptodate) +{ + if (uptodate) { + set_buffer_uptodate(bh); + } else { + /* This happens, due to failed READA attempts. */ + clear_buffer_uptodate(bh); + } + unlock_buffer(bh); +} + /* * On entry, the page is fully not uptodate. * On exit the page is fully uptodate in the areas outside (from,to) @@ -2408,12 +2430,25 @@ } if (nr_reads) { - ll_rw_block(READ, nr_reads, read_bh); + struct buffer_head *bh; + + /* + * The page is locked, so these buffers are protected from + * any VM or truncate activity. Hence we don't need to care + * for the buffer_head refcounts. + */ + for (i = 0; i < nr_reads; i++) { + bh = read_bh[i]; + lock_buffer(bh); + bh->b_end_io = end_buffer_read_nobh; + submit_bh(READ, bh); + } for (i = 0; i < nr_reads; i++) { - wait_on_buffer(read_bh[i]); - if (!buffer_uptodate(read_bh[i])) + bh = read_bh[i]; + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) ret = -EIO; - free_buffer_head(read_bh[i]); + free_buffer_head(bh); read_bh[i] = NULL; } if (ret) @@ -2512,9 +2547,11 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t *get_block) { - unsigned long index = from >> PAGE_CACHE_SHIFT; + pgoff_t index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); - unsigned blocksize, iblock, length, pos; + unsigned blocksize; + pgoff_t iblock; + unsigned length, pos; struct inode *inode = mapping->host; struct page *page; struct buffer_head *bh; @@ -2594,7 +2631,7 @@ { struct inode * const inode = page->mapping->host; loff_t i_size = i_size_read(inode); - const unsigned long end_index = i_size >> PAGE_CACHE_SHIFT; + const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; void *kaddr; diff -urN linux-2.6.4-rc2/fs/coda/inode.c linux-2.6.4-rc3/fs/coda/inode.c --- linux-2.6.4-rc2/fs/coda/inode.c 2004-02-17 19:57:58.000000000 -0800 +++ linux-2.6.4-rc3/fs/coda/inode.c 2004-03-09 16:36:28.000000000 -0800 @@ -195,6 +195,8 @@ printk("coda_read_super: rootinode is %ld dev %s\n", root->i_ino, root->i_sb->s_id); sb->s_root = d_alloc_root(root); + if (!sb->s_root) + goto error; return 0; error: diff -urN linux-2.6.4-rc2/fs/cramfs/inode.c linux-2.6.4-rc3/fs/cramfs/inode.c --- linux-2.6.4-rc2/fs/cramfs/inode.c 2004-02-17 19:57:13.000000000 -0800 +++ linux-2.6.4-rc3/fs/cramfs/inode.c 2004-03-09 16:36:28.000000000 -0800 @@ -199,6 +199,7 @@ struct cramfs_super super; unsigned long root_offset; struct cramfs_sb_info *sbi; + struct inode *root; sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); if (!sbi) @@ -263,7 +264,14 @@ /* Set it all up.. */ sb->s_op = &cramfs_ops; - sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); + root = get_cramfs_inode(sb, &super.root); + if (!root) + goto out; + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + iput(root); + goto out; + } return 0; out: kfree(sbi); diff -urN linux-2.6.4-rc2/fs/efs/super.c linux-2.6.4-rc3/fs/efs/super.c --- linux-2.6.4-rc2/fs/efs/super.c 2004-02-17 19:59:11.000000000 -0800 +++ linux-2.6.4-rc3/fs/efs/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -210,6 +210,7 @@ { struct efs_sb_info *sb; struct buffer_head *bh; + struct inode *root; sb = kmalloc(sizeof(struct efs_sb_info), GFP_KERNEL); if (!sb) @@ -266,10 +267,12 @@ s->s_flags |= MS_RDONLY; } s->s_op = &efs_superblock_operations; - s->s_root = d_alloc_root(iget(s, EFS_ROOTINODE)); + root = iget(s, EFS_ROOTINODE); + s->s_root = d_alloc_root(root); if (!(s->s_root)) { printk(KERN_ERR "EFS: get root inode failed\n"); + iput(root); goto out_no_fs; } diff -urN linux-2.6.4-rc2/fs/ext2/ialloc.c linux-2.6.4-rc3/fs/ext2/ialloc.c --- linux-2.6.4-rc2/fs/ext2/ialloc.c 2004-02-17 19:57:59.000000000 -0800 +++ linux-2.6.4-rc3/fs/ext2/ialloc.c 2004-03-09 16:36:28.000000000 -0800 @@ -431,8 +431,8 @@ * That failed: try linear search for a free inode, even if that group * has no free blocks. */ - group = parent_group + 1; - for (i = 2; i < ngroups; i++) { + group = parent_group; + for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; desc = ext2_get_group_desc (sb, group, &bh); diff -urN linux-2.6.4-rc2/fs/ext2/super.c linux-2.6.4-rc3/fs/ext2/super.c --- linux-2.6.4-rc2/fs/ext2/super.c 2004-02-17 19:58:37.000000000 -0800 +++ linux-2.6.4-rc3/fs/ext2/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -563,6 +563,7 @@ struct buffer_head * bh; struct ext2_sb_info * sbi; struct ext2_super_block * es; + struct inode *root; unsigned long block, sb_block = 1; unsigned long logic_sb_block = get_sb_block(&data); unsigned long offset = 0; @@ -815,15 +816,17 @@ */ sb->s_op = &ext2_sops; sb->s_export_op = &ext2_export_ops; - sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); - if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) || - !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) { - if (sb->s_root) { - dput(sb->s_root); - sb->s_root = NULL; - printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); - } else - printk(KERN_ERR "EXT2-fs: get root inode failed\n"); + root = iget(sb, EXT2_ROOT_INO); + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + iput(root); + printk(KERN_ERR "EXT2-fs: get root inode failed\n"); + goto failed_mount2; + } + if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { + dput(sb->s_root); + sb->s_root = NULL; + printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); goto failed_mount2; } if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) diff -urN linux-2.6.4-rc2/fs/ext3/ialloc.c linux-2.6.4-rc3/fs/ext3/ialloc.c --- linux-2.6.4-rc2/fs/ext3/ialloc.c 2004-02-17 19:57:57.000000000 -0800 +++ linux-2.6.4-rc3/fs/ext3/ialloc.c 2004-03-09 16:36:28.000000000 -0800 @@ -398,8 +398,8 @@ * That failed: try linear search for a free inode, even if that group * has no free blocks. */ - group = parent_group + 1; - for (i = 2; i < ngroups; i++) { + group = parent_group; + for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; desc = ext3_get_group_desc (sb, group, &bh); diff -urN linux-2.6.4-rc2/fs/ext3/super.c linux-2.6.4-rc3/fs/ext3/super.c --- linux-2.6.4-rc2/fs/ext3/super.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/ext3/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -1040,6 +1040,7 @@ unsigned long offset = 0; unsigned long journal_inum = 0; unsigned long def_mount_opts; + struct inode *root; int blocksize; int hblock; int db_count; @@ -1354,16 +1355,17 @@ * so we can safely mount the rest of the filesystem now. */ - sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO)); - if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) || - !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) { - if (sb->s_root) { - dput(sb->s_root); - sb->s_root = NULL; - printk(KERN_ERR - "EXT3-fs: corrupt root inode, run e2fsck\n"); - } else - printk(KERN_ERR "EXT3-fs: get root inode failed\n"); + root = iget(sb, EXT3_ROOT_INO); + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + printk(KERN_ERR "EXT3-fs: get root inode failed\n"); + iput(root); + goto failed_mount3; + } + if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { + dput(sb->s_root); + sb->s_root = NULL; + printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n"); goto failed_mount3; } diff -urN linux-2.6.4-rc2/fs/fcntl.c linux-2.6.4-rc3/fs/fcntl.c --- linux-2.6.4-rc2/fs/fcntl.c 2004-02-17 19:58:39.000000000 -0800 +++ linux-2.6.4-rc3/fs/fcntl.c 2004-03-09 16:36:28.000000000 -0800 @@ -19,7 +19,7 @@ #include #include -void set_close_on_exec(unsigned int fd, int flag) +void fastcall set_close_on_exec(unsigned int fd, int flag) { struct files_struct *files = current->files; spin_lock(&files->file_lock); diff -urN linux-2.6.4-rc2/fs/file_table.c linux-2.6.4-rc3/fs/file_table.c --- linux-2.6.4-rc2/fs/file_table.c 2004-02-17 19:57:13.000000000 -0800 +++ linux-2.6.4-rc3/fs/file_table.c 2004-03-09 16:36:28.000000000 -0800 @@ -152,7 +152,7 @@ EXPORT_SYMBOL(close_private_file); -void fput(struct file *file) +void fastcall fput(struct file *file) { if (atomic_dec_and_test(&file->f_count)) __fput(file); @@ -163,7 +163,7 @@ /* __fput is called from task context when aio completion releases the last * last use of a struct file *. Do not use otherwise. */ -void __fput(struct file *file) +void fastcall __fput(struct file *file) { struct dentry *dentry = file->f_dentry; struct vfsmount *mnt = file->f_vfsmnt; @@ -192,7 +192,7 @@ mntput(mnt); } -struct file *fget(unsigned int fd) +struct file fastcall *fget(unsigned int fd) { struct file *file; struct files_struct *files = current->files; @@ -214,7 +214,7 @@ * and a flag is returned to be passed to the corresponding fput_light(). * There must not be a cloning between an fget_light/fput_light pair. */ -struct file *fget_light(unsigned int fd, int *fput_needed) +struct file fastcall *fget_light(unsigned int fd, int *fput_needed) { struct file *file; struct files_struct *files = current->files; diff -urN linux-2.6.4-rc2/fs/freevxfs/vxfs_super.c linux-2.6.4-rc3/fs/freevxfs/vxfs_super.c --- linux-2.6.4-rc2/fs/freevxfs/vxfs_super.c 2004-02-17 19:59:18.000000000 -0800 +++ linux-2.6.4-rc3/fs/freevxfs/vxfs_super.c 2004-03-09 16:36:28.000000000 -0800 @@ -143,6 +143,7 @@ struct vxfs_sb *rsbp; struct buffer_head *bp = NULL; u_long bsize; + struct inode *root; infp = kmalloc(sizeof(*infp), GFP_KERNEL); if (!infp) { @@ -208,8 +209,10 @@ } sbp->s_op = &vxfs_super_ops; - sbp->s_root = d_alloc_root(iget(sbp, VXFS_ROOT_INO)); + root = iget(sbp, VXFS_ROOT_INO); + sbp->s_root = d_alloc_root(root); if (!sbp->s_root) { + iput(root); printk(KERN_WARNING "vxfs: unable to get root dentry.\n"); goto out_free_ilist; } diff -urN linux-2.6.4-rc2/fs/hfs/super.c linux-2.6.4-rc3/fs/hfs/super.c --- linux-2.6.4-rc2/fs/hfs/super.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/hfs/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -294,13 +294,15 @@ sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) - goto bail_no_root; + goto bail_iput; sb->s_root->d_op = &hfs_dentry_operations; /* everything's okay */ return 0; +bail_iput: + iput(root_inode); bail_no_root: hfs_warn("hfs_fs: get root inode failed.\n"); hfs_mdb_put(sb); diff -urN linux-2.6.4-rc2/fs/hfsplus/dir.c linux-2.6.4-rc3/fs/hfsplus/dir.c --- linux-2.6.4-rc2/fs/hfsplus/dir.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/hfsplus/dir.c 2004-03-09 16:36:28.000000000 -0800 @@ -399,6 +399,7 @@ res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); if (!res) { + dentry->d_fsdata = (void *)inode->i_ino; d_instantiate(dentry, inode); mark_inode_dirty(inode); } @@ -424,6 +425,7 @@ return res; } init_special_inode(inode, mode, rdev); + dentry->d_fsdata = (void *)inode->i_ino; d_instantiate(dentry, inode); mark_inode_dirty(inode); diff -urN linux-2.6.4-rc2/fs/hfsplus/inode.c linux-2.6.4-rc3/fs/hfsplus/inode.c --- linux-2.6.4-rc2/fs/hfsplus/inode.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/hfsplus/inode.c 2004-03-09 16:36:28.000000000 -0800 @@ -335,6 +335,14 @@ init_MUTEX(&HFSPLUS_I(inode).extents_lock); atomic_set(&HFSPLUS_I(inode).opencnt, 0); HFSPLUS_I(inode).flags = 0; + memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec)); + memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); + HFSPLUS_I(inode).alloc_blocks = 0; + HFSPLUS_I(inode).first_blocks = 0; + HFSPLUS_I(inode).cached_start = 0; + HFSPLUS_I(inode).cached_blocks = 0; + HFSPLUS_I(inode).phys_size = 0; + HFSPLUS_I(inode).rsrc_inode = 0; if (S_ISDIR(inode->i_mode)) { inode->i_size = 2; HFSPLUS_SB(sb).folder_count++; @@ -346,14 +354,6 @@ inode->i_fop = &hfsplus_file_operations; inode->i_mapping->a_ops = &hfsplus_aops; HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks; - memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec)); - memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); - HFSPLUS_I(inode).alloc_blocks = 0; - HFSPLUS_I(inode).first_blocks = 0; - HFSPLUS_I(inode).cached_start = 0; - HFSPLUS_I(inode).cached_blocks = 0; - HFSPLUS_I(inode).phys_size = 0; - HFSPLUS_I(inode).rsrc_inode = 0; } else if (S_ISLNK(inode->i_mode)) { HFSPLUS_SB(sb).file_count++; inode->i_op = &page_symlink_inode_operations; diff -urN linux-2.6.4-rc2/fs/hfsplus/super.c linux-2.6.4-rc3/fs/hfsplus/super.c --- linux-2.6.4-rc2/fs/hfsplus/super.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/hfsplus/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -278,6 +278,7 @@ struct hfsplus_sb_info *sbi; hfsplus_cat_entry entry; struct hfs_find_data fd; + struct inode *root; struct qstr str; int err = -EINVAL; @@ -364,10 +365,12 @@ } /* Load the root directory */ - sb->s_root = d_alloc_root(iget(sb, HFSPLUS_ROOT_CNID)); + root = iget(sb, HFSPLUS_ROOT_CNID); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { if (!silent) printk("HFS+-fs: failed to load root directory\n"); + iput(root); goto cleanup; } diff -urN linux-2.6.4-rc2/fs/hpfs/super.c linux-2.6.4-rc3/fs/hpfs/super.c --- linux-2.6.4-rc2/fs/hpfs/super.c 2004-02-17 19:58:16.000000000 -0800 +++ linux-2.6.4-rc3/fs/hpfs/super.c 2004-03-09 16:36:28.000000000 -0800 @@ -448,6 +448,7 @@ struct hpfs_super_block *superblock; struct hpfs_spare_block *spareblock; struct hpfs_sb_info *sbi; + struct inode *root; uid_t uid; gid_t gid; @@ -613,10 +614,11 @@ brelse(bh0); hpfs_lock_iget(s, 1); - s->s_root = d_alloc_root(iget(s, sbi->sb_root)); + root = iget(s, sbi->sb_root); hpfs_unlock_iget(s); - if (!s->s_root || !s->s_root->d_inode) { - printk("HPFS: iget failed. Why???\n"); + s->s_root = d_alloc_root(root); + if (!s->s_root) { + iput(root); goto bail0; } hpfs_set_dentry_operations(s->s_root); @@ -627,22 +629,24 @@ root_dno = hpfs_fnode_dno(s, sbi->sb_root); if (root_dno) - de = map_dirent(s->s_root->d_inode, root_dno, "\001\001", 2, NULL, &qbh); - if (!root_dno || !de) hpfs_error(s, "unable to find root dir"); + de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh); + if (!de) + hpfs_error(s, "unable to find root dir"); else { - s->s_root->d_inode->i_atime.tv_sec = local_to_gmt(s, de->read_date); - s->s_root->d_inode->i_atime.tv_nsec = 0; - s->s_root->d_inode->i_mtime.tv_sec = local_to_gmt(s, de->write_date); - s->s_root->d_inode->i_mtime.tv_nsec = 0; - s->s_root->d_inode->i_ctime.tv_sec = local_to_gmt(s, de->creation_date); - s->s_root->d_inode->i_ctime.tv_nsec = 0; - hpfs_i(s->s_root->d_inode)->i_ea_size = de->ea_size; - hpfs_i(s->s_root->d_inode)->i_parent_dir = s->s_root->d_inode->i_ino; - if (s->s_root->d_inode->i_size == -1) s->s_root->d_inode->i_size = 2048; - if (s->s_root->d_inode->i_blocks == -1) s->s_root->d_inode->i_blocks = 5; + root->i_atime.tv_sec = local_to_gmt(s, de->read_date); + root->i_atime.tv_nsec = 0; + root->i_mtime.tv_sec = local_to_gmt(s, de->write_date); + root->i_mtime.tv_nsec = 0; + root->i_ctime.tv_sec = local_to_gmt(s, de->creation_date); + root->i_ctime.tv_nsec = 0; + hpfs_i(root)->i_ea_size = de->ea_size; + hpfs_i(root)->i_parent_dir = root->i_ino; + if (root->i_size == -1) + root->i_size = 2048; + if (root->i_blocks == -1) + root->i_blocks = 5; + hpfs_brelse4(&qbh); } - if (de) hpfs_brelse4(&qbh); - return 0; bail4: brelse(bh2); diff -urN linux-2.6.4-rc2/fs/jfs/acl.c linux-2.6.4-rc3/fs/jfs/acl.c --- linux-2.6.4-rc2/fs/jfs/acl.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/acl.c 2004-03-09 16:36:29.000000000 -0800 @@ -24,7 +24,7 @@ #include "jfs_xattr.h" #include "jfs_acl.h" -struct posix_acl *jfs_get_acl(struct inode *inode, int type) +static struct posix_acl *jfs_get_acl(struct inode *inode, int type) { struct posix_acl *acl; char *ea_name; @@ -74,7 +74,7 @@ return acl; } -int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { char *ea_name; struct jfs_inode_info *ji = JFS_IP(inode); @@ -247,7 +247,7 @@ return rc; } -int jfs_acl_chmod(struct inode *inode) +static int jfs_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int rc; diff -urN linux-2.6.4-rc2/fs/jfs/jfs_acl.h linux-2.6.4-rc3/fs/jfs/jfs_acl.h --- linux-2.6.4-rc2/fs/jfs/jfs_acl.h 2004-02-17 19:59:18.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_acl.h 2004-03-09 16:36:29.000000000 -0800 @@ -22,8 +22,6 @@ #include -struct posix_acl *jfs_get_acl(struct inode *, int); -int jfs_set_acl(struct inode *, int, struct posix_acl *); int jfs_permission(struct inode *, int, struct nameidata *); int jfs_init_acl(struct inode *, struct inode *); int jfs_setattr(struct dentry *, struct iattr *); diff -urN linux-2.6.4-rc2/fs/jfs/jfs_dmap.c linux-2.6.4-rc3/fs/jfs/jfs_dmap.c --- linux-2.6.4-rc2/fs/jfs/jfs_dmap.c 2004-02-17 19:59:18.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_dmap.c 2004-03-09 16:36:29.000000000 -0800 @@ -124,7 +124,7 @@ s64 * results); static int dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results); -int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks); +static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks); static int dbFindBits(u32 word, int l2nb); static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno); static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx); @@ -134,10 +134,10 @@ int nblocks); static int dbMaxBud(u8 * cp); s64 dbMapFileSizeToMapSize(struct inode *ipbmap); -int blkstol2(s64 nb); +static int blkstol2(s64 nb); -int cntlz(u32 value); -int cnttz(u32 word); +static int cntlz(u32 value); +static int cnttz(u32 word); static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno, int nblocks); @@ -155,7 +155,7 @@ * into the table, with the table elements yielding the maximum * binary buddy of free bits within the character. */ -signed char budtab[256] = { +static s8 budtab[256] = { 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -942,7 +942,7 @@ return (rc); } - +#ifdef _NOTYET /* * NAME: dbAllocExact() * @@ -1009,7 +1009,7 @@ return (rc); } - +#endif /* _NOTYET */ /* * NAME: dbReAlloc() @@ -1092,7 +1092,7 @@ * -ENOSPC - insufficient disk resources * -EIO - i/o error */ -int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) +static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) { struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); s64 lblkno, lastblkno, extblkno; @@ -3022,7 +3022,7 @@ * RETURN VALUES: * count of trailing zeros */ -int cnttz(u32 word) +static int cnttz(u32 word) { int n; @@ -3047,7 +3047,7 @@ * RETURN VALUES: * count of leading zeros */ -int cntlz(u32 value) +static int cntlz(u32 value) { int n; diff -urN linux-2.6.4-rc2/fs/jfs/jfs_dmap.h linux-2.6.4-rc3/fs/jfs/jfs_dmap.h --- linux-2.6.4-rc2/fs/jfs/jfs_dmap.h 2004-02-17 19:58:00.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_dmap.h 2004-03-09 16:36:29.000000000 -0800 @@ -286,8 +286,6 @@ extern int dbAlloc(struct inode *ipbmap, s64 hint, s64 nblocks, s64 * results); -extern int dbAllocExact(struct inode *ip, s64 blkno, int nblocks); - extern int dbReAlloc(struct inode *ipbmap, s64 blkno, s64 nblocks, s64 addnblocks, s64 * results); diff -urN linux-2.6.4-rc2/fs/jfs/jfs_dtree.c linux-2.6.4-rc3/fs/jfs/jfs_dtree.c --- linux-2.6.4-rc2/fs/jfs/jfs_dtree.c 2004-02-17 19:58:47.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_dtree.c 2004-03-09 16:36:29.000000000 -0800 @@ -162,9 +162,6 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp, dtpage_t * fp, struct btstack * btstack); -static int dtSearchNode(struct inode *ip, - s64 lmxaddr, pxd_t * kpxd, struct btstack * btstack); - static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p); static int dtReadFirst(struct inode *ip, struct btstack * btstack); @@ -2380,7 +2377,7 @@ return 0; } - +#ifdef _NOTYET /* * NAME: dtRelocate() * @@ -2575,7 +2572,6 @@ return rc; } - /* * NAME: dtSearchNode() * @@ -2677,7 +2673,7 @@ goto loop; } - +#endif /* _NOTYET */ /* * dtRelink() @@ -2933,7 +2929,7 @@ /* * function to determine next variable-sized jfs_dirent in buffer */ -inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent) +static inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent) { return (struct jfs_dirent *) ((char *)dirent + diff -urN linux-2.6.4-rc2/fs/jfs/jfs_dtree.h linux-2.6.4-rc3/fs/jfs/jfs_dtree.h --- linux-2.6.4-rc2/fs/jfs/jfs_dtree.h 2004-02-17 19:57:59.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_dtree.h 2004-03-09 16:36:29.000000000 -0800 @@ -265,9 +265,6 @@ extern int dtDelete(tid_t tid, struct inode *ip, struct component_name * key, ino_t * data, int flag); -extern int dtRelocate(tid_t tid, - struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr); - extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, ino_t * orig_ino, ino_t new_ino, int flag); diff -urN linux-2.6.4-rc2/fs/jfs/jfs_extent.c linux-2.6.4-rc3/fs/jfs/jfs_extent.c --- linux-2.6.4-rc2/fs/jfs/jfs_extent.c 2004-02-17 19:58:06.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_extent.c 2004-03-09 16:36:29.000000000 -0800 @@ -35,7 +35,6 @@ /* * external references */ -extern int dbExtend(struct inode *, s64, s64, s64); extern int jfs_commit_inode(struct inode *, int); diff -urN linux-2.6.4-rc2/fs/jfs/jfs_incore.h linux-2.6.4-rc3/fs/jfs/jfs_incore.h --- linux-2.6.4-rc2/fs/jfs/jfs_incore.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_incore.h 2004-03-09 16:36:29.000000000 -0800 @@ -114,7 +114,6 @@ * cflag */ enum cflags { - COMMIT_New, /* never committed inode */ COMMIT_Nolink, /* inode committed with zero link count */ COMMIT_Inlineea, /* commit inode inline EA */ COMMIT_Freewmap, /* free WMAP at iClose() */ diff -urN linux-2.6.4-rc2/fs/jfs/jfs_inode.c linux-2.6.4-rc3/fs/jfs/jfs_inode.c --- linux-2.6.4-rc2/fs/jfs/jfs_inode.c 2004-02-17 19:57:15.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_inode.c 2004-03-09 16:36:29.000000000 -0800 @@ -72,7 +72,6 @@ inode->i_generation = JFS_SBI(sb)->gengen++; jfs_inode->cflag = 0; - set_cflag(COMMIT_New, inode); /* Zero remaining fields */ memset(&jfs_inode->acl, 0, sizeof(dxd_t)); diff -urN linux-2.6.4-rc2/fs/jfs/jfs_logmgr.c linux-2.6.4-rc3/fs/jfs/jfs_logmgr.c --- linux-2.6.4-rc2/fs/jfs/jfs_logmgr.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_logmgr.c 2004-03-09 16:36:29.000000000 -0800 @@ -196,6 +196,7 @@ static bio_end_io_t lbmIODone; static void lbmStartIO(struct lbuf * bp); static void lmGCwrite(struct jfs_log * log, int cant_block); +static int lmLogSync(struct jfs_log * log, int nosyncwait); @@ -810,7 +811,7 @@ * NOTE: * This routine is called a interrupt time by lbmIODone */ -void lmPostGC(struct lbuf * bp) +static void lmPostGC(struct lbuf * bp) { unsigned long flags; struct jfs_log *log = bp->l_log; @@ -933,7 +934,7 @@ * * serialization: LOG_LOCK() held on entry/exit */ -int lmLogSync(struct jfs_log * log, int nosyncwait) +static int lmLogSync(struct jfs_log * log, int nosyncwait) { int logsize; int written; /* written since last syncpt */ diff -urN linux-2.6.4-rc2/fs/jfs/jfs_logmgr.h linux-2.6.4-rc3/fs/jfs/jfs_logmgr.h --- linux-2.6.4-rc2/fs/jfs/jfs_logmgr.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_logmgr.h 2004-03-09 16:36:29.000000000 -0800 @@ -505,7 +505,6 @@ extern int lmLogOpen(struct super_block *sb); extern int lmLogClose(struct super_block *sb); -extern int lmLogSync(struct jfs_log * log, int nosyncwait); extern int lmLogShutdown(struct jfs_log * log); extern int lmLogInit(struct jfs_log * log); extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize); diff -urN linux-2.6.4-rc2/fs/jfs/jfs_txnmgr.c linux-2.6.4-rc3/fs/jfs/jfs_txnmgr.c --- linux-2.6.4-rc2/fs/jfs/jfs_txnmgr.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_txnmgr.c 2004-03-09 16:36:29.000000000 -0800 @@ -168,25 +168,23 @@ /* * forward references */ -int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck, struct commit * cd); -int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); -void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); -void inlineLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); -void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); +static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck, struct commit * cd); +static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck); +static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck); +static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck); static void txAbortCommit(struct commit * cd); static void txAllocPMap(struct inode *ip, struct maplock * maplock, - struct tblock * tblk); -void txForce(struct tblock * tblk); -static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd); -int txMoreLock(void); + struct tblock * tblk); +static void txForce(struct tblock * tblk); +static int txLog(struct jfs_log * log, struct tblock * tblk, + struct commit * cd); static void txUpdateMap(struct tblock * tblk); static void txRelease(struct tblock * tblk); -void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck); static void LogSyncRelease(struct metapage * mp); @@ -1240,8 +1238,8 @@ * Ensure that inode isn't reused before * lazy commit thread finishes processing */ - if (tblk->xflag & (COMMIT_CREATE | COMMIT_DELETE)) { - atomic_inc(&tblk->ip->i_count); + if (tblk->xflag & COMMIT_DELETE) { + atomic_inc(&tblk->u.ip->i_count); /* * Avoid a rare deadlock * @@ -1252,13 +1250,13 @@ * commit the transaction synchronously, so the last iput * will be done by the calling thread (or later) */ - if (tblk->ip->i_state & I_LOCK) + if (tblk->u.ip->i_state & I_LOCK) tblk->xflag &= ~COMMIT_LAZY; } ASSERT((!(tblk->xflag & COMMIT_DELETE)) || - ((tblk->ip->i_nlink == 0) && - !test_cflag(COMMIT_Nolink, tblk->ip))); + ((tblk->u.ip->i_nlink == 0) && + !test_cflag(COMMIT_Nolink, tblk->u.ip))); /* * write COMMIT log record @@ -1399,7 +1397,7 @@ * * function: log inode tlock and format maplock to update bmap; */ -int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck, struct commit * cd) { int rc = 0; @@ -1514,7 +1512,7 @@ * * function: log data tlock */ -int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck) { struct metapage *mp; @@ -1560,7 +1558,7 @@ * * function: log dtree tlock and format maplock to update bmap; */ -void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck) { struct metapage *mp; @@ -1665,7 +1663,7 @@ * * function: log xtree tlock and format maplock to update bmap; */ -void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck) { struct inode *ip; @@ -2360,23 +2358,17 @@ * unlock mapper/write lock */ if (tblk->xflag & COMMIT_CREATE) { - ip = tblk->ip; - - ASSERT(test_cflag(COMMIT_New, ip)); - clear_cflag(COMMIT_New, ip); - - diUpdatePMap(ipimap, ip->i_ino, FALSE, tblk); + diUpdatePMap(ipimap, tblk->ino, FALSE, tblk); ipimap->i_state |= I_DIRTY; /* update persistent block allocation map * for the allocation of inode extent; */ pxdlock.flag = mlckALLOCPXD; - pxdlock.pxd = JFS_IP(ip)->ixpxd; + pxdlock.pxd = tblk->u.ixpxd; pxdlock.index = 1; - txAllocPMap(ip, (struct maplock *) & pxdlock, tblk); - iput(ip); + txAllocPMap(ipimap, (struct maplock *) & pxdlock, tblk); } else if (tblk->xflag & COMMIT_DELETE) { - ip = tblk->ip; + ip = tblk->u.ip; diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk); ipimap->i_state |= I_DIRTY; iput(ip); @@ -2725,7 +2717,7 @@ * allocation maps are updated in order. For synchronous transactions, * let the user thread finish processing after txUpdateMap() is called. */ -void txLazyCommit(struct tblock * tblk) +static void txLazyCommit(struct tblock * tblk) { struct jfs_log *log; diff -urN linux-2.6.4-rc2/fs/jfs/jfs_txnmgr.h linux-2.6.4-rc3/fs/jfs/jfs_txnmgr.h --- linux-2.6.4-rc2/fs/jfs/jfs_txnmgr.h 2004-02-17 19:59:07.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_txnmgr.h 2004-03-09 16:36:29.000000000 -0800 @@ -62,7 +62,11 @@ * ready transactions wait on this * event for group commit completion. */ - struct inode *ip; /* inode being created or deleted */ + union { + struct inode *ip; /* inode being deleted */ + pxd_t ixpxd; /* pxd of inode extent for created inode */ + } u; + u32 ino; /* inode number being created */ }; extern struct tblock *TxBlock; /* transaction block table */ diff -urN linux-2.6.4-rc2/fs/jfs/jfs_unicode.c linux-2.6.4-rc3/fs/jfs/jfs_unicode.c --- linux-2.6.4-rc2/fs/jfs/jfs_unicode.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_unicode.c 2004-03-09 16:36:29.000000000 -0800 @@ -34,6 +34,8 @@ { int i; int outlen = 0; + static int warn_again = 5; /* Only warn up to 5 times total */ + int warn = !!warn_again; /* once per string */ if (codepage) { for (i = 0; (i < len) && from[i]; i++) { @@ -48,8 +50,22 @@ to[outlen++] = '?'; } } else { - for (i = 0; (i < len) && from[i]; i++) - to[i] = (char) (le16_to_cpu(from[i])); + for (i = 0; (i < len) && from[i]; i++) { + if (le16_to_cpu(from[i]) & 0xff00) { + if (warn) { + warn--; + warn_again--; + printk(KERN_ERR + "non-latin1 character 0x%x found in JFS file name\n", + le16_to_cpu(from[i])); + printk(KERN_ERR + "mount with iocharset=utf8 to access\n"); + } + to[i] = '?'; + } + else + to[i] = (char) (le16_to_cpu(from[i])); + } outlen = i; } to[outlen] = 0; @@ -62,8 +78,8 @@ * FUNCTION: Convert character string to unicode string * */ -int jfs_strtoUCS(wchar_t * to, - const char *from, int len, struct nls_table *codepage) +static int jfs_strtoUCS(wchar_t * to, const char *from, int len, + struct nls_table *codepage) { int charlen; int i; diff -urN linux-2.6.4-rc2/fs/jfs/jfs_xtree.c linux-2.6.4-rc3/fs/jfs/jfs_xtree.c --- linux-2.6.4-rc2/fs/jfs/jfs_xtree.c 2004-02-17 19:57:55.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_xtree.c 2004-03-09 16:36:29.000000000 -0800 @@ -1736,7 +1736,7 @@ return rc; } - +#ifdef _NOTYET /* * xtTailgate() * @@ -1918,7 +1918,7 @@ return rc; } - +#endif /* _NOTYET */ /* * xtUpdate() diff -urN linux-2.6.4-rc2/fs/jfs/jfs_xtree.h linux-2.6.4-rc3/fs/jfs/jfs_xtree.h --- linux-2.6.4-rc2/fs/jfs/jfs_xtree.h 2004-02-17 19:59:52.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/jfs_xtree.h 2004-03-09 16:36:29.000000000 -0800 @@ -117,8 +117,10 @@ int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag); extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen, int flag); +#ifdef _NOTYET extern int xtTailgate(tid_t tid, struct inode *ip, s64 xoff, int xlen, s64 xaddr, int flag); +#endif extern int xtUpdate(tid_t tid, struct inode *ip, struct xad *nxad); extern int xtDelete(tid_t tid, struct inode *ip, s64 xoff, int xlen, int flag); diff -urN linux-2.6.4-rc2/fs/jfs/namei.c linux-2.6.4-rc3/fs/jfs/namei.c --- linux-2.6.4-rc2/fs/jfs/namei.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/namei.c 2004-03-09 16:36:29.000000000 -0800 @@ -44,7 +44,7 @@ struct inode_operations jfs_dir_inode_operations; struct file_operations jfs_dir_operations; -s64 commitZeroLink(tid_t, struct inode *); +static s64 commitZeroLink(tid_t, struct inode *); /* * NAME: jfs_create(dip, dentry, mode) @@ -60,7 +60,7 @@ * RETURN: Errors from subroutines * */ -int jfs_create(struct inode *dip, struct dentry *dentry, int mode, +static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, struct nameidata *nd) { int rc = 0; @@ -104,7 +104,8 @@ tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; - tblk->ip = ip; + tblk->ino = ip->i_ino; + tblk->u.ixpxd = JFS_IP(ip)->ixpxd; iplist[0] = dip; iplist[1] = ip; @@ -181,7 +182,7 @@ * note: * EACCESS: user needs search+write permission on the parent directory */ -int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) +static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) { int rc = 0; tid_t tid; /* transaction id */ @@ -230,7 +231,8 @@ tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; - tblk->ip = ip; + tblk->ino = ip->i_ino; + tblk->u.ixpxd = JFS_IP(ip)->ixpxd; iplist[0] = dip; iplist[1] = ip; @@ -314,7 +316,7 @@ * but the directory is not removed until the last reference to * the directory is released (cf.unlink() of regular file). */ -int jfs_rmdir(struct inode *dip, struct dentry *dentry) +static int jfs_rmdir(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ @@ -346,7 +348,7 @@ tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; - tblk->ip = ip; + tblk->u.ip = ip; /* * delete the entry of target directory from parent directory @@ -437,7 +439,7 @@ * JFS does NOT support unlink() on directories. * */ -int jfs_unlink(struct inode *dip, struct dentry *dentry) +static int jfs_unlink(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ @@ -505,7 +507,7 @@ } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; - tblk->ip = ip; + tblk->u.ip = ip; } /* @@ -590,7 +592,7 @@ * * RETURN: Errors from subroutines */ -s64 commitZeroLink(tid_t tid, struct inode *ip) +static s64 commitZeroLink(tid_t tid, struct inode *ip) { int filetype; struct tblock *tblk; @@ -758,7 +760,7 @@ * EXDEV: target object and new link are on different file systems and * implementation does not support links between file systems [XPG4.2]. */ -int jfs_link(struct dentry *old_dentry, +static int jfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { int rc; @@ -838,7 +840,8 @@ * an intermediate result whose length exceeds PATH_MAX [XPG4.2] */ -int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) +static int jfs_symlink(struct inode *dip, struct dentry *dentry, + const char *name) { int rc; tid_t tid; @@ -889,7 +892,8 @@ tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; - tblk->ip = ip; + tblk->ino = ip->i_ino; + tblk->u.ixpxd = JFS_IP(ip)->ixpxd; /* * create entry for symbolic link in parent directory @@ -1042,7 +1046,7 @@ * * FUNCTION: rename a file or directory */ -int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, +static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct btstack btstack; @@ -1151,7 +1155,7 @@ } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; - tblk->ip = new_ip; + tblk->u.ip = new_ip; } else if (new_ip->i_nlink == 0) { assert(!test_cflag(COMMIT_Nolink, new_ip)); /* free block resources */ @@ -1162,7 +1166,7 @@ } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; - tblk->ip = new_ip; + tblk->u.ip = new_ip; } else { new_ip->i_ctime = CURRENT_TIME; mark_inode_dirty(new_ip); @@ -1310,7 +1314,8 @@ * * FUNCTION: Create a special file (device) */ -int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) +static int jfs_mknod(struct inode *dir, struct dentry *dentry, + int mode, dev_t rdev) { struct jfs_inode_info *jfs_ip; struct btstack btstack; @@ -1347,7 +1352,8 @@ tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; - tblk->ip = ip; + tblk->ino = ip->i_ino; + tblk->u.ixpxd = JFS_IP(ip)->ixpxd; ino = ip->i_ino; if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) diff -urN linux-2.6.4-rc2/fs/jfs/super.c linux-2.6.4-rc3/fs/jfs/super.c --- linux-2.6.4-rc2/fs/jfs/super.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/super.c 2004-03-09 16:36:29.000000000 -0800 @@ -321,7 +321,7 @@ return 0; } -int jfs_remount(struct super_block *sb, int *flags, char *data) +static int jfs_remount(struct super_block *sb, int *flags, char *data) { s64 newLVSize = 0; int rc = 0; diff -urN linux-2.6.4-rc2/fs/jfs/xattr.c linux-2.6.4-rc3/fs/jfs/xattr.c --- linux-2.6.4-rc2/fs/jfs/xattr.c 2004-02-17 19:57:27.000000000 -0800 +++ linux-2.6.4-rc3/fs/jfs/xattr.c 2004-03-09 16:36:29.000000000 -0800 @@ -640,6 +640,7 @@ } inode->i_blocks += LBLK2PBLK(inode->i_sb, new_blocks - old_blocks); + inode->i_ctime = CURRENT_TIME; rc = txCommit(tid, 1, &inode, 0); txEnd(tid); up(&ji->commit_sem); diff -urN linux-2.6.4-rc2/fs/lockd/clntproc.c linux-2.6.4-rc3/fs/lockd/clntproc.c --- linux-2.6.4-rc2/fs/lockd/clntproc.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/fs/lockd/clntproc.c 2004-03-09 16:36:29.000000000 -0800 @@ -195,19 +195,6 @@ } /* - * Wait while server is in grace period - */ -static inline int -nlmclnt_grace_wait(struct nlm_host *host) -{ - if (!host->h_reclaiming) - interruptible_sleep_on_timeout(&host->h_gracewait, 10*HZ); - else - interruptible_sleep_on(&host->h_gracewait); - return signalled()? -ERESTARTSYS : 0; -} - -/* * Allocate an NLM RPC call struct */ struct nlm_rqst * diff -urN linux-2.6.4-rc2/fs/namei.c linux-2.6.4-rc3/fs/namei.c --- linux-2.6.4-rc2/fs/namei.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/namei.c 2004-03-09 16:36:29.000000000 -0800 @@ -571,7 +571,7 @@ * * We expect 'base' to be positive and a directory. */ -int link_path_walk(const char * name, struct nameidata *nd) +int fastcall link_path_walk(const char * name, struct nameidata *nd) { struct path next; struct inode *inode; @@ -771,7 +771,7 @@ return err; } -int path_walk(const char * name, struct nameidata *nd) +int fastcall path_walk(const char * name, struct nameidata *nd) { current->total_link_count = 0; return link_path_walk(name, nd); @@ -858,7 +858,7 @@ return 1; } -int path_lookup(const char *name, unsigned int flags, struct nameidata *nd) +int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) { nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; @@ -971,7 +971,7 @@ * that namei follows links, while lnamei does not. * SMP-safe */ -int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) +int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) { char *tmp = getname(name); int err = PTR_ERR(tmp); diff -urN linux-2.6.4-rc2/fs/nfsd/export.c linux-2.6.4-rc3/fs/nfsd/export.c --- linux-2.6.4-rc2/fs/nfsd/export.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/nfsd/export.c 2004-03-09 16:36:29.000000000 -0800 @@ -56,11 +56,6 @@ #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) static struct cache_head *expkey_table[EXPKEY_HASHMAX]; -static inline int key_len(int type) -{ - return type == 0 ? 8 : type == 1 ? 4 : 12; -} - static inline int svc_expkey_hash(struct svc_expkey *item) { int hash = item->ek_fsidtype; @@ -547,8 +542,8 @@ mk_fsid_v0(fsidv, dev, ino); return exp_find_key(clp, 0, fsidv, NULL); } - mk_fsid_v2(fsidv, dev, ino); - return exp_find_key(clp, 2, fsidv, NULL); + mk_fsid_v3(fsidv, dev, ino); + return exp_find_key(clp, 3, fsidv, NULL); } /* @@ -684,8 +679,8 @@ mk_fsid_v0(fsid, dev, inode->i_ino); return exp_set_key(clp, 0, fsid, exp); } - mk_fsid_v2(fsid, dev, inode->i_ino); - return exp_set_key(clp, 2, fsid, exp); + mk_fsid_v3(fsid, dev, inode->i_ino); + return exp_set_key(clp, 3, fsid, exp); } static void exp_unhash(struct svc_export *exp) diff -urN linux-2.6.4-rc2/fs/nfsd/nfsfh.c linux-2.6.4-rc3/fs/nfsd/nfsfh.c --- linux-2.6.4-rc2/fs/nfsd/nfsfh.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/nfsd/nfsfh.c 2004-03-09 16:36:29.000000000 -0800 @@ -117,19 +117,14 @@ case 0: break; default: goto out; } - - switch (fh->fh_fsid_type) { - case 0: - len = 2; - break; - case 1: - len = 1; - break; - case 2: + len = key_len(fh->fh_fsid_type) / 4; + if (len == 0) goto out; + if (fh->fh_fsid_type == 2) { + /* deprecated, convert to type 3 */ len = 3; - break; - default: - goto out; + fh->fh_fsid_type = 3; + fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); + fh->fh_fsid[1] = fh->fh_fsid[2]; } if ((data_left -= len)<0) goto out; exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle); @@ -336,19 +331,31 @@ parent->d_name.name, dentry->d_name.name, (inode ? inode->i_ino : 0)); - /* for large devnums rules are simple */ - if (!old_valid_dev(ex_dev)) { - ref_fh_version = 1; - if (exp->ex_flags & NFSEXP_FSID) - ref_fh_fsid_type = 1; - else - ref_fh_fsid_type = 2; - } else if (ref_fh) { + if (ref_fh) { ref_fh_version = ref_fh->fh_handle.fh_version; - ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type; - if (!(exp->ex_flags & NFSEXP_FSID) || ref_fh_fsid_type == 2) + if (ref_fh_version == 0xca) + ref_fh_fsid_type = 0; + else + ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type; + if (ref_fh_fsid_type > 3) ref_fh_fsid_type = 0; } + /* make sure ref_fh type works for given export */ + if (ref_fh_fsid_type == 1 && + !(exp->ex_flags & NFSEXP_FSID)) { + /* if we don't have an fsid, we cannot provide one... */ + ref_fh_fsid_type = 0; + } + if (!old_valid_dev(ex_dev) && ref_fh_fsid_type == 0) { + /* for newer device numbers, we must use a newer fsid format */ + ref_fh_version = 1; + ref_fh_fsid_type = 3; + } + if (old_valid_dev(ex_dev) && + (ref_fh_fsid_type == 2 || ref_fh_fsid_type == 3)) + /* must use type1 for smaller device numbers */ + ref_fh_fsid_type = 0; + if (ref_fh == fhp) fh_put(ref_fh); @@ -376,16 +383,23 @@ if (inode) _fh_update_old(dentry, exp, &fhp->fh_handle); } else { + int len; fhp->fh_handle.fh_version = 1; fhp->fh_handle.fh_auth_type = 0; datap = fhp->fh_handle.fh_auth+0; fhp->fh_handle.fh_fsid_type = ref_fh_fsid_type; switch (ref_fh_fsid_type) { + case 0: + /* + * fsid_type 0: + * 2byte major, 2byte minor, 4byte inode + */ + mk_fsid_v0(datap, ex_dev, + exp->ex_dentry->d_inode->i_ino); + break; case 1: /* fsid_type 1 == 4 bytes filesystem id */ mk_fsid_v1(datap, exp->ex_fsid); - datap += 1; - fhp->fh_handle.fh_size = 2*4; break; case 2: /* @@ -394,21 +408,22 @@ */ mk_fsid_v2(datap, ex_dev, exp->ex_dentry->d_inode->i_ino); - datap += 3; - fhp->fh_handle.fh_size = 4*4; break; - default: + case 3: /* - * fsid_type 0: - * 2byte major, 2byte minor, 4byte inode + * fsid_type 3: + * 4byte devicenumber, 4byte inode */ - mk_fsid_v0(datap, ex_dev, + mk_fsid_v3(datap, ex_dev, exp->ex_dentry->d_inode->i_ino); - datap += 2; - fhp->fh_handle.fh_size = 3*4; + break; } + len = key_len(ref_fh_fsid_type); + datap += len/4; + fhp->fh_handle.fh_size = 4 + len; + if (inode) { - int size = fhp->fh_maxsize/4 - 3; + int size = (fhp->fh_maxsize-len-4)/4; fhp->fh_handle.fh_fileid_type = _fh_update(dentry, exp, datap, &size); fhp->fh_handle.fh_size += size*4; diff -urN linux-2.6.4-rc2/fs/open.c linux-2.6.4-rc3/fs/open.c --- linux-2.6.4-rc2/fs/open.c 2004-02-17 19:57:14.000000000 -0800 +++ linux-2.6.4-rc3/fs/open.c 2004-03-09 16:36:29.000000000 -0800 @@ -890,7 +890,7 @@ files->next_fd = fd; } -void put_unused_fd(unsigned int fd) +void fastcall put_unused_fd(unsigned int fd) { struct files_struct *files = current->files; spin_lock(&files->file_lock); @@ -913,7 +913,7 @@ * will follow. */ -void fd_install(unsigned int fd, struct file * file) +void fastcall fd_install(unsigned int fd, struct file * file) { struct files_struct *files = current->files; spin_lock(&files->file_lock); diff -urN linux-2.6.4-rc2/fs/proc/proc_misc.c linux-2.6.4-rc3/fs/proc/proc_misc.c --- linux-2.6.4-rc2/fs/proc/proc_misc.c 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/fs/proc/proc_misc.c 2004-03-09 16:36:29.000000000 -0800 @@ -389,7 +389,7 @@ jiffies_to_clock_t(iowait), jiffies_to_clock_t(irq), jiffies_to_clock_t(softirq)); - for_each_online_cpu(i) { + for_each_cpu(i) { seq_printf(p, "cpu%d %u %u %u %u %u %u %u\n", i, jiffies_to_clock_t(kstat_cpu(i).cpustat.user), @@ -424,7 +424,7 @@ static int stat_open(struct inode *inode, struct file *file) { - unsigned size = 4096 * (1 + num_online_cpus() / 32); + unsigned size = 4096 * (1 + num_possible_cpus() / 32); char *buf; struct seq_file *m; int res; diff -urN linux-2.6.4-rc2/fs/romfs/inode.c linux-2.6.4-rc3/fs/romfs/inode.c --- linux-2.6.4-rc2/fs/romfs/inode.c 2004-02-17 19:58:40.000000000 -0800 +++ linux-2.6.4-rc3/fs/romfs/inode.c 2004-03-09 16:36:29.000000000 -0800 @@ -115,6 +115,7 @@ { struct buffer_head *bh; struct romfs_super_block *rsb; + struct inode *root; int sz; /* I would parse the options here, but there are none.. :) */ @@ -154,23 +155,25 @@ strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD) & ROMFH_MASK; - brelse(bh); - s->s_op = &romfs_ops; + root = iget(s, sz); + if (!root) + goto out; + s->s_root = d_alloc_root(iget(s, sz)); if (!s->s_root) - goto outnobh; + goto outiput; - /* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */ - if (0) { + brelse(bh); + return 0; + +outiput: + iput(root); out: - brelse(bh); + brelse(bh); outnobh: - return -EINVAL; - } - - return 0; + return -EINVAL; } /* That's simple too. */ diff -urN linux-2.6.4-rc2/fs/xfs/linux/xfs_super.c linux-2.6.4-rc3/fs/xfs/linux/xfs_super.c --- linux-2.6.4-rc2/fs/xfs/linux/xfs_super.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/xfs/linux/xfs_super.c 2004-03-09 16:36:29.000000000 -0800 @@ -247,7 +247,7 @@ { struct inode *inode = LINVFS_GET_IP(XFS_ITOV(ip)); - filemap_fdatawrite(inode->i_mapping); + filemap_flush(inode->i_mapping); } void diff -urN linux-2.6.4-rc2/fs/xfs/xfs_log.c linux-2.6.4-rc3/fs/xfs/xfs_log.c --- linux-2.6.4-rc2/fs/xfs/xfs_log.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/fs/xfs/xfs_log.c 2004-03-09 16:36:29.000000000 -0800 @@ -1227,7 +1227,7 @@ kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); iclog = *iclogp; iclog->hic_data = (xlog_in_core_2_t *) - kmem_alloc(iclogsize, KM_SLEEP); + kmem_zalloc(iclogsize, KM_SLEEP); iclog->ic_prev = prev_iclog; prev_iclog = iclog; diff -urN linux-2.6.4-rc2/include/acpi/acconfig.h linux-2.6.4-rc3/include/acpi/acconfig.h --- linux-2.6.4-rc2/include/acpi/acconfig.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/acpi/acconfig.h 2004-03-09 16:36:29.000000000 -0800 @@ -64,7 +64,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20040211 +#define ACPI_CA_VERSION 0x20040220 /* Maximum objects in the various object caches */ diff -urN linux-2.6.4-rc2/include/acpi/acglobal.h linux-2.6.4-rc3/include/acpi/acglobal.h --- linux-2.6.4-rc2/include/acpi/acglobal.h 2004-02-17 19:57:11.000000000 -0800 +++ linux-2.6.4-rc3/include/acpi/acglobal.h 2004-03-09 16:36:29.000000000 -0800 @@ -57,6 +57,12 @@ #define ACPI_EXTERN extern #endif +/* + * Keep local copies of these FADT-based registers. NOTE: These globals + * are first in this file for alignment reasons on 64-bit systems. + */ +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; /***************************************************************************** * @@ -97,6 +103,11 @@ ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT; ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS; ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; +/* + * Since there may be multiple SSDTs and PSDTS, a single pointer is not + * sufficient; Therefore, there isn't one! + */ + /* * Handle both ACPI 1.0 and ACPI 2.0 Integer widths @@ -107,17 +118,6 @@ ACPI_EXTERN u8 acpi_gbl_integer_byte_width; ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; -/* Keep local copies of these FADT-based registers */ - -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; - -/* - * Since there may be multiple SSDTs and PSDTS, a single pointer is not - * sufficient; Therefore, there isn't one! - */ - - /* * ACPI Table info arrays */ @@ -165,7 +165,8 @@ extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; extern const u8 acpi_gbl_decode_to8bit[8]; -extern const char *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; diff -urN linux-2.6.4-rc2/include/acpi/actypes.h linux-2.6.4-rc3/include/acpi/actypes.h --- linux-2.6.4-rc2/include/acpi/actypes.h 2004-02-17 19:58:25.000000000 -0800 +++ linux-2.6.4-rc3/include/acpi/actypes.h 2004-03-09 16:36:29.000000000 -0800 @@ -880,7 +880,8 @@ { ACPI_COMMON_OBJ_INFO; - u32 valid; /* Indicates which fields are valid */ + u8 highest_dstates[4]; /* _sx_d values 0xFF indicates not valid */ + u32 valid; /* Indicates which fields below are valid */ u32 current_status; /* _STA value */ acpi_integer address; /* _ADR value if any */ struct acpi_device_id hardware_id; /* _HID value if any */ diff -urN linux-2.6.4-rc2/include/acpi/acutils.h linux-2.6.4-rc3/include/acpi/acutils.h --- linux-2.6.4-rc2/include/acpi/acutils.h 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/include/acpi/acutils.h 2004-03-09 16:36:29.000000000 -0800 @@ -508,6 +508,10 @@ struct acpi_namespace_node *device_node, struct acpi_device_id *uid); +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest); /* * ut_mutex - mutual exclusion interfaces diff -urN linux-2.6.4-rc2/include/asm-i386/acpi.h linux-2.6.4-rc3/include/asm-i386/acpi.h --- linux-2.6.4-rc2/include/asm-i386/acpi.h 2004-02-17 19:59:23.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-i386/acpi.h 2004-03-09 16:36:29.000000000 -0800 @@ -110,6 +110,7 @@ extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; +extern int acpi_strict; /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 diff -urN linux-2.6.4-rc2/include/asm-i386/cpufeature.h linux-2.6.4-rc3/include/asm-i386/cpufeature.h --- linux-2.6.4-rc2/include/asm-i386/cpufeature.h 2004-02-17 19:58:49.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-i386/cpufeature.h 2004-03-09 16:36:29.000000000 -0800 @@ -76,6 +76,9 @@ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ #define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ +#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */ +#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */ +#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */ #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) @@ -101,6 +104,7 @@ #define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR) #define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR) #define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE) +#define cpu_has_xcrypt boot_cpu_has(X86_FEATURE_XCRYPT) #endif /* __ASM_I386_CPUFEATURE_H */ diff -urN linux-2.6.4-rc2/include/asm-i386/fixmap.h linux-2.6.4-rc3/include/asm-i386/fixmap.h --- linux-2.6.4-rc2/include/asm-i386/fixmap.h 2004-02-17 19:57:14.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-i386/fixmap.h 2004-03-09 16:36:29.000000000 -0800 @@ -71,6 +71,9 @@ FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, #endif +#ifdef CONFIG_PCI_MMCONFIG + FIX_PCIE_MCFG, +#endif __end_of_permanent_fixed_addresses, /* temporary boot-time mappings, used before ioremap() is functional */ #define NR_FIX_BTMAPS 16 diff -urN linux-2.6.4-rc2/include/asm-i386/linkage.h linux-2.6.4-rc3/include/asm-i386/linkage.h --- linux-2.6.4-rc2/include/asm-i386/linkage.h 2004-02-17 19:59:57.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-i386/linkage.h 2004-03-09 16:36:29.000000000 -0800 @@ -3,6 +3,7 @@ #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) #define FASTCALL(x) x __attribute__((regparm(3))) +#define fastcall __attribute__((regparm(3))) #ifdef CONFIG_X86_ALIGNMENT_16 #define __ALIGN .align 16,0x90 diff -urN linux-2.6.4-rc2/include/asm-i386/smp.h linux-2.6.4-rc3/include/asm-i386/smp.h --- linux-2.6.4-rc2/include/asm-i386/smp.h 2004-02-17 19:58:26.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-i386/smp.h 2004-03-09 16:36:29.000000000 -0800 @@ -38,7 +38,6 @@ extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); -extern void smp_send_reschedule(int cpu); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); diff -urN linux-2.6.4-rc2/include/asm-ia64/acpi.h linux-2.6.4-rc3/include/asm-ia64/acpi.h --- linux-2.6.4-rc2/include/asm-ia64/acpi.h 2004-02-17 19:59:21.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-ia64/acpi.h 2004-03-09 16:36:29.000000000 -0800 @@ -88,6 +88,8 @@ #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ ((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr)) +#define acpi_strict 1 /* no ACPI spec workarounds on IA64 */ + const char *acpi_get_sysname (void); int acpi_request_vector (u32 int_type); int acpi_register_irq (u32 gsi, u32 polarity, u32 trigger); diff -urN linux-2.6.4-rc2/include/asm-ppc64/iSeries/vio.h linux-2.6.4-rc3/include/asm-ppc64/iSeries/vio.h --- linux-2.6.4-rc2/include/asm-ppc64/iSeries/vio.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-ppc64/iSeries/vio.h 2004-03-09 16:36:30.000000000 -0800 @@ -127,4 +127,8 @@ viorc_openRejected = 0x0301 }; +struct device; + +extern struct device *iSeries_vio_dev; + #endif /* _ISERIES_VIO_H */ diff -urN linux-2.6.4-rc2/include/asm-ppc64/mmu.h linux-2.6.4-rc3/include/asm-ppc64/mmu.h --- linux-2.6.4-rc2/include/asm-ppc64/mmu.h 2004-02-17 19:58:42.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-ppc64/mmu.h 2004-03-09 16:36:30.000000000 -0800 @@ -18,15 +18,25 @@ #ifndef __ASSEMBLY__ -/* Default "unsigned long" context */ -typedef unsigned long mm_context_t; +/* Time to allow for more things here */ +typedef unsigned long mm_context_id_t; +typedef struct { + mm_context_id_t id; +#ifdef CONFIG_HUGETLB_PAGE + int low_hpages; +#endif +} mm_context_t; #ifdef CONFIG_HUGETLB_PAGE -#define CONTEXT_LOW_HPAGES (1UL<<63) +#define KERNEL_LOW_HPAGES .low_hpages = 0, #else -#define CONTEXT_LOW_HPAGES 0 +#define KERNEL_LOW_HPAGES #endif +#define KERNEL_CONTEXT(ea) ({ \ + mm_context_t ctx = { .id = REGION_ID(ea), KERNEL_LOW_HPAGES}; \ + ctx; }) + /* * Hardware Segment Lookaside Buffer Entry * This structure has been padded out to two 64b doublewords (actual SLBE's are diff -urN linux-2.6.4-rc2/include/asm-ppc64/mmu_context.h linux-2.6.4-rc3/include/asm-ppc64/mmu_context.h --- linux-2.6.4-rc2/include/asm-ppc64/mmu_context.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-ppc64/mmu_context.h 2004-03-09 16:36:30.000000000 -0800 @@ -52,7 +52,7 @@ long head; long tail; long size; - mm_context_t elements[LAST_USER_CONTEXT]; + mm_context_id_t elements[LAST_USER_CONTEXT]; }; extern struct mmu_context_queue_t mmu_context_queue; @@ -83,7 +83,6 @@ long head; unsigned long flags; /* This does the right thing across a fork (I hope) */ - unsigned long low_hpages = mm->context & CONTEXT_LOW_HPAGES; spin_lock_irqsave(&mmu_context_queue.lock, flags); @@ -93,8 +92,7 @@ } head = mmu_context_queue.head; - mm->context = mmu_context_queue.elements[head]; - mm->context |= low_hpages; + mm->context.id = mmu_context_queue.elements[head]; head = (head < LAST_USER_CONTEXT-1) ? head+1 : 0; mmu_context_queue.head = head; @@ -132,8 +130,7 @@ #endif mmu_context_queue.size++; - mmu_context_queue.elements[index] = - mm->context & ~CONTEXT_LOW_HPAGES; + mmu_context_queue.elements[index] = mm->context.id; spin_unlock_irqrestore(&mmu_context_queue.lock, flags); } @@ -212,8 +209,6 @@ { unsigned long ordinal, vsid; - context &= ~CONTEXT_LOW_HPAGES; - ordinal = (((ea >> 28) & 0x1fffff) * LAST_USER_CONTEXT) | context; vsid = (ordinal * VSID_RANDOMIZER) & VSID_MASK; diff -urN linux-2.6.4-rc2/include/asm-ppc64/page.h linux-2.6.4-rc3/include/asm-ppc64/page.h --- linux-2.6.4-rc2/include/asm-ppc64/page.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-ppc64/page.h 2004-03-09 16:36:30.000000000 -0800 @@ -32,6 +32,7 @@ /* For 64-bit processes the hugepage range is 1T-1.5T */ #define TASK_HPAGE_BASE (0x0000010000000000UL) #define TASK_HPAGE_END (0x0000018000000000UL) + /* For 32-bit processes the hugepage range is 2-3G */ #define TASK_HPAGE_BASE_32 (0x80000000UL) #define TASK_HPAGE_END_32 (0xc0000000UL) @@ -39,7 +40,7 @@ #define ARCH_HAS_HUGEPAGE_ONLY_RANGE #define is_hugepage_only_range(addr, len) \ ( ((addr > (TASK_HPAGE_BASE-len)) && (addr < TASK_HPAGE_END)) || \ - ((current->mm->context & CONTEXT_LOW_HPAGES) && \ + (current->mm->context.low_hpages && \ (addr > (TASK_HPAGE_BASE_32-len)) && (addr < TASK_HPAGE_END_32)) ) #define hugetlb_free_pgtables free_pgtables #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA @@ -47,7 +48,7 @@ #define in_hugepage_area(context, addr) \ ((cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) && \ ((((addr) >= TASK_HPAGE_BASE) && ((addr) < TASK_HPAGE_END)) || \ - (((context) & CONTEXT_LOW_HPAGES) && \ + ((context).low_hpages && \ (((addr) >= TASK_HPAGE_BASE_32) && ((addr) < TASK_HPAGE_END_32))))) #else /* !CONFIG_HUGETLB_PAGE */ diff -urN linux-2.6.4-rc2/include/asm-sparc/system.h linux-2.6.4-rc3/include/asm-sparc/system.h --- linux-2.6.4-rc2/include/asm-sparc/system.h 2004-02-17 19:58:46.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-sparc/system.h 2004-03-09 16:36:30.000000000 -0800 @@ -75,7 +75,7 @@ #ifdef CONFIG_SMP #define SWITCH_ENTER(prv) \ do { \ - if (test_tsk_thread_flag(prv, TIF_USEDFPU) { \ + if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \ put_psr(get_psr() | PSR_EF); \ fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \ &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \ diff -urN linux-2.6.4-rc2/include/asm-sparc/thread_info.h linux-2.6.4-rc3/include/asm-sparc/thread_info.h --- linux-2.6.4-rc2/include/asm-sparc/thread_info.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-sparc/thread_info.h 2004-03-09 16:36:30.000000000 -0800 @@ -79,9 +79,9 @@ /* * thread information allocation */ -#ifdef CONFIG_SUN4 +#if PAGE_SHIFT == 13 #define THREAD_INFO_ORDER 0 -#else +#else /* PAGE_SHIFT */ #define THREAD_INFO_ORDER 1 #endif diff -urN linux-2.6.4-rc2/include/asm-sparc/unistd.h linux-2.6.4-rc3/include/asm-sparc/unistd.h --- linux-2.6.4-rc2/include/asm-sparc/unistd.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-sparc/unistd.h 2004-03-09 16:36:30.000000000 -0800 @@ -461,7 +461,6 @@ unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff); -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); struct sigaction; asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, diff -urN linux-2.6.4-rc2/include/asm-sparc64/smp.h linux-2.6.4-rc3/include/asm-sparc64/smp.h --- linux-2.6.4-rc2/include/asm-sparc64/smp.h 2004-02-17 19:57:22.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-sparc64/smp.h 2004-03-09 16:36:30.000000000 -0800 @@ -35,11 +35,6 @@ extern cpumask_t phys_cpu_present_map; #define cpu_possible_map phys_cpu_present_map -#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) - -extern atomic_t sparc64_num_cpus_possible; -#define num_possible_cpus() (atomic_read(&sparc64_num_cpus_possible)) - /* * General functions that each host system must provide. */ @@ -75,10 +70,6 @@ #endif /* !(__ASSEMBLY__) */ -#else - -#define num_possible_cpus() (1) - #endif /* !(CONFIG_SMP) */ #define NO_PROC_ID 0xFF diff -urN linux-2.6.4-rc2/include/asm-um/linkage.h linux-2.6.4-rc3/include/asm-um/linkage.h --- linux-2.6.4-rc2/include/asm-um/linkage.h 2004-02-17 19:59:28.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-um/linkage.h 2004-03-09 16:36:30.000000000 -0800 @@ -2,5 +2,6 @@ #define __ASM_LINKAGE_H #define FASTCALL(x) x __attribute__((regparm(3))) +#define fastcall __attribute__((regparm(3))) #endif diff -urN linux-2.6.4-rc2/include/asm-x86_64/acpi.h linux-2.6.4-rc3/include/asm-x86_64/acpi.h --- linux-2.6.4-rc2/include/asm-x86_64/acpi.h 2004-02-17 19:58:39.000000000 -0800 +++ linux-2.6.4-rc3/include/asm-x86_64/acpi.h 2004-03-09 16:36:30.000000000 -0800 @@ -104,6 +104,7 @@ extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; +extern int acpi_strict; /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 diff -urN linux-2.6.4-rc2/include/linux/acpi.h linux-2.6.4-rc3/include/linux/acpi.h --- linux-2.6.4-rc2/include/linux/acpi.h 2004-02-17 19:57:11.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/acpi.h 2004-03-09 16:36:30.000000000 -0800 @@ -233,8 +233,27 @@ } __attribute__ ((packed)); /* + * Simple Boot Flags + * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx + */ +struct acpi_table_sbf +{ + u8 sbf_signature[4]; + u32 sbf_len; + u8 sbf_revision; + u8 sbf_csum; + u8 sbf_oemid[6]; + u8 sbf_oemtable[8]; + u8 sbf_revdata[4]; + u8 sbf_creator[4]; + u8 sbf_crearev[4]; + u8 sbf_cmos; + u8 sbf_spare[3]; +} __attribute__ ((packed)); + +/* * System Resource Affinity Table (SRAT) - * see http://www.microsoft.com/hwdev/design/srat.htm + * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx */ struct acpi_table_srat { @@ -317,6 +336,15 @@ char ec_id[0]; } __attribute__ ((packed)); +/* PCI MMCONFIG */ + +struct acpi_table_mcfg { + struct acpi_table_header header; + u8 reserved[8]; + u32 base_address; + u32 base_reserved; +} __attribute__ ((packed)); + /* Table Handlers */ enum acpi_table_id { @@ -338,6 +366,7 @@ ACPI_SSDT, ACPI_SPMI, ACPI_HPET, + ACPI_MCFG, ACPI_TABLE_COUNT }; @@ -369,6 +398,10 @@ extern int acpi_mp_config; +extern u32 pci_mmcfg_base_addr; + +extern int sbf_port ; + #else /*!CONFIG_ACPI_BOOT*/ #define acpi_mp_config 0 diff -urN linux-2.6.4-rc2/include/linux/blkdev.h linux-2.6.4-rc3/include/linux/blkdev.h --- linux-2.6.4-rc2/include/linux/blkdev.h 2004-02-17 19:57:20.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/blkdev.h 2004-03-09 16:36:30.000000000 -0800 @@ -369,9 +369,12 @@ #define QUEUE_FLAG_READFULL 3 /* write queue has been filled */ #define QUEUE_FLAG_WRITEFULL 4 /* read queue has been filled */ #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ +#define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ #define blk_queue_plugged(q) !list_empty(&(q)->plug_list) #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) +#define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) + #define blk_fs_request(rq) ((rq)->flags & REQ_CMD) #define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC) #define blk_noretry_request(rq) ((rq)->flags & REQ_FAILFAST) diff -urN linux-2.6.4-rc2/include/linux/compat.h linux-2.6.4-rc3/include/linux/compat.h --- linux-2.6.4-rc2/include/linux/compat.h 2004-02-17 19:57:50.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/compat.h 2004-03-09 16:36:30.000000000 -0800 @@ -45,7 +45,7 @@ extern int cp_compat_stat(struct kstat *, struct compat_stat *); extern int get_compat_timespec(struct timespec *, const struct compat_timespec *); -extern int put_compat_timespec(struct timespec *, const struct compat_timespec *); +extern int put_compat_timespec(const struct timespec *, struct compat_timespec *); struct compat_iovec { compat_uptr_t iov_base; diff -urN linux-2.6.4-rc2/include/linux/compat_ioctl.h linux-2.6.4-rc3/include/linux/compat_ioctl.h --- linux-2.6.4-rc2/include/linux/compat_ioctl.h 2004-02-17 19:59:43.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/compat_ioctl.h 2004-03-09 16:36:30.000000000 -0800 @@ -122,7 +122,6 @@ COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) /* DM */ -#ifdef CONFIG_DM_IOCTL_V4 COMPATIBLE_IOCTL(DM_VERSION) COMPATIBLE_IOCTL(DM_LIST_DEVICES) COMPATIBLE_IOCTL(DM_DEV_CREATE) @@ -135,19 +134,6 @@ COMPATIBLE_IOCTL(DM_TABLE_CLEAR) COMPATIBLE_IOCTL(DM_TABLE_DEPS) COMPATIBLE_IOCTL(DM_TABLE_STATUS) -#else -COMPATIBLE_IOCTL(DM_VERSION) -COMPATIBLE_IOCTL(DM_REMOVE_ALL) -COMPATIBLE_IOCTL(DM_DEV_CREATE) -COMPATIBLE_IOCTL(DM_DEV_REMOVE) -COMPATIBLE_IOCTL(DM_DEV_RELOAD) -COMPATIBLE_IOCTL(DM_DEV_SUSPEND) -COMPATIBLE_IOCTL(DM_DEV_RENAME) -COMPATIBLE_IOCTL(DM_DEV_DEPS) -COMPATIBLE_IOCTL(DM_DEV_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_WAIT) -#endif /* Big K */ COMPATIBLE_IOCTL(PIO_FONT) COMPATIBLE_IOCTL(GIO_FONT) diff -urN linux-2.6.4-rc2/include/linux/cpu.h linux-2.6.4-rc3/include/linux/cpu.h --- linux-2.6.4-rc2/include/linux/cpu.h 2004-02-17 19:57:18.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/cpu.h 2004-03-09 16:36:30.000000000 -0800 @@ -21,6 +21,8 @@ #include #include +#include +#include #include struct cpu { @@ -56,9 +58,20 @@ extern struct semaphore cpucontrol; #define lock_cpu_hotplug() down(&cpucontrol) #define unlock_cpu_hotplug() up(&cpucontrol) +#define lock_cpu_hotplug_interruptible() down_interruptible(&cpucontrol) +#define hotcpu_notifier(fn, pri) { \ + static struct notifier_block fn##_nb = { fn, pri }; \ + register_cpu_notifier(&fn##_nb); \ +} +#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) #else #define lock_cpu_hotplug() do { } while (0) #define unlock_cpu_hotplug() do { } while (0) +#define lock_cpu_hotplug_interruptible() 0 +#define hotcpu_notifier(fn, pri) + +/* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */ +#define cpu_is_offline(cpu) 0 #endif #endif /* _LINUX_CPU_H_ */ diff -urN linux-2.6.4-rc2/include/linux/cpumask.h linux-2.6.4-rc3/include/linux/cpumask.h --- linux-2.6.4-rc2/include/linux/cpumask.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/cpumask.h 2004-03-09 16:36:30.000000000 -0800 @@ -12,6 +12,7 @@ extern cpumask_t cpu_possible_map; #define num_online_cpus() cpus_weight(cpu_online_map) +#define num_possible_cpus() cpus_weight(cpu_possible_map) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) #define cpu_possible(cpu) cpu_isset(cpu, cpu_possible_map) @@ -24,7 +25,9 @@ #define for_each_online_cpu(cpu) for_each_cpu_mask(cpu, cpu_online_map) #else #define cpu_online_map cpumask_of_cpu(0) +#define cpu_possible_map cpumask_of_cpu(0) #define num_online_cpus() 1 +#define num_possible_cpus() 1 #define cpu_online(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define cpu_possible(cpu) ({ BUG_ON((cpu) != 0); 1; }) diff -urN linux-2.6.4-rc2/include/linux/dm-ioctl-v1.h linux-2.6.4-rc3/include/linux/dm-ioctl-v1.h --- linux-2.6.4-rc2/include/linux/dm-ioctl-v1.h 2004-02-17 19:59:59.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/dm-ioctl-v1.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2001 Sistina Software (UK) Limited. - * - * This file is released under the LGPL. - */ - -#ifndef _LINUX_DM_IOCTL_V1_H -#define _LINUX_DM_IOCTL_V1_H - -#include - -#define DM_DIR "mapper" /* Slashes not supported */ -#define DM_MAX_TYPE_NAME 16 -#define DM_NAME_LEN 128 -#define DM_UUID_LEN 129 - -/* - * Implements a traditional ioctl interface to the device mapper. - */ - -/* - * All ioctl arguments consist of a single chunk of memory, with - * this structure at the start. If a uuid is specified any - * lookup (eg. for a DM_INFO) will be done on that, *not* the - * name. - */ -struct dm_ioctl { - /* - * The version number is made up of three parts: - * major - no backward or forward compatibility, - * minor - only backwards compatible, - * patch - both backwards and forwards compatible. - * - * All clients of the ioctl interface should fill in the - * version number of the interface that they were - * compiled with. - * - * All recognised ioctl commands (ie. those that don't - * return -ENOTTY) fill out this field, even if the - * command failed. - */ - uint32_t version[3]; /* in/out */ - uint32_t data_size; /* total size of data passed in - * including this struct */ - - uint32_t data_start; /* offset to start of data - * relative to start of this struct */ - - uint32_t target_count; /* in/out */ - uint32_t open_count; /* out */ - uint32_t flags; /* in/out */ - - __kernel_old_dev_t dev; /* in/out */ - - char name[DM_NAME_LEN]; /* device name */ - char uuid[DM_UUID_LEN]; /* unique identifier for - * the block device */ -}; - -/* - * Used to specify tables. These structures appear after the - * dm_ioctl. - */ -struct dm_target_spec { - int32_t status; /* used when reading from kernel only */ - uint64_t sector_start; - uint32_t length; - - /* - * Offset in bytes (from the start of this struct) to - * next target_spec. - */ - uint32_t next; - - char target_type[DM_MAX_TYPE_NAME]; - - /* - * Parameter string starts immediately after this object. - * Be careful to add padding after string to ensure correct - * alignment of subsequent dm_target_spec. - */ -}; - -/* - * Used to retrieve the target dependencies. - */ -struct dm_target_deps { - uint32_t count; - - __kernel_old_dev_t dev[0]; /* out */ -}; - -/* - * If you change this make sure you make the corresponding change - * to dm-ioctl.c:lookup_ioctl() - */ -enum { - /* Top level cmds */ - DM_VERSION_CMD = 0, - DM_REMOVE_ALL_CMD, - - /* device level cmds */ - DM_DEV_CREATE_CMD, - DM_DEV_REMOVE_CMD, - DM_DEV_RELOAD_CMD, - DM_DEV_RENAME_CMD, - DM_DEV_SUSPEND_CMD, - DM_DEV_DEPS_CMD, - DM_DEV_STATUS_CMD, - - /* target level cmds */ - DM_TARGET_STATUS_CMD, - DM_TARGET_WAIT_CMD -}; - -#define DM_IOCTL 0xfd - -#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) -#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) - -#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) -#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) -#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl) -#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) -#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) -#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl) -#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) - -#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl) -#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl) - -#define DM_VERSION_MAJOR 1 -#define DM_VERSION_MINOR 0 -#define DM_VERSION_PATCHLEVEL 6 -#define DM_VERSION_EXTRA "-ioctl (2002-10-15)" - -/* Status bits */ -#define DM_READONLY_FLAG 0x00000001 -#define DM_SUSPEND_FLAG 0x00000002 -#define DM_EXISTS_FLAG 0x00000004 -#define DM_PERSISTENT_DEV_FLAG 0x00000008 - -/* - * Flag passed into ioctl STATUS command to get table information - * rather than current status. - */ -#define DM_STATUS_TABLE_FLAG 0x00000010 - -#endif /* _LINUX_DM_IOCTL_H */ diff -urN linux-2.6.4-rc2/include/linux/dm-ioctl-v4.h linux-2.6.4-rc3/include/linux/dm-ioctl-v4.h --- linux-2.6.4-rc2/include/linux/dm-ioctl-v4.h 2004-02-17 19:57:15.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/dm-ioctl-v4.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited. - * - * This file is released under the LGPL. - */ - -#ifndef _LINUX_DM_IOCTL_V4_H -#define _LINUX_DM_IOCTL_V4_H - -#include - -#define DM_DIR "mapper" /* Slashes not supported */ -#define DM_MAX_TYPE_NAME 16 -#define DM_NAME_LEN 128 -#define DM_UUID_LEN 129 - -/* - * A traditional ioctl interface for the device mapper. - * - * Each device can have two tables associated with it, an - * 'active' table which is the one currently used by io passing - * through the device, and an 'inactive' one which is a table - * that is being prepared as a replacement for the 'active' one. - * - * DM_VERSION: - * Just get the version information for the ioctl interface. - * - * DM_REMOVE_ALL: - * Remove all dm devices, destroy all tables. Only really used - * for debug. - * - * DM_LIST_DEVICES: - * Get a list of all the dm device names. - * - * DM_DEV_CREATE: - * Create a new device, neither the 'active' or 'inactive' table - * slots will be filled. The device will be in suspended state - * after creation, however any io to the device will get errored - * since it will be out-of-bounds. - * - * DM_DEV_REMOVE: - * Remove a device, destroy any tables. - * - * DM_DEV_RENAME: - * Rename a device. - * - * DM_SUSPEND: - * This performs both suspend and resume, depending which flag is - * passed in. - * Suspend: This command will not return until all pending io to - * the device has completed. Further io will be deferred until - * the device is resumed. - * Resume: It is no longer an error to issue this command on an - * unsuspended device. If a table is present in the 'inactive' - * slot, it will be moved to the active slot, then the old table - * from the active slot will be _destroyed_. Finally the device - * is resumed. - * - * DM_DEV_STATUS: - * Retrieves the status for the table in the 'active' slot. - * - * DM_DEV_WAIT: - * Wait for a significant event to occur to the device. This - * could either be caused by an event triggered by one of the - * targets of the table in the 'active' slot, or a table change. - * - * DM_TABLE_LOAD: - * Load a table into the 'inactive' slot for the device. The - * device does _not_ need to be suspended prior to this command. - * - * DM_TABLE_CLEAR: - * Destroy any table in the 'inactive' slot (ie. abort). - * - * DM_TABLE_DEPS: - * Return a set of device dependencies for the 'active' table. - * - * DM_TABLE_STATUS: - * Return the targets status for the 'active' table. - */ - -/* - * All ioctl arguments consist of a single chunk of memory, with - * this structure at the start. If a uuid is specified any - * lookup (eg. for a DM_INFO) will be done on that, *not* the - * name. - */ -struct dm_ioctl { - /* - * The version number is made up of three parts: - * major - no backward or forward compatibility, - * minor - only backwards compatible, - * patch - both backwards and forwards compatible. - * - * All clients of the ioctl interface should fill in the - * version number of the interface that they were - * compiled with. - * - * All recognised ioctl commands (ie. those that don't - * return -ENOTTY) fill out this field, even if the - * command failed. - */ - uint32_t version[3]; /* in/out */ - uint32_t data_size; /* total size of data passed in - * including this struct */ - - uint32_t data_start; /* offset to start of data - * relative to start of this struct */ - - uint32_t target_count; /* in/out */ - int32_t open_count; /* out */ - uint32_t flags; /* in/out */ - uint32_t event_nr; /* in/out */ - uint32_t padding; - - uint64_t dev; /* in/out */ - - char name[DM_NAME_LEN]; /* device name */ - char uuid[DM_UUID_LEN]; /* unique identifier for - * the block device */ -}; - -/* - * Used to specify tables. These structures appear after the - * dm_ioctl. - */ -struct dm_target_spec { - uint64_t sector_start; - uint64_t length; - int32_t status; /* used when reading from kernel only */ - - /* - * Offset in bytes (from the start of this struct) to - * next target_spec. - */ - uint32_t next; - - char target_type[DM_MAX_TYPE_NAME]; - - /* - * Parameter string starts immediately after this object. - * Be careful to add padding after string to ensure correct - * alignment of subsequent dm_target_spec. - */ -}; - -/* - * Used to retrieve the target dependencies. - */ -struct dm_target_deps { - uint32_t count; /* Array size */ - uint32_t padding; /* unused */ - uint64_t dev[0]; /* out */ -}; - -/* - * Used to get a list of all dm devices. - */ -struct dm_name_list { - uint64_t dev; - uint32_t next; /* offset to the next record from - the _start_ of this */ - char name[0]; -}; - -/* - * If you change this make sure you make the corresponding change - * to dm-ioctl.c:lookup_ioctl() - */ -enum { - /* Top level cmds */ - DM_VERSION_CMD = 0, - DM_REMOVE_ALL_CMD, - DM_LIST_DEVICES_CMD, - - /* device level cmds */ - DM_DEV_CREATE_CMD, - DM_DEV_REMOVE_CMD, - DM_DEV_RENAME_CMD, - DM_DEV_SUSPEND_CMD, - DM_DEV_STATUS_CMD, - DM_DEV_WAIT_CMD, - - /* Table level cmds */ - DM_TABLE_LOAD_CMD, - DM_TABLE_CLEAR_CMD, - DM_TABLE_DEPS_CMD, - DM_TABLE_STATUS_CMD, -}; - -#define DM_IOCTL 0xfd - -#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) -#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) -#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl) - -#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) -#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) -#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) -#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) -#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) -#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl) - -#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl) -#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl) -#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl) -#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl) - -#define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 0 -#define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2003-06-04)" - -/* Status bits */ -#define DM_READONLY_FLAG (1 << 0) /* In/Out */ -#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */ -#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */ - -/* - * Flag passed into ioctl STATUS command to get table information - * rather than current status. - */ -#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */ - -/* - * Flags that indicate whether a table is present in either of - * the two table slots that a device has. - */ -#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */ -#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */ - -/* - * Indicates that the buffer passed in wasn't big enough for the - * results. - */ -#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */ - -#endif /* _LINUX_DM_IOCTL_H */ diff -urN linux-2.6.4-rc2/include/linux/dm-ioctl.h linux-2.6.4-rc3/include/linux/dm-ioctl.h --- linux-2.6.4-rc2/include/linux/dm-ioctl.h 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/dm-ioctl.h 2004-03-09 16:36:30.000000000 -0800 @@ -1,18 +1,237 @@ /* - * Copyright (C) 2003 Sistina Software (UK) Limited. + * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited. * * This file is released under the LGPL. */ -#ifndef _LINUX_DM_IOCTL_H -#define _LINUX_DM_IOCTL_H +#ifndef _LINUX_DM_IOCTL_V4_H +#define _LINUX_DM_IOCTL_V4_H -#include +#include -#ifdef CONFIG_DM_IOCTL_V4 -#include "dm-ioctl-v4.h" -#else -#include "dm-ioctl-v1.h" -#endif +#define DM_DIR "mapper" /* Slashes not supported */ +#define DM_MAX_TYPE_NAME 16 +#define DM_NAME_LEN 128 +#define DM_UUID_LEN 129 -#endif +/* + * A traditional ioctl interface for the device mapper. + * + * Each device can have two tables associated with it, an + * 'active' table which is the one currently used by io passing + * through the device, and an 'inactive' one which is a table + * that is being prepared as a replacement for the 'active' one. + * + * DM_VERSION: + * Just get the version information for the ioctl interface. + * + * DM_REMOVE_ALL: + * Remove all dm devices, destroy all tables. Only really used + * for debug. + * + * DM_LIST_DEVICES: + * Get a list of all the dm device names. + * + * DM_DEV_CREATE: + * Create a new device, neither the 'active' or 'inactive' table + * slots will be filled. The device will be in suspended state + * after creation, however any io to the device will get errored + * since it will be out-of-bounds. + * + * DM_DEV_REMOVE: + * Remove a device, destroy any tables. + * + * DM_DEV_RENAME: + * Rename a device. + * + * DM_SUSPEND: + * This performs both suspend and resume, depending which flag is + * passed in. + * Suspend: This command will not return until all pending io to + * the device has completed. Further io will be deferred until + * the device is resumed. + * Resume: It is no longer an error to issue this command on an + * unsuspended device. If a table is present in the 'inactive' + * slot, it will be moved to the active slot, then the old table + * from the active slot will be _destroyed_. Finally the device + * is resumed. + * + * DM_DEV_STATUS: + * Retrieves the status for the table in the 'active' slot. + * + * DM_DEV_WAIT: + * Wait for a significant event to occur to the device. This + * could either be caused by an event triggered by one of the + * targets of the table in the 'active' slot, or a table change. + * + * DM_TABLE_LOAD: + * Load a table into the 'inactive' slot for the device. The + * device does _not_ need to be suspended prior to this command. + * + * DM_TABLE_CLEAR: + * Destroy any table in the 'inactive' slot (ie. abort). + * + * DM_TABLE_DEPS: + * Return a set of device dependencies for the 'active' table. + * + * DM_TABLE_STATUS: + * Return the targets status for the 'active' table. + */ + +/* + * All ioctl arguments consist of a single chunk of memory, with + * this structure at the start. If a uuid is specified any + * lookup (eg. for a DM_INFO) will be done on that, *not* the + * name. + */ +struct dm_ioctl { + /* + * The version number is made up of three parts: + * major - no backward or forward compatibility, + * minor - only backwards compatible, + * patch - both backwards and forwards compatible. + * + * All clients of the ioctl interface should fill in the + * version number of the interface that they were + * compiled with. + * + * All recognised ioctl commands (ie. those that don't + * return -ENOTTY) fill out this field, even if the + * command failed. + */ + uint32_t version[3]; /* in/out */ + uint32_t data_size; /* total size of data passed in + * including this struct */ + + uint32_t data_start; /* offset to start of data + * relative to start of this struct */ + + uint32_t target_count; /* in/out */ + int32_t open_count; /* out */ + uint32_t flags; /* in/out */ + uint32_t event_nr; /* in/out */ + uint32_t padding; + + uint64_t dev; /* in/out */ + + char name[DM_NAME_LEN]; /* device name */ + char uuid[DM_UUID_LEN]; /* unique identifier for + * the block device */ +}; + +/* + * Used to specify tables. These structures appear after the + * dm_ioctl. + */ +struct dm_target_spec { + uint64_t sector_start; + uint64_t length; + int32_t status; /* used when reading from kernel only */ + + /* + * Offset in bytes (from the start of this struct) to + * next target_spec. + */ + uint32_t next; + + char target_type[DM_MAX_TYPE_NAME]; + + /* + * Parameter string starts immediately after this object. + * Be careful to add padding after string to ensure correct + * alignment of subsequent dm_target_spec. + */ +}; + +/* + * Used to retrieve the target dependencies. + */ +struct dm_target_deps { + uint32_t count; /* Array size */ + uint32_t padding; /* unused */ + uint64_t dev[0]; /* out */ +}; + +/* + * Used to get a list of all dm devices. + */ +struct dm_name_list { + uint64_t dev; + uint32_t next; /* offset to the next record from + the _start_ of this */ + char name[0]; +}; + +/* + * If you change this make sure you make the corresponding change + * to dm-ioctl.c:lookup_ioctl() + */ +enum { + /* Top level cmds */ + DM_VERSION_CMD = 0, + DM_REMOVE_ALL_CMD, + DM_LIST_DEVICES_CMD, + + /* device level cmds */ + DM_DEV_CREATE_CMD, + DM_DEV_REMOVE_CMD, + DM_DEV_RENAME_CMD, + DM_DEV_SUSPEND_CMD, + DM_DEV_STATUS_CMD, + DM_DEV_WAIT_CMD, + + /* Table level cmds */ + DM_TABLE_LOAD_CMD, + DM_TABLE_CLEAR_CMD, + DM_TABLE_DEPS_CMD, + DM_TABLE_STATUS_CMD, +}; + +#define DM_IOCTL 0xfd + +#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) +#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) +#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl) + +#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) +#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) +#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) +#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) +#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) +#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl) + +#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl) +#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl) +#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl) +#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl) + +#define DM_VERSION_MAJOR 4 +#define DM_VERSION_MINOR 0 +#define DM_VERSION_PATCHLEVEL 0 +#define DM_VERSION_EXTRA "-ioctl (2003-06-04)" + +/* Status bits */ +#define DM_READONLY_FLAG (1 << 0) /* In/Out */ +#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */ +#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */ + +/* + * Flag passed into ioctl STATUS command to get table information + * rather than current status. + */ +#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */ + +/* + * Flags that indicate whether a table is present in either of + * the two table slots that a device has. + */ +#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */ +#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */ + +/* + * Indicates that the buffer passed in wasn't big enough for the + * results. + */ +#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */ + +#endif /* _LINUX_DM_IOCTL_H */ diff -urN linux-2.6.4-rc2/include/linux/i2o-dev.h linux-2.6.4-rc3/include/linux/i2o-dev.h --- linux-2.6.4-rc2/include/linux/i2o-dev.h 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/i2o-dev.h 2004-03-09 16:36:31.000000000 -0800 @@ -182,7 +182,7 @@ { u32 adapter_id; u32 parent_tid:12; - u32 tate:4; + u32 state:4; u32 bus_num:8; u32 bus_type:8; union diff -urN linux-2.6.4-rc2/include/linux/i2o.h linux-2.6.4-rc3/include/linux/i2o.h --- linux-2.6.4-rc2/include/linux/i2o.h 2004-02-17 19:57:20.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/i2o.h 2004-03-09 16:36:31.000000000 -0800 @@ -544,6 +544,25 @@ #define I2O_DSC_DEVICE_BUSY 0x001B #define I2O_DSC_DEVICE_NOT_AVAILABLE 0x001C +/* DetailedStatusCode defines for Block Storage Operation: Table 6-7 Detailed + Status Codes.*/ + +#define I2O_BSA_DSC_SUCCESS 0x0000 +#define I2O_BSA_DSC_MEDIA_ERROR 0x0001 +#define I2O_BSA_DSC_ACCESS_ERROR 0x0002 +#define I2O_BSA_DSC_DEVICE_FAILURE 0x0003 +#define I2O_BSA_DSC_DEVICE_NOT_READY 0x0004 +#define I2O_BSA_DSC_MEDIA_NOT_PRESENT 0x0005 +#define I2O_BSA_DSC_MEDIA_LOCKED 0x0006 +#define I2O_BSA_DSC_MEDIA_FAILURE 0x0007 +#define I2O_BSA_DSC_PROTOCOL_FAILURE 0x0008 +#define I2O_BSA_DSC_BUS_FAILURE 0x0009 +#define I2O_BSA_DSC_ACCESS_VIOLATION 0x000A +#define I2O_BSA_DSC_WRITE_PROTECTED 0x000B +#define I2O_BSA_DSC_DEVICE_RESET 0x000C +#define I2O_BSA_DSC_VOLUME_CHANGED 0x000D +#define I2O_BSA_DSC_TIMEOUT 0x000E + /* FailureStatusCodes, Table 3-3 Message Failure Codes */ #define I2O_FSC_TRANSPORT_SERVICE_SUSPENDED 0x81 diff -urN linux-2.6.4-rc2/include/linux/linkage.h linux-2.6.4-rc3/include/linux/linkage.h --- linux-2.6.4-rc2/include/linux/linkage.h 2004-02-17 19:58:26.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/linkage.h 2004-03-09 16:36:31.000000000 -0800 @@ -37,6 +37,7 @@ #ifndef FASTCALL #define FASTCALL(x) x +#define fastcall #endif #endif diff -urN linux-2.6.4-rc2/include/linux/mm.h linux-2.6.4-rc3/include/linux/mm.h --- linux-2.6.4-rc2/include/linux/mm.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/mm.h 2004-03-09 16:36:31.000000000 -0800 @@ -530,7 +530,8 @@ /* mmap.c */ extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); -extern void build_mmap_rb(struct mm_struct *); +extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *, + struct rb_node **, struct rb_node *); extern void exit_mmap(struct mm_struct *); extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); diff -urN linux-2.6.4-rc2/include/linux/nfsd/nfsfh.h linux-2.6.4-rc3/include/linux/nfsd/nfsfh.h --- linux-2.6.4-rc2/include/linux/nfsd/nfsfh.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/nfsd/nfsfh.h 2004-03-09 16:36:31.000000000 -0800 @@ -66,8 +66,9 @@ * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number * NOTE: we cannot use the kdev_t device id value, because kdev_t.h * says we mustn't. We must break it up and reassemble. - * Possible future encodings: * 1 - 4 byte user specified identifier + * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED + * 3 - 4 byte device id, encoded for user-space, 4 byte inode number * * The fileid_type identified how the file within the filesystem is encoded. * This is (will be) passed to, and set by, the underlying filesystem if it supports @@ -114,6 +115,7 @@ #define fh_auth_type fh_base.fh_new.fb_auth_type #define fh_fileid_type fh_base.fh_new.fb_fileid_type #define fh_auth fh_base.fh_new.fb_auth +#define fh_fsid fh_base.fh_new.fb_auth #ifdef __KERNEL__ @@ -183,6 +185,23 @@ fsidv[2] = ino_t_to_u32(ino); } +static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino) +{ + fsidv[0] = new_encode_dev(dev); + fsidv[1] = ino_t_to_u32(ino); +} + +static inline int key_len(int type) +{ + switch(type) { + case 0: return 8; + case 1: return 4; + case 2: return 12; + case 3: return 8; + default: return 0; + } +} + /* * Shorthand for dprintk()'s */ diff -urN linux-2.6.4-rc2/include/linux/pci_ids.h linux-2.6.4-rc3/include/linux/pci_ids.h --- linux-2.6.4-rc2/include/linux/pci_ids.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/pci_ids.h 2004-03-09 16:36:31.000000000 -0800 @@ -1808,6 +1808,7 @@ #define PCI_VENDOR_ID_AFAVLAB 0x14db #define PCI_DEVICE_ID_AFAVLAB_P028 0x2180 +#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5700 0x1644 diff -urN linux-2.6.4-rc2/include/linux/sched.h linux-2.6.4-rc3/include/linux/sched.h --- linux-2.6.4-rc2/include/linux/sched.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/sched.h 2004-03-09 16:36:31.000000000 -0800 @@ -602,7 +602,7 @@ extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state)); extern int FASTCALL(wake_up_process(struct task_struct * tsk)); #ifdef CONFIG_SMP - extern void FASTCALL(kick_process(struct task_struct * tsk)); + extern void kick_process(struct task_struct *tsk); #else static inline void kick_process(struct task_struct *tsk) { } #endif diff -urN linux-2.6.4-rc2/include/linux/serial_core.h linux-2.6.4-rc3/include/linux/serial_core.h --- linux-2.6.4-rc2/include/linux/serial_core.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/serial_core.h 2004-03-09 16:36:31.000000000 -0800 @@ -84,6 +84,7 @@ #include #include #include +#include struct uart_port; struct uart_info; diff -urN linux-2.6.4-rc2/include/linux/smp.h linux-2.6.4-rc3/include/linux/smp.h --- linux-2.6.4-rc2/include/linux/smp.h 2004-02-17 19:58:11.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/smp.h 2004-03-09 16:36:31.000000000 -0800 @@ -30,7 +30,7 @@ /* * sends a 'reschedule' event to another CPU: */ -extern void FASTCALL(smp_send_reschedule(int cpu)); +extern void smp_send_reschedule(int cpu); /* diff -urN linux-2.6.4-rc2/include/linux/stop_machine.h linux-2.6.4-rc3/include/linux/stop_machine.h --- linux-2.6.4-rc2/include/linux/stop_machine.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/stop_machine.h 2004-03-09 16:36:31.000000000 -0800 @@ -0,0 +1,52 @@ +#ifndef _LINUX_STOP_MACHINE +#define _LINUX_STOP_MACHINE +/* "Bogolock": stop the entire machine, disable interrupts. This is a + very heavy lock, which is equivalent to grabbing every spinlock + (and more). So the "read" side to such a lock is anything which + diables preeempt. */ +#include +#include +#include + +#ifdef CONFIG_SMP +/** + * stop_machine_run: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr for the @fn() + * @cpu: the cpu to run @fn() on (or any, if @cpu == NR_CPUS. + * + * Description: This causes a thread to be scheduled on every other cpu, + * each of which disables interrupts, and finally interrupts are disabled + * on the current CPU. The result is that noone is holding a spinlock + * or inside any other preempt-disabled region when @fn() runs. + * + * This can be thought of as a very heavy write lock, equivalent to + * grabbing every spinlock in the kernel. */ +int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu); + +/** + * __stop_machine_run: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr for the @fn + * @cpu: the cpu to run @fn on (or any, if @cpu == NR_CPUS. + * + * Description: This is a special version of the above, which returns the + * thread which has run @fn(): kthread_stop will return the return value + * of @fn(). Used by hotplug cpu. + */ +struct task_struct *__stop_machine_run(int (*fn)(void *), void *data, + unsigned int cpu); + +#else + +static inline int stop_machine_run(int (*fn)(void *), void *data, + unsigned int cpu) +{ + int ret; + local_irq_disable(); + ret = fn(data); + local_irq_enable(); + return ret; +} +#endif /* CONFIG_SMP */ +#endif /* _LINUX_STOP_MACHINE */ diff -urN linux-2.6.4-rc2/include/linux/syscalls.h linux-2.6.4-rc3/include/linux/syscalls.h --- linux-2.6.4-rc2/include/linux/syscalls.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/syscalls.h 2004-03-09 16:36:31.000000000 -0800 @@ -386,24 +386,24 @@ unsigned int count); asmlinkage long sys_setsockopt(int fd, int level, int optname, - char *optval, int optlen); + char __user *optval, int optlen); asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen); -asmlinkage long sys_bind(int, struct sockaddr *, int); -asmlinkage long sys_connect(int, struct sockaddr *, int); -asmlinkage long sys_accept(int, struct sockaddr *, int *); -asmlinkage long sys_getsockname(int, struct sockaddr *, int *); -asmlinkage long sys_getpeername(int, struct sockaddr *, int *); -asmlinkage long sys_send(int, void *, size_t, unsigned); -asmlinkage long sys_sendto(int, void *, size_t, unsigned, - struct sockaddr *, int); +asmlinkage long sys_bind(int, struct sockaddr __user *, int); +asmlinkage long sys_connect(int, struct sockaddr __user *, int); +asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); +asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); +asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); +asmlinkage long sys_send(int, void __user *, size_t, unsigned); +asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, + struct sockaddr __user *, int); asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); -asmlinkage long sys_recv(int, void *, size_t, unsigned); -asmlinkage long sys_recvfrom(int, void *, size_t, unsigned, - struct sockaddr *, int *); +asmlinkage long sys_recv(int, void __user *, size_t, unsigned); +asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, + struct sockaddr __user *, int __user *); asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); asmlinkage long sys_socket(int, int, int); -asmlinkage long sys_socketpair(int, int, int, int [2]); +asmlinkage long sys_socketpair(int, int, int, int __user *); asmlinkage long sys_socketcall(int call, unsigned long __user *args); asmlinkage long sys_listen(int, int); asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, diff -urN linux-2.6.4-rc2/include/linux/sysctl.h linux-2.6.4-rc3/include/linux/sysctl.h --- linux-2.6.4-rc2/include/linux/sysctl.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/linux/sysctl.h 2004-03-09 16:36:31.000000000 -0800 @@ -321,6 +321,7 @@ NET_TCP_LOW_LATENCY=93, NET_IPV4_IPFRAG_SECRET_INTERVAL=94, NET_TCP_WESTWOOD=95, + NET_IPV4_IGMP_MAX_MSF=96, }; enum { @@ -404,7 +405,8 @@ NET_IPV6_IP6FRAG_HIGH_THRESH=21, NET_IPV6_IP6FRAG_LOW_THRESH=22, NET_IPV6_IP6FRAG_TIME=23, - NET_IPV6_IP6FRAG_SECRET_INTERVAL=24 + NET_IPV6_IP6FRAG_SECRET_INTERVAL=24, + NET_IPV6_MLD_MAX_MSF=25, }; enum { diff -urN linux-2.6.4-rc2/include/net/bluetooth/hci.h linux-2.6.4-rc3/include/net/bluetooth/hci.h --- linux-2.6.4-rc2/include/net/bluetooth/hci.h 2004-02-17 19:59:25.000000000 -0800 +++ linux-2.6.4-rc3/include/net/bluetooth/hci.h 2004-03-09 16:36:31.000000000 -0800 @@ -35,21 +35,31 @@ #define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) /* HCI dev events */ -#define HCI_DEV_REG 1 -#define HCI_DEV_UNREG 2 -#define HCI_DEV_UP 3 -#define HCI_DEV_DOWN 4 -#define HCI_DEV_SUSPEND 5 -#define HCI_DEV_RESUME 6 +#define HCI_DEV_REG 1 +#define HCI_DEV_UNREG 2 +#define HCI_DEV_UP 3 +#define HCI_DEV_DOWN 4 +#define HCI_DEV_SUSPEND 5 +#define HCI_DEV_RESUME 6 + +/* HCI notify events */ +#define HCI_NOTIFY_CONN_ADD 1 +#define HCI_NOTIFY_CONN_DEL 2 +#define HCI_NOTIFY_VOICE_SETTING 3 /* HCI device types */ #define HCI_VHCI 0 #define HCI_USB 1 #define HCI_PCCARD 2 -#define HCI_UART 3 -#define HCI_RS232 4 +#define HCI_UART 3 +#define HCI_RS232 4 #define HCI_PCI 5 +/* HCI device quirks */ +enum { + HCI_QUIRK_RESET_ON_INIT +}; + /* HCI device flags */ enum { HCI_UP, @@ -90,24 +100,24 @@ #define HCIINQUIRY _IOR('H', 240, int) /* HCI timeouts */ -#define HCI_CONN_TIMEOUT (HZ * 40) -#define HCI_DISCONN_TIMEOUT (HZ * 2) +#define HCI_CONN_TIMEOUT (HZ * 40) +#define HCI_DISCONN_TIMEOUT (HZ * 2) #define HCI_CONN_IDLE_TIMEOUT (HZ * 60) /* HCI Packet types */ #define HCI_COMMAND_PKT 0x01 -#define HCI_ACLDATA_PKT 0x02 -#define HCI_SCODATA_PKT 0x03 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 #define HCI_EVENT_PKT 0x04 #define HCI_UNKNOWN_PKT 0xff /* HCI Packet types */ -#define HCI_DM1 0x0008 -#define HCI_DM3 0x0400 -#define HCI_DM5 0x4000 -#define HCI_DH1 0x0010 -#define HCI_DH3 0x0800 -#define HCI_DH5 0x8000 +#define HCI_DM1 0x0008 +#define HCI_DM3 0x0400 +#define HCI_DM5 0x4000 +#define HCI_DH1 0x0010 +#define HCI_DH3 0x0800 +#define HCI_DH5 0x8000 #define HCI_HV1 0x0020 #define HCI_HV2 0x0040 diff -urN linux-2.6.4-rc2/include/net/bluetooth/hci_core.h linux-2.6.4-rc3/include/net/bluetooth/hci_core.h --- linux-2.6.4-rc2/include/net/bluetooth/hci_core.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/net/bluetooth/hci_core.h 2004-03-09 16:36:31.000000000 -0800 @@ -77,6 +77,8 @@ __u16 link_policy; __u16 link_mode; + unsigned long quirks; + atomic_t cmd_cnt; unsigned int acl_cnt; unsigned int sco_cnt; @@ -128,6 +130,7 @@ int (*flush)(struct hci_dev *hdev); int (*send)(struct sk_buff *skb); void (*destruct)(struct hci_dev *hdev); + void (*notify)(struct hci_dev *hdev, unsigned int evt); int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); }; diff -urN linux-2.6.4-rc2/include/net/ipv6.h linux-2.6.4-rc3/include/net/ipv6.h --- linux-2.6.4-rc2/include/net/ipv6.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/net/ipv6.h 2004-03-09 16:36:31.000000000 -0800 @@ -108,6 +108,7 @@ /* sysctls */ extern int sysctl_ipv6_bindv6only; +extern int sysctl_mld_max_msf; /* MIBs */ DECLARE_SNMP_STAT(struct ipv6_mib, ipv6_statistics); diff -urN linux-2.6.4-rc2/include/net/irda/crc.h linux-2.6.4-rc3/include/net/irda/crc.h --- linux-2.6.4-rc2/include/net/irda/crc.h 2004-02-17 19:57:21.000000000 -0800 +++ linux-2.6.4-rc3/include/net/irda/crc.h 2004-03-09 16:36:31.000000000 -0800 @@ -28,6 +28,6 @@ } /* Recompute the FCS with len bytes appended. */ -unsigned short irda_calc_crc16( __u16 fcs, __u8 const *buf, size_t len); +__u16 irda_calc_crc16( __u16 fcs, __u8 const *buf, size_t len); #endif diff -urN linux-2.6.4-rc2/include/net/irda/irda.h linux-2.6.4-rc3/include/net/irda/irda.h --- linux-2.6.4-rc2/include/net/irda/irda.h 2004-02-17 19:57:22.000000000 -0800 +++ linux-2.6.4-rc3/include/net/irda/irda.h 2004-03-09 16:36:31.000000000 -0800 @@ -61,7 +61,7 @@ #ifdef CONFIG_IRDA_DEBUG -extern __u32 irda_debug; +extern unsigned int irda_debug; /* use 0 for production, 1 for verification, >2 for debug */ #define IRDA_DEBUG_LEVEL 0 diff -urN linux-2.6.4-rc2/include/net/irda/irda_device.h linux-2.6.4-rc3/include/net/irda/irda_device.h --- linux-2.6.4-rc2/include/net/irda/irda_device.h 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/include/net/irda/irda_device.h 2004-03-09 16:36:31.000000000 -0800 @@ -227,7 +227,6 @@ int irda_device_set_raw_mode(struct net_device* self, int status); int irda_device_set_dtr_rts(struct net_device *dev, int dtr, int rts); int irda_device_change_speed(struct net_device *dev, __u32 speed); -void irda_device_setup(struct net_device *dev); struct net_device *alloc_irdadev(int sizeof_priv); /* Dongle interface */ @@ -253,28 +252,11 @@ * Utility function for getting the minimum turnaround time out of * the skb, where it has been hidden in the cb field. */ -#define irda_get_mtt(skb) ( \ - IRDA_MIN(10000, \ - (((struct irda_skb_cb *) skb->cb)->magic == LAP_MAGIC) ? \ - ((struct irda_skb_cb *)(skb->cb))->mtt : 10000 \ - ) \ -) - -#if 0 -extern inline __u16 irda_get_mtt(struct sk_buff *skb) +static inline __u16 irda_get_mtt(const struct sk_buff *skb) { - __u16 mtt; - - if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC) - mtt = 10000; - else - mtt = ((struct irda_skb_cb *)(skb->cb))->mtt; - - ASSERT(mtt <= 10000, return 10000;); - - return mtt; + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->mtt : 10000; } -#endif /* * Function irda_get_next_speed (skb) @@ -283,24 +265,11 @@ * * Note : return -1 for user space frames */ -#define irda_get_next_speed(skb) ( \ - (((struct irda_skb_cb*) skb->cb)->magic == LAP_MAGIC) ? \ - ((struct irda_skb_cb *)(skb->cb))->next_speed : -1 \ -) - -#if 0 -extern inline __u32 irda_get_next_speed(struct sk_buff *skb) +static inline __u32 irda_get_next_speed(const struct sk_buff *skb) { - __u32 speed; - - if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC) - speed = -1; - else - speed = ((struct irda_skb_cb *)(skb->cb))->next_speed; - - return speed; + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->next_speed : -1; } -#endif /* * Function irda_get_next_xbofs (skb) @@ -309,10 +278,11 @@ * * Note : default to 10 for user space frames */ -#define irda_get_xbofs(skb) ( \ - (((struct irda_skb_cb*) skb->cb)->magic == LAP_MAGIC) ? \ - ((struct irda_skb_cb *)(skb->cb))->xbofs : 10 \ -) +static inline __u16 irda_get_xbofs(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->xbofs : 10; +} /* * Function irda_get_next_xbofs (skb) @@ -321,11 +291,11 @@ * * Note : return -1 for user space frames */ -#define irda_get_next_xbofs(skb) ( \ - (((struct irda_skb_cb*) skb->cb)->magic == LAP_MAGIC) ? \ - ((struct irda_skb_cb *)(skb->cb))->next_xbofs : -1 \ -) - +static inline __u16 irda_get_next_xbofs(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->next_xbofs : -1; +} #endif /* IRDA_DEVICE_H */ diff -urN linux-2.6.4-rc2/include/net/irda/irias_object.h linux-2.6.4-rc3/include/net/irda/irias_object.h --- linux-2.6.4-rc2/include/net/irda/irias_object.h 2004-02-17 19:59:53.000000000 -0800 +++ linux-2.6.4-rc3/include/net/irda/irias_object.h 2004-03-09 16:36:31.000000000 -0800 @@ -101,7 +101,7 @@ struct ias_value *irias_new_missing_value(void); void irias_delete_value(struct ias_value *value); -extern struct ias_value missing; +extern struct ias_value irias_missing; extern hashbin_t *irias_objects; #endif diff -urN linux-2.6.4-rc2/include/net/irda/irlmp.h linux-2.6.4-rc3/include/net/irda/irlmp.h --- linux-2.6.4-rc2/include/net/irda/irlmp.h 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/include/net/irda/irlmp.h 2004-03-09 16:36:31.000000000 -0800 @@ -249,10 +249,17 @@ __u8 irlmp_find_free_slsap(void); LM_REASON irlmp_convert_lap_reason(LAP_REASON); -__u32 irlmp_get_saddr(struct lsap_cb *self); -__u32 irlmp_get_daddr(struct lsap_cb *self); +static inline __u32 irlmp_get_saddr(const struct lsap_cb *self) +{ + return (self && !self->lap) ? self->lap->saddr : 0; +} + +static inline __u32 irlmp_get_daddr(const struct lsap_cb *self) +{ + return (self && self->lap) ? self->lap->daddr : 0; +} -extern char *lmp_reasons[]; +extern const char *irlmp_reasons[]; extern int sysctl_discovery_timeout; extern int sysctl_discovery_slots; extern int sysctl_discovery; diff -urN linux-2.6.4-rc2/include/net/irda/timer.h linux-2.6.4-rc3/include/net/irda/timer.h --- linux-2.6.4-rc2/include/net/irda/timer.h 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/include/net/irda/timer.h 2004-03-09 16:36:31.000000000 -0800 @@ -71,8 +71,18 @@ typedef void (*TIMER_CALLBACK)(void *); -void irda_start_timer(struct timer_list *ptimer, int timeout, void* data, - TIMER_CALLBACK callback); +static inline void irda_start_timer(struct timer_list *ptimer, int timeout, + void* data, TIMER_CALLBACK callback) +{ + ptimer->function = (void (*)(unsigned long)) callback; + ptimer->data = (unsigned long) data; + + /* Set new value for timer (update or add timer). + * We use mod_timer() because it's more efficient and also + * safer with respect to race conditions - Jean II */ + mod_timer(ptimer, jiffies + timeout); +} + void irlap_start_slot_timer(struct irlap_cb *self, int timeout); void irlap_start_query_timer(struct irlap_cb *self, int timeout); diff -urN linux-2.6.4-rc2/init/Kconfig linux-2.6.4-rc3/init/Kconfig --- linux-2.6.4-rc2/init/Kconfig 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/init/Kconfig 2004-03-09 16:36:31.000000000 -0800 @@ -304,4 +304,10 @@ runs modprobe with the appropriate arguments, thereby loading the module if it is available. If unsure, say Y. +config STOP_MACHINE + bool + default y + depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU + help + Need stop_machine() primitive. endmenu diff -urN linux-2.6.4-rc2/init/main.c linux-2.6.4-rc3/init/main.c --- linux-2.6.4-rc2/init/main.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/init/main.c 2004-03-09 16:36:31.000000000 -0800 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -510,8 +511,11 @@ for (call = &__initcall_start; call < &__initcall_end; call++) { char *msg; - if (initcall_debug) - printk("calling initcall 0x%p\n", *call); + if (initcall_debug) { + printk(KERN_DEBUG "Calling initcall 0x%p", *call); + print_symbol(": %s()", (unsigned long) *call); + printk("\n"); + } (*call)(); diff -urN linux-2.6.4-rc2/kernel/Makefile linux-2.6.4-rc3/kernel/Makefile --- linux-2.6.4-rc2/kernel/Makefile 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/Makefile 2004-03-09 16:36:31.000000000 -0800 @@ -20,6 +20,7 @@ obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_IKCONFIG_PROC) += configs.o +obj-$(CONFIG_STOP_MACHINE) += stop_machine.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -urN linux-2.6.4-rc2/kernel/acct.c linux-2.6.4-rc3/kernel/acct.c --- linux-2.6.4-rc2/kernel/acct.c 2004-02-17 19:58:10.000000000 -0800 +++ linux-2.6.4-rc3/kernel/acct.c 2004-03-09 16:36:31.000000000 -0800 @@ -235,8 +235,11 @@ } error = security_acct(file); - if (error) + if (error) { + if (file) + filp_close(file, NULL); return error; + } spin_lock(&acct_globals.lock); acct_file_reopen(file); diff -urN linux-2.6.4-rc2/kernel/compat.c linux-2.6.4-rc3/kernel/compat.c --- linux-2.6.4-rc2/kernel/compat.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/compat.c 2004-03-09 16:36:31.000000000 -0800 @@ -30,7 +30,7 @@ __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } -int put_compat_timespec(struct timespec *ts, const struct compat_timespec *cts) +int put_compat_timespec(const struct timespec *ts, struct compat_timespec *cts) { return (verify_area(VERIFY_WRITE, cts, sizeof(*cts)) || __put_user(ts->tv_sec, &cts->tv_sec) || diff -urN linux-2.6.4-rc2/kernel/exit.c linux-2.6.4-rc3/kernel/exit.c --- linux-2.6.4-rc2/kernel/exit.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/exit.c 2004-03-09 16:36:31.000000000 -0800 @@ -386,7 +386,7 @@ } } -void put_files_struct(struct files_struct *files) +void fastcall put_files_struct(struct files_struct *files) { if (atomic_dec_and_test(&files->count)) { close_files(files); @@ -810,7 +810,7 @@ do_exit((error_code&0xff)<<8); } -task_t *next_thread(task_t *p) +task_t fastcall *next_thread(task_t *p) { struct pid_link *link = p->pids + PIDTYPE_TGID; struct list_head *tmp, *head = &link->pidptr->task_list; diff -urN linux-2.6.4-rc2/kernel/fork.c linux-2.6.4-rc3/kernel/fork.c --- linux-2.6.4-rc2/kernel/fork.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/fork.c 2004-03-09 16:36:31.000000000 -0800 @@ -91,7 +91,7 @@ free_task(tsk); } -void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -103,7 +103,7 @@ EXPORT_SYMBOL(add_wait_queue); -void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait) +void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -115,7 +115,7 @@ EXPORT_SYMBOL(add_wait_queue_exclusive); -void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -139,7 +139,7 @@ * stops them from bleeding out - it would still allow subsequent * loads to move into the the critical region). */ -void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) +void fastcall prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) { unsigned long flags; @@ -153,7 +153,7 @@ EXPORT_SYMBOL(prepare_to_wait); -void +void fastcall prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state) { unsigned long flags; @@ -168,7 +168,7 @@ EXPORT_SYMBOL(prepare_to_wait_exclusive); -void finish_wait(wait_queue_head_t *q, wait_queue_t *wait) +void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait) { unsigned long flags; @@ -265,6 +265,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) { struct vm_area_struct * mpnt, *tmp, **pprev; + struct rb_node **rb_link, *rb_parent; int retval; unsigned long charge = 0; @@ -277,6 +278,9 @@ mm->map_count = 0; mm->rss = 0; cpus_clear(mm->cpu_vm_mask); + mm->mm_rb = RB_ROOT; + rb_link = &mm->mm_rb.rb_node; + rb_parent = NULL; pprev = &mm->mmap; /* @@ -324,11 +328,17 @@ /* * Link in the new vma and copy the page table entries: - * link in first so that swapoff can see swap entries. + * link in first so that swapoff can see swap entries, + * and try_to_unmap_one's find_vma find the new vma. */ spin_lock(&mm->page_table_lock); *pprev = tmp; pprev = &tmp->vm_next; + + __vma_link_rb(mm, tmp, rb_link, rb_parent); + rb_link = &tmp->vm_rb.rb_right; + rb_parent = &tmp->vm_rb; + mm->map_count++; retval = copy_page_range(mm, current->mm, tmp); spin_unlock(&mm->page_table_lock); @@ -340,7 +350,6 @@ goto fail; } retval = 0; - build_mmap_rb(mm); out: flush_tlb_mm(current->mm); @@ -418,7 +427,7 @@ * is dropped: either by a lazy thread or by * mmput. Free the page directory and the mm. */ -void __mmdrop(struct mm_struct *mm) +void fastcall __mmdrop(struct mm_struct *mm) { BUG_ON(mm == &init_mm); mm_free_pgd(mm); diff -urN linux-2.6.4-rc2/kernel/module.c linux-2.6.4-rc3/kernel/module.c --- linux-2.6.4-rc2/kernel/module.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/module.c 2004-03-09 16:36:31.000000000 -0800 @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -474,190 +474,36 @@ } #endif /* CONFIG_MODULE_FORCE_UNLOAD */ -static int try_stop_module_local(struct module *mod, int flags, int *forced) -{ - local_irq_disable(); - - /* If it's not unused, quit unless we are told to block. */ - if ((flags & O_NONBLOCK) && module_refcount(mod) != 0) { - if (!(*forced = try_force(flags))) { - local_irq_enable(); - return -EWOULDBLOCK; - } - } - - /* Mark it as dying. */ - mod->waiter = current; - mod->state = MODULE_STATE_GOING; - local_irq_enable(); - return 0; -} - -#ifdef CONFIG_SMP -/* Thread to stop each CPU in user context. */ -enum stopref_state { - STOPREF_WAIT, - STOPREF_PREPARE, - STOPREF_DISABLE_IRQ, - STOPREF_EXIT, -}; - -static enum stopref_state stopref_state; -static unsigned int stopref_num_threads; -static atomic_t stopref_thread_ack; - -static int stopref(void *cpu) -{ - int irqs_disabled = 0; - int prepared = 0; - - set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu)); - - /* Ack: we are alive */ - mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */ - atomic_inc(&stopref_thread_ack); - - /* Simple state machine */ - while (stopref_state != STOPREF_EXIT) { - if (stopref_state == STOPREF_DISABLE_IRQ && !irqs_disabled) { - local_irq_disable(); - irqs_disabled = 1; - /* Ack: irqs disabled. */ - mb(); /* Must read state first. */ - atomic_inc(&stopref_thread_ack); - } else if (stopref_state == STOPREF_PREPARE && !prepared) { - /* Everyone is in place, hold CPU. */ - preempt_disable(); - prepared = 1; - mb(); /* Must read state first. */ - atomic_inc(&stopref_thread_ack); - } - if (irqs_disabled || prepared) - cpu_relax(); - else - yield(); - } - - /* Ack: we are exiting. */ - mb(); /* Must read state first. */ - atomic_inc(&stopref_thread_ack); - - if (irqs_disabled) - local_irq_enable(); - if (prepared) - preempt_enable(); - - return 0; -} - -/* Change the thread state */ -static void stopref_set_state(enum stopref_state state, int sleep) -{ - atomic_set(&stopref_thread_ack, 0); - wmb(); - stopref_state = state; - while (atomic_read(&stopref_thread_ack) != stopref_num_threads) { - if (sleep) - yield(); - else - cpu_relax(); - } -} - struct stopref { struct module *mod; int flags; int *forced; - struct completion started; }; -static int spawn_stopref(void *data) +/* Whole machine is stopped with interrupts off when this runs. */ +static inline int __try_stop_module(void *_sref) { - struct stopref *sref = data; - struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; - unsigned int i, cpu = smp_processor_id(); - int ret = 0; - - complete(&sref->started); - - /* One high-prio thread per cpu. We'll do one (any one). */ - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - sys_sched_setscheduler(current->pid, SCHED_FIFO, ¶m); - - atomic_set(&stopref_thread_ack, 0); - stopref_num_threads = 0; - stopref_state = STOPREF_WAIT; - - for_each_online_cpu(i) { - if (i == cpu) - continue; - ret = kernel_thread(stopref, (void *)(long)i, CLONE_KERNEL); - if (ret < 0) - break; - stopref_num_threads++; - } - - /* Wait for them all to come to life. */ - while (atomic_read(&stopref_thread_ack) != stopref_num_threads) - yield(); + struct stopref *sref = _sref; - /* If some failed, kill them all. */ - if (ret < 0) { - stopref_set_state(STOPREF_EXIT, 1); - goto out; + /* If it's not unused, quit unless we are told to block. */ + if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) { + if (!(*sref->forced = try_force(sref->flags))) + return -EWOULDBLOCK; } - /* Don't schedule us away at this point, please. */ - preempt_disable(); - - /* Now they are all started, make them hold the CPUs, ready. */ - stopref_set_state(STOPREF_PREPARE, 0); - - /* Make them disable irqs. */ - stopref_set_state(STOPREF_DISABLE_IRQ, 0); - - /* Atomically disable module if possible */ - ret = try_stop_module_local(sref->mod, sref->flags, sref->forced); - - stopref_set_state(STOPREF_EXIT, 0); - preempt_enable(); - -out: - /* Wait for kthread_stop */ - while (!kthread_should_stop()) { - __set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return ret; + /* Mark it as dying. */ + sref->mod->waiter = current; + sref->mod->state = MODULE_STATE_GOING; + return 0; } static int try_stop_module(struct module *mod, int flags, int *forced) { - struct task_struct *p; struct stopref sref = { mod, flags, forced }; - int ret; - - init_completion(&sref.started); - /* No CPUs can come up or down during this. */ - lock_cpu_hotplug(); - p = kthread_run(spawn_stopref, &sref, "krmmod"); - if (IS_ERR(p)) - ret = PTR_ERR(p); - else { - wait_for_completion(&sref.started); - ret = kthread_stop(p); - } - unlock_cpu_hotplug(); - return ret; + return stop_machine_run(__try_stop_module, &sref, NR_CPUS); } -#else /* ...!SMP */ -static inline int try_stop_module(struct module *mod, int flags, int *forced) -{ - return try_stop_module_local(mod, flags, forced); -} -#endif unsigned int module_refcount(struct module *mod) { diff -urN linux-2.6.4-rc2/kernel/pid.c linux-2.6.4-rc3/kernel/pid.c --- linux-2.6.4-rc2/kernel/pid.c 2004-02-17 19:58:14.000000000 -0800 +++ linux-2.6.4-rc3/kernel/pid.c 2004-03-09 16:36:31.000000000 -0800 @@ -57,7 +57,7 @@ static spinlock_t pidmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; -inline void free_pidmap(int pid) +fastcall void free_pidmap(int pid) { pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE; int offset = pid & BITS_PER_PAGE_MASK; @@ -146,7 +146,7 @@ return -1; } -inline struct pid *find_pid(enum pid_type type, int nr) +fastcall struct pid *find_pid(enum pid_type type, int nr) { struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)]; struct pid *pid; @@ -159,14 +159,14 @@ return NULL; } -void link_pid(task_t *task, struct pid_link *link, struct pid *pid) +void fastcall link_pid(task_t *task, struct pid_link *link, struct pid *pid) { atomic_inc(&pid->count); list_add_tail(&link->pid_chain, &pid->task_list); link->pidptr = pid; } -int attach_pid(task_t *task, enum pid_type type, int nr) +int fastcall attach_pid(task_t *task, enum pid_type type, int nr) { struct pid *pid = find_pid(type, nr); @@ -209,7 +209,7 @@ __detach_pid(task, type); } -void detach_pid(task_t *task, enum pid_type type) +void fastcall detach_pid(task_t *task, enum pid_type type) { int nr = __detach_pid(task, type); diff -urN linux-2.6.4-rc2/kernel/printk.c linux-2.6.4-rc3/kernel/printk.c --- linux-2.6.4-rc2/kernel/printk.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/printk.c 2004-03-09 16:36:31.000000000 -0800 @@ -522,7 +522,7 @@ log_level_unknown = 1; } - if (!cpu_online(smp_processor_id())) { + if (!cpu_online(smp_processor_id()) && !system_running) { /* * Some console drivers may assume that per-cpu resources have * been allocated. So don't allow them to be called by this diff -urN linux-2.6.4-rc2/kernel/rcupdate.c linux-2.6.4-rc3/kernel/rcupdate.c --- linux-2.6.4-rc2/kernel/rcupdate.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/kernel/rcupdate.c 2004-03-09 16:36:31.000000000 -0800 @@ -66,7 +66,7 @@ * The read-side of critical section that use call_rcu() for updation must * be protected by rcu_read_lock()/rcu_read_unlock(). */ -void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg) +void fastcall call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg) { int cpu; unsigned long flags; diff -urN linux-2.6.4-rc2/kernel/sched.c linux-2.6.4-rc3/kernel/sched.c --- linux-2.6.4-rc2/kernel/sched.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/sched.c 2004-03-09 16:36:31.000000000 -0800 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -700,7 +701,7 @@ return success; } -int wake_up_process(task_t * p) +int fastcall wake_up_process(task_t * p) { return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0); @@ -708,7 +709,7 @@ EXPORT_SYMBOL(wake_up_process); -int wake_up_state(task_t *p, unsigned int state) +int fastcall wake_up_state(task_t *p, unsigned int state) { return try_to_wake_up(p, state, 0); } @@ -717,7 +718,7 @@ * Perform scheduler related setup for a newly forked process p. * p is forked by current. */ -void sched_fork(task_t *p) +void fastcall sched_fork(task_t *p) { /* * We mark the process as running here, but have not actually @@ -773,7 +774,7 @@ * This function will do some initial scheduler statistics housekeeping * that must be done for every newly created process. */ -void wake_up_forked_process(task_t * p) +void fastcall wake_up_forked_process(task_t * p) { unsigned long flags; runqueue_t *rq = task_rq_lock(current, &flags); @@ -817,7 +818,7 @@ * artificially, because any timeslice recovered here * was given away by the parent in the first place.) */ -void sched_exit(task_t * p) +void fastcall sched_exit(task_t * p) { unsigned long flags; runqueue_t *rq; @@ -1796,7 +1797,7 @@ * @mode: which threads * @nr_exclusive: how many wake-one or wake-many threads to wake up */ -void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) +void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { unsigned long flags; @@ -1810,7 +1811,7 @@ /* * Same as __wake_up but called with the spinlock in wait_queue_head_t held. */ -void __wake_up_locked(wait_queue_head_t *q, unsigned int mode) +void fastcall __wake_up_locked(wait_queue_head_t *q, unsigned int mode) { __wake_up_common(q, mode, 1, 0); } @@ -1828,7 +1829,7 @@ * * On UP it can prevent extra preemption. */ -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) +void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { unsigned long flags; @@ -1845,7 +1846,7 @@ EXPORT_SYMBOL_GPL(__wake_up_sync); /* For internal use only */ -void complete(struct completion *x) +void fastcall complete(struct completion *x) { unsigned long flags; @@ -1858,7 +1859,7 @@ EXPORT_SYMBOL(complete); -void complete_all(struct completion *x) +void fastcall complete_all(struct completion *x) { unsigned long flags; @@ -1869,7 +1870,7 @@ spin_unlock_irqrestore(&x->wait.lock, flags); } -void wait_for_completion(struct completion *x) +void fastcall wait_for_completion(struct completion *x) { might_sleep(); spin_lock_irq(&x->wait.lock); @@ -1907,7 +1908,7 @@ __remove_wait_queue(q, &wait); \ spin_unlock_irqrestore(&q->lock, flags); -void interruptible_sleep_on(wait_queue_head_t *q) +void fastcall interruptible_sleep_on(wait_queue_head_t *q) { SLEEP_ON_VAR @@ -1920,7 +1921,7 @@ EXPORT_SYMBOL(interruptible_sleep_on); -long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) +long fastcall interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) { SLEEP_ON_VAR @@ -1935,7 +1936,7 @@ EXPORT_SYMBOL(interruptible_sleep_on_timeout); -void sleep_on(wait_queue_head_t *q) +void fastcall sleep_on(wait_queue_head_t *q) { SLEEP_ON_VAR @@ -1948,7 +1949,7 @@ EXPORT_SYMBOL(sleep_on); -long sleep_on_timeout(wait_queue_head_t *q, long timeout) +long fastcall sleep_on_timeout(wait_queue_head_t *q, long timeout) { SLEEP_ON_VAR @@ -2365,7 +2366,7 @@ goto out_unlock; retval = 0; - cpus_and(mask, p->cpus_allowed, cpu_online_map); + cpus_and(mask, p->cpus_allowed, cpu_possible_map); out_unlock: read_unlock(&tasklist_lock); diff -urN linux-2.6.4-rc2/kernel/signal.c linux-2.6.4-rc3/kernel/signal.c --- linux-2.6.4-rc2/kernel/signal.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/signal.c 2004-03-09 16:36:31.000000000 -0800 @@ -213,7 +213,7 @@ #define PENDING(p,b) has_pending_signals(&(p)->signal, (b)) -inline void recalc_sigpending_tsk(struct task_struct *t) +fastcall void recalc_sigpending_tsk(struct task_struct *t) { if (t->signal->group_stop_count > 0 || PENDING(&t->pending, &t->blocked) || diff -urN linux-2.6.4-rc2/kernel/softirq.c linux-2.6.4-rc3/kernel/softirq.c --- linux-2.6.4-rc2/kernel/softirq.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/softirq.c 2004-03-09 16:36:31.000000000 -0800 @@ -130,7 +130,7 @@ /* * This function must run with irqs disabled! */ -inline void raise_softirq_irqoff(unsigned int nr) +inline fastcall void raise_softirq_irqoff(unsigned int nr) { __raise_softirq_irqoff(nr); @@ -149,7 +149,7 @@ EXPORT_SYMBOL(raise_softirq_irqoff); -void raise_softirq(unsigned int nr) +void fastcall raise_softirq(unsigned int nr) { unsigned long flags; @@ -179,7 +179,7 @@ static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL }; static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL }; -void __tasklet_schedule(struct tasklet_struct *t) +void fastcall __tasklet_schedule(struct tasklet_struct *t) { unsigned long flags; @@ -192,7 +192,7 @@ EXPORT_SYMBOL(__tasklet_schedule); -void __tasklet_hi_schedule(struct tasklet_struct *t) +void fastcall __tasklet_hi_schedule(struct tasklet_struct *t) { unsigned long flags; diff -urN linux-2.6.4-rc2/kernel/stop_machine.c linux-2.6.4-rc3/kernel/stop_machine.c --- linux-2.6.4-rc2/kernel/stop_machine.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.4-rc3/kernel/stop_machine.c 2004-03-09 16:36:31.000000000 -0800 @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include +#include +#include + +/* Since we effect priority and affinity (both of which are visible + * to, and settable by outside processes) we do indirection via a + * kthread. */ + +/* Thread to stop each CPU in user context. */ +enum stopmachine_state { + STOPMACHINE_WAIT, + STOPMACHINE_PREPARE, + STOPMACHINE_DISABLE_IRQ, + STOPMACHINE_EXIT, +}; + +static enum stopmachine_state stopmachine_state; +static unsigned int stopmachine_num_threads; +static atomic_t stopmachine_thread_ack; +static DECLARE_MUTEX(stopmachine_mutex); + +static int stopmachine(void *cpu) +{ + int irqs_disabled = 0; + int prepared = 0; + + set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu)); + + /* Ack: we are alive */ + mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */ + atomic_inc(&stopmachine_thread_ack); + + /* Simple state machine */ + while (stopmachine_state != STOPMACHINE_EXIT) { + if (stopmachine_state == STOPMACHINE_DISABLE_IRQ + && !irqs_disabled) { + local_irq_disable(); + irqs_disabled = 1; + /* Ack: irqs disabled. */ + mb(); /* Must read state first. */ + atomic_inc(&stopmachine_thread_ack); + } else if (stopmachine_state == STOPMACHINE_PREPARE + && !prepared) { + /* Everyone is in place, hold CPU. */ + preempt_disable(); + prepared = 1; + mb(); /* Must read state first. */ + atomic_inc(&stopmachine_thread_ack); + } + cpu_relax(); + } + + /* Ack: we are exiting. */ + mb(); /* Must read state first. */ + atomic_inc(&stopmachine_thread_ack); + + if (irqs_disabled) + local_irq_enable(); + if (prepared) + preempt_enable(); + + return 0; +} + +/* Change the thread state */ +static void stopmachine_set_state(enum stopmachine_state state) +{ + atomic_set(&stopmachine_thread_ack, 0); + wmb(); + stopmachine_state = state; + while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads) + cpu_relax(); +} + +static int stop_machine(void) +{ + int i, ret = 0; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + + /* One high-prio thread per cpu. We'll do this one. */ + sys_sched_setscheduler(current->pid, SCHED_FIFO, ¶m); + + atomic_set(&stopmachine_thread_ack, 0); + stopmachine_num_threads = 0; + stopmachine_state = STOPMACHINE_WAIT; + + for_each_online_cpu(i) { + if (i == smp_processor_id()) + continue; + ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL); + if (ret < 0) + break; + stopmachine_num_threads++; + } + + /* Wait for them all to come to life. */ + while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads) + yield(); + + /* If some failed, kill them all. */ + if (ret < 0) { + stopmachine_set_state(STOPMACHINE_EXIT); + up(&stopmachine_mutex); + return ret; + } + + /* Don't schedule us away at this point, please. */ + local_irq_disable(); + + /* Now they are all started, make them hold the CPUs, ready. */ + stopmachine_set_state(STOPMACHINE_PREPARE); + + /* Make them disable irqs. */ + stopmachine_set_state(STOPMACHINE_DISABLE_IRQ); + + return 0; +} + +static void restart_machine(void) +{ + stopmachine_set_state(STOPMACHINE_EXIT); + local_irq_enable(); +} + +struct stop_machine_data +{ + int (*fn)(void *); + void *data; + struct completion done; +}; + +static int do_stop(void *_smdata) +{ + struct stop_machine_data *smdata = _smdata; + int ret; + + ret = stop_machine(); + if (ret == 0) { + ret = smdata->fn(smdata->data); + restart_machine(); + } + + /* We're done: you can kthread_stop us now */ + complete(&smdata->done); + + /* Wait for kthread_stop */ + while (!kthread_should_stop()) { + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return ret; +} + +struct task_struct *__stop_machine_run(int (*fn)(void *), void *data, + unsigned int cpu) +{ + struct stop_machine_data smdata; + struct task_struct *p; + + smdata.fn = fn; + smdata.data = data; + init_completion(&smdata.done); + + down(&stopmachine_mutex); + + /* If they don't care which CPU fn runs on, bind to any online one. */ + if (cpu == NR_CPUS) + cpu = smp_processor_id(); + + p = kthread_create(do_stop, &smdata, "kstopmachine"); + if (!IS_ERR(p)) { + kthread_bind(p, cpu); + wake_up_process(p); + wait_for_completion(&smdata.done); + } + up(&stopmachine_mutex); + return p; +} + +int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) +{ + struct task_struct *p; + int ret; + + /* No CPUs can come up or down during this. */ + lock_cpu_hotplug(); + p = __stop_machine_run(fn, data, cpu); + if (!IS_ERR(p)) + ret = kthread_stop(p); + else + ret = PTR_ERR(p); + unlock_cpu_hotplug(); + + return ret; +} diff -urN linux-2.6.4-rc2/kernel/timer.c linux-2.6.4-rc3/kernel/timer.c --- linux-2.6.4-rc2/kernel/timer.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/timer.c 2004-03-09 16:36:31.000000000 -0800 @@ -997,7 +997,7 @@ * * In all cases the return value is guaranteed to be non-negative. */ -signed long schedule_timeout(signed long timeout) +fastcall signed long schedule_timeout(signed long timeout) { struct timer_list timer; unsigned long expire; diff -urN linux-2.6.4-rc2/kernel/workqueue.c linux-2.6.4-rc3/kernel/workqueue.c --- linux-2.6.4-rc2/kernel/workqueue.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/kernel/workqueue.c 2004-03-09 16:36:31.000000000 -0800 @@ -78,7 +78,7 @@ * We queue the work to the CPU it was submitted, but there is no * guarantee that it will be processed by that CPU. */ -int queue_work(struct workqueue_struct *wq, struct work_struct *work) +int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work) { int ret = 0, cpu = get_cpu(); @@ -99,7 +99,7 @@ __queue_work(wq->cpu_wq + smp_processor_id(), work); } -int queue_delayed_work(struct workqueue_struct *wq, +int fastcall queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay) { int ret = 0; @@ -203,7 +203,7 @@ * This function used to run the workqueues itself. Now we just wait for the * helper threads to do it. */ -void flush_workqueue(struct workqueue_struct *wq) +void fastcall flush_workqueue(struct workqueue_struct *wq) { struct cpu_workqueue_struct *cwq; int cpu; @@ -310,12 +310,12 @@ static struct workqueue_struct *keventd_wq; -int schedule_work(struct work_struct *work) +int fastcall schedule_work(struct work_struct *work) { return queue_work(keventd_wq, work); } -int schedule_delayed_work(struct work_struct *work, unsigned long delay) +int fastcall schedule_delayed_work(struct work_struct *work, unsigned long delay) { return queue_delayed_work(keventd_wq, work, delay); } diff -urN linux-2.6.4-rc2/lib/rwsem-spinlock.c linux-2.6.4-rc3/lib/rwsem-spinlock.c --- linux-2.6.4-rc2/lib/rwsem-spinlock.c 2004-02-17 19:57:16.000000000 -0800 +++ linux-2.6.4-rc3/lib/rwsem-spinlock.c 2004-03-09 16:36:31.000000000 -0800 @@ -29,7 +29,7 @@ /* * initialise the semaphore */ -void init_rwsem(struct rw_semaphore *sem) +void fastcall init_rwsem(struct rw_semaphore *sem) { sem->activity = 0; spin_lock_init(&sem->wait_lock); @@ -117,7 +117,7 @@ /* * get a read lock on the semaphore */ -void __down_read(struct rw_semaphore *sem) +void fastcall __down_read(struct rw_semaphore *sem) { struct rwsem_waiter waiter; struct task_struct *tsk; @@ -162,7 +162,7 @@ /* * trylock for reading -- returns 1 if successful, 0 if contention */ -int __down_read_trylock(struct rw_semaphore *sem) +int fastcall __down_read_trylock(struct rw_semaphore *sem) { int ret = 0; rwsemtrace(sem,"Entering __down_read_trylock"); @@ -185,7 +185,7 @@ * get a write lock on the semaphore * - note that we increment the waiting count anyway to indicate an exclusive lock */ -void __down_write(struct rw_semaphore *sem) +void fastcall __down_write(struct rw_semaphore *sem) { struct rwsem_waiter waiter; struct task_struct *tsk; @@ -230,7 +230,7 @@ /* * trylock for writing -- returns 1 if successful, 0 if contention */ -int __down_write_trylock(struct rw_semaphore *sem) +int fastcall __down_write_trylock(struct rw_semaphore *sem) { int ret = 0; rwsemtrace(sem,"Entering __down_write_trylock"); @@ -252,7 +252,7 @@ /* * release a read lock on the semaphore */ -void __up_read(struct rw_semaphore *sem) +void fastcall __up_read(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering __up_read"); @@ -269,7 +269,7 @@ /* * release a write lock on the semaphore */ -void __up_write(struct rw_semaphore *sem) +void fastcall __up_write(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering __up_write"); @@ -288,7 +288,7 @@ * downgrade a write lock into a read lock * - just wake up any readers at the front of the queue */ -void __downgrade_write(struct rw_semaphore *sem) +void fastcall __downgrade_write(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering __downgrade_write"); diff -urN linux-2.6.4-rc2/lib/rwsem.c linux-2.6.4-rc3/lib/rwsem.c --- linux-2.6.4-rc2/lib/rwsem.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/lib/rwsem.c 2004-03-09 16:36:31.000000000 -0800 @@ -162,7 +162,7 @@ /* * wait for the read lock to be granted */ -struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_down_read_failed(struct rw_semaphore *sem) { struct rwsem_waiter waiter; @@ -178,7 +178,7 @@ /* * wait for the write lock to be granted */ -struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_down_write_failed(struct rw_semaphore *sem) { struct rwsem_waiter waiter; @@ -195,7 +195,7 @@ * handle waking up a waiter on the semaphore * - up_read has decremented the active part of the count if we come here */ -struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_wake(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering rwsem_wake"); @@ -217,7 +217,7 @@ * - caller incremented waiting part of count, and discovered it to be still negative * - just wake up any readers at the front of the queue */ -struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem) +struct rw_semaphore fastcall *rwsem_downgrade_wake(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering rwsem_downgrade_wake"); diff -urN linux-2.6.4-rc2/mm/filemap.c linux-2.6.4-rc3/mm/filemap.c --- linux-2.6.4-rc2/mm/filemap.c 2004-02-17 19:57:22.000000000 -0800 +++ linux-2.6.4-rc3/mm/filemap.c 2004-03-09 16:36:31.000000000 -0800 @@ -161,13 +161,15 @@ /* * This is a mostly non-blocking flush. Not suitable for data-integrity - * purposes. + * purposes - I/O may not be started against all dirty pages. */ int filemap_flush(struct address_space *mapping) { return __filemap_fdatawrite(mapping, WB_SYNC_NONE); } +EXPORT_SYMBOL(filemap_flush); + /** * filemap_fdatawait - walk the list of locked pages of the given address * space and wait for all of them. @@ -292,7 +294,7 @@ return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)]; } -void wait_on_page_bit(struct page *page, int bit_nr) +void fastcall wait_on_page_bit(struct page *page, int bit_nr) { wait_queue_head_t *waitqueue = page_waitqueue(page); DEFINE_WAIT(wait); @@ -324,7 +326,7 @@ * the clear_bit and the read of the waitqueue (to avoid SMP races with a * parallel wait_on_page_locked()). */ -void unlock_page(struct page *page) +void fastcall unlock_page(struct page *page) { wait_queue_head_t *waitqueue = page_waitqueue(page); smp_mb__before_clear_bit(); @@ -365,7 +367,7 @@ * chances are that on the second loop, the block layer's plug list is empty, * so sync_page() will then return in state TASK_UNINTERRUPTIBLE. */ -void __lock_page(struct page *page) +void fastcall __lock_page(struct page *page) { wait_queue_head_t *wqh = page_waitqueue(page); DEFINE_WAIT(wait); @@ -953,7 +955,7 @@ * and schedules an I/O to read in its contents from disk. */ static int FASTCALL(page_cache_read(struct file * file, unsigned long offset)); -static int page_cache_read(struct file * file, unsigned long offset) +static int fastcall page_cache_read(struct file * file, unsigned long offset) { struct address_space *mapping = file->f_mapping; struct page *page; diff -urN linux-2.6.4-rc2/mm/highmem.c linux-2.6.4-rc3/mm/highmem.c --- linux-2.6.4-rc2/mm/highmem.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/mm/highmem.c 2004-03-09 16:36:31.000000000 -0800 @@ -147,7 +147,7 @@ return vaddr; } -void *kmap_high(struct page *page) +void fastcall *kmap_high(struct page *page) { unsigned long vaddr; @@ -170,7 +170,7 @@ EXPORT_SYMBOL(kmap_high); -void kunmap_high(struct page *page) +void fastcall kunmap_high(struct page *page) { unsigned long vaddr; unsigned long nr; diff -urN linux-2.6.4-rc2/mm/memory.c linux-2.6.4-rc3/mm/memory.c --- linux-2.6.4-rc2/mm/memory.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/mm/memory.c 2004-03-09 16:36:31.000000000 -0800 @@ -145,7 +145,7 @@ } while (--nr); } -pte_t * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +pte_t fastcall * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address) { if (!pmd_present(*pmd)) { struct page *new; @@ -171,7 +171,7 @@ return pte_offset_map(pmd, address); } -pte_t * pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +pte_t fastcall * pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address) { if (!pmd_present(*pmd)) { pte_t *new; @@ -1646,7 +1646,7 @@ * On a two-level page table, this ends up actually being entirely * optimized away. */ -pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) +pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) { pmd_t *new; diff -urN linux-2.6.4-rc2/mm/mmap.c linux-2.6.4-rc3/mm/mmap.c --- linux-2.6.4-rc2/mm/mmap.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/mm/mmap.c 2004-03-09 16:36:31.000000000 -0800 @@ -222,8 +222,8 @@ } } -static void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, - struct rb_node **rb_link, struct rb_node *rb_parent) +void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, + struct rb_node **rb_link, struct rb_node *rb_parent) { rb_link_node(&vma->vm_rb, rb_parent, rb_link); rb_insert_color(&vma->vm_rb, &mm->mm_rb); @@ -1404,22 +1404,6 @@ EXPORT_SYMBOL(do_brk); -/* Build the RB tree corresponding to the VMA list. */ -void build_mmap_rb(struct mm_struct * mm) -{ - struct vm_area_struct * vma; - struct rb_node ** rb_link, * rb_parent; - - mm->mm_rb = RB_ROOT; - rb_link = &mm->mm_rb.rb_node; - rb_parent = NULL; - for (vma = mm->mmap; vma; vma = vma->vm_next) { - __vma_link_rb(mm, vma, rb_link, rb_parent); - rb_parent = &vma->vm_rb; - rb_link = &rb_parent->rb_right; - } -} - /* Release all mmaps. */ void exit_mmap(struct mm_struct *mm) { diff -urN linux-2.6.4-rc2/mm/page_alloc.c linux-2.6.4-rc3/mm/page_alloc.c --- linux-2.6.4-rc2/mm/page_alloc.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/mm/page_alloc.c 2004-03-09 16:36:31.000000000 -0800 @@ -390,6 +390,27 @@ return allocated; } +#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU) +static void __drain_pages(unsigned int cpu) +{ + struct zone *zone; + int i; + + for_each_zone(zone) { + struct per_cpu_pageset *pset; + + pset = &zone->pageset[cpu]; + for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { + struct per_cpu_pages *pcp; + + pcp = &pset->pcp[i]; + pcp->count -= free_pages_bulk(zone, pcp->count, + &pcp->list, 0); + } + } +} +#endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */ + #ifdef CONFIG_PM int is_head_of_free_region(struct page *page) { @@ -419,22 +440,9 @@ void drain_local_pages(void) { unsigned long flags; - struct zone *zone; - int i; local_irq_save(flags); - for_each_zone(zone) { - struct per_cpu_pageset *pset; - - pset = &zone->pageset[smp_processor_id()]; - for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { - struct per_cpu_pages *pcp; - - pcp = &pset->pcp[i]; - pcp->count -= free_pages_bulk(zone, pcp->count, - &pcp->list, 0); - } - } + __drain_pages(smp_processor_id()); local_irq_restore(flags); } #endif /* CONFIG_PM */ @@ -443,7 +451,7 @@ * Free a 0-order page */ static void FASTCALL(free_hot_cold_page(struct page *page, int cold)); -static void free_hot_cold_page(struct page *page, int cold) +static void fastcall free_hot_cold_page(struct page *page, int cold) { struct zone *zone = page_zone(page); struct per_cpu_pages *pcp; @@ -462,12 +470,12 @@ put_cpu(); } -void free_hot_page(struct page *page) +void fastcall free_hot_page(struct page *page) { free_hot_cold_page(page, 0); } -void free_cold_page(struct page *page) +void fastcall free_cold_page(struct page *page) { free_hot_cold_page(page, 1); } @@ -532,7 +540,7 @@ * sized machine, GFP_HIGHMEM and GFP_KERNEL requests basically leave the DMA * zone untouched. */ -struct page * +struct page * fastcall __alloc_pages(unsigned int gfp_mask, unsigned int order, struct zonelist *zonelist) { @@ -685,7 +693,7 @@ /* * Common helper functions. */ -unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order) +fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order) { struct page * page; @@ -697,7 +705,7 @@ EXPORT_SYMBOL(__get_free_pages); -unsigned long get_zeroed_page(unsigned int gfp_mask) +fastcall unsigned long get_zeroed_page(unsigned int gfp_mask) { struct page * page; @@ -726,7 +734,7 @@ free_hot_cold_page(pvec->pages[i], pvec->cold); } -void __free_pages(struct page *page, unsigned int order) +fastcall void __free_pages(struct page *page, unsigned int order) { if (!PageReserved(page) && put_page_testzero(page)) { if (order == 0) @@ -738,7 +746,7 @@ EXPORT_SYMBOL(__free_pages); -void free_pages(unsigned long addr, unsigned int order) +fastcall void free_pages(unsigned long addr, unsigned int order) { if (addr != 0) { BUG_ON(!virt_addr_valid(addr)); diff -urN linux-2.6.4-rc2/mm/rmap.c linux-2.6.4-rc3/mm/rmap.c --- linux-2.6.4-rc2/mm/rmap.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/mm/rmap.c 2004-03-09 16:36:31.000000000 -0800 @@ -112,7 +112,7 @@ * If the page has a single-entry pte_chain, collapse that back to a PageDirect * representation. This way, it's only done under memory pressure. */ -int page_referenced(struct page * page) +int fastcall page_referenced(struct page * page) { struct pte_chain *pc; int referenced = 0; @@ -165,7 +165,7 @@ * Add a new pte reverse mapping to a page. * The caller needs to hold the mm->page_table_lock. */ -struct pte_chain * +struct pte_chain * fastcall page_add_rmap(struct page *page, pte_t *ptep, struct pte_chain *pte_chain) { pte_addr_t pte_paddr = ptep_to_paddr(ptep); @@ -221,7 +221,7 @@ * the page. * Caller needs to hold the mm->page_table_lock. */ -void page_remove_rmap(struct page *page, pte_t *ptep) +void fastcall page_remove_rmap(struct page *page, pte_t *ptep) { pte_addr_t pte_paddr = ptep_to_paddr(ptep); struct pte_chain *pc; @@ -293,7 +293,7 @@ * mm->page_table_lock try_to_unmap_one(), trylock */ static int FASTCALL(try_to_unmap_one(struct page *, pte_addr_t)); -static int try_to_unmap_one(struct page * page, pte_addr_t paddr) +static int fastcall try_to_unmap_one(struct page * page, pte_addr_t paddr) { pte_t *ptep = rmap_ptep_map(paddr); unsigned long address = ptep_to_address(ptep); @@ -382,7 +382,7 @@ * SWAP_AGAIN - we missed a trylock, try again later * SWAP_FAIL - the page is unswappable */ -int try_to_unmap(struct page * page) +int fastcall try_to_unmap(struct page * page) { struct pte_chain *pc, *next_pc, *start; int ret = SWAP_SUCCESS; diff -urN linux-2.6.4-rc2/mm/slab.c linux-2.6.4-rc3/mm/slab.c --- linux-2.6.4-rc2/mm/slab.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/mm/slab.c 2004-03-09 16:36:31.000000000 -0800 @@ -521,9 +521,19 @@ static DEFINE_PER_CPU(struct timer_list, reap_timers); static void reap_timer_fnc(unsigned long data); - +static void free_block(kmem_cache_t* cachep, void** objpp, int len); static void enable_cpucache (kmem_cache_t *cachep); +static inline void ** ac_entry(struct array_cache *ac) +{ + return (void**)(ac+1); +} + +static inline struct array_cache *ac_data(kmem_cache_t *cachep) +{ + return cachep->array[smp_processor_id()]; +} + /* Cal the num objs, wastage, and bytes left over for a given slab size. */ static void cache_estimate (unsigned long gfporder, size_t size, int flags, size_t *left_over, unsigned int *num) @@ -573,6 +583,7 @@ if (rt->function == NULL) { init_timer(rt); rt->expires = jiffies + HZ + 3*cpu; + rt->data = cpu; rt->function = reap_timer_fnc; add_timer_on(rt, cpu); } @@ -589,16 +600,15 @@ void *hcpu) { long cpu = (long)hcpu; - struct list_head *p; + kmem_cache_t* cachep; switch (action) { case CPU_UP_PREPARE: down(&cache_chain_sem); - list_for_each(p, &cache_chain) { + list_for_each_entry(cachep, &cache_chain, next) { int memsize; struct array_cache *nc; - kmem_cache_t* cachep = list_entry(p, kmem_cache_t, next); memsize = sizeof(void*)*cachep->limit+sizeof(struct array_cache); nc = kmalloc(memsize, GFP_KERNEL); if (!nc) @@ -618,15 +628,13 @@ up(&cache_chain_sem); break; case CPU_ONLINE: - if (g_cpucache_up == FULL) - start_cpu_timer(cpu); + start_cpu_timer(cpu); break; case CPU_UP_CANCELED: down(&cache_chain_sem); - list_for_each(p, &cache_chain) { + list_for_each_entry(cachep, &cache_chain, next) { struct array_cache *nc; - kmem_cache_t* cachep = list_entry(p, kmem_cache_t, next); nc = cachep->array[cpu]; cachep->array[cpu] = NULL; @@ -643,16 +651,6 @@ static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 }; -static inline void ** ac_entry(struct array_cache *ac) -{ - return (void**)(ac+1); -} - -static inline struct array_cache *ac_data(kmem_cache_t *cachep) -{ - return cachep->array[smp_processor_id()]; -} - /* Initialisation. * Called after the gfp() functions have been enabled, and before smp_init(). */ @@ -1368,7 +1366,6 @@ preempt_enable(); } -static void free_block (kmem_cache_t* cachep, void** objpp, int len); static void drain_array_locked(kmem_cache_t* cachep, struct array_cache *ac, int force); @@ -2134,7 +2131,7 @@ * * Currently only used for dentry validation. */ -int kmem_ptr_validate(kmem_cache_t *cachep, void *ptr) +int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr) { unsigned long addr = (unsigned long) ptr; unsigned long min_addr = PAGE_OFFSET; @@ -2601,17 +2598,19 @@ } /* - * This is a timer handler. There is on per CPU. It is called periodially + * This is a timer handler. There is one per CPU. It is called periodially * to shrink this CPU's caches. Otherwise there could be memory tied up * for long periods (or for ever) due to load changes. */ -static void reap_timer_fnc(unsigned long data) +static void reap_timer_fnc(unsigned long cpu) { - int cpu = smp_processor_id(); struct timer_list *rt = &__get_cpu_var(reap_timers); - cache_reap(); - mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu); + /* CPU hotplug can drag us off cpu: don't run on wrong CPU */ + if (!cpu_is_offline(cpu)) { + cache_reap(); + mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu); + } } #ifdef CONFIG_PROC_FS diff -urN linux-2.6.4-rc2/mm/swap.c linux-2.6.4-rc3/mm/swap.c --- linux-2.6.4-rc2/mm/swap.c 2004-02-17 19:57:30.000000000 -0800 +++ linux-2.6.4-rc3/mm/swap.c 2004-03-09 16:36:31.000000000 -0800 @@ -76,7 +76,7 @@ /* * FIXME: speed this up? */ -void activate_page(struct page *page) +void fastcall activate_page(struct page *page) { struct zone *zone = page_zone(page); @@ -97,7 +97,7 @@ * inactive,referenced -> active,unreferenced * active,unreferenced -> active,referenced */ -void mark_page_accessed(struct page *page) +void fastcall mark_page_accessed(struct page *page) { if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) { activate_page(page); @@ -116,7 +116,7 @@ static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, }; static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, }; -void lru_cache_add(struct page *page) +void fastcall lru_cache_add(struct page *page) { struct pagevec *pvec = &get_cpu_var(lru_add_pvecs); @@ -126,7 +126,7 @@ put_cpu_var(lru_add_pvecs); } -void lru_cache_add_active(struct page *page) +void fastcall lru_cache_add_active(struct page *page) { struct pagevec *pvec = &get_cpu_var(lru_add_active_pvecs); @@ -152,7 +152,7 @@ * This path almost never happens for VM activity - pages are normally * freed via pagevecs. But it gets used by networking. */ -void __page_cache_release(struct page *page) +void fastcall __page_cache_release(struct page *page) { unsigned long flags; struct zone *zone = page_zone(page); diff -urN linux-2.6.4-rc2/net/bluetooth/hci_conn.c linux-2.6.4-rc3/net/bluetooth/hci_conn.c --- linux-2.6.4-rc2/net/bluetooth/hci_conn.c 2004-02-17 19:59:50.000000000 -0800 +++ linux-2.6.4-rc3/net/bluetooth/hci_conn.c 2004-03-09 16:36:31.000000000 -0800 @@ -170,6 +170,9 @@ hci_conn_hash_add(hdev, conn); tasklet_enable(&hdev->tx_task); + if (hdev->notify) + hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); + return conn; } @@ -196,6 +199,9 @@ hdev->acl_cnt += conn->sent; } + if (hdev->notify) + hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); + tasklet_disable(&hdev->tx_task); hci_conn_hash_del(hdev, conn); tasklet_enable(&hdev->tx_task); diff -urN linux-2.6.4-rc2/net/bluetooth/hci_core.c linux-2.6.4-rc3/net/bluetooth/hci_core.c --- linux-2.6.4-rc2/net/bluetooth/hci_core.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/bluetooth/hci_core.c 2004-03-09 16:36:31.000000000 -0800 @@ -189,6 +189,10 @@ /* Mandatory initialization */ + /* Reset */ + if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks)) + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL); + /* Read Local Supported Features */ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL); diff -urN linux-2.6.4-rc2/net/bluetooth/hci_event.c linux-2.6.4-rc3/net/bluetooth/hci_event.c --- linux-2.6.4-rc2/net/bluetooth/hci_event.c 2004-02-17 19:57:12.000000000 -0800 +++ linux-2.6.4-rc3/net/bluetooth/hci_event.c 2004-03-09 16:36:31.000000000 -0800 @@ -232,6 +232,9 @@ hdev->voice_setting = setting; BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); + + if (hdev->notify) + hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); } break; @@ -247,6 +250,9 @@ hdev->voice_setting = setting; BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); + + if (hdev->notify) + hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); } hci_req_complete(hdev, status); break; diff -urN linux-2.6.4-rc2/net/bluetooth/rfcomm/core.c linux-2.6.4-rc3/net/bluetooth/rfcomm/core.c --- linux-2.6.4-rc2/net/bluetooth/rfcomm/core.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/bluetooth/rfcomm/core.c 2004-03-09 16:36:31.000000000 -0800 @@ -50,7 +50,7 @@ #include #include -#define VERSION "1.1" +#define VERSION "1.2" #ifndef CONFIG_BT_RFCOMM_DEBUG #undef BT_DBG @@ -409,7 +409,7 @@ return len; } -void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) +void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); @@ -420,7 +420,7 @@ rfcomm_schedule(RFCOMM_SCHED_TX); } -void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); diff -urN linux-2.6.4-rc2/net/bluetooth/rfcomm/tty.c linux-2.6.4-rc3/net/bluetooth/rfcomm/tty.c --- linux-2.6.4-rc2/net/bluetooth/rfcomm/tty.c 2004-02-17 19:58:06.000000000 -0800 +++ linux-2.6.4-rc3/net/bluetooth/rfcomm/tty.c 2004-03-09 16:36:31.000000000 -0800 @@ -50,6 +50,8 @@ #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ #define RFCOMM_TTY_MINOR 0 +static struct tty_driver *rfcomm_tty_driver; + struct rfcomm_dev { struct list_head list; atomic_t refcnt; @@ -98,6 +100,8 @@ rfcomm_dlc_put(dlc); + tty_unregister_device(rfcomm_tty_driver, dev->id); + /* Refcount should only hit zero when called from rfcomm_dev_del() which will have taken us off the list. Everything else are refcounting bugs. */ @@ -239,8 +243,11 @@ if (err) { kfree(dev); return err; - } else - return dev->id; + } + + tty_register_device(rfcomm_tty_driver, dev->id, NULL); + + return dev->id; } static void rfcomm_dev_del(struct rfcomm_dev *dev) @@ -871,8 +878,6 @@ /* ---- TTY structure ---- */ -static struct tty_driver *rfcomm_tty_driver; - static struct tty_operations rfcomm_ops = { .open = rfcomm_tty_open, .close = rfcomm_tty_close, @@ -906,7 +911,7 @@ rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR; rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; - rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW; + rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; rfcomm_tty_driver->init_termios = tty_std_termios; rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); diff -urN linux-2.6.4-rc2/net/core/netfilter.c linux-2.6.4-rc3/net/core/netfilter.c --- linux-2.6.4-rc2/net/core/netfilter.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/core/netfilter.c 2004-03-09 16:36:31.000000000 -0800 @@ -636,6 +636,7 @@ #ifdef CONFIG_IP_ROUTE_FWMARK fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; #endif + fl.proto = iph->protocol; if (ip_route_output_key(&rt, &fl) != 0) return -1; diff -urN linux-2.6.4-rc2/net/ipv4/igmp.c linux-2.6.4-rc3/net/ipv4/igmp.c --- linux-2.6.4-rc2/net/ipv4/igmp.c 2004-02-17 19:59:48.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv4/igmp.c 2004-03-09 16:36:31.000000000 -0800 @@ -105,7 +105,8 @@ #include #endif -#define IP_MAX_MEMBERSHIPS 20 +#define IP_MAX_MEMBERSHIPS 20 +#define IP_MAX_MSF 10 #ifdef CONFIG_IP_MULTICAST /* Parameter names and values are taken from igmp-v2-06 draft */ @@ -1325,6 +1326,7 @@ * Join a socket to a group */ int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS; +int sysctl_igmp_max_msf = IP_MAX_MSF; static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, @@ -1790,6 +1792,10 @@ } /* else, add a new source to the filter */ + if (psl && psl->sl_count >= sysctl_igmp_max_msf) { + err = -ENOBUFS; + goto done; + } if (!psl || psl->sl_count == psl->sl_max) { struct ip_sf_socklist *newpsl; int count = IP_SFBLOCK; diff -urN linux-2.6.4-rc2/net/ipv4/ip_sockglue.c linux-2.6.4-rc3/net/ipv4/ip_sockglue.c --- linux-2.6.4-rc2/net/ipv4/ip_sockglue.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv4/ip_sockglue.c 2004-03-09 16:36:31.000000000 -0800 @@ -618,6 +618,7 @@ case IP_MSFILTER: { extern int sysctl_optmem_max; + extern int sysctl_igmp_max_msf; struct ip_msfilter *msf; if (optlen < IP_MSFILTER_SIZE(0)) @@ -636,9 +637,14 @@ kfree(msf); break; } - if (IP_MSFILTER_SIZE(msf->imsf_numsrc) < - IP_MSFILTER_SIZE(0) || - IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) { + /* numsrc >= (1G-4) overflow in 32 bits */ + if (msf->imsf_numsrc >= 0x3ffffffcU || + msf->imsf_numsrc > sysctl_igmp_max_msf) { + kfree(msf); + err = -ENOBUFS; + break; + } + if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) { kfree(msf); err = -EINVAL; break; @@ -765,6 +771,8 @@ } case MCAST_MSFILTER: { + extern int sysctl_optmem_max; + extern int sysctl_igmp_max_msf; struct sockaddr_in *psin; struct ip_msfilter *msf = 0; struct group_filter *gsf = 0; @@ -772,6 +780,10 @@ if (optlen < GROUP_FILTER_SIZE(0)) goto e_inval; + if (optlen > sysctl_optmem_max) { + err = -ENOBUFS; + break; + } gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL); if (gsf == 0) { err = -ENOBUFS; @@ -781,7 +793,13 @@ if (copy_from_user(gsf, optval, optlen)) { goto mc_msf_out; } - if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) { + /* numsrc >= (4G-140)/128 overflow in 32 bits */ + if (gsf->gf_numsrc >= 0x1ffffff || + gsf->gf_numsrc > sysctl_igmp_max_msf) { + err = -ENOBUFS; + goto mc_msf_out; + } + if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { err = EINVAL; goto mc_msf_out; } diff -urN linux-2.6.4-rc2/net/ipv4/ipvs/ip_vs_ctl.c linux-2.6.4-rc3/net/ipv4/ipvs/ip_vs_ctl.c --- linux-2.6.4-rc2/net/ipv4/ipvs/ip_vs_ctl.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv4/ipvs/ip_vs_ctl.c 2004-03-09 16:36:31.000000000 -0800 @@ -1836,9 +1836,9 @@ /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) { - IP_VS_INFO("vs_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s", - ntohs(usvc->protocol), NIPQUAD(usvc->addr), - ntohs(usvc->port), usvc->sched_name); + IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n", + usvc->protocol, NIPQUAD(usvc->addr), + ntohs(usvc->port), usvc->sched_name); ret = -EFAULT; goto out_unlock; } diff -urN linux-2.6.4-rc2/net/ipv4/sysctl_net_ipv4.c linux-2.6.4-rc3/net/ipv4/sysctl_net_ipv4.c --- linux-2.6.4-rc2/net/ipv4/sysctl_net_ipv4.c 2004-02-17 19:58:50.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv4/sysctl_net_ipv4.c 2004-03-09 16:36:31.000000000 -0800 @@ -39,6 +39,7 @@ /* From igmp.c */ extern int sysctl_igmp_max_memberships; +extern int sysctl_igmp_max_msf; /* From inetpeer.c */ extern int inet_peer_threshold; @@ -412,6 +413,14 @@ #endif { + .ctl_name = NET_IPV4_IGMP_MAX_MSF, + .procname = "igmp_max_msf", + .data = &sysctl_igmp_max_msf, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { .ctl_name = NET_IPV4_INET_PEER_THRESHOLD, .procname = "inet_peer_threshold", .data = &inet_peer_threshold, diff -urN linux-2.6.4-rc2/net/ipv6/ipv6_sockglue.c linux-2.6.4-rc3/net/ipv6/ipv6_sockglue.c --- linux-2.6.4-rc2/net/ipv6/ipv6_sockglue.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv6/ipv6_sockglue.c 2004-03-09 16:36:31.000000000 -0800 @@ -437,6 +437,7 @@ case MCAST_MSFILTER: { extern int sysctl_optmem_max; + extern int sysctl_mld_max_msf; struct group_filter *gsf; if (optlen < GROUP_FILTER_SIZE(0)) @@ -455,8 +456,14 @@ kfree(gsf); break; } - if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < GROUP_FILTER_SIZE(0) || - GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { + /* numsrc >= (4G-140)/128 overflow in 32 bits */ + if (gsf->gf_numsrc >= 0x1ffffffU || + gsf->gf_numsrc > sysctl_mld_max_msf) { + kfree(gsf); + retv = -ENOBUFS; + break; + } + if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { kfree(gsf); retv = -EINVAL; break; diff -urN linux-2.6.4-rc2/net/ipv6/mcast.c linux-2.6.4-rc3/net/ipv6/mcast.c --- linux-2.6.4-rc2/net/ipv6/mcast.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv6/mcast.c 2004-03-09 16:36:31.000000000 -0800 @@ -166,6 +166,10 @@ #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) +#define IPV6_MLD_MAX_MSF 10 + +int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF; + /* * socket join on multicast group */ @@ -404,6 +408,10 @@ } /* else, add a new source to the filter */ + if (psl && psl->sl_count >= sysctl_mld_max_msf) { + err = -ENOBUFS; + goto done; + } if (!psl || psl->sl_count == psl->sl_max) { struct ip6_sf_socklist *newpsl; int count = IP6_SFBLOCK; diff -urN linux-2.6.4-rc2/net/ipv6/sysctl_net_ipv6.c linux-2.6.4-rc3/net/ipv6/sysctl_net_ipv6.c --- linux-2.6.4-rc2/net/ipv6/sysctl_net_ipv6.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/ipv6/sysctl_net_ipv6.c 2004-03-09 16:36:31.000000000 -0800 @@ -76,6 +76,14 @@ .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies }, + { + .ctl_name = NET_IPV6_MLD_MAX_MSF, + .procname = "mld_max_msf", + .data = &sysctl_mld_max_msf, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, { .ctl_name = 0 } }; diff -urN linux-2.6.4-rc2/net/irda/Makefile linux-2.6.4-rc3/net/irda/Makefile --- linux-2.6.4-rc2/net/irda/Makefile 2004-02-17 19:59:23.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/Makefile 2004-03-09 16:36:31.000000000 -0800 @@ -10,6 +10,6 @@ irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \ irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \ irttp.o irda_device.o irias_object.o crc.o wrapper.o af_irda.o \ - discovery.o parameters.o irsyms.o + discovery.o parameters.o irmod.o irda-$(CONFIG_PROC_FS) += irproc.o irda-$(CONFIG_SYSCTL) += irsysctl.o diff -urN linux-2.6.4-rc2/net/irda/crc.c linux-2.6.4-rc3/net/irda/crc.c --- linux-2.6.4-rc2/net/irda/crc.c 2004-02-17 19:57:26.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/crc.c 2004-03-09 16:36:31.000000000 -0800 @@ -14,6 +14,7 @@ ********************************************************************/ #include +#include /* * This mysterious table is just the CRC of each possible byte. It can be @@ -56,10 +57,12 @@ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; +EXPORT_SYMBOL(irda_crc16_table); -unsigned short irda_calc_crc16( __u16 fcs, __u8 const *buf, size_t len) +__u16 irda_calc_crc16( __u16 fcs, __u8 const *buf, size_t len) { while (len--) fcs = irda_fcs(fcs, *buf++); return fcs; } +EXPORT_SYMBOL(irda_calc_crc16); diff -urN linux-2.6.4-rc2/net/irda/irda_device.c linux-2.6.4-rc3/net/irda/irda_device.c --- linux-2.6.4-rc2/net/irda/irda_device.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irda_device.c 2004-03-09 16:36:31.000000000 -0800 @@ -140,6 +140,8 @@ irlap_stop_mbusy_timer(self); } } +EXPORT_SYMBOL(irda_device_set_media_busy); + int irda_device_set_dtr_rts(struct net_device *dev, int dtr, int rts) { @@ -214,6 +216,7 @@ task->state = state; } +EXPORT_SYMBOL(irda_task_next_state); static void __irda_task_delete(struct irda_task *task) { @@ -320,7 +323,6 @@ struct irda_task *parent, void *param) { struct irda_task *task; - int ret; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); @@ -342,12 +344,9 @@ hashbin_insert(tasks, (irda_queue_t *) task, (long) task, NULL); /* No time to waste, so lets get going! */ - ret = irda_task_kick(task); - if (ret) - return NULL; - else - return task; + return irda_task_kick(task) ? NULL : task; } +EXPORT_SYMBOL(irda_task_execute); /* * Function irda_task_timer_expired (data) @@ -395,6 +394,7 @@ { return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup); } +EXPORT_SYMBOL(alloc_irdadev); /* * Function irda_device_init_dongle (self, type, qos) @@ -446,6 +446,7 @@ spin_unlock(&dongles->hb_spinlock); return dongle; } +EXPORT_SYMBOL(irda_device_dongle_init); /* * Function irda_device_dongle_cleanup (dongle) @@ -460,6 +461,7 @@ return 0; } +EXPORT_SYMBOL(irda_device_dongle_cleanup); /* * Function irda_device_register_dongle (dongle) @@ -479,6 +481,7 @@ return 0; } +EXPORT_SYMBOL(irda_device_register_dongle); /* * Function irda_device_unregister_dongle (dongle) @@ -496,6 +499,7 @@ ERROR("%s: dongle not found!\n", __FUNCTION__); spin_unlock(&dongles->hb_spinlock); } +EXPORT_SYMBOL(irda_device_unregister_dongle); /* * Function irda_device_set_mode (self, mode) diff -urN linux-2.6.4-rc2/net/irda/iriap.c linux-2.6.4-rc3/net/irda/iriap.c --- linux-2.6.4-rc2/net/irda/iriap.c 2004-02-17 19:57:21.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/iriap.c 2004-03-09 16:36:31.000000000 -0800 @@ -25,6 +25,7 @@ ********************************************************************/ #include +#include #include #include #include @@ -61,8 +62,6 @@ static hashbin_t *iriap = NULL; static void *service_handle; -extern char *lmp_reasons[]; - static void __iriap_close(struct iriap_cb *self); static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode); static void iriap_disconnect_indication(void *instance, void *sap, @@ -200,6 +199,7 @@ return self; } +EXPORT_SYMBOL(iriap_open); /* * Function __iriap_close (self) @@ -248,6 +248,7 @@ __iriap_close(self); } +EXPORT_SYMBOL(iriap_close); static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) { @@ -288,7 +289,7 @@ { struct iriap_cb *self; - IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, lmp_reasons[reason]); + IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]); self = (struct iriap_cb *) instance; @@ -435,6 +436,7 @@ return 0; } +EXPORT_SYMBOL(iriap_getvaluebyclass_request); /* * Function iriap_getvaluebyclass_confirm (self, skb) @@ -674,7 +676,7 @@ if (obj == NULL) { IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name); iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN, - &missing); + &irias_missing); return; } IRDA_DEBUG(4, "LM-IAS: found %s, id=%d\n", obj->name, obj->id); @@ -683,7 +685,8 @@ if (attrib == NULL) { IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr); iriap_getvaluebyclass_response(self, obj->id, - IAS_ATTRIB_UNKNOWN, &missing); + IAS_ATTRIB_UNKNOWN, + &irias_missing); return; } diff -urN linux-2.6.4-rc2/net/irda/irias_object.c linux-2.6.4-rc3/net/irda/irias_object.c --- linux-2.6.4-rc2/net/irda/irias_object.c 2004-02-17 19:58:34.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irias_object.c 2004-03-09 16:36:31.000000000 -0800 @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -33,7 +34,7 @@ /* * Used when a missing value needs to be returned */ -struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}}; +struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}}; /* * Function strndup (str, max) @@ -107,6 +108,7 @@ return obj; } +EXPORT_SYMBOL(irias_new_object); /* * Function irias_delete_attrib (attrib) @@ -165,6 +167,7 @@ return 0; } +EXPORT_SYMBOL(irias_delete_object); /* * Function irias_delete_attrib (obj) @@ -210,6 +213,7 @@ hashbin_insert(irias_objects, (irda_queue_t *) obj, 0, obj->name); } +EXPORT_SYMBOL(irias_insert_object); /* * Function irias_find_object (name) @@ -224,6 +228,7 @@ /* Unsafe (locking), object might change */ return hashbin_lock_find(irias_objects, 0, name); } +EXPORT_SYMBOL(irias_find_object); /* * Function irias_find_attrib (obj, name) @@ -246,6 +251,7 @@ /* Unsafe (locking), attrib might change */ return attrib; } +EXPORT_SYMBOL(irias_find_attrib); /* * Function irias_add_attribute (obj, attrib) @@ -318,6 +324,7 @@ spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); return 0; } +EXPORT_SYMBOL(irias_object_change_attribute); /* * Function irias_object_add_integer_attrib (obj, name, value) @@ -350,6 +357,7 @@ irias_add_attrib(obj, attrib, owner); } +EXPORT_SYMBOL(irias_add_integer_attrib); /* * Function irias_add_octseq_attrib (obj, name, octet_seq, len) @@ -384,6 +392,7 @@ irias_add_attrib(obj, attrib, owner); } +EXPORT_SYMBOL(irias_add_octseq_attrib); /* * Function irias_object_add_string_attrib (obj, string) @@ -417,6 +426,7 @@ irias_add_attrib(obj, attrib, owner); } +EXPORT_SYMBOL(irias_add_string_attrib); /* * Function irias_new_integer_value (integer) @@ -441,6 +451,7 @@ return value; } +EXPORT_SYMBOL(irias_new_integer_value); /* * Function irias_new_string_value (string) @@ -467,7 +478,7 @@ return value; } - +EXPORT_SYMBOL(irias_new_string_value); /* * Function irias_new_octseq_value (octets, len) @@ -502,6 +513,7 @@ memcpy(value->t.oct_seq, octseq , len); return value; } +EXPORT_SYMBOL(irias_new_octseq_value); struct ias_value *irias_new_missing_value(void) { @@ -553,3 +565,4 @@ } kfree(value); } +EXPORT_SYMBOL(irias_delete_value); diff -urN linux-2.6.4-rc2/net/irda/irlap.c linux-2.6.4-rc3/net/irda/irlap.c --- linux-2.6.4-rc2/net/irda/irlap.c 2004-02-17 19:59:30.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irlap.c 2004-03-09 16:36:31.000000000 -0800 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -173,6 +174,7 @@ return self; } +EXPORT_SYMBOL(irlap_open); /* * Function __irlap_close (self) @@ -233,6 +235,7 @@ } __irlap_close(lap); } +EXPORT_SYMBOL(irlap_close); /* * Function irlap_connect_indication (self, skb) diff -urN linux-2.6.4-rc2/net/irda/irlmp.c linux-2.6.4-rc3/net/irda/irlmp.c --- linux-2.6.4-rc2/net/irda/irlmp.c 2004-02-17 19:59:26.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irlmp.c 2004-03-09 16:36:31.000000000 -0800 @@ -25,6 +25,7 @@ ********************************************************************/ #include +#include #include #include #include @@ -49,11 +50,12 @@ /* These can be altered by the sysctl interface */ int sysctl_discovery = 0; int sysctl_discovery_timeout = 3; /* 3 seconds by default */ +EXPORT_SYMBOL(sysctl_discovery_timeout); int sysctl_discovery_slots = 6; /* 6 slots by default */ int sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ; char sysctl_devname[65]; -char *lmp_reasons[] = { +const char *irlmp_reasons[] = { "ERROR, NOT USED", "LM_USER_REQUEST", "LM_LAP_DISCONNECT", @@ -62,8 +64,7 @@ "LM_INIT_DISCONNECT", "ERROR, NOT USED", }; - -__u8 *irlmp_hint_to_service(__u8 *hint); +EXPORT_SYMBOL(irlmp_reasons); /* * Function irlmp_init (void) @@ -189,6 +190,7 @@ return self; } +EXPORT_SYMBOL(irlmp_open_lsap); /* * Function __irlmp_close_lsap (self) @@ -264,6 +266,7 @@ } __irlmp_close_lsap(self); } +EXPORT_SYMBOL(irlmp_close_lsap); /* * Function irlmp_register_irlap (saddr, notify) @@ -496,6 +499,7 @@ dev_kfree_skb(tx_skb); return ret; } +EXPORT_SYMBOL(irlmp_connect_request); /* * Function irlmp_connect_indication (self) @@ -569,6 +573,7 @@ return 0; } +EXPORT_SYMBOL(irlmp_connect_response); /* * Function irlmp_connect_confirm (handle, skb) @@ -667,6 +672,7 @@ return new; } +EXPORT_SYMBOL(irlmp_dup); /* * Function irlmp_disconnect_request (handle, userdata) @@ -729,6 +735,7 @@ return 0; } +EXPORT_SYMBOL(irlmp_disconnect_request); /* * Function irlmp_disconnect_indication (reason, userdata) @@ -740,7 +747,7 @@ { struct lsap_cb *lsap; - IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lmp_reasons[reason]); + IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -900,6 +907,7 @@ * Jean II */ } } +EXPORT_SYMBOL(irlmp_discovery_request); /* * Function irlmp_get_discoveries (pn, mask, slots) @@ -931,6 +939,7 @@ /* Return current cached discovery log */ return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE)); } +EXPORT_SYMBOL(irlmp_get_discoveries); /* * Function irlmp_notify_client (log) @@ -1122,6 +1131,7 @@ return ret; } +EXPORT_SYMBOL(irlmp_data_request); /* * Function irlmp_data_indication (handle, skb) @@ -1433,7 +1443,7 @@ } #endif -const __u16 service_hint_mapping[S_END][2] = { +static const __u16 service_hint_mapping[S_END][2] = { { HINT_PNP, 0 }, /* S_PNP */ { HINT_PDA, 0 }, /* S_PDA */ { HINT_COMPUTER, 0 }, /* S_COMPUTER */ @@ -1463,6 +1473,7 @@ return hint.word; } +EXPORT_SYMBOL(irlmp_service_to_hint); /* * Function irlmp_register_service (service) @@ -1490,6 +1501,7 @@ return (void *)service; } +EXPORT_SYMBOL(irlmp_register_service); /* * Function irlmp_unregister_service (handle) @@ -1532,6 +1544,7 @@ spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags); return 0; } +EXPORT_SYMBOL(irlmp_unregister_service); /* * Function irlmp_register_client (hint_mask, callback1, callback2) @@ -1568,6 +1581,7 @@ return (void *) client; } +EXPORT_SYMBOL(irlmp_register_client); /* * Function irlmp_update_client (handle, hint_mask, callback1, callback2) @@ -1599,6 +1613,7 @@ return 0; } +EXPORT_SYMBOL(irlmp_update_client); /* * Function irlmp_unregister_client (handle) @@ -1628,6 +1643,7 @@ return 0; } +EXPORT_SYMBOL(irlmp_unregister_client); /* * Function irlmp_slsap_inuse (slsap) @@ -1765,22 +1781,6 @@ return reason; } -__u32 irlmp_get_saddr(struct lsap_cb *self) -{ - ASSERT(self != NULL, return 0;); - ASSERT(self->lap != NULL, return 0;); - - return self->lap->saddr; -} - -__u32 irlmp_get_daddr(struct lsap_cb *self) -{ - ASSERT(self != NULL, return 0;); - ASSERT(self->lap != NULL, return 0;); - - return self->lap->daddr; -} - #ifdef CONFIG_PROC_FS struct irlmp_iter_state { diff -urN linux-2.6.4-rc2/net/irda/irmod.c linux-2.6.4-rc3/net/irda/irmod.c --- linux-2.6.4-rc2/net/irda/irmod.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irmod.c 2004-03-09 16:36:31.000000000 -0800 @@ -0,0 +1,185 @@ +/********************************************************************* + * + * Filename: irmod.c + * Version: 0.9 + * Description: IrDA stack main entry points + * Status: Experimental. + * Author: Dag Brattli + * Created at: Mon Dec 15 13:55:39 1997 + * Modified at: Wed Jan 5 15:12:41 2000 + * Modified by: Dag Brattli + * + * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2004 Jean Tourrilhes + * + * 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. + * + * Neither Dag Brattli nor University of Tromsų admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +/* + * This file contains the main entry points of the IrDA stack. + * They are in this file and not af_irda.c because some developpers + * are using the IrDA stack without the socket API (compiling out + * af_irda.c). + * Jean II + */ + +#include +#include +#include + +#include +#include /* notify_t */ +#include /* irlap_init */ +#include /* irlmp_init */ +#include /* iriap_init */ +#include /* irttp_init */ +#include /* irda_device_init */ + +/* irproc.c */ +extern void irda_proc_register(void); +extern void irda_proc_unregister(void); +/* irsysctl.c */ +extern int irda_sysctl_register(void); +extern void irda_sysctl_unregister(void); +/* af_irda.c */ +extern int irsock_init(void); +extern void irsock_cleanup(void); +/* irlap_frame.c */ +extern int irlap_driver_rcv(struct sk_buff *, struct net_device *, + struct packet_type *); + +/* + * Module parameters + */ +#ifdef CONFIG_IRDA_DEBUG +unsigned int irda_debug = IRDA_DEBUG_LEVEL; +module_param_named(debug, irda_debug, uint, 0); +MODULE_PARM_DESC(irda_debug, "IRDA debugging level"); +EXPORT_SYMBOL(irda_debug); +#endif + +/* Packet type handler. + * Tell the kernel how IrDA packets should be handled. + */ +static struct packet_type irda_packet_type = { + .type = __constant_htons(ETH_P_IRDA), + .func = irlap_driver_rcv, /* Packet type handler irlap_frame.c */ +}; + +/* + * Function irda_notify_init (notify) + * + * Used for initializing the notify structure + * + */ +void irda_notify_init(notify_t *notify) +{ + notify->data_indication = NULL; + notify->udata_indication = NULL; + notify->connect_confirm = NULL; + notify->connect_indication = NULL; + notify->disconnect_indication = NULL; + notify->flow_indication = NULL; + notify->status_indication = NULL; + notify->instance = NULL; + strlcpy(notify->name, "Unknown", sizeof(notify->name)); +} +EXPORT_SYMBOL(irda_notify_init); + +/* + * Function irda_init (void) + * + * Protocol stack initialisation entry point. + * Initialise the various components of the IrDA stack + */ +int __init irda_init(void) +{ + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + + /* Lower layer of the stack */ + irlmp_init(); + irlap_init(); + + /* Higher layers of the stack */ + iriap_init(); + irttp_init(); + irsock_init(); + + /* Add IrDA packet type (Start receiving packets) */ + dev_add_pack(&irda_packet_type); + + /* External APIs */ +#ifdef CONFIG_PROC_FS + irda_proc_register(); +#endif +#ifdef CONFIG_SYSCTL + irda_sysctl_register(); +#endif + + /* Driver/dongle support */ + irda_device_init(); + + return 0; +} + +/* + * Function irda_cleanup (void) + * + * Protocol stack cleanup/removal entry point. + * Cleanup the various components of the IrDA stack + */ +void __exit irda_cleanup(void) +{ + /* Remove External APIs */ +#ifdef CONFIG_SYSCTL + irda_sysctl_unregister(); +#endif +#ifdef CONFIG_PROC_FS + irda_proc_unregister(); +#endif + + /* Remove IrDA packet type (stop receiving packets) */ + dev_remove_pack(&irda_packet_type); + + /* Remove higher layers */ + irsock_cleanup(); + irttp_cleanup(); + iriap_cleanup(); + + /* Remove lower layers */ + irda_device_cleanup(); + irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ + + /* Remove middle layer */ + irlmp_cleanup(); +} + +/* + * The IrDA stack must be initialised *before* drivers get initialised, + * and *before* higher protocols (IrLAN/IrCOMM/IrNET) get initialised, + * otherwise bad things will happen (hashbins will be NULL for example). + * Those modules are at module_init()/device_initcall() level. + * + * On the other hand, it needs to be initialised *after* the basic + * networking, the /proc/net filesystem and sysctl module. Those are + * currently initialised in .../init/main.c (before initcalls). + * Also, IrDA drivers needs to be initialised *after* the random number + * generator (main stack and higher layer init don't need it anymore). + * + * Jean II + */ +subsys_initcall(irda_init); +module_exit(irda_cleanup); + +MODULE_AUTHOR("Dag Brattli & Jean Tourrilhes "); +MODULE_DESCRIPTION("The Linux IrDA Protocol Stack"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_IRDA); diff -urN linux-2.6.4-rc2/net/irda/irproc.c linux-2.6.4-rc3/net/irda/irproc.c --- linux-2.6.4-rc2/net/irda/irproc.c 2004-02-17 20:00:01.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irproc.c 2004-03-09 16:36:31.000000000 -0800 @@ -45,6 +45,7 @@ }; struct proc_dir_entry *proc_irda; +EXPORT_SYMBOL(proc_irda); static struct irda_entry irda_dirs[] = { {"discovery", &discovery_seq_fops}, diff -urN linux-2.6.4-rc2/net/irda/irqueue.c linux-2.6.4-rc3/net/irda/irqueue.c --- linux-2.6.4-rc2/net/irda/irqueue.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irqueue.c 2004-03-09 16:36:31.000000000 -0800 @@ -191,6 +191,7 @@ * * Jean II */ +#include #include #include @@ -374,6 +375,7 @@ return hashbin; } +EXPORT_SYMBOL(hashbin_new); /* @@ -427,6 +429,7 @@ return 0; } +EXPORT_SYMBOL(hashbin_delete); /********************* HASHBIN LIST OPERATIONS *********************/ @@ -478,6 +481,7 @@ spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); } /* Default is no-lock */ } +EXPORT_SYMBOL(hashbin_insert); /* * Function hashbin_remove_first (hashbin) @@ -628,6 +632,7 @@ return NULL; } +EXPORT_SYMBOL(hashbin_remove); /* * Function hashbin_remove_this (hashbin, entry) @@ -690,6 +695,7 @@ return entry; } +EXPORT_SYMBOL(hashbin_remove_this); /*********************** HASHBIN ENUMERATION ***********************/ @@ -743,6 +749,7 @@ return NULL; } +EXPORT_SYMBOL(hashbin_find); /* * Function hashbin_lock_find (hashbin, hashv, name) @@ -771,6 +778,7 @@ return entry; } +EXPORT_SYMBOL(hashbin_lock_find); /* * Function hashbin_find (hashbin, hashv, name, pnext) @@ -812,6 +820,7 @@ return entry; } +EXPORT_SYMBOL(hashbin_find_next); /* * Function hashbin_get_first (hashbin) @@ -843,6 +852,7 @@ */ return NULL; } +EXPORT_SYMBOL(hashbin_get_first); /* * Function hashbin_get_next (hashbin) @@ -900,3 +910,4 @@ } return NULL; } +EXPORT_SYMBOL(hashbin_get_next); diff -urN linux-2.6.4-rc2/net/irda/irsyms.c linux-2.6.4-rc3/net/irda/irsyms.c --- linux-2.6.4-rc2/net/irda/irsyms.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irsyms.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,300 +0,0 @@ -/********************************************************************* - * - * Filename: irsyms.c - * Version: 0.9 - * Description: IrDA module symbols - * Status: Experimental. - * Author: Dag Brattli - * Created at: Mon Dec 15 13:55:39 1997 - * Modified at: Wed Jan 5 15:12:41 2000 - * Modified by: Dag Brattli - * - * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes - * - * 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. - * - * Neither Dag Brattli nor University of Tromsų admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include -#include - -#include -#include -#include -#include -#include /* ARPHRD_IRDA */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct proc_dir_entry *proc_irda; - -extern void irda_proc_register(void); -extern void irda_proc_unregister(void); -extern int irda_sysctl_register(void); -extern void irda_sysctl_unregister(void); - -extern int irda_proto_init(void); -extern void irda_proto_cleanup(void); - -extern int irda_device_init(void); -extern int irlan_init(void); -extern int irlan_client_init(void); -extern int irlan_server_init(void); -extern int ircomm_init(void); -extern int ircomm_tty_init(void); -extern int irlpt_client_init(void); -extern int irlpt_server_init(void); - -extern int irsock_init(void); -extern void irsock_cleanup(void); -extern int irlap_driver_rcv(struct sk_buff *, struct net_device *, - struct packet_type *); - -/* IrTTP */ -EXPORT_SYMBOL(irttp_open_tsap); -EXPORT_SYMBOL(irttp_close_tsap); -EXPORT_SYMBOL(irttp_connect_response); -EXPORT_SYMBOL(irttp_data_request); -EXPORT_SYMBOL(irttp_disconnect_request); -EXPORT_SYMBOL(irttp_flow_request); -EXPORT_SYMBOL(irttp_connect_request); -EXPORT_SYMBOL(irttp_udata_request); -EXPORT_SYMBOL(irttp_dup); - -/* Main IrDA module */ -#ifdef CONFIG_IRDA_DEBUG -EXPORT_SYMBOL(irda_debug); -#endif -EXPORT_SYMBOL(irda_notify_init); -#ifdef CONFIG_PROC_FS -EXPORT_SYMBOL(proc_irda); -#endif -EXPORT_SYMBOL(irda_param_insert); -EXPORT_SYMBOL(irda_param_extract); -EXPORT_SYMBOL(irda_param_extract_all); -EXPORT_SYMBOL(irda_param_pack); -EXPORT_SYMBOL(irda_param_unpack); - -/* IrIAP/IrIAS */ -EXPORT_SYMBOL(iriap_open); -EXPORT_SYMBOL(iriap_close); -EXPORT_SYMBOL(iriap_getvaluebyclass_request); -EXPORT_SYMBOL(irias_object_change_attribute); -EXPORT_SYMBOL(irias_add_integer_attrib); -EXPORT_SYMBOL(irias_add_octseq_attrib); -EXPORT_SYMBOL(irias_add_string_attrib); -EXPORT_SYMBOL(irias_insert_object); -EXPORT_SYMBOL(irias_new_object); -EXPORT_SYMBOL(irias_delete_object); -EXPORT_SYMBOL(irias_delete_value); -EXPORT_SYMBOL(irias_find_object); -EXPORT_SYMBOL(irias_find_attrib); -EXPORT_SYMBOL(irias_new_integer_value); -EXPORT_SYMBOL(irias_new_string_value); -EXPORT_SYMBOL(irias_new_octseq_value); - -/* IrLMP */ -EXPORT_SYMBOL(irlmp_discovery_request); -EXPORT_SYMBOL(irlmp_get_discoveries); -EXPORT_SYMBOL(sysctl_discovery_timeout); -EXPORT_SYMBOL(irlmp_register_client); -EXPORT_SYMBOL(irlmp_unregister_client); -EXPORT_SYMBOL(irlmp_update_client); -EXPORT_SYMBOL(irlmp_register_service); -EXPORT_SYMBOL(irlmp_unregister_service); -EXPORT_SYMBOL(irlmp_service_to_hint); -EXPORT_SYMBOL(irlmp_data_request); -EXPORT_SYMBOL(irlmp_open_lsap); -EXPORT_SYMBOL(irlmp_close_lsap); -EXPORT_SYMBOL(irlmp_connect_request); -EXPORT_SYMBOL(irlmp_connect_response); -EXPORT_SYMBOL(irlmp_disconnect_request); -EXPORT_SYMBOL(irlmp_get_daddr); -EXPORT_SYMBOL(irlmp_get_saddr); -EXPORT_SYMBOL(irlmp_dup); -EXPORT_SYMBOL(lmp_reasons); - -/* Queue */ -EXPORT_SYMBOL(hashbin_new); -EXPORT_SYMBOL(hashbin_insert); -EXPORT_SYMBOL(hashbin_delete); -EXPORT_SYMBOL(hashbin_remove); -EXPORT_SYMBOL(hashbin_remove_this); -EXPORT_SYMBOL(hashbin_find); -EXPORT_SYMBOL(hashbin_lock_find); -EXPORT_SYMBOL(hashbin_find_next); -EXPORT_SYMBOL(hashbin_get_next); -EXPORT_SYMBOL(hashbin_get_first); - -/* IrLAP */ -EXPORT_SYMBOL(irlap_open); -EXPORT_SYMBOL(irlap_close); -EXPORT_SYMBOL(irda_init_max_qos_capabilies); -EXPORT_SYMBOL(irda_qos_bits_to_value); -EXPORT_SYMBOL(irda_device_setup); -EXPORT_SYMBOL(alloc_irdadev); -EXPORT_SYMBOL(irda_device_set_media_busy); -EXPORT_SYMBOL(irda_device_txqueue_empty); - -EXPORT_SYMBOL(irda_device_dongle_init); -EXPORT_SYMBOL(irda_device_dongle_cleanup); -EXPORT_SYMBOL(irda_device_register_dongle); -EXPORT_SYMBOL(irda_device_unregister_dongle); -EXPORT_SYMBOL(irda_task_execute); -EXPORT_SYMBOL(irda_task_next_state); -EXPORT_SYMBOL(irda_task_delete); - -EXPORT_SYMBOL(async_wrap_skb); -EXPORT_SYMBOL(async_unwrap_char); -EXPORT_SYMBOL(irda_calc_crc16); -EXPORT_SYMBOL(irda_crc16_table); -EXPORT_SYMBOL(irda_start_timer); - -#ifdef CONFIG_IRTTY -EXPORT_SYMBOL(irtty_set_dtr_rts); -EXPORT_SYMBOL(irtty_register_dongle); -EXPORT_SYMBOL(irtty_unregister_dongle); -EXPORT_SYMBOL(irtty_set_packet_mode); -#endif - -#ifdef CONFIG_IRDA_DEBUG -__u32 irda_debug = IRDA_DEBUG_LEVEL; -#endif - -/* Packet type handler. - * Tell the kernel how IrDA packets should be handled. - */ -static struct packet_type irda_packet_type = { - .type = __constant_htons(ETH_P_IRDA), - .func = irlap_driver_rcv, /* Packet type handler irlap_frame.c */ -}; - -/* - * Function irda_notify_init (notify) - * - * Used for initializing the notify structure - * - */ -void irda_notify_init(notify_t *notify) -{ - notify->data_indication = NULL; - notify->udata_indication = NULL; - notify->connect_confirm = NULL; - notify->connect_indication = NULL; - notify->disconnect_indication = NULL; - notify->flow_indication = NULL; - notify->status_indication = NULL; - notify->instance = NULL; - strlcpy(notify->name, "Unknown", sizeof(notify->name)); -} - -/* - * Function irda_init (void) - * - * Protocol stack initialisation entry point. - * Initialise the various components of the IrDA stack - */ -int __init irda_init(void) -{ - IRDA_DEBUG(0, "%s()\n", __FUNCTION__); - - /* Lower layer of the stack */ - irlmp_init(); - irlap_init(); - - /* Higher layers of the stack */ - iriap_init(); - irttp_init(); - irsock_init(); - - /* Add IrDA packet type (Start receiving packets) */ - dev_add_pack(&irda_packet_type); - - /* External APIs */ -#ifdef CONFIG_PROC_FS - irda_proc_register(); -#endif -#ifdef CONFIG_SYSCTL - irda_sysctl_register(); -#endif - - /* Driver/dongle support */ - irda_device_init(); - - return 0; -} - -/* - * Function irda_cleanup (void) - * - * Protocol stack cleanup/removal entry point. - * Cleanup the various components of the IrDA stack - */ -void __exit irda_cleanup(void) -{ - /* Remove External APIs */ -#ifdef CONFIG_SYSCTL - irda_sysctl_unregister(); -#endif -#ifdef CONFIG_PROC_FS - irda_proc_unregister(); -#endif - - /* Remove IrDA packet type (stop receiving packets) */ - dev_remove_pack(&irda_packet_type); - - /* Remove higher layers */ - irsock_cleanup(); - irttp_cleanup(); - iriap_cleanup(); - - /* Remove lower layers */ - irda_device_cleanup(); - irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ - - /* Remove middle layer */ - irlmp_cleanup(); -} - -/* - * The IrDA stack must be initialised *before* drivers get initialised, - * and *before* higher protocols (IrLAN/IrCOMM/IrNET) get initialised, - * otherwise bad things will happen (hashbins will be NULL for example). - * Those modules are at module_init()/device_initcall() level. - * - * On the other hand, it needs to be initialised *after* the basic - * networking, the /proc/net filesystem and sysctl module. Those are - * currently initialised in .../init/main.c (before initcalls). - * Also, IrDA drivers needs to be initialised *after* the random number - * generator (main stack and higher layer init don't need it anymore). - * - * Jean II - */ -subsys_initcall(irda_init); -module_exit(irda_cleanup); - -MODULE_AUTHOR("Dag Brattli & Jean Tourrilhes "); -MODULE_DESCRIPTION("The Linux IrDA Protocol Stack"); -MODULE_LICENSE("GPL"); -#ifdef CONFIG_IRDA_DEBUG -MODULE_PARM(irda_debug, "1l"); -#endif -MODULE_ALIAS_NETPROTO(PF_IRDA); diff -urN linux-2.6.4-rc2/net/irda/irsysctl.c linux-2.6.4-rc3/net/irda/irsysctl.c --- linux-2.6.4-rc2/net/irda/irsysctl.c 2004-02-17 19:57:30.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irsysctl.c 2004-03-09 16:36:31.000000000 -0800 @@ -29,7 +29,7 @@ #include #include -#include +#include /* irda_debug */ #include #define NET_IRDA 412 /* Random number */ @@ -53,10 +53,6 @@ extern int sysctl_warn_noreply_time; extern int sysctl_lap_keepalive_time; -#ifdef CONFIG_IRDA_DEBUG -extern unsigned int irda_debug; -#endif - /* this is needed for the proc_dointvec_minmax - Jean II */ static int max_discovery_slots = 16; /* ??? */ static int min_discovery_slots = 1; diff -urN linux-2.6.4-rc2/net/irda/irttp.c linux-2.6.4-rc3/net/irda/irttp.c --- linux-2.6.4-rc2/net/irda/irttp.c 2004-02-17 19:58:28.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/irttp.c 2004-03-09 16:36:31.000000000 -0800 @@ -450,6 +450,7 @@ return self; } +EXPORT_SYMBOL(irttp_open_tsap); /* * Function irttp_close (handle) @@ -525,6 +526,7 @@ return 0; } +EXPORT_SYMBOL(irttp_close_tsap); /* * Function irttp_udata_request (self, skb) @@ -562,6 +564,8 @@ dev_kfree_skb(skb); return -1; } +EXPORT_SYMBOL(irttp_udata_request); + /* * Function irttp_data_request (handle, skb) @@ -672,6 +676,7 @@ dev_kfree_skb(skb); return ret; } +EXPORT_SYMBOL(irttp_data_request); /* * Function irttp_run_tx_queue (self) @@ -1058,6 +1063,7 @@ IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __FUNCTION__); } } +EXPORT_SYMBOL(irttp_flow_request); /* * Function irttp_connect_request (self, dtsap_sel, daddr, qos) @@ -1153,6 +1159,7 @@ return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, tx_skb); } +EXPORT_SYMBOL(irttp_connect_request); /* * Function irttp_connect_confirm (handle, qos, skb) @@ -1397,6 +1404,7 @@ return ret; } +EXPORT_SYMBOL(irttp_connect_response); /* * Function irttp_dup (self, instance) @@ -1455,6 +1463,7 @@ return new; } +EXPORT_SYMBOL(irttp_dup); /* * Function irttp_disconnect_request (self) @@ -1549,6 +1558,7 @@ return ret; } +EXPORT_SYMBOL(irttp_disconnect_request); /* * Function irttp_disconnect_indication (self, reason) diff -urN linux-2.6.4-rc2/net/irda/parameters.c linux-2.6.4-rc3/net/irda/parameters.c --- linux-2.6.4-rc2/net/irda/parameters.c 2004-02-17 19:58:39.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/parameters.c 2004-03-09 16:36:31.000000000 -0800 @@ -29,6 +29,8 @@ ********************************************************************/ #include +#include + #include #include @@ -393,6 +395,7 @@ return 0; } +EXPORT_SYMBOL(irda_param_pack); /* * Function irda_param_unpack (skb, fmt, ...) @@ -437,6 +440,7 @@ return 0; } +EXPORT_SYMBOL(irda_param_unpack); /* * Function irda_param_insert (self, pi, buf, len, info) @@ -489,6 +493,7 @@ pi_minor_info->func); return ret; } +EXPORT_SYMBOL(irda_param_insert); /* * Function irda_param_extract_all (self, buf, len, info) @@ -544,6 +549,7 @@ type, pi_minor_info->func); return ret; } +EXPORT_SYMBOL(irda_param_extract); /* * Function irda_param_extract_all (self, buf, len, info) @@ -575,4 +581,4 @@ } return n; } - +EXPORT_SYMBOL(irda_param_extract_all); diff -urN linux-2.6.4-rc2/net/irda/qos.c linux-2.6.4-rc3/net/irda/qos.c --- linux-2.6.4-rc2/net/irda/qos.c 2004-02-17 19:59:19.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/qos.c 2004-03-09 16:36:31.000000000 -0800 @@ -336,6 +336,7 @@ qos->link_disc_time.bits &= 0xff; qos->additional_bofs.bits = 0xff; } +EXPORT_SYMBOL(irda_init_max_qos_capabilies); /* * Function irlap_adjust_qos_settings (qos) @@ -774,3 +775,4 @@ index = msb_index(qos->additional_bofs.bits); qos->additional_bofs.value = add_bofs[index]; } +EXPORT_SYMBOL(irda_qos_bits_to_value); diff -urN linux-2.6.4-rc2/net/irda/timer.c linux-2.6.4-rc3/net/irda/timer.c --- linux-2.6.4-rc2/net/irda/timer.c 2004-02-17 19:58:07.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/timer.c 2004-03-09 16:36:31.000000000 -0800 @@ -41,29 +41,6 @@ static void irlap_backoff_timer_expired(void* data); static void irlap_media_busy_expired(void* data); -/* - * Function irda_start_timer (timer, timeout) - * - * Start an IrDA timer - * - */ -void irda_start_timer(struct timer_list *ptimer, int timeout, void *data, - TIMER_CALLBACK callback) -{ - /* - * For most architectures void * is the same as unsigned long, but - * at least we try to use void * as long as possible. Since the - * timer functions use unsigned long, we cast the function here - */ - ptimer->function = (void (*)(unsigned long)) callback; - ptimer->data = (unsigned long) data; - - /* Set new value for timer (update or add timer). - * We use mod_timer() because it's more efficient and also - * safer with respect to race conditions - Jean II */ - mod_timer(ptimer, jiffies + timeout); -} - void irlap_start_slot_timer(struct irlap_cb *self, int timeout) { irda_start_timer(&self->slot_timer, timeout, (void *) self, diff -urN linux-2.6.4-rc2/net/irda/wrapper.c linux-2.6.4-rc3/net/irda/wrapper.c --- linux-2.6.4-rc2/net/irda/wrapper.c 2004-02-17 19:58:52.000000000 -0800 +++ linux-2.6.4-rc3/net/irda/wrapper.c 2004-03-09 16:36:31.000000000 -0800 @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -151,6 +152,7 @@ return n; } +EXPORT_SYMBOL(async_wrap_skb); /************************* FRAME UNWRAPPING *************************/ /* @@ -481,4 +483,5 @@ break; } } +EXPORT_SYMBOL(async_unwrap_char); diff -urN linux-2.6.4-rc2/net/sched/sch_red.c linux-2.6.4-rc3/net/sched/sch_red.c --- linux-2.6.4-rc2/net/sched/sch_red.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/sched/sch_red.c 2004-03-09 16:36:31.000000000 -0800 @@ -41,9 +41,6 @@ #include #include -#define RED_ECN_ECT 0x02 -#define RED_ECN_CE 0x01 - /* Random Early Detection (RED) algorithm. ======================================= @@ -165,28 +162,16 @@ switch (skb->protocol) { case __constant_htons(ETH_P_IP): - { - u8 tos = skb->nh.iph->tos; - - if (!(tos & RED_ECN_ECT)) + if (!INET_ECN_is_capable(skb->nh.iph->tos)) return 0; - - if (!(tos & RED_ECN_CE)) + if (INET_ECN_is_not_ce(skb->nh.iph->tos)) IP_ECN_set_ce(skb->nh.iph); - return 1; - } - case __constant_htons(ETH_P_IPV6): - { - u32 label = *(u32*)skb->nh.raw; - - if (!(label & __constant_htonl(RED_ECN_ECT<<20))) + if (!INET_ECN_is_capable(ip6_get_dsfield(skb->nh.ipv6h))) return 0; - label |= __constant_htonl(RED_ECN_CE<<20); + IP6_ECN_set_ce(skb->nh.ipv6h); return 1; - } - default: return 0; } diff -urN linux-2.6.4-rc2/net/sunrpc/auth_gss/svcauth_gss.c linux-2.6.4-rc3/net/sunrpc/auth_gss/svcauth_gss.c --- linux-2.6.4-rc2/net/sunrpc/auth_gss/svcauth_gss.c 2004-03-09 16:36:17.000000000 -0800 +++ linux-2.6.4-rc3/net/sunrpc/auth_gss/svcauth_gss.c 2004-03-09 16:36:31.000000000 -0800 @@ -594,12 +594,13 @@ iov.iov_len = sizeof(xdr_seq); xdr_buf_from_iov(&iov, &verf_data); p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len; + mic.data = (u8 *)(p + 1); maj_stat = gss_get_mic(ctx_id, 0, &verf_data, &mic); if (maj_stat != GSS_S_COMPLETE) return -1; - p = xdr_encode_netobj(rqstp->rq_res.head->iov_base - + rqstp->rq_res.head->iov_len, &mic); - kfree(mic.data); + *p++ = htonl(mic.len); + memset((u8 *)p + mic.len, 0, round_up_to_quad(mic.len) - mic.len); + p += XDR_QUADLEN(mic.len); if (!xdr_ressize_check(rqstp, p)) return -1; return 0; diff -urN linux-2.6.4-rc2/sound/oss/Makefile linux-2.6.4-rc3/sound/oss/Makefile --- linux-2.6.4-rc2/sound/oss/Makefile 2004-02-17 19:57:21.000000000 -0800 +++ linux-2.6.4-rc3/sound/oss/Makefile 2004-03-09 16:36:31.000000000 -0800 @@ -68,7 +68,7 @@ obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o -obj-$(CONFIG_SOUND_FORTE) += forte.o +obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o diff -urN linux-2.6.4-rc2/sound/oss/ac97_plugin_ad1980.c linux-2.6.4-rc3/sound/oss/ac97_plugin_ad1980.c --- linux-2.6.4-rc2/sound/oss/ac97_plugin_ad1980.c 2004-02-17 19:57:11.000000000 -0800 +++ linux-2.6.4-rc3/sound/oss/ac97_plugin_ad1980.c 2004-03-09 16:36:31.000000000 -0800 @@ -123,3 +123,4 @@ module_init(ad1980_init); module_exit(ad1980_exit); +MODULE_LICENSE("GPL"); diff -urN linux-2.6.4-rc2/sound/oss/cs46xx_wrapper-24.h linux-2.6.4-rc3/sound/oss/cs46xx_wrapper-24.h --- linux-2.6.4-rc2/sound/oss/cs46xx_wrapper-24.h 2004-02-17 19:58:36.000000000 -0800 +++ linux-2.6.4-rc3/sound/oss/cs46xx_wrapper-24.h 2004-03-09 16:36:31.000000000 -0800 @@ -28,7 +28,7 @@ #include -#define CS_OWNER owner: +#define CS_OWNER .owner = #define CS_THIS_MODULE THIS_MODULE, void cs46xx_null(struct pci_dev *pcidev) { return; } #define cs4x_mem_map_reserve(page) SetPageReserved(page) diff -urN linux-2.6.4-rc2/sound/oss/emu10k1/cardwi.c linux-2.6.4-rc3/sound/oss/emu10k1/cardwi.c --- linux-2.6.4-rc2/sound/oss/emu10k1/cardwi.c 2004-02-17 19:58:35.000000000 -0800 +++ linux-2.6.4-rc3/sound/oss/emu10k1/cardwi.c 2004-03-09 16:36:31.000000000 -0800 @@ -164,7 +164,6 @@ if (alloc_buffer(card, &wiinst->buffer) < 0) { ERROR(); - emu10k1_wavein_close(wave_dev); return -1; } diff -urN linux-2.6.4-rc2/sound/oss/sb_audio.c linux-2.6.4-rc3/sound/oss/sb_audio.c --- linux-2.6.4-rc2/sound/oss/sb_audio.c 2004-02-17 19:59:13.000000000 -0800 +++ linux-2.6.4-rc3/sound/oss/sb_audio.c 2004-03-09 16:36:31.000000000 -0800 @@ -882,7 +882,7 @@ c -= locallen; p += locallen; } /* used = ( samples * 16 bits size ) */ - *used = len << 1; + *used = max_in > ( max_out << 1) ? (max_out << 1) : max_in; /* returned = ( samples * 8 bits size ) */ *returned = len; }