--- linux-2.6.1-rc1/arch/alpha/kernel/traps.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/alpha/kernel/traps.c 2003-12-30 22:49:56.000000000 -0800 @@ -636,6 +636,7 @@ do_entUna(void * va, unsigned long opcod lock_kernel(); printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", pc, va, opcode, reg); + dump_stack(); do_exit(SIGSEGV); got_exception: --- linux-2.6.1-rc1/arch/i386/boot/setup.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/boot/setup.S 2003-12-30 22:50:18.000000000 -0800 @@ -162,7 +162,7 @@ cmd_line_ptr: .long 0 # (Header versio # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd --- linux-2.6.1-rc1/arch/i386/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/Kconfig 2003-12-30 22:50:18.000000000 -0800 @@ -402,6 +402,54 @@ config X86_OOSTORE depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 default y +config X86_4G + bool "4 GB kernel-space and 4 GB user-space virtual memory support" + help + This option is only useful for systems that have more than 1 GB + of RAM. + + The default kernel VM layout leaves 1 GB of virtual memory for + kernel-space mappings, and 3 GB of VM for user-space applications. + This option ups both the kernel-space VM and the user-space VM to + 4 GB. + + The cost of this option is additional TLB flushes done at + system-entry points that transition from user-mode into kernel-mode. + I.e. system calls and page faults, and IRQs that interrupt user-mode + code. There's also additional overhead to kernel operations that copy + memory to/from user-space. The overhead from this is hard to tell and + depends on the workload - it can be anything from no visible overhead + to 20-30% overhead. A good rule of thumb is to count with a runtime + overhead of 20%. + + The upside is the much increased kernel-space VM, which more than + quadruples the maximum amount of RAM supported. Kernels compiled with + this option boot on 64GB of RAM and still have more than 3.1 GB of + 'lowmem' left. Another bonus is that highmem IO bouncing decreases, + if used with drivers that still use bounce-buffers. + + There's also a 33% increase in user-space VM size - database + applications might see a boost from this. + + But the cost of the TLB flushes and the runtime overhead has to be + weighed against the bonuses offered by the larger VM spaces. The + dividing line depends on the actual workload - there might be 4 GB + systems that benefit from this option. Systems with less than 4 GB + of RAM will rarely see a benefit from this option - but it's not + out of question, the exact circumstances have to be considered. + +config X86_SWITCH_PAGETABLES + def_bool X86_4G + +config X86_4G_VM_LAYOUT + def_bool X86_4G + +config X86_UACCESS_INDIRECT + def_bool X86_4G + +config X86_HIGH_ENTRY + def_bool X86_4G + config HPET_TIMER bool "HPET Timer Support" help @@ -1230,6 +1278,15 @@ config DEBUG_PAGEALLOC This results in a large slowdown, but helps to find certain types of memory corruptions. +config SPINLINE + bool "Spinlock inlining" + depends on DEBUG_KERNEL + help + This will change spinlocks from out of line to inline, making them + account cost to the callers in readprofile, rather than the lock + itself (as ".text.lock.filename"). This can be helpful for finding + the callers of locks. + config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM @@ -1246,20 +1303,208 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" help If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb.txt file. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +config KGDB_PORT + hex "hex I/O port address of the debug serial port" + depends on KGDB + default 3f8 + help + Some systems (x86 family at this writing) allow the port + address to be configured. The number entered is assumed to be + hex, don't put 0x in front of it. The standard address are: + COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx + will tell you what you have. It is good to test the serial + connection with a live system before trying to debug. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 4 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config STACK_OVERFLOW_TEST + bool "Turn on kernel stack overflow testing?" + depends on KGDB + default n + help + This option enables code in the front line interrupt handlers + to check for kernel stack overflow on interrupts and system + calls. This is part of the kgdb code on x86 systems. + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + config FRAME_POINTER bool "Compile the kernel with frame pointers" + default KGDB help If you say Y here the resulting kernel image will be slightly larger and slower, but it will give very useful debugging information. If you don't debug the kernel, you can say N, but we may not be able to solve problems without frame pointers. +config MAGIC_SYSRQ + bool + depends on KGDB_SYSRQ + default y + config X86_EXTRA_IRQS bool depends on X86_LOCAL_APIC || X86_VOYAGER --- linux-2.6.1-rc1/arch/i386/kernel/acpi/boot.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/acpi/boot.c 2003-12-30 22:49:52.000000000 -0800 @@ -41,9 +41,8 @@ #define PREFIX "ACPI: " -extern int acpi_disabled; -extern int acpi_irq; -extern int acpi_ht; +int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +int acpi_ht __initdata = 1; /* enable HT */ int acpi_lapic = 0; int acpi_ioapic = 0; @@ -250,29 +249,66 @@ acpi_parse_nmi_src ( #ifdef CONFIG_ACPI_BUS /* - * Set specified PIC IRQ to level triggered mode. + * "acpi_pic_sci=level" (current default) + * 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 + * it may require Edge Trigger -- use "acpi_pic_sci=edge" + * (NO-OP if the BIOS set Edge Trigger already) * * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) - * - * As the BIOS should have done this for us, - * print a warning if the IRQ wasn't already set to level. */ -void acpi_pic_set_level_irq(unsigned int irq) +static int __initdata acpi_pic_sci_trigger; /* 0: level, 1: edge */ + +void __init +acpi_pic_sci_set_trigger(unsigned int irq) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); unsigned char val = inb(port); + + printk(PREFIX "IRQ%d SCI:", irq); if (!(val & mask)) { - printk(KERN_WARNING PREFIX "IRQ %d was Edge Triggered, " - "setting to Level Triggerd\n", irq); - outb(val | mask, port); + printk(" Edge"); + + if (!acpi_pic_sci_trigger) { + printk(" set to Level"); + outb(val | mask, port); + } + } else { + printk(" Level"); + + if (acpi_pic_sci_trigger) { + printk(" set to Edge"); + outb(val | mask, port); + } } + printk(" Trigger.\n"); } + +int __init +acpi_pic_sci_setup(char *str) +{ + while (str && *str) { + if (strncmp(str, "level", 5) == 0) + acpi_pic_sci_trigger = 0; /* force level trigger */ + if (strncmp(str, "edge", 4) == 0) + acpi_pic_sci_trigger = 1; /* force edge trigger */ + str = strchr(str, ','); + if (str) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("acpi_pic_sci=", acpi_pic_sci_setup); + #endif /* CONFIG_ACPI_BUS */ @@ -327,6 +363,37 @@ static int __init acpi_parse_hpet(unsign } #endif +/* detect the location of the ACPI PM Timer */ +#ifdef CONFIG_X86_PM_TIMER +extern u32 pmtmr_ioport; + +static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt =0; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if(!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + + if (fadt->revision >= FADT2_REVISION_ID) { + /* FADT rev. 2 */ + if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) + return 0; + + pmtmr_ioport = fadt->xpm_tmr_blk.address; + } else { + /* FADT rev. 1 */ + pmtmr_ioport = fadt->V1_pm_tmr_blk; + } + if (pmtmr_ioport) + printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport); + return 0; +} +#endif + + unsigned long __init acpi_find_rsdp (void) { @@ -387,8 +454,10 @@ acpi_boot_init (void) * Initialize the ACPI boot-time table parser. */ result = acpi_table_init(); - if (result) + if (result) { + acpi_disabled = 1; return result; + } result = acpi_blacklisted(); if (result) { @@ -469,7 +538,7 @@ acpi_boot_init (void) * If MPS is present, it will handle them, * otherwise the system will stay in PIC mode */ - if (acpi_disabled || !acpi_irq) { + if (acpi_disabled || acpi_noirq) { return 1; } @@ -511,6 +580,8 @@ acpi_boot_init (void) acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */ @@ -526,5 +597,9 @@ acpi_boot_init (void) acpi_table_parse(ACPI_HPET, acpi_parse_hpet); #endif +#ifdef CONFIG_X86_PM_TIMER + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); +#endif + return 0; } --- linux-2.6.1-rc1/arch/i386/kernel/asm-offsets.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/asm-offsets.c 2003-12-30 22:50:18.000000000 -0800 @@ -4,9 +4,11 @@ * to extract and format the required data. */ +#include #include #include #include "sigframe.h" +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -28,4 +30,17 @@ void foo(void) DEFINE(RT_SIGFRAME_sigcontext, offsetof (struct rt_sigframe, uc.uc_mcontext)); + DEFINE(TI_task, offsetof (struct thread_info, task)); + DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain)); + DEFINE(TI_flags, offsetof (struct thread_info, flags)); + DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count)); + DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit)); + DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack)); + DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack)); + DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd)); + + DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0)); + DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL)); + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(task_thread_db7, offsetof (struct task_struct, thread.debugreg[7])); } --- linux-2.6.1-rc1/arch/i386/kernel/cpu/common.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/cpu/common.c 2003-12-30 22:50:18.000000000 -0800 @@ -514,12 +514,16 @@ void __init cpu_init (void) set_tss_desc(cpu,t); cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); - load_LDT(&init_mm.context); + if (cpu) + load_LDT(&init_mm.context); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; + if (cpu) + trap_init_virtual_GDT(); + /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); --- linux-2.6.1-rc1/arch/i386/kernel/cpu/intel.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/kernel/cpu/intel.c 2003-12-30 22:50:18.000000000 -0800 @@ -1,5 +1,7 @@ +#include #include #include + #include #include #include @@ -8,10 +10,15 @@ #include #include #include +#include #include "cpu.h" -extern int trap_init_f00f_bug(void); +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#include +#endif #ifdef CONFIG_X86_INTEL_USERCOPY /* @@ -157,7 +164,7 @@ static void __init init_intel(struct cpu c->f00f_bug = 1; if ( !f00f_workaround_enabled ) { - trap_init_f00f_bug(); + trap_init_virtual_IDT(); printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); f00f_workaround_enabled = 1; } @@ -240,6 +247,12 @@ static void __init init_intel(struct cpu /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */ if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) clear_bit(X86_FEATURE_SEP, c->x86_capability); + /* + * FIXME: SEP is disabled for 4G/4G for now: + */ +#ifdef CONFIG_X86_HIGH_ENTRY + clear_bit(X86_FEATURE_SEP, c->x86_capability); +#endif /* Names for the Pentium II/Celeron processors detectable only by also checking the cache size. @@ -277,6 +290,7 @@ static void __init init_intel(struct cpu extern int phys_proc_id[NR_CPUS]; u32 eax, ebx, ecx, edx; + int index_lsb, index_msb, tmp; int cpu = smp_processor_id(); cpuid(1, &eax, &ebx, &ecx, &edx); @@ -285,6 +299,8 @@ static void __init init_intel(struct cpu if (smp_num_siblings == 1) { printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); } else if (smp_num_siblings > 1 ) { + index_lsb = 0; + index_msb = 31; /* * At this point we only support two siblings per * processor package. @@ -295,13 +311,19 @@ static void __init init_intel(struct cpu smp_num_siblings = 1; goto too_many_siblings; } - /* cpuid returns the value latched in the HW at reset, - * not the APIC ID register's value. For any box - * whose BIOS changes APIC IDs, like clustered APIC - * systems, we must use hard_smp_processor_id. - * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID. - */ - phys_proc_id[cpu] = hard_smp_processor_id() & ~(smp_num_siblings - 1); + tmp = smp_num_siblings; + while ((tmp & 1) == 0) { + tmp >>=1 ; + index_lsb++; + } + tmp = smp_num_siblings; + while ((tmp & 0x80000000 ) == 0) { + tmp <<=1 ; + index_msb--; + } + if (index_lsb != index_msb ) + index_msb++; + phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb); printk(KERN_INFO "CPU: Physical Processor ID: %d\n", phys_proc_id[cpu]); --- linux-2.6.1-rc1/arch/i386/kernel/dmi_scan.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/i386/kernel/dmi_scan.c 2003-12-30 22:49:41.000000000 -0800 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ EXPORT_SYMBOL(dmi_broken); int is_sony_vaio_laptop; int is_unsafe_smbus; +int es7000_plat = 0; struct dmi_header { @@ -504,6 +506,7 @@ static __init int print_if_true(struct d } +#ifdef CONFIG_ACPI_BOOT extern int acpi_disabled, acpi_force; static __init __attribute__((unused)) int acpi_disable(struct dmi_blacklist *d) @@ -518,8 +521,6 @@ static __init __attribute__((unused)) in return 0; } - -#ifdef CONFIG_ACPI_BOOT extern int acpi_ht; /* @@ -542,10 +543,8 @@ static __init __attribute__((unused)) in #ifdef CONFIG_ACPI_PCI static __init int disable_acpi_pci(struct dmi_blacklist *d) { - extern __init void pci_disable_acpi(void) ; - printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", d->ident); - pci_disable_acpi(); + acpi_noirq_set(); return 0; } #endif @@ -1011,6 +1010,7 @@ static __init void dmi_check_blacklist(v printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s); printk(KERN_NOTICE "You can enable it with acpi=force\n"); acpi_disabled = 1; + acpi_ht = 0; } } } --- linux-2.6.1-rc1/arch/i386/kernel/doublefault.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/doublefault.c 2003-12-30 22:50:18.000000000 -0800 @@ -7,12 +7,13 @@ #include #include #include +#include #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) -#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000) +#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START)) static void doublefault_fn(void) { @@ -38,8 +39,8 @@ static void doublefault_fn(void) printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", t->eax, t->ebx, t->ecx, t->edx); - printk("esi = %08lx, edi = %08lx\n", - t->esi, t->edi); + printk("esi = %08lx, edi = %08lx, ebp = %08lx\n", + t->esi, t->edi, t->ebp); } } --- linux-2.6.1-rc1/arch/i386/kernel/entry.S 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/kernel/entry.S 2003-12-30 22:50:18.000000000 -0800 @@ -43,11 +43,25 @@ #include #include #include +#include #include #include +#include #include #include #include "irq_vectors.h" + /* We do not recover from a stack overflow, but at least + * we know it happened and should be able to track it down. + */ +#ifdef CONFIG_STACK_OVERFLOW_TEST +#define STACK_OVERFLOW_TEST \ + testl $7680,%esp; \ + jnz 10f; \ + call stack_overflow; \ +10: +#else +#define STACK_OVERFLOW_TEST +#endif #define nr_syscalls ((syscall_table_size)/4) @@ -87,7 +101,102 @@ TSS_ESP0_OFFSET = (4 - 0x200) #define resume_kernel restore_all #endif -#define SAVE_ALL \ +#ifdef CONFIG_X86_HIGH_ENTRY + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) +/* + * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu, + * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is + * left stale, so we must check whether to repeat the real stack calculation. + */ +#define repeat_if_esp_changed \ + xorl %esp, %ebp; \ + testl $0xffffe000, %ebp; \ + jnz 0b +#else +#define repeat_if_esp_changed +#endif + +/* clobbers ebx, edx and ebp */ + +#define __SWITCH_KERNELSPACE \ + cmpl $0xff000000, %esp; \ + jb 1f; \ + \ + /* \ + * switch pagetables and load the real stack, \ + * keep the stack offset: \ + */ \ + \ + movl $swapper_pg_dir-__PAGE_OFFSET, %edx; \ + \ + /* GET_THREAD_INFO(%ebp) intermixed */ \ +0: \ + movl %esp, %ebp; \ + movl %esp, %ebx; \ + andl $0xffffe000, %ebp; \ + andl $0x00001fff, %ebx; \ + orl TI_real_stack(%ebp), %ebx; \ + repeat_if_esp_changed; \ + \ + movl %edx, %cr3; \ + movl %ebx, %esp; \ +1: + +#endif + + +#define __SWITCH_USERSPACE \ + /* interrupted any of the user return paths? */ \ + \ + movl EIP(%esp), %eax; \ + \ + cmpl $int80_ret_start_marker, %eax; \ + jb 33f; /* nope - continue with sysexit check */\ + cmpl $int80_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ +33: \ + cmpl $sysexit_ret_start_marker, %eax; \ + jb 44f; /* nope - continue with user check */ \ + cmpl $sysexit_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ + /* return to userspace? */ \ +44: \ + movl EFLAGS(%esp),%ecx; \ + movb CS(%esp),%cl; \ + testl $(VM_MASK | 3),%ecx; \ + jz 2f; \ +22: \ + /* \ + * switch to the virtual stack, then switch to \ + * the userspace pagetables. \ + */ \ + \ + GET_THREAD_INFO(%ebp); \ + movl TI_virtual_stack(%ebp), %edx; \ + movl TI_user_pgd(%ebp), %ecx; \ + \ + movl %esp, %ebx; \ + andl $0x1fff, %ebx; \ + orl %ebx, %edx; \ +int80_ret_start_marker: \ + movl %edx, %esp; \ + movl %ecx, %cr3; \ + \ + __RESTORE_ALL; \ +int80_ret_end_marker: \ +2: + +#else /* !CONFIG_X86_HIGH_ENTRY */ + +#define __SWITCH_KERNELSPACE +#define __SWITCH_USERSPACE + +#endif + +#define __SAVE_ALL \ cld; \ pushl %es; \ pushl %ds; \ @@ -102,7 +211,7 @@ TSS_ESP0_OFFSET = (4 - 0x200) movl %edx, %ds; \ movl %edx, %es; -#define RESTORE_INT_REGS \ +#define __RESTORE_INT_REGS \ popl %ebx; \ popl %ecx; \ popl %edx; \ @@ -111,29 +220,28 @@ TSS_ESP0_OFFSET = (4 - 0x200) popl %ebp; \ popl %eax -#define RESTORE_REGS \ - RESTORE_INT_REGS; \ -1: popl %ds; \ -2: popl %es; \ +#define __RESTORE_REGS \ + __RESTORE_INT_REGS; \ +111: popl %ds; \ +222: popl %es; \ .section .fixup,"ax"; \ -3: movl $0,(%esp); \ - jmp 1b; \ -4: movl $0,(%esp); \ - jmp 2b; \ +444: movl $0,(%esp); \ + jmp 111b; \ +555: movl $0,(%esp); \ + jmp 222b; \ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,3b; \ - .long 2b,4b; \ + .long 111b,444b;\ + .long 222b,555b;\ .previous - -#define RESTORE_ALL \ - RESTORE_REGS \ +#define __RESTORE_ALL \ + __RESTORE_REGS \ addl $4, %esp; \ -1: iret; \ +333: iret; \ .section .fixup,"ax"; \ -2: sti; \ +666: sti; \ movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ @@ -142,10 +250,19 @@ TSS_ESP0_OFFSET = (4 - 0x200) .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,2b; \ + .long 333b,666b;\ .previous +#define SAVE_ALL \ + __SAVE_ALL; \ + __SWITCH_KERNELSPACE; \ + STACK_OVERFLOW_TEST; + +#define RESTORE_ALL \ + __SWITCH_USERSPACE; \ + __RESTORE_ALL; +.section .entry.text,"ax" ENTRY(lcall7) pushfl # We get a different stack layout with call @@ -163,7 +280,7 @@ do_lcall: movl %edx,EIP(%ebp) # Now we move them to their "normal" places movl %ecx,CS(%ebp) # andl $-8192, %ebp # GET_THREAD_INFO - movl TI_EXEC_DOMAIN(%ebp), %edx # Get the execution domain + movl TI_exec_domain(%ebp), %edx # Get the execution domain call *4(%edx) # Call the lcall7 handler for the domain addl $4, %esp popl %eax @@ -208,7 +325,7 @@ ENTRY(resume_userspace) cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? jne work_pending @@ -216,18 +333,18 @@ ENTRY(resume_userspace) #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) - cmpl $0,TI_PRE_COUNT(%ebp) # non-zero preempt_count ? + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? jnz restore_all need_resched: - movl TI_FLAGS(%ebp), %ecx # need_resched set ? + movl TI_flags(%ebp), %ecx # need_resched set ? testb $_TIF_NEED_RESCHED, %cl jz restore_all testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ? jz restore_all - movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp) + movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp) sti call schedule - movl $0,TI_PRE_COUNT(%ebp) + movl $0,TI_preempt_count(%ebp) cli jmp need_resched #endif @@ -246,37 +363,50 @@ sysenter_past_esp: pushl $(__USER_CS) pushl $SYSENTER_RETURN -/* - * Load the potential sixth argument from user stack. - * Careful about security. - */ - cmpl $__PAGE_OFFSET-3,%ebp - jae syscall_fault -1: movl (%ebp),%ebp -.section __ex_table,"a" - .align 4 - .long 1b,syscall_fault -.previous - pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) cmpl $(nr_syscalls), %eax jae syscall_badsys - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) cli - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + + GET_THREAD_INFO(%ebp) + movl TI_virtual_stack(%ebp), %edx + movl TI_user_pgd(%ebp), %ecx + movl %esp, %ebx + andl $0x1fff, %ebx + orl %ebx, %edx +sysexit_ret_start_marker: + movl %edx, %esp + movl %ecx, %cr3 +#endif + /* + * only ebx is not restored by the userspace sysenter vsyscall + * code, it assumes it to be callee-saved. + */ + movl EBX(%esp), %ebx + /* if something modifies registers it must also disable sysexit */ + movl EIP(%esp), %edx movl OLDESP(%esp), %ecx + sti sysexit +#ifdef CONFIG_X86_SWITCH_PAGETABLES +sysexit_ret_end_marker: + nop +#endif # system call handler stub @@ -287,7 +417,7 @@ ENTRY(system_call) cmpl $(nr_syscalls), %eax jae syscall_badsys # system call tracing in operation - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry syscall_call: call *sys_call_table(,%eax,4) @@ -296,10 +426,23 @@ syscall_exit: cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work restore_all: +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS + movl EFLAGS(%esp), %eax # mix EFLAGS and CS + movb CS(%esp), %al + testl $(VM_MASK | 3), %eax + jz resume_kernelX # returning to kernel or vm86-space + + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jz resume_kernelX + + int $3 + +resume_kernelX: +#endif RESTORE_ALL # perform work that needs to be done immediately before resumption @@ -312,7 +455,7 @@ work_resched: cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done other # than syscall tracing? jz restore_all @@ -327,6 +470,22 @@ work_notifysig: # deal with pending s # vm86-space xorl %edx, %edx call do_notify_resume + +#if CONFIG_X86_HIGH_ENTRY + /* + * Reload db7 if necessary: + */ + movl TI_flags(%ebp), %ecx + testb $_TIF_DB7, %cl + jnz work_db7 + + jmp restore_all + +work_db7: + movl TI_task(%ebp), %edx; + movl task_thread_db7(%edx), %edx; + movl %edx, %db7; +#endif jmp restore_all ALIGN @@ -382,7 +541,7 @@ syscall_badsys: */ .data ENTRY(interrupt) -.text +.previous vector=0 ENTRY(irq_entries_start) @@ -392,7 +551,7 @@ ENTRY(irq_entries_start) jmp common_interrupt .data .long 1b -.text +.previous vector=vector+1 .endr @@ -433,12 +592,17 @@ error_code: movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) - movl %esp, %edx pushl %esi # push the error code - pushl %edx # push the pt_regs pointer movl $(__USER_DS), %edx movl %edx, %ds movl %edx, %es + +/* clobbers edx, ebx and ebp */ + __SWITCH_KERNELSPACE + + leal 4(%esp), %edx # prepare pt_regs + pushl %edx # push pt_regs + call *%edi addl $8, %esp jmp ret_from_exception @@ -529,7 +693,7 @@ nmi_stack_correct: pushl %edx call do_nmi addl $8, %esp - RESTORE_ALL + jmp restore_all nmi_stack_fixup: FIX_STACK(12,nmi_stack_correct, 1) @@ -606,6 +770,8 @@ ENTRY(spurious_interrupt_bug) pushl $do_spurious_interrupt_bug jmp error_code +.previous + .data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/kernel/entry_trampoline.c 2003-12-30 22:50:18.000000000 -0800 @@ -0,0 +1,75 @@ +/* + * linux/arch/i386/kernel/entry_trampoline.c + * + * (C) Copyright 2003 Ingo Molnar + * + * This file contains the needed support code for 4GB userspace + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text; + +void __init init_entry_mappings(void) +{ +#ifdef CONFIG_X86_HIGH_ENTRY + void *tramp; + + /* + * We need a high IDT and GDT for the 4G/4G split: + */ + trap_init_virtual_IDT(); + + __set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL); + __set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL); + tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0); + + printk("mapped 4G/4G trampoline to %p.\n", tramp); + BUG_ON((void *)&__start___entry_text != tramp); + /* + * Virtual kernel stack: + */ + BUG_ON(__kmap_atomic_vaddr(KM_VSTACK0) & 8191); + BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE); + BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE); + + /* + * set up the initial thread's virtual stack related + * fields: + */ + current->thread.stack_page0 = virt_to_page((char *)current->thread_info); + current->thread.stack_page1 = virt_to_page((char *)current->thread_info + PAGE_SIZE); + current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0); + + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(current->thread.stack_page0, KM_VSTACK0); + __kmap_atomic(current->thread.stack_page1, KM_VSTACK1); + +#endif + printk("current: %p\n", current); + printk("current->thread_info: %p\n", current->thread_info); + current->thread_info->real_stack = (void *)current->thread_info; + current->thread_info->user_pgd = NULL; + current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE; +} + + + +void __init entry_trampoline_setup(void) +{ + /* + * old IRQ entries set up by the boot code will still hang + * around - they are a sign of hw trouble anyway, now they'll + * produce a double fault message. + */ + trap_init_virtual_GDT(); +} --- linux-2.6.1-rc1/arch/i386/kernel/head.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/head.S 2003-12-30 22:50:18.000000000 -0800 @@ -16,6 +16,7 @@ #include #include #include +#include #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -330,7 +331,7 @@ ENTRY(stack_start) /* This is the default interrupt "handler" :-) */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt or fault at EIP %p %p %p\n" ALIGN ignore_int: cld @@ -342,9 +343,17 @@ ignore_int: movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es + pushl 16(%esp) + pushl 24(%esp) + pushl 32(%esp) + pushl 40(%esp) pushl $int_msg call printk popl %eax + popl %eax + popl %eax + popl %eax + popl %eax popl %ds popl %es popl %edx @@ -377,23 +386,27 @@ cpu_gdt_descr: .fill NR_CPUS-1,8,0 # space for the other GDT descriptors /* - * This is initialized to create an identity-mapping at 0-8M (for bootup - * purposes) and another mapping of the 0-8M area at virtual address + * This is initialized to create an identity-mapping at 0-16M (for bootup + * purposes) and another mapping of the 0-16M area at virtual address * PAGE_OFFSET. */ .org 0x1000 ENTRY(swapper_pg_dir) .long 0x00102007 .long 0x00103007 - .fill BOOT_USER_PGD_PTRS-2,4,0 - /* default: 766 entries */ + .long 0x00104007 + .long 0x00105007 + .fill BOOT_USER_PGD_PTRS-4,4,0 + /* default: 764 entries */ .long 0x00102007 .long 0x00103007 - /* default: 254 entries */ - .fill BOOT_KERNEL_PGD_PTRS-2,4,0 + .long 0x00104007 + .long 0x00105007 + /* default: 252 entries */ + .fill BOOT_KERNEL_PGD_PTRS-4,4,0 /* - * The page tables are initialized to only 8MB here - the final page + * The page tables are initialized to only 16MB here - the final page * tables are set up later depending on memory size. */ .org 0x2000 @@ -402,15 +415,21 @@ ENTRY(pg0) .org 0x3000 ENTRY(pg1) +.org 0x4000 +ENTRY(pg2) + +.org 0x5000 +ENTRY(pg3) + /* * empty_zero_page must immediately follow the page tables ! (The * initialization loop counts until empty_zero_page) */ -.org 0x4000 +.org 0x6000 ENTRY(empty_zero_page) -.org 0x5000 +.org 0x7000 /* * Real beginning of normal "text" segment @@ -419,12 +438,12 @@ ENTRY(stext) ENTRY(_stext) /* - * This starts the data section. Note that the above is all - * in the text section because it has alignment requirements - * that we cannot fulfill any other way. + * This starts the data section. */ .data +.align PAGE_SIZE_asm + /* * The Global Descriptor Table contains 28 quadwords, per-CPU. */ @@ -439,7 +458,9 @@ ENTRY(boot_gdt_table) .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ #endif - .align L1_CACHE_BYTES + +.align PAGE_SIZE_asm + ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ --- linux-2.6.1-rc1/arch/i386/kernel/i386_ksyms.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/i386_ksyms.c 2003-12-30 22:50:18.000000000 -0800 @@ -98,7 +98,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed_inter EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__udelay); @@ -112,13 +111,17 @@ EXPORT_SYMBOL_NOVERS(__get_user_4); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +#if !defined(CONFIG_X86_UACCESS_INDIRECT) EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__direct_strncpy_from_user); EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__copy_from_user_ll); EXPORT_SYMBOL(__copy_to_user_ll); EXPORT_SYMBOL(strnlen_user); +#else /* CONFIG_X86_UACCESS_INDIRECT */ +EXPORT_SYMBOL(direct_csum_partial_copy_generic); +#endif EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_free_coherent); --- linux-2.6.1-rc1/arch/i386/kernel/i387.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/i387.c 2003-12-30 22:50:18.000000000 -0800 @@ -218,6 +218,7 @@ void set_fpu_mxcsr( struct task_struct * static int convert_fxsr_to_user( struct _fpstate __user *buf, struct i387_fxsave_struct *fxsave ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpreg __user *to; struct _fpxreg *from; @@ -234,23 +235,25 @@ static int convert_fxsr_to_user( struct if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; - to = &buf->_st[0]; + to = tmp; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f+1); + to->exponent = from->exponent; } + if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8]))) + return 1; return 0; } static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpxreg *to; struct _fpreg __user *from; @@ -258,6 +261,8 @@ static int convert_fxsr_from_user( struc if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; + if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8]))) + return 1; fxsave->cwd = (unsigned short)(env[0] & 0xffff); fxsave->swd = (unsigned short)(env[1] & 0xffff); @@ -269,15 +274,14 @@ static int convert_fxsr_from_user( struc fxsave->fos = env[6]; to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; + from = tmp; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f + 1); + to->exponent = from->exponent; } return 0; } --- linux-2.6.1-rc1/arch/i386/kernel/init_task.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/init_task.c 2003-12-30 22:50:18.000000000 -0800 @@ -26,7 +26,7 @@ EXPORT_SYMBOL(init_mm); */ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; + { INIT_THREAD_INFO(init_task, init_thread_union) }; /* * Initial task structure. @@ -44,5 +44,5 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS }; --- linux-2.6.1-rc1/arch/i386/kernel/io_apic.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/io_apic.c 2003-12-30 22:49:41.000000000 -0800 @@ -1650,10 +1650,6 @@ static void __init setup_ioapic_ids_from unsigned char old_id; unsigned long flags; - if (acpi_ioapic) - /* This gets done during IOAPIC enumeration for ACPI. */ - return; - /* * This is broken; anything with a real cpu count has to * circumvent this idiocy regardless. @@ -2286,12 +2282,14 @@ void __init setup_IO_APIC(void) /* * Set up IO-APIC IRQ routing. */ - setup_ioapic_ids_from_mpc(); + if (!acpi_ioapic) + setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); - print_IO_APIC(); + if (!acpi_ioapic) + print_IO_APIC(); } /* --- linux-2.6.1-rc1/arch/i386/kernel/irq.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/irq.c 2003-12-30 22:49:27.000000000 -0800 @@ -508,6 +508,8 @@ out: irq_exit(); + kgdb_process_breakpoint(); + return 1; } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/kernel/kgdb_stub.c 2003-12-30 22:49:27.000000000 -0800 @@ -0,0 +1,2457 @@ +/* + * + * 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, or (at your option) any + * 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. + * + */ + +/* + * Copyright (c) 2000 VERITAS Software Corporation. + * + */ +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * Updated by: David Grothe + * Updated by: Robert Walsh + * Updated by: wangdi + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Compatibility with 2.1.xx kernel by David Grothe + * + * Changes to allow auto initilization. All that is needed is that it + * be linked with the kernel and a break point (int 3) be executed. + * The header file defines BREAKPOINT to allow one to do + * this. It should also be possible, once the interrupt system is up, to + * call putDebugChar("+"). Once this is done, the remote debugger should + * get our attention by sending a ^C in a packet. George Anzinger + * + * Integrated into 2.2.5 kernel by Tigran Aivazian + * Added thread support, support for multiple processors, + * support for ia-32(x86) hardware debugging. + * Amit S. Kale ( akale@veritas.com ) + * + * Modified to support debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing an int 3. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ +#define KGDB_VERSION "<20030915.1651.33>" +#include +#include +#include /* for strcpy */ +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*Function) (void); /* pointer to a function */ + +/* Thread reference */ +typedef unsigned char threadref[8]; + +extern int tty_putDebugChar(int); /* write a single character */ +extern int tty_getDebugChar(void); /* read and return a single char */ +extern void tty_flushDebugChar(void); /* flush pending characters */ +extern int eth_putDebugChar(int); /* write a single character */ +extern int eth_getDebugChar(void); /* read and return a single char */ +extern void eth_flushDebugChar(void); /* flush pending characters */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 400 + +char *kgdb_version = KGDB_VERSION; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int debug_regs = 0; /* set to non-zero to print registers */ + +/* filled in by an external module */ +char *gdb_module_offsets; + +static const char hexchars[] = "0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES 64 +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + */ +enum regnames { _EAX, /* 0 */ + _ECX, /* 1 */ + _EDX, /* 2 */ + _EBX, /* 3 */ + _ESP, /* 4 */ + _EBP, /* 5 */ + _ESI, /* 6 */ + _EDI, /* 7 */ + _PC /* 8 also known as eip */ , + _PS /* 9 also known as eflags */ , + _CS, /* 10 */ + _SS, /* 11 */ + _DS, /* 12 */ + _ES, /* 13 */ + _FS, /* 14 */ + _GS /* 15 */ +}; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* + * Put the error code here just in case the user cares. + * Likewise, the vector number here (since GDB only gets the signal + * number through the usual means, and that's not very specific). + * The called_from is the return address so he can tell how we entered kgdb. + * This will allow him to seperate out the various possible entries. + */ +#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ + +#define PID_MAX PID_MAX_DEFAULT + +#ifdef CONFIG_SMP +void smp_send_nmi_allbutself(void); +#define IF_SMP(x) x +#undef MAX_NO_CPUS +#ifndef CONFIG_NO_KGDB_CPUS +#define CONFIG_NO_KGDB_CPUS 2 +#endif +#if CONFIG_NO_KGDB_CPUS > NR_CPUS +#define MAX_NO_CPUS NR_CPUS +#else +#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS +#endif +#define hold_init hold_on_sstep: 1, +#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) +#define NUM_CPUS num_online_cpus() +#else +#define IF_SMP(x) +#define hold_init +#undef MAX_NO_CPUS +#define MAX_NO_CPUS 1 +#define NUM_CPUS 1 +#endif +#define NOCPU (struct task_struct *)0xbad1fbad +/* *INDENT-OFF* */ +struct kgdb_info { + int used_malloc; + void *called_from; + long long entry_tsc; + int errcode; + int vector; + int print_debug_info; +#ifdef CONFIG_SMP + int hold_on_sstep; + struct { + volatile struct task_struct *task; + int pid; + int hold; + struct pt_regs *regs; + } cpus_waiting[MAX_NO_CPUS]; +#endif +} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1}; + +/* *INDENT-ON* */ + +#define used_m kgdb_info.used_malloc +/* + * This is little area we set aside to contain the stack we + * need to build to allow gdb to call functions. We use one + * per cpu to avoid locking issues. We will do all this work + * with interrupts off so that should take care of the protection + * issues. + */ +#define LOOKASIDE_SIZE 200 /* should be more than enough */ +#define MALLOC_MAX 200 /* Max malloc size */ +struct { + unsigned int esp; + int array[LOOKASIDE_SIZE]; +} fn_call_lookaside[MAX_NO_CPUS]; + +static int trap_cpu; +static unsigned int OLD_esp; + +#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE] +#define IF_BIT 0x200 +#define TF_BIT 0x100 + +#define MALLOC_ROUND 8-1 + +static char malloc_array[MALLOC_MAX]; +IF_SMP(static void to_gdb(const char *mess)); +void * +malloc(int size) +{ + + if (size <= (MALLOC_MAX - used_m)) { + int old_used = used_m; + used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); + return &malloc_array[old_used]; + } else { + return NULL; + } +} + +/* + * I/O dispatch functions... + * Based upon kgdboe, either call the ethernet + * handler or the serial one.. + */ +void +putDebugChar(int c) +{ + if (!kgdboe) { + tty_putDebugChar(c); + } else { + eth_putDebugChar(c); + } +} + +int +getDebugChar(void) +{ + if (!kgdboe) { + return tty_getDebugChar(); + } else { + return eth_getDebugChar(); + } +} + +void +flushDebugChar(void) +{ + if (!kgdboe) { + tty_flushDebugChar(); + } else { + eth_flushDebugChar(); + } +} + +/* + * Gdb calls functions by pushing agruments, including a return address + * on the stack and the adjusting EIP to point to the function. The + * whole assumption in GDB is that we are on a different stack than the + * one the "user" i.e. code that hit the break point, is on. This, of + * course is not true in the kernel. Thus various dodges are needed to + * do the call without directly messing with EIP (which we can not change + * as it is just a location and not a register. To adjust it would then + * require that we move every thing below EIP up or down as needed. This + * will not work as we may well have stack relative pointer on the stack + * (such as the pointer to regs, for example). + + * So here is what we do: + * We detect gdb attempting to store into the stack area and instead, store + * into the fn_call_lookaside.array at the same relative location as if it + * were the area ESP pointed at. We also trap ESP modifications + * and uses these to adjust fn_call_lookaside.esp. On entry + * fn_call_lookaside.esp will be set to point at the last entry in + * fn_call_lookaside.array. This allows us to check if it has changed, and + * if so, on exit, we add the registers we will use to do the move and a + * trap/ interrupt return exit sequence. We then adjust the eflags in the + * regs array (remember we now have a copy in the fn_call_lookaside.array) to + * kill the interrupt bit, AND we change EIP to point at our set up stub. + * As part of the register set up we preset the registers to point at the + * begining and end of the fn_call_lookaside.array, so all the stub needs to + * do is move words from the array to the stack until ESP= the desired value + * then do the rti. This will then transfer to the desired function with + * all the correct registers. Nifty huh? + */ +extern asmlinkage void fn_call_stub(void); +extern asmlinkage void fn_rtn_stub(void); +/* *INDENT-OFF* */ +__asm__("fn_rtn_stub:\n\t" + "movl %eax,%esp\n\t" + "fn_call_stub:\n\t" + "1:\n\t" + "addl $-4,%ebx\n\t" + "movl (%ebx), %eax\n\t" + "pushl %eax\n\t" + "cmpl %esp,%ecx\n\t" + "jne 1b\n\t" + "popl %eax\n\t" + "popl %ebx\n\t" + "popl %ecx\n\t" + "iret \n\t"); +/* *INDENT-ON* */ +#define gdb_i386vector kgdb_info.vector +#define gdb_i386errcode kgdb_info.errcode +#define waiting_cpus kgdb_info.cpus_waiting +#define remote_debug kgdb_info.print_debug_info +#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold +/* gdb locks */ + +#ifdef CONFIG_SMP +static int in_kgdb_called; +static spinlock_t waitlocks[MAX_NO_CPUS] = + {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; +/* + * The following array has the thread pointer of each of the "other" + * cpus. We make it global so it can be seen by gdb. + */ +volatile int in_kgdb_entry_log[MAX_NO_CPUS]; +volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; +/* +static spinlock_t continuelocks[MAX_NO_CPUS]; +*/ +spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; +/* waiters on our spinlock plus us */ +static atomic_t spinlock_waiters = ATOMIC_INIT(1); +static int spinlock_count = 0; +static int spinlock_cpu = 0; +/* + * Note we use nested spin locks to account for the case where a break + * point is encountered when calling a function by user direction from + * kgdb. Also there is the memory exception recursion to account for. + * Well, yes, but this lets other cpus thru too. Lets add a + * cpu id to the lock. + */ +#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ + spinlock_cpu != smp_processor_id()){\ + atomic_inc(&spinlock_waiters); \ + while (! spin_trylock(x)) {\ + in_kgdb(®s);\ + }\ + atomic_dec(&spinlock_waiters); \ + spinlock_count = 1; \ + spinlock_cpu = smp_processor_id(); \ + }else{ \ + spinlock_count++; \ + } +#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) +#else +unsigned kgdb_spinlock = 0; +#define KGDB_SPIN_LOCK(x) --*x +#define KGDB_SPIN_UNLOCK(x) ++*x +#endif + +int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug) && (checksum != xmitcsum)) { + printk + ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + + if (remote_debug) + printk("R:%s\n", buffer); + flushDebugChar(); +} + +/* send the packet in buffer. */ + +void +putpacket(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + + if (!kgdboe) { + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + + } while ((getDebugChar() & 0x7f) != '+'); + } else { + /* + * For udp, we can not transfer too much bytes once. + * We only transfer MAX_SEND_COUNT size bytes each time + */ + +#define MAX_SEND_COUNT 30 + + int send_count = 0, i = 0; + char send_buf[MAX_SEND_COUNT]; + + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + send_count = 0; + while ((ch = buffer[count])) { + if (send_count >= MAX_SEND_COUNT) { + for(i = 0; i < MAX_SEND_COUNT; i++) { + putDebugChar(send_buf[i]); + } + flushDebugChar(); + send_count = 0; + } else { + send_buf[send_count] = ch; + checksum += ch; + count ++; + send_count++; + } + } + for(i = 0; i < send_count; i++) + putDebugChar(send_buf[i]); + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + } while ((getDebugChar() & 0x7f) != '+'); + } +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static short error; + +void +debug_error(char *format, char *parm) +{ + if (remote_debug) + printk(format, parm); +} + +static void +print_regs(struct pt_regs *regs) +{ + printk("EAX=%08lx ", regs->eax); + printk("EBX=%08lx ", regs->ebx); + printk("ECX=%08lx ", regs->ecx); + printk("EDX=%08lx ", regs->edx); + printk("\n"); + printk("ESI=%08lx ", regs->esi); + printk("EDI=%08lx ", regs->edi); + printk("EBP=%08lx ", regs->ebp); + printk("ESP=%08lx ", (long) ®s->esp); + printk("\n"); + printk(" DS=%08x ", regs->xds); + printk(" ES=%08x ", regs->xes); + printk(" SS=%08x ", __KERNEL_DS); + printk(" FL=%08lx ", regs->eflags); + printk("\n"); + printk(" CS=%08x ", regs->xcs); + printk(" IP=%08lx ", regs->eip); +#if 0 + printk(" FS=%08x ", regs->fs); + printk(" GS=%08x ", regs->gs); +#endif + printk("\n"); + +} /* print_regs */ + +#define NEW_esp fn_call_lookaside[trap_cpu].esp + +static void +regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_EAX] = regs->eax; + gdb_regs[_EBX] = regs->ebx; + gdb_regs[_ECX] = regs->ecx; + gdb_regs[_EDX] = regs->edx; + gdb_regs[_ESI] = regs->esi; + gdb_regs[_EDI] = regs->edi; + gdb_regs[_EBP] = regs->ebp; + gdb_regs[_DS] = regs->xds; + gdb_regs[_ES] = regs->xes; + gdb_regs[_PS] = regs->eflags; + gdb_regs[_CS] = regs->xcs; + gdb_regs[_PC] = regs->eip; + /* Note, as we are a debugging the kernel, we will always + * trap in kernel code, this means no priviledge change, + * and so the pt_regs structure is not completely valid. In a non + * privilege change trap, only EFLAGS, CS and EIP are put on the stack, + * SS and ESP are not stacked, this means that the last 2 elements of + * pt_regs is not valid (they would normally refer to the user stack) + * also, using regs+1 is no good because you end up will a value that is + * 2 longs (8) too high. This used to cause stepping over functions + * to fail, so my fix is to use the address of regs->esp, which + * should point at the end of the stack frame. Note I have ignored + * completely exceptions that cause an error code to be stacked, such + * as double fault. Stuart Hughes, Zentropix. + * original code: gdb_regs[_ESP] = (int) (regs + 1) ; + + * this is now done on entry and moved to OLD_esp (as well as NEW_esp). + */ + gdb_regs[_ESP] = NEW_esp; + gdb_regs[_SS] = __KERNEL_DS; + gdb_regs[_FS] = 0xFFFF; + gdb_regs[_GS] = 0xFFFF; +} /* regs_to_gdb_regs */ + +static void +gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs) +{ + regs->eax = gdb_regs[_EAX]; + regs->ebx = gdb_regs[_EBX]; + regs->ecx = gdb_regs[_ECX]; + regs->edx = gdb_regs[_EDX]; + regs->esi = gdb_regs[_ESI]; + regs->edi = gdb_regs[_EDI]; + regs->ebp = gdb_regs[_EBP]; + regs->xds = gdb_regs[_DS]; + regs->xes = gdb_regs[_ES]; + regs->eflags = gdb_regs[_PS]; + regs->xcs = gdb_regs[_CS]; + regs->eip = gdb_regs[_PC]; + NEW_esp = gdb_regs[_ESP]; /* keep the value */ +#if 0 /* can't change these */ + regs->esp = gdb_regs[_ESP]; + regs->xss = gdb_regs[_SS]; + regs->fs = gdb_regs[_FS]; + regs->gs = gdb_regs[_GS]; +#endif + +} /* gdb_regs_to_regs */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +int thread_list = 0; + +void +get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs) +{ + unsigned long stack_page; + int count = 0; + IF_SMP(int i); + if (!p || p == current) { + regs_to_gdb_regs(gdb_regs, regs); + return; + } +#ifdef CONFIG_SMP + for (i = 0; i < MAX_NO_CPUS; i++) { + if (p == kgdb_info.cpus_waiting[i].task) { + regs_to_gdb_regs(gdb_regs, + kgdb_info.cpus_waiting[i].regs); + gdb_regs[_ESP] = + (int) &kgdb_info.cpus_waiting[i].regs->esp; + + return; + } + } +#endif + memset(gdb_regs, 0, NUMREGBYTES); + gdb_regs[_ESP] = p->thread.esp; + gdb_regs[_PC] = p->thread.eip; + gdb_regs[_EBP] = *(int *) gdb_regs[_ESP]; + gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4); + gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8); + +/* + * This code is to give a more informative notion of where a process + * is waiting. It is used only when the user asks for a thread info + * list. If he then switches to the thread, s/he will find the task + * is in schedule, but a back trace should show the same info we come + * up with. This code was shamelessly purloined from process.c. It was + * then enhanced to provide more registers than simply the program + * counter. + */ + + if (!thread_list) { + return; + } + + if (p->state == TASK_RUNNING) + return; + stack_page = (unsigned long) p->thread_info; + if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > 8188 + stack_page) + return; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + do { + if (gdb_regs[_EBP] < stack_page || + gdb_regs[_EBP] > 8184 + stack_page) + return; + gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4); + gdb_regs[_ESP] = gdb_regs[_EBP] + 8; + gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP]; + if (gdb_regs[_PC] < first_sched || gdb_regs[_PC] >= last_sched) + return; + } while (count++ < 16); + return; +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; +static volatile int mem_err_expected = 0; +static volatile int mem_err_cnt = 0; +static int garbage_loc = -1; + +int +get_char(char *addr) +{ + return *addr; +} + +void +set_char(char *addr, int val, int may_fault) +{ + /* + * This code traps references to the area mapped to the kernel + * stack as given by the regs and, instead, stores to the + * fn_call_lookaside[cpu].array + */ + if (may_fault && + (unsigned int) addr < OLD_esp && + ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) { + addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr); + } + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex(char *mem, char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + /* printk("%lx = ", mem) ; */ + + ch = get_char(mem++); + + /* printk("%02x\n", ch & 0xFF) ; */ + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault fetching from addr %lx\n", + (long) (mem - 1)); + *buf = 0; /* truncate buffer */ + return (buf); + } + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_err_expected = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +/* NOTE: We use the may fault flag to also indicate if the write is to + * the registers (0) or "other" memory (!=0) + */ +char * +hex2mem(char *buf, char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + set_char(mem++, ch, may_fault); + + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault storing to addr %lx\n", + (long) (mem - 1)); + return (mem); + } + } + if (may_fault) + mem_err_expected = 0; + return (mem); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define stubhex(h) hex(h) +#ifdef old_thread_list + +static int +stub_unpack_int(char *buff, int fieldlength) +{ + int nibble; + int retval = 0; + + while (fieldlength) { + nibble = stubhex(*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} +#endif +static char * +pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +#define BUF_THREAD_ID_SIZE 16 + +static char * +pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + return pkt; +} + +#ifdef old_thread_list +static char * +unpack_byte(char *buf, int *value) +{ + *value = stub_unpack_int(buf, 2); + return buf + 2; +} + +static char * +unpack_threadid(char *inbuf, threadref * id) +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + + altref = (char *) id; + + while (inbuf < limit) { + x = stubhex(*inbuf++); + y = stubhex(*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} +#endif +void +int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} +int +int_to_hex_v(unsigned char * id, int value) +{ + unsigned char *start = id; + int shift; + int ch; + + for (shift = 28; shift >= 0; shift -= 4) { + if ((ch = (value >> shift) & 0xf) || (id != start)) { + *id = hexchars[ch]; + id++; + } + } + if (id == start) + *id++ = '0'; + return id - start; +} +#ifdef old_thread_list + +static int +threadref_to_int(threadref * ref) +{ + int i, value = 0; + unsigned char *scan; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} +#endif +static int +cmp_str(char *s1, char *s2, int count) +{ + while (count--) { + if (*s1++ != *s2++) + return 0; + } + return 1; +} + +#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ +extern struct task_struct *kgdb_get_idle(int cpu); +#define idle_task(cpu) kgdb_get_idle(cpu) +#else +#define idle_task(cpu) init_tasks[cpu] +#endif + +extern int kgdb_pid_init_done; + +struct task_struct * +getthread(int pid) +{ + struct task_struct *thread; + if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { + + return idle_task(pid - PID_MAX); + } else { + /* + * find_task_by_pid is relatively safe all the time + * Other pid functions require lock downs which imply + * that we may be interrupting them (as we get here + * in the middle of most any lock down). + * Still we don't want to call until the table exists! + */ + if (kgdb_pid_init_done){ + thread = find_task_by_pid(pid); + if (thread) { + return thread; + } + } + } + return NULL; +} +/* *INDENT-OFF* */ +struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned addr; +} breakinfo[4] = { {enabled:0}, + {enabled:0}, + {enabled:0}, + {enabled:0}}; +/* *INDENT-ON* */ +unsigned hw_breakpoint_status; +void +correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned dr7; + + asm volatile ("movl %%db7, %0\n":"=r" (dr7) + :); + /* *INDENT-OFF* */ + do { + unsigned addr0, addr1, addr2, addr3; + asm volatile ("movl %%db0, %0\n" + "movl %%db1, %1\n" + "movl %%db2, %2\n" + "movl %%db3, %3\n" + :"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3) + :); + } while (0); + /* *INDENT-ON* */ + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movl %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movl %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movl %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movl %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) { + asm volatile ("movl %0, %%db7\n"::"r" (dr7)); + } +} + +int +remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 0; + return 0; +} + +int +set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].len = len; + breakinfo[breakno].addr = addr; + return 0; +} + +#ifdef CONFIG_SMP +static int in_kgdb_console = 0; + +int +in_kgdb(struct pt_regs *regs) +{ + unsigned flags; + int cpu = smp_processor_id(); + in_kgdb_called = 1; + if (!spin_is_locked(&kgdb_spinlock)) { + if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ + in_kgdb_console) { /* or we are doing slow i/o */ + return 1; + } + return 0; + } + + /* As I see it the only reason not to let all cpus spin on + * the same spin_lock is to allow selected ones to proceed. + * This would be a good thing, so we leave it this way. + * Maybe someday.... Done ! + + * in_kgdb() is called from an NMI so we don't pretend + * to have any resources, like printk() for example. + */ + + kgdb_local_irq_save(flags); /* only local here, to avoid hanging */ + /* + * log arival of this cpu + * The NMI keeps on ticking. Protect against recurring more + * than once, and ignor the cpu that has the kgdb lock + */ + in_kgdb_entry_log[cpu]++; + in_kgdb_here_log[cpu] = regs; + if (cpu == spinlock_cpu || waiting_cpus[cpu].task) + goto exit_in_kgdb; + + /* + * For protection of the initilization of the spin locks by kgdb + * it locks the kgdb spinlock before it gets the wait locks set + * up. We wait here for the wait lock to be taken. If the + * kgdb lock goes away first?? Well, it could be a slow exit + * sequence where the wait lock is removed prior to the kgdb lock + * so if kgdb gets unlocked, we just exit. + */ + + while (spin_is_locked(&kgdb_spinlock) && + !spin_is_locked(waitlocks + cpu)) ; + if (!spin_is_locked(&kgdb_spinlock)) + goto exit_in_kgdb; + + waiting_cpus[cpu].task = current; + waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); + waiting_cpus[cpu].regs = regs; + + spin_unlock_wait(waitlocks + cpu); + + /* + * log departure of this cpu + */ + waiting_cpus[cpu].task = 0; + waiting_cpus[cpu].pid = 0; + waiting_cpus[cpu].regs = 0; + correct_hw_break(); + exit_in_kgdb: + in_kgdb_here_log[cpu] = 0; + kgdb_local_irq_restore(flags); + return 1; + /* + spin_unlock(continuelocks + smp_processor_id()); + */ +} + +void +smp__in_kgdb(struct pt_regs regs) +{ + ack_APIC_irq(); + in_kgdb(®s); +} +#else +int +in_kgdb(struct pt_regs *regs) +{ + return (kgdb_spinlock); +} +#endif + +void +printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ + unsigned dr6; + int i; + switch (exceptionNo) { + case 1: /* debug exception */ + break; + case 3: /* breakpoint */ + sprintf(buffer, "Software breakpoint"); + return; + default: + sprintf(buffer, "Details not available"); + return; + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (dr6 & 0x4000) { + sprintf(buffer, "Single step"); + return; + } + for (i = 0; i < 4; ++i) { + if (dr6 & (1 << i)) { + sprintf(buffer, "Hardware breakpoint %d", i); + return; + } + } + sprintf(buffer, "Unknown trap"); + return; +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * NOTE: The INT nn instruction leaves the state of the interrupt + * enable flag UNCHANGED. That means that when this routine + * is entered via a breakpoint (INT 3) instruction from code + * that has interrupts enabled, then interrupts will STILL BE + * enabled when this routine is entered. The first thing that + * we do here is disable interrupts so as to prevent recursive + * entries and bothersome serial interrupts while we are + * trying to run the serial port in polled mode. + * + * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so + * it is always necessary to do a restore_flags before returning + * so as to let go of that lock. + */ +int +kgdb_handle_exception(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs) +{ + struct task_struct *usethread = NULL; + struct task_struct *thread_list_start = 0, *thread = NULL; + int addr, length; + int breakno, breaktype; + char *ptr; + int newPC; + threadref thref; + int threadid; + int thread_min = PID_MAX + MAX_NO_CPUS; +#ifdef old_thread_list + int maxthreads; +#endif + int nothreads; + unsigned long flags; + int gdb_regs[NUMREGBYTES / 4]; + int dr6; + IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ +#define NO_NMI 1 +#define NO_SYNC 2 +#define regs (*linux_regs) +#define NUMREGS NUMREGBYTES/4 + /* + * If the entry is not from the kernel then return to the Linux + * trap handler and let it process the interrupt normally. + */ + if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) { + printk("ignoring non-kernel exception\n"); + print_regs(®s); + return (0); + } + /* + * If we're using eth mode, set the 'mode' in the netdevice. + */ + + if (kgdboe) + netpoll_set_trap(1); + + kgdb_local_irq_save(flags); + + /* Get kgdb spinlock */ + + KGDB_SPIN_LOCK(&kgdb_spinlock); + rdtscll(kgdb_info.entry_tsc); + /* + * We depend on this spinlock and the NMI watch dog to control the + * other cpus. They will arrive at "in_kgdb()" as a result of the + * NMI and will wait there for the following spin locks to be + * released. + */ +#ifdef CONFIG_SMP + +#if 0 + if (cpu_callout_map & ~MAX_CPU_MASK) { + printk("kgdb : too many cpus, possibly not mapped" + " in contiguous space, change MAX_NO_CPUS" + " in kgdb_stub and make new kernel.\n" + " cpu_callout_map is %lx\n", cpu_callout_map); + goto exit_just_unlock; + } +#endif + if (spinlock_count == 1) { + int time, end_time, dum; + int i; + int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) + }; + if (remote_debug) { + printk("kgdb : cpu %d entry, syncing others\n", + smp_processor_id()); + } + for (i = 0; i < MAX_NO_CPUS; i++) { + /* + * Use trylock as we may already hold the lock if + * we are holding the cpu. Net result is all + * locked. + */ + spin_trylock(&waitlocks[i]); + } + for (i = 0; i < MAX_NO_CPUS; i++) + cpu_logged_in[i] = 0; + /* + * Wait for their arrival. We know the watch dog is active if + * in_kgdb() has ever been called, as it is always called on a + * watchdog tick. + */ + rdtsc(dum, time); + end_time = time + 2; /* Note: we use the High order bits! */ + i = 1; + if (num_online_cpus() > 1) { + int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; + smp_send_nmi_allbutself(); + + while (i < num_online_cpus() && time != end_time) { + int j; + for (j = 0; j < MAX_NO_CPUS; j++) { + if (waiting_cpus[j].task && + waiting_cpus[j].task != NOCPU && + !cpu_logged_in[j]) { + i++; + cpu_logged_in[j] = 1; + if (remote_debug) { + printk + ("kgdb : cpu %d arrived at kgdb\n", + j); + } + break; + } else if (!waiting_cpus[j].task && + !cpu_online(j)) { + waiting_cpus[j].task = NOCPU; + cpu_logged_in[j] = 1; + waiting_cpus[j].hold = 1; + break; + } + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + + int wait = 100000; + while (wait--) ; + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + printk + ("kgdb : cpu %d stall" + " in in_kgdb\n", + j); + i++; + cpu_logged_in[j] = 1; + waiting_cpus[j].task = + (struct task_struct + *) 1; + } + } + } + + if (in_kgdb_entry_log[smp_processor_id()] > + (me_in_kgdb + 10)) { + break; + } + + rdtsc(dum, time); + } + if (i < num_online_cpus()) { + printk + ("kgdb : time out, proceeding without sync\n"); +#if 0 + printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", + waiting_cpus[0].task != 0, + waiting_cpus[1].task != 0); + printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", + cpu_logged_in[0], cpu_logged_in[1]); + printk + ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", + in_kgdb_here_log[0] != 0, + in_kgdb_here_log[1] != 0); +#endif + entry_state = NO_SYNC; + } else { +#if 0 + int ent = + in_kgdb_entry_log[smp_processor_id()] - + me_in_kgdb; + printk("kgdb : sync after %d entries\n", ent); +#endif + } + } else { + if (remote_debug) { + printk + ("kgdb : %d cpus, but watchdog not active\n" + "proceeding without locking down other cpus\n", + num_online_cpus()); + entry_state = NO_NMI; + } + } + } +#endif + + if (remote_debug) { + unsigned long *lp = (unsigned long *) &linux_regs; + + printk("handle_exception(exceptionVector=%d, " + "signo=%d, err_code=%d, linux_regs=%p)\n", + exceptionVector, signo, err_code, linux_regs); + if (debug_regs) { + print_regs(®s); + printk("Stk: %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[0], lp[1], lp[2], lp[3], + lp[4], lp[5], lp[6], lp[7]); + printk(" %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[8], lp[9], lp[10], lp[11], + lp[12], lp[13], lp[14], lp[15]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[16], lp[17], lp[18], lp[19], + lp[20], lp[21], lp[22], lp[23]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[24], lp[25], lp[26], lp[27], + lp[28], lp[29], lp[30], lp[31]); + } + } + + /* Disable hardware debugging while we are in kgdb */ + /* Get the debug register status register */ +/* *INDENT-OFF* */ + __asm__("movl %0,%%db7" + : /* no output */ + :"r"(0)); + + asm volatile ("movl %%db6, %0\n" + :"=r" (hw_breakpoint_status) + :); + +/* *INDENT-ON* */ + switch (exceptionVector) { + case 0: /* divide error */ + case 1: /* debug exception */ + case 2: /* NMI */ + case 3: /* breakpoint */ + case 4: /* overflow */ + case 5: /* bounds check */ + case 6: /* invalid opcode */ + case 7: /* device not available */ + case 8: /* double fault (errcode) */ + case 10: /* invalid TSS (errcode) */ + case 12: /* stack fault (errcode) */ + case 16: /* floating point error */ + case 17: /* alignment check (errcode) */ + default: /* any undocumented */ + break; + case 11: /* segment not present (errcode) */ + case 13: /* general protection (errcode) */ + case 14: /* page fault (special errcode) */ + case 19: /* cache flush denied */ + if (mem_err_expected) { + /* + * This fault occured because of the + * get_char or set_char routines. These + * two routines use either eax of edx to + * indirectly reference the location in + * memory that they are working with. + * For a page fault, when we return the + * instruction will be retried, so we + * have to make sure that these + * registers point to valid memory. + */ + mem_err = 1; /* set mem error flag */ + mem_err_expected = 0; + mem_err_cnt++; /* helps in debugging */ + /* make valid address */ + regs.eax = (long) &garbage_loc; + /* make valid address */ + regs.edx = (long) &garbage_loc; + if (remote_debug) + printk("Return after memory error: " + "mem_err_cnt=%d\n", mem_err_cnt); + if (debug_regs) + print_regs(®s); + goto exit_kgdb; + } + break; + } + if (remote_debug) + printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); + + gdb_i386vector = exceptionVector; + gdb_i386errcode = err_code; + kgdb_info.called_from = __builtin_return_address(0); +#ifdef CONFIG_SMP + /* + * OK, we can now communicate, lets tell gdb about the sync. + * but only if we had a problem. + */ + switch (entry_state) { + case NO_NMI: + to_gdb("NMI not active, other cpus not stopped\n"); + break; + case NO_SYNC: + to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); + default:; + } + +#endif +/* + * Set up the gdb function call area. + */ + trap_cpu = smp_processor_id(); + OLD_esp = NEW_esp = (int) (&linux_regs->esp); + + IF_SMP(once_again:) + /* reply to host that an exception has occurred */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1 == 1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + printk("Remote debug %s\n", + remote_debug ? "on" : "off"); + break; + case 'g': /* return the value of the CPU registers */ + get_gdb_regs(usethread, ®s, gdb_regs); + mem2hex((char *) gdb_regs, + remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], + (char *) gdb_regs, NUMREGBYTES, 0); + if (!usethread || usethread == current) { + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E00"); + } + break; + + case 'P':{ /* set the value of a single CPU register - + return OK */ + /* + * For some reason, gdb wants to talk about psudo + * registers (greater than 15). These may have + * meaning for ptrace, but for us it is safe to + * ignor them. We do this by dumping them into + * _GS which we also ignor, but do have memory for. + */ + int regno; + + ptr = &remcomInBuffer[1]; + regs_to_gdb_regs(gdb_regs, ®s); + if ((!usethread || usethread == current) && + hexToInt(&ptr, ®no) && + *ptr++ == '=' && (regno >= 0)) { + regno = + (regno >= NUMREGS ? _GS : regno); + hex2mem(ptr, (char *) &gdb_regs[regno], + 4, 0); + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + break; + } + strcpy(remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && (hexToInt(&ptr, &length))) { + ptr = 0; + /* + * hex doubles the byte count + */ + if (length > (BUFMAX / 2)) + length = BUFMAX / 2; + mem2hex((char *) addr, + remcomOutBuffer, length, 1); + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } + } + + if (ptr) { + strcpy(remcomOutBuffer, "E01"); + debug_error + ("malformed read memory command: %s\n", + remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: + Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && + (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) { + hex2mem(ptr, (char *) addr, length, 1); + + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } else { + strcpy(remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) { + strcpy(remcomOutBuffer, "E02"); + debug_error + ("malformed write memory command: %s\n", + remcomInBuffer); + } + break; + case 'S': + remcomInBuffer[0] = 's'; + case 'C': + /* Csig;AA..AA where ;AA..AA is optional + * continue with signal + * Since signals are meaning less to us, delete that + * part and then fall into the 'c' code. + */ + ptr = &remcomInBuffer[1]; + length = 2; + while (*ptr && *ptr != ';') { + length++; + ptr++; + } + if (*ptr) { + do { + ptr++; + *(ptr - length++) = *ptr; + } while (*ptr); + } else { + remcomInBuffer[1] = 0; + } + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* D detach, reply OK and then continue */ + case 'c': + case 's': + case 'D': + + /* try to read optional parameter, + pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) { + if (remote_debug) + printk("Changing EIP to 0x%x\n", addr); + + regs.eip = addr; + } + + newPC = regs.eip; + + /* clear the trace bit */ + regs.eflags &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + regs.eflags |= 0x100; + + /* detach is a friendly version of continue. Note that + debugging is still enabled (e.g hit control C) + */ + if (remcomInBuffer[0] == 'D') { + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + } + + if (remote_debug) { + printk("Resuming execution\n"); + print_regs(®s); + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (!(dr6 & 0x4000)) { + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno) && + (breakinfo[breakno].type == 0)) { + /* Set restore flag */ + regs.eflags |= 0x10000; + break; + } + } + } + + if (kgdboe) + netpoll_set_trap(0); + + correct_hw_break(); + asm volatile ("movl %0, %%db6\n"::"r" (0)); + goto exit_kgdb; + + /* kill the program */ + case 'k': /* do nothing */ + break; + + /* query */ + case 'q': + nothreads = 0; + switch (remcomInBuffer[1]) { + case 'f': + threadid = 1; + thread_list = 2; + thread_list_start = (usethread ? : current); + case 's': + if (!cmp_str(&remcomInBuffer[2], + "ThreadInfo", 10)) + break; + + remcomOutBuffer[nothreads++] = 'm'; + for (; threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + nothreads += int_to_hex_v( + &remcomOutBuffer[ + nothreads], + threadid); + if (thread_min > threadid) + thread_min = threadid; + remcomOutBuffer[ + nothreads] = ','; + nothreads++; + if (nothreads > BUFMAX - 10) + break; + } + } + if (remcomOutBuffer[nothreads - 1] == 'm') { + remcomOutBuffer[nothreads - 1] = 'l'; + } else { + nothreads--; + } + remcomOutBuffer[nothreads] = 0; + break; + +#ifdef old_thread_list /* Old thread info request */ + case 'L': + /* List threads */ + thread_list = 2; + thread_list_start = (usethread ? : current); + unpack_byte(remcomInBuffer + 3, &maxthreads); + unpack_threadid(remcomInBuffer + 5, &thref); + do { + int buf_thread_limit = + (BUFMAX - 22) / BUF_THREAD_ID_SIZE; + if (maxthreads > buf_thread_limit) { + maxthreads = buf_thread_limit; + } + } while (0); + remcomOutBuffer[0] = 'q'; + remcomOutBuffer[1] = 'M'; + remcomOutBuffer[4] = '0'; + pack_threadid(remcomOutBuffer + 5, &thref); + + threadid = threadref_to_int(&thref); + for (nothreads = 0; + nothreads < maxthreads && + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(remcomOutBuffer + + 21 + + nothreads * 16, + &thref); + nothreads++; + if (thread_min > threadid) + thread_min = threadid; + } + } + + if (threadid == PID_MAX + MAX_NO_CPUS) { + remcomOutBuffer[4] = '1'; + } + pack_hex_byte(remcomOutBuffer + 2, nothreads); + remcomOutBuffer[21 + nothreads * 16] = '\0'; + break; +#endif + case 'C': + /* Current thread id */ + remcomOutBuffer[0] = 'Q'; + remcomOutBuffer[1] = 'C'; + threadid = current->pid; + if (!threadid) { + /* + * idle thread + */ + for (threadid = PID_MAX; + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + if (current == + idle_task(threadid - + PID_MAX)) + break; + } + } + int_to_threadref(&thref, threadid); + pack_threadid(remcomOutBuffer + 2, &thref); + remcomOutBuffer[18] = '\0'; + break; + + case 'E': + /* Print exception info */ + printexceptioninfo(exceptionVector, + err_code, remcomOutBuffer); + break; + case 'T':{ + char * nptr; + /* Thread extra info */ + if (!cmp_str(&remcomInBuffer[2], + "hreadExtraInfo,", 15)) { + break; + } + ptr = &remcomInBuffer[17]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + nptr = &thread->comm[0]; + length = 0; + ptr = &remcomOutBuffer[0]; + do { + length++; + ptr = pack_hex_byte(ptr, *nptr++); + } while (*nptr && length < 16); + /* + * would like that 16 to be the size of + * task_struct.comm but don't know the + * syntax.. + */ + *ptr = 0; + } + } + break; + + /* task related */ + case 'H': + switch (remcomInBuffer[1]) { + case 'g': + ptr = &remcomInBuffer[2]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (!thread) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + break; + } + /* + * Just in case I forget what this is all about, + * the "thread info" command to gdb causes it + * to ask for a thread list. It then switches + * to each thread and asks for the registers. + * For this (and only this) usage, we want to + * fudge the registers of tasks not on the run + * list (i.e. waiting) to show the routine that + * called schedule. Also, gdb, is a minimalist + * in that if the current thread is the last + * it will not re-read the info when done. + * This means that in this case we must show + * the real registers. So here is how we do it: + * Each entry we keep track of the min + * thread in the list (the last that gdb will) + * get info for. We also keep track of the + * starting thread. + * "thread_list" is cleared when switching back + * to the min thread if it is was current, or + * if it was not current, thread_list is set + * to 1. When the switch to current comes, + * if thread_list is 1, clear it, else do + * nothing. + */ + usethread = thread; + if ((thread_list == 1) && + (thread == thread_list_start)) { + thread_list = 0; + } + if (thread_list && (threadid == thread_min)) { + if (thread == thread_list_start) { + thread_list = 0; + } else { + thread_list = 1; + } + } + /* follow through */ + case 'c': + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (thread) { + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + if (thread_min > threadid) + thread_min = threadid; + } else { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + } + break; + + case 'Y': /* set up a hardware breakpoint */ + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + ptr++; + hexToInt(&ptr, &breaktype); + ptr++; + hexToInt(&ptr, &length); + ptr++; + hexToInt(&ptr, &addr); + if (set_hw_break(breakno & 0x3, + breaktype & 0x3, + length & 0x3, addr) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + case 'r': /* reboot */ + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + /*to_gdb("Rebooting\n"); */ + /* triplefault no return from here */ + { + static long no_idt[2]; + __asm__ __volatile__("lidt %0"::"m"(no_idt[0])); + BREAKPOINT; + } + + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1==1) */ + /* + * reached by goto only. + */ + exit_kgdb: + /* + * Here is where we set up to trap a gdb function call. NEW_esp + * will be changed if we are trying to do this. We handle both + * adding and subtracting, thus allowing gdb to put grung on + * the stack which it removes later. + */ + if (NEW_esp != OLD_esp) { + int *ptr = END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) + ptr -= (OLD_esp - NEW_esp) / sizeof (int); + *--ptr = linux_regs->eflags; + *--ptr = linux_regs->xcs; + *--ptr = linux_regs->eip; + *--ptr = linux_regs->ecx; + *--ptr = linux_regs->ebx; + *--ptr = linux_regs->eax; + linux_regs->ecx = NEW_esp - (sizeof (int) * 6); + linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) { + linux_regs->eip = (unsigned int) fn_call_stub; + } else { + linux_regs->eip = (unsigned int) fn_rtn_stub; + linux_regs->eax = NEW_esp; + } + linux_regs->eflags &= ~(IF_BIT | TF_BIT); + } +#ifdef CONFIG_SMP + /* + * Release gdb wait locks + * Sanity check time. Must have at least one cpu to run. Also single + * step must not be done if the current cpu is on hold. + */ + if (spinlock_count == 1) { + int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep; + int cpu_avail = 0; + int i; + + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!cpu_online(i)) + break; + if (!hold_cpu(i)) { + cpu_avail = 1; + } + } + /* + * Early in the bring up there will be NO cpus on line... + */ + if (!cpu_avail && !cpus_empty(cpu_online_map)) { + to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); + goto once_again; + } + if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) { + to_gdb + ("Current cpu must be unblocked to single step\n"); + goto once_again; + } + if (!(ss_hold)) { + int i; + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!hold_cpu(i)) { + spin_unlock(&waitlocks[i]); + } + } + } else { + spin_unlock(&waitlocks[smp_processor_id()]); + } + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + /* + * If this cpu is on hold, this is where we + * do it. Note, the NMI will pull us out of here, + * but will return as the above lock is not held. + * We will stay here till another cpu releases the lock for us. + */ + spin_unlock_wait(waitlocks + smp_processor_id()); + kgdb_local_irq_restore(flags); + return (0); + } +#if 0 +exit_just_unlock: +#endif +#endif + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + kgdb_local_irq_restore(flags); + return (0); +} + +/* this function is used to set up exception handlers for tracing and + * breakpoints. + * This function is not needed as the above line does all that is needed. + * We leave it for backward compatitability... + */ +void +set_debug_traps(void) +{ + /* + * linux_debug_hook is defined in traps.c. We store a pointer + * to our own exception handler into it. + + * But really folks, every hear of labeled common, an old Fortran + * concept. Lots of folks can reference it and it is define if + * anyone does. Only one can initialize it at link time. We do + * this with the hook. See the statement above. No need for any + * executable code and it is ready as soon as the kernel is + * loaded. Very desirable in kernel debugging. + + linux_debug_hook = handle_exception ; + */ + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. + putDebugChar ('+'); + + initialized = 1; + */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ +/* But really, just use the BREAKPOINT macro. We will handle the int stuff + */ + +#ifdef later +/* + * possibly we should not go thru the traps.c code at all? Someday. + */ +void +do_kgdb_int3(struct pt_regs *regs, long error_code) +{ + kgdb_handle_exception(3, 5, error_code, regs); + return; +} +#endif +#undef regs +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS +asmlinkage void +bad_sys_call_exit(int stuff) +{ + struct pt_regs *regs = (struct pt_regs *) &stuff; + printk("Sys call %d return with %x preempt_count\n", + (int) regs->orig_eax, preempt_count()); +} +#endif +#ifdef CONFIG_STACK_OVERFLOW_TEST +#include +asmlinkage void +stack_overflow(void) +{ +#ifdef BREAKPOINT + BREAKPOINT; +#else + printk("Kernel stack overflow, looping forever\n"); +#endif + while (1) { + } +} +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) +char gdbconbuf[BUFMAX]; + +static void +kgdb_gdb_message(const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + /* + * This takes care of NMI while spining out chars to gdb + */ + IF_SMP(in_kgdb_console = 1); + gdbconbuf[0] = 'O'; + bufptr = gdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + putpacket(gdbconbuf); + + } + IF_SMP(in_kgdb_console = 0); +} +#endif +#ifdef CONFIG_SMP +static void +to_gdb(const char *s) +{ + int count = 0; + while (s[count] && (count++ < BUFMAX)) ; + kgdb_gdb_message(s, count); +} +#endif +#ifdef CONFIG_KGDB_CONSOLE +#include +#include +#include +#include +#include + +void +kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + + if (gdb_i386vector == -1) { + /* + * We have not yet talked to gdb. What to do... + * lets break, on continue we can do the write. + * But first tell him whats up. Uh, well no can do, + * as this IS the console. Oh well... + * We do need to wait or the messages will be lost. + * Other option would be to tell the above code to + * ignore this breakpoint and do an auto return, + * but that might confuse gdb. Also this happens + * early enough in boot up that we don't have the traps + * set up yet, so... + */ + breakpoint(); + } + kgdb_gdb_message(s, count); +} + +/* + * ------------------------------------------------------------ + * Serial KGDB driver + * ------------------------------------------------------------ + */ + +static struct console kgdbcons = { + name:"kgdb", + write:kgdb_console_write, +#ifdef CONFIG_KGDB_USER_CONSOLE + device:kgdb_console_device, +#endif + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +/* + * The trick here is that this file gets linked before printk.o + * That means we get to peer at the console info in the command + * line before it does. If we are up, we register, otherwise, + * do nothing. By returning 0, we allow printk to look also. + */ +static int kgdb_console_enabled; + +int __init +kgdb_console_init(char *str) +{ + if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { + register_console(&kgdbcons); + kgdb_console_enabled = 1; + } + return 0; /* let others look at the string */ +} + +__setup("console=", kgdb_console_init); + +#ifdef CONFIG_KGDB_USER_CONSOLE +static kdev_t kgdb_console_device(struct console *c); +/* This stuff sort of works, but it knocks out telnet devices + * we are leaving it here in case we (or you) find time to figure it out + * better.. + */ + +/* + * We need a real char device as well for when the console is opened for user + * space activities. + */ + +static int +kgdb_consdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t +kgdb_consdev_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int size, ret = 0; + static char kbuf[128]; + static DECLARE_MUTEX(sem); + + /* We are not reentrant... */ + if (down_interruptible(&sem)) + return -ERESTARTSYS; + + while (count > 0) { + /* need to copy the data from user space */ + size = count; + if (size > sizeof (kbuf)) + size = sizeof (kbuf); + if (copy_from_user(kbuf, buf, size)) { + ret = -EFAULT; + break;; + } + kgdb_console_write(&kgdbcons, kbuf, size); + count -= size; + ret += size; + buf += size; + } + + up(&sem); + + return ret; +} + +struct file_operations kgdb_consdev_fops = { + open:kgdb_consdev_open, + write:kgdb_consdev_write +}; +static kdev_t +kgdb_console_device(struct console *c) +{ + return MKDEV(TTYAUX_MAJOR, 1); +} + +/* + * This routine gets called from the serial stub in the i386/lib + * This is so it is done late in bring up (just before the console open). + */ +void +kgdb_console_finit(void) +{ + if (kgdb_console_enabled) { + char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); + char *cp = cptr; + while (*cptr && *cptr != '(') + cptr++; + *cptr = 0; + unregister_chrdev(TTYAUX_MAJOR, cp); + register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); + } +} +#endif +#endif +#ifdef CONFIG_KGDB_TS +#include /* time stamp code */ +#include /* in_interrupt */ +#ifdef CONFIG_KGDB_TS_64 +#define DATA_POINTS 64 +#endif +#ifdef CONFIG_KGDB_TS_128 +#define DATA_POINTS 128 +#endif +#ifdef CONFIG_KGDB_TS_256 +#define DATA_POINTS 256 +#endif +#ifdef CONFIG_KGDB_TS_512 +#define DATA_POINTS 512 +#endif +#ifdef CONFIG_KGDB_TS_1024 +#define DATA_POINTS 1024 +#endif +#ifndef DATA_POINTS +#define DATA_POINTS 128 /* must be a power of two */ +#endif +#define INDEX_MASK (DATA_POINTS - 1) +#if (INDEX_MASK & DATA_POINTS) +#error "CONFIG_KGDB_TS_COUNT must be a power of 2" +#endif +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + int data0; + int data1; +}; +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + struct task_struct *t1; + struct task_struct *t2; +}; +struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; + +struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; +int kgdb_and_then_count; + +void +kgdb_tstamp(int line, char *source, int data0, int data1) +{ + static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; + int flags; + kgdb_local_irq_save(flags); + spin_lock(&ts_spin); + rdtscll(kgdb_and_then->at_time); +#ifdef CONFIG_SMP + kgdb_and_then->on_cpu = smp_processor_id(); +#endif + kgdb_and_then->task = current; + kgdb_and_then->from_ln = line; + kgdb_and_then->in_src = source; + kgdb_and_then->from = __builtin_return_address(0); + kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) | + (preempt_count() << 8)); + kgdb_and_then->data0 = data0; + kgdb_and_then->data1 = data1; + kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; + spin_unlock(&ts_spin); + kgdb_local_irq_restore(flags); +#ifdef CONFIG_PREEMPT + +#endif + return; +} +#endif +typedef int gdb_debug_hook(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs); +gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ + +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + BREAKPOINT; + } +} + --- linux-2.6.1-rc1/arch/i386/kernel/ldt.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/ldt.c 2003-12-30 22:50:18.000000000 -0800 @@ -2,7 +2,7 @@ * linux/kernel/ldt.c * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds - * Copyright (C) 1999 Ingo Molnar + * Copyright (C) 1999, 2003 Ingo Molnar */ #include @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -29,34 +31,31 @@ static void flush_ldt(void *null) static int alloc_ldt(mm_context_t *pc, int mincount, int reload) { - void *oldldt; - void *newldt; - int oldsize; + int oldsize, newsize, i; if (mincount <= pc->size) return 0; + /* + * LDT got larger - reallocate if necessary. + */ oldsize = pc->size; mincount = (mincount+511)&(~511); - if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) - newldt = vmalloc(mincount*LDT_ENTRY_SIZE); - else - newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); - - if (!newldt) - return -ENOMEM; - - if (oldsize) - memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); - oldldt = pc->ldt; - memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); - pc->ldt = newldt; - wmb(); + newsize = mincount*LDT_ENTRY_SIZE; + for (i = 0; i < newsize; i += PAGE_SIZE) { + int nr = i/PAGE_SIZE; + BUG_ON(i >= 64*1024); + if (!pc->ldt_pages[nr]) { + pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER); + if (!pc->ldt_pages[nr]) + return -ENOMEM; + clear_highpage(pc->ldt_pages[nr]); + } + } pc->size = mincount; - wmb(); - if (reload) { #ifdef CONFIG_SMP cpumask_t mask; + preempt_disable(); load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); @@ -67,21 +66,20 @@ static int alloc_ldt(mm_context_t *pc, i load_LDT(pc); #endif } - if (oldsize) { - if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(oldldt); - else - kfree(oldldt); - } return 0; } static inline int copy_ldt(mm_context_t *new, mm_context_t *old) { - int err = alloc_ldt(new, old->size, 0); - if (err < 0) + int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE; + + err = alloc_ldt(new, size, 0); + if (err < 0) { + new->size = 0; return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + } + for (i = 0; i < nr_pages; i++) + copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0); return 0; } @@ -96,6 +94,7 @@ int init_new_context(struct task_struct init_MUTEX(&mm->context.sem); mm->context.size = 0; + memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES); old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); @@ -107,23 +106,21 @@ int init_new_context(struct task_struct /* * No need to lock the MM as we are the last user + * Do not touch the ldt register, we are already + * in the next thread. */ void destroy_context(struct mm_struct *mm) { - if (mm->context.size) { - if (mm == current->active_mm) - clear_LDT(); - if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(mm->context.ldt); - else - kfree(mm->context.ldt); - mm->context.size = 0; - } + int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) + __free_page(mm->context.ldt_pages[i]); + mm->context.size = 0; } static int read_ldt(void __user * ptr, unsigned long bytecount) { - int err; + int err, i; unsigned long size; struct mm_struct * mm = current->mm; @@ -138,8 +135,25 @@ static int read_ldt(void __user * ptr, u size = bytecount; err = 0; - if (copy_to_user(ptr, mm->context.ldt, size)) - err = -EFAULT; + /* + * This is necessary just in case we got here straight from a + * context-switch where the ptes were set but no tlb flush + * was done yet. We rather avoid doing a TLB flush in the + * context-switch path and do it here instead. + */ + __flush_tlb_global(); + + for (i = 0; i < size; i += PAGE_SIZE) { + int nr = i / PAGE_SIZE, bytes; + char *kaddr = kmap(mm->context.ldt_pages[nr]); + + bytes = size - i; + if (bytes > PAGE_SIZE) + bytes = PAGE_SIZE; + if (copy_to_user(ptr + i, kaddr, size - i)) + err = -EFAULT; + kunmap(mm->context.ldt_pages[nr]); + } up(&mm->context.sem); if (err < 0) return err; @@ -158,7 +172,7 @@ static int read_default_ldt(void __user err = 0; address = &default_ldt[0]; - size = 5*sizeof(struct desc_struct); + size = 5*LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; @@ -200,7 +214,15 @@ static int write_ldt(void __user * ptr, goto out_unlock; } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); + /* + * No rescheduling allowed from this point to the install. + * + * We do a TLB flush for the same reason as in the read_ldt() path. + */ + preempt_disable(); + __flush_tlb_global(); + lp = (__u32 *) ((ldt_info.entry_number << 3) + + (char *) __kmap_atomic_vaddr(KM_LDT_PAGE0)); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -221,6 +243,7 @@ install: *lp = entry_1; *(lp+1) = entry_2; error = 0; + preempt_enable(); out_unlock: up(&mm->context.sem); @@ -248,3 +271,26 @@ asmlinkage int sys_modify_ldt(int func, } return ret; } + +/* + * load one particular LDT into the current CPU + */ +void load_LDT_nolock(mm_context_t *pc, int cpu) +{ + struct page **pages = pc->ldt_pages; + int count = pc->size; + int nr_pages, i; + + if (likely(!count)) { + pages = &default_ldt_page; + count = 5; + } + nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) { + __kunmap_atomic_type(KM_LDT_PAGE0 - i); + __kmap_atomic(pages[i], KM_LDT_PAGE0 - i); + } + set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count); + load_LDT_desc(); +} --- linux-2.6.1-rc1/arch/i386/kernel/Makefile 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/Makefile 2003-12-30 22:50:18.000000000 -0800 @@ -7,13 +7,14 @@ extra-y := head.o init_task.o vmlinux.ld obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o + doublefault.o entry_trampoline.o obj-y += cpu/ obj-y += timers/ obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o --- linux-2.6.1-rc1/arch/i386/kernel/mpparse.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/mpparse.c 2003-12-30 22:50:18.000000000 -0800 @@ -668,7 +668,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); @@ -962,7 +962,8 @@ void __init mp_override_legacy_irq ( */ for (i = 0; i < mp_irq_entries; i++) { if ((mp_irqs[i].mpc_dstapic == intsrc.mpc_dstapic) - && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) { + && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq) + && (mp_irqs[i].mpc_irqtype == intsrc.mpc_irqtype)) { mp_irqs[i] = intsrc; found = 1; break; @@ -1081,8 +1082,14 @@ found: ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; + /* + * MPS INTI flags: + * trigger: 0=default, 1=edge, 3=level + * polarity: 0=default, 1=high, 3=low + * Per ACPI spec, default for SCI means level/low. + */ io_apic_set_pci_routing(ioapic, ioapic_pin, irq, - (flags.trigger >> 1) , (flags.polarity >> 1)); + (flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1)); } #ifdef CONFIG_ACPI_PCI @@ -1129,8 +1136,11 @@ void __init mp_parse_prt (void) continue; ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - if (!ioapic && (irq < 16)) - irq += 16; + if (es7000_plat) { + if (!ioapic && (irq < 16)) + irq += 16; + } + /* * Avoid pin reprogramming. PRTs typically include entries * with redundant pin->irq mappings (but unique PCI devices); @@ -1166,6 +1176,10 @@ void __init mp_parse_prt (void) mp_ioapic_routing[ioapic].apic_id, ioapic_pin, entry->irq); } + + print_IO_APIC(); + + return; } #endif /*CONFIG_ACPI_PCI*/ --- linux-2.6.1-rc1/arch/i386/kernel/nmi.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/nmi.c 2003-12-30 22:49:25.000000000 -0800 @@ -31,7 +31,16 @@ #include #include +#ifdef CONFIG_KGDB +#include +#ifdef CONFIG_SMP +unsigned int nmi_watchdog = NMI_IO_APIC; +#else +unsigned int nmi_watchdog = NMI_LOCAL_APIC; +#endif +#else unsigned int nmi_watchdog = NMI_NONE; +#endif static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); @@ -408,6 +417,9 @@ void touch_nmi_watchdog (void) for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } +#ifdef CONFIG_KGDB +int tune_watchdog = 5*HZ; +#endif void nmi_watchdog_tick (struct pt_regs * regs) { @@ -421,12 +433,24 @@ void nmi_watchdog_tick (struct pt_regs * sum = irq_stat[cpu].apic_timer_irqs; +#ifdef CONFIG_KGDB + if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) { + +#else if (last_irq_sums[cpu] == sum) { +#endif /* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; +#ifdef CONFIG_KGDB + if (alert_counter[cpu] == tune_watchdog) { + kgdb_handle_exception(2, SIGPWR, 0, regs); + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } +#endif if (alert_counter[cpu] == 5*nmi_hz) { spin_lock(&nmi_print_lock); /* --- linux-2.6.1-rc1/arch/i386/kernel/process.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/process.c 2003-12-30 22:50:18.000000000 -0800 @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -302,6 +303,9 @@ void flush_thread(void) struct task_struct *tsk = current; memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); +#ifdef CONFIG_X86_HIGH_ENTRY + clear_thread_flag(TIF_DB7); +#endif memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* * Forget coprocessor state.. @@ -315,9 +319,8 @@ void release_thread(struct task_struct * if (dead_task->mm) { // temporary debugging check if (dead_task->mm->context.size) { - printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + printk("WARNING: dead process %8s still has LDT? <%d>\n", dead_task->comm, - dead_task->mm->context.ldt, dead_task->mm->context.size); BUG(); } @@ -352,7 +355,17 @@ int copy_thread(int nr, unsigned long cl p->thread.esp = (unsigned long) childregs; p->thread.esp0 = (unsigned long) (childregs+1); + /* + * get the two stack pages, for the virtual stack. + * + * IMPORTANT: this code relies on the fact that the task + * structure is an 8K aligned piece of physical memory. + */ + p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info); + p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE); + p->thread.eip = (unsigned long) ret_from_fork; + p->thread_info->real_stack = p->thread_info; savesegment(fs,p->thread.fs); savesegment(gs,p->thread.gs); @@ -504,10 +517,41 @@ struct task_struct * __switch_to(struct __unlazy_fpu(prev_p); +#ifdef CONFIG_X86_HIGH_ENTRY + /* + * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is + * needed because otherwise NMIs could interrupt the + * user-return code with a virtual stack and stale TLBs.) + */ + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(next->stack_page0, KM_VSTACK0); + __kmap_atomic(next->stack_page1, KM_VSTACK1); + + /* + * NOTE: here we rely on the task being the stack as well + */ + next_p->thread_info->virtual_stack = + (void *)__kmap_atomic_vaddr(KM_VSTACK0); + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + /* + * If next was preempted on entry from userspace to kernel, + * and now it's on a different cpu, we need to adjust %esp. + * This assumes that entry.S does not copy %esp while on the + * virtual stack (with interrupts enabled): which is so, + * except within __SWITCH_KERNELSPACE itself. + */ + if (unlikely(next->esp >= TASK_SIZE)) { + next->esp &= THREAD_SIZE - 1; + next->esp |= (unsigned long) next_p->thread_info->virtual_stack; + } +#endif +#endif /* * Reload esp0, LDT and the page table pointer: */ - load_esp0(tss, next); + load_virtual_esp0(tss, next_p); /* * Load the per-thread Thread-Local Storage descriptor. --- linux-2.6.1-rc1/arch/i386/kernel/reboot.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/reboot.c 2003-12-30 22:50:18.000000000 -0800 @@ -155,12 +155,11 @@ void machine_real_restart(unsigned char CMOS_WRITE(0x00, 0x8f); spin_unlock_irqrestore(&rtc_lock, flags); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + /* + * Remap the first 16 MB of RAM (which includes the kernel image) + * at virtual address zero: + */ + setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024); /* * Use `swapper_pg_dir' as our page directory. --- linux-2.6.1-rc1/arch/i386/kernel/setup.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/setup.c 2003-12-30 22:49:41.000000000 -0800 @@ -78,13 +78,10 @@ EXPORT_SYMBOL_GPL(mmu_cr4_features); EXPORT_SYMBOL(acpi_disabled); #ifdef CONFIG_ACPI_BOOT - int acpi_irq __initdata = 1; /* enable IRQ */ - int acpi_ht __initdata = 1; /* enable HT */ +extern int __initdata acpi_ht; +int __initdata acpi_force = 0; #endif -int acpi_force __initdata = 0; - - int MCA_bus; /* for MCA, but anyone else can use it if they want */ unsigned int machine_id; @@ -573,7 +570,7 @@ static void __init parse_cmdline_early ( /* "pci=noacpi" disables ACPI interrupt routing */ else if (!memcmp(from, "pci=noacpi", 10)) { - acpi_irq = 0; + acpi_noirq_set(); } #ifdef CONFIG_X86_LOCAL_APIC --- linux-2.6.1-rc1/arch/i386/kernel/signal.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/kernel/signal.c 2003-12-30 22:50:18.000000000 -0800 @@ -128,28 +128,29 @@ sys_sigaltstack(const stack_t __user *us */ static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) +restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *__sc, int *peax) { - unsigned int err = 0; + struct sigcontext scratch; /* 88 bytes of scratch area */ /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; -#define COPY(x) err |= __get_user(regs->x, &sc->x) + if (copy_from_user(&scratch, __sc, sizeof(scratch))) + return -EFAULT; + +#define COPY(x) regs->x = scratch.x #define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ loadsegment(seg,tmp); } GET_SEG(gs); @@ -168,27 +169,23 @@ restore_sigcontext(struct pt_regs *regs, COPY_SEG_STRICT(ss); { - unsigned int tmpflags; - err |= __get_user(tmpflags, &sc->eflags); + unsigned int tmpflags = scratch.eflags; regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ } { - struct _fpstate __user * buf; - err |= __get_user(buf, &sc->fpstate); + struct _fpstate * buf = scratch.fpstate; if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); + return -EFAULT; + if (restore_i387(buf)) + return -EFAULT; } } - err |= __get_user(*peax, &sc->eax); - return err; - -badframe: - return 1; + *peax = scratch.eax; + return 0; } asmlinkage int sys_sigreturn(unsigned long __unused) @@ -266,46 +263,47 @@ badframe: */ static int -setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, +setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { - int tmp, err = 0; + struct sigcontext sc; /* 88 bytes of scratch area */ + int tmp; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->gs); + *(unsigned int *)&sc.gs = tmp; __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->fs); - - err |= __put_user(regs->xes, (unsigned int *)&sc->es); - err |= __put_user(regs->xds, (unsigned int *)&sc->ds); - err |= __put_user(regs->edi, &sc->edi); - err |= __put_user(regs->esi, &sc->esi); - err |= __put_user(regs->ebp, &sc->ebp); - err |= __put_user(regs->esp, &sc->esp); - err |= __put_user(regs->ebx, &sc->ebx); - err |= __put_user(regs->edx, &sc->edx); - err |= __put_user(regs->ecx, &sc->ecx); - err |= __put_user(regs->eax, &sc->eax); - err |= __put_user(current->thread.trap_no, &sc->trapno); - err |= __put_user(current->thread.error_code, &sc->err); - err |= __put_user(regs->eip, &sc->eip); - err |= __put_user(regs->xcs, (unsigned int *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); - err |= __put_user(regs->esp, &sc->esp_at_signal); - err |= __put_user(regs->xss, (unsigned int *)&sc->ss); + *(unsigned int *)&sc.fs = tmp; + *(unsigned int *)&sc.es = regs->xes; + *(unsigned int *)&sc.ds = regs->xds; + sc.edi = regs->edi; + sc.esi = regs->esi; + sc.ebp = regs->ebp; + sc.esp = regs->esp; + sc.ebx = regs->ebx; + sc.edx = regs->edx; + sc.ecx = regs->ecx; + sc.eax = regs->eax; + sc.trapno = current->thread.trap_no; + sc.err = current->thread.error_code; + sc.eip = regs->eip; + *(unsigned int *)&sc.cs = regs->xcs; + sc.eflags = regs->eflags; + sc.esp_at_signal = regs->esp; + *(unsigned int *)&sc.ss = regs->xss; tmp = save_i387(fpstate); if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + return 1; + sc.fpstate = tmp ? fpstate : NULL; /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(current->thread.cr2, &sc->cr2); + sc.oldmask = mask; + sc.cr2 = current->thread.cr2; - return err; + if (copy_to_user(__sc, &sc, sizeof(sc))) + return 1; + return 0; } /* @@ -443,7 +441,7 @@ static void setup_rt_frame(int sig, stru /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->esp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); --- linux-2.6.1-rc1/arch/i386/kernel/smp.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/smp.c 2003-12-30 22:50:18.000000000 -0800 @@ -327,10 +327,12 @@ asmlinkage void smp_invalidate_interrupt if (flush_mm == cpu_tlbstate[cpu].active_mm) { if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (flush_va == FLUSH_ALL) local_flush_tlb(); else __flush_tlb_one(flush_va); +#endif } else leave_mm(cpu); } @@ -396,21 +398,6 @@ static void flush_tlb_others(cpumask_t c spin_unlock(&tlbstate_lock); } -void flush_tlb_current_task(void) -{ - struct mm_struct *mm = current->mm; - cpumask_t cpu_mask; - - preempt_disable(); - cpu_mask = mm->cpu_vm_mask; - cpu_clear(smp_processor_id(), cpu_mask); - - local_flush_tlb(); - if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, FLUSH_ALL); - preempt_enable(); -} - void flush_tlb_mm (struct mm_struct * mm) { cpumask_t cpu_mask; @@ -442,7 +429,10 @@ void flush_tlb_page(struct vm_area_struc if (current->active_mm == mm) { if(current->mm) - __flush_tlb_one(va); +#ifndef CONFIG_X86_SWITCH_PAGETABLES + __flush_tlb_one(va) +#endif + ; else leave_mm(smp_processor_id()); } @@ -466,7 +456,17 @@ void flush_tlb_all(void) { on_each_cpu(do_flush_tlb_all, 0, 1, 1); } - +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing --- linux-2.6.1-rc1/arch/i386/kernel/sysenter.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/sysenter.c 2003-12-30 22:50:18.000000000 -0800 @@ -18,13 +18,18 @@ #include #include #include +#include extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void *info) { int cpu = get_cpu(); +#ifdef CONFIG_X86_HIGH_ENTRY + struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else struct tss_struct *tss = init_tss + cpu; +#endif tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; --- linux-2.6.1-rc1/arch/i386/kernel/timers/common.c 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/i386/kernel/timers/common.c 2003-12-30 22:49:52.000000000 -0800 @@ -137,3 +137,23 @@ bad_calibration: } #endif +/* calculate cpu_khz */ +void __init init_cpu_khz(void) +{ + if (cpu_has_tsc) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000; + __asm__("divl %2" + :"=a" (cpu_khz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); + } + } + } +} --- linux-2.6.1-rc1/arch/i386/kernel/timers/Makefile 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/i386/kernel/timers/Makefile 2003-12-30 22:49:51.000000000 -0800 @@ -6,3 +6,4 @@ obj-y := timer.o timer_none.o timer_tsc. obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o obj-$(CONFIG_HPET_TIMER) += timer_hpet.o +obj-$(CONFIG_X86_PM_TIMER) += timer_pm.o --- linux-2.6.1-rc1/arch/i386/kernel/timers/timer.c 2003-09-08 13:58:55.000000000 -0700 +++ 25/arch/i386/kernel/timers/timer.c 2003-12-30 22:49:51.000000000 -0800 @@ -19,6 +19,9 @@ static struct timer_opts* timers[] = { #ifdef CONFIG_HPET_TIMER &timer_hpet, #endif +#ifdef CONFIG_X86_PM_TIMER + &timer_pmtmr, +#endif &timer_tsc, &timer_pit, NULL, --- linux-2.6.1-rc1/arch/i386/kernel/timers/timer_cyclone.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/timers/timer_cyclone.c 2003-12-30 22:49:52.000000000 -0800 @@ -212,26 +212,7 @@ static int __init init_cyclone(char* ove } } - /* init cpu_khz. - * XXX - This should really be done elsewhere, - * and in a more generic fashion. -johnstul@us.ibm.com - */ - if (cpu_has_tsc) { - unsigned long tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000; - __asm__("divl %2" - :"=a" (cpu_khz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); - } - } - } + init_cpu_khz(); /* Everything looks good! */ return 0; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/kernel/timers/timer_pm.c 2003-12-30 22:49:52.000000000 -0800 @@ -0,0 +1,201 @@ +/* + * (C) Dominik Brodowski 2003 + * + * Driver to use the Power Management Timer (PMTMR) available in some + * southbridges as primary timing source for the Linux kernel. + * + * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, + * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. + * + * This file is licensed under the GPL v2. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* The I/O port the PMTMR resides at. + * The location is detected during setup_arch(), + * in arch/i386/acpi/boot.c */ +u32 pmtmr_ioport = 0; + + +/* value of the Power timer at last timer interrupt */ +static u32 offset_tick; +static u32 offset_delay; + +static unsigned long long monotonic_base; +static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED; + +#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ + +static int init_pmtmr(char* override) +{ + u32 value1, value2; + unsigned int i; + + if (override[0] && strncmp(override,"pmtmr",5)) + return -ENODEV; + + if (!pmtmr_ioport) + return -ENODEV; + + /* "verify" this timing source */ + value1 = inl(pmtmr_ioport); + value1 &= ACPI_PM_MASK; + for (i=0; i < 10000; i++) { + value2 = inl(pmtmr_ioport); + value2 &= ACPI_PM_MASK; + if (value2 == value1) + continue; + if (value2 > value1) + goto pm_good; + if ((value2 < value1) && ((value2) < 0xFFF)) + goto pm_good; + printk(KERN_INFO "PM-Timer had inconsistent results: 0x%#x, 0x%#x - aborting.\n", value1, value2); + return -EINVAL; + } + printk(KERN_INFO "PM-Timer had no reasonable result: 0x%#x - aborting.\n", value1); + return -ENODEV; + +pm_good: + init_cpu_khz(); + return 0; +} + +static inline u32 cyc2us(u32 cycles) +{ + /* The Power Management Timer ticks at 3.579545 ticks per microsecond. + * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%] + * + * Even with HZ = 100, delta is at maximum 35796 ticks, so it can + * easily be multiplied with 286 (=0x11E) without having to fear + * u32 overflows. + */ + cycles *= 286; + return (cycles >> 10); +} + +/* + * this gets called during each timer interrupt + * - Called while holding the writer xtime_lock + */ +static void mark_offset_pmtmr(void) +{ + u32 lost, delta, last_offset; + static int first_run = 1; + + write_seqlock(&monotonic_lock); + + last_offset = offset_tick; + offset_tick = inl(pmtmr_ioport); + offset_tick &= ACPI_PM_MASK; /* limit it to 24 bits */ + + /* calculate tick interval */ + delta = likely(last_offset < offset_tick) ? + offset_tick - last_offset : ACPI_PM_MASK - last_offset + offset_tick; + + /* convert to usecs */ + delta = cyc2us(delta); + + /* update the monotonic base value */ + monotonic_base += delta * NSEC_PER_USEC; + write_sequnlock(&monotonic_lock); + + /* convert to ticks */ + delta += offset_delay; + lost = delta / (USEC_PER_SEC / HZ); + offset_delay = delta % (USEC_PER_SEC / HZ); + + /* compensate for lost ticks */ + if (lost >= 2) + jiffies += lost - 1; + + /* don't calculate delay for first run, + or if we've got less then a tick */ + if (first_run || (lost < 1)) { + first_run = 0; + offset_delay = 0; + } +} + + +static unsigned long long monotonic_clock_pmtmr(void) +{ + u32 last_offset, this_offset; + unsigned long long base, ret; + unsigned seq; + + + /* atomically read monotonic base & last_offset */ + do { + seq = read_seqbegin(&monotonic_lock); + last_offset = offset_tick; + base = monotonic_base; + } while (read_seqretry(&monotonic_lock, seq)); + + /* Read the pmtmr */ + this_offset = inl(pmtmr_ioport) & ACPI_PM_MASK; + + /* convert to nanoseconds */ + ret = (this_offset - last_offset) & ACPI_PM_MASK; + ret = base + (cyc2us(ret)*NSEC_PER_USEC); + return ret; +} + +/* + * copied from delay_pit + */ +static void delay_pmtmr(unsigned long loops) +{ + int d0; + __asm__ __volatile__( + "\tjmp 1f\n" + ".align 16\n" + "1:\tjmp 2f\n" + ".align 16\n" + "2:\tdecl %0\n\tjns 2b" + :"=&a" (d0) + :"0" (loops)); +} + + +/* + * get the offset (in microseconds) from the last call to mark_offset() + * - Called holding a reader xtime_lock + */ +static unsigned long get_offset_pmtmr(void) +{ + u32 now, offset, delta = 0; + + offset = offset_tick; + now = inl(pmtmr_ioport); + now &= ACPI_PM_MASK; + delta = likely(offset < now) ? now - offset : ACPI_PM_MASK - offset + now; + + return (unsigned long) offset_delay + cyc2us(delta); +} + + +/* acpi timer_opts struct */ +struct timer_opts timer_pmtmr = { + .name = "acpi_pm_timer", + .init = init_pmtmr, + .mark_offset = mark_offset_pmtmr, + .get_offset = get_offset_pmtmr, + .monotonic_clock = monotonic_clock_pmtmr, + .delay = delay_pmtmr, +}; + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dominik Brodowski "); +MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86"); --- linux-2.6.1-rc1/arch/i386/kernel/timers/timer_tsc.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/timers/timer_tsc.c 2003-12-30 22:50:10.000000000 -0800 @@ -140,7 +140,8 @@ unsigned long long sched_clock(void) #ifndef CONFIG_NUMA if (!use_tsc) #endif - return (unsigned long long)get_jiffies_64() * (1000000000 / HZ); + /* jiffies might overflow but this is not a big deal here */ + return (unsigned long long)jiffies * (1000000000 / HZ); /* Read the Time Stamp Counter */ rdtscll(this_offset); --- linux-2.6.1-rc1/arch/i386/kernel/traps.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/traps.c 2003-12-30 22:50:18.000000000 -0800 @@ -54,12 +54,8 @@ #include "mach_traps.h" -asmlinkage int system_call(void); -asmlinkage void lcall7(void); -asmlinkage void lcall27(void); - -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 }, { 0, 0 } }; +struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; +struct page *default_ldt_page; /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; @@ -91,6 +87,43 @@ asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); +#ifdef CONFIG_KGDB +extern void sysenter_entry(void); +#include +#include +extern void int3(void); +extern void debug(void); +void set_intr_gate(unsigned int n, void *addr); +static void set_intr_usr_gate(unsigned int n, void *addr); +/* + * Should be able to call this breakpoint() very early in + * bring up. Just hard code the call where needed. + * The breakpoint() code is here because set_?_gate() functions + * are local (static) to trap.c. They need be done only once, + * but it does not hurt to do them over. + */ +void breakpoint(void) +{ + init_entry_mappings(); + set_intr_usr_gate(3,&int3); /* disable ints on trap */ + set_intr_gate(1,&debug); + set_intr_gate(14,&page_fault); + + BREAKPOINT; +} +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \ + { \ + if (!user_mode(regs) ) \ + { \ + kgdb_handle_exception(trapnr, signr, error_code, regs); \ + after; \ + } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \ + } +#else +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) +#endif + + static int kstack_depth_to_print = 24; void show_trace(struct task_struct *task, unsigned long * stack) @@ -175,8 +208,9 @@ void show_registers(struct pt_regs *regs ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", - smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, + regs->eip, print_tainted(), regs->eflags); print_symbol("EIP is at %s\n", regs->eip); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", @@ -192,23 +226,27 @@ void show_registers(struct pt_regs *regs * time of the fault.. */ if (in_kernel) { + u8 *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - if(regs->eip < PAGE_OFFSET) - goto bad; - for(i=0;i<20;i++) - { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { + unsigned char c = 0xff; + + if ((user_mode(regs) && get_user(c, eip)) || + (!user_mode(regs) && __direct_get_user(c, eip))) { + printk(" Bad EIP value."); break; } - printk("%02x ", c); + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); } } printk("\n"); @@ -255,12 +293,36 @@ spinlock_t die_lock = SPIN_LOCK_UNLOCKED void die(const char * str, struct pt_regs * regs, long err) { static int die_counter; + int nl = 0; console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); handle_BUG(regs); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); + nl = 1; +#endif +#ifdef CONFIG_SMP + printk("SMP "); + nl = 1; +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); + nl = 1; +#endif + if (nl) + printk("\n"); +#ifdef CONFIG_KGDB + /* This is about the only place we want to go to kgdb even if in + * user mode. But we must go in via a trap so within kgdb we will + * always be in kernel mode. + */ + if (user_mode(regs)) + BREAKPOINT; +#endif + CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,) show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); @@ -330,6 +392,7 @@ static inline void do_trap(int trapnr, i #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -347,7 +410,9 @@ asmlinkage void do_##name(struct pt_regs #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ + return; \ } #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ @@ -394,8 +459,10 @@ gp_in_vm86: return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)){ + CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,) die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -534,10 +601,18 @@ asmlinkage void do_debug(struct pt_regs if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); - /* Mask out spurious debug traps due to lazy DR7 setting */ + /* + * Mask out spurious debug traps due to lazy DR7 setting or + * due to 4G/4G kernel mode: + */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) goto clear_dr7; + if (!user_mode(regs)) { + // restore upon return-to-userspace: + set_thread_flag(TIF_DB7); + goto clear_dr7; + } } if (regs->eflags & VM_MASK) @@ -557,8 +632,18 @@ asmlinkage void do_debug(struct pt_regs * allowing programs to debug themselves without the ptrace() * interface. */ +#ifdef CONFIG_KGDB + /* + * I think this is the only "real" case of a TF in the kernel + * that really belongs to user space. Others are + * "Ours all ours!" + */ + if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry)) + goto clear_TF_reenable; +#else if ((regs->xcs & 3) == 0) goto clear_TF_reenable; +#endif if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -570,6 +655,17 @@ asmlinkage void do_debug(struct pt_regs info.si_errno = 0; info.si_code = TRAP_BRKPT; +#ifdef CONFIG_KGDB + /* + * If this is a kernel mode trap, we need to reset db7 to allow us + * to continue sanely ALSO skip the signal delivery + */ + if ((regs->xcs & 3) == 0) + goto clear_dr7; + + /* if not kernel, allow ints but only if they were on */ + if ( regs->eflags & 0x200) local_irq_enable(); +#endif /* If this is a kernel mode trap, save the user PC on entry to * the kernel, that's what the debugger can make sense of. */ @@ -584,6 +680,7 @@ clear_dr7: __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); + CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,) return; debug_vm86: @@ -779,19 +876,53 @@ asmlinkage void math_emulate(long arg) #endif /* CONFIG_MATH_EMULATION */ -#ifdef CONFIG_X86_F00F_BUG -void __init trap_init_f00f_bug(void) +void __init trap_init_virtual_IDT(void) { - __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); - /* - * Update the IDT descriptor and reload the IDT so that - * it uses the read-only mapped virtual address. + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. */ - idt_descr.address = fix_to_virt(FIX_F00F_IDT); + __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO); + idt_descr.address = __fix_to_virt(FIX_IDT); + __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); } + +void __init trap_init_virtual_GDT(void) +{ + int cpu = smp_processor_id(); + struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu; + struct Xgt_desc_struct tmp_desc = {0, 0}; + struct tss_struct * t; + + __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory"); + +#ifdef CONFIG_X86_HIGH_ENTRY + if (!cpu) { + __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL); + __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL); + __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL); + } + + gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu; +#else + gdt_desc->address = (unsigned long)cpu_gdt_table[cpu]; +#endif + __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc)); + +#ifdef CONFIG_X86_HIGH_ENTRY + t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else + t = init_tss + cpu; #endif + set_tss_desc(cpu, t); + cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + load_TR_desc(); +} #define _set_gate(gate_addr,type,dpl,addr,seg) \ do { \ @@ -818,20 +949,26 @@ void set_intr_gate(unsigned int n, void _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } -static void __init set_trap_gate(unsigned int n, void *addr) +void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); } -static void __init set_system_gate(unsigned int n, void *addr) +void __init set_system_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); } -static void __init set_call_gate(void *a, void *addr) +void __init set_call_gate(void *a, void *addr) { _set_gate(a,12,3,addr,__KERNEL_CS); } +#ifdef CONFIG_KGDB +void set_intr_usr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,3,addr,__KERNEL_CS); +} +#endif static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) { @@ -850,11 +987,16 @@ void __init trap_init(void) #ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif + init_entry_mappings(); set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); +#ifndef CONFIG_KGDB set_system_gate(3,&int3); /* int3-5 can be called from all */ +#else + set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */ +#endif set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); --- linux-2.6.1-rc1/arch/i386/kernel/vm86.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/vm86.c 2003-12-30 22:50:18.000000000 -0800 @@ -125,7 +125,7 @@ struct pt_regs * save_v86_state(struct k tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; - load_esp0(tss, ¤t->thread); + load_virtual_esp0(tss, current); current->thread.saved_esp0 = 0; put_cpu(); @@ -305,7 +305,7 @@ static void do_sys_vm86(struct kernel_vm tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; - load_esp0(tss, &tsk->thread); + load_virtual_esp0(tss, tsk); put_cpu(); tsk->thread.screen_bitmap = info->screen_bitmap; --- linux-2.6.1-rc1/arch/i386/kernel/vmlinux.lds.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/vmlinux.lds.S 2003-12-30 22:50:18.000000000 -0800 @@ -3,6 +3,9 @@ */ #include +#include +#include +#include OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -10,7 +13,7 @@ ENTRY(startup_32) jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { @@ -19,6 +22,19 @@ SECTIONS *(.gnu.warning) } = 0x9090 +#ifdef CONFIG_X86_4G + . = ALIGN(PAGE_SIZE_asm); + __entry_tramp_start = .; + . = FIX_ENTRY_TRAMPOLINE_0_addr; + __start___entry_text = .; + .entry.text : AT (__entry_tramp_start) { *(.entry.text) } + __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text); + . = __entry_tramp_end; + . = ALIGN(PAGE_SIZE_asm); +#else + .entry.text : { *(.entry.text) } +#endif + _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ @@ -34,15 +50,12 @@ SECTIONS CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_begin = .; .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_end = .; - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } @@ -52,7 +65,7 @@ SECTIONS .data.init_task : { *(.data.init_task) } /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE_asm); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -91,7 +104,7 @@ SECTIONS from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; @@ -99,10 +112,22 @@ SECTIONS __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __init_end = .; /* freed after init ends here */ - + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_tss : { *(.data.tss) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_default_ldt : { *(.data.default_ldt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_idt : { *(.data.idt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_gdt : { *(.data.gdt) } + __bss_start = .; /* BSS */ .bss : { *(.bss) } __bss_stop = .; @@ -122,4 +147,6 @@ SECTIONS .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } + + } --- linux-2.6.1-rc1/arch/i386/kernel/vsyscall.lds 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/vsyscall.lds 2003-12-30 22:50:18.000000000 -0800 @@ -5,7 +5,7 @@ */ /* This must match . */ -VSYSCALL_BASE = 0xffffe000; +VSYSCALL_BASE = 0xffffd000; SECTIONS { --- linux-2.6.1-rc1/arch/i386/kernel/vsyscall-sysenter.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/vsyscall-sysenter.S 2003-12-30 22:50:18.000000000 -0800 @@ -7,6 +7,11 @@ .type __kernel_vsyscall,@function __kernel_vsyscall: .LSTART_vsyscall: + cmpl $192, %eax + jne 1f + int $0x80 + ret +1: push %ecx .Lpush_ecx: push %edx --- linux-2.6.1-rc1/arch/i386/lib/checksum.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/checksum.S 2003-12-30 22:50:18.000000000 -0800 @@ -280,14 +280,14 @@ unsigned int csum_partial_copy_generic ( .previous .align 4 -.globl csum_partial_copy_generic +.globl direct_csum_partial_copy_generic #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: subl $4,%esp pushl %edi pushl %esi @@ -422,7 +422,7 @@ DST( movb %cl, (%edi) ) #define ARGBASE 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: pushl %ebx pushl %edi pushl %esi --- linux-2.6.1-rc1/arch/i386/lib/dec_and_lock.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/dec_and_lock.c 2003-12-30 22:50:17.000000000 -0800 @@ -10,6 +10,7 @@ #include #include +#ifndef ATOMIC_DEC_AND_LOCK int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -38,3 +39,5 @@ slow_path: spin_unlock(lock); return 0; } +#endif + --- linux-2.6.1-rc1/arch/i386/lib/getuser.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/getuser.S 2003-12-30 22:50:18.000000000 -0800 @@ -9,6 +9,7 @@ * return value. */ #include +#include /* @@ -28,7 +29,7 @@ .globl __get_user_1 __get_user_1: GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 1: movzbl (%eax),%edx xorl %eax,%eax @@ -40,7 +41,7 @@ __get_user_2: addl $1,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 2: movzwl -1(%eax),%edx xorl %eax,%eax @@ -52,7 +53,7 @@ __get_user_4: addl $3,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 3: movl -3(%eax),%edx xorl %eax,%eax --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/lib/kgdb_serial.c 2003-12-30 22:49:27.000000000 -0800 @@ -0,0 +1,499 @@ +/* + * Serial interface GDB stub + * + * Written (hacked together) by David Grothe (dave@gcom.com) + * Modified to allow invokation early in boot see also + * kgdb.h for instructions by George Anzinger(george@mvista.com) + * Modified to handle debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KGDB_USER_CONSOLE +extern void kgdb_console_finit(void); +#endif +#define PRNT_off +#define TEST_EXISTANCE +#ifdef PRNT +#define dbprintk(s) printk s +#else +#define dbprintk(s) +#endif +#define TEST_INTERRUPT_off +#ifdef TEST_INTERRUPT +#define intprintk(s) printk s +#else +#define intprintk(s) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char gdb_buf[GDB_BUF_SIZE]; +static int gdb_buf_in_inx; +static atomic_t gdb_buf_in_cnt; +static int gdb_buf_out_inx; + +struct async_struct *gdb_async_info; +static int gdb_async_irq; + +#define outb_px(a,b) outb_p(b,a) + +static void program_uart(struct async_struct *info); +static void write_char(struct async_struct *info, int chr); +/* + * Get a byte from the hardware data buffer and return it + */ +static int +read_data_bfr(struct async_struct *info) +{ + char it = inb_p(info->port + UART_LSR); + + if (it & UART_LSR_DR) + return (inb_p(info->port + UART_RX)); + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + program_uart(info); + write_char(info, '-'); + return ('-'); + } + return (-1); + +} /* read_data_bfr */ + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + + * Locking here is a bit of a problem. We MUST not lock out communication + * if we are trying to talk to gdb about a kgdb entry. ON the other hand + * we can loose chars in the console pass thru if we don't lock. It is also + * possible that we could hold the lock or be waiting for it when kgdb + * NEEDS to talk. Since kgdb locks down the world, it does not need locks. + * We do, of course have possible issues with interrupting a uart operation, + * but we will just depend on the uart status to help keep that straight. + + */ +static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SMP +extern spinlock_t kgdb_spinlock; +#endif + +static int +read_char(struct async_struct *info) +{ + int chr; + unsigned long flags; + local_irq_save(flags); +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_lock(&uart_interrupt_lock); + } +#endif + if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ + chr = gdb_buf[gdb_buf_out_inx++]; + gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&gdb_buf_in_cnt); + } else { + chr = read_data_bfr(info); + } +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_unlock(&uart_interrupt_lock); + } +#endif + local_irq_restore(flags); + return (chr); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +write_char(struct async_struct *info, int chr) +{ + while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ; + + outb_p(chr, info->port + UART_TX); + +} /* write_char */ + +/* + * Mostly we don't need a spinlock, but since the console goes + * thru here with interrutps on, well, we need to catch those + * chars. + */ +/* + * This is the receiver interrupt routine for the GDB stub. + * It will receive a limited number of characters of input + * from the gdb host machine and save them up in a buffer. + * + * When the gdb stub routine tty_getDebugChar() is called it + * draws characters out of the buffer until it is empty and + * then reads directly from the serial port. + * + * We do not attempt to write chars from the interrupt routine + * since the stubs do all of that via tty_putDebugChar() which + * writes one byte after waiting for the interface to become + * ready. + * + * The debug stubs like to run with interrupts disabled since, + * after all, they run as a consequence of a breakpoint in + * the kernel. + * + * Perhaps someone who knows more about the tty driver than I + * care to learn can make this work for any low level serial + * driver. + */ +static irqreturn_t +gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct async_struct *info; + unsigned long flags; + + info = gdb_async_info; + if (!info || !info->tty || irq != gdb_async_irq) + return IRQ_NONE; + + local_irq_save(flags); + spin_lock(&uart_interrupt_lock); + do { + int chr = read_data_bfr(info); + intprintk(("Debug char on int: %x hex\n", chr)); + if (chr < 0) + continue; + + if (chr == 3) { /* Ctrl-C means remote interrupt */ + BREAKPOINT; + continue; + } + + if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { + /* buffer overflow tosses early char */ + read_char(info); + } + gdb_buf[gdb_buf_in_inx++] = chr; + gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); + } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI); + spin_unlock(&uart_interrupt_lock); + local_irq_restore(flags); + return IRQ_HANDLED; +} /* gdb_interrupt */ + +/* + * Just a NULL routine for testing. + */ +void +gdb_null(void) +{ +} /* gdb_null */ + +/* These structure are filled in with values defined in asm/kgdb_local.h + */ +static struct serial_state state = SB_STATE; +static struct async_struct local_info = SB_INFO; +static int ok_to_enable_ints = 0; +static void kgdb_enable_ints_now(void); + +extern char *kgdb_version; +/* + * Hook an IRQ for KGDB. + * + * This routine is called from tty_putDebugChar, below. + */ +static int ints_disabled = 1; +int +gdb_hook_interrupt(struct async_struct *info, int verb) +{ + struct serial_state *state = info->state; + unsigned long flags; + int port; +#ifdef TEST_EXISTANCE + int scratch, scratch2; +#endif + + /* The above fails if memory managment is not set up yet. + * Rather than fail the set up, just keep track of the fact + * and pick up the interrupt thing later. + */ + gdb_async_info = info; + port = gdb_async_info->port; + gdb_async_irq = state->irq; + if (verb) { + printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", + kgdb_version, + port, + gdb_async_irq, gdb_async_info->state->custom_divisor); + } + local_irq_save(flags); +#ifdef TEST_EXISTANCE + /* Existance test */ + /* Should not need all this, but just in case.... */ + + scratch = inb_p(port + UART_IER); + outb_px(port + UART_IER, 0); + outb_px(0xff, 0x080); + scratch2 = inb_p(port + UART_IER); + outb_px(port + UART_IER, scratch); + if (scratch2) { + printk + ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); + local_irq_restore(flags); + return 1; /* We failed; there's nothing here */ + } + scratch2 = inb_p(port + UART_LCR); + outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */ + outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */ + outb_px(port + UART_LCR, 0); + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = inb_p(port + UART_IIR) >> 6; + if (scratch == 1) { + printk("gdb_hook_interrupt: Undefined UART type!" + " Not a UART! \n"); + local_irq_restore(flags); + return 1; + } else { + dbprintk(("gdb_hook_interrupt: UART type " + "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); + } + scratch = inb_p(port + UART_MCR); + outb_px(port + UART_MCR, UART_MCR_LOOP | scratch); + outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A); + scratch2 = inb_p(port + UART_MSR) & 0xF0; + outb_px(port + UART_MCR, scratch); + if (scratch2 != 0x90) { + printk("gdb_hook_interrupt: " + "Loop back test failed! Not a UART!\n"); + local_irq_restore(flags); + return scratch2 + 1000; /* force 0 to fail */ + } +#endif /* test existance */ + program_uart(info); + local_irq_restore(flags); + + return (0); + +} /* gdb_hook_interrupt */ + +static void +program_uart(struct async_struct *info) +{ + int port = info->port; + + (void) inb_p(port + UART_RX); + outb_px(port + UART_IER, 0); + + (void) inb_p(port + UART_RX); /* serial driver comments say */ + (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */ + (void) inb_p(port + UART_MSR); + outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */ + outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */ + outb_px(port + UART_MCR, info->MCR); + + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ + outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + return; +} + +/* + * tty_getDebugChar + * + * This is a GDB stub routine. It waits for a character from the + * serial interface and then returns it. If there is no serial + * interface connection then it returns a bogus value which will + * almost certainly cause the system to hang. In the + */ +int kgdb_in_isr = 0; +int kgdb_in_lsr = 0; +extern spinlock_t kgdb_spinlock; + +/* Caller takes needed protections */ + +int +tty_getDebugChar(void) +{ + volatile int chr, dum, time, end_time; + + dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + /* + * This trick says if we wait a very long time and get + * no char, return the -1 and let the upper level deal + * with it. + */ + rdtsc(dum, time); + end_time = time + 2; + while (((chr = read_char(gdb_async_info)) == -1) && + (end_time - time) > 0) { + rdtsc(dum, time); + }; + /* + * This covers our butts if some other code messes with + * our uart, hay, it happens :o) + */ + if (chr == -1) + program_uart(gdb_async_info); + + dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); + return (chr); + +} /* tty_getDebugChar */ + +static int count = 3; +static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; + +static int __init +kgdb_enable_ints(void) +{ + if (kgdboe) { + return 0; + } + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 1); + } + ok_to_enable_ints = 1; + kgdb_enable_ints_now(); +#ifdef CONFIG_KGDB_USER_CONSOLE + kgdb_console_finit(); +#endif + return 0; +} + +#ifdef CONFIG_SERIAL_8250 +void shutdown_for_kgdb(struct async_struct *gdb_async_info); +#endif + +#ifdef CONFIG_DISCONTIGMEM +static inline int kgdb_mem_init_done(void) +{ + return highmem_start_page != NULL; +} +#else +static inline int kgdb_mem_init_done(void) +{ + return max_mapnr != 0; +} +#endif + +static void +kgdb_enable_ints_now(void) +{ + if (!spin_trylock(&one_at_atime)) + return; + if (!ints_disabled) + goto exit; + if (kgdb_mem_init_done() && + ints_disabled) { /* don't try till mem init */ +#ifdef CONFIG_SERIAL_8250 + /* + * The ifdef here allows the system to be configured + * without the serial driver. + * Don't make it a module, however, it will steal the port + */ + shutdown_for_kgdb(gdb_async_info); +#endif + ints_disabled = request_irq(gdb_async_info->state->irq, + gdb_interrupt, + IRQ_T(gdb_async_info), + "KGDB-stub", NULL); + intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); + } + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + exit: + spin_unlock(&one_at_atime); +} + +/* + * tty_putDebugChar + * + * This is a GDB stub routine. It waits until the interface is ready + * to transmit a char and then sends it. If there is no serial + * interface connection then it simply returns to its caller, having + * pretended to send the char. Caller takes needed protections. + */ +void +tty_putDebugChar(int chr) +{ + dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", + gdb_async_info->port, + chr, + chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + + write_char(gdb_async_info, chr); /* this routine will wait */ + count = (chr == '#') ? 0 : count + 1; + if ((count == 2)) { /* try to enable after */ + if (ints_disabled & ok_to_enable_ints) + kgdb_enable_ints_now(); /* try to enable after */ + + /* We do this a lot because, well we really want to get these + * interrupts. The serial driver will clear these bits when it + * initializes the chip. Every thing else it does is ok, + * but this. + */ + if (!ints_disabled) { + outb_px(gdb_async_info->port + UART_IER, + gdb_async_info->IER); + } + } + +} /* tty_putDebugChar */ + +/* + * This does nothing for the serial port, since it doesn't buffer. + */ + +void tty_flushDebugChar(void) +{ +} + +module_init(kgdb_enable_ints); --- linux-2.6.1-rc1/arch/i386/lib/Makefile 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/Makefile 2003-12-30 22:49:25.000000000 -0800 @@ -9,4 +9,5 @@ lib-y = checksum.o delay.o \ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o lib-$(CONFIG_DEBUG_IOVIRT) += iodebug.o --- linux-2.6.1-rc1/arch/i386/lib/usercopy.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/lib/usercopy.c 2003-12-30 22:50:18.000000000 -0800 @@ -76,7 +76,7 @@ do { \ * and returns @count. */ long -__strncpy_from_user(char *dst, const char __user *src, long count) +__direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); @@ -102,7 +102,7 @@ __strncpy_from_user(char *dst, const cha * and returns @count. */ long -strncpy_from_user(char *dst, const char __user *src, long count) +direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -147,7 +147,7 @@ do { \ * On success, this will be zero. */ unsigned long -clear_user(void __user *to, unsigned long n) +direct_clear_user(void __user *to, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) @@ -167,7 +167,7 @@ clear_user(void __user *to, unsigned lon * On success, this will be zero. */ unsigned long -__clear_user(void __user *to, unsigned long n) +__direct_clear_user(void __user *to, unsigned long n) { __do_clear_user(to, n); return n; @@ -184,7 +184,7 @@ __clear_user(void __user *to, unsigned l * On exception, returns 0. * If the string is too long, returns a value greater than @n. */ -long strnlen_user(const char __user *s, long n) +long direct_strnlen_user(const char __user *s, long n) { unsigned long mask = -__addr_ok(s); unsigned long res, tmp; @@ -575,3 +575,4 @@ unsigned long __copy_from_user_ll(void * n = __copy_user_zeroing_intel(to, (const void *) from, n); return n; } + --- linux-2.6.1-rc1/arch/i386/mach-es7000/es7000.c 2003-06-16 22:32:20.000000000 -0700 +++ 25/arch/i386/mach-es7000/es7000.c 2003-12-30 22:49:41.000000000 -0800 @@ -51,8 +51,6 @@ struct mip_reg *host_reg; int mip_port; unsigned long mip_addr, host_addr; -static int es7000_plat; - /* * Parse the OEM Table */ --- linux-2.6.1-rc1/arch/i386/mach-voyager/voyager_smp.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/mach-voyager/voyager_smp.c 2003-12-30 22:50:14.000000000 -0800 @@ -130,7 +130,7 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi) { int cpu; - for_each_cpu(cpu, cpu_online_map) { + for_each_online_cpu(cpu) { if(cpuset & (1< #include #include +#include /* This sets the pointer FPU_info to point to the argument part of the stack frame of math_emulate() */ @@ -22,7 +23,7 @@ /* s is always from a cpu register, and the cpu does bounds checking * during register load --> no further bounds checks needed */ -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) --- linux-2.6.1-rc1/arch/i386/mm/extable.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/mm/extable.c 2003-12-30 22:50:18.000000000 -0800 @@ -6,6 +6,52 @@ #include #include #include +#include + +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of sections + * as well as the init section and the main kernel text section. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void fixup_sort_exception_table(void) +{ + struct exception_table_entry *p; + + /* + * Fix up the trampoline exception addresses: + */ + for (p = __start___ex_table; p < __stop___ex_table; p++) { + p->insn = (unsigned long)(void *)p->insn; + p->fixup = (unsigned long)(void *)p->fixup; + } + sort_ex_table(__start___ex_table, __stop___ex_table); +} /* Simple binary search */ const struct exception_table_entry * @@ -15,13 +61,15 @@ search_extable(const struct exception_ta { while (first <= last) { const struct exception_table_entry *mid; - long diff; mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) + /* + * careful, the distance between entries can be + * larger than 2GB: + */ + if (mid->insn == value) return mid; - else if (diff < 0) + else if (mid->insn < value) first = mid+1; else last = mid-1; --- linux-2.6.1-rc1/arch/i386/mm/fault.c 2003-12-17 21:20:01.000000000 -0800 +++ 25/arch/i386/mm/fault.c 2003-12-30 22:50:18.000000000 -0800 @@ -27,6 +27,7 @@ #include #include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -104,8 +105,17 @@ static inline unsigned long get_segment_ if (seg & (1<<2)) { /* Must lock the LDT while reading it. */ down(¤t->mm->context.sem); +#if 1 + /* horrible hack for 4/4 disabled kernels. + I'm not quite sure what the TLB flush is good for, + it's mindlessly copied from the read_ldt code */ + __flush_tlb_global(); + desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]); + desc = (void *)desc + ((seg & ~7) % PAGE_SIZE); +#else desc = current->mm->context.ldt; desc = (void *)desc + (seg & ~7); +#endif } else { /* Must disable preemption while reading the GDT. */ desc = (u32 *)&cpu_gdt_table[get_cpu()]; @@ -118,6 +128,9 @@ static inline unsigned long get_segment_ (desc[1] & 0xff000000); if (seg & (1<<2)) { +#if 1 + kunmap((void *)((unsigned long)desc & PAGE_MASK)); +#endif up(¤t->mm->context.sem); } else put_cpu(); @@ -243,6 +256,19 @@ asmlinkage void do_page_fault(struct pt_ * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ +#ifdef CONFIG_X86_4G + /* + * On 4/4 all kernels faults are either bugs, vmalloc or prefetch + */ + if (unlikely((regs->xcs & 3) == 0)) { + if (error_code & 3) + goto bad_area_nosemaphore; + + /* If it's vm86 fall through */ + if (!(regs->eflags & VM_MASK)) + goto vmalloc_fault; + } +#else if (unlikely(address >= TASK_SIZE)) { if (!(error_code & 5)) goto vmalloc_fault; @@ -252,6 +278,7 @@ asmlinkage void do_page_fault(struct pt_ */ goto bad_area_nosemaphore; } +#endif mm = tsk->mm; @@ -403,6 +430,12 @@ no_context: * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ +#ifdef CONFIG_KGDB + if (!user_mode(regs)){ + kgdb_handle_exception(14,SIGBUS, error_code, regs); + return; + } +#endif bust_spinlocks(1); --- linux-2.6.1-rc1/arch/i386/mm/init.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/mm/init.c 2003-12-30 22:50:18.000000000 -0800 @@ -40,125 +40,13 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; static int do_test_wp_bit(void); -/* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - if (pmd_table != pmd_offset(pgd, 0)) - BUG(); -#else - pmd_table = pmd_offset(pgd, 0); -#endif - - return pmd_table; -} - -/* - * Create a page table and place a pointer to it in a middle page - * directory entry. - */ -static pte_t * __init one_page_table_init(pmd_t *pmd) -{ - if (pmd_none(*pmd)) { - pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); - if (page_table != pte_offset_kernel(pmd, 0)) - BUG(); - - return page_table; - } - - return pte_offset_kernel(pmd, 0); -} - -/* - * This function initializes a certain range of kernel virtual memory - * with new bootmem page tables, everywhere page tables are missing in - * the given range. - */ - -/* - * NOTE: The pagetables are allocated contiguous on the physical space - * so we can cache the place of the first one and move around without - * checking the pgd every time. - */ -static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - int pgd_idx, pmd_idx; - unsigned long vaddr; - - vaddr = start; - pgd_idx = pgd_index(vaddr); - pmd_idx = pmd_index(vaddr); - pgd = pgd_base + pgd_idx; - - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - if (pgd_none(*pgd)) - one_md_table_init(pgd); - - pmd = pmd_offset(pgd, vaddr); - for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { - if (pmd_none(*pmd)) - one_page_table_init(pmd); - - vaddr += PMD_SIZE; - } - pmd_idx = 0; - } -} - -/* - * This maps the physical memory to kernel virtual address space, a total - * of max_low_pfn pages, by creating page tables starting from address - * PAGE_OFFSET. - */ -static void __init kernel_physical_mapping_init(pgd_t *pgd_base) -{ - unsigned long pfn; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int pgd_idx, pmd_idx, pte_ofs; - - pgd_idx = pgd_index(PAGE_OFFSET); - pgd = pgd_base + pgd_idx; - pfn = 0; - - for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - if (pfn >= max_low_pfn) - continue; - for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { - /* Map with big pages if possible, otherwise create normal page tables. */ - if (cpu_has_pse) { - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; - } else { - pte = one_page_table_init(pmd); - - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); - } - } - } -} - static inline int page_kills_ppro(unsigned long pagenr) { if (pagenr >= 0x70000 && pagenr <= 0x7003F) @@ -206,11 +94,8 @@ static inline int page_is_ram(unsigned l return 0; } -#ifdef CONFIG_HIGHMEM pte_t *kmap_pte; -pgprot_t kmap_prot; -EXPORT_SYMBOL(kmap_prot); EXPORT_SYMBOL(kmap_pte); #define kmap_get_fixmap_pte(vaddr) \ @@ -218,29 +103,7 @@ EXPORT_SYMBOL(kmap_pte); void __init kmap_init(void) { - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; -} - -void __init permanent_kmaps_init(pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long vaddr; - - vaddr = PKMAP_BASE; - page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + pgd_index(vaddr); - pmd = pmd_offset(pgd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; + kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); } void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) @@ -255,6 +118,8 @@ void __init one_highpage_init(struct pag SetPageReserved(page); } +#ifdef CONFIG_HIGHMEM + #ifndef CONFIG_DISCONTIGMEM void __init set_highmem_pages_init(int bad_ppro) { @@ -266,12 +131,9 @@ void __init set_highmem_pages_init(int b #else extern void set_highmem_pages_init(int); #endif /* !CONFIG_DISCONTIGMEM */ - #else -#define kmap_init() do { } while (0) -#define permanent_kmaps_init(pgd_base) do { } while (0) -#define set_highmem_pages_init(bad_ppro) do { } while (0) -#endif /* CONFIG_HIGHMEM */ +# define set_highmem_pages_init(bad_ppro) do { } while (0) +#endif unsigned long __PAGE_KERNEL = _PAGE_KERNEL; @@ -281,30 +143,125 @@ unsigned long __PAGE_KERNEL = _PAGE_KERN extern void __init remap_numa_kva(void); #endif -static void __init pagetable_init (void) +static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_base + pgd_index(address); + pmd = pmd_offset(pgd, address); + if (!pmd_present(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); + } +} + +static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) { unsigned long vaddr; - pgd_t *pgd_base = swapper_pg_dir; + for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE) + prepare_pagetables(pgd_base, vaddr); +} + +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) +{ + unsigned long vaddr; + pgd_t *pgd; + int i, j, k; + pmd_t *pmd; + pte_t *pte, *pte_base; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + if (cpu_has_pse) { + unsigned long __pe; + + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start; + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) + __pe += _PAGE_GLOBAL; + __PAGE_KERNEL |= _PAGE_GLOBAL; +#endif + } + set_pmd(pmd, __pmd(__pe)); + continue; + } + if (!pmd_present(*pmd)) + pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + else + pte_base = (pte_t *) page_address(pmd_page(*pmd)); + pte = pte_base; + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + *pte = mk_pte_phys(vaddr-start, PAGE_KERNEL); + } + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); + } + } +} + +static void __init pagetable_init (void) +{ + unsigned long vaddr, end; + pgd_t *pgd_base; #ifdef CONFIG_X86_PAE int i; - /* Init entries of the first-level page table to the zero page */ - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #endif - /* Enable PSE if available */ - if (cpu_has_pse) { - set_in_cr4(X86_CR4_PSE); - } + /* + * This can be zero as well - no problem, in that case we exit + * the loops anyway due to the PTRS_PER_* conditions. + */ + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); - /* Enable PGE if available */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); - __PAGE_KERNEL |= _PAGE_GLOBAL; + pgd_base = swapper_pg_dir; +#ifdef CONFIG_X86_PAE + /* + * It causes too many problems if there's no proper pmd set up + * for all 4 entries of the PGD - so we allocate all of them. + * PAE systems will not miss this extra 4-8K anyway ... + */ + for (i = 0; i < PTRS_PER_PGD; i++) { + pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1)); } +#endif + /* + * Set up lowmem-sized identity mappings at PAGE_OFFSET: + */ + setup_identity_mappings(pgd_base, PAGE_OFFSET, end); - kernel_physical_mapping_init(pgd_base); + /* + * Add flat-mode identity-mappings - SMP needs it when + * starting up on an AP from real-mode. (In the non-PAE + * case we already have these mappings through head.S.) + * All user-space mappings are explicitly cleared after + * SMP startup. + */ +#if CONFIG_SMP && CONFIG_X86_PAE + setup_identity_mappings(pgd_base, 0, 16*1024*1024); +#endif remap_numa_kva(); /* @@ -312,38 +269,64 @@ static void __init pagetable_init (void) * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - page_table_range_init(vaddr, 0, pgd_base); + fixrange_init(vaddr, 0, pgd_base); - permanent_kmaps_init(pgd_base); +#if CONFIG_HIGHMEM + { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + + pgd = swapper_pg_dir + pgd_index(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + pkmap_page_table = pte; + } #endif } -void zap_low_mappings (void) +/* + * Clear kernel pagetables in a PMD_SIZE-aligned range. + */ +static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { - int i; + unsigned long vaddr; + pgd_t *pgd; + pmd_t *pmd; + int i, j; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + pmd_clear(pmd); + } + } + flush_tlb_all(); +} + +void __init zap_low_mappings(void) +{ + printk("zapping low mappings.\n"); /* * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. */ - for (i = 0; i < USER_PTRS_PER_PGD; i++) -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - flush_tlb_all(); + clear_mappings(swapper_pg_dir, 0, 16*1024*1024); } #ifndef CONFIG_DISCONTIGMEM @@ -441,6 +424,7 @@ extern void set_max_mapnr_init(void); #endif /* !CONFIG_DISCONTIGMEM */ static struct kcore_list kcore_mem, kcore_vmalloc; +extern void fixup_sort_exception_table(void); void __init mem_init(void) { @@ -449,6 +433,8 @@ void __init mem_init(void) int tmp; int bad_ppro; + fixup_sort_exception_table(); + #ifndef CONFIG_DISCONTIGMEM if (!mem_map) BUG(); @@ -524,13 +510,18 @@ void __init mem_init(void) #ifndef CONFIG_SMP zap_low_mappings(); #endif + entry_trampoline_setup(); + default_ldt_page = virt_to_page(default_ldt); + load_LDT(&init_mm.context); } -kmem_cache_t *pgd_cache; -kmem_cache_t *pmd_cache; +kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; void __init pgtable_cache_init(void) { + void (*ctor)(void *, kmem_cache_t *, unsigned long); + void (*dtor)(void *, kmem_cache_t *, unsigned long); + if (PTRS_PER_PMD > 1) { pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), @@ -540,13 +531,36 @@ void __init pgtable_cache_init(void) NULL); if (!pmd_cache) panic("pgtable_cache_init(): cannot create pmd cache"); + + if (TASK_SIZE > PAGE_OFFSET) { + kpmd_cache = kmem_cache_create("kpmd", + PTRS_PER_PMD*sizeof(pmd_t), + 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, + kpmd_ctor, + NULL); + if (!kpmd_cache) + panic("pgtable_cache_init(): " + "cannot create kpmd cache"); + } } + + if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET) + ctor = pgd_ctor; + else + ctor = NULL; + + if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET) + dtor = pgd_dtor; + else + dtor = NULL; + pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD*sizeof(pgd_t), 0, SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, - pgd_ctor, - PTRS_PER_PMD == 1 ? pgd_dtor : NULL); + ctor, + dtor); if (!pgd_cache) panic("pgtable_cache_init(): Cannot create pgd cache"); } --- linux-2.6.1-rc1/arch/i386/mm/pgtable.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/i386/mm/pgtable.c 2003-12-30 22:50:18.000000000 -0800 @@ -21,6 +21,7 @@ #include #include #include +#include void show_mem(void) { @@ -157,11 +158,20 @@ void pmd_ctor(void *pmd, kmem_cache_t *c memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); } +void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags) +{ + pmd_t *kpmd, *pmd; + kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1], + (PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE); + pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS); + + memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t)); + memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t)); +} + /* - * List of all pgd's needed for non-PAE so it can invalidate entries - * in both cached and uncached pgd's; not needed for PAE since the - * kernel pmd is shared. If PAE were not to share the pmd a similar - * tactic would be needed. This is essentially codepath-based locking + * List of all pgd's needed so it can invalidate entries in both cached + * and uncached pgd's. This is essentially codepath-based locking * against pageattr.c; it is the unique case in which a valid change * of kernel pagetables can't be lazily synchronized by vmalloc faults. * vmalloc faults work because attached pagetables are never freed. @@ -170,30 +180,60 @@ void pmd_ctor(void *pmd, kmem_cache_t *c * could be used. The locking scheme was chosen on the basis of * manfred's recommendations and having no core impact whatsoever. * -- wli + * + * The entire issue goes away when XKVA is configured. */ spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(pgd_list); -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +/* + * This is not that hard to figure out. + * (a) PTRS_PER_PMD == 1 means non-PAE. + * (b) PTRS_PER_PMD > 1 means PAE. + * (c) TASK_SIZE > PAGE_OFFSET means XKVA. + * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA. + * + * Do *NOT* back out the preconstruction like the patch I'm cleaning + * up after this very instant did, or at all, for that matter. + * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET. + * -- wli + */ +void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused) { + pgd_t *pgd = (pgd_t *)__pgd; unsigned long flags; - if (PTRS_PER_PMD == 1) - spin_lock_irqsave(&pgd_lock, flags); + if (PTRS_PER_PMD == 1) { + if (TASK_SIZE <= PAGE_OFFSET) + spin_lock_irqsave(&pgd_lock, flags); + else + memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS], + &swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS], + NR_SHARED_PMDS * sizeof(pgd_t)); + } - memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + if (TASK_SIZE <= PAGE_OFFSET) + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); if (PTRS_PER_PMD > 1) return; - list_add(&virt_to_page(pgd)->lru, &pgd_list); - spin_unlock_irqrestore(&pgd_lock, flags); - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + if (TASK_SIZE > PAGE_OFFSET) + memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t)); + else { + list_add(&virt_to_page(pgd)->lru, &pgd_list); + spin_unlock_irqrestore(&pgd_lock, flags); + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + } } -/* never called when PTRS_PER_PMD > 1 */ +/* + * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET + * for with PAE we would list_del() multiple times, and for non-PAE + * with XKVA all the AGP pgd shootdown code is unnecessary. + */ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ @@ -203,6 +243,12 @@ void pgd_dtor(void *pgd, kmem_cache_t *c spin_unlock_irqrestore(&pgd_lock, flags); } +/* + * See the comments above pgd_ctor() wrt. preconstruction. + * Do *NOT* memcpy() here. If you do, you back out important + * anti- cache pollution code. + * + */ pgd_t *pgd_alloc(struct mm_struct *mm) { int i; @@ -211,15 +257,33 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (PTRS_PER_PMD == 1 || !pgd) return pgd; + /* + * In the 4G userspace case alias the top 16 MB virtual + * memory range into the user mappings as well (these + * include the trampoline and CPU data structures). + */ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { - pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + kmem_cache_t *cache; + pmd_t *pmd; + + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + pmd = kmem_cache_alloc(cache, GFP_KERNEL); if (!pmd) goto out_oom; set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd)))); } - return pgd; + return pgd; out_oom: + /* + * we don't have to handle the kpmd_cache here, since it's the + * last allocation, and has either nothing to free or when it + * succeeds the whole operation succeeds. + */ for (i--; i >= 0; i--) kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); kmem_cache_free(pgd_cache, pgd); @@ -230,10 +294,29 @@ void pgd_free(pgd_t *pgd) { int i; - /* in the PAE case user pgd entries are overwritten before usage */ - if (PTRS_PER_PMD > 1) - for (i = 0; i < USER_PTRS_PER_PGD; ++i) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); /* in the non-PAE case, clear_page_tables() clears user pgd entries */ + if (PTRS_PER_PMD == 1) + goto out_free; + + /* in the PAE case user pgd entries are overwritten before usage */ + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + kmem_cache_t *cache; + pmd_t *pmd = __va(pgd_val(pgd[i]) - 1); + + /* + * only userspace pmd's are cleared for us + * by mm/memory.c; it's a slab cache invariant + * that we must separate the kernel pmd slab + * all times, else we'll have bad pmd's. + */ + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + kmem_cache_free(cache, pmd); + } +out_free: kmem_cache_free(pgd_cache, pgd); } + --- linux-2.6.1-rc1/arch/i386/pci/acpi.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/i386/pci/acpi.c 2003-12-30 22:49:41.000000000 -0800 @@ -18,7 +18,7 @@ static int __init pci_acpi_init(void) if (pcibios_scanned) return 0; - if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { + if (!acpi_noirq) { if (!acpi_pci_irq_init()) { printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n"); @@ -31,15 +31,4 @@ static int __init pci_acpi_init(void) return 0; } - -/* - * pci_disable_acpi() - * act like pci=noacpi seen on command line - * called by DMI blacklist code - */ -__init void pci_disable_acpi(void) -{ - pci_probe |= PCI_NO_ACPI_ROUTING; -} - subsys_initcall(pci_acpi_init); --- linux-2.6.1-rc1/arch/i386/pci/common.c 2003-09-08 13:58:55.000000000 -0700 +++ 25/arch/i386/pci/common.c 2003-12-30 22:49:41.000000000 -0800 @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -197,12 +198,10 @@ char * __devinit pcibios_setup(char *st return NULL; } #endif -#ifdef CONFIG_ACPI_PCI else if (!strcmp(str, "noacpi")) { - pci_probe |= PCI_NO_ACPI_ROUTING; + acpi_noirq_set(); return NULL; } -#endif #ifndef CONFIG_X86_VISWS else if (!strcmp(str, "usepirqmask")) { pci_probe |= PCI_USE_PIRQ_MASK; --- linux-2.6.1-rc1/arch/i386/pci/fixup.c 2003-08-08 22:55:10.000000000 -0700 +++ 25/arch/i386/pci/fixup.c 2003-12-30 22:50:13.000000000 -0800 @@ -187,6 +187,22 @@ static void __devinit pci_fixup_transpar dev->transparent = 1; } +/* + * Halt Disconnect and Stop Grant Disconnect (bit 4 at offset 0x6F) + * must be disabled when APIC is used (or lockups will happen). + */ +static void __devinit pci_fixup_nforce2_disconnect(struct pci_dev *d) +{ + u8 t; + + pci_read_config_byte(d, 0x6F, &t); + if (t & 0x10) { + printk(KERN_INFO "PCI: disabling nForce2 Halt Disconnect" + " and Stop Grant Disconnect\n"); + pci_write_config_byte(d, 0x6F, (t & 0xef)); + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, @@ -205,5 +221,6 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2_disconnect }, { 0 } }; --- linux-2.6.1-rc1/arch/i386/pci/pci.h 2003-06-22 12:04:43.000000000 -0700 +++ 25/arch/i386/pci/pci.h 2003-12-30 22:49:41.000000000 -0800 @@ -22,7 +22,6 @@ #define PCI_ASSIGN_ROMS 0x1000 #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 -#define PCI_NO_ACPI_ROUTING 0x8000 extern unsigned int pci_probe; --- linux-2.6.1-rc1/arch/ia64/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/Kconfig 2003-12-30 22:50:17.000000000 -0800 @@ -667,6 +667,13 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + endmenu source "security/Kconfig" --- linux-2.6.1-rc1/arch/ia64/kernel/perfmon.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/kernel/perfmon.c 2003-12-30 22:49:34.000000000 -0800 @@ -2157,6 +2157,7 @@ pfm_alloc_fd(struct file **cfile) d_add(file->f_dentry, inode); file->f_vfsmnt = mntget(pfmfs_mnt); + file->f_mapping = inode->i_mapping; file->f_op = &pfm_file_ops; file->f_mode = FMODE_READ; --- linux-2.6.1-rc1/arch/parisc/kernel/sys_parisc.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/parisc/kernel/sys_parisc.c 2003-12-30 22:49:36.000000000 -0800 @@ -93,17 +93,13 @@ static unsigned long get_shared_area(str unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct inode *inode; - if (len > TASK_SIZE) return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - inode = filp ? filp->f_dentry->d_inode : NULL; - - if (inode && (flags & MAP_SHARED)) { - addr = get_shared_area(inode->i_mapping, addr, len, pgoff); + if (filp && (flags & MAP_SHARED)) { + addr = get_shared_area(filp->f_mapping, addr, len, pgoff); } else { addr = get_unshared_area(addr, len); } --- linux-2.6.1-rc1/arch/ppc64/kernel/irq.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ppc64/kernel/irq.c 2003-12-30 22:49:45.000000000 -0800 @@ -300,7 +300,7 @@ void enable_irq(unsigned int irq) spin_lock_irqsave(&desc->lock, flags); switch (desc->depth) { case 1: { - unsigned int status = desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS); + unsigned int status = desc->status & ~IRQ_DISABLED; desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status = status | IRQ_REPLAY; --- linux-2.6.1-rc1/arch/ppc64/kernel/misc.S 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/ppc64/kernel/misc.S 2003-12-30 22:49:44.000000000 -0800 @@ -843,15 +843,15 @@ _GLOBAL(sys_call_table32) .llong .sys_ni_syscall .llong .sys_ni_syscall .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 245 */ - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall + .llong .compat_clock_settime /* 245 */ + .llong .compat_clock_gettime + .llong .compat_clock_getres + .llong .compat_clock_nanosleep + .llong .sys_ni_syscall /* 249 swapcontext */ .llong .sys32_tgkill /* 250 */ .llong .sys32_utimes - .llong .sys_statfs64 - .llong .sys_fstatfs64 + .llong .compat_statfs64 + .llong .compat_fstatfs64 .balign 8 _GLOBAL(sys_call_table) --- linux-2.6.1-rc1/arch/ppc64/kernel/time.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/ppc64/kernel/time.c 2003-12-30 22:49:44.000000000 -0800 @@ -91,6 +91,9 @@ unsigned tb_to_us; unsigned long processor_freq; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +unsigned long tb_to_ns_scale; +unsigned long tb_to_ns_shift; + struct gettimeofday_struct do_gtod; extern unsigned long wall_jiffies; @@ -313,11 +316,13 @@ int timer_interrupt(struct pt_regs * reg /* * Scheduler clock - returns current time in nanosec units. * - * This is wrong, but my CPUs run at 1GHz, so nyer nyer. + * Note: mulhdu(a, b) (multiply high double unsigned) returns + * the high 64 bits of a * b, i.e. (a * b) >> 64, where a and b + * are 64-bit unsigned numbers. */ unsigned long long sched_clock(void) { - return get_tb(); + return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; } /* @@ -473,9 +478,30 @@ void __init time_init(void) /* This function is only called on the boot processor */ unsigned long flags; struct rtc_time tm; + struct div_result res; + unsigned long scale, shift; ppc_md.calibrate_decr(); + /* + * Compute scale factor for sched_clock. + * The calibrate_decr() function has set tb_ticks_per_sec, + * which is the timebase frequency. + * We compute 1e9 * 2^64 / tb_ticks_per_sec and interpret + * the 128-bit result as a 64.64 fixed-point number. + * We then shift that number right until it is less than 1.0, + * giving us the scale factor and shift count to use in + * sched_clock(). + */ + div128_by_32(1000000000, 0, tb_ticks_per_sec, &res); + scale = res.result_low; + for (shift = 0; res.result_high != 0; ++shift) { + scale = (scale >> 1) | (res.result_high << 63); + res.result_high >>= 1; + } + tb_to_ns_scale = scale; + tb_to_ns_shift = shift; + #ifdef CONFIG_PPC_ISERIES if (!piranha_simulator) #endif --- linux-2.6.1-rc1/arch/ppc64/mm/numa.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/ppc64/mm/numa.c 2003-12-30 22:49:44.000000000 -0800 @@ -108,7 +108,7 @@ static int __init parse_numa_properties( for (memory = find_type_devices("memory"); memory; memory = memory->next) { - int *tmp1, *tmp2; + unsigned int *tmp1, *tmp2; unsigned long i; unsigned long start = 0; unsigned long size = 0; --- linux-2.6.1-rc1/arch/ppc/boot/ld.script 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/ppc/boot/ld.script 2003-12-30 22:50:19.000000000 -0800 @@ -82,6 +82,7 @@ SECTIONS *(__ksymtab) *(__ksymtab_strings) *(__bug_table) + *(__kcrctab) } } --- linux-2.6.1-rc1/arch/ppc/kernel/Makefile 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/ppc/kernel/Makefile 2003-12-30 22:49:58.000000000 -0800 @@ -9,8 +9,7 @@ ifdef CONFIG_4xx EXTRA_AFLAGS := -Wa,-m405 endif -# Start off with 'head.o', change as needed. -extra-y := head.o +extra-$(CONFIG_PPC_STD_MMU) := head.o extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_8xx) := head_8xx.o --- linux-2.6.1-rc1/arch/ppc/kernel/ppc_ksyms.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ppc/kernel/ppc_ksyms.c 2003-12-30 22:49:58.000000000 -0800 @@ -92,7 +92,7 @@ EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); -EXPORT_SYMBOL_NOVERS(DMA_MODE_READ); +EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); #if defined(CONFIG_PPC_PREP) EXPORT_SYMBOL(_prep_type); @@ -167,9 +167,9 @@ EXPORT_SYMBOL(ppc_ide_md); #endif #ifdef CONFIG_PCI -EXPORT_SYMBOL_NOVERS(isa_io_base); -EXPORT_SYMBOL_NOVERS(isa_mem_base); -EXPORT_SYMBOL_NOVERS(pci_dram_offset); +EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(isa_mem_base); +EXPORT_SYMBOL(pci_dram_offset); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_bus_io_base); @@ -246,7 +246,7 @@ EXPORT_SYMBOL(register_backlight_control EXPORT_SYMBOL(_machine); #endif #ifdef CONFIG_PPC_PMAC -EXPORT_SYMBOL_NOVERS(sys_ctrler); +EXPORT_SYMBOL(sys_ctrler); EXPORT_SYMBOL(pmac_newworld); #endif #ifdef CONFIG_PPC_OF @@ -294,15 +294,15 @@ EXPORT_SYMBOL(to_tm); EXPORT_SYMBOL(pm_power_off); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memchr); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(abs); @@ -366,7 +366,7 @@ EXPORT_SYMBOL(request_8xxirq); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(handle_mm_fault); /* For MOL */ -EXPORT_SYMBOL_NOVERS(disarm_decr); +EXPORT_SYMBOL(disarm_decr); #ifdef CONFIG_PPC_STD_MMU extern long mol_trampoline; EXPORT_SYMBOL(mol_trampoline); /* For MOL */ @@ -381,5 +381,5 @@ EXPORT_SYMBOL(intercept_table); EXPORT_SYMBOL(cur_cpu_spec); #ifdef CONFIG_PPC_PMAC extern unsigned long agp_special_page; -EXPORT_SYMBOL_NOVERS(agp_special_page); +EXPORT_SYMBOL(agp_special_page); #endif --- linux-2.6.1-rc1/arch/ppc/mm/cachemap.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/ppc/mm/cachemap.c 2003-12-30 22:49:57.000000000 -0800 @@ -170,3 +170,5 @@ void consistent_sync_page(struct page *p start = (unsigned long)page_address(page) + offset; consistent_sync((void *)start, size, direction); } + +EXPORT_SYMBOL(consistent_sync_page); --- linux-2.6.1-rc1/arch/ppc/platforms/mpc82xx.h 2003-09-27 18:57:43.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,42 +0,0 @@ -/* - * arch/ppc/platforms/mpc82xx.h - * - * Board specific support for various 82xx platforms. - * - * Author: Allen Curtis - * - * Copyright 2002 Ones and Zeros, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#ifndef __CONFIG_82XX_PLATFORMS -#define __CONFIG_82XX_PLATFORMS - -#ifdef CONFIG_8260 - -#ifdef CONFIG_EST8260 -#include -#endif - -#ifdef CONFIG_SBS8260 -#include -#endif - -#ifdef CONFIG_RPX6 -#include -#endif - -#ifdef CONFIG_WILLOW -#include -#endif - -#ifdef CONFIG_TQM8260 -#include -#endif - -#endif /* CONFIG_8260 */ - -#endif --- linux-2.6.1-rc1/arch/sparc64/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/sparc64/Kconfig 2003-12-30 22:50:17.000000000 -0800 @@ -840,12 +840,19 @@ config STACK_DEBUG depends on DEBUG_KERNEL bool "Stack Overflow Detection Support" +config LOCKMETER + bool "Kernel lock metering" + depends on SMP && !PREEMPT + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + # We have a custom atomic_dec_and_lock() implementation but it's not # compatible with spinlock debugging so we need to fall back on # the generic version in that case. config HAVE_DEC_LOCK bool - depends on SMP && !DEBUG_SPINLOCK + depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER default y config MCOUNT --- linux-2.6.1-rc1/arch/sparc64/lib/rwlock.S 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/sparc64/lib/rwlock.S 2003-12-30 22:50:17.000000000 -0800 @@ -85,5 +85,20 @@ __write_trylock_succeed: __write_trylock_fail: retl mov 0, %o0 + + .globl __read_trylock +__read_trylock: /* %o0 = lock_ptr */ + ldsw [%o0], %g5 + brlz,pn %g5, 100f + add %g5, 1, %g7 + cas [%o0], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __read_trylock + membar #StoreLoad | #StoreStore + retl + mov 1, %o0 +100: retl + mov 0, %o0 + rwlock_impl_end: --- linux-2.6.1-rc1/arch/um/drivers/ubd_kern.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/um/drivers/ubd_kern.c 2003-12-30 22:49:33.000000000 -0800 @@ -49,9 +49,9 @@ static spinlock_t ubd_lock = SPIN_LOCK_U static void (*do_ubd)(void); -static int ubd_open(struct inode * inode, struct file * filp); -static int ubd_release(struct inode * inode, struct file * file); -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_open(struct block_device *bdev, struct file * filp); +static int ubd_release(struct gendisk *disk); +static int ubd_ioctl(struct block_device *bdev, struct file * file, unsigned int cmd, unsigned long arg); #define MAX_DEV (8) @@ -710,9 +710,9 @@ int ubd_driver_init(void){ device_initcall(ubd_driver_init); -static int ubd_open(struct inode *inode, struct file *filp) +static int ubd_open(struct block_device *bdev, struct file *filp) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct ubd *dev = disk->private_data; int err = -EISDIR; @@ -739,9 +739,8 @@ static int ubd_open(struct inode *inode, return(err); } -static int ubd_release(struct inode * inode, struct file * file) +static int ubd_release(struct gendisk *disk) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; if(--dev->count == 0) @@ -865,11 +864,11 @@ static void do_ubd_request(request_queue } } -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_ioctl(struct block_device *bdev, struct file * file, unsigned int cmd, unsigned long arg) { struct hd_geometry *loc = (struct hd_geometry *) arg; - struct ubd *dev = inode->i_bdev->bd_disk->private_data; + struct ubd *dev = bdev->bd_disk->private_data; int err; struct hd_driveid ubd_id = { .cyls = 0, @@ -890,7 +889,7 @@ static int ubd_ioctl(struct inode * inod case HDIO_SET_UNMASKINTR: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || (inode->i_bdev->bd_contains != inode->i_bdev)) + if((arg > 1) || (bdev->bd_contains != bdev)) return(-EINVAL); return(0); @@ -910,7 +909,7 @@ static int ubd_ioctl(struct inode * inod case HDIO_SET_MULTCOUNT: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if(inode->i_bdev->bd_contains != inode->i_bdev) + if(bdev->bd_contains != bdev) return(-EINVAL); return(0); --- linux-2.6.1-rc1/arch/x86_64/boot/compressed/head.S 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/x86_64/boot/compressed/head.S 2003-12-30 22:49:25.000000000 -0800 @@ -26,6 +26,7 @@ .code32 .text +#define IN_BOOTLOADER #include #include --- linux-2.6.1-rc1/arch/x86_64/boot/compressed/misc.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/x86_64/boot/compressed/misc.c 2003-12-30 22:49:25.000000000 -0800 @@ -9,6 +9,7 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#define IN_BOOTLOADER #include "miscsetup.h" #include --- linux-2.6.1-rc1/arch/x86_64/kernel/acpi/boot.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/x86_64/kernel/acpi/boot.c 2003-12-30 22:49:41.000000000 -0800 @@ -46,11 +46,13 @@ #include #include -int acpi_lapic = 0; -int acpi_ioapic = 0; - #define PREFIX "ACPI: " +int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +int acpi_ht __initdata = 1; /* enable HT */ + +int acpi_lapic = 0; +int acpi_ioapic = 0; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -253,29 +255,66 @@ acpi_parse_hpet ( #ifdef CONFIG_ACPI_BUS /* - * Set specified PIC IRQ to level triggered mode. + * "acpi_pic_sci=level" (current default) + * 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 + * it may require Edge Trigger -- use "acpi_pic_sci=edge" + * (NO-OP if the BIOS set Edge Trigger already) * * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) - * - * As the BIOS should have done this for us, - * print a warning if the IRQ wasn't already set to level. */ -void acpi_pic_set_level_irq(unsigned int irq) +static int __initdata acpi_pic_sci_trigger; /* 0: level, 1: edge */ + +void __init +acpi_pic_sci_set_trigger(unsigned int irq) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); unsigned char val = inb(port); + + printk(PREFIX "IRQ%d SCI:", irq); if (!(val & mask)) { - printk(KERN_WARNING PREFIX "IRQ %d was Edge Triggered, " - "setting to Level Triggerd\n", irq); - outb(val | mask, port); + printk(" Edge"); + + if (!acpi_pic_sci_trigger) { + printk(" set to Level"); + outb(val | mask, port); + } + } else { + printk(" Level"); + + if (acpi_pic_sci_trigger) { + printk(" set to Edge"); + outb(val | mask, port); + } } + printk(" Trigger.\n"); } + +int __init +acpi_pic_sci_setup(char *str) +{ + while (str && *str) { + if (strncmp(str, "level", 5) == 0) + acpi_pic_sci_trigger = 0; /* force level trigger */ + if (strncmp(str, "edge", 4) == 0) + acpi_pic_sci_trigger = 1; /* force edge trigger */ + str = strchr(str, ','); + if (str) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("acpi_pic_sci=", acpi_pic_sci_setup); + #endif /* CONFIG_ACPI_BUS */ static unsigned long __init @@ -354,8 +393,10 @@ acpi_boot_init (void) * Initialize the ACPI boot-time table parser. */ result = acpi_table_init(); - if (result) + if (result) { + acpi_disabled = 1; return result; + } result = acpi_blacklisted(); if (result) { @@ -442,7 +483,7 @@ acpi_boot_init (void) * If MPS is present, it will handle them, * otherwise the system will stay in PIC mode */ - if (acpi_disabled) { + if (acpi_disabled || acpi_noirq) { return 1; } @@ -484,6 +525,8 @@ acpi_boot_init (void) acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; #endif /*CONFIG_X86_IO_APIC*/ --- linux-2.6.1-rc1/arch/x86_64/kernel/io_apic.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/x86_64/kernel/io_apic.c 2003-12-30 22:49:41.000000000 -0800 @@ -1087,8 +1087,6 @@ static void __init setup_ioapic_ids_from unsigned char old_id; unsigned long flags; - if (acpi_ioapic) return; /* ACPI does that already */ - /* * Set the IOAPIC ID to the value stored in the MPC table. */ @@ -1673,12 +1671,14 @@ void __init setup_IO_APIC(void) /* * Set up the IO-APIC IRQ routing table. */ - setup_ioapic_ids_from_mpc(); + if (!acpi_ioapic) + setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); - print_IO_APIC(); + if (!acpi_ioapic) + print_IO_APIC(); } /* Ensure the ACPI SCI interrupt level is active low, edge-triggered */ --- linux-2.6.1-rc1/arch/x86_64/kernel/mpparse.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/kernel/mpparse.c 2003-12-30 22:49:41.000000000 -0800 @@ -950,6 +950,8 @@ void __init mp_parse_prt (void) entry->irq); } + print_IO_APIC(); + return; } --- linux-2.6.1-rc1/arch/x86_64/kernel/setup.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/x86_64/kernel/setup.c 2003-12-30 22:49:41.000000000 -0800 @@ -65,7 +65,11 @@ unsigned long mmu_cr4_features; EXPORT_SYMBOL_GPL(mmu_cr4_features); int acpi_disabled = 0; -int acpi_ht = 0; + +#ifdef CONFIG_ACPI_BOOT +extern int __initdata acpi_ht; +/* int __initdata acpi_force = 0; */ +#endif /* For PCI or other memory-mapped resources */ unsigned long pci_mem_start = 0x10000000; @@ -195,6 +199,7 @@ static __init void parse_cmdline_early ( if (c != ' ') goto next_char; +#ifdef CONFIG_ACPI_BOOT /* "acpi=off" disables both ACPI table parsing and interpreter init */ if (!memcmp(from, "acpi=off", 8)) acpi_disabled = 1; @@ -210,6 +215,7 @@ static __init void parse_cmdline_early ( if (!memcmp(from, "acpi=ht", 7)) { acpi_ht = 1; } +#endif if (!memcmp(from, "nolapic", 7) || !memcmp(from, "disableapic", 11)) --- linux-2.6.1-rc1/Documentation/Changes 2003-10-08 15:07:08.000000000 -0700 +++ 25/Documentation/Changes 2003-12-30 22:49:58.000000000 -0800 @@ -56,7 +56,7 @@ o module-init-tools 0.9.10 o e2fsprogs 1.29 # tune2fs o jfsutils 1.1.3 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs -o xfsprogs 2.1.0 # xfs_db -V +o xfsprogs 2.6.0 # xfs_db -V o pcmcia-cs 3.1.21 # cardmgr -V o quota-tools 3.09 # quota -V o PPP 2.4.0 # pppd --version @@ -183,9 +183,8 @@ Xfsprogs The latest version of xfsprogs contains mkfs.xfs, xfs_db, and the xfs_repair utilities, among others, for the XFS filesystem. It is architecture independent and any version from 2.0.0 onward should -work correctly with this version of the XFS kernel code. For the new -(v2) log format that has better support for stripe-size aligning on -LVM and MD devices at least xfsprogs 2.1.0 is needed. +work correctly with this version of the XFS kernel code (2.6.0 or +later is recommended, due to some significant improvements). Pcmcia-cs @@ -359,7 +358,7 @@ o +o Pcmcia-cs --------- --- linux-2.6.1-rc1/Documentation/DocBook/kernel-locking.tmpl 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/DocBook/kernel-locking.tmpl 2003-12-30 22:50:15.000000000 -0800 @@ -66,6 +66,7 @@ fundamentals of concurrency and locking for SMP. + The Problem With Concurrency @@ -193,6 +194,7 @@ And then there are the unfriendly primitives, but I'll pretend they don't exist. + @@ -657,6 +659,7 @@ + @@ -1110,6 +1113,7 @@ used to protect the reference count itse return obj; } + @@ -1229,6 +1233,7 @@ which locks. This is extremely importan behavior of the code, and can be hard to gain from just reading. And as Alan Cox says, Lock data, not code. + @@ -1317,6 +1322,7 @@ as Alan Cox says, Lock data, not The two CPUs will spin forever, waiting for the other to give up their lock. It will look, smell, and feel like a crash. + Preventing Deadlock @@ -1886,6 +1892,7 @@ machines due to caching. + Some Functions Which Don't Sleep --- linux-2.6.1-rc1/Documentation/filesystems/proc.txt 2003-11-09 16:45:05.000000000 -0800 +++ 25/Documentation/filesystems/proc.txt 2003-12-30 22:50:20.000000000 -0800 @@ -900,6 +900,15 @@ super-nr shows the number of currently a Every mounted file system needs a super block, so if you plan to mount lots of file systems, you may want to increase these numbers. +aio-nr and aio-max-nr +--------------------- + +aio-nr is the running total of the number of events specified on the +io_setup system call for all currently active aio contexts. If aio-nr +reaches aio-max-nr then io_setup will fail with EAGAIN. Note that +raising aio-max-nr does not result in the pre-allocation or re-sizing +of any kernel data structures. + 2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats ----------------------------------------------------------- --- linux-2.6.1-rc1/Documentation/filesystems/xfs.txt 2003-10-17 15:58:03.000000000 -0700 +++ 25/Documentation/filesystems/xfs.txt 2003-12-30 22:49:58.000000000 -0800 @@ -29,10 +29,11 @@ When mounting an XFS filesystem, the fol The preferred buffered I/O size can also be altered on an individual file basis using the ioctl(2) system call. - ikeep + ikeep/noikeep When inode clusters are emptied of inodes, keep them around - on the disk, this is the old XFS behavior. Default is now to - return the inode cluster to the free space pool. + on the disk (ikeep) - this is the traditional XFS behaviour + and is still the default for now. Using the noikeep option, + inode clusters are returned to the free space pool. logbufs=value Set the number of in-memory log buffers. Valid numbers range @@ -75,6 +76,10 @@ When mounting an XFS filesystem, the fol Filesystems mounted "norecovery" must be mounted read-only or the mount will fail. + nouuid + Don't check for double mounted file systems using the file system uuid. + This is useful to mount LVM snapshot volumes. + osyncisosync Make O_SYNC writes implement true O_SYNC. WITHOUT this option, Linux XFS behaves as if an "osyncisdsync" option is used, @@ -108,10 +113,6 @@ When mounting an XFS filesystem, the fol The "swidth" option is required if the "sunit" option has been specified, and must be a multiple of the "sunit" value. - nouuid - Don't check for double mounted file systems using the file system uuid. - This is useful to mount LVM snapshot volumes. - sysctls ======= @@ -139,14 +140,14 @@ The following sysctls are available for Causes certain error conditions to call BUG(). Value is a bitmask; AND together the tags which represent errors which should cause panics: - XFS_NO_PTAG 0LL - XFS_PTAG_IFLUSH 0x0000000000000001LL - XFS_PTAG_LOGRES 0x0000000000000002LL - XFS_PTAG_AILDELETE 0x0000000000000004LL - XFS_PTAG_ERROR_REPORT 0x0000000000000008LL - XFS_PTAG_SHUTDOWN_CORRUPT 0x0000000000000010LL - XFS_PTAG_SHUTDOWN_IOERROR 0x0000000000000020LL - XFS_PTAG_SHUTDOWN_LOGERROR 0x0000000000000040LL + XFS_NO_PTAG 0 + XFS_PTAG_IFLUSH 0x00000001 + XFS_PTAG_LOGRES 0x00000002 + XFS_PTAG_AILDELETE 0x00000004 + XFS_PTAG_ERROR_REPORT 0x00000008 + XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010 + XFS_PTAG_SHUTDOWN_IOERROR 0x00000020 + XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040 This option is intended for debugging only. @@ -165,6 +166,21 @@ The following sysctls are available for Controls whether unprivileged users can use chown to "give away" a file to another user. + fs.xfs.inherit_sync (Min: 0 Default: 1 Max 1) + Setting this to "1" will cause the "sync" flag set + by the chattr(1) command on a directory to be + inherited by files in that directory. + + fs.xfs.inherit_nodump (Min: 0 Default: 1 Max 1) + Setting this to "1" will cause the "nodump" flag set + by the chattr(1) command on a directory to be + inherited by files in that directory. + + fs.xfs.inherit_noatime (Min: 0 Default: 1 Max 1) + Setting this to "1" will cause the "noatime" flag set + by the chattr(1) command on a directory to be + inherited by files in that directory. + vm.pagebuf.stats_clear (Min: 0 Default: 0 Max: 1) Setting this to "1" clears accumulated pagebuf statistics in /proc/fs/pagebuf/stat. It then immediately reset to "0". --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/andthen 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,100 @@ + +define set_andthen + set var $thp=0 + set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0] + set var $at_size = (sizeof kgdb_data)/(sizeof *$thp) + set var $at_oc=kgdb_and_then_count + set var $at_cc=$at_oc +end + +define andthen_next + set var $at_cc=$arg0 +end + +define andthen + andthen_set_edge + if ($at_cc >= $at_oc) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc + output *($thp+($at_cc++ % $at_size )) + printf "\n" + end +end +define andthen_set_edge + set var $at_oc=kgdb_and_then_count + set var $at_low = $at_oc - $at_size + if ($at_low < 0 ) + set var $at_low = 0 + end + if (( $at_cc > $at_oc) || ($at_cc < $at_low)) + printf "Count outside of window, setting count to " + if ($at_cc >= $at_oc) + set var $at_cc = $at_oc + else + set var $at_cc = $at_low + end + printf "%d\n",$at_cc + end +end + +define beforethat + andthen_set_edge + if ($at_cc <= $at_low) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc-1 + output *($thp+(--$at_cc % $at_size )) + printf "\n" + end +end + +document andthen_next + andthen_next + . sets the number of the event to display next. If this event + . is not in the event pool, either andthen or beforethat will + . correct it to the nearest event pool edge. The event pool + . ends at the last event recorded and begins + . prior to that. If beforethat is used next, it will display + . event -1. +. + andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + + +document andthen + andthen +. displays the next event in the list. sets up to display +. the oldest saved event first. +. (optional) count of the event to display. +. note the number of events saved is specified at configure time. +. if events are saved between calls to andthen the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document set_andthen + set_andthen +. sets up to use the and commands. +. if you have defined your own struct, use the above and +. then enter the following: +. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0] +. where is the name of your structure. +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document beforethat + beforethat +. displays the next prior event in the list. sets up to +. display the last occuring event first. +. +. note the number of events saved is specified at configure time. +. if events are saved between calls to beforethat the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/debug-nmi.txt 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,37 @@ +Subject: Debugging with NMI +Date: Mon, 12 Jul 1999 11:28:31 -0500 +From: David Grothe +Organization: Gcom, Inc +To: David Grothe + +Kernel hackers: + +Maybe this is old hat, but it is new to me -- + +On an ISA bus machine, if you short out the A1 and B1 pins of an ISA +slot you will generate an NMI to the CPU. This interrupts even a +machine that is hung in a loop with interrupts disabled. Used in +conjunction with kgdb < +ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can +gain debugger control of a machine that is hung in the kernel! Even +without kgdb the kernel will print a stack trace so you can find out +where it was hung. + +The A1/B1 pins are directly opposite one another and the farthest pins +towards the bracket end of the ISA bus socket. You can stick a paper +clip or multi-meter probe between them to short them out. + +I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the +board consists of two rows of wire wrap pins. So I wired a push button +between the A1/B1 pins and now have an ISA board that I can stick into +any ISA bus slot for debugger entry. + +Microsoft has a circuit diagram of a PCI card at +http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to +build one you will have to mail them and ask for the PAL equations. +Nobody makes one comercially. + +[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if +your machine catches fire, it is your problem, not mine.] + +-- Dave (the kgdb guy) --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdb-globals.txt 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,71 @@ +Sender: akale@veritas.com +Date: Fri, 23 Jun 2000 19:26:35 +0530 +From: "Amit S. Kale" +Organization: Veritas Software (India) +To: Dave Grothe , linux-kernel@vger.rutgers.edu +CC: David Milburn , + "Edouard G. Parmelan" , + ezannoni@cygnus.com, Keith Owens +Subject: Re: Module debugging using kgdb + +Dave Grothe wrote: +> +> Amit: +> +> There is a 2.4.0 version of kgdb on our ftp site: +> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb +> and loadmodule.sh there. +> +> Have a look at the README file and see if I go it right. If not, send +> me some corrections and I will update it. +> +> Does your version of gdb solve the global variable problem? + +Yes. +Thanks to Elena Zanoni, gdb (developement version) can now calculate +correctly addresses of dynamically loaded object files. I have not been +following gdb developement for sometime and am not sure when symbol +address calculation fix is going to appear in a gdb stable version. + +Elena, any idea when the fix will make it to a prebuilt gdb from a +redhat release? + +For the time being I have built a gdb developement version. It can be +used for module debugging with loadmodule.sh script. + +The problem with calculating of module addresses with previous versions +of gdb was as follows: +gdb did not use base address of a section while calculating address of +a symbol in the section in an object file loaded via 'add-symbol-file'. +It used address of .text segment instead. Due to this addresses of +symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly. + +Above mentioned fix allow gdb to use base address of a segment while +calculating address of a symbol in it. It adds a parameter '-s' to +'add-symbol-file' command for specifying base address of a segment. + +loadmodule.sh script works as follows. + +1. Copy a module file to target machine. +2. Load the module on the target machine using insmod with -m parameter. +insmod produces a module load map which contains base addresses of all +sections in the module and addresses of symbols in the module file. +3. Find all sections and their base addresses in the module from +the module map. +4. Generate a script that loads the module file. The script uses +'add-symbol-file' and specifies address of text segment followed by +addresses of all segments in the module. + +Here is an example gdb script produced by loadmodule.sh script. + +add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5 +-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38 +-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838 + +With this command gdb can calculate addresses of symbols in ANY segment +in a module file. + +Regards. +-- +Amit Kale +Veritas Software ( http://www.veritas.com ) --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,14 @@ +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 +target remote /dev/ttyS0 +define si +stepi +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip +end +define ni +nexti +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit.hw 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,117 @@ + +#Using ia-32 hardware breakpoints. +# +#4 hardware breakpoints are available in ia-32 processors. These breakpoints +#do not need code modification. They are set using debug registers. +# +#Each hardware breakpoint can be of one of the +#three types: execution, write, access. +#1. An Execution breakpoint is triggered when code at the breakpoint address is +#executed. +#2. A write breakpoint ( aka watchpoints ) is triggered when memory location +#at the breakpoint address is written. +#3. An access breakpoint is triggered when memory location at the breakpoint +#address is either read or written. +# +#As hardware breakpoints are available in limited number, use software +#breakpoints ( br command in gdb ) instead of execution hardware breakpoints. +# +#Length of an access or a write breakpoint defines length of the datatype to +#be watched. Length is 1 for char, 2 short , 3 int. +# +#For placing execution, write and access breakpoints, use commands +#hwebrk, hwwbrk, hwabrk +#To remove a breakpoint use hwrmbrk command. +# +#These commands take following types of arguments. For arguments associated +#with each command, use help command. +#1. breakpointno: 0 to 3 +#2. length: 1 to 3 +#3. address: Memory location in hex ( without 0x ) e.g c015e9bc +# +#Use the command exinfo to find which hardware breakpoint occured. + +#hwebrk breakpointno address +define hwebrk + maintenance packet Y$arg0,0,0,$arg1 +end +document hwebrk + hwebrk
+ Places a hardware execution breakpoint + = 0 - 3 +
= Hex digits without leading "0x". +end + +#hwwbrk breakpointno length address +define hwwbrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwwbrk + hwwbrk
+ Places a hardware write breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwabrk breakpointno length address +define hwabrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwabrk + hwabrk
+ Places a hardware access breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwrmbrk breakpointno +define hwrmbrk + maintenance packet y$arg0 +end +document hwrmbrk + hwrmbrk + = 0 - 3 + Removes a hardware breakpoint +end + +define reboot + maintenance packet r +end +#exinfo +define exinfo + maintenance packet qE +end +document exinfo + exinfo + Gives information about a breakpoint. +end +define get_th + p $th=(struct thread_info *)((int)$esp & ~8191) +end +document get_th + get_tu + Gets and prints the current thread_info pointer, Defines th to be it. +end +define get_cu + p $cu=((struct thread_info *)((int)$esp & ~8191))->task +end +document get_cu + get_cu + Gets and print the "current" value. Defines $cu to be it. +end +define int_off + set var $flags=$eflags + set $eflags=$eflags&~0x200 + end +define int_on + set var $eflags|=$flags&0x200 + end +document int_off + saves the current interrupt state and clears the processor interrupt + flag. Use int_on to restore the saved flag. +end +document int_on + Restores the interrupt flag saved by int_off. +end --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit-modules 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,146 @@ +# +# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub. +# +# This don't work for Linux-2.0 or older. +# +# Author Edouard G. Parmelan +# +# +# Fri Apr 30 20:33:29 CEST 1999 +# First public release. +# +# Major cleanup after experiment Linux-2.0 kernel without success. +# Symbols of a module are not in the correct order, I can't explain +# why :( +# +# Fri Mar 19 15:41:40 CET 1999 +# Initial version. +# +# Thu Jan 6 16:29:03 CST 2000 +# A little fixing by Dave Grothe +# +# Mon Jun 19 09:33:13 CDT 2000 +# Alignment changes from Edouard Parmelan +# +# The basic idea is to find where insmod load the module and inform +# GDB to load the symbol table of the module with the GDB command +# ``add-symbol-file
''. +# +# The Linux kernel holds the list of all loaded modules in module_list, +# this list end with &kernel_module (exactly with module->next == NULL, +# but the last module is not a real module). +# +# Insmod allocates the struct module before the object file. Since +# Linux-2.1, this structure contain his size. The real address of +# the object file is then (char*)module + module->size_of_struct. +# +# You can use three user functions ``mod-list'', ``mod-print-symbols'' +# and ``add-module-symbols''. +# +# mod-list list all loaded modules with the format: +# +# +# As soon as you have found the address of your module, you can +# print its exported symbols (mod-print-symbols) or inform GDB to add +# symbols from your module file (mod-add-symbols). +# +# The argument that you give to mod-print-symbols or mod-add-symbols +# is the from the mod-list command. +# +# When using the mod-add-symbols command you must also give the full +# pathname of the modules object code file. +# +# The command mod-add-lis is an example of how to make this easier. +# You can edit this macro to contain the path name of your own +# favorite module and then use it as a shorthand to load it. You +# still need the module-address, however. +# +# The internal function ``mod-validate'' set the GDB variable $mod +# as a ``struct module*'' if the kernel known the module otherwise +# $mod is set to NULL. This ensure to not add symbols for a wrong +# address. +# +# Have a nice hacking day ! +# +# +define mod-list + set $mod = (struct module*)module_list + # the last module is the kernel, ignore it + while $mod != &kernel_module + printf "%p\t%s\n", (long)$mod, ($mod)->name + set $mod = $mod->next + end +end +document mod-list +List all modules in the form: +Use the as the argument for the other +mod-commands: mod-print-symbols, mod-add-symbols. +end + +define mod-validate + set $mod = (struct module*)module_list + while ($mod != $arg0) && ($mod != &kernel_module) + set $mod = $mod->next + end + if $mod == &kernel_module + set $mod = 0 + printf "%p is not a module\n", $arg0 + end +end +document mod-validate +mod-validate +Internal user-command used to validate the module parameter. +If is a real loaded module, set $mod to it otherwise set $mod to 0. +end + + +define mod-print-symbols + mod-validate $arg0 + if $mod != 0 + set $i = 0 + while $i < $mod->nsyms + set $sym = $mod->syms[$i] + printf "%p\t%s\n", $sym->value, $sym->name + set $i = $i + 1 + end + end +end +document mod-print-symbols +mod-print-symbols +Print all exported symbols of the module. see mod-list +end + + +define mod-add-symbols-align + mod-validate $arg0 + if $mod != 0 + set $mod_base = ($mod->size_of_struct + (long)$mod) + if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0) + set $mod_base = ($mod_base | ($arg2 - 1)) + 1 + end + add-symbol-file $arg1 $mod_base + end +end +document mod-add-symbols-align +mod-add-symbols-align +Load the symbols table of the module from the object file where +first section aligment is . +To retreive alignment, use `objdump -h '. +end + +define mod-add-symbols + mod-add-symbols-align $arg0 $arg1 sizeof(long) +end +document mod-add-symbols +mod-add-symbols +Load the symbols table of the module from the object file. +Default alignment is 4. See mod-add-symbols-align. +end + +define mod-add-lis + mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16 +end +document mod-add-lis +mod-add-lis +Does mod-add-symbols /usr/src/LiS/streams.o +end --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/kgdbeth.txt 2003-12-30 22:49:27.000000000 -0800 @@ -0,0 +1,92 @@ +KGDB over ethernet +================== + +Authors +------- + +Robert Walsh (2.6 port) +wangdi (2.6 port) +Matt Mackall (netpoll api) +San Mehat (original 2.4 code) + + +Introduction +------------ + +KGDB supports debugging over ethernet (kgdboe) via polling of a given +network interface. Most cards should be supported automatically. +Debugging facilities are available as soon as the network driver and +kgdboe have initialized. Unfortunately, this is too late in the boot +process for debugging some issues, but works quite well for many +others. This should not interfere with normal network usage and +doesn't require a dedicated NIC. + +Terminology +----------- + +This document uses the following terms: + + TARGET: the machine being debugged. + HOST: the machine running gdb. + + +Usage +----- + +You need to use the following command-line option on the TARGET kernel: + + kgdboe=[tgt-port]@/[dev],[host-port]@/[host-macaddr] + + where + tgt-port source for UDP packets (defaults to 6443) + tgt-ip source IP to use (interface address) + dev network interface (eth0) + host-port HOST UDP port (6442) (not really used) + host-ip IP address for HOST machine + host-macaddr ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff) + + examples: + + kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D + this machine is 192.168.0.1 on eth1 + remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D + listen for gdb packets on port 7000 + send unsolicited gdb packets to port 7001 + + kgdboe=@192.168.0.1/,@192.168.0.2/ + this machine is 192.168.0.1 on default interface eth0 + remote machine is 192.168.0.2, use default broadcast MAC address + listen for gdb packets on default port 6443 + send unsolicited gdb packets to port 6442 + +Only packets originating from the configured HOST IP address will be +accepted by the debugger. + +On the HOST side, run gdb as normal and use a remote UDP host as the +target: + + % gdb ./vmlinux + GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) + Copyright 2003 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux-gnu"... + (gdb) target remote udp:HOSTNAME:6443 + +You can now continue as if you were debugging over a serial line. + +Limitations +----------- + +The current release of this code is exclusive of using kgdb on a +serial interface, so you must boot without the kgdboe option to use +serial debugging. Trying to debug the network driver while using it +will prove interesting. + +Bug reports +----------- + +Send bug reports to Robert Walsh and Matt +Mackall . --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/kgdb.txt 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,775 @@ +Last edit: <20030806.1637.12> +This file has information specific to the i386 kgdb option. Other +platforms with the kgdb option may behave in a similar fashion. + +New features: +============ +20030806.1557.37 +This version was made against the 2.6.0-test2 kernel. We have made the +following changes: + +- The getthread() code in the stub calls find_task_by_pid(). It fails + if we are early in the bring up such that the pid arrays have yet to + be allocated. We have added a line to kernel/pid.c to make + "kgdb_pid_init_done" true once the arrays are allocated. This way the + getthread() code knows not to call. This is only used by the thread + debugging stuff and threads will not yet exist at this point in the + boot. + +- For some reason, gdb was not asking for a new thread list when the + "info thread" command was given. We changed to the newer version of + the thread info command and gdb now seems to ask when needed. Result, + we now get all threads in the thread list. + +- We now respond to the ThreadExtraInfo request from gdb with the thread + name from task_struct .comm. This then appears in the thread list. + Thoughts on additional options for this are welcome. Things such as + "has BKL" and "Preempted" come to mind. I think we could have a flag + word that could enable different bits of info here. + +- We now honor, sort of, the C and S commands. These are continue and + single set after delivering a signal. We ignore the signal and do the + requested action. This only happens when we told gdb that a signal + was the reason for entry, which is only done on memory faults. The + result is that you can now continue into the Oops. + +- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb, + but it is more exact on what language to use. + +- We added two dwarf2 include files and a bit of code at the end of + entry.S. This does not yet work, so it is disabled. Still we want to + keep track of the code and "maybe" someone out there can fix it. + +- Randy Dunlap sent some fix ups for this file which are now merged. + +- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a + compiler warning if CONFIG_KGDB is off (now who would do that :). + +- Andrew Morton sent a fix for the serial driver which is now merged. + +- Andrew also sent a change to the stub around the cpu managment code + which is also merged. + +- Andrew also sent a patch to make "f" as well as "g" work as SysRq + commands to enter kgdb, merged. + +- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a + "who" field to the spinlock data struct. This is filled with + "current" when ever the spinlock suceeds. Useful if you want to know + who has the lock. + +_ And last, but not least, we fixed the "get_cu" macro to properly get + the current value of "current". + +New features: +============ +20030505.1827.27 +We are starting to align with the sourceforge version, at least in +commands. To this end, the boot command string to start kgdb at +boot time has been changed from "kgdb" to "gdb". + +Andrew Morton sent a couple of patches which are now included as follows: +1.) We now return a flag to the interrupt handler. +2.) We no longer use smp_num_cpus (a conflict with the lock meter). +3.) And from William Lee Irwin III code to make + sure high-mem is set up before we attempt to register our interrupt + handler. +We now include asm/kgdb.h from config.h so you will most likely never +have to include it. It also 'NULLS' the kgdb macros you might have in +your code when CONFIG_KGDB is not defined. This allows you to just +turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such. +This include is conditioned on the machine being an x86 so as to not +mess with other archs. + +20020801.1129.03 +This is currently the version for the 2.4.18 (and beyond?) kernel. + +We have several new "features" beginning with this version: + +1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more + waiting and it will pull that guy out of an IRQ off spin lock :) + +2.) We doctored up the code that tells where a task is waiting and + included it so that the "info thread" command will show a bit more + than "schedule()". Try it... + +3.) Added the ability to call a function from gdb. All the standard gdb + issues apply, i.e. if you hit a breakpoint in the function, you are + not allowed to call another (gdb limitation, not kgdb). To help + this capability we added a memory allocation function. Gdb does not + return this memory (it is used for strings that you pass to that function + you are calling from gdb) so we fixed up a way to allow you to + manually return the memory (see below). + +4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the + interrupt flag to now also include the preemption count and the + "in_interrupt" info. The flag is now called "with_pif" to indicate + the order, preempt_count, in_interrupt, flag. The preempt_count is + shifted left by 4 bits so you can read the count in hex by dropping + the low order digit. In_interrupt is in bit 1, and the flag is in + bit 0. + +5.) The command: "p kgdb_info" is now expanded and prints something + like: +(gdb) p kgdb_info +$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259, + errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1, + cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0, + regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}} + + Things to note here: a.) used_malloc is the amount of memory that + has been malloc'ed to do calls from gdb. You can reclaim this + memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.) + cpus_waiting is now "sized" by the number of CPUs you enter at + configure time in the kgdb configure section. This is NOT used + anywhere else in the system, but it is "nice" here. c.) The task's + "pid" is now in the structure. This is the pid you will need to use + to decode to the thread id to get gdb to look at that thread. + Remember that the "info thread" command prints a list of threads + wherein it numbers each thread with its reference number followed + by the thread's pid. Note that the per-CPU idle threads actually + have pids of 0 (yes, there is more than one pid 0 in an SMP system). + To avoid confusion, kgdb numbers these threads with numbers beyond + the MAX_PID. That is why you see 32768 and above. + +6.) A subtle change, we now provide the complete register set for tasks + that are active on the other CPUs. This allows better trace back on + those tasks. + + And, let's mention what we could not fix. Back-trace from all but the + thread that we trapped will, most likely, have a bogus entry in it. + The problem is that gdb does not recognize the entry code for + functions that use "current" near (at all?) the entry. The compiler + is putting the "current" decode as the first two instructions of the + function where gdb expects to find %ebp changing code. Back trace + also has trouble with interrupt frames. I am talking with Daniel + Jacobowitz about some way to fix this, but don't hold your breath. + +20011220.0050.35 +Major enhancement with this version is the ability to hold one or more +CPUs in an SMP system while allowing the others to continue. Also, by +default only the current CPU is enabled on single-step commands (please +note that gdb issues single-step commands at times other than when you +use the si command). + +Another change is to collect some useful information in +a global structure called "kgdb_info". You should be able to just: + +p kgdb_info + +although I have seen cases where the first time this is done gdb just +prints the first member but prints the whole structure if you then enter +CR (carriage return or enter). This also works: + +p *&kgdb_info + +Here is a sample: +(gdb) p kgdb_info +$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0, + vector = 3, print_debug_info = 0} + +"Called_from" is the return address from the current entry into kgdb. +Sometimes it is useful to know why you are in kgdb, for example, was +it an NMI or a real breakpoint? The simple way to interrogate this +return address is: + +l *0xc010732c + +which will print the surrounding few lines of source code. + +"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the +kgdb_ts entries). + +"errcode" and "vector" are other entry parameters which may be helpful on +some traps. + +"print_debug_info" is the internal debugging kgdb print enable flag. Yes, +you can modify it. + +In SMP systems kgdb_info also includes the "cpus_waiting" structure and +"hold_on_step": + +(gdb) p kgdb_info +$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0, + vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{ + task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0, + regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}}} + +"Cpus_waiting" has an entry for each CPU other than the current one that +has been stopped. Each entry contains the task_struct address for that +CPU, the address of the regs for that task and a hold flag. All these +have the proper typing so that, for example: + +p *kgdb_info.cpus_waiting[1].regs + +will print the registers for CPU 1. + +"Hold_on_sstep" is a new feature with this version and comes up set or +true. What this means is that whenever kgdb is asked to single-step all +other CPUs are held (i.e. not allowed to execute). The flag applies to +all but the current CPU and, again, can be changed: + +p kgdb_info.hold_on_sstep=0 + +restores the old behavior of letting all CPUs run during single-stepping. + +Likewise, each CPU has a "hold" flag, which if set, locks that CPU out +of execution. Note that this has some risk in cases where the CPUs need +to communicate with each other. If kgdb finds no CPU available on exit, +it will push a message thru gdb and stay in kgdb. Note that it is legal +to hold the current CPU as long as at least one CPU can execute. + +20010621.1117.09 +This version implements an event queue. Events are signaled by calling +a function in the kgdb stub and may be examined from gdb. See EVENTS +below for details. This version also tightens up the interrupt and SMP +handling to not allow interrupts on the way to kgdb from a breakpoint +trap. It is fine to allow these interrupts for user code, but not +system debugging. + +Version +======= + +This version of the kgdb package was developed and tested on +kernel version 2.4.16. It will not install on any earlier kernels. +It is possible that it will continue to work on later versions +of 2.4 and then versions of 2.5 (I hope). + + +Debugging Setup +=============== + +Designate one machine as the "development" machine. This is the +machine on which you run your compiles and which has your source +code for the kernel. Designate a second machine as the "target" +machine. This is the machine that will run your experimental +kernel. + +The two machines will be connected together via a serial line out +one or the other of the COM ports of the PC. You will need the +appropriate modem eliminator (null modem) cable(s) for this. + +Decide on which tty port you want the machines to communicate, then +connect them up back-to-back using the null modem cable. COM1 is +/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection +with the two machines prior to trying to debug a kernel. Once you +have it working, on the TARGET machine, enter: + +setserial /dev/ttyS0 (or what ever tty you are using) + +and record the port address and the IRQ number. + +On the DEVELOPMENT machine you need to apply the patch for the kgdb +hooks. You have probably already done that if you are reading this +file. + +On your DEVELOPMENT machine, go to your kernel source directory and do +"make Xconfig" where X is one of "x", "menu", or "". If you are +configuring in the standard serial driver, it must not be a module. +Either yes or no is ok, but making the serial driver a module means it +will initialize after kgdb has set up the UART interrupt code and may +cause a failure of the control-C option discussed below. The configure +question for the serial driver is under the "Character devices" heading +and is: + +"Standard/generic (8250/16550 and compatible UARTs) serial support" + +Go down to the kernel debugging menu item and open it up. Enable the +kernel kgdb stub code by selecting that item. You can also choose to +turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler +to put more debug info (like local symbols) in the object file. On the +i386 -g and -ggdb are the same so this option just reduces to "O1". The +-O1 reduces the optimization level. This may be helpful in some cases, +be aware, however, that this may also mask the problem you are looking +for. + +The baud rate. Default is 115200. What ever you choose be sure that +the host machine is set to the same speed. I recommend the default. + +The port. This is the I/O address of the serial UART that you should +have gotten using setserial as described above. The standard COM1 port +(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ +3. + +The port IRQ (see above). + +Stack overflow test. This option makes a minor change in the trap, +system call and interrupt code to detect stack overflow and transfer +control to kgdb if it happens. (Some platforms have this in the +baseline code, but the i386 does not.) + +You can also configure the system to recognize the boot option +"console=kgdb" which if given will cause all console output during +booting to be put thru gdb as well as other consoles. This option +requires that gdb and kgdb be connected prior to sending console output +so, if they are not, a breakpoint is executed to force the connection. +This will happen before any kernel output (it is going thru gdb, right), +and will stall the boot until the connection is made. + +You can also configure in a patch to SysRq to enable the kGdb SysRq. +This request generates a breakpoint. Since the serial port IRQ line is +set up after any serial drivers, it is possible that this command will +work when the control-C will not. + +Save and exit the Xconfig program. Then do "make clean" , "make dep" +and "make bzImage" (or whatever target you want to make). This gets the +kernel compiled with the "-g" option set -- necessary for debugging. + +You have just built the kernel on your DEVELOPMENT machine that you +intend to run on your TARGET machine. + +To install this new kernel, use the following installation procedure. +Remember, you are on the DEVELOPMENT machine patching the kernel source +for the kernel that you intend to run on the TARGET machine. + +Copy this kernel to your target machine using your usual procedures. I +usually arrange to copy development: +/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine +via a LAN based NFS access. That is, I run the cp command on the target +and copy from the development machine via the LAN. Run Lilo (see "man +lilo" for details on how to set this up) on the new kernel on the target +machine so that it will boot! Then boot the kernel on the target +machine. + +On the DEVELOPMENT machine, create a file called .gdbinit in the +directory /usr/src/linux. An example .gdbinit file looks like this: + +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 (or what ever speed you have chosen) +target remote /dev/ttyS0 + + +Change the "echo" and "target" definition so that it specifies the tty +port that you intend to use. Change the "remotebaud" definition to +match the data rate that you are going to use for the com line. + +You are now ready to try it out. + +Boot your target machine with "kgdb" in the boot command i.e. something +like: + +lilo> test kgdb + +or if you also want console output thru gdb: + +lilo> test kgdb console=kgdb + +You should see the lilo message saying it has loaded the kernel and then +all output stops. The kgdb stub is trying to connect with gdb. Start +gdb something like this: + + +On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux". +When gdb gets the symbols loaded it will read your .gdbinit file and, if +everything is working correctly, you should see gdb print out a few +lines indicating that a breakpoint has been taken. It will actually +show a line of code in the target kernel inside the kgdb activation +code. + +The gdb interaction should look something like this: + + linux-dev:/usr/src/linux# gdb vmlinux + GDB is free software and you are welcome to distribute copies of it + under certain conditions; type "show copying" to see the conditions. + There is absolutely no warranty for GDB; type "show warranty" for details. + GDB 4.15.1 (i486-slackware-linux), + Copyright 1995 Free Software Foundation, Inc... + breakpoint () at i386-stub.c:750 + 750 } + (gdb) + +You can now use whatever gdb commands you like to set breakpoints. +Enter "continue" to start your target machine executing again. At this +point the target system will run at full speed until it encounters +your breakpoint or gets a segment violation in the kernel, or whatever. + +If you have the kgdb console enabled when you continue, gdb will print +out all the console messages. + +The above example caused a breakpoint relatively early in the boot +process. For the i386 kgdb it is possible to code a break instruction +as the first C-language point in init/main.c, i.e. as the first instruction +in start_kernel(). This could be done as follows: + +#include + breakpoint(); + +This breakpoint() is really a function that sets up the breakpoint and +single-step hardware trap cells and then executes a breakpoint. Any +early hard coded breakpoint will need to use this function. Once the +trap cells are set up they need not be set again, but doing it again +does not hurt anything, so you don't need to be concerned about which +breakpoint is hit first. Once the trap cells are set up (and the kernel +sets them up in due course even if breakpoint() is never called) the +macro: + +BREAKPOINT; + +will generate an inline breakpoint. This may be more useful as it stops +the processor at the instruction instead of in a function a step removed +from the location of interest. In either case must be +included to define both breakpoint() and BREAKPOINT. + +Triggering kgdbstub at other times +================================== + +Often you don't need to enter the debugger until much later in the boot +or even after the machine has been running for some time. Once the +kernel is booted and interrupts are on, you can force the system to +enter the debugger by sending a control-C to the debug port. This is +what the first line of the recommended .gdbinit file does. This allows +you to start gdb any time after the system is up as well as when the +system is already at a breakpoint. (In the case where the system is +already at a breakpoint the control-C is not needed, however, it will +be ignored by the target so no harm is done. Also note the the echo +command assumes that the port speed is already set. This will be true +once gdb has connected, but it is best to set the port speed before you +run gdb.) + +Another simple way to do this is to put the following file in you ~/bin +directory: + +#!/bin/bash +echo -e "\003" > /dev/ttyS0 + +Here, the ttyS0 should be replaced with what ever port you are using. +The "\003" is control-C. Once you are connected with gdb, you can enter +control-C at the command prompt. + +An alternative way to get control to the debugger is to enable the kGdb +SysRq command. Then you would enter Alt-SysRq-g (all three keys at the +same time, but push them down in the order given). To refresh your +memory of the available SysRq commands try Alt-SysRq-=. Actually any +undefined command could replace the "=", but I like to KNOW that what I +am pushing will never be defined. + +Debugging hints +=============== + +You can break into the target machine at any time from the development +machine by typing ^C (see above paragraph). If the target machine has +interrupts enabled this will stop it in the kernel and enter the +debugger. + +There is unfortunately no way of breaking into the kernel if it is +in a loop with interrupts disabled, so if this happens to you then +you need to place exploratory breakpoints or printk's into the kernel +to find out where it is looping. The exploratory breakpoints can be +entered either thru gdb or hard coded into the source. This is very +handy if you do something like: + +if () BREAKPOINT; + + +There is a copy of an e-mail in the Documentation/i386/kgdb/ directory +(debug-nmi.txt) which describes how to create an NMI on an ISA bus +machine using a paper clip. I have a sophisticated version of this made +by wiring a push button switch into a PC104/ISA bus adapter card. The +adapter card nicely furnishes wire wrap pins for all the ISA bus +signals. + +When you are done debugging the kernel on the target machine it is a +good idea to leave it in a running state. This makes reboots faster, +bypassing the fsck. So do a gdb "continue" as the last gdb command if +this is possible. To terminate gdb itself on the development machine +and leave the target machine running, first clear all breakpoints and +continue, then type ^Z to suspend gdb and then kill it with "kill %1" or +something similar. + +If gdbstub Does Not Work +======================== + +If it doesn't work, you will have to troubleshoot it. Do the easy +things first like double checking your cabling and data rates. You +might try some non-kernel based programs to see if the back-to-back +connection works properly. Just something simple like cat /etc/hosts +>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you +if you can send data from one machine to the other. Make sure it works +in both directions. There is no point in tearing out your hair in the +kernel if the line doesn't work. + +All of the real action takes place in the file +/usr/src/linux/arch/i386/kernel/kgdb_stub.c. That is the code on the target +machine that interacts with gdb on the development machine. In gdb you can +turn on a debug switch with the following command: + + set remotedebug + +This will print out the protocol messages that gdb is exchanging with +the target machine. + +Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is +the code that talks to the serial port on the target side. There might +be a problem there. In particular there is a section of this code that +tests the UART which will tell you what UART you have if you define +"PRNT" (just remove "_off" from the #define PRNT_off). To view this +report you will need to boot the system without any beakpoints. This +allows the kernel to run to the point where it calls kgdb to set up +interrupts. At this time kgdb will test the UART and print out the type +it finds. (You need to wait so that the printks are actually being +printed. Early in the boot they are cached, waiting for the console to +be enabled. Also, if kgdb is entered thru a breakpoint it is possible +to cause a dead lock by calling printk when the console is locked. The +stub thus avoids doing printks from breakpoints, especially in the +serial code.) At this time, if the UART fails to do the expected thing, +kgdb will print out (using printk) information on what failed. (These +messages will be buried in all the other boot up messages. Look for +lines that start with "gdb_hook_interrupt:". You may want to use dmesg +once the system is up to view the log. If this fails or if you still +don't connect, review your answers for the port address. Use: + +setserial /dev/ttyS0 + +to get the current port and IRQ information. This command will also +tell you what the system found for the UART type. The stub recognizes +the following UART types: + +16450, 16550, and 16550A + +If you are really desperate you can use printk debugging in the +kgdbstub code in the target kernel until you get it working. In particular, +there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c +named "remote_debug". Compile your kernel with this set to 1, rather +than 0 and the debug stub will print out lots of stuff as it does +what it does. Likewise there are debug printks in the kgdb_serial.c +code that can be turned on with simple changes in the macro defines. + + +Debugging Loadable Modules +========================== + +This technique comes courtesy of Edouard Parmelan + + +When you run gdb, enter the command + +source gdbinit-modules + +This will read in a file of gdb macros that was installed in your +kernel source directory when kgdb was installed. This file implements +the following commands: + +mod-list + Lists the loaded modules in the form + +mod-print-symbols + Prints all the symbols in the indicated module. + +mod-add-symbols + Loads the symbols from the object file and associates them + with the indicated module. + +After you have loaded the module that you want to debug, use the command +mod-list to find the of your module. Then use that +address in the mod-add-symbols command to load your module's symbols. +From that point onward you can debug your module as if it were a part +of the kernel. + +The file gdbinit-modules also contains a command named mod-add-lis as +an example of how to construct a command of your own to load your +favorite module. The idea is to "can" the pathname of the module +in the command so you don't have to type so much. + +Threads +======= + +Each process in a target machine is seen as a gdb thread. gdb thread +related commands (info threads, thread n) can be used. + +ia-32 hardware breakpoints +========================== + +kgdb stub contains support for hardware breakpoints using debugging features +of ia-32(x86) processors. These breakpoints do not need code modification. +They use debugging registers. 4 hardware breakpoints are available in ia-32 +processors. + +Each hardware breakpoint can be of one of the following three types. + +1. Execution breakpoint - An Execution breakpoint is triggered when code + at the breakpoint address is executed. + + As limited number of hardware breakpoints are available, it is + advisable to use software breakpoints ( break command ) instead + of execution hardware breakpoints, unless modification of code + is to be avoided. + +2. Write breakpoint - A write breakpoint is triggered when memory + location at the breakpoint address is written. + + A write or can be placed for data of variable length. Length of + a write breakpoint indicates length of the datatype to be + watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for + 4 byte data. + +3. Access breakpoint - An access breakpoint is triggered when memory + location at the breakpoint address is either read or written. + + Access breakpoints also have lengths similar to write breakpoints. + +IO breakpoints in ia-32 are not supported. + +Since gdb stub at present does not use the protocol used by gdb for hardware +breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros +for hardware breakpoints are described below. + +hwebrk - Places an execution breakpoint + hwebrk breakpointno address +hwwbrk - Places a write breakpoint + hwwbrk breakpointno length address +hwabrk - Places an access breakpoint + hwabrk breakpointno length address +hwrmbrk - Removes a breakpoint + hwrmbrk breakpointno +exinfo - Tells whether a software or hardware breakpoint has occurred. + Prints number of the hardware breakpoint if a hardware breakpoint has + occurred. + +Arguments required by these commands are as follows +breakpointno - 0 to 3 +length - 1 to 3 +address - Memory location in hex digits ( without 0x ) e.g c015e9bc + +SMP support +========== + +When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb +client, all the processors are forced to enter the debugger. Current +thread corresponds to the thread running on the processor where +breakpoint occurred. Threads running on other processor(s) appear +similar to other non-running threads in the 'info threads' output. +Within the kgdb stub there is a structure "waiting_cpus" in which kgdb +records the values of "current" and "regs" for each CPU other than the +one that hit the breakpoint. "current" is a pointer to the task +structure for the task that CPU is running, while "regs" points to the +saved registers for the task. This structure can be examined with the +gdb "p" command. + +ia-32 hardware debugging registers on all processors are set to same +values. Hence any hardware breakpoints may occur on any processor. + +gdb troubleshooting +=================== + +1. gdb hangs +Kill it. restart gdb. Connect to target machine. + +2. gdb cannot connect to target machine (after killing a gdb and +restarting another) If the target machine was not inside debugger when +you killed gdb, gdb cannot connect because the target machine won't +respond. In this case echo "Ctrl+C"(ASCII 3) to the serial line. +e.g. echo -e "\003" > /dev/ttyS1 +This forces that target machine into the debugger, after which you +can connect. + +3. gdb cannot connect even after echoing Ctrl+C into serial line +Try changing serial line settings min to 1 and time to 0 +e.g. stty min 1 time 0 < /dev/ttyS1 +Try echoing again + +Check serial line speed and set it to correct value if required +e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1 + +EVENTS +====== + +Ever want to know the order of things happening? Which CPU did what and +when? How did the spinlock get the way it is? Then events are for +you. Events are defined by calls to an event collection interface and +saved for later examination. In this case, kgdb events are saved by a +very fast bit of code in kgdb which is fully SMP and interrupt protected +and they are examined by using gdb to display them. Kgdb keeps only +the last N events, where N must be a power of two and is defined at +configure time. + + +Events are signaled to kgdb by calling: + +kgdb_ts(data0,data1) + +For each call kgdb records each call in an array along with other info. +Here is the array definition: + +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + int data0; + int data1; +}; + +For SMP machines the CPU is recorded, for all machines the TSC is +recorded (gets a time stamp) as well as the line number and source file +the call was made from. The address of the (from), the "if" (interrupt +flag) and the two data items are also recorded. The macro kgdb_ts casts +the types to int, so you can put any 32-bit values here. There is a +configure option to select the number of events you want to keep. A +nice number might be 128, but you can keep up to 1024 if you want. The +number must be a power of two. An "andthen" macro library is provided +for gdb to help you look at these events. It is also possible to define +a different structure for the event storage and cast the data to this +structure. For example the following structure is defined in kgdb: + +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + struct task_struct *t1; + struct task_struct *t2; +}; + +If you use this for display, the data elements will be displayed as +pointers to task_struct entries. You may want to define your own +structure to use in casting. You should only change the last two items +and you must keep the structure size the same. Kgdb will handle these +as 32-bit ints, but within that constraint you can define a structure to +cast to any 32-bit quantity. This need only be available to gdb and is +only used for casting in the display code. + +Final Items +=========== + +I picked up this code from Amit S. Kale and enhanced it. + +If you make some really cool modification to this stuff, or if you +fix a bug, please let me know. + +George Anzinger + + +Amit S. Kale + + +(First kgdb by David Grothe ) + +(modified by Tigran Aivazian ) + Putting gdbstub into the kernel config menu. + +(modified by Scott Foehner ) + Hooks for entering gdbstub at boot time. + +(modified by Amit S. Kale ) + Threads, ia-32 hw debugging, mp support, console support, + nmi watchdog handling. + +(modified by George Anzinger ) + Extended threads to include the idle threads. + Enhancements to allow breakpoint() at first C code. + Use of module_init() and __setup() to automate the configure. + Enhanced the cpu "collection" code to work in early bring-up. + Added ability to call functions from gdb + Print info thread stuff without going back to schedule() + Now collect the "other" cpus with an IPI/ NMI. --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/loadmodule.sh 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,78 @@ +#/bin/sh +# This script loads a module on a target machine and generates a gdb script. +# source generated gdb script to load the module file at appropriate addresses +# in gdb. +# +# Usage: +# Loading the module on target machine and generating gdb script) +# [foo]$ loadmodule.sh +# +# Loading the module file into gdb +# (gdb) source +# +# Modify following variables according to your setup. +# TESTMACHINE - Name of the target machine +# GDBSCRIPTS - The directory where a gdb script will be generated +# +# Author: Amit S. Kale (akale@veritas.com). +# +# If you run into problems, please check files pointed to by following +# variables. +# ERRFILE - /tmp/.errs contains stderr output of insmod +# MAPFILE - /tmp/.map contains stdout output of insmod +# GDBSCRIPT - $GDBSCRIPTS/load gdb script. + +TESTMACHINE=foo +GDBSCRIPTS=/home/bar + +if [ $# -lt 1 ] ; then { + echo Usage: $0 modulefile + exit +} ; fi + +MODULEFILE=$1 +MODULEFILEBASENAME=`basename $1` + +if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then { + MODULEFILE=`pwd`/$MODULEFILE +} fi + +ERRFILE=/tmp/$MODULEFILEBASENAME.errs +MAPFILE=/tmp/$MODULEFILEBASENAME.map +GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME + +function findaddr() { + local ADDR=0x$(echo "$SEGMENTS" | \ + grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \ + sed 's/[ ]*[^ ]*$//') + echo $ADDR +} + +function checkerrs() { + if [ "`cat $ERRFILE`" != "" ] ; then { + cat $ERRFILE + exit + } fi +} + +#load the module +echo Copying $MODULEFILE to $TESTMACHINE +rcp $MODULEFILE root@${TESTMACHINE}: + +echo Loading module $MODULEFILE +rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \ + > $MAPFILE 2> $ERRFILE +checkerrs + +SEGMENTS=`head -n 11 $MAPFILE | tail -n 10` +TEXTADDR=$(findaddr "\\.text[^.]") +LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR" +SEGADDRS=`echo "$SEGMENTS" | awk '//{ + if ($1 != ".text" && $1 != ".this" && + $1 != ".kstrtab" && $1 != ".kmodtab") { + print " -s " $1 " 0x" $3 " " + } +}'` +LOADSTRING="$LOADSTRING $SEGADDRS" +echo Generating script $GDBSCRIPT +echo $LOADSTRING > $GDBSCRIPT --- linux-2.6.1-rc1/Documentation/kernel-parameters.txt 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/kernel-parameters.txt 2003-12-30 22:49:52.000000000 -0800 @@ -92,6 +92,23 @@ running once the system is up. ht -- run only enough ACPI to enable Hyper Threading See also Documentation/pm.txt. + acpi_pic_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode + Format: { level | edge } + level Force PIC-mode SCI to Level Trigger (default) + edge Force PIC-mode SCI to Edge Trigge + + acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs + default in APIC mode + + acpi_irq_nobalance [HW,ACPI] ACPI will not move active IRQs (default) + default in PIC mode + + acpi_irq_pci= [HW,ACPI] If irq_balance, Clear listed IRQs for use by PCI + Format: ,... + + acpi_irq_isa= [HW,ACPI] If irq_balance, Mark listed IRQs used by ISA + Format: ,... + ad1816= [HW,OSS] Format: ,,, See also Documentation/sound/oss/AD1816. @@ -215,7 +232,7 @@ running once the system is up. Forces specified timesource (if avaliable) to be used when calculating gettimeofday(). If specicified timesource is not avalible, it defaults to PIT. - Format: { pit | tsc | cyclone | ... } + Format: { pit | tsc | cyclone | pmtmr } hpet= [IA-32,HPET] option to disable HPET and use PIT. Format: disable --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/must-fix.txt 2003-12-30 22:49:28.000000000 -0800 @@ -0,0 +1,288 @@ + +Must-fix bugs +============= + +drivers/char/ +~~~~~~~~~~~~~ + +o TTY locking is broken. + + o see FIXME in do_tty_hangup(). This causes ppp BUGs in local_bh_enable() + + o Other problems: aviro, dipankar, Alan have details. + + o somebody will have to document the tty driver and ldisc API + +drivers/tty +~~~~~~~~~~~ + +o viro: tty_driver refcounting, tty/misc/upper levels of sound still not + completely fixed. + +drivers/block/ +~~~~~~~~~~~~~~ + +o loop.c: Concurrent write access on block devices might cause a deadlock + of the complete system. See: + http://marc.theaimsgroup.com/?l=linux-kernel&m=106275365925769&w== + http://bugzilla.kernel.org/show_bug.cgi?id=1198 + Thread of possible fix: + http://www.kerneli.org/pipermail/cryptoapi-devel/2003-October/000676.html + + (Fruhwirth Clemens) + +o ideraid hasn't been ported to 2.5 at all yet. + + We need to understand whether the proposed BIO split code will suffice + for this. + +drivers/input/ +~~~~~~~~~~~~~~ + +o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0 + currently on these remaining in my/Linus' tree.) + +o viro: large absence of locking. + +o viro: parport is nearly as bad as that and there the code is more hairy. + IMO parport is more of "figure out what API changes are needed for its + users, get them done ASAP, then fix generic layer at leisure" + +o (Albert Cahalan) Lots of people (check Google) get this message from the + kernel: + + psmouse.c: Lost synchronization, throwing 2 bytes away. + + (the number of bytes will be 1, 2, or 3) + + At work, I get it when there is heavy NFS traffic. The mouse goes crazy, + jumping around and doing random cut-and-paste all over everything. This + is with a decently fast and modern PC. + +o There seem to be too many reports of keyboards and mice failing or acting + strangely. + + +drivers/misc/ +~~~~~~~~~~~~~ + +o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM + tree. (touchscreen, audio, gpio, type device.) + + These need to be moved out of drivers/misc/ and into real places + +o viro: actually, misc.c has a good chance to die. With cdev-cidr that's + trivial. + +drivers/net/ +~~~~~~~~~~~~ + +drivers/net/irda/ +~~~~~~~~~~~~~~~~~ + + (Jean Tourrilhes) + +o irport need to be converted to sir-kthread + +o dongle drivers need to be converted to sir-dev (in progress) + +o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing (in progress) + + +drivers/pci/ +~~~~~~~~~~~~ + +o alan: Some cardbus crashes the system + + (bugzilla, please?) + +drivers/pcmcia/ +~~~~~~~~~~~~~~~ + +o alan: This is a locking disaster. + + (rmk, brodo: in progress) + +drivers/pld/ +~~~~~~~~~~~~ + +o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld) + + (rmk: will work out what to do here. maybe drivers/arm/) + +drivers/video/ +~~~~~~~~~~~~~~ + +o Lots of drivers don't compile, others do but don't work. + +drivers/scsi/ +~~~~~~~~~~~~~ + +o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping + +o Make inia100, cpqfc, pci2000 and dc390t compile + +o Convert + + wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93 + + 53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000 + pci2220i dc390t + + To new error handling + + It also might be possible to shift the 53c7xx based drivers over to + 53c700 which does the new EH stuff, but I don't have the hardware to check + such a shift. + + For the non-compiling stuff, I've probably missed a few that just aren't + compilable on my platforms, so any updates would be welcome. Also, are + some of our non-compiling or unconverted drivers obsolete? + +fs/ +~~~ + +o AIO/direct-IO writes can race with truncate and wreck filesystems. + (Badari has a patch) + +o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr. + In progress. + +o forward-port sct's O_DIRECT fixes (Badari has a patch) + +o viro: there is some generic stuff for namei/namespace/super, but that's a + slow-merge and can go in 2.6 just fine + +o trond: NFS has a mmap-versus-truncate problem (fixed? needs testing) + +o trond: NFSv4 client, bugs in lockd, RPSEC_GSS for NFSv[23], some atomic open + bits. more info: http://www.fys.uio.no/~trondmy/src/Linux-2.6.x/2.6.0-test11/ + +kernel/sched.c +~~~~~~~~~~~~~~ + +o Starvation, general interactivity need close monitoring. + +o SMT aware scheduler (Ingo, Rusty, Nick have implementations) + +kernel/ +~~~~~~~ + +o Alan: 32bit uid support is *still* broken for process accounting. + + Create a 32bit uid, turn accounting on. Shock horror it doesn't work + because the field is 16bit. We need an acct structure flag day for 2.6 + IMHO + + (alan has patch) + +o viro: core sysctl code is racy. And its interaction wiuth sysfs + +o (ingo) rwsems (on x86) are limited to 32766 waiting processes. This + means that setting pid_max to above 32K is unsafe :-( + + An option is to use CONFIG_RWSEM_GENERIC_SPINLOCK variant all the time, + for all archs, and not inline any part of the ops. + +lib/kobject.c +~~~~~~~~~~~~~ + +o kobject refcounting (comments from Al Viro): + + _anything_ can grab a temporary reference to kobject. IOW, if kobject is + embedded into something that could be freed - it _MUST_ have a destructor + and that destructor _MUST_ be the destructor for containing object. + + Any violation of the above (and we already have a bunch of those) is a + user-triggerable memory corruption. + + We can tolerate it for a while in 2.5 (e.g. during work on susbsystem we + can decide to switch to that way of handling objects and have subsystem + vulnerable for a while), but all such windows must be closed before 2.6 + and during 2.6 we can't open them at all. + +o All block drivers which control multiple gendisks with a single + request_queue are broken, due to one-to-one assumptions in the request + queue sysfs hookup. + +mm/ +~~~ + +o GFP_DMA32 (or something like that). Lots of ideas. jejb, zaitcev, + willy, arjan, wli. + + Specifically, 64-bit systems need to be able to enforce 32-bit addressing + limits for device metadata like network cards' ring buffers and SCSI + command descriptors. + +o access_process_vm() doesn't flush right. We probably need new flushing + primitives to do this (davem?) + + +modules +~~~~~~~ + + (Rusty) + +net/ +~~~~ + + (davem) + +o UDP apps can in theory deadlock, because the ip_append_data path can end + up sleeping while the socket lock is held. + + It is OK to sleep with the socket held held, normally. But in this case + the sleep happens while waiting for socket memory/space to become + available, if another context needs to take the socket lock to free up the + space we could hang. + + I sent a rough patch on how to fix this to Alexey, and he is analyzing + the situation. I expect a final fix from him next week or so. + +o Semantics for IPSEC during operations such as TCP connect suck currently. + + When we first try to connect to a destination, we may need to ask the + IPSEC key management daemon to resolve the IPSEC routes for us. For the + purposes of what the kernel needs to do, you can think of it like ARP. We + can't send the packet out properly until we resolve the path. + + What happens now for IPSEC is basically this: + + O_NONBLOCK: returns -EAGAIN over and over until route is resolved + + !O_NONBLOCK: Sleeps until route is resolved + + These semantics are total crap. The solution, which Alexey is working + on, is to allow incomplete routes to exist. These "incomplete" routes + merely put the packet onto a "resolution queue", and once the key manager + does it's thing we finish the output of the packet. This is precisely how + ARP works. + + I don't know when Alexey will be done with this. + +net/*/netfilter/ +~~~~~~~~~~~~~~~~ + + (Rusty) + +sound/ +~~~~~~ + +global +~~~~~~ + +o viro: 64-bit dev_t (not a mustfix for 2.6.0). 32-bit dev_t is done, 64-bit + means extra work on nfsd/raid/etc. + +o alan: Forward port 2.4 fixes + - Chris Wright: Security fixes including execve holes, execve vs proc races + +o There are about 60 or 70 security related checks that need doing + (copy_user etc) from Stanford tools. (badari is looking into this, and + hollisb) + +o A couple of hundred real looking bugzilla bugs + +o viro: cdev rework. Mostly done. + --- linux-2.6.1-rc1/Documentation/networking/8139too.txt 2003-08-22 19:23:39.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,449 +0,0 @@ - - "8139too" Fast Ethernet driver for Linux - RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters - - Copyright 2000,2001 Jeff Garzik - - http://sourceforge.net/projects/gkernel/ - - - Architectures supported (all PCI platforms): - x86, Alpha AXP, PowerPC, Sparc64 - - Kernel versions supported: 2.4.x - - - -Disclaimer ----------- - -DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is -completely different and maintained independently of the 8139too code base. - - - -Requirements ------------- -Kernel 2.4.3 or later. -A Fast Ethernet adapter containing an RTL8139-based chip. - - - -Introduction ------------- - -The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial -modification of the experimental rtl8139 driver from Donald Becker, -some versions of which appeared in 2.2.x and 2.3.x kernels. The -RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very -popular. - -The step from 2.2.x to 2.4.x kernels brings many new features to Linux -device drivers. Features for MMIO resources, a standard hot-plug API, -and other interfaces are now becoming requirements, as drivers move -off the x86 platform. With that in mind, I have begun updating the -RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and -fixing the problems that users have been encountering. - - - -Features of 8139too -------------------- -[note - this list intended for people familiar with kernel drivers] - -** 100% MMIO, for full speed operation. All users (so far) have -reported performance increases over their existing RTL drivers. - -** Multi-platform support: x86, Alpha, PPC, ... - -** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the -driver portable to non-x86 SMP platforms in the process. - -** Use new PCI driver API for seamless, low-maintenance hot-plug support - -** Several bugs fixes from original rtl8139 1.08r (October 5, 1999), -including the very common "transmit timeout" problem. - -* Use new resource allocation API, required for hot-plug support -* Use new register read/write macros -* initcall support (module_init/exit) -* vastly improved debug tracing support -* code formatting in many places for readability -* use new init_etherdev() facilities - -...and probably some other less important changes which I forgot. - - - -Installation ------------- - -OPTION 1: Build inside kernel tree (into kernel image, or as module) - - (overwrite 8139too driver in kernel tree with different version) - 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c - -OPTION 2: Build outside kernel tree - - Use the included Makefile. - - - -Tested Adapters ---------------- -AOpen ALN-325C -AT-2500TX 10/100 PCI Fast Ethernet Network Adapter Card -D-Link DFE-530TX -Cnet CNF401 'SinglePoint' 10/100 Base-TX -Genius GF 100TXR4 Fast Ethernet 10/100M PCI Network Card -KTI KF-230TX -KTI KF-230TX/2 -Lantech FastNet TX -Ovislink Fast Ethernet -Planet ENW-9504 (V.4) 10/100 -SDT Jeoun Fast PCI-TX -SMC EZNET 10/100 -UNEX NexNIC ND012C - -(please add your adapter model to this list) - - - -Status of Platform Support --------------------------- - -(see errata below for details) - -x86: tested, stable -Alpha AXP: tested, stable -PowerPC: tested, unstable -Sparc64: not tested - - - -Special Thanks --------------- -The following people contributed invaluable testing time, feedback -and/or patches during the development of this driver. Thanks to all -of them. - -Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration - -Alan Cox, Gerard Roudier - insight on posted MMIO writes - -Martin Mares - code review - -Tigran Aivazian - testing, code review, and a bug fix - -Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin, -James Fidell, Taso Hatzi, Peter K - intrepid test team - -And thanks to every supporter free software. - -(see top of 8139too.c for further credits and kudos) - - - -Submitting Bug Reports ----------------------- -Obtain and compile the modified rtl8139-diag source code from the -8139too driver Web site, http://sourceforge.net/projects/gkernel/ -This diagnostics programs, originally from Donald Becker, has been -modified to display all registers on your RTL8139 chip, not just the -first 0x80. - -If possible, send the output of a working and broken driver with - rtl8139-diag -mmaaavvveefN > my-output-file.txt - -Send "lspci -vvv" or "cat /proc/pci" output for PCI information. - - - -Known Bugs / Errata / To-Do ---------------------------- -The following issues are known, and are actively being pursued. Patches -to resolve these issues is welcome. If a problem occurs which is not in -the list, please report it. That's why we do beta releases, after all... - - - -1) Work with Donald to merge fixes and updates into his driver. - -2) ETHTOOL_SSET support - -3) PPC platform has stability problems. (XXX: verify this is still true) - -4) Sparc64 platform not tested at all. - -8) Much improved command line / module parameter setup. (patches and -suggestions welcome) (WIP) - -9) Better documentation. (patches welcome) - -12) 10base-T support flaky or slow (todo: verify this is still true) - - - - -Change History --------------- - -Version 0.9.26 - August 9, 2002 - -* Fix MII ioctl phy id corruption. -* Fix big-endian multicast bug. -* Support register dumps via ethtool. -* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit -* Replace several "magic numbers" with their proper representation - constants in linux/mii.h. -* Support ethtool media interface via generic kernel MII API -* Export NIC-specific statistics via ethtool. -* Proper support for RTL8139 rev K. (can be disabled via - compile-time conditional) -* Add PCI ids for new 8139 boards. -* Use ethernet crc via generic linux/crc32.h kernel API. -* Better RX reset. Old rx-reset method still available via - a compile-time conditional. -* Only account specific RX errors if rx_status is !OK - - -Version 0.9.22 - November 8, 2001 - -* Additional retries before aborting Tx -* Do not write other TxConfig bits when writing clear-abort bit. -* Ack TxErr intr status after each Tx abort, too. -* Fix oops in interface restart - - -Version 0.9.21 - November 1, 2001 - -* Disable early Rx, it hurts performance and creates races. -* Remove DPRINTK macro function tracing. -* Better interrupt sharing behavior. -* Acknowledge PCI errors. -* Remove early-Rx acknowledgement, unnecessary -* Remove code for uncommon case where Tx packets are - properly aligned, and do not need to be copied. - Tx packets are now always copied into a static DMA buffer, - which is allocated at interface open. -* Fix problems with kernel thread exit. - - -Version 0.9.20 - October 18, 2001 - -* Print out notice when 8139C+ chip is detected -* Add id for D-Link DFE690TXD pcmcia cardbus card (Gert Dewit) - - -Version 0.9.19 - October 9, 2001 - -* Eliminate buffer copy for unaligned Tx's (manfred) -* Better RX error recovery (manfred) -* Wake-On-LAN and ETHTOOL_GSET support (Kalle Niemitalo) -* Fix assertion in PIO mode (various) - - -Version 0.9.18 - July 6, 2001 - -* Fix race leading to crashes on some machines. -* Minimize race leading to low performance. -* Correct interrupt acknowledgement to cover all three - relevant Rx events. -* Add ethtool driver info support. -* Collect additional driver-internal statistics. -* Add descriptions for module parameters. -* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6. -* Multicast filter big endian fix. -* Support new PCI PM API added in kernel 2.4.6. - - -Version 0.9.17 - May 7, 2001 - -* Fix chipset wakeup bug which prevent media connection for 8139B -* Print out "media is unconnected..." instead of - "partner ability 0000" - - -Version 0.9.16 - April 14, 2001 - -* Complete MMIO audit, disable read-after-every-write -* Update Rx interrupt handling -* Enable Early Rx thresholds, highly recommended to reduce - Rx FIFO overflow -* Make 8129 support conditional -* Support for new 2.4.3 kernel APIs -* More correct PIO/MMIO PCI BAR region size checking -* Add check for totally dead/missing hardware -* Disable media timer code to "set full duplex" -* s/spin_lock_irq/spin_lock_irqsave/ -* Only set AcceptMulticast if more than one mc address -* Only set rx_mode if changed, in set_rx_mode -* Only suspend/resume if interface is up -* Always print out version upon module load, even if no devices found - - -Version 0.9.15 - February 20, 2001 - -* Call pci_enable_device to wake up/assign resource to device, - before actually using it. -* Support wacky clone PCI ids (report from Norival Toniato Junior) -* Text spelling corrections -* Make sure tp->phys[] is signed -* Always wake queue after hw restart, in tx_timeout -* Record time of last received packet - - -Version 0.9.14 - January 11, 2001 - -* Merge some changes from Becker version 1.13: - * Add DFE 538TX PCI id - * MII read/write functions updated - * Cfg93[45]6 lock/unlock fix - * RTL-8129 (MII) support -* Clean up spinlocking - - -Version 0.9.13 - December, 2000 - -* Clear blocked signals, avoid buffer overrun setting current->comm -* Remove bogus PCI BAR length assertions -* Remove unused 'debug' module parameter - - -Version 0.9.12 - November 23, 2000 - -* Kill major Tx stop/wake queue race -* Use SET_MODULE_OWNER and fix module unload race -* Fix cable length ("Twister") tuning -* Proper media[] array length checking -* Replace timer with kernel thread for twister tuning state machine - and media checking. Fixes mdio_xxx locking, now mdio_xxx is always - protected by rtnl_lock semaphore. -* Correct some sledgehammer a.k.a. overzealous spin-locks -* Performance: Eliminate atomic_t for Tx counters, we don't need it -* Performance: Don't copy Tx buffer if the rare case occurs where it - is aligned perfectly for us. -* Eliminate needless casting of dev->priv -* PIO mode selection and Twister tuning are now CONFIG_xxx options - (though purposefully not in net/Config.in... yet) - - -Version 0.9.11 - October 28, 2000 - -* Do not fail when PIO and MMIO region lengths do not match. - (They don't on some CardBus models, at least) -* Sanity check Rx packet status and size (Tobias) -* When handling a Tx timeout, disable Tx ASAP if not already. -* Do not inline Tx interrupt handler (better register usage) -* Handle dirty_tx signed integer wrap -* Do not abort Rx processing on lack of memory, keep going - until the current Rx ring is completely handling. (Tobias) -* Clean up rtl8139_close -* Whitespace correction for dev_kfree_skb_irq call - - -Version 0.9.10 - September 12, 2000 - -* Never wrap an Rx packet (faster Rx interrupt handling) -* Clear all TxAborted conditions (bug fix) -* Correct copyright -* More credits -* Update NWay doc URL -* Clean up commonly used ifdef switches -* Reorg info displayed at bootup/modprobe time -* Remove some unneeded spinlocks -* Misc cosmetic code cleanup -* Always print interrupt status for abnormal interrupts -* Use RealTek-recommended FIFO and DMA burst settings (1024 bytes) - - -Version 0.9.9 - September 9, 2000 - -* Fix oops-able bug in Rx ring wrap calculation (David Ford) -* Use PIO instead of MMIO when USE_IO_OPS is defined -* Move Rx error handling out of Rx interrupt handler, resulting in - tighter Rx interrupt processing - - -Version 0.9.8 - September 7, 2000 - -* Propagate request_irq error value (andrew morton) -* Correct potential oops bug in PCI DMA unmap code -* Fix bugs related to counting/discounting of 32-bit CRC in each Rx packet -* Fix 16/32-bit bug in interrupt status check -* Timer cleanups (andrew morton) - - -Version 0.9.7 - June 11, 2000 - -* Fix support for older chips (RTL8139 early chips should now work again) - - -Version 0.9.6 - May 30, 2000 - -* Fix 4-extra-bytes bug - (thanks to Markus Westergren, via Santiago Garcia Mantinan) -* Yet more improved chip recognition - - -Version 0.9.5 - May 17, 2000 - -* Improved chip version recognition -* Continue banging away at receiver hang problem -* Use spin_lock_irq in another spot -* Don't print anything on pci_enable_device, it does so for us -* Disable buggy NWay code -* Define TxConfig bitmasks - - -Version 0.9.4.1 - April 27, 2000 - third public beta release - -* Replace several "magic numbers" with symbolic constants -* Differentiate between board-specific info and chip-specific info - (allows for easier support of specific boards or chips) -* Move some of the transmit side outside of the spinlock - by using atomic variables. Use spin_lock_irq instead of - spin_lock_irq{save,restore} in select places, for better performance. -* New module option "media" for forcing media selection. Functions the - same as "options" in other drivers, and will soon be renamed - 'options' to be homogeneous. -* New power management wake-up code -* Slightly more verbose chip id messages in kernel log -* Add/correct chip register constant list -* New chipset wake up (open) logic -* No longer locks CONFIGx updates -* Do not set Interfame Gap (IFG) bits in TxConfig -* Better Rx reset logic in case of Rx FIFO Overflow -* For chips which support it, enable bit to automatically clear Rx - FIFO overflow -* No longer enable and disable interrupts in interrupt handler - (technique borrowed from BSD driver, appears to have problems - with some chips) -* H/W spinlock now protects ioctl -* Chipset-dependent RxConfig settings - - -Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release - -* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now) -* Softnet logic updates to fix bugs and improve performance -* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones) -* Remove bogus SiS entries from PCI probe table -* Add support for cards - "Delta Electronics 8139 10/100BaseTX" - "Addtron Technolgy 8139 10/100BaseTX" -* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r) -* PCI DMA mapping by Dave Miller -* Complete rewrite of SMP locking logic -* Hotplug support -* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code - from rtl8139_open -* Reset NWay registers to sane defaults on rtl8139_open/hw_start -* Miscellaneous code cleanup - - -Version 0.7.0 - Feb 7, 2000 - first public beta release -* Initial public version, derived from Donald Becker's rtl8139.c v1.08r - -[EOF] - --- linux-2.6.1-rc1/Documentation/networking/bonding.txt 2003-09-27 18:57:43.000000000 -0700 +++ 25/Documentation/networking/bonding.txt 2003-12-30 22:49:19.000000000 -0800 @@ -21,7 +21,7 @@ userspace tools, please follow the links Table of Contents ================= - + Installation Bond Configuration Module Parameters @@ -66,7 +66,7 @@ of the -I option on the ifenslave compil /usr/include/linux. To install ifenslave.c, do: - # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave + # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave # cp ifenslave /sbin/ifenslave @@ -74,10 +74,10 @@ Bond Configuration ================== You will need to add at least the following line to /etc/modules.conf -so the bonding driver will automatically load when the bond0 interface is -configured. Refer to the modules.conf manual page for specific modules.conf -syntax details. The Module Parameters section of this document describes each -bonding driver parameter. +so the bonding driver will automatically load when the bond0 interface is +configured. Refer to the modules.conf manual page for specific modules.conf +syntax details. The Module Parameters section of this document describes each +bonding driver parameter. alias bond0 bonding @@ -113,7 +113,7 @@ bonding interface (bond1), use MASTER=bo network interface be a slave of bond1. Restart the networking subsystem or just bring up the bonding device if your -administration tools allow it. Otherwise, reboot. On Red Hat distros you can +administration tools allow it. Otherwise, reboot. On Red Hat distros you can issue `ifup bond0' or `/etc/rc.d/init.d/network restart'. If the administration tools of your distribution do not support @@ -128,30 +128,30 @@ manually configure the bonding device wi (use appropriate values for your network above) -You can then create a script containing these commands and place it in the +You can then create a script containing these commands and place it in the appropriate rc directory. If you specifically need all network drivers loaded before the bonding driver, -adding the following line to modules.conf will cause the network driver for +adding the following line to modules.conf will cause the network driver for eth0 and eth1 to be loaded before the bonding driver. probeall bond0 eth0 eth1 bonding -Be careful not to reference bond0 itself at the end of the line, or modprobe +Be careful not to reference bond0 itself at the end of the line, or modprobe will die in an endless recursive loop. -To have device characteristics (such as MTU size) propagate to slave devices, -set the bond characteristics before enslaving the device. The characteristics +To have device characteristics (such as MTU size) propagate to slave devices, +set the bond characteristics before enslaving the device. The characteristics are propagated during the enslave process. -If running SNMP agents, the bonding driver should be loaded before any network -drivers participating in a bond. This requirement is due to the the interface -index (ipAdEntIfIndex) being associated to the first interface found with a -given IP address. That is, there is only one ipAdEntIfIndex for each IP -address. For example, if eth0 and eth1 are slaves of bond0 and the driver for -eth0 is loaded before the bonding driver, the interface for the IP address -will be associated with the eth0 interface. This configuration is shown below, -the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 +If running SNMP agents, the bonding driver should be loaded before any network +drivers participating in a bond. This requirement is due to the the interface +index (ipAdEntIfIndex) being associated to the first interface found with a +given IP address. That is, there is only one ipAdEntIfIndex for each IP +address. For example, if eth0 and eth1 are slaves of bond0 and the driver for +eth0 is loaded before the bonding driver, the interface for the IP address +will be associated with the eth0 interface. This configuration is shown below, +the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 in the ifDescr table (ifDescr.2). interfaces.ifTable.ifEntry.ifDescr.1 = lo @@ -189,10 +189,10 @@ functions such as Interface_Scan_Next wi Module Parameters ================= -Optional parameters for the bonding driver can be supplied as command line -arguments to the insmod command. Typically, these parameters are specified in -the file /etc/modules.conf (see the manual page for modules.conf). The -available bonding driver parameters are listed below. If a parameter is not +Optional parameters for the bonding driver can be supplied as command line +arguments to the insmod command. Typically, these parameters are specified in +the file /etc/modules.conf (see the manual page for modules.conf). The +available bonding driver parameters are listed below. If a parameter is not specified the default value is used. When initially configuring a bond, it is recommended "tail -f /var/log/messages" be run in a separate window to watch for bonding driver error messages. @@ -202,19 +202,19 @@ parameters be specified, otherwise serio during link failures. arp_interval - - Specifies the ARP monitoring frequency in milli-seconds. - If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the - switch should be configured in a mode that evenly distributes packets - across all links - such as round-robin. If the switch is configured to - distribute the packets in an XOR fashion, all replies from the ARP - targets will be received on the same link which could cause the other + + Specifies the ARP monitoring frequency in milli-seconds. + If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the + switch should be configured in a mode that evenly distributes packets + across all links - such as round-robin. If the switch is configured to + distribute the packets in an XOR fashion, all replies from the ARP + targets will be received on the same link which could cause the other team members to fail. ARP monitoring should not be used in conjunction - with miimon. A value of 0 disables ARP monitoring. The default value + with miimon. A value of 0 disables ARP monitoring. The default value is 0. - + arp_ip_target - + Specifies the ip addresses to use when arp_interval is > 0. These are the targets of the ARP request sent to determine the health of the link to the targets. Specify these values in ddd.ddd.ddd.ddd @@ -223,8 +223,8 @@ arp_ip_target maximum number of targets that can be specified is set at 16. downdelay - - Specifies the delay time in milli-seconds to disable a link after a + + Specifies the delay time in milli-seconds to disable a link after a link failure has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. @@ -247,7 +247,7 @@ max_bonds and bond2 will be created. The default value is 1. miimon - + Specifies the frequency in milli-seconds that MII link monitoring will occur. A value of zero disables MII link monitoring. A value of 100 is a good starting point. See High Availability section for @@ -258,7 +258,7 @@ mode Specifies one of the bonding policies. The default is round-robin (balance-rr). Possible values are (you can use either the text or numeric option): - + balance-rr or 0 Round-robin policy: Transmit in a sequential order @@ -273,7 +273,7 @@ mode externally visible on only one port (network adapter) to avoid confusing the switch. This mode provides fault tolerance. - + balance-xor or 2 XOR policy: Transmit based on [(source MAC address @@ -293,7 +293,7 @@ mode groups that share the same speed and duplex settings. Transmits and receives on all slaves in the active aggregator. - + Pre-requisites: 1. Ethtool support in the base drivers for retrieving the @@ -317,7 +317,7 @@ mode Ethtool support in the base drivers for retrieving the speed of each slave. - balance-alb or 6 + balance-alb or 6 Adaptive load balancing: includes balance-tlb + receive load balancing (rlb) for IPV4 traffic and does not require @@ -327,7 +327,7 @@ mode overwrites the src hw address with the unique hw address of one of the slaves in the bond such that different clients use different hw addresses for the server. - + Receive traffic from connections created by the server is also balanced. When the server sends an ARP Request the bonding driver copies and saves the client's IP information @@ -363,25 +363,11 @@ mode 2. Base driver support for setting the hw address of a device also when it is open. This is required so that there will always be one slave in the team using the bond hw - address (the current_slave) while having a unique hw - address for each slave in the bond. If the current_slave - fails it's hw address is swapped with the new current_slave + address (the curr_active_slave) while having a unique hw + address for each slave in the bond. If the curr_active_slave + fails it's hw address is swapped with the new curr_active_slave that was chosen. -multicast - - Option specifying the mode of operation for multicast support. - Possible values are: - - disabled or 0 - Disabled (no multicast support) - - active or 1 - Enabled on active slave only, useful in active-backup mode - - all or 2 - Enabled on all slaves, this is the default - primary A string (eth0, eth2, etc) to equate to a primary device. If this @@ -397,11 +383,11 @@ primary primary is only valid in active-backup mode. updelay - - Specifies the delay time in milli-seconds to enable a link after a + + Specifies the delay time in milli-seconds to enable a link after a link up status has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. - + use_carrier Specifies whether or not miimon should use MII or ETHTOOL @@ -529,20 +515,20 @@ Verifying Bond Configuration ---------------------------- The bonding driver information files reside in the /proc/net/bonding directory. -Sample contents of /proc/net/bonding/bond0 after the driver is loaded with +Sample contents of /proc/net/bonding/bond0 after the driver is loaded with parameters of mode=0 and miimon=1000 is shown below. - + Bonding Mode: load balancing (round-robin) Currently Active Slave: eth0 MII Status: up MII Polling Interval (ms): 1000 Up Delay (ms): 0 Down Delay (ms): 0 - + Slave Interface: eth1 MII Status: up Link Failure Count: 1 - + Slave Interface: eth0 MII Status: up Link Failure Count: 1 @@ -550,34 +536,34 @@ parameters of mode=0 and miimon=1000 is 2) Network verification ----------------------- The network configuration can be verified using the ifconfig command. In -the example below, the bond0 interface is the master (MASTER) while eth0 and -eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address +the example below, the bond0 interface is the master (MASTER) while eth0 and +eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address (HWaddr) as bond0 for all modes except TLB and ALB that require a unique MAC address for each slave. [root]# /sbin/ifconfig -bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:0 + collisions:0 txqueuelen:0 -eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:10 Base address:0x1080 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 -eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:9 Base address:0x1400 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 Frequently Asked Questions @@ -605,9 +591,9 @@ Frequently Asked Questions 5. What happens when a slave link dies? - If your ethernet cards support MII or ETHTOOL link status monitoring - and the MII monitoring has been enabled in the driver (see description - of module parameters), there will be no adverse consequences. This + If your ethernet cards support MII or ETHTOOL link status monitoring + and the MII monitoring has been enabled in the driver (see description + of module parameters), there will be no adverse consequences. This release of the bonding driver knows how to get the MII information and enables or disables its slaves according to their link status. See section on High Availability for additional information. @@ -622,8 +608,8 @@ Frequently Asked Questions slave. If neither mii_monitor and arp_interval is configured, the bonding - driver will not handle this situation very well. The driver will - continue to send packets but some packets will be lost. Retransmits + driver will not handle this situation very well. The driver will + continue to send packets but some packets will be lost. Retransmits will cause serious degradation of performance (in the case when one of two slave links fails, 50% packets will be lost, which is a serious problem for both TCP and UDP). @@ -636,9 +622,9 @@ Frequently Asked Questions 7. Which switches/systems does it work with? - In round-robin and XOR mode, it works with systems that support + In round-robin and XOR mode, it works with systems that support trunking: - + * Many Cisco switches and routers (look for EtherChannel support). * SunTrunking software. * Alteon AceDirector switches / WebOS (use Trunks). @@ -646,7 +632,7 @@ Frequently Asked Questions models (450) can define trunks between ports on different physical units. * Linux bonding, of course ! - + In 802.3ad mode, it works with with systems that support IEEE 802.3ad Dynamic Link Aggregation: @@ -667,21 +653,21 @@ Frequently Asked Questions is then passed to all following slaves and remains persistent (even if the the first slave is removed) until the bonding device is brought down or reconfigured. - + If you wish to change the MAC address, you can set it with ifconfig: # ifconfig bond0 hw ether 00:11:22:33:44:55 The MAC address can be also changed by bringing down/up the device and then changing its slaves (or their order): - + # ifconfig bond0 down ; modprobe -r bonding # ifconfig bond0 .... up # ifenslave bond0 eth... This method will automatically take the address from the next slave that will be added. - + To restore your slaves' MAC addresses, you need to detach them from the bond (`ifenslave -d bond0 eth0'), set them down (`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for @@ -729,27 +715,27 @@ High Availability ================= To implement high availability using the bonding driver, the driver needs to be -compiled as a module, because currently it is the only way to pass parameters +compiled as a module, because currently it is the only way to pass parameters to the driver. This may change in the future. -High availability is achieved by using MII or ETHTOOL status reporting. You -need to verify that all your interfaces support MII or ETHTOOL link status -reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and -yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting -is available for interface eth0, type "ethtool eth0" and the "Link detected:" -line should contain the correct link status. If your system has an interface -that does not support MII or ETHTOOL status reporting, a failure of its link -will not be detected! A message indicating MII and ETHTOOL is not supported by -a network driver is logged when the bonding driver is loaded with a non-zero +High availability is achieved by using MII or ETHTOOL status reporting. You +need to verify that all your interfaces support MII or ETHTOOL link status +reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and +yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting +is available for interface eth0, type "ethtool eth0" and the "Link detected:" +line should contain the correct link status. If your system has an interface +that does not support MII or ETHTOOL status reporting, a failure of its link +will not be detected! A message indicating MII and ETHTOOL is not supported by +a network driver is logged when the bonding driver is loaded with a non-zero miimon value. The bonding driver can regularly check all its slaves links using the ETHTOOL -IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The -check interval is specified by the module argument "miimon" (MII monitoring). -It takes an integer that represents the checking time in milliseconds. It -should not come to close to (1000/HZ) (10 milli-seconds on i386) because it -may then reduce the system interactivity. A value of 100 seems to be a good -starting point. It means that a dead link will be detected at most 100 +IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The +check interval is specified by the module argument "miimon" (MII monitoring). +It takes an integer that represents the checking time in milliseconds. It +should not come to close to (1000/HZ) (10 milli-seconds on i386) because it +may then reduce the system interactivity. A value of 100 seems to be a good +starting point. It means that a dead link will be detected at most 100 milli-seconds after it goes down. Example: @@ -761,7 +747,7 @@ Or, put the following lines in /etc/modu alias bond0 bonding options bond0 miimon=100 -There are currently two policies for high availability. They are dependent on +There are currently two policies for high availability. They are dependent on whether: a) hosts are connected to a single host or switch that support trunking @@ -811,7 +797,7 @@ Example 2 : host to switch at twice the # ifenslave bond0 eth0 eth1 -2) High Availability on two or more switches (or a single switch without +2) High Availability on two or more switches (or a single switch without trunking support) --------------------------------------------------------------------------- This mode is more problematic because it relies on the fact that there @@ -870,10 +856,10 @@ by another external mechanism, it is goo connected to one switch and host2's to the other. Such system will survive a failure of a single host, cable, or switch. The worst thing that may happen in the case of a switch failure is that half of the hosts will be temporarily -unreachable until the other switch expires its tables. +unreachable until the other switch expires its tables. Example 2: Using multiple ethernet cards connected to a switch to configure - NIC failover (switch is not required to support trunking). + NIC failover (switch is not required to support trunking). +----------+ +----------+ @@ -957,7 +943,7 @@ The main limitations are : servers, but may be useful when the front switches send multicast information on their links (e.g. VRRP), or even health-check the servers. Use the arp_interval/arp_ip_target parameters to count incoming/outgoing - frames. + frames. @@ -973,13 +959,12 @@ Donald Becker's Ethernet Drivers and dia You will also find a lot of information regarding Ethernet, NWay, MII, etc. at www.scyld.com. -For new versions of the driver, patches for older kernels and the updated -userspace tools, take a look at Willy Tarreau's site : +Patches for 2.2 kernels are at Willy Tarreau's site : - http://wtarreau.free.fr/pub/bonding/ - - http://www-miaif.lip6.fr/willy/pub/bonding/ + - http://www-miaif.lip6.fr/~tarreau/pub/bonding/ To get latest informations about Linux Kernel development, please consult the Linux Kernel Mailing List Archives at : - http://boudicca.tux.org/hypermail/linux-kernel/latest/ + http://www.ussg.iu.edu/hypermail/linux/kernel/ -- END -- --- linux-2.6.1-rc1/Documentation/networking/ifenslave.c 2003-09-27 18:57:43.000000000 -0700 +++ 25/Documentation/networking/ifenslave.c 2003-12-30 22:49:19.000000000 -0800 @@ -4,8 +4,6 @@ * This program controls the Linux implementation of running multiple * network interfaces in parallel. * - * Usage: ifenslave [-v] master-interface < slave-interface [metric ] > ... - * * Author: Donald Becker * Copyright 1994-1996 Donald Becker * @@ -90,24 +88,30 @@ * - For opt_c: slave should not be set to the master's setting * while it is running. It was already set during enslave. To * simplify things, it is now handeled separately. + * + * - 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes + * set version to 1.1.0 */ -#define APP_VERSION "1.0.12" -#define APP_RELDATE "June 30, 2003" +#define APP_VERSION "1.1.0" +#define APP_RELDATE "Septemer 24, 2003" #define APP_NAME "ifenslave" static char *version = -APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" -"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" -"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; +APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" +"o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +"o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" +"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" +" (ctindel at ieee dot org).\n"; static const char *usage_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n"; +"Usage: ifenslave [-f] [...]\n" +" ifenslave -d [...]\n" +" ifenslave -c \n" +" ifenslave --help\n"; -static const char *howto_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n" +static const char *help_msg = "\n" " To create a bond device, simply follow these three steps :\n" " - ensure that the required drivers are properly loaded :\n" @@ -115,18 +119,32 @@ static const char *howto_msg = " - assign an IP address to the bond device :\n" " # ifconfig bond0 netmask broadcast \n" " - attach all the interfaces you need to the bond device :\n" -" # ifenslave bond0 eth0 eth1 eth2\n" +" # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" " interfaces attached AFTER this assignment will get the same MAC addr.\n" -"\n" -" To detach a dead interface without setting the bond device down :\n" -" # ifenslave -d bond0 eth1\n" +" (except for ALB/TLB modes)\n" "\n" " To set the bond device down and automatically release all the slaves :\n" " # ifconfig bond0 down\n" "\n" +" To detach a dead interface without setting the bond device down :\n" +" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" +"\n" " To change active slave :\n" -" # ifenslave -c bond0 eth0\n" +" # ifenslave {-c|--change-active} bond0 eth0\n" +"\n" +" To show master interface info\n" +" # ifenslave bond0\n" +"\n" +" To show all interfaces info\n" +" # ifenslave {-a|--all-interfaces}\n" +"\n" +" To be more verbose\n" +" # ifenslave {-v|--verbose} ...\n" +"\n" +" # ifenslave {-u|--usage} Show usage\n" +" # ifenslave {-V|--version} Show version\n" +" # ifenslave {-h|--help} This message\n" "\n"; #include @@ -153,476 +171,332 @@ typedef __uint8_t u8; /* ditto */ #include struct option longopts[] = { - /* { name has_arg *flag val } */ - {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ - {"force", 0, 0, 'f'}, /* Force the operation. */ - {"help", 0, 0, '?'}, /* Give help */ - {"howto", 0, 0, 'h'}, /* Give some more help */ - {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */ - {"verbose", 0, 0, 'v'}, /* Report each action taken. */ - {"version", 0, 0, 'V'}, /* Emit version information. */ - {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ - {"change-active", 0, 0, 'c'}, /* Change the active slave. */ - { 0, 0, 0, 0 } + /* { name has_arg *flag val } */ + {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ + {"change-active", 0, 0, 'c'}, /* Change the active slave. */ + {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ + {"force", 0, 0, 'f'}, /* Force the operation. */ + {"help", 0, 0, 'h'}, /* Give help */ + {"usage", 0, 0, 'u'}, /* Give usage */ + {"verbose", 0, 0, 'v'}, /* Report each action taken. */ + {"version", 0, 0, 'V'}, /* Emit version information. */ + { 0, 0, 0, 0} }; /* Command-line flags. */ unsigned int -opt_a = 0, /* Show-all-interfaces flag. */ -opt_f = 0, /* Force the operation. */ -opt_r = 0, /* Set up a Rx-only slave. */ -opt_d = 0, /* detach a slave interface. */ -opt_c = 0, /* change-active-slave flag. */ -verbose = 0, /* Verbose flag. */ -opt_version = 0, -opt_howto = 0; -int skfd = -1; /* AF_INET socket for ioctl() calls. */ +opt_a = 0, /* Show-all-interfaces flag. */ +opt_c = 0, /* Change-active-slave flag. */ +opt_d = 0, /* Detach a slave interface. */ +opt_f = 0, /* Force the operation. */ +opt_h = 0, /* Help */ +opt_u = 0, /* Usage */ +opt_v = 0, /* Verbose flag. */ +opt_V = 0; /* Version */ + +int skfd = -1; /* AF_INET socket for ioctl() calls.*/ +int abi_ver = 0; /* userland - kernel ABI version */ +int hwaddr_set = 0; /* Master's hwaddr is set */ +int saved_errno; + +struct ifreq master_mtu, master_flags, master_hwaddr; +struct ifreq slave_mtu, slave_flags, slave_hwaddr; + +struct dev_ifr { + struct ifreq *req_ifr; + char *req_name; + int req_type; +}; + +struct dev_ifr master_ifra[] = { + {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; + +struct dev_ifr slave_ifra[] = { + {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; static void if_print(char *ifname); -static int get_abi_ver(char *master_ifname); +static int get_drv_info(char *master_ifname); +static int get_if_settings(char *ifname, struct dev_ifr ifra[]); +static int get_slave_flags(char *slave_ifname); +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); +static int set_slave_mtu(char *slave_ifname, int mtu); +static int set_if_flags(char *ifname, short flags); +static int set_if_up(char *ifname, short flags); +static int set_if_down(char *ifname, short flags); +static int clear_if_addr(char *ifname); +static int set_if_addr(char *master_ifname, char *slave_ifname); +static int change_active(char *master_ifname, char *slave_ifname); +static int enslave(char *master_ifname, char *slave_ifname); +static int release(char *master_ifname, char *slave_ifname); +#define v_print(fmt, args...) \ + if (opt_v) \ + fprintf(stderr, fmt, ## args ) -int -main(int argc, char **argv) +int main(int argc, char *argv[]) { - struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; - struct ifreq if_netmask, if_brdaddr, if_flags; - int rv, goterr = 0; - int c, errflag = 0; - sa_family_t master_family; char **spp, *master_ifname, *slave_ifname; - int hwaddr_notset; - int abi_ver = 0; + int c, i, rv; + int res = 0; + int exclusive = 0; - while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) + while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { switch (c) { - case 'a': opt_a++; break; - case 'f': opt_f++; break; - case 'r': opt_r++; break; - case 'd': opt_d++; break; - case 'c': opt_c++; break; - case 'v': verbose++; break; - case 'V': opt_version++; break; - case 'h': opt_howto++; break; - case '?': errflag++; - } + case 'a': opt_a++; exclusive++; break; + case 'c': opt_c++; exclusive++; break; + case 'd': opt_d++; exclusive++; break; + case 'f': opt_f++; exclusive++; break; + case 'h': opt_h++; exclusive++; break; + case 'u': opt_u++; exclusive++; break; + case 'v': opt_v++; break; + case 'V': opt_V++; exclusive++; break; - /* option check */ - if (opt_c) - if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || - opt_howto || errflag ) { + case '?': fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } + } - if (errflag) { + /* options check */ + if (exclusive > 1) { fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } - if (opt_howto) { - fprintf(stderr, howto_msg); - return 0; + if (opt_v || opt_V) { + printf(version); + if (opt_V) { + res = 0; + goto out; + } } - if (verbose || opt_version) { - printf(version); - if (opt_version) - exit(0); + if (opt_u) { + printf(usage_msg); + res = 0; + goto out; } - /* Open a basic socket. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { - perror("socket"); - exit(-1); + if (opt_h) { + printf(usage_msg); + printf(help_msg); + res = 0; + goto out; } - if (verbose) - fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", - argc, optind, argv[optind]); + /* Open a basic socket */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + res = 1; + goto out; + } - /* No remaining args means show all interfaces. */ - if (optind == argc) { - if_print((char *)NULL); - (void) close(skfd); - exit(0); + if (opt_a) { + if (optind == argc) { + /* No remaining args */ + /* show all interfaces */ + if_print((char *)NULL); + goto out; + } else { + /* Just show usage */ + fprintf(stderr, usage_msg); + res = 2; + goto out; + } } - /* Copy the interface name. */ + /* Copy the interface name */ spp = argv + optind; master_ifname = *spp++; - slave_ifname = *spp++; - /* Check command line. */ - if (opt_c) { - char **tempp = spp; - if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { - fprintf(stderr, usage_msg); - (void) close(skfd); - return 2; - } + if (master_ifname == NULL) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* A single args means show the configuration for this interface. */ - if (slave_ifname == NULL) { - if_print(master_ifname); - (void) close(skfd); - exit(0); + /* exchange abi version with bonding module */ + res = get_drv_info(master_ifname); + if (res) { + fprintf(stderr, + "Master '%s': Error: handshake with driver failed. " + "Aborting\n", + master_ifname); + goto out; } - /* exchange abi version with bonding driver */ - abi_ver = get_abi_ver(master_ifname); - if (abi_ver < 0) { - (void) close(skfd); - exit(1); - } - - /* Get the vitals from the master interface. */ - { - struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, - &if_brdaddr, &if_netmask, &if_flags, - &if_hwaddr }; - const char *req_name[7] = { - "IP address", "MTU", "destination address", - "broadcast address", "netmask", "status flags", - "hardware address" }; - const int ioctl_req_type[7] = { - SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR, - SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, - SIOCGIFHWADDR }; - int i; - - for (i = 0; i < 7; i++) { - strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); - if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { - fprintf(stderr, - "Something broke getting the master's %s: %s.\n", - req_name[i], strerror(errno)); - } - } - - /* check if master is up; if not then fail any operation */ - if (!(if_flags.ifr_flags & IFF_UP)) { - fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname); - (void) close(skfd); - exit (1); - } + slave_ifname = *spp++; - hwaddr_notset = 1; /* assume master's address not set yet */ - for (i = 0; hwaddr_notset && (i < 6); i++) { - hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; + if (slave_ifname == NULL) { + if (opt_d || opt_c) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* The family '1' is ARPHRD_ETHER for ethernet. */ - if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) { - fprintf(stderr, "The specified master interface '%s' is not" - " ethernet-like.\n This program is designed to work" - " with ethernet-like network interfaces.\n" - " Use the '-f' option to force the operation.\n", - master_ifname); - (void) close(skfd); - exit (1); - } - master_family = if_hwaddr.ifr_hwaddr.sa_family; - if (verbose) { - unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data; - printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname, - if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* A single arg means show the + * configuration for this interface + */ + if_print(master_ifname); + goto out; } + res = get_if_settings(master_ifname, master_ifra); + if (res) { + /* Probably a good reason not to go on */ + fprintf(stderr, + "Master '%s': Error: get settings failed: %s. " + "Aborting\n", + master_ifname, strerror(res)); + goto out; + } - /* do this when enslaving interfaces */ - do { - if (opt_d) { /* detach a slave interface from the master */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) && - (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", - slave_ifname, master_ifname, strerror(errno)); - } - else if (abi_ver < 1) { - /* The driver is using an old ABI, so we'll set the interface - * down to avoid any conflicts due to same IP/MAC - */ - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - } - else { - ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - } - } else if (opt_c) { /* change primary slave */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && - (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); - } - } else { /* attach a slave interface to the master */ - - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - (void) close(skfd); - return 1; - } - - if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { - fprintf(stderr, "%s is already a slave\n", slave_ifname); - (void) close(skfd); - return 1; - } - - /* if hwaddr_notset, assign the slave hw address to the master */ - if (hwaddr_notset) { - /* assign the slave hw address to the - * master since it currently does not - * have one; otherwise, slaves may - * have different hw addresses in - * active-backup mode as seen when enslaving - * using "ifenslave bond0 eth0 eth1" because - * hwaddr_notset is set outside this loop. - * TODO: put this and the "else" portion in - * a function. - */ - /* get the slaves MAC address */ - strncpy(if_hwaddr.ifr_name, slave_ifname, - IFNAMSIZ); - rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr); - if (-1 == rv) { - fprintf(stderr, "Could not get MAC " - "address of %s: %s\n", - slave_ifname, - strerror(errno)); - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - goterr = 1; - } - - if (!goterr) { - if (abi_ver < 1) { - /* In ABI versions older than 1, the - * master's set_mac routine couldn't - * work if it was up, because it - * used the default ethernet set_mac - * function. - */ - /* bring master down */ - if_flags.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - goterr = 1; - fprintf(stderr, - "Shutting down " - "interface %s failed: " - "%s\n", - master_ifname, - strerror(errno)); - } - } - - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, - &if_hwaddr) < 0) { - fprintf(stderr, - "Could not set MAC " - "address of %s: %s\n", - master_ifname, - strerror(errno)); - goterr=1; - } else { - hwaddr_notset = 0; - } - - if (abi_ver < 1) { - /* bring master back up */ - if_flags.ifr_flags |= IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - fprintf(stderr, - "Bringing up interface " - "%s failed: %s\n", - master_ifname, - strerror(errno)); - } - } - } - } else if (abi_ver < 1) { /* if (hwaddr_notset) */ - - /* The driver is using an old ABI, so we'll set the interface - * down and assign the master's hwaddr to it - */ - if (ifr2.ifr_flags & IFF_UP) { - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - - strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, - strerror(saved_errno)); - if (saved_errno == EBUSY) - fprintf(stderr, " The slave device %s is busy: it must be" - " idle before running this command.\n", slave_ifname); - else if (saved_errno == EOPNOTSUPP) - fprintf(stderr, " The slave device you specified does not support" - " setting the MAC address.\n Your kernel likely does not" - " support slave devices.\n"); - else if (saved_errno == EINVAL) - fprintf(stderr, " The slave device's address type does not match" - " the master's address type.\n"); - } else { - if (verbose) { - unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; - printf("Slave's (%s) hardware address set to " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, - hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } - } - } + /* check if master is indeed a master; + * if not then fail any operation + */ + if (!(master_flags.ifr_flags & IFF_MASTER)) { + fprintf(stderr, + "Illegal operation; the specified interface '%s' " + "is not a master. Aborting\n", + master_ifname); + res = 1; + goto out; + } - if (*spp && !strcmp(*spp, "metric")) { - if (*++spp == NULL) { - fprintf(stderr, usage_msg); - (void) close(skfd); - exit(2); - } - if_metric.ifr_metric = atoi(*spp); - strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { - fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, - strerror(errno)); - goterr = 1; - } - spp++; - } + /* check if master is up; if not then fail any operation */ + if (!(master_flags.ifr_flags & IFF_UP)) { + fprintf(stderr, + "Illegal operation; the specified master interface " + "'%s' is not up.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave's address: %s.\n", - strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; - printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + /* Only for enslaving */ + if (!opt_c && !opt_d) { + sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; + unsigned char *hwaddr = + (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; - if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { - fprintf(stderr, "Something broke setting the slave MTU: %s.\n", - strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); - } + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (master_family != 1 && !opt_f) { + fprintf(stderr, + "Illegal operation: The specified master " + "interface '%s' is not ethernet-like.\n " + "This program is designed to work with " + "ethernet-like network interfaces.\n " + "Use the '-f' option to force the " + "operation.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { - fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; - printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } + /* Check master's hw addr */ + for (i = 0; i < 6; i++) { + if (hwaddr[i] != 0) { + hwaddr_set = 1; + break; } + } - if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) broadcast address: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; - printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + if (hwaddr_set) { + v_print("current hardware address of master '%s' " + "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "type %d\n", + master_ifname, + hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], + hwaddr[4], hwaddr[5], + master_family); + } + } - if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) netmask: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; - printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + /* Accepts only one slave */ + if (opt_c) { + /* change active slave */ + res = get_slave_flags(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: get flags failed. " + "Aborting\n", + slave_ifname); + goto out; + } + res = change_active(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Change active failed\n", + master_ifname, slave_ifname); + } + } else { + /* Accept multiple slaves */ + do { + if (opt_d) { + /* detach a slave interface from the master */ + rv = get_slave_flags(slave_ifname); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get flags " + "failed. Skipping\n", + slave_ifname); + res = rv; + continue; } - } - - if (abi_ver < 1) { - - /* The driver is using an old ABI, so we'll set the interface - * up before enslaving it - */ - ifr2.ifr_flags |= IFF_UP; - if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 - || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) flags: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) flags %4.4x.\n", - slave_ifname, if_flags.ifr_flags); + rv = release(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Release failed\n", + master_ifname, slave_ifname); + res = rv; } } else { - /* the bonding module takes care of setting the slave's mac address - * and opening its interface - */ - if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } + /* attach a slave interface to the master */ + rv = get_if_settings(slave_ifname, slave_ifra); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get " + "settings failed: %s. " + "Skipping\n", + slave_ifname, strerror(rv)); + res = rv; + continue; } - } - - /* Do the real thing */ - if (!opt_r) { - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && - (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + rv = enslave(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Enslave failed\n", + master_ifname, slave_ifname); + res = rv; } } - } - } while ( (slave_ifname = *spp++) != NULL); + } while ((slave_ifname = *spp++) != NULL); + } - /* Close the socket. */ - (void) close(skfd); +out: + if (skfd >= 0) { + close(skfd); + } - return(goterr); + return res; } static short mif_flags; @@ -631,35 +505,34 @@ static short mif_flags; static int if_getconfig(char *ifname) { struct ifreq ifr; - int metric, mtu; /* Parameters of the master interface. */ + int metric, mtu; /* Parameters of the master interface. */ struct sockaddr dstaddr, broadaddr, netmask; + unsigned char *hwaddr; strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) return -1; mif_flags = ifr.ifr_flags; printf("The result of SIOCGIFFLAGS on %s is %x.\n", - ifname, ifr.ifr_flags); + ifname, ifr.ifr_flags); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) return -1; printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", - ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], - ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) return -1; - { - /* Gotta convert from 'char' to unsigned for printf(). */ - unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; - printf("The result of SIOCGIFHWADDR is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* Gotta convert from 'char' to unsigned for printf(). */ + hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { @@ -691,7 +564,7 @@ static int if_getconfig(char *ifname) } else netmask = ifr.ifr_netmask; - return(0); + return 0; } static void if_print(char *ifname) @@ -705,15 +578,16 @@ static void if_print(char *ifname) ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + perror("SIOCGIFCONF failed"); return; } ifr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { if (if_getconfig(ifr->ifr_name) < 0) { - fprintf(stderr, "%s: unknown interface.\n", - ifr->ifr_name); + fprintf(stderr, + "%s: unknown interface.\n", + ifr->ifr_name); continue; } @@ -721,16 +595,18 @@ static void if_print(char *ifname) /*ife_print(&ife);*/ } } else { - if (if_getconfig(ifname) < 0) - fprintf(stderr, "%s: unknown interface.\n", ifname); + if (if_getconfig(ifname) < 0) { + fprintf(stderr, + "%s: unknown interface.\n", ifname); + } } } -static int get_abi_ver(char *master_ifname) +static int get_drv_info(char *master_ifname) { struct ifreq ifr; struct ethtool_drvinfo info; - int abi_ver = 0; + char *endptr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); @@ -739,24 +615,487 @@ static int get_abi_ver(char *master_ifna info.cmd = ETHTOOL_GDRVINFO; strncpy(info.driver, "ifenslave", 32); snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) { - char *endptr; - abi_ver = strtoul(info.fw_version, &endptr, 0); - if (*endptr) { - fprintf(stderr, "Error: got invalid string as an ABI " - "version from the bonding module\n"); - return -1; + if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { + if (errno == EOPNOTSUPP) { + goto out; } + + saved_errno = errno; + v_print("Master '%s': Error: get bonding info failed %s\n", + master_ifname, strerror(saved_errno)); + return 1; } - if (verbose) { - printf("ABI ver is %d\n", abi_ver); + abi_ver = strtoul(info.fw_version, &endptr, 0); + if (*endptr) { + v_print("Master '%s': Error: got invalid string as an ABI " + "version from the bonding module\n", + master_ifname); + return 1; } - return abi_ver; + +out: + v_print("ABI ver is %d\n", abi_ver); + + return 0; } +static int change_active(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " + "%s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + return res; +} + +static int enslave(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (slave_flags.ifr_flags & IFF_SLAVE) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is already a slave\n", + slave_ifname); + return 1; + } + + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface down failed\n", + slave_ifname); + return res; + } + + if (abi_ver < 2) { + /* Older bonding versions would panic if the slave has no IP + * address, so get the IP setting from the master. + */ + res = set_if_addr(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set address failed\n", + slave_ifname); + return res; + } + } else { + res = clear_if_addr(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: clear address failed\n", + slave_ifname); + return res; + } + } + + if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { + res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set MTU failed\n", + slave_ifname); + return res; + } + } + + if (hwaddr_set) { + /* Master already has an hwaddr + * so set it's hwaddr to the slave + */ + if (abi_ver < 1) { + /* The driver is using an old ABI, so + * the application sets the slave's + * hwaddr + */ + res = set_slave_hwaddr(slave_ifname, + &(master_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set hw address " + "failed\n", + slave_ifname); + goto undo_mtu; + } + + /* For old ABI the application needs to bring the + * slave back up + */ + res = set_if_up(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + goto undo_slave_mac; + } + } + /* The driver is using a new ABI, + * so the driver takes care of setting + * the slave's hwaddr and bringing + * it up again + */ + } else { + /* No hwaddr for master yet, so + * set the slave's hwaddr to it + */ + if (abi_ver < 1) { + /* For old ABI, the master needs to be + * down before setting it's hwaddr + */ + res = set_if_down(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "down failed\n", + master_ifname); + goto undo_mtu; + } + } + + res = set_master_hwaddr(master_ifname, + &(slave_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Master '%s': Error: set hw address " + "failed\n", + master_ifname); + goto undo_mtu; + } + + if (abi_ver < 1) { + /* For old ABI, bring the master + * back up + */ + res = set_if_up(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "up failed\n", + master_ifname); + goto undo_master_mac; + } + } + + hwaddr_set = 1; + } + + /* Do the real thing */ + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + if (res) { + goto undo_master_mac; + } + + return 0; + +/* rollback (best effort) */ +undo_master_mac: + set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); + hwaddr_set = 0; + goto undo_mtu; +undo_slave_mac: + set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); +undo_mtu: + set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); + return res; +} + +static int release(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && + (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", + master_ifname, strerror(saved_errno)); + return 1; + } else if (abi_ver < 1) { + /* The driver is using an old ABI, so we'll set the interface + * down to avoid any conflicts due to same MAC/IP + */ + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + } + } + + /* set to default mtu */ + set_slave_mtu(slave_ifname, 1500); + + return res; +} + +static int get_if_settings(char *ifname, struct dev_ifr ifra[]) +{ + int i; + int res = 0; + + for (i = 0; ifra[i].req_ifr; i++) { + strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: %s failed: %s\n", + ifname, ifra[i].req_name, + strerror(saved_errno)); + + return saved_errno; + } + } + + return 0; +} + +static int get_slave_flags(char *slave_ifname) +{ + int res = 0; + + strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave %s: flags %04X.\n", + slave_ifname, slave_flags.ifr_flags); + } + + return res; +} + +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", + master_ifname, strerror(saved_errno)); + return res; + } else { + v_print("Master '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + master_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + + v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", + slave_ifname, strerror(saved_errno)); + + if (saved_errno == EBUSY) { + v_print(" The device is busy: it must be idle " + "before running this command.\n"); + } else if (saved_errno == EOPNOTSUPP) { + v_print(" The device does not support setting " + "the MAC address.\n" + " Your kernel likely does not support slave " + "devices.\n"); + } else if (saved_errno == EINVAL) { + v_print(" The device's address type does not match " + "the master's address type.\n"); + } + return res; + } else { + v_print("Slave '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + slave_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_mtu(char *slave_ifname, int mtu) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_mtu = mtu; + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFMTU, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); + } + + return res; +} + +static int set_if_flags(char *ifname, short flags) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_flags = flags; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFFLAGS, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': flags set to %04X.\n", ifname, flags); + } + + return res; +} + +static int set_if_up(char *ifname, short flags) +{ + return set_if_flags(ifname, flags | IFF_UP); +} + +static int set_if_down(char *ifname, short flags) +{ + return set_if_flags(ifname, flags & ~IFF_UP); +} + +static int clear_if_addr(char *ifname) +{ + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); + + res = ioctl(skfd, SIOCSIFADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': address cleared\n", ifname); + } + + return res; +} + +static int set_if_addr(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res; + unsigned char *ipaddr; + int i; + struct { + char *req_name; + char *desc; + int g_ioctl; + int s_ioctl; + } ifra[] = { + {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, + {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, + {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, + {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, + {NULL, NULL, 0, 0}, + }; + + for (i = 0; ifra[i].req_name; i++) { + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].g_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCG%s failed: %s\n", + master_ifname, ifra[i].req_name, + strerror(saved_errno)); + + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, + sizeof(ifr.ifr_addr.sa_data)); + } + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].s_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCS%s failed: %s\n", + slave_ifname, ifra[i].req_name, + strerror(saved_errno)); + + return res; + } + + ipaddr = ifr.ifr_addr.sa_data; + v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", + slave_ifname, ifra[i].desc, + ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + + return 0; +} /* * Local variables: @@ -768,3 +1107,4 @@ static int get_abi_ver(char *master_ifna * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * End: */ + --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/networking/netconsole.txt 2003-12-30 22:49:19.000000000 -0800 @@ -0,0 +1,57 @@ + +started by Ingo Molnar , 2001.09.17 +2.6 port and netpoll api by Matt Mackall , Sep 9 2003 + +Please send bug reports to Matt Mackall + +This module logs kernel printk messages over UDP allowing debugging of +problem where disk logging fails and serial consoles are impractical. + +It can be used either built-in or as a module. As a built-in, +netconsole initializes immediately after NIC cards and will bring up +the specified interface as soon as possible. While this doesn't allow +capture of early kernel panics, it does capture most of the boot +process. + +It takes a string configuration parameter "netconsole" in the +following format: + + netconsole=[src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] + + where + src-port source for UDP packets (defaults to 6665) + src-ip source IP to use (interface address) + dev network interface (eth0) + tgt-port port for logging agent (6666) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) + +Examples: + + linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc + + or + + insmod netconsole netconsole=@/,@10.0.0.2/ + +Built-in netconsole starts immediately after the TCP stack is +initialized and attempts to bring up the supplied dev at the supplied +address. + +The remote host can run either 'netcat -u -l -p ' or syslogd. + +WARNING: the default target ethernet setting uses the broadcast +ethernet address to send packets, which can cause increased load on +other systems on the same ethernet segment. + +NOTE: the network device (eth1 in the above case) can run any kind +of other network traffic, netconsole is not intrusive. Netconsole +might cause slight delays in other traffic if the volume of kernel +messages is high, but should have no other impact. + +Netconsole was designed to be as instantaneous as possible, to +enable the logging of even the most critical kernel bugs. It works +from IRQ contexts as well, and does not enable interrupts while +sending packets. Due to these unique needs, configuration can not +be more automatic, and some fundamental limitations will remain: +only IP networks, UDP packets and ethernet devices are supported. --- linux-2.6.1-rc1/Documentation/networking/sk98lin.txt 2003-09-27 18:57:43.000000000 -0700 +++ 25/Documentation/networking/sk98lin.txt 2003-12-30 22:49:19.000000000 -0800 @@ -2,9 +2,9 @@ All rights reserved =========================================================================== -sk98lin.txt created 23-Sep-2003 +sk98lin.txt created 15-Dec-2003 -Readme File for sk98lin v6.18 +Readme File for sk98lin v6.21 Marvell Yukon/SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX This file contains @@ -466,7 +466,7 @@ The Marvell Yukon/SysKonnect Linux drive Link Aggregation according to IEEE standards 802.1, 802.1q, and 802.3ad. These features are only available after installation of open source modules available on the Internet: -For VLAN go to: http://scry.wanfear.com/~greear/vlan.html +For VLAN go to: http://www.candelatech.com/~greear/vlan.html For Link Aggregation go to: http://www.st.rim.or.jp/~yumo NOTE: SysKonnect GmbH does not offer any support for these open source --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/should-fix.txt 2003-12-30 22:49:28.000000000 -0800 @@ -0,0 +1,545 @@ +Not-ready features and speedups +=============================== + +Legend: + +PRI1: We're totally lame if this doesn't get in +PRI2: Would be nice +PRI3: Not very important + +drivers/block/ +~~~~~~~~~~~~~~ + +o viro: paride drivers need a big cleanup. Partially done, but ATAPI drivers + need serious work and bug fixing. + + PRI2 + +drivers/char/rtc/ +~~~~~~~~~~~~~~~~~ + +o rmk, trini: add support for alarms to the existing generic rtc driver. + + PRI2 + +console drivers +~~~~~~~~~~~~~~~ + (Pavel Machek ) + +o There are few must-fix bugs in cursor handling. + +o Play with gpm selection for a while and your cursor gets corrupted with + random dots. Ouch. + +device mapper +~~~~~~~~~~~~~ + +o ioctl interface cleanup patch is ready (redo the structure layouts) + + PRI1 + +o A port of the 2.4 snapshot and mirror targets is in progress + + PRI1 + +o the fs interface to dm needs to be redone. gregkh was going to work on + this. viro is interested in seeing work thus-far. + + PRI2 + +drivers/net/wireless/ +~~~~~~~~~~~~~~~~~~~~~ + + (Jean Tourrilhes ) + +o get HostAP driver in the kernel. No consolidation of the 802.11 + management across driver can happen until this one is in (which is probably + 2.7.X material). I think Jouni is mostly ready but didn't find time for + it. + + PRI2 + +o get more wireless drivers into the kernel. The most "integrable" drivers + at this point seem the NWN driver, Pavel's Spectrum driver. + + PRI1 + +drivers/usb/gadget/ +~~~~~~~~~~~~~~~~~~~ + +o rmk: SA11xx USB client/gadget code (David B has been doing some work on + this, and keeps trying to prod me, but unfortunately I haven't had the time + to look at his work, sorry David.) + + PRI3 + +fs/ +~~~ + +o ext3 and ext2 block allocators have serious failure modes - interleaved + allocations. + + PRI3 + +o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling + patches. They make reiserfs a lot safer. + + Ordered: PRI2 + data journalled: PRI3 + +o viro: convert more filesystems to use lib/parser.c for options. + + PRI2 + +o aio: fs IO isn't async at present. suparna has restart patches, they're + in -mm. Need to get Ben to review/comment. + + PRI1. + +o drepper: various filesystems use ->pid wrongly + + PRI1 + +o hch: devfs: there's a fundamental lookup vs devfsd race that's only + fixable by introducing a lookup vs devfs deadlock. I can't see how this is + fixable without getting rid of the current devfsd design. Mandrake seems + to have a workaround for this so this is at least not triggered so easily, + but that's not what I'd consider a fix.. + + PRI2 + +kernel/ +~~~~~~~ + +o rusty: Zippel's Reference count simplification. Tricky code, but cuts + about 120 lines from module.c. Patch exists, needs stressing. + + PRI3 + +o rusty: Fix module-failed-init races by starting module "disabled". Patch + exists, requires some subsystems (ie. add_partition) to explicitly say + "make module live now". Without patch we are no worse off than 2.4 etc. + + PRI1 + +o Integrate userspace irq balancing daemon. + + PRI2 + +o kexec. Seems to work, was in -mm. + + PRI3 + +o rmk: lib/inflate.c must not use static variables (causes these to be + referenced via GOTOFF relocations in PIC decompressor. We have a PIC + decompressor to avoid having to hard code a per platform zImage link + address into the makefiles.) + + PRI2 + +o klibc merge? + + PRI2 + +mm/ +~~~ + +o dropbehind for large files + + PRI2 + +net/ +~~~~ + + (davem) + +o Real serious use of IPSEC is hampered by lack of MPLS support. MPLS is a + switching technology that works by switching based upon fixed length labels + prepended to packets. Many people use this and IPSEC to implement VPNs + over public networks, it is also used for things like traffic engineering. + + A good reference site is: + + http://www.mplsrc.com/ + + Anyways, an existing (crappy) implementation exists. I've almost + completed a rewrite, I should have something in the tree next week. + + PRI1 + +o Sometimes we generate IP fragments when it truly isn't necessary. + + The way IP fragmentation is specified, each fragment must be modulo 8 + bytes in length. So suppose the device has an MTU that is not 0 modulo 8, + ethernet even classifies in this way. 1500 == (8 * 187) + 4 + + Our IP fragmenting engine can fragment on packets that are sized within + the last modulo 8 bytes of the MTU. This happens in obscure cases, but it + does happen. + + I've proposed a fix to Alexey, whereby very late in the output path we + check the packet, if we fragmented but the data length would fit into the + MTU we unfragment the packet. + + This is low priority, because technically it creates suboptimal behavior + rather than mis-operation. + + PRI1 + +net/*/netfilter/ +~~~~~~~~~~~~~~~~ + +o Lots of misc. cleanups, which are happening slowly. + + PRI2 + +power management +~~~~~~~~~~~~~~~~ + +o Pat and Pavel disagree over swsusp. Need to sort that out. + + PRI2 + +o Frame buffer restore codepaths (that requires some deep PCI magic) + + PRI2 + +o XFree86 hooks + + PRI2 + +o AGP restoration + + PRI2 + +o DRI restoration + + (davej/Alan: not super-critical, can crash laptop on restore. davej + looking into it.) + + PRI2 + +o IDE suspend/resume without races (Ben is looking at this a little) + + PRI2 + +o Pat: There are already CPU device structures; MTRRs should be a + dynamically registered interface of CPUs, which implies there needs + to be some other glue to know that there are MTRRs that need to be + saved/restored. + + PRI1 + +global +~~~~~~ + +o We need a kernel side API for reporting error events to userspace (could + be async to 2.6 itself) + + (Prototype core based on netlink exists) + + PRI2 + +o Kai: Introduce a sane, easy and standard way to build external modules + - make clean and make modules_install are both broken + + PRI2 + +drivers +~~~~~~~ + +o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do + multiheader right and so on + + PRI1 + +drivers/acpi/ +~~~~~~~~~~~~~ + +o Fix acpi for all newer IBM Thinkpads see + http://bugme.osdl.org/show_bug.cgi?id=1038 for more information + +o alan: VIA APIC stuff is one bit of this, there are also some other + reports that were caused by ACPI not setting level v edge trigger some + times + + PRI1 + +o mochel: it seems the acpi irq routing code could use a serious rewrite. + + grover: The problem is the ACPI irq routing code is trying to piggyback + on the existing MPS-specific data structures, and it's generally a hack. + So yes mochel is right, but it is also purging MPS-ities from common code + as well. I've done some preliminary work in this area and it doesn't seem + to break anything (yet) but a rewrite in this area imho should not be + rushed out the door. And, I think the above bugs can be fixed w/o the + rewrite. + + PRI2 + +o mochel: ACPI suspend doesn't work. Important, not cricital. Pat is + working it. + + PRI2 + +drivers/block/ +~~~~~~~~~~~~~~ + +o More testing of floppy + + PRI3 + +drivers/char/ +~~~~~~~~~~~~~ + + +drivers/ide/ +~~~~~~~~~~~~ + + (Alan) + +o IDE PIO has occasional unexplained PIO disk eating reports + + PRI1 + +o IDE has multiple zillions of races/hangs in 2.5 still + + PRI1 + +o IDE scsi needs rewriting + + PRI2 + +o IDE needs significant reworking to handle Simplex right + + PRI2 + +o IDE hotplug handling for 2.5 is completely broken still + + PRI2 + +o There are lots of other IDE bugs that wont go away until the taskfile + stuff is included, the locking bugs that allow any user to hang the IDE + layer in 2.5, and some other updates are forward ported. (esp. HPT372N). + + PRI1 + +drivers/isdn/ +~~~~~~~~~~~~~ + + (Kai, rmk) + +o isdn_tty locking is completely broken (cli() and friends) + + PRI2 + +o fix other drivers + + PRI2 + +o lots more cleanups, adaption to recent APIs etc + + PRI3 + +o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent + 3-set patch for serial stuff) + + Alternatively, we could re-introduce the fallback to driver ioctl parsing + for these if not enough drivers get updated. + + PRI3 + +drivers/net/ +~~~~~~~~~~~~ + +o davej: Either Wireless network drivers or PCMCIA broke somewhen. A + configuration that worked fine under 2.4 doesn't receive any packets. Need + to look into this more to make sure I don't have any misconfiguration that + just 'happened to work' under 2.4 + + PRI1 + +drivers/scsi/ +~~~~~~~~~~~~~ + +o jejb: qlogic - + + o Merge the feral driver. It covers all qlogic chips: 1020 all the way + up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5 + + o qla2xxx: only for FC chips. Has significant build issues. hch + promises to send me a "must fix" list for this. + http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5 + + PRI2 + +o hch, Mike Anderson, Badari Pulavarty: scsi locking issues + + o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd + with very unclear locking, many of them probably want to become + atomic_t's or bitmaps (for the 1bit bitfields). + + o there's lots of volatile abuse in the scsi code that needs to be + thought about. + + o there's some global variables incremented without any locks + + PRI2 + +sound/ +~~~~~~ + +o rmk: several OSS drivers for SA11xx-based hardware in need of + ALSA-ification and L3 bus support code for these. + +o rmk: need to complete ALSA-ification of the WaveArtist driver for both + NetWinder and other stuff (there's some fairly fundamental differences in + the way the mixer needs to be handled for the NetWinder.) + + (Issues with forward-porting 2.4 bugfixes.) + (Killing off OSS is 2.7 material) + +PRI2 + +arch/i386/ +~~~~~~~~~~ + +o Also PC9800 merge needs finishing to the point we want for 2.6 (not all). + + PRI3 + +o davej: PAT support (for mtrr exhaustion w/ AGP) + + PRI2 + +o 2.5.x won't boot on some 440GX + + alan: Problem understood now, feasible fix in 2.4/2.4-ac. (440GX has two + IRQ routers, we use the $PIR table with the PIIX, but the 440GX doesnt use + the PIIX for its IRQ routing). Fall back to BIOS for 440GX works and Intel + concurs. + + PRI1 + +o 2.5.x doesn't handle VIA APIC right yet. + + 1. We must write the PCI_INTERRUPT_LINE + + 2. We have quirk handlers that seem to trash it. + + PRI1 + +o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan + Hollis) + + alan: ECC - I have some test bits from Dan's stuff - they need no kernel + core changes for most platforms. That means we can treat it as a random + driver merge. + + PRI3 + +o alan: 2.4 has some fixes for tsc handling bugs. One where some bioses in + SMM mode mess up our toggle on the time high/low or mangle the counter and + one where a few chips need religious use of _p for timer access and we + don't do that. This is forward porting little bits of fixup. + + ACPI HZ stuff we can't trap - a lot of ACPI is implemented as outb's + triggering SMM traps + + PRI1 + +arch/x86_64/ +~~~~~~~~~~~~ + + (Andi) + +o time handling is broken. Need to move up 2.4 time.c code. + + PRI1 + +o NMI watchdog seems to tick too fast + + PRI2 + +o need to coredump 64bit vsyscall code with dwarf2 + + PRI2 + +o move 64bit signal trampolines into vsyscall code and add dwarf2 for it. + (in progress) + + PRI1 + +o describe kernel assembly with dwarf2 annotations for kgdb + + PRI3 + +arch/alpha/ +~~~~~~~~~~~ + +o rth: Ptrace writes are broken. This means we can't (reliably) set + breakpoints or modify variables from gdb. + + PRI1 + +arch/arm/ +~~~~~~~~~ + +o rmk: missing raw keyboard translation tables for all ARM machines. + Haven't even looked into this at all. This could be messy since there + isn't an ARM architecture standard. I'm presently hoping that it won't be + an issue. If it does, I guess we'll see drivers/char/keyboard.c explode. + + PRI2 + +arch/others/ +~~~~~~~~~~~~ + +o SH needs resyncing, as do some other ports. SH64 needs merging. + No impact on mainstream platforms hopefully. + + PRI2 + +arch/s390/ +~~~~~~~~~ + +o A nastly memory management problem causes random crashes. These appear + to be fixed/hidden by the objrmap patch, more investigation is needed. + + PRI1 + +drivers/s390/ +~~~~~~~~~~~~~ + +o Early userspace and 64 bit dev_t will allow the removal of most of + dasd_devmap.c and dasd_genhd.c. + + PRI2 + +o The 3270 console driver needs to be replaced with a working one + (prototype is there, needs to be finished). + + PRI2 + +o Minor interface changes are pending in cio/ when the z990 machines are + out. + + PRI2 + +o Jan Glauber is working on a fix for the timer issues related to running + on virtualized CPUs (wall-clock vs. cpu time). + + PRI1 + +o a block device driver for ramdisks shared among virtual machines + + PRI3 + +o driver for crypto hardware + + PRI3 + +o 'claw' network device driver + + PRI3 + --- linux-2.6.1-rc1/Documentation/SubmittingPatches 2003-07-10 18:50:30.000000000 -0700 +++ 25/Documentation/SubmittingPatches 2003-12-30 22:49:19.000000000 -0800 @@ -239,7 +239,7 @@ Let the compiler optimize away the "no-o Simple example, of poor code: - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; #ifdef CONFIG_NET_FUNKINESS @@ -254,7 +254,7 @@ Cleaned-up example: #endif (in the code itself) - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; init_funky_net(dev); --- linux-2.6.1-rc1/Documentation/sysctl/fs.txt 2003-11-09 16:45:05.000000000 -0800 +++ 25/Documentation/sysctl/fs.txt 2003-12-30 22:50:20.000000000 -0800 @@ -138,3 +138,13 @@ thus the maximum number of mounted files can have. You only need to increase super-max if you need to mount more filesystems than the current value in super-max allows you to. + +============================================================== + +aio-nr & aio-max-nr: + +aio-nr shows the current system-wide number of asynchronous io +requests. aio-max-nr allows you to change the maximum value +aio-nr can grow to. + +============================================================== --- linux-2.6.1-rc1/drivers/acorn/block/fd1772.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/acorn/block/fd1772.c 2003-12-30 22:49:33.000000000 -0800 @@ -365,13 +365,12 @@ static void finish_fdc_done(int dummy); static void floppy_off(unsigned int nr); static void setup_req_params(int drive); static void redo_fd_request(void); -static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param); static void fd_probe(int drive); static int fd_test_drive_present(int drive); static void config_types(void); -static int floppy_open(struct inode *inode, struct file *filp); -static int floppy_release(struct inode *inode, struct file *filp); +static int floppy_open(struct block_device *bdev, struct file *filp); static void do_fd_request(request_queue_t *); /************************* End of Prototypes **************************/ @@ -1309,11 +1308,9 @@ static int invalidate_drive(struct block return 0; } -static int fd_ioctl(struct inode *inode, struct file *filp, +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { - struct block_device *bdev = inode->i_bdev; - switch (cmd) { case FDFMTEND: case FDFLUSH: @@ -1453,10 +1450,11 @@ static void config_types(void) * drive with different device numbers. */ -static int floppy_open(struct inode *inode, struct file *filp) +static int floppy_open(struct block_device *bdev, struct file *filp) { - int drive = iminor(inode) & 3; - int type = iminor(inode) >> 2; + struct archy_floppy_struct *p = bdev->bd_disk->private_data; + int drive = p - unit; + int type = MINOR(bdev->bd_dev) >> 2; int old_dev = fd_device[drive]; if (fd_ref[drive] && old_dev != type) @@ -1476,10 +1474,13 @@ static int floppy_open(struct inode *ino return 0; if (filp->f_mode & 3) { - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (filp->f_mode & 2) { - if (unit[drive].wpstat) { - floppy_release(inode, filp); + if (p->wpstat) { + if (fd_ref[drive] < 0) + fd_ref[drive] = 0; + else + fd_ref[drive]--; return -EROFS; } } @@ -1487,10 +1488,10 @@ static int floppy_open(struct inode *ino return 0; } - -static int floppy_release(struct inode *inode, struct file *filp) +static int floppy_release(struct gendisk *disk) { - int drive = iminor(inode) & 3; + struct archy_floppy_struct *p = disk->private_data; + int drive = p - unit; if (fd_ref[drive] < 0) fd_ref[drive] = 0; --- linux-2.6.1-rc1/drivers/acorn/block/mfmhd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/acorn/block/mfmhd.c 2003-12-30 22:49:29.000000000 -0800 @@ -1153,9 +1153,9 @@ static int mfm_initdrives(void) * The 'front' end of the mfm driver follows... */ -static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +static int mfm_ioctl(struct block_device *bdev, struct file *file, u_int cmd, u_long arg) { - struct mfm_info *p = inode->i_bdev->bd_disk->private_data; + struct mfm_info *p = bdev->bd_disk->private_data; struct hd_geometry *geo = (struct hd_geometry *) arg; if (cmd != HDIO_GETGEO) return -EINVAL; @@ -1167,7 +1167,7 @@ static int mfm_ioctl(struct inode *inode return -EFAULT; if (put_user (p->cylinders, &geo->cylinders)) return -EFAULT; - if (put_user (get_start_sect(inode->i_bdev), &geo->start)) + if (put_user (get_start_sect(bdev), &geo->start)) return -EFAULT; return 0; } --- linux-2.6.1-rc1/drivers/acpi/bus.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/drivers/acpi/bus.c 2003-12-30 22:49:41.000000000 -0800 @@ -39,7 +39,7 @@ #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME ("acpi_bus") -extern void acpi_pic_set_level_irq(unsigned int irq); +extern void __init acpi_pic_sci_set_trigger(unsigned int irq); FADT_DESCRIPTOR acpi_fadt; struct acpi_device *acpi_root; @@ -615,7 +615,7 @@ acpi_bus_init (void) if (acpi_ioapic) mp_config_ioapic_for_sci(acpi_fadt.sci_int); else - acpi_pic_set_level_irq(acpi_fadt.sci_int); + acpi_pic_sci_set_trigger(acpi_fadt.sci_int); #endif status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dsinit.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/dispatcher/dsinit.c 2003-12-30 22:49:41.000000000 -0800 @@ -106,7 +106,7 @@ acpi_ds_init_one_object ( status = acpi_ds_initialize_region (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", - obj_handle, ((struct acpi_namespace_node *) obj_handle)->name.ascii, + obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); } @@ -141,7 +141,7 @@ acpi_ds_init_one_object ( status = acpi_ds_parse_method (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", - obj_handle, ((struct acpi_namespace_node *) obj_handle)->name.ascii, + obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); /* This parse failed, but we will continue parsing more methods */ --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dsmethod.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/drivers/acpi/dispatcher/dsmethod.c 2003-12-30 22:49:41.000000000 -0800 @@ -94,7 +94,7 @@ acpi_ds_parse_method ( } ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n", - ((struct acpi_namespace_node *) obj_handle)->name.ascii, obj_handle)); + acpi_ut_get_node_name (obj_handle), obj_handle)); /* Extract the method object from the method Node */ @@ -169,7 +169,7 @@ acpi_ds_parse_method ( ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", - ((struct acpi_namespace_node *) obj_handle)->name.ascii, obj_handle, op)); + acpi_ut_get_node_name (obj_handle), obj_handle, op)); acpi_ps_delete_parse_tree (op); return_ACPI_STATUS (status); --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dsmthdat.c 2003-06-22 12:04:44.000000000 -0700 +++ 25/drivers/acpi/dispatcher/dsmthdat.c 2003-12-30 22:49:42.000000000 -0800 @@ -567,13 +567,13 @@ acpi_ds_store_object_to_local ( acpi_status status; struct acpi_namespace_node *node; union acpi_operand_object *current_obj_desc; + union acpi_operand_object *new_obj_desc; ACPI_FUNCTION_TRACE ("ds_store_object_to_local"); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n", opcode, index, obj_desc)); - /* Parameter validation */ if (!obj_desc) { @@ -595,6 +595,18 @@ acpi_ds_store_object_to_local ( } /* + * If the reference count on the object is more than one, we must + * take a copy of the object before we store. + */ + new_obj_desc = obj_desc; + if (obj_desc->common.reference_count > 1) { + status = acpi_ut_copy_iobject_to_iobject (obj_desc, &new_obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* * If there is an object already in this slot, we either * have to delete it, or if this is an argument and there * is an object reference stored there, we have to do @@ -624,8 +636,8 @@ acpi_ds_store_object_to_local ( * operand objects of type Reference. */ if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) { - ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: %X\n", - current_obj_desc->common.type)); + ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n", + acpi_ut_get_descriptor_name (current_obj_desc))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -636,15 +648,21 @@ acpi_ds_store_object_to_local ( if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Arg (%p) is an obj_ref(Node), storing in node %p\n", - obj_desc, current_obj_desc)); + "Arg (%p) is an obj_ref(Node), storing in node %p\n", + new_obj_desc, current_obj_desc)); /* * Store this object to the Node * (perform the indirect store) */ - status = acpi_ex_store_object_to_node (obj_desc, + status = acpi_ex_store_object_to_node (new_obj_desc, current_obj_desc->reference.object, walk_state); + + /* Remove local reference if we copied the object above */ + + if (new_obj_desc != obj_desc) { + acpi_ut_remove_reference (new_obj_desc); + } return_ACPI_STATUS (status); } } @@ -657,12 +675,18 @@ acpi_ds_store_object_to_local ( } /* - * Install the obj_stack descriptor (*obj_desc) into + * Install the Obj descriptor (*new_obj_desc) into * the descriptor for the Arg or Local. - * Install the new object in the stack entry * (increments the object reference count by one) */ - status = acpi_ds_method_data_set_value (opcode, index, obj_desc, walk_state); + status = acpi_ds_method_data_set_value (opcode, index, new_obj_desc, walk_state); + + /* Remove local reference if we copied the object above */ + + if (new_obj_desc != obj_desc) { + acpi_ut_remove_reference (new_obj_desc); + } + return_ACPI_STATUS (status); } --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dsopcode.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/acpi/dispatcher/dsopcode.c 2003-12-30 22:49:41.000000000 -0800 @@ -201,7 +201,7 @@ acpi_ds_get_buffer_field_arguments ( ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL)); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n", - node->name.ascii)); + acpi_ut_get_node_name (node))); /* Execute the AML code for the term_arg arguments */ @@ -346,7 +346,7 @@ acpi_ds_get_region_arguments ( ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL)); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] op_region Arg Init at AML %p\n", - node->name.ascii, extra_desc->extra.aml_start)); + acpi_ut_get_node_name (node), extra_desc->extra.aml_start)); /* Execute the argument AML */ @@ -438,8 +438,8 @@ acpi_ds_init_buffer_field ( * after resolution in acpi_ex_resolve_operands(). */ if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination must be a NS Node\n", - acpi_ps_get_opcode_name (aml_opcode))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n", + acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc))); status = AE_AML_OPERAND_TYPE; goto cleanup; @@ -514,14 +514,16 @@ acpi_ds_init_buffer_field ( goto cleanup; } - /* Entire field must fit within the current length of the buffer */ if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Field size %d exceeds Buffer size %d (bits)\n", - bit_offset + bit_count, 8 * (u32) buffer_desc->buffer.length)); + "Field [%4.4s] size %d exceeds Buffer [%4.4s] size %d (bits)\n", + acpi_ut_get_node_name (result_desc), + bit_offset + bit_count, + acpi_ut_get_node_name (buffer_desc->buffer.node), + 8 * (u32) buffer_desc->buffer.length)); status = AE_AML_BUFFER_LIMIT; goto cleanup; } @@ -742,7 +744,7 @@ acpi_ds_eval_region_operands ( ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n", obj_desc, - ACPI_HIDWORD (obj_desc->region.address), ACPI_LODWORD (obj_desc->region.address), + ACPI_FORMAT_UINT64 (obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dswexec.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/drivers/acpi/dispatcher/dswexec.c 2003-12-30 22:49:41.000000000 -0800 @@ -416,10 +416,24 @@ acpi_ds_exec_end_op ( status = acpi_gbl_op_type_dispatch [op_type] (walk_state); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "[%s]: Could not resolve operands, %s\n", - acpi_ps_get_opcode_name (walk_state->opcode), - acpi_format_exception (status))); + /* + * Treat constructs of the form "Store(local_x,local_x)" as noops when the + * Local is uninitialized. + */ + if ((status == AE_AML_UNINITIALIZED_LOCAL) && + (walk_state->opcode == AML_STORE_OP) && + (walk_state->operands[0]->common.type == ACPI_TYPE_LOCAL_REFERENCE) && + (walk_state->operands[1]->common.type == ACPI_TYPE_LOCAL_REFERENCE) && + (walk_state->operands[0]->reference.opcode == + walk_state->operands[1]->reference.opcode)) { + status = AE_OK; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "[%s]: Could not resolve operands, %s\n", + acpi_ps_get_opcode_name (walk_state->opcode), + acpi_format_exception (status))); + } } /* Always delete the argument objects and clear the operand stack */ --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dswload.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/dispatcher/dswload.c 2003-12-30 22:49:41.000000000 -0800 @@ -167,7 +167,7 @@ acpi_ds_load1_begin_op ( object_type = walk_state->op_info->object_type; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "State=%p Op=%p [%s] ", walk_state, op, acpi_ut_get_type_name (object_type))); + "State=%p Op=%p [%s]\n", walk_state, op, acpi_ut_get_type_name (object_type))); switch (walk_state->opcode) { case AML_SCOPE_OP: @@ -260,10 +260,12 @@ acpi_ds_load1_begin_op ( if ((walk_state->opcode != AML_SCOPE_OP) && (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { flags |= ACPI_NS_ERROR_IF_FOUND; - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Cannot already exist\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n", + acpi_ut_get_type_name (object_type))); } else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Both Find or Create allowed\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", + acpi_ut_get_type_name (object_type))); } /* --- linux-2.6.1-rc1/drivers/acpi/dispatcher/dswscope.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/dispatcher/dswscope.c 2003-12-30 22:49:41.000000000 -0800 @@ -146,7 +146,7 @@ acpi_ds_scope_stack_push ( if (old_scope_info) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "[%4.4s] (%s)", - old_scope_info->scope.node->name.ascii, + acpi_ut_get_node_name (old_scope_info->scope.node), acpi_ut_get_type_name (old_scope_info->common.value))); } else { @@ -156,7 +156,7 @@ acpi_ds_scope_stack_push ( ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, ", New scope -> [%4.4s] (%s)\n", - scope_info->scope.node->name.ascii, + acpi_ut_get_node_name (scope_info->scope.node), acpi_ut_get_type_name (scope_info->common.value))); /* Push new scope object onto stack */ @@ -207,14 +207,14 @@ acpi_ds_scope_stack_pop ( ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%.2d] Popped scope [%4.4s] (%s), New scope -> ", (u32) walk_state->scope_depth, - scope_info->scope.node->name.ascii, + acpi_ut_get_node_name (scope_info->scope.node), acpi_ut_get_type_name (scope_info->common.value))); new_scope_info = walk_state->scope_info; if (new_scope_info) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "[%4.4s] (%s)\n", - new_scope_info->scope.node->name.ascii, + acpi_ut_get_node_name (new_scope_info->scope.node), acpi_ut_get_type_name (new_scope_info->common.value))); } else { --- linux-2.6.1-rc1/drivers/acpi/events/evgpeblk.c 2003-06-22 12:04:44.000000000 -0700 +++ 25/drivers/acpi/events/evgpeblk.c 2003-12-30 22:49:41.000000000 -0800 @@ -477,7 +477,7 @@ unlock_and_exit: * * RETURN: Status * - * DESCRIPTION: Install new GPE block with mutex support + * DESCRIPTION: Remove a GPE block * ******************************************************************************/ @@ -743,8 +743,7 @@ acpi_ev_create_gpe_block ( ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), gpe_device->name.ascii, gpe_block->register_count, - ACPI_HIDWORD (gpe_block->block_address.address), - ACPI_LODWORD (gpe_block->block_address.address), + ACPI_FORMAT_UINT64 (gpe_block->block_address.address), interrupt_level)); /* Find all GPE methods (_Lxx, _Exx) for this block */ --- linux-2.6.1-rc1/drivers/acpi/events/evgpe.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/drivers/acpi/events/evgpe.c 2003-12-30 22:49:41.000000000 -0800 @@ -139,12 +139,10 @@ acpi_ev_gpe_detect ( { u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; - u8 bit_mask; struct acpi_gpe_register_info *gpe_register_info; u32 in_value; acpi_status status; struct acpi_gpe_block_info *gpe_block; - u32 gpe_number; u32 i; u32 j; @@ -187,11 +185,9 @@ acpi_ev_gpe_detect ( ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", - ACPI_HIDWORD (gpe_register_info->status_address.address), - ACPI_LODWORD (gpe_register_info->status_address.address), + ACPI_FORMAT_UINT64 (gpe_register_info->status_address.address), gpe_register_info->status, - ACPI_HIDWORD (gpe_register_info->enable_address.address), - ACPI_LODWORD (gpe_register_info->enable_address.address), + ACPI_FORMAT_UINT64 (gpe_register_info->enable_address.address), gpe_register_info->enable)); /* First check if there is anything active at all in this register */ @@ -206,19 +202,17 @@ acpi_ev_gpe_detect ( /* Now look at the individual GPEs in this byte register */ - for (j = 0, bit_mask = 1; j < ACPI_GPE_REGISTER_WIDTH; j++, bit_mask <<= 1) { + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { /* Examine one GPE bit */ - if (enabled_status_byte & bit_mask) { + if (enabled_status_byte & acpi_gbl_decode_to8bit[j]) { /* * Found an active GPE. Dispatch the event to a handler * or method. */ - gpe_number = (i * ACPI_GPE_REGISTER_WIDTH) + j; - int_status |= acpi_ev_gpe_dispatch ( - &gpe_block->event_info[gpe_number], - j + gpe_register_info->base_gpe_number); + &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], + j + gpe_register_info->base_gpe_number); } } } @@ -294,7 +288,7 @@ acpi_ev_asynch_execute_gpe_method ( if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), - local_gpe_event_info.method_node->name.ascii, gpe_number)); + acpi_ut_get_node_name (local_gpe_event_info.method_node), gpe_number)); } } @@ -367,6 +361,18 @@ acpi_ev_gpe_dispatch ( /* Invoke the installed handler (at interrupt level) */ gpe_event_info->handler (gpe_event_info->context); + + /* It is now safe to clear level-triggered events. */ + + if (gpe_event_info->flags & ACPI_EVENT_LEVEL_TRIGGERED) { + status = acpi_hw_clear_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (( + "acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n", + gpe_number)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); + } + } } else if (gpe_event_info->method_node) { /* @@ -375,13 +381,16 @@ acpi_ev_gpe_dispatch ( */ status = acpi_hw_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } - /* Execute the method associated with the GPE. */ - + /* + * Execute the method associated with the GPE + * NOTE: Level-triggered GPEs are cleared after the method completes. + */ if (ACPI_FAILURE (acpi_os_queue_for_execution (OSD_PRIORITY_GPE, acpi_ev_asynch_execute_gpe_method, gpe_event_info))) { @@ -399,22 +408,12 @@ acpi_ev_gpe_dispatch ( /* * Disable the GPE. The GPE will remain disabled until the ACPI - * Core Subsystem is restarted, or the handler is reinstalled. + * Core Subsystem is restarted, or a handler is installed. */ status = acpi_hw_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", - gpe_number)); - return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); - } - } - - /* It is now safe to clear level-triggered events. */ - - if (gpe_event_info->flags & ACPI_EVENT_LEVEL_TRIGGERED) { - status = acpi_hw_clear_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } --- linux-2.6.1-rc1/drivers/acpi/events/evmisc.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/drivers/acpi/events/evmisc.c 2003-12-30 22:49:41.000000000 -0800 @@ -195,7 +195,8 @@ acpi_ev_queue_notify_request ( /* There is no per-device notify handler for this device */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "No notify handler for [%4.4s] node %p\n", node->name.ascii, node)); + "No notify handler for [%4.4s] node %p\n", + acpi_ut_get_node_name (node), node)); } return (status); --- linux-2.6.1-rc1/drivers/acpi/events/evregion.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/events/evregion.c 2003-12-30 22:49:41.000000000 -0800 @@ -136,7 +136,7 @@ acpi_ev_init_address_spaces ( * ******************************************************************************/ -static acpi_status +acpi_status acpi_ev_execute_reg_method ( union acpi_operand_object *region_obj, u32 function) @@ -202,7 +202,7 @@ cleanup: * * FUNCTION: acpi_ev_address_space_dispatch * - * PARAMETERS: region_obj - internal region object + * PARAMETERS: region_obj - Internal region object * space_id - ID of the address space (0-255) * Function - Read or Write operation * Address - Where in the space to read or write @@ -243,9 +243,11 @@ acpi_ev_address_space_dispatch ( /* Ensure that there is a handler associated with this region */ - handler_desc = region_obj->region.address_space; + handler_desc = region_obj->region.handler; if (!handler_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "no handler for region(%p) [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No handler for Region [%4.4s] (%p) [%s]\n", + acpi_ut_get_node_name (region_obj->region.node), region_obj, acpi_ut_get_region_name (region_obj->region.space_id))); return_ACPI_STATUS (AE_NOT_EXIST); @@ -320,8 +322,8 @@ acpi_ev_address_space_dispatch ( ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", - ®ion_obj->region.address_space->address_space, handler, - ACPI_HIDWORD (address), ACPI_LODWORD (address), + ®ion_obj->region.handler->address_space, handler, + ACPI_FORMAT_UINT64 (address), acpi_ut_get_region_name (region_obj->region.space_id))); if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { @@ -359,6 +361,7 @@ acpi_ev_address_space_dispatch ( return_ACPI_STATUS (status); } + /******************************************************************************* * * FUNCTION: acpi_ev_detach_region @@ -398,7 +401,7 @@ acpi_ev_detach_region( /* Get the address handler from the region object */ - handler_obj = region_obj->region.address_space; + handler_obj = region_obj->region.handler; if (!handler_obj) { /* This region has no handler, all done */ @@ -472,7 +475,7 @@ acpi_ev_detach_region( * If the region is on the handler's list * this better be the region's handler */ - region_obj->region.address_space = NULL; + region_obj->region.handler = NULL; acpi_ut_remove_reference (handler_obj); return_VOID; @@ -515,17 +518,15 @@ acpi_ev_attach_region ( union acpi_operand_object *region_obj, u8 acpi_ns_is_locked) { - acpi_status status; - acpi_status status2; - ACPI_FUNCTION_TRACE ("ev_attach_region"); ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Adding Region %p to address handler %p [%s]\n", - region_obj, handler_obj, acpi_ut_get_region_name (region_obj->region.space_id))); - + "Adding Region [%4.4s] %p to address handler %p [%s]\n", + acpi_ut_get_node_name (region_obj->region.node), + region_obj, handler_obj, + acpi_ut_get_region_name (region_obj->region.space_id))); /* Link this region to the front of the handler's list */ @@ -534,34 +535,14 @@ acpi_ev_attach_region ( /* Install the region's handler */ - if (region_obj->region.address_space) { + if (region_obj->region.handler) { return_ACPI_STATUS (AE_ALREADY_EXISTS); } - region_obj->region.address_space = handler_obj; + region_obj->region.handler = handler_obj; acpi_ut_add_reference (handler_obj); - /* - * Tell all users that this region is usable by running the _REG - * method - */ - if (acpi_ns_is_locked) { - status2 = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status2)) { - return_ACPI_STATUS (status2); - } - } - - status = acpi_ev_execute_reg_method (region_obj, 1); - - if (acpi_ns_is_locked) { - status2 = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status2)) { - return_ACPI_STATUS (status2); - } - } - - return_ACPI_STATUS (status); + return_ACPI_STATUS (AE_OK); } @@ -569,9 +550,7 @@ acpi_ev_attach_region ( * * FUNCTION: acpi_ev_install_handler * - * PARAMETERS: Handle - Node to be dumped - * Level - Nesting level of the handle - * Context - Passed into acpi_ns_walk_namespace + * PARAMETERS: walk_namespace callback * * DESCRIPTION: This routine installs an address handler into objects that are * of type Region or Device. @@ -640,7 +619,7 @@ acpi_ev_install_handler ( if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_DEVICE) { /* Check if this Device already has a handler for this address space */ - next_handler_obj = obj_desc->device.address_space; + next_handler_obj = obj_desc->device.handler; while (next_handler_obj) { /* Found a handler, is it for the same address space? */ @@ -697,4 +676,77 @@ acpi_ev_install_handler ( return (status); } +/******************************************************************************* + * + * FUNCTION: acpi_ev_reg_run + * + * PARAMETERS: walk_namespace callback + * + * DESCRIPTION: Run _REg method for region objects of the requested space_iD + * + ******************************************************************************/ + +acpi_status +acpi_ev_reg_run ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value) +{ + union acpi_operand_object *handler_obj; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node; + acpi_status status; + + + ACPI_FUNCTION_NAME ("ev_reg_run"); + + + handler_obj = (union acpi_operand_object *) context; + + /* Parameter validation */ + + if (!handler_obj) { + return (AE_OK); + } + + /* Convert and validate the device handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + return (AE_BAD_PARAMETER); + } + + /* + * We only care about regions.and objects + * that are allowed to have address space handlers + */ + if ((node->type != ACPI_TYPE_REGION) && + (node != acpi_gbl_root_node)) { + return (AE_OK); + } + + /* Check for an existing internal object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* No object, just exit */ + + return (AE_OK); + } + + + /* Object is a Region */ + + if (obj_desc->region.space_id != handler_obj->address_space.space_id) { + /* + * This region is for a different address space + * -- just ignore it + */ + return (AE_OK); + } + + status = acpi_ev_execute_reg_method (obj_desc, 1); + return (status); +} --- linux-2.6.1-rc1/drivers/acpi/events/evrgnini.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/drivers/acpi/events/evrgnini.c 2003-12-30 22:49:41.000000000 -0800 @@ -177,7 +177,7 @@ acpi_ev_pci_config_region_setup ( ACPI_FUNCTION_TRACE ("ev_pci_config_region_setup"); - handler_obj = region_obj->region.address_space; + handler_obj = region_obj->region.handler; if (!handler_obj) { /* * No installed handler. This shouldn't happen because the dispatch @@ -239,7 +239,7 @@ acpi_ev_pci_config_region_setup ( else { ACPI_REPORT_ERROR (( "Could not install pci_config handler for Root Bridge %4.4s, %s\n", - pci_root_node->name.ascii, acpi_format_exception (status))); + acpi_ut_get_node_name (pci_root_node), acpi_format_exception (status))); } } break; @@ -469,7 +469,7 @@ acpi_ev_initialize_region ( /* Setup defaults */ - region_obj->region.address_space = NULL; + region_obj->region.handler = NULL; region_obj2->extra.method_REG = NULL; region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; @@ -502,17 +502,17 @@ acpi_ev_initialize_region ( switch (node->type) { case ACPI_TYPE_DEVICE: - handler_obj = obj_desc->device.address_space; + handler_obj = obj_desc->device.handler; break; case ACPI_TYPE_PROCESSOR: - handler_obj = obj_desc->processor.address_space; + handler_obj = obj_desc->processor.handler; break; case ACPI_TYPE_THERMAL: - handler_obj = obj_desc->thermal_zone.address_space; + handler_obj = obj_desc->thermal_zone.handler; break; default: @@ -533,6 +533,26 @@ acpi_ev_initialize_region ( status = acpi_ev_attach_region (handler_obj, region_obj, acpi_ns_locked); + /* + * Tell all users that this region is usable by running the _REG + * method + */ + if (acpi_ns_locked) { + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + status = acpi_ev_execute_reg_method (region_obj, 1); + + if (acpi_ns_locked) { + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + return_ACPI_STATUS (AE_OK); } --- linux-2.6.1-rc1/drivers/acpi/events/evxfregn.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/drivers/acpi/events/evxfregn.c 2003-12-30 22:49:41.000000000 -0800 @@ -173,7 +173,7 @@ acpi_install_address_space_handler ( * The attached device object already exists. * Make sure the handler is not already installed. */ - handler_obj = obj_desc->device.address_space; + handler_obj = obj_desc->device.handler; /* Walk the handler list for this device */ @@ -240,7 +240,8 @@ acpi_install_address_space_handler ( ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", - acpi_ut_get_region_name (space_id), space_id, node->name.ascii, node, obj_desc)); + acpi_ut_get_region_name (space_id), space_id, + acpi_ut_get_node_name (node), node, obj_desc)); /* * Install the handler @@ -267,13 +268,13 @@ acpi_install_address_space_handler ( /* Install at head of Device.address_space list */ - handler_obj->address_space.next = obj_desc->device.address_space; + handler_obj->address_space.next = obj_desc->device.handler; /* * The Device object is the first reference on the handler_obj. * Each region that uses the handler adds a reference. */ - obj_desc->device.address_space = handler_obj; + obj_desc->device.handler = handler_obj; /* * Walk the namespace finding all of the regions this @@ -291,6 +292,17 @@ acpi_install_address_space_handler ( ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, handler_obj, NULL); + /* + * Now we can run the _REG methods for all Regions for this + * space ID. This is a separate walk in order to handle any + * interdependencies between regions and _REG methods. (i.e. handlers + * must be installed for all regions of this Space ID before we + * can run any _REG methods. + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, + handler_obj, NULL); + unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); @@ -357,8 +369,8 @@ acpi_remove_address_space_handler ( /* Find the address handler the user requested */ - handler_obj = obj_desc->device.address_space; - last_obj_ptr = &obj_desc->device.address_space; + handler_obj = obj_desc->device.handler; + last_obj_ptr = &obj_desc->device.handler; while (handler_obj) { /* We have a handler, see if user requested this one */ --- linux-2.6.1-rc1/drivers/acpi/executer/exdump.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/drivers/acpi/executer/exdump.c 2003-12-30 22:49:41.000000000 -0800 @@ -89,27 +89,27 @@ acpi_ex_dump_operand ( if (!obj_desc) { /* - * This usually indicates that something serious is wrong -- - * since most (if not all) - * code that dumps the stack expects something to be there! + * This usually indicates that something serious is wrong */ - acpi_os_printf ("Null stack entry ptr\n"); + acpi_os_printf ("Null Object Descriptor\n"); return; } if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p NS Node: ", obj_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is a NS Node: ", obj_desc)); ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_EXEC); return; } if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is not a local object\n", obj_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%p is not a node or operand object: [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc))); ACPI_DUMP_BUFFER (obj_desc, sizeof (union acpi_operand_object)); return; } - /* obj_desc is a valid object */ + /* obj_desc is a valid object */ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc)); @@ -151,11 +151,10 @@ acpi_ex_dump_operand ( obj_desc->reference.offset); if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { - /* Value is a Number */ + /* Value is an Integer */ acpi_os_printf (" value is [%8.8X%8.8x]", - ACPI_HIDWORD(obj_desc->integer.value), - ACPI_LODWORD(obj_desc->integer.value)); + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); } acpi_os_printf ("\n"); @@ -169,11 +168,10 @@ acpi_ex_dump_operand ( if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { - /* Value is a Number */ + /* Value is an Integer */ acpi_os_printf (" value is [%8.8X%8.8x]", - ACPI_HIDWORD(obj_desc->integer.value), - ACPI_LODWORD(obj_desc->integer.value)); + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); } acpi_os_printf ("\n"); @@ -189,7 +187,7 @@ acpi_ex_dump_operand ( default: - /* unknown opcode */ + /* Unknown opcode */ acpi_os_printf ("Unknown Reference opcode=%X\n", obj_desc->reference.opcode); @@ -229,8 +227,7 @@ acpi_ex_dump_operand ( case ACPI_TYPE_INTEGER: acpi_os_printf ("Integer %8.8X%8.8X\n", - ACPI_HIDWORD (obj_desc->integer.value), - ACPI_LODWORD (obj_desc->integer.value)); + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); break; @@ -271,8 +268,7 @@ acpi_ex_dump_operand ( } else { acpi_os_printf (" base %8.8X%8.8X Length %X\n", - ACPI_HIDWORD (obj_desc->region.address), - ACPI_LODWORD (obj_desc->region.address), + ACPI_FORMAT_UINT64 (obj_desc->region.address), obj_desc->region.length); } break; @@ -494,7 +490,7 @@ acpi_ex_out_address ( acpi_os_printf ("%20s : %p\n", title, value); #else acpi_os_printf ("%20s : %8.8X%8.8X\n", title, - ACPI_HIDWORD (value), ACPI_LODWORD (value)); + ACPI_FORMAT_UINT64 (value)); #endif } @@ -525,7 +521,7 @@ acpi_ex_dump_node ( } } - acpi_os_printf ("%20s : %4.4s\n", "Name", node->name.ascii); + acpi_os_printf ("%20s : %4.4s\n", "Name", acpi_ut_get_node_name (node)); acpi_ex_out_string ("Type", acpi_ut_get_type_name (node->type)); acpi_ex_out_integer ("Flags", node->flags); acpi_ex_out_integer ("Owner Id", node->owner_id); @@ -573,7 +569,8 @@ acpi_ex_dump_object_descriptor ( } if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { - acpi_os_printf ("ex_dump_object_descriptor: %p is not a valid ACPI object\n", obj_desc); + acpi_os_printf ("ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc)); return_VOID; } @@ -589,8 +586,7 @@ acpi_ex_dump_object_descriptor ( case ACPI_TYPE_INTEGER: acpi_os_printf ("%20s : %8.8X%8.8X\n", "Value", - ACPI_HIDWORD (obj_desc->integer.value), - ACPI_LODWORD (obj_desc->integer.value)); + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); break; @@ -635,7 +631,7 @@ acpi_ex_dump_object_descriptor ( case ACPI_TYPE_DEVICE: - acpi_ex_out_pointer ("address_space", obj_desc->device.address_space); + acpi_ex_out_pointer ("Handler", obj_desc->device.handler); acpi_ex_out_pointer ("system_notify", obj_desc->device.system_notify); acpi_ex_out_pointer ("device_notify", obj_desc->device.device_notify); break; @@ -673,7 +669,7 @@ acpi_ex_dump_object_descriptor ( acpi_ex_out_integer ("Flags", obj_desc->region.flags); acpi_ex_out_address ("Address", obj_desc->region.address); acpi_ex_out_integer ("Length", obj_desc->region.length); - acpi_ex_out_pointer ("address_space", obj_desc->region.address_space); + acpi_ex_out_pointer ("Handler", obj_desc->region.handler); acpi_ex_out_pointer ("Next", obj_desc->region.next); break; @@ -694,7 +690,7 @@ acpi_ex_dump_object_descriptor ( acpi_ex_out_address ("Address", (acpi_physical_address) obj_desc->processor.address); acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify); acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify); - acpi_ex_out_pointer ("address_space", obj_desc->processor.address_space); + acpi_ex_out_pointer ("Handler", obj_desc->processor.handler); break; @@ -702,7 +698,7 @@ acpi_ex_dump_object_descriptor ( acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify); acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify); - acpi_ex_out_pointer ("address_space", obj_desc->thermal_zone.address_space); + acpi_ex_out_pointer ("Handler", obj_desc->thermal_zone.handler); break; --- linux-2.6.1-rc1/drivers/acpi/executer/exfldio.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/executer/exfldio.c 2003-12-30 22:49:41.000000000 -0800 @@ -138,8 +138,9 @@ acpi_ex_setup_region ( */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", - obj_desc->common_field.node->name.ascii, obj_desc->common_field.access_byte_width, - rgn_desc->region.node->name.ascii, rgn_desc->region.length)); + acpi_ut_get_node_name (obj_desc->common_field.node), + obj_desc->common_field.access_byte_width, + acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); } /* @@ -148,9 +149,10 @@ acpi_ex_setup_region ( */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", - obj_desc->common_field.node->name.ascii, obj_desc->common_field.base_byte_offset, + acpi_ut_get_node_name (obj_desc->common_field.node), + obj_desc->common_field.base_byte_offset, field_datum_byte_offset, obj_desc->common_field.access_byte_width, - rgn_desc->region.node->name.ascii, rgn_desc->region.length)); + acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); #ifdef CONFIG_ACPI_RELAXED_AML { @@ -261,7 +263,7 @@ acpi_ex_access_region ( obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, field_datum_byte_offset, - ACPI_HIDWORD (address), ACPI_LODWORD (address))); + ACPI_FORMAT_UINT64 (address))); /* Invoke the appropriate address_space/op_region handler */ @@ -514,12 +516,12 @@ acpi_ex_field_datum_io ( if (ACPI_SUCCESS (status)) { if (read_write == ACPI_READ) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", - ACPI_HIDWORD (*value), ACPI_LODWORD (*value), + ACPI_FORMAT_UINT64 (*value), obj_desc->common_field.access_byte_width)); } else { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", - ACPI_HIDWORD (*value), ACPI_LODWORD (*value), + ACPI_FORMAT_UINT64 (*value), obj_desc->common_field.access_byte_width)); } } @@ -612,11 +614,11 @@ acpi_ex_write_with_update_rule ( ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n", - ACPI_HIDWORD (mask), ACPI_LODWORD (mask), + ACPI_FORMAT_UINT64 (mask), field_datum_byte_offset, obj_desc->common_field.access_byte_width, - ACPI_HIDWORD (field_value), ACPI_LODWORD (field_value), - ACPI_HIDWORD (merged_value),ACPI_LODWORD (merged_value))); + ACPI_FORMAT_UINT64 (field_value), + ACPI_FORMAT_UINT64 (merged_value))); /* Write the merged value */ @@ -784,12 +786,13 @@ acpi_ex_extract_from_field ( { acpi_status status; u32 field_datum_byte_offset; - u32 datum_offset; - acpi_integer previous_raw_datum; + u32 buffer_datum_offset; + acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; u32 byte_field_length; u32 datum_count; + u32 i; ACPI_FUNCTION_TRACE ("ex_extract_from_field"); @@ -812,77 +815,74 @@ acpi_ex_extract_from_field ( datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); + /* + * If the field is not aligned on a datum boundary and does not + * fit within a single datum, we must read an extra datum. + * + * We could just split the aligned and non-aligned cases since the + * aligned case is so very simple, but this would require more code. + */ + if ((obj_desc->common_field.end_field_valid_bits != 0) && + (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { + datum_count++; + } + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "byte_len %X, datum_len %X, byte_gran %X\n", byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); /* * Clear the caller's buffer (the whole buffer length as given) - * This is very important, especially in the cases where a byte is read, - * but the buffer is really a u32 (4 bytes). + * This is very important, especially in the cases where the buffer + * is longer than the size of the field. */ ACPI_MEMSET (buffer, 0, buffer_length); - /* Read the first raw datum to prime the loop */ - field_datum_byte_offset = 0; - datum_offset= 0; - - status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, - &previous_raw_datum, ACPI_READ); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - + buffer_datum_offset= 0; - /* We might actually be done if the request fits in one datum */ + /* Read the entire field */ - if ((datum_count == 1) && - (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { - /* 1) Shift the valid data bits down to start at bit 0 */ + for (i = 0; i < datum_count; i++) { + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + &this_raw_datum, ACPI_READ); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); + /* We might actually be done if the request fits in one datum */ - /* 2) Mask off any upper unused bits (bits not part of the field) */ + if ((datum_count == 1) && + (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { + /* 1) Shift the valid data bits down to start at bit 0 */ - if (obj_desc->common_field.end_buffer_valid_bits) { - merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); - } + merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset); - /* Store the datum to the caller buffer */ + /* 2) Mask off any upper unused bits (bits not part of the field) */ - acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, - obj_desc->common_field.access_byte_width, datum_offset); + if (obj_desc->common_field.end_buffer_valid_bits) { + merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); + } - return_ACPI_STATUS (AE_OK); - } + /* Store the datum to the caller buffer */ + acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, + obj_desc->common_field.access_byte_width, buffer_datum_offset); - /* We need to get more raw data to complete one or more field data */ + return_ACPI_STATUS (AE_OK); + } - while (datum_offset < datum_count) { - field_datum_byte_offset += obj_desc->common_field.access_byte_width; + /* Special handling for the last datum to ignore extra bits */ - /* - * If the field is aligned on a byte boundary, we don't want - * to perform a final read, since this would potentially read - * past the end of the region. - * - * We could just split the aligned and non-aligned cases since the - * aligned case is so very simple, but this would require more code. - */ - if ((obj_desc->common_field.start_field_bit_offset != 0) || - ((obj_desc->common_field.start_field_bit_offset == 0) && - (datum_offset < (datum_count -1)))) { + if ((i >= (datum_count -1)) && + (obj_desc->common_field.end_field_valid_bits)) { /* - * Get the next raw datum, it contains some or all bits - * of the current field datum + * This is the last iteration of the loop. We need to clear + * any unused bits (bits that are not part of this field) before + * we store the final merged datum into the caller buffer. */ - status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, - &this_raw_datum, ACPI_READ); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + this_raw_datum &= + ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); } /* @@ -891,48 +891,48 @@ acpi_ex_extract_from_field ( if (obj_desc->common_field.start_field_bit_offset == 0) { /* Field is not skewed and we can just copy the datum */ - merged_datum = previous_raw_datum; + acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length, + obj_desc->common_field.access_byte_width, buffer_datum_offset); + buffer_datum_offset++; } else { - /* - * Put together the appropriate bits of the two raw data to make a - * single complete field datum - * - * 1) Normalize the first datum down to bit 0 - */ - merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); - - /* 2) Insert the second datum "above" the first datum */ + /* Not aligned -- on the first iteration, just save the datum */ - merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits); - - if ((datum_offset >= (datum_count -1))) { + if (i != 0) { /* - * This is the last iteration of the loop. We need to clear - * any unused bits (bits that are not part of this field) that - * came from the last raw datum before we store the final - * merged datum into the caller buffer. + * Put together the appropriate bits of the two raw data to make a + * single complete field datum + * + * 1) Normalize the first datum down to bit 0 */ - if (obj_desc->common_field.end_buffer_valid_bits) { - merged_datum &= - ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); - } + merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); + + /* 2) Insert the second datum "above" the first datum */ + + merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits); + + acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, + obj_desc->common_field.access_byte_width, buffer_datum_offset); + buffer_datum_offset++; } + + /* + * Save the raw datum that was just acquired since it may contain bits + * of the *next* field datum + */ + previous_raw_datum = this_raw_datum; } - /* - * Store the merged field datum in the caller's buffer, according to - * the granularity of the field (size of each datum). - */ - acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, - obj_desc->common_field.access_byte_width, datum_offset); + field_datum_byte_offset += obj_desc->common_field.access_byte_width; + } - /* - * Save the raw datum that was just acquired since it may contain bits - * of the *next* field datum. Update offsets - */ - previous_raw_datum = this_raw_datum; - datum_offset++; + /* For non-aligned case, there is one last datum to insert */ + + if (obj_desc->common_field.start_field_bit_offset != 0) { + merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset); + + acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, + obj_desc->common_field.access_byte_width, buffer_datum_offset); } return_ACPI_STATUS (AE_OK); --- linux-2.6.1-rc1/drivers/acpi/executer/exmisc.c 2003-06-14 12:18:30.000000000 -0700 +++ 25/drivers/acpi/executer/exmisc.c 2003-12-30 22:49:41.000000000 -0800 @@ -121,8 +121,8 @@ acpi_ex_get_object_reference ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type %X in %p\n", - ACPI_GET_DESCRIPTOR_TYPE (obj_desc), obj_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p has invalid descriptor [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc))); return_ACPI_STATUS (AE_TYPE); } @@ -139,7 +139,7 @@ acpi_ex_get_object_reference ( *return_desc = reference_obj; ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n", - obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); + obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); return_ACPI_STATUS (AE_OK); } --- linux-2.6.1-rc1/drivers/acpi/executer/exmutex.c 2003-06-14 12:18:30.000000000 -0700 +++ 25/drivers/acpi/executer/exmutex.c 2003-12-30 22:49:41.000000000 -0800 @@ -159,7 +159,7 @@ acpi_ex_acquire_mutex ( if (!walk_state->thread) { ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n", - obj_desc->mutex.node->name.ascii)); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -169,7 +169,7 @@ acpi_ex_acquire_mutex ( */ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n", - obj_desc->mutex.node->name.ascii)); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } @@ -242,7 +242,7 @@ acpi_ex_release_mutex ( if (!obj_desc->mutex.owner_thread) { ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], not acquired\n", - obj_desc->mutex.node->name.ascii)); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); } @@ -250,7 +250,7 @@ acpi_ex_release_mutex ( if (!walk_state->thread) { ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], null thread info\n", - obj_desc->mutex.node->name.ascii)); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -260,7 +260,7 @@ acpi_ex_release_mutex ( ACPI_REPORT_ERROR (( "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n", walk_state->thread->thread_id, - obj_desc->mutex.node->name.ascii, + acpi_ut_get_node_name (obj_desc->mutex.node), obj_desc->mutex.owner_thread->thread_id)); return_ACPI_STATUS (AE_AML_NOT_OWNER); } @@ -271,7 +271,7 @@ acpi_ex_release_mutex ( */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n", - obj_desc->mutex.node->name.ascii)); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } --- linux-2.6.1-rc1/drivers/acpi/executer/exoparg1.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/executer/exoparg1.c 2003-12-30 22:49:41.000000000 -0800 @@ -351,8 +351,7 @@ acpi_ex_opcode_1A_1T_1R ( if (digit > 0) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Integer too large to convert to BCD: %8.8X%8.8X\n", - ACPI_HIDWORD(operand[0]->integer.value), - ACPI_LODWORD(operand[0]->integer.value))); + ACPI_FORMAT_UINT64 (operand[0]->integer.value))); status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } --- linux-2.6.1-rc1/drivers/acpi/executer/exoparg3.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/drivers/acpi/executer/exoparg3.c 2003-12-30 22:49:41.000000000 -0800 @@ -101,15 +101,14 @@ acpi_ex_opcode_3A_0T_0R ( switch (walk_state->opcode) { - case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", - (u32) operand[0]->integer.value, (u32) operand[1]->integer.value, + (u32) operand[0]->integer.value, + (u32) operand[1]->integer.value, (u32) operand[2]->integer.value)); - fatal = ACPI_MEM_ALLOCATE (sizeof (struct acpi_signal_fatal_info)); if (fatal) { fatal->type = (u32) operand[0]->integer.value; --- linux-2.6.1-rc1/drivers/acpi/executer/exprep.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/executer/exprep.c 2003-12-30 22:49:41.000000000 -0800 @@ -351,7 +351,7 @@ acpi_ex_prep_common_field_object ( */ nearest_byte_address = ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position); - obj_desc->common_field.base_byte_offset = + obj_desc->common_field.base_byte_offset = (u32) ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment); /* @@ -539,7 +539,7 @@ acpi_ex_prep_field_value ( acpi_ns_get_type (info->field_node)); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set named_obj %p [%4.4s], obj_desc %p\n", - info->field_node, info->field_node->name.ascii, obj_desc)); + info->field_node, acpi_ut_get_node_name (info->field_node), obj_desc)); /* Remove local reference to the object */ --- linux-2.6.1-rc1/drivers/acpi/executer/exregion.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/drivers/acpi/executer/exregion.c 2003-12-30 22:49:41.000000000 -0800 @@ -161,7 +161,7 @@ acpi_ex_system_memory_space_handler ( (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", - ACPI_HIDWORD (address), ACPI_LODWORD (address), (u32) window_size)); + ACPI_FORMAT_UINT64 (address), (u32) window_size)); mem_info->mapped_length = 0; return_ACPI_STATUS (status); } @@ -180,8 +180,8 @@ acpi_ex_system_memory_space_handler ( ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, - ACPI_HIDWORD (address), ACPI_LODWORD (address))); + "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, + ACPI_FORMAT_UINT64 (address))); /* * Perform the memory read or write @@ -290,8 +290,8 @@ acpi_ex_system_io_space_handler ( ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "system_iO %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, - ACPI_HIDWORD (address), ACPI_LODWORD (address))); + "system_iO %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, + ACPI_FORMAT_UINT64 (address))); /* Decode the function parameter */ --- linux-2.6.1-rc1/drivers/acpi/executer/exresolv.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/executer/exresolv.c 2003-12-30 22:49:41.000000000 -0800 @@ -349,6 +349,8 @@ acpi_ex_resolve_multiple ( /* All "References" point to a NS node */ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -399,7 +401,9 @@ acpi_ex_resolve_multiple ( /* All "References" point to a NS node */ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { - return_ACPI_STATUS (AE_AML_INTERNAL); + ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); + return_ACPI_STATUS (AE_AML_INTERNAL); } /* Get the attached object */ --- linux-2.6.1-rc1/drivers/acpi/executer/exresop.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/executer/exresop.c 2003-12-30 22:49:41.000000000 -0800 @@ -247,8 +247,8 @@ acpi_ex_resolve_operands ( /* Invalid descriptor */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Bad descriptor type %X in Obj %p\n", - ACPI_GET_DESCRIPTOR_TYPE (obj_desc), obj_desc)); + "Invalid descriptor %p [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } --- linux-2.6.1-rc1/drivers/acpi/executer/exstore.c 2003-06-22 12:04:44.000000000 -0700 +++ 25/drivers/acpi/executer/exstore.c 2003-12-30 22:49:41.000000000 -0800 @@ -190,8 +190,7 @@ acpi_ex_store ( case ACPI_TYPE_INTEGER: ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%8.8X%8.8X\n", - ACPI_HIDWORD (source_desc->integer.value), - ACPI_LODWORD (source_desc->integer.value))); + ACPI_FORMAT_UINT64 (source_desc->integer.value))); break; --- linux-2.6.1-rc1/drivers/acpi/executer/exsystem.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/executer/exsystem.c 2003-12-30 22:49:41.000000000 -0800 @@ -111,11 +111,16 @@ acpi_ex_system_wait_semaphore ( * * FUNCTION: acpi_ex_system_do_stall * - * PARAMETERS: how_long - The amount of time to stall + * PARAMETERS: how_long - The amount of time to stall, + * in microseconds * * RETURN: Status * * DESCRIPTION: Suspend running thread for specified amount of time. + * Note: ACPI specification requires that Stall() does not + * relinquish the processor, and delays longer than 100 usec + * should use Sleep() instead. We allow stalls up to 255 usec + * for compatibility with other interpreters and existing BIOSs. * ******************************************************************************/ @@ -129,12 +134,15 @@ acpi_ex_system_do_stall ( ACPI_FUNCTION_ENTRY (); - if (how_long > 100) /* 100 microseconds */ { + if (how_long > 255) /* 255 microseconds */ { /* - * Longer than 100 usec, use sleep instead - * (according to ACPI specification) + * Longer than 255 usec, this is an error + * + * (ACPI specifies 100 usec as max, but this gives some slack in + * order to support existing BIOSs) */ - status = acpi_ex_system_do_suspend ((how_long / 1000) + 1); + ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", how_long)); + status = AE_AML_OPERAND_VALUE; } else { acpi_os_stall (how_long); @@ -148,7 +156,8 @@ acpi_ex_system_do_stall ( * * FUNCTION: acpi_ex_system_do_suspend * - * PARAMETERS: how_long - The amount of time to suspend + * PARAMETERS: how_long - The amount of time to suspend, + * in milliseconds * * RETURN: None * --- linux-2.6.1-rc1/drivers/acpi/hardware/hwacpi.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/hardware/hwacpi.c 2003-12-30 22:49:41.000000000 -0800 @@ -119,7 +119,7 @@ acpi_hw_set_mode ( * system does not support mode transition. */ if (!acpi_gbl_FADT->smi_cmd) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No SMI_CMD in FADT, mode transition failed.\n")); + ACPI_REPORT_ERROR (("No SMI_CMD in FADT, mode transition failed.\n")); return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } @@ -131,7 +131,7 @@ acpi_hw_set_mode ( * transitions are not supported. */ if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No mode transition supported in this system.\n")); + ACPI_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n")); return_ACPI_STATUS (AE_OK); } @@ -162,6 +162,7 @@ acpi_hw_set_mode ( } if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -171,18 +172,16 @@ acpi_hw_set_mode ( */ retry = 3000; while (retry) { - status = AE_NO_HARDWARE_RESPONSE; - if (acpi_hw_get_mode() == mode) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode)); - status = AE_OK; - break; + return_ACPI_STATUS (AE_OK); } acpi_os_stall(1000); retry--; } - return_ACPI_STATUS (status); + ACPI_REPORT_ERROR (("Hardware never changed modes\n")); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } --- linux-2.6.1-rc1/drivers/acpi/hardware/hwregs.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/drivers/acpi/hardware/hwregs.c 2003-12-30 22:49:41.000000000 -0800 @@ -418,16 +418,14 @@ acpi_set_register ( ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", register_value, - ACPI_HIDWORD (acpi_gbl_FADT->xpm2_cnt_blk.address), - ACPI_LODWORD (acpi_gbl_FADT->xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, bit_reg_info->access_bit_mask, value); ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", register_value, - ACPI_HIDWORD (acpi_gbl_FADT->xpm2_cnt_blk.address), - ACPI_LODWORD (acpi_gbl_FADT->xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); @@ -763,8 +761,7 @@ acpi_hw_low_level_read ( ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", *value, width, - ACPI_HIDWORD (reg->address), - ACPI_LODWORD (reg->address), + ACPI_FORMAT_UINT64 (reg->address), acpi_ut_get_region_name (reg->address_space_id))); return (status); @@ -850,8 +847,7 @@ acpi_hw_low_level_write ( ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", value, width, - ACPI_HIDWORD (reg->address), - ACPI_LODWORD (reg->address), + ACPI_FORMAT_UINT64 (reg->address), acpi_ut_get_region_name (reg->address_space_id))); return (status); --- linux-2.6.1-rc1/drivers/acpi/hardware/hwsleep.c 2003-06-22 12:04:44.000000000 -0700 +++ 25/drivers/acpi/hardware/hwsleep.c 2003-12-30 22:49:41.000000000 -0800 @@ -181,6 +181,13 @@ acpi_enter_sleep_state_prep ( return_ACPI_STATUS (status); } + /* Set the system indicators to show the desired sleep state. */ + + status = acpi_evaluate_object (NULL, "\\_SI._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 (AE_OK); } @@ -220,27 +227,28 @@ acpi_enter_sleep_state ( return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } - sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); - /* Clear wake status */ + if (sleep_state != ACPI_STATE_S5) { + /* Clear wake status */ - status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - /* Disable BM arbitration */ + /* Disable BM arbitration */ - status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } status = acpi_hw_disable_non_wakeup_gpes(); @@ -297,11 +305,13 @@ acpi_enter_sleep_state ( return_ACPI_STATUS (status); } - /* - * Wait a second, then try again. This is to get S4/5 to work on all machines. - */ if (sleep_state > ACPI_STATE_S3) { /* + * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that + * we are still executing!) + * + * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines. + * * We wait so long to allow chipsets that poll this reg very slowly to * still read the right value. Ideally, this entire block would go * away entirely. @@ -354,6 +364,7 @@ acpi_enter_sleep_state_s4bios ( ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios"); + acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); @@ -389,15 +400,38 @@ acpi_enter_sleep_state_s4bios ( acpi_status acpi_leave_sleep_state ( - u8 sleep_state) + u8 sleep_state) { - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status; + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + struct acpi_bit_register_info *sleep_type_reg_info; + struct acpi_bit_register_info *sleep_enable_reg_info; + u32 pm1x_control; ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state"); + /* Some machines require SLP_TYPE and SLP_EN to be cleared */ + + sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); + sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); + + /* Get current value of PM1A control */ + + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, &pm1x_control); + if (ACPI_SUCCESS (status)) { + /* Clear SLP_TYP and SLP_EN */ + + pm1x_control &= ~(sleep_type_reg_info->access_bit_mask | + sleep_enable_reg_info->access_bit_mask); + + acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1A_CONTROL, pm1x_control); + acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1B_CONTROL, pm1x_control); + } /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ @@ -407,12 +441,17 @@ acpi_leave_sleep_state ( arg_list.count = 1; arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = sleep_state; /* Ignore any errors from these methods */ + arg.integer.value = 0; + status = acpi_evaluate_object (NULL, "\\_SI._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); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); @@ -430,8 +469,8 @@ acpi_leave_sleep_state ( return_ACPI_STATUS (status); } - /* Disable BM arbitration */ - status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK); + /* Enable BM arbitration */ + status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK); return_ACPI_STATUS (status); } --- linux-2.6.1-rc1/drivers/acpi/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/drivers/acpi/Kconfig 2003-12-30 22:49:52.000000000 -0800 @@ -263,5 +263,23 @@ config ACPI_RELAXED_AML 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 + depends on ACPI_BOOT && EXPERIMENTAL + default n + help + The Power Management Timer is available on all ACPI-capable, + in most cases even if ACPI is unusable or blacklisted. + + This timing source is not affected by powermanagement features + like aggressive processor idling, throttling, frequency and/or + voltage scaling, unlike the commonly used Time Stamp Counter + (TSC) timing source. + + So, if you see messages like 'Losing too many ticks!' in the + kernel logs, and/or you are using a this on a notebook which + does not yet have an HPET, you should say "Y" here. + endmenu --- linux-2.6.1-rc1/drivers/acpi/namespace/nsaccess.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/drivers/acpi/namespace/nsaccess.c 2003-12-30 22:49:41.000000000 -0800 @@ -314,8 +314,8 @@ acpi_ns_lookup ( else { prefix_node = scope_info->scope.node; if (ACPI_GET_DESCRIPTOR_TYPE (prefix_node) != ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "[%p] Not a namespace node\n", - prefix_node)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p Not a namespace node [%s]\n", + prefix_node, acpi_ut_get_descriptor_name (prefix_node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -379,7 +379,7 @@ acpi_ns_lookup ( ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching relative to prefix scope [%4.4s] (%p)\n", - prefix_node->name.ascii, prefix_node)); + acpi_ut_get_node_name (prefix_node), prefix_node)); /* * Handle multiple Parent Prefixes (carat) by just getting @@ -413,7 +413,7 @@ acpi_ns_lookup ( if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Search scope is [%4.4s], path has %d carat(s)\n", - this_node->name.ascii, num_carats)); + acpi_ut_get_node_name (this_node), num_carats)); } } --- linux-2.6.1-rc1/drivers/acpi/namespace/nsalloc.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/drivers/acpi/namespace/nsalloc.c 2003-12-30 22:49:41.000000000 -0800 @@ -271,7 +271,7 @@ acpi_ns_install_node ( * alphabetic placement. */ previous_child_node = NULL; - while (acpi_ns_compare_names (child_node->name.ascii, node->name.ascii) < 0) { + while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) { if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { /* Last peer; Clear end-of-list flag */ @@ -335,8 +335,9 @@ acpi_ns_install_node ( node->type = (u8) type; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s (%s) added to %4.4s (%s) %p at %p\n", - node->name.ascii, acpi_ut_get_type_name (node->type), - parent_node->name.ascii, acpi_ut_get_type_name (parent_node->type), parent_node, node)); + acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), + acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type), + parent_node, node)); /* * Increment the reference count(s) of all parents up to --- linux-2.6.1-rc1/drivers/acpi/namespace/nsdump.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/namespace/nsdump.c 2003-12-30 22:49:41.000000000 -0800 @@ -50,8 +50,8 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsdump") -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /******************************************************************************* * @@ -76,7 +76,7 @@ acpi_ns_print_pathname ( return; } - /* Print the entire name */ + /* Print the entire name */ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[")); @@ -205,7 +205,7 @@ acpi_ns_dump_one_object ( * Now we can print out the pertinent information */ acpi_os_printf ("%4.4s %-12s %p ", - this_node->name.ascii, acpi_ut_get_type_name (type), this_node); + acpi_ut_get_node_name (this_node), acpi_ut_get_type_name (type), this_node); dbg_level = acpi_dbg_level; acpi_dbg_level = 0; @@ -250,8 +250,7 @@ acpi_ns_dump_one_object ( case ACPI_TYPE_INTEGER: acpi_os_printf ("= %8.8X%8.8X\n", - ACPI_HIDWORD (obj_desc->integer.value), - ACPI_LODWORD (obj_desc->integer.value)); + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); break; @@ -302,8 +301,7 @@ acpi_ns_dump_one_object ( acpi_os_printf ("[%s]", acpi_ut_get_region_name (obj_desc->region.space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { acpi_os_printf (" Addr %8.8X%8.8X Len %.4X\n", - ACPI_HIDWORD (obj_desc->region.address), - ACPI_LODWORD (obj_desc->region.address), + ACPI_FORMAT_UINT64 (obj_desc->region.address), obj_desc->region.length); } else { @@ -324,7 +322,7 @@ acpi_ns_dump_one_object ( if (obj_desc->buffer_field.buffer_obj && obj_desc->buffer_field.buffer_obj->buffer.node) { acpi_os_printf ("Buf [%4.4s]", - obj_desc->buffer_field.buffer_obj->buffer.node->name.ascii); + acpi_ut_get_node_name (obj_desc->buffer_field.buffer_obj->buffer.node)); } break; @@ -332,29 +330,29 @@ acpi_ns_dump_one_object ( case ACPI_TYPE_LOCAL_REGION_FIELD: acpi_os_printf ("Rgn [%4.4s]", - obj_desc->common_field.region_obj->region.node->name.ascii); + acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: acpi_os_printf ("Rgn [%4.4s] Bnk [%4.4s]", - obj_desc->common_field.region_obj->region.node->name.ascii, - obj_desc->bank_field.bank_obj->common_field.node->name.ascii); + acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node), + acpi_ut_get_node_name (obj_desc->bank_field.bank_obj->common_field.node)); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf ("Idx [%4.4s] Dat [%4.4s]", - obj_desc->index_field.index_obj->common_field.node->name.ascii, - obj_desc->index_field.data_obj->common_field.node->name.ascii); + acpi_ut_get_node_name (obj_desc->index_field.index_obj->common_field.node), + acpi_ut_get_node_name (obj_desc->index_field.data_obj->common_field.node)); break; case ACPI_TYPE_LOCAL_ALIAS: - acpi_os_printf ("Target %4.4s (%p)\n", ((struct acpi_namespace_node *) obj_desc)->name.ascii, obj_desc); + acpi_os_printf ("Target %4.4s (%p)\n", acpi_ut_get_node_name (obj_desc), obj_desc); break; default: @@ -371,7 +369,7 @@ acpi_ns_dump_one_object ( case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: - acpi_os_printf ("Off %.2X Len %.2X Acc %.2hd\n", + acpi_os_printf (" Off %.3X Len %.2X Acc %.2hd\n", (obj_desc->common_field.base_byte_offset * 8) + obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.bit_length, @@ -408,8 +406,8 @@ acpi_ns_dump_one_object ( case ACPI_TYPE_INTEGER: - acpi_os_printf (" N:%X%X\n", ACPI_HIDWORD(obj_desc->integer.value), - ACPI_LODWORD(obj_desc->integer.value)); + acpi_os_printf (" I:%8.8X8.8%X\n", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); break; case ACPI_TYPE_STRING: @@ -485,7 +483,8 @@ acpi_ns_dump_one_object ( default: - acpi_os_printf ("(String or Buffer ptr - not an object descriptor)\n"); + acpi_os_printf ("(String or Buffer ptr - not an object descriptor) [%s]\n", + acpi_ut_get_descriptor_name (obj_desc)); bytes_to_dump = 16; break; } @@ -581,7 +580,6 @@ acpi_ns_dump_objects ( info.owner_id = owner_id; info.display_type = display_type; - (void) acpi_ns_walk_namespace (type, start_handle, max_depth, ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object, (void *) &info, NULL); @@ -628,7 +626,6 @@ acpi_ns_dump_tables ( ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n")); } - acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_OBJECTS, max_depth, ACPI_UINT32_MAX, search_handle); return_VOID; --- linux-2.6.1-rc1/drivers/acpi/namespace/nsdumpdv.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/drivers/acpi/namespace/nsdumpdv.c 2003-12-30 22:49:41.000000000 -0800 @@ -93,7 +93,7 @@ acpi_ns_dump_one_device ( ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", info->hardware_id.value, - ACPI_HIDWORD (info->address), ACPI_LODWORD (info->address), + ACPI_FORMAT_UINT64 (info->address), info->current_status)); ACPI_MEM_FREE (info); } --- linux-2.6.1-rc1/drivers/acpi/namespace/nsinit.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/drivers/acpi/namespace/nsinit.c 2003-12-30 22:49:41.000000000 -0800 @@ -144,10 +144,17 @@ acpi_ns_initialize_devices ( ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Executing all Device _STA and_INI methods:")); - /* Walk namespace for all objects of type Device */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Walk namespace for all objects of type Device or Processor */ - status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, FALSE, acpi_ns_init_one_device, &info, NULL); + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n", @@ -290,7 +297,8 @@ acpi_ns_init_one_object ( ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not execute arguments for [%4.4s] (%s), %s\n", - node->name.ascii, acpi_ut_get_type_name (type), acpi_format_exception (status))); + acpi_ut_get_node_name (node), acpi_ut_get_type_name (type), + acpi_format_exception (status))); } /* Print a dot for each object unless we are going to print the entire pathname */ @@ -338,45 +346,48 @@ acpi_ns_init_one_device ( ACPI_FUNCTION_TRACE ("ns_init_one_device"); - if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && (!(acpi_dbg_level & ACPI_LV_INFO))) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); - } - - info->device_count++; - - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - node = acpi_ns_map_handle_to_node (obj_handle); if (!node) { - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_BAD_PARAMETER); } - status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + /* + * We will run _STA/_INI on Devices and Processors only + */ + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR)) { + return_ACPI_STATUS (AE_OK); } + if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && (!(acpi_dbg_level & ACPI_LV_INFO))) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); + } + + info->device_count++; + /* * Run _STA to determine if we can run _INI on the device. */ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, node, "_STA")); status = acpi_ut_execute_STA (node, &flags); + if (ACPI_FAILURE (status)) { - /* Ignore error and move on to next device */ + if (node->type == ACPI_TYPE_DEVICE) { + /* Ignore error and move on to next device */ - return_ACPI_STATUS (AE_OK); - } + return_ACPI_STATUS (AE_OK); + } - info->num_STA++; + /* _STA is not required for Processor objects */ + } + else { + info->num_STA++; - if (!(flags & 0x01)) { - /* don't look at children of a not present device */ + if (!(flags & 0x01)) { + /* Don't look at children of a not present device */ - return_ACPI_STATUS(AE_CTRL_DEPTH); + return_ACPI_STATUS(AE_CTRL_DEPTH); + } } /* --- linux-2.6.1-rc1/drivers/acpi/namespace/nsobject.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/drivers/acpi/namespace/nsobject.c 2003-12-30 22:49:41.000000000 -0800 @@ -104,7 +104,8 @@ acpi_ns_attach_object ( if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { /* Not a name handle */ - ACPI_REPORT_ERROR (("ns_attach_object: Invalid handle\n")); + ACPI_REPORT_ERROR (("ns_attach_object: Invalid handle %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -151,7 +152,7 @@ acpi_ns_attach_object ( } ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n", - obj_desc, node, node->name.ascii)); + obj_desc, node, acpi_ut_get_node_name (node))); /* Detach an existing attached object if present */ @@ -234,7 +235,7 @@ acpi_ns_detach_object ( node->type = ACPI_TYPE_ANY; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", - node, node->name.ascii, obj_desc)); + node, acpi_ut_get_node_name (node), obj_desc)); /* Remove one reference on the object (and all subobjects) */ --- linux-2.6.1-rc1/drivers/acpi/namespace/nssearch.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/namespace/nssearch.c 2003-12-30 22:49:41.000000000 -0800 @@ -119,7 +119,7 @@ acpi_ns_search_node ( ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n", (char *) &target_name, acpi_ut_get_type_name (next_node->type), - next_node, node->name.ascii, node)); + next_node, acpi_ut_get_node_name (node), node)); *return_node = next_node; return_ACPI_STATUS (AE_OK); @@ -145,7 +145,7 @@ acpi_ns_search_node ( ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Name [%4.4s] (%s) not found in search in scope [%4.4s] %p first child %p\n", (char *) &target_name, acpi_ut_get_type_name (type), - node->name.ascii, node, node->child)); + acpi_ut_get_node_name (node), node, node->child)); return_ACPI_STATUS (AE_NOT_FOUND); } --- linux-2.6.1-rc1/drivers/acpi/namespace/nsutils.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/namespace/nsutils.c 2003-12-30 22:49:41.000000000 -0800 @@ -977,8 +977,8 @@ acpi_ns_find_parent_name ( parent_node = acpi_ns_get_parent_node (child_node); if (parent_node) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Parent of %p [%4.4s] is %p [%4.4s]\n", - child_node, child_node->name.ascii, - parent_node, parent_node->name.ascii)); + child_node, acpi_ut_get_node_name (child_node), + parent_node, acpi_ut_get_node_name (parent_node))); if (parent_node->name.integer) { return_VALUE ((acpi_name) parent_node->name.integer); @@ -986,7 +986,7 @@ acpi_ns_find_parent_name ( } ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "unable to find parent of %p (%4.4s)\n", - child_node, child_node->name.ascii)); + child_node, acpi_ut_get_node_name (child_node))); } return_VALUE (ACPI_UNKNOWN_NAME); --- linux-2.6.1-rc1/drivers/acpi/namespace/nsxfname.c 2003-06-14 12:18:03.000000000 -0700 +++ 25/drivers/acpi/namespace/nsxfname.c 2003-12-30 22:49:41.000000000 -0800 @@ -199,7 +199,7 @@ acpi_get_name ( /* Just copy the ACPI name from the Node and zero terminate it */ - ACPI_STRNCPY (buffer->pointer, node->name.ascii, + ACPI_STRNCPY (buffer->pointer, acpi_ut_get_node_name (node), ACPI_NAME_SIZE); ((char *) buffer->pointer) [ACPI_NAME_SIZE] = 0; status = AE_OK; --- linux-2.6.1-rc1/drivers/acpi/parser/psargs.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/drivers/acpi/parser/psargs.c 2003-12-30 22:49:41.000000000 -0800 @@ -490,7 +490,7 @@ union acpi_parse_object * acpi_ps_get_next_field ( struct acpi_parse_state *parser_state) { - u32 aml_offset = ACPI_PTR_DIFF (parser_state->aml, + u32 aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); union acpi_parse_object *field; u16 opcode; @@ -677,7 +677,7 @@ acpi_ps_get_next_arg ( /* Fill in bytelist data */ - arg->common.value.size = ACPI_PTR_DIFF (parser_state->pkg_end, + arg->common.value.size = (u32) ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml); arg->named.data = parser_state->aml; --- linux-2.6.1-rc1/drivers/acpi/parser/psparse.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/parser/psparse.c 2003-12-30 22:49:41.000000000 -0800 @@ -498,7 +498,7 @@ acpi_ps_parse_loop ( if (!op) { /* Get the next opcode from the AML stream */ - walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, + walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); walk_state->opcode = acpi_ps_peek_opcode (parser_state); @@ -710,7 +710,7 @@ acpi_ps_parse_loop ( while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && !walk_state->arg_count) { - walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, + walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); status = acpi_ps_get_next_arg (walk_state, parser_state, GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); --- linux-2.6.1-rc1/drivers/acpi/parser/psxface.c 2003-06-14 12:18:30.000000000 -0700 +++ 25/drivers/acpi/parser/psxface.c 2003-12-30 22:49:41.000000000 -0800 @@ -127,7 +127,8 @@ acpi_psx_execute ( op = acpi_ps_create_scope_op (); if (!op) { - return_ACPI_STATUS (AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto cleanup1; } /* @@ -142,20 +143,24 @@ acpi_psx_execute ( walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, NULL, NULL, NULL); if (!walk_state) { - return_ACPI_STATUS (AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto cleanup2; } status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, NULL, NULL, 1); if (ACPI_FAILURE (status)) { - acpi_ds_delete_walk_state (walk_state); - return_ACPI_STATUS (status); + goto cleanup3; } /* Parse the AML */ status = acpi_ps_parse_aml (walk_state); acpi_ps_delete_parse_tree (op); + if (ACPI_FAILURE (status)) { + goto cleanup1; /* Walk state is already deleted */ + + } /* * 2) Execute the method. Performs second pass parse simultaneously @@ -168,7 +173,8 @@ acpi_psx_execute ( op = acpi_ps_create_scope_op (); if (!op) { - return_ACPI_STATUS (AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto cleanup1; } /* Init new op with the method name and pointer back to the NS node */ @@ -180,22 +186,30 @@ acpi_psx_execute ( walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL); if (!walk_state) { - return_ACPI_STATUS (AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto cleanup2; } status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, params, return_obj_desc, 3); if (ACPI_FAILURE (status)) { - acpi_ds_delete_walk_state (walk_state); - return_ACPI_STATUS (status); + goto cleanup3; } /* * The walk of the parse tree is where we actually execute the method */ status = acpi_ps_parse_aml (walk_state); + goto cleanup2; /* Walk state already deleted */ + + +cleanup3: + acpi_ds_delete_walk_state (walk_state); + +cleanup2: acpi_ps_delete_parse_tree (op); +cleanup1: if (params) { /* Take away the extra reference that we gave the parameters above */ @@ -206,6 +220,10 @@ acpi_psx_execute ( } } + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* * If the method has returned an object, signal this to the caller with * a control exception code --- linux-2.6.1-rc1/drivers/acpi/pci_link.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/pci_link.c 2003-12-30 22:49:41.000000000 -0800 @@ -99,7 +99,7 @@ acpi_pci_link_check_possible ( void *context) { struct acpi_pci_link *link = (struct acpi_pci_link *) context; - int i = 0; + u32 i = 0; ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible"); @@ -294,7 +294,10 @@ acpi_pci_link_try_get_current ( if (!link->irq.active) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n")); - printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for device (%s [%s]).\n", irq, acpi_device_name(link->device), acpi_device_bid(link->device)); + printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for" + "device (%s [%s]).\n", irq, + acpi_device_name(link->device), + acpi_device_bid(link->device)); link->irq.active = irq; } @@ -429,30 +432,67 @@ retry_programming: PCI Link IRQ Management -------------------------------------------------------------------------- */ -#define ACPI_MAX_IRQS 256 -#define ACPI_MAX_ISA_IRQ 16 - /* - * IRQ penalties are used to promote PCI IRQ balancing. We set each ISA- - * possible IRQ (0-15) with a default penalty relative to its feasibility - * for PCI's use: + * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt + * Link Devices to move the PIRQs around to minimize sharing. + * + * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs + * that the BIOS has already set to active. This is necessary because + * ACPI has no automatic means of knowing what ISA IRQs are used. Note that + * if the BIOS doesn't set a Link Device active, ACPI needs to program it + * even if acpi_irq_nobalance is set. + * + * A tables of penalties avoids directing PCI interrupts to well known + * ISA IRQs. Boot params are available to over-ride the default table: * - * Never use: 0, 1, 2 (timer, keyboard, and cascade) - * Avoid using: 13, 14, and 15 (FP error and IDE) - * Penalize: 3, 4, 6, 7, 12 (known ISA uses) + * List interrupts that are free for PCI use. + * acpi_irq_pci=n[,m] * - * Thus we're left with IRQs 5, 9, 10, 11, and everything above 15 (IO[S]APIC) - * as 'best bets' for PCI use. + * List interrupts that should not be used for PCI: + * acpi_irq_isa=n[,m] + * + * Note that PCI IRQ routers have a list of possible IRQs, + * which may not include the IRQs this table says are available. + * + * Since this heuristic can't tell the difference between a link + * that no device will attach to, vs. a link which may be shared + * by multiple active devices -- it is not optimal. + * + * If interrupt performance is that important, get an IO-APIC system + * with a pin dedicated to each device. Or for that matter, an MSI + * enabled system. */ +#define ACPI_MAX_IRQS 256 +#define ACPI_MAX_ISA_IRQ 16 + +#define PIRQ_PENALTY_PCI_AVAILABLE (0) +#define PIRQ_PENALTY_PCI_POSSIBLE (16*16) +#define PIRQ_PENALTY_PCI_USING (16*16*16) +#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16) +#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) +#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) + static int acpi_irq_penalty[ACPI_MAX_IRQS] = { - 1000000, 1000000, 1000000, 10000, - 10000, 0, 10000, 10000, - 10000, 0, 0, 0, - 10000, 100000, 100000, 100000, + PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ + PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ + PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */ + PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ + PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ + PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ12 mouse */ + PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ + PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ + PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ + /* >IRQ15 */ }; - int acpi_pci_link_check (void) { @@ -473,20 +513,30 @@ acpi_pci_link_check (void) continue; } - if (link->irq.active) - acpi_irq_penalty[link->irq.active] += 100; - else if (link->irq.possible_count) { - int penalty = 100 / link->irq.possible_count; - for (i=0; iirq.possible_count; i++) { + /* + * reflect the possible and active irqs in the penalty table -- + * useful for breaking ties. + */ + if (link->irq.possible_count) { + int penalty = PIRQ_PENALTY_PCI_POSSIBLE / link->irq.possible_count; + + for (i = 0; i < link->irq.possible_count; i++) { if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) acpi_irq_penalty[link->irq.possible[i]] += penalty; } + + } else if (link->irq.active) { + acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_POSSIBLE; } } + /* Add a penalty for the SCI */ + acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING; return_VALUE(0); } +static int acpi_irq_balance; /* 0: static, 1: balance */ + static int acpi_pci_link_allocate(struct acpi_pci_link* link) { int irq; int i; @@ -500,12 +550,14 @@ static int acpi_pci_link_allocate(struct irq = link->irq.active; } else { irq = link->irq.possible[0]; + } + if (acpi_irq_balance || !link->irq.active) { /* * Select the best IRQ. This is done in reverse to promote * the use of IRQs 9, 10, 11, and >15. */ - for (i=(link->irq.possible_count-1); i>0; i--) { + for (i = (link->irq.possible_count - 1); i >= 0; i--) { if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]]) irq = link->irq.possible[i]; } @@ -518,13 +570,14 @@ static int acpi_pci_link_allocate(struct acpi_device_bid(link->device)); return_VALUE(-ENODEV); } else { - acpi_irq_penalty[link->irq.active] += 100; + acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; printk(PREFIX "%s [%s] enabled at IRQ %d\n", acpi_device_name(link->device), acpi_device_bid(link->device), link->irq.active); } link->irq.setonboot = 1; + return_VALUE(0); } @@ -607,9 +660,12 @@ acpi_pci_link_add ( if (result) goto end; + /* query and set link->irq.active */ acpi_pci_link_get_current(link); - printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), acpi_device_bid(device)); +//#ifdef CONFIG_ACPI_DEBUG + printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), + acpi_device_bid(device)); for (i = 0; i < link->irq.possible_count; i++) { if (link->irq.active == link->irq.possible[i]) { printk(" *%d", link->irq.possible[i]); @@ -619,6 +675,7 @@ acpi_pci_link_add ( printk(" %d", link->irq.possible[i]); } printk(")\n"); +//#endif /* CONFIG_ACPI_DEBUG */ /* TBD: Acquire/release lock */ list_add_tail(&link->node, &acpi_link.entries); @@ -654,6 +711,77 @@ acpi_pci_link_remove ( return_VALUE(0); } +/* + * modify acpi_irq_penalty[] from cmdline + */ +static int __init acpi_irq_penalty_update(char *str, int used) +{ + int i; + + for (i = 0; i < 16; i++) { + int retval; + int irq; + + retval = get_option(&str,&irq); + + if (!retval) + break; /* no number found */ + + if (irq < 0) + continue; + + if (irq >= ACPI_MAX_IRQS) + continue; + + if (used) + acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; + else + acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE; + + if (retval != 2) /* no next number */ + break; + } + return 1; +} + +/* + * Over-ride default table to reserve additional IRQs for use by ISA + * e.g. acpi_irq_isa=5 + * Useful for telling ACPI how not to interfere with your ISA sound card. + */ +static int __init acpi_irq_isa(char *str) +{ + return(acpi_irq_penalty_update(str, 1)); +} +__setup("acpi_irq_isa=", acpi_irq_isa); + +/* + * Over-ride default table to free additional IRQs for use by PCI + * e.g. acpi_irq_pci=7,15 + * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing. + */ +static int __init acpi_irq_pci(char *str) +{ + return(acpi_irq_penalty_update(str, 0)); +} +__setup("acpi_irq_pci=", acpi_irq_pci); + +static int __init acpi_irq_nobalance_set(char *str) +{ +printk("ACPI STATIC SET\n"); + acpi_irq_balance = 0; + return(1); +} +__setup("acpi_irq_nobalance", acpi_irq_nobalance_set); + +int __init acpi_irq_balance_set(char *str) +{ +printk("ACPI BALANCE SET\n"); + acpi_irq_balance = 1; + return(1); +} +__setup("acpi_irq_balance", acpi_irq_balance_set); + static int __init acpi_pci_link_init (void) { --- linux-2.6.1-rc1/drivers/acpi/pci_root.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/acpi/pci_root.c 2003-12-30 22:49:41.000000000 -0800 @@ -62,8 +62,6 @@ struct acpi_pci_root { acpi_handle handle; struct acpi_pci_id id; struct pci_bus *bus; - u64 mem_tra; - u64 io_tra; }; static LIST_HEAD(acpi_pci_roots); @@ -115,97 +113,6 @@ void acpi_pci_unregister_driver(struct a } } -void -acpi_pci_get_translations ( - struct acpi_pci_id *id, - u64 *mem_tra, - u64 *io_tra) -{ - struct list_head *node = NULL; - struct acpi_pci_root *entry; - - /* TBD: Locking */ - list_for_each(node, &acpi_pci_roots) { - entry = list_entry(node, struct acpi_pci_root, node); - if ((id->segment == entry->id.segment) - && (id->bus == entry->id.bus)) { - *mem_tra = entry->mem_tra; - *io_tra = entry->io_tra; - return; - } - } - - *mem_tra = 0; - *io_tra = 0; -} - - -static u64 -acpi_pci_root_bus_tra ( - struct acpi_resource *resource, - int type) -{ - struct acpi_resource_address16 *address16; - struct acpi_resource_address32 *address32; - struct acpi_resource_address64 *address64; - - while (1) { - switch (resource->id) { - case ACPI_RSTYPE_END_TAG: - return 0; - - case ACPI_RSTYPE_ADDRESS16: - address16 = (struct acpi_resource_address16 *) &resource->data; - if (type == address16->resource_type) { - return address16->address_translation_offset; - } - break; - - case ACPI_RSTYPE_ADDRESS32: - address32 = (struct acpi_resource_address32 *) &resource->data; - if (type == address32->resource_type) { - return address32->address_translation_offset; - } - break; - - case ACPI_RSTYPE_ADDRESS64: - address64 = (struct acpi_resource_address64 *) &resource->data; - if (type == address64->resource_type) { - return address64->address_translation_offset; - } - break; - } - resource = ACPI_PTR_ADD (struct acpi_resource, - resource, resource->length); - } - - return 0; -} - - -static int -acpi_pci_evaluate_crs ( - struct acpi_pci_root *root) -{ - acpi_status status; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - - ACPI_FUNCTION_TRACE("acpi_pci_evaluate_crs"); - - status = acpi_get_current_resources (root->handle, &buffer); - if (ACPI_FAILURE(status)) - return_VALUE(-ENODEV); - - root->io_tra = acpi_pci_root_bus_tra ((struct acpi_resource *) - buffer.pointer, ACPI_IO_RANGE); - root->mem_tra = acpi_pci_root_bus_tra ((struct acpi_resource *) - buffer.pointer, ACPI_MEMORY_RANGE); - - acpi_os_free(buffer.pointer); - return_VALUE(0); -} - - static int acpi_pci_root_add ( struct acpi_device *device) @@ -288,10 +195,8 @@ acpi_pci_root_add ( root->id.function = device->pnp.bus_address & 0xFFFF; /* - * Evaluate _CRS to get root bridge resources * TBD: Need PCI interface for enumeration/configuration of roots. */ - acpi_pci_evaluate_crs(root); /* TBD: Locking */ list_add_tail(&root->node, &acpi_pci_roots); --- linux-2.6.1-rc1/drivers/acpi/resources/rscalc.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/acpi/resources/rscalc.c 2003-12-30 22:49:41.000000000 -0800 @@ -696,7 +696,7 @@ acpi_rs_get_list_length ( default: /* * If we get here, everything is out of sync, - * so exit with an error + * exit with an error */ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } @@ -704,7 +704,7 @@ acpi_rs_get_list_length ( /* * Update the return value and counter */ - buffer_size += ACPI_ALIGN_RESOURCE_SIZE(structure_size); + buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE (structure_size); bytes_parsed += bytes_consumed; /* --- linux-2.6.1-rc1/drivers/acpi/resources/rscreate.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/drivers/acpi/resources/rscreate.c 2003-12-30 22:49:41.000000000 -0800 @@ -331,7 +331,7 @@ acpi_rs_create_pci_routing_table ( /* Now align the current length */ - user_prt->length = ACPI_ROUND_UP_to_64_bITS (user_prt->length); + user_prt->length = (u32) ACPI_ROUND_UP_to_64_bITS (user_prt->length); /* * 4) Fourth subobject: Dereference the PRT.source_index --- linux-2.6.1-rc1/drivers/acpi/resources/rsdump.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/acpi/resources/rsdump.c 2003-12-30 22:49:41.000000000 -0800 @@ -899,24 +899,19 @@ acpi_rs_dump_address64 ( "" : "not "); acpi_os_printf (" Granularity: %8.8X%8.8X\n", - ACPI_HIDWORD (address64_data->granularity), - ACPI_LODWORD (address64_data->granularity)); + ACPI_FORMAT_UINT64 (address64_data->granularity)); acpi_os_printf (" Address range min: %8.8X%8.8X\n", - ACPI_HIDWORD (address64_data->min_address_range), - ACPI_HIDWORD (address64_data->min_address_range)); + ACPI_FORMAT_UINT64 (address64_data->min_address_range)); acpi_os_printf (" Address range max: %8.8X%8.8X\n", - ACPI_HIDWORD (address64_data->max_address_range), - ACPI_HIDWORD (address64_data->max_address_range)); + ACPI_FORMAT_UINT64 (address64_data->max_address_range)); acpi_os_printf (" Address translation offset: %8.8X%8.8X\n", - ACPI_HIDWORD (address64_data->address_translation_offset), - ACPI_HIDWORD (address64_data->address_translation_offset)); + ACPI_FORMAT_UINT64 (address64_data->address_translation_offset)); acpi_os_printf (" Address Length: %8.8X%8.8X\n", - ACPI_HIDWORD (address64_data->address_length), - ACPI_HIDWORD (address64_data->address_length)); + ACPI_FORMAT_UINT64 (address64_data->address_length)); if(0xFF != address64_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", @@ -1126,8 +1121,7 @@ acpi_rs_dump_irq_list ( acpi_os_printf ("PCI IRQ Routing Table structure %X.\n", count++); acpi_os_printf (" Address: %8.8X%8.8X\n", - ACPI_HIDWORD (prt_element->address), - ACPI_LODWORD (prt_element->address)); + ACPI_FORMAT_UINT64 (prt_element->address)); acpi_os_printf (" Pin: %X\n", prt_element->pin); --- linux-2.6.1-rc1/drivers/acpi/resources/rsirq.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/resources/rsirq.c 2003-12-30 22:49:41.000000000 -0800 @@ -132,26 +132,28 @@ acpi_rs_irq_resource ( temp8 = *buffer; /* - * Check for HE, LL or HL + * Check for HE, LL interrupts */ - if (temp8 & 0x01) { + switch (temp8 & 0x09) { + case 0x01: /* HE */ output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE; output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH; - } - else { - if (temp8 & 0x8) { - output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE; - output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW; - } - else { - /* - * Only _LL and _HE polarity/trigger interrupts - * are allowed (ACPI spec v1.0b ection 6.4.2.1), - * so an error will occur if we reach this point - */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid interrupt polarity/trigger in resource list\n")); - return_ACPI_STATUS (AE_BAD_DATA); - } + break; + + case 0x08: /* LL */ + output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE; + output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW; + break; + + default: + /* + * Only _LL and _HE polarity/trigger interrupts + * are allowed (ACPI spec, section "IRQ Format") + * so 0x00 and 0x09 are illegal. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid interrupt polarity/trigger in resource list, %X\n", temp8)); + return_ACPI_STATUS (AE_BAD_DATA); } /* @@ -419,7 +421,7 @@ acpi_rs_extended_irq_resource ( * Point the String pointer to the end of this structure. */ output_struct->data.extended_irq.resource_source.string_ptr = - (char *)(output_struct + struct_size); + (char *)((char *) output_struct + struct_size); temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr; --- linux-2.6.1-rc1/drivers/acpi/resources/rslist.c 2003-06-14 12:18:51.000000000 -0700 +++ 25/drivers/acpi/resources/rslist.c 2003-12-30 22:49:41.000000000 -0800 @@ -312,8 +312,8 @@ acpi_rs_byte_stream_to_list ( * Set the Buffer to the next structure */ resource = ACPI_CAST_PTR (struct acpi_resource, buffer); - resource->length = ACPI_ALIGN_RESOURCE_SIZE(resource->length); - buffer += ACPI_ALIGN_RESOURCE_SIZE(structure_size); + resource->length = (u32) ACPI_ALIGN_RESOURCE_SIZE (resource->length); + buffer += ACPI_ALIGN_RESOURCE_SIZE (structure_size); } /* end while */ --- linux-2.6.1-rc1/drivers/acpi/scan.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/drivers/acpi/scan.c 2003-12-30 22:49:41.000000000 -0800 @@ -336,6 +336,9 @@ acpi_bus_register_driver ( ACPI_FUNCTION_TRACE("acpi_bus_register_driver"); + if (acpi_disabled) + return_VALUE(-ENODEV); + if (driver) { spin_lock(&acpi_device_lock); list_add_tail(&driver->node, &acpi_bus_drivers); --- linux-2.6.1-rc1/drivers/acpi/sleep/proc.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/acpi/sleep/proc.c 2003-12-30 22:49:41.000000000 -0800 @@ -374,6 +374,9 @@ static int acpi_sleep_proc_init(void) { struct proc_dir_entry *entry = NULL; + if (acpi_disabled) + return 0; + /* 'sleep' [R/W]*/ entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); --- linux-2.6.1-rc1/drivers/acpi/tables.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/tables.c 2003-12-30 22:49:41.000000000 -0800 @@ -60,6 +60,9 @@ static char *acpi_table_signatures[ACPI_ [ACPI_HPET] = "HPET", }; +static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; +static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; + /* System Description Table (RSDT/XSDT) */ struct acpi_table_sdt { unsigned long pa; @@ -136,8 +139,14 @@ acpi_table_print_madt_entry ( { struct acpi_table_int_src_ovr *p = (struct acpi_table_int_src_ovr*) header; - printk(KERN_INFO PREFIX "INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n", - p->bus, p->bus_irq, p->global_irq, p->flags.polarity, p->flags.trigger); + printk(KERN_INFO PREFIX "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", + p->bus, p->bus_irq, p->global_irq, + mps_inti_flags_polarity[p->flags.polarity], + mps_inti_flags_trigger[p->flags.trigger]); + if(p->flags.reserved) + printk(KERN_INFO PREFIX "INT_SRC_OVR unexpected reserved flags: 0x%x\n", + p->flags.reserved); + } break; @@ -145,8 +154,9 @@ acpi_table_print_madt_entry ( { struct acpi_table_nmi_src *p = (struct acpi_table_nmi_src*) header; - printk(KERN_INFO PREFIX "NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n", - p->flags.polarity, p->flags.trigger, p->global_irq); + printk(KERN_INFO PREFIX "NMI_SRC (%s %s global_irq %d)\n", + mps_inti_flags_polarity[p->flags.polarity], + mps_inti_flags_trigger[p->flags.trigger], p->global_irq); } break; @@ -154,8 +164,10 @@ acpi_table_print_madt_entry ( { struct acpi_table_lapic_nmi *p = (struct acpi_table_lapic_nmi*) header; - printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n", - p->acpi_id, p->flags.polarity, p->flags.trigger, p->lint); + printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", + p->acpi_id, + mps_inti_flags_polarity[p->flags.polarity], + mps_inti_flags_trigger[p->flags.trigger], p->lint); } break; @@ -190,8 +202,10 @@ acpi_table_print_madt_entry ( { struct acpi_table_plat_int_src *p = (struct acpi_table_plat_int_src*) header; - printk(KERN_INFO PREFIX "PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", - p->flags.polarity, p->flags.trigger, p->type, p->id, p->eid, p->iosapic_vector, p->global_irq); + printk(KERN_INFO PREFIX "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + mps_inti_flags_polarity[p->flags.polarity], + mps_inti_flags_trigger[p->flags.trigger], + p->type, p->id, p->eid, p->iosapic_vector, p->global_irq); } break; --- linux-2.6.1-rc1/drivers/acpi/tables/tbgetall.c 2003-06-14 12:18:29.000000000 -0700 +++ 25/drivers/acpi/tables/tbgetall.c 2003-12-30 22:49:41.000000000 -0800 @@ -240,8 +240,7 @@ acpi_tb_get_required_tables ( if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) { ACPI_REPORT_WARNING (("%s, while getting table at %8.8X%8.8X\n", acpi_format_exception (status), - ACPI_HIDWORD (address.pointer.value), - ACPI_LODWORD (address.pointer.value))); + ACPI_FORMAT_UINT64 (address.pointer.value))); } } --- linux-2.6.1-rc1/drivers/acpi/tables/tbget.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/drivers/acpi/tables/tbget.c 2003-12-30 22:49:41.000000000 -0800 @@ -148,8 +148,7 @@ acpi_tb_get_table_header ( (void *) &header); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n", - ACPI_HIDWORD (address->pointer.physical), - ACPI_LODWORD (address->pointer.physical), + ACPI_FORMAT_UINT64 (address->pointer.physical), sizeof (struct acpi_table_header))); return_ACPI_STATUS (status); } @@ -365,8 +364,7 @@ acpi_tb_get_this_table ( if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", header->signature, - ACPI_HIDWORD (address->pointer.physical), - ACPI_LODWORD (address->pointer.physical), header->length)); + ACPI_FORMAT_UINT64 (address->pointer.physical), header->length)); return (status); } @@ -408,8 +406,7 @@ acpi_tb_get_this_table ( ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n", full_table->signature, - ACPI_HIDWORD (address->pointer.physical), - ACPI_LODWORD (address->pointer.physical), full_table)); + ACPI_FORMAT_UINT64 (address->pointer.physical), full_table)); return_ACPI_STATUS (status); } @@ -458,6 +455,7 @@ acpi_tb_get_table_ptr ( if (instance == 1) { /* Get the first */ + *table_ptr_loc = NULL; if (acpi_gbl_table_lists[table_type].next) { *table_ptr_loc = acpi_gbl_table_lists[table_type].next->pointer; } --- linux-2.6.1-rc1/drivers/acpi/tables/tbrsdt.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/drivers/acpi/tables/tbrsdt.c 2003-12-30 22:49:41.000000000 -0800 @@ -278,8 +278,7 @@ acpi_tb_get_table_rsdt ( ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP located at %p, points to RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, - ACPI_HIDWORD (address.pointer.value), - ACPI_LODWORD (address.pointer.value))); + ACPI_FORMAT_UINT64 (address.pointer.value))); /* Check the RSDT or XSDT signature */ --- linux-2.6.1-rc1/drivers/acpi/tables/tbxface.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/drivers/acpi/tables/tbxface.c 2003-12-30 22:49:41.000000000 -0800 @@ -251,7 +251,7 @@ acpi_unload_table ( /* Find all tables of the requested type */ table_desc = acpi_gbl_table_lists[table_type].next; - while (table_desc); { + while (table_desc) { /* * Delete all namespace entries owned by this table. Note that these * entries can appear anywhere in the namespace by virtue of the AML --- linux-2.6.1-rc1/drivers/acpi/tables/tbxfroot.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/drivers/acpi/tables/tbxfroot.c 2003-12-30 22:49:41.000000000 -0800 @@ -211,8 +211,7 @@ acpi_get_firmware_table ( ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, - ACPI_HIDWORD (address.pointer.value), - ACPI_LODWORD (address.pointer.value))); + ACPI_FORMAT_UINT64 (address.pointer.value))); /* Insert processor_mode flags */ --- linux-2.6.1-rc1/drivers/acpi/thermal.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/drivers/acpi/thermal.c 2003-12-30 22:49:41.000000000 -0800 @@ -467,6 +467,7 @@ acpi_thermal_critical ( if (result) return_VALUE(result); + printk(KERN_EMERG "Critical temperature reached (%ld C), shutting down.\n", KELVIN_TO_CELSIUS(tz->temperature)); acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled); acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF); --- linux-2.6.1-rc1/drivers/acpi/utilities/utalloc.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/utilities/utalloc.c 2003-12-30 22:49:41.000000000 -0800 @@ -902,71 +902,30 @@ acpi_ut_dump_allocations ( descriptor = ACPI_CAST_PTR (union acpi_descriptor, &element->user_space); if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) { - acpi_os_printf ("%p Len %04X %9.9s-%d ", + acpi_os_printf ("%p Len %04X %9.9s-%d [%s] ", descriptor, element->size, element->module, - element->line); + element->line, acpi_ut_get_descriptor_name (descriptor)); - /* Most of the elements will be internal objects. */ + /* Most of the elements will be Operand objects. */ switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) { case ACPI_DESC_TYPE_OPERAND: - acpi_os_printf ("obj_type %12.12s R%hd", + acpi_os_printf ("%12.12s R%hd", acpi_ut_get_type_name (descriptor->object.common.type), descriptor->object.common.reference_count); break; case ACPI_DESC_TYPE_PARSER: - acpi_os_printf ("parse_obj aml_opcode %04hX", + acpi_os_printf ("aml_opcode %04hX", descriptor->op.asl.aml_opcode); break; case ACPI_DESC_TYPE_NAMED: - acpi_os_printf ("Node %4.4s", - descriptor->node.name.ascii); - break; - - case ACPI_DESC_TYPE_STATE: - acpi_os_printf ("Untyped state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_UPDATE: - acpi_os_printf ("UPDATE state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_PACKAGE: - acpi_os_printf ("PACKAGE state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_CONTROL: - acpi_os_printf ("CONTROL state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_RPSCOPE: - acpi_os_printf ("ROOT-PARSE-SCOPE state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_PSCOPE: - acpi_os_printf ("PARSE-SCOPE state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_WSCOPE: - acpi_os_printf ("WALK-SCOPE state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_RESULT: - acpi_os_printf ("RESULT state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_NOTIFY: - acpi_os_printf ("NOTIFY state_obj"); - break; - - case ACPI_DESC_TYPE_STATE_THREAD: - acpi_os_printf ("THREAD state_obj"); + acpi_os_printf ("%4.4s", + acpi_ut_get_node_name (&descriptor->node)); break; default: - /* All types should appear above */ break; } --- linux-2.6.1-rc1/drivers/acpi/utilities/utdebug.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/drivers/acpi/utilities/utdebug.c 2003-12-30 22:49:41.000000000 -0800 @@ -447,7 +447,7 @@ acpi_ut_value_exit ( acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str, - ACPI_HIDWORD (value), ACPI_LODWORD (value)); + ACPI_FORMAT_UINT64 (value)); acpi_gbl_nesting_level--; } --- linux-2.6.1-rc1/drivers/acpi/utilities/utdelete.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/drivers/acpi/utilities/utdelete.c 2003-12-30 22:49:41.000000000 -0800 @@ -140,7 +140,7 @@ acpi_ut_delete_internal_obj ( /* Walk the handler list for this device */ - handler_desc = object->device.address_space; + handler_desc = object->device.handler; while (handler_desc) { next_desc = handler_desc->address_space.next; acpi_ut_remove_reference (handler_desc); @@ -193,7 +193,7 @@ acpi_ut_delete_internal_obj ( * default handlers -- and therefore, we created the context object * locally, it was not created by an external caller. */ - handler_desc = object->region.address_space; + handler_desc = object->region.handler; if (handler_desc) { if (handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { obj_pointer = second_desc->extra.region_context; --- linux-2.6.1-rc1/drivers/acpi/utilities/uteval.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/drivers/acpi/utilities/uteval.c 2003-12-30 22:49:41.000000000 -0800 @@ -91,7 +91,7 @@ acpi_ut_evaluate_object ( if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", - prefix_node->name.ascii, path)); + acpi_ut_get_node_name (prefix_node), path)); } else { ACPI_REPORT_METHOD_ERROR ("Method execution failed", @@ -544,7 +544,7 @@ acpi_ut_execute_STA ( if (AE_NOT_FOUND == status) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_STA on %4.4s was not found, assuming device is present\n", - device_node->name.ascii)); + acpi_ut_get_node_name (device_node))); *flags = 0x0F; status = AE_OK; --- linux-2.6.1-rc1/drivers/acpi/utilities/utglobal.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/acpi/utilities/utglobal.c 2003-12-30 22:49:41.000000000 -0800 @@ -358,7 +358,7 @@ struct acpi_fixed_event_info acpi /* ACPI_EVENT_GLOBAL */ {ACPI_BITREG_GLOBAL_LOCK_STATUS, ACPI_BITREG_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, /* ACPI_EVENT_POWER_BUTTON */ {ACPI_BITREG_POWER_BUTTON_STATUS, ACPI_BITREG_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_ENABLE}, /* ACPI_EVENT_SLEEP_BUTTON */ {ACPI_BITREG_SLEEP_BUTTON_STATUS, ACPI_BITREG_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, - /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, 0, 0}, + /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE}, }; /***************************************************************************** @@ -534,6 +534,99 @@ acpi_ut_get_object_type_name ( } +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_node_name + * + * PARAMETERS: Object - A namespace node + * + * RETURN: Pointer to a string + * + * DESCRIPTION: Validate the node and return the node's ACPI name. + * + ****************************************************************************/ + +char * +acpi_ut_get_node_name ( + void *object) +{ + struct acpi_namespace_node *node; + + + if (!object) + { + return ("NULL NODE"); + } + + node = (struct acpi_namespace_node *) object; + + if (node->descriptor != ACPI_DESC_TYPE_NAMED) + { + return ("****"); + } + + if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii)) + { + return ("----"); + } + + return (node->name.ascii); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_descriptor_name + * + * PARAMETERS: Object - An ACPI object + * + * RETURN: Pointer to a string + * + * DESCRIPTION: Validate object and return the descriptor type + * + ****************************************************************************/ + +static const char *acpi_gbl_desc_type_names[] = /* printable names of descriptor types */ +{ + /* 00 */ "Invalid", + /* 01 */ "Cached", + /* 02 */ "State-Generic", + /* 03 */ "State-Update", + /* 04 */ "State-Package", + /* 05 */ "State-Control", + /* 06 */ "State-root_parse_scope", + /* 07 */ "State-parse_scope", + /* 08 */ "State-walk_scope", + /* 09 */ "State-Result", + /* 10 */ "State-Notify", + /* 11 */ "State-Thread", + /* 12 */ "Walk", + /* 13 */ "Parser", + /* 14 */ "Operand", + /* 15 */ "Node" +}; + + +char * +acpi_ut_get_descriptor_name ( + void *object) +{ + + if (!object) + { + return ("NULL OBJECT"); + } + + if (ACPI_GET_DESCRIPTOR_TYPE (object) > ACPI_DESC_TYPE_MAX) + { + return ((char *) acpi_gbl_bad_type); + } + + return ((char *) acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE (object)]); + +} + + #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /* * Strings and procedures used for debug only --- linux-2.6.1-rc1/drivers/acpi/utilities/utobject.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/drivers/acpi/utilities/utobject.c 2003-12-30 22:49:41.000000000 -0800 @@ -223,29 +223,10 @@ acpi_ut_valid_internal_object ( return (TRUE); - case ACPI_DESC_TYPE_NAMED: - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "**** Obj %p is a named obj, not ACPI obj\n", object)); - break; - - case ACPI_DESC_TYPE_PARSER: - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "**** Obj %p is a parser obj, not ACPI obj\n", object)); - break; - - case ACPI_DESC_TYPE_CACHED: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "**** Obj %p has already been released to internal cache\n", object)); - break; - default: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "**** Obj %p has unknown descriptor type %X\n", object, - ACPI_GET_DESCRIPTOR_TYPE (object))); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "%p is not not an ACPI operand obj [%s]\n", + object, acpi_ut_get_descriptor_name (object))); break; } @@ -322,7 +303,8 @@ acpi_ut_delete_object_desc ( if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Obj %p is not an ACPI object\n", object)); + "%p is not an ACPI Operand object [%s]\n", object, + acpi_ut_get_descriptor_name (object))); return_VOID; } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/base/class_simple.c 2003-12-30 22:50:05.000000000 -0800 @@ -0,0 +1,123 @@ +/* + * class_simple.c - basic char device support + * + * Copyright (c) 2003 Greg Kroah-Hartman + * Copyright (c) 2003 IBM Corp. + * + * This file is released under the GPLv2 + * + */ + +#undef DEBUG + +#include +#include +#include + +struct simple_dev { + struct list_head node; + dev_t dev; + struct class_device class_dev; +}; +#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev) + +static LIST_HEAD(simple_dev_list); +static spinlock_t simple_dev_list_lock = SPIN_LOCK_UNLOCKED; + +static void release_simple_dev(struct class_device *class_dev) +{ + struct simple_dev *s_dev = to_simple_dev(class_dev); + kfree(s_dev); +} + +static ssize_t show_dev(struct class_device *class_dev, char *buf) +{ + struct simple_dev *s_dev = to_simple_dev(class_dev); + return print_dev_t(buf, s_dev->dev); +} +static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); + +/** + * simple_add_class_device - adds a class device to sysfs for a character driver + * @class: pointer to the struct class that this device should be registered to. + * @dev: the dev_t for the device to be added. + * @device: a pointer to a struct device that is assiociated with this class device. + * @fmt: string for the class device's name + * + * This function can be used by simple char device classes that do not + * implement their own class device registration. A struct class_device will + * be created in sysfs, registered to the specified class. A "dev" file will + * be created, showing the dev_t for the device. The pointer to the struct + * class_device will be returned from the call. Any further sysfs files that + * might be required can be created using this pointer. + * Note: the struct class passed to this function must have previously been + * registered with a call to register_class(). + */ +struct class_device *simple_add_class_device(struct class *class, dev_t dev, struct device *device, const char *fmt, ...) +{ + va_list args; + struct simple_dev *s_dev; + int retval; + + s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL); + if (!s_dev) { + retval = -ENOMEM; + goto error; + } + memset(s_dev, 0x00, sizeof(*s_dev)); + + class->release = &release_simple_dev; + s_dev->dev = dev; + s_dev->class_dev.dev = device; + s_dev->class_dev.class = class; + + va_start(args,fmt); + vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args); + va_end(args); + retval = class_device_register(&s_dev->class_dev); + if (retval) + goto error; + class_device_create_file(&s_dev->class_dev, &class_device_attr_dev); + spin_lock(&simple_dev_list_lock); + list_add(&s_dev->node, &simple_dev_list); + spin_unlock(&simple_dev_list_lock); + + return &s_dev->class_dev; + +error: + kfree(s_dev); + return ERR_PTR(retval); +} +EXPORT_SYMBOL(simple_add_class_device); + +/** + * simple_remove_class_device - removes a class device that was created with simple_add_class_device() + * @dev: the dev_t of the device that was previously registered. + * + * This call unregisters and cleans up a class device that was created with a + * call to simple_add_class_device() + */ +void simple_remove_class_device(dev_t dev) +{ + struct simple_dev *s_dev = NULL; + struct list_head *tmp; + int found = 0; + + spin_lock(&simple_dev_list_lock); + list_for_each(tmp, &simple_dev_list) { + s_dev = list_entry(tmp, struct simple_dev, node); + if (s_dev->dev == dev) { + found = 1; + break; + } + } + if (found) { + list_del(&s_dev->node); + spin_unlock(&simple_dev_list_lock); + class_device_unregister(&s_dev->class_dev); + } else { + spin_unlock(&simple_dev_list_lock); + } +} +EXPORT_SYMBOL(simple_remove_class_device); + --- linux-2.6.1-rc1/drivers/base/Makefile 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/base/Makefile 2003-12-30 22:50:05.000000000 -0800 @@ -1,7 +1,7 @@ # Makefile for the Linux device tree obj-y := core.o sys.o interface.o bus.o \ - driver.o class.o platform.o \ + driver.o class.o class_simple.o platform.o \ cpu.o firmware.o init.o map.o obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o --- linux-2.6.1-rc1/drivers/block/acsi.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/acsi.c 2003-12-30 22:49:33.000000000 -0800 @@ -359,10 +359,9 @@ static void copy_from_acsibuffer( void ) static void do_end_requests( void ); static void do_acsi_request( request_queue_t * ); static void redo_acsi_request( void ); -static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int +static int acsi_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg ); -static int acsi_open( struct inode * inode, struct file * filp ); -static int acsi_release( struct inode * inode, struct file * file ); +static int acsi_open(struct block_device *bdev, struct file *filp); static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag ); static int acsi_change_blk_size( int target, int lun); static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ); @@ -1081,10 +1080,10 @@ static void redo_acsi_request( void ) ***********************************************************************/ -static int acsi_ioctl( struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg ) +static int acsi_ioctl(struct block_device *bdev, struct file *file, + unsigned int cmd, unsigned long arg ) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct acsi_info_struct *aip = disk->private_data; switch (cmd) { case HDIO_GETGEO: @@ -1096,7 +1095,7 @@ static int acsi_ioctl( struct inode *ino put_user( 64, &geo->heads ); put_user( 32, &geo->sectors ); put_user( aip->size >> 11, &geo->cylinders ); - put_user(get_start_sect(inode->i_bdev), &geo->start); + put_user(get_start_sect(bdev), &geo->start); return 0; } case SCSI_IOCTL_GET_IDLUN: @@ -1126,16 +1125,16 @@ static int acsi_ioctl( struct inode *ino * */ -static int acsi_open( struct inode * inode, struct file * filp ) +static int acsi_open(struct block_device *bdev, struct file *filp) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct acsi_info_struct *aip = disk->private_data; if (aip->access_count == 0 && aip->removable) { #if 0 aip->changed = 1; /* safety first */ #endif - check_disk_change( inode->i_bdev ); + check_disk_change(bdev); if (aip->changed) /* revalidate was not successful (no medium) */ return -ENXIO; acsi_prevent_removal(aip, 1); @@ -1143,10 +1142,11 @@ static int acsi_open( struct inode * ino aip->access_count++; if (filp && filp->f_mode) { - check_disk_change( inode->i_bdev ); + check_disk_change(bdev); if (filp->f_mode & 2) { if (aip->read_only) { - acsi_release( inode, filp ); + if (--aip->access_count == 0 && aip->removable) + acsi_prevent_removal(aip, 0); return -EROFS; } } @@ -1160,9 +1160,8 @@ static int acsi_open( struct inode * ino * be forgotten about... */ -static int acsi_release( struct inode * inode, struct file * file ) +static int acsi_release(struct gendisk *disk) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct acsi_info_struct *aip = disk->private_data; if (--aip->access_count == 0 && aip->removable) acsi_prevent_removal(aip, 0); @@ -1328,8 +1327,6 @@ static int acsi_mode_sense( int target, ********************************************************************/ -extern struct block_device_operations acsi_fops; - static struct gendisk *acsi_gendisk[MAX_DEV]; #define MAX_SCSI_DEVICE_CODE 10 --- linux-2.6.1-rc1/drivers/block/amiflop.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/amiflop.c 2003-12-30 22:49:33.000000000 -0800 @@ -1434,10 +1434,11 @@ static void do_fd_request(request_queue_ redo_fd_request(); } -static int fd_ioctl(struct inode *inode, struct file *filp, +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { - int drive = iminor(inode) & 3; + struct amiga_floppy_struct *floppy = bdev->bd_disk->private_data; + int drive = floppy - unit; static struct floppy_struct getprm; switch(cmd){ @@ -1459,7 +1460,7 @@ static int fd_ioctl(struct inode *inode, rel_fdc(); return -EBUSY; } - fsync_bdev(inode->i_bdev); + fsync_bdev(bdev); if (fd_motor_on(drive) == 0) { rel_fdc(); return -ENODEV; @@ -1488,7 +1489,7 @@ static int fd_ioctl(struct inode *inode, break; case FDFMTEND: floppy_off(drive); - invalidate_bdev(inode->i_bdev, 0); + invalidate_bdev(bdev, 0); break; case FDGETPRM: memset((void *)&getprm, 0, sizeof (getprm)); @@ -1559,10 +1560,11 @@ static void fd_probe(int dev) * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */ -static int floppy_open(struct inode *inode, struct file *filp) +static int floppy_open(struct block_device *bdev, struct file *filp) { - int drive = iminor(inode) & 3; - int system = (iminor(inode) & 4) >> 2; + struct amiga_floppy_struct *p = bdev->bd_disk->private_data; + int drive = p - unit; + int system = (MINOR(bdev->bd_dev) & 4) >> 2; int old_dev; unsigned long flags; @@ -1572,7 +1574,7 @@ static int floppy_open(struct inode *ino return -EBUSY; if (filp && filp->f_mode & 3) { - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (filp->f_mode & 2 ) { int wrprot; @@ -1607,9 +1609,10 @@ static int floppy_open(struct inode *ino return 0; } -static int floppy_release(struct inode * inode, struct file * filp) +static int floppy_release(struct gendisk *disk) { - int drive = iminor(inode) & 3; + struct amiga_floppy_struct *p = disk->private_data; + int drive = p - unit; if (unit[drive].dirty == 1) { del_timer (flush_track_timer + drive); --- linux-2.6.1-rc1/drivers/block/as-iosched.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/block/as-iosched.c 2003-12-30 22:49:54.000000000 -0800 @@ -70,6 +70,7 @@ /* Bits in as_io_context.state */ enum as_io_states { AS_TASK_RUNNING=0, /* Process has not exitted */ + AS_TASK_IOSTARTED, /* Process has started some IO */ AS_TASK_IORUNNING, /* Process has completed some IO */ }; @@ -99,7 +100,14 @@ struct as_data { sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ - unsigned long new_success; /* anticipation success on new proc */ + + unsigned long exit_prob; /* probability a task will exit while + being waited on */ + unsigned long new_ttime_total; /* mean thinktime on new proc */ + unsigned long new_ttime_mean; + u64 new_seek_total; /* mean seek on new proc */ + sector_t new_seek_mean; + unsigned long current_batch_expires; unsigned long last_check_fifo[2]; int changed_batch; /* 1: waiting for old batch to end */ @@ -137,6 +145,10 @@ enum arq_state { scheduler */ AS_RQ_DISPATCHED, /* On the dispatch list. It belongs to the driver now */ + AS_RQ_PRESCHED, /* Debug poisoning for requests being used */ + AS_RQ_REMOVED, + AS_RQ_MERGED, + AS_RQ_POSTSCHED, /* when they shouldn't be */ }; struct as_rq { @@ -183,6 +195,7 @@ static void free_as_io_context(struct as /* Called when the task exits */ static void exit_as_io_context(struct as_io_context *aic) { + WARN_ON(!test_bit(AS_TASK_RUNNING, &aic->state)); clear_bit(AS_TASK_RUNNING, &aic->state); } @@ -585,18 +598,11 @@ static void as_antic_stop(struct as_data int status = ad->antic_status; if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) { - struct as_io_context *aic; - if (status == ANTIC_WAIT_NEXT) del_timer(&ad->antic_timer); ad->antic_status = ANTIC_FINISHED; /* see as_work_handler */ kblockd_schedule_work(&ad->antic_work); - - aic = ad->io_context->aic; - if (aic->seek_samples == 0) - /* new process */ - ad->new_success = (ad->new_success * 3) / 4 + 256; } } @@ -612,14 +618,15 @@ static void as_antic_timeout(unsigned lo spin_lock_irqsave(q->queue_lock, flags); if (ad->antic_status == ANTIC_WAIT_REQ || ad->antic_status == ANTIC_WAIT_NEXT) { - struct as_io_context *aic; + struct as_io_context *aic = ad->io_context->aic; + ad->antic_status = ANTIC_FINISHED; kblockd_schedule_work(&ad->antic_work); - aic = ad->io_context->aic; - if (aic->seek_samples == 0) - /* new process */ - ad->new_success = (ad->new_success * 3) / 4; + if (aic->ttime_samples == 0) { + /* process anticipated on has exitted or timed out*/ + ad->exit_prob = (7*ad->exit_prob + 256)/8; + } } spin_unlock_irqrestore(q->queue_lock, flags); } @@ -633,7 +640,7 @@ static int as_close_req(struct as_data * unsigned long delay; /* milliseconds */ sector_t last = ad->last_sector[ad->batch_data_dir]; sector_t next = arq->request->sector; - sector_t delta; /* acceptable close offset (in sectors) */ + sector_t delta; /* acceptable close offset (in sectors) */ if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished) delay = 0; @@ -650,6 +657,7 @@ static int as_close_req(struct as_data * return (last - (delta>>1) <= next) && (next <= last + delta); } +static void as_update_thinktime(struct as_data *ad, struct as_io_context *aic, unsigned long ttime); /* * as_can_break_anticipation returns true if we have been anticipating this * request. @@ -667,9 +675,27 @@ static int as_can_break_anticipation(str { struct io_context *ioc; struct as_io_context *aic; + sector_t s; + + ioc = ad->io_context; + BUG_ON(!ioc); + + if (arq && ioc == arq->io_context) { + /* request from same process */ + return 1; + } if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, arq)) { /* close request */ + struct as_io_context *aic = ioc->aic; + if (aic) { + unsigned long thinktime; + spin_lock(&aic->lock); + thinktime = jiffies - aic->last_end_request; + aic->last_end_request = jiffies; + as_update_thinktime(ad, aic, thinktime); + spin_unlock(&aic->lock); + } return 1; } @@ -681,20 +707,14 @@ static int as_can_break_anticipation(str return 1; } - ioc = ad->io_context; - BUG_ON(!ioc); - - if (arq && ioc == arq->io_context) { - /* request from same process */ - return 1; - } - aic = ioc->aic; if (!aic) return 0; if (!test_bit(AS_TASK_RUNNING, &aic->state)) { /* process anticipated on has exitted */ + if (aic->ttime_samples == 0) + ad->exit_prob = (7*ad->exit_prob + 256)/8; return 1; } @@ -708,28 +728,36 @@ static int as_can_break_anticipation(str return 1; } - if (ad->new_success < 256 && - (aic->seek_samples == 0 || aic->ttime_samples == 0)) { - /* - * Process has just started IO and we have a bad history of - * success anticipating on new processes! - */ - return 1; - } - - if (aic->ttime_mean > ad->antic_expire) { + if (aic->ttime_samples == 0) { + if (ad->new_ttime_mean > ad->antic_expire) + return 1; + if (ad->exit_prob > 128) + return 1; + } else if (aic->ttime_mean > ad->antic_expire) { /* the process thinks too much between requests */ return 1; } - if (arq && aic->seek_samples) { - sector_t s; - if (ad->last_sector[REQ_SYNC] < arq->request->sector) - s = arq->request->sector - ad->last_sector[REQ_SYNC]; - else - s = ad->last_sector[REQ_SYNC] - arq->request->sector; + if (!arq) + return 0; + + if (ad->last_sector[REQ_SYNC] < arq->request->sector) + s = arq->request->sector - ad->last_sector[REQ_SYNC]; + else + s = ad->last_sector[REQ_SYNC] - arq->request->sector; + + if (aic->seek_samples == 0) { + /* + * Process has just started IO. Use past statistics to + * guage success possibility + */ + if (ad->new_seek_mean/2 > s) { + /* this request is better than what we're expecting */ + return 1; + } - if (aic->seek_mean > (s>>1)) { + } else { + if (aic->seek_mean/2 > s) { /* this request is better than what we're expecting */ return 1; } @@ -774,12 +802,51 @@ static int as_can_anticipate(struct as_d return 1; } +static void as_update_thinktime(struct as_data *ad, struct as_io_context *aic, unsigned long ttime) +{ + /* fixed point: 1.0 == 1<<8 */ + if (aic->ttime_samples == 0) { + ad->new_ttime_total = (7*ad->new_ttime_total + 256*ttime) / 8; + ad->new_ttime_mean = ad->new_ttime_total / 256; + + ad->exit_prob = (7*ad->exit_prob)/8; + } + aic->ttime_samples = (7*aic->ttime_samples + 256) / 8; + aic->ttime_total = (7*aic->ttime_total + 256*ttime) / 8; + aic->ttime_mean = (aic->ttime_total + 128) / aic->ttime_samples; +} + +static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic, sector_t sdist) +{ + u64 total; + + if (aic->seek_samples == 0) { + ad->new_seek_total = (7*ad->new_seek_total + 256*(u64)sdist)/8; + ad->new_seek_mean = ad->new_seek_total / 256; + } + + /* + * Don't allow the seek distance to get too large from the + * odd fragment, pagein, etc + */ + if (aic->seek_samples <= 60) /* second&third seek */ + sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*1024); + else + sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*64); + + aic->seek_samples = (7*aic->seek_samples + 256) / 8; + aic->seek_total = (7*aic->seek_total + (u64)256*sdist) / 8; + total = aic->seek_total + (aic->seek_samples/2); + do_div(total, aic->seek_samples); + aic->seek_mean = (sector_t)total; +} + /* * as_update_iohist keeps a decaying histogram of IO thinktimes, and * updates @aic->ttime_mean based on that. It is called when a new * request is queued. */ -static void as_update_iohist(struct as_io_context *aic, struct request *rq) +static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, struct request *rq) { struct as_rq *arq = RQ_DATA(rq); int data_dir = arq->is_sync; @@ -790,60 +857,29 @@ static void as_update_iohist(struct as_i return; if (data_dir == REQ_SYNC) { + unsigned long in_flight = atomic_read(&aic->nr_queued) + + atomic_read(&aic->nr_dispatched); spin_lock(&aic->lock); - - if (test_bit(AS_TASK_IORUNNING, &aic->state) - && !atomic_read(&aic->nr_queued) - && !atomic_read(&aic->nr_dispatched)) { + if (test_bit(AS_TASK_IORUNNING, &aic->state) || + test_bit(AS_TASK_IOSTARTED, &aic->state)) { /* Calculate read -> read thinktime */ - thinktime = jiffies - aic->last_end_request; - thinktime = min(thinktime, MAX_THINKTIME-1); - /* fixed point: 1.0 == 1<<8 */ - aic->ttime_samples += 256; - aic->ttime_total += 256*thinktime; - if (aic->ttime_samples) - /* fixed point factor is cancelled here */ - aic->ttime_mean = (aic->ttime_total + 128) - / aic->ttime_samples; - aic->ttime_samples = (aic->ttime_samples>>1) - + (aic->ttime_samples>>2); - aic->ttime_total = (aic->ttime_total>>1) - + (aic->ttime_total>>2); - } - - /* Calculate read -> read seek distance */ - if (!aic->seek_samples) - seek_dist = 0; - else if (aic->last_request_pos < rq->sector) - seek_dist = rq->sector - aic->last_request_pos; - else - seek_dist = aic->last_request_pos - rq->sector; - + if (test_bit(AS_TASK_IORUNNING, &aic->state) + && in_flight == 0) { + thinktime = jiffies - aic->last_end_request; + thinktime = min(thinktime, MAX_THINKTIME-1); + } else + thinktime = 0; + as_update_thinktime(ad, aic, thinktime); + + /* Calculate read -> read seek distance */ + if (aic->last_request_pos < rq->sector) + seek_dist = rq->sector - aic->last_request_pos; + else + seek_dist = aic->last_request_pos - rq->sector; + as_update_seekdist(ad, aic, seek_dist); + } aic->last_request_pos = rq->sector + rq->nr_sectors; - - /* - * Don't allow the seek distance to get too large from the - * odd fragment, pagein, etc - */ - if (aic->seek_samples < 400) /* second&third seek */ - seek_dist = min(seek_dist, (aic->seek_mean * 4) - + 2*1024*1024); - else - seek_dist = min(seek_dist, (aic->seek_mean * 4) - + 2*1024*64); - - aic->seek_samples += 256; - aic->seek_total += (u64)256*seek_dist; - if (aic->seek_samples) { - u64 total = aic->seek_total + (aic->seek_samples>>1); - do_div(total, aic->seek_samples); - aic->seek_mean = (sector_t)total; - } - aic->seek_samples = (aic->seek_samples>>1) - + (aic->seek_samples>>2); - aic->seek_total = (aic->seek_total>>1) - + (aic->seek_total>>2); - + set_bit(AS_TASK_IOSTARTED, &aic->state); spin_unlock(&aic->lock); } } @@ -908,15 +944,25 @@ static void as_completed_request(request { struct as_data *ad = q->elevator.elevator_data; struct as_rq *arq = RQ_DATA(rq); - struct as_io_context *aic; WARN_ON(!list_empty(&rq->queuelist)); - if (unlikely(arq->state != AS_RQ_DISPATCHED)) - return; + if (arq->state == AS_RQ_PRESCHED) { + WARN_ON(arq->io_context); + goto out; + } + + if (arq->state == AS_RQ_MERGED) + goto out_ioc; + + if (arq->state != AS_RQ_REMOVED) { + printk("arq->state %d\n", arq->state); + WARN_ON(1); + goto out; + } if (!blk_fs_request(rq)) - return; + goto out; if (ad->changed_batch && ad->nr_dispatched == 1) { kblockd_schedule_work(&ad->antic_work); @@ -940,10 +986,7 @@ static void as_completed_request(request ad->new_batch = 0; } - if (!arq->io_context) - return; - - if (ad->io_context == arq->io_context) { + if (ad->io_context == arq->io_context && ad->io_context) { ad->antic_start = jiffies; ad->ioc_finished = 1; if (ad->antic_status == ANTIC_WAIT_REQ) { @@ -955,18 +998,23 @@ static void as_completed_request(request } } - aic = arq->io_context->aic; - if (!aic) - return; +out_ioc: + if (!arq->io_context) + goto out; - spin_lock(&aic->lock); if (arq->is_sync == REQ_SYNC) { - set_bit(AS_TASK_IORUNNING, &aic->state); - aic->last_end_request = jiffies; + struct as_io_context *aic = arq->io_context->aic; + if (aic) { + spin_lock(&aic->lock); + set_bit(AS_TASK_IORUNNING, &aic->state); + aic->last_end_request = jiffies; + spin_unlock(&aic->lock); + } } - spin_unlock(&aic->lock); put_io_context(arq->io_context); +out: + arq->state = AS_RQ_POSTSCHED; } /* @@ -1035,14 +1083,14 @@ static void as_remove_request(request_qu struct as_rq *arq = RQ_DATA(rq); if (unlikely(arq->state == AS_RQ_NEW)) - return; - - if (!arq) { - WARN_ON(1); - return; - } + goto out; if (ON_RB(&arq->rb_node)) { + if (arq->state != AS_RQ_QUEUED) { + printk("arq->state %d\n", arq->state); + WARN_ON(1); + goto out; + } /* * We'll lose the aliased request(s) here. I don't think this * will ever happen, but if it does, hopefully someone will @@ -1050,8 +1098,16 @@ static void as_remove_request(request_qu */ WARN_ON(!list_empty(&rq->queuelist)); as_remove_queued_request(q, rq); - } else + } else { + if (arq->state != AS_RQ_DISPATCHED) { + printk("arq->state %d\n", arq->state); + WARN_ON(1); + goto out; + } as_remove_dispatched_request(q, rq); + } +out: + arq->state = AS_RQ_REMOVED; } /* @@ -1229,9 +1285,9 @@ static int as_dispatch_request(struct as */ goto dispatch_writes; - if (ad->batch_data_dir == REQ_ASYNC) { + if (ad->batch_data_dir == REQ_ASYNC) { WARN_ON(ad->new_batch); - ad->changed_batch = 1; + ad->changed_batch = 1; } ad->batch_data_dir = REQ_SYNC; arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next); @@ -1247,8 +1303,8 @@ static int as_dispatch_request(struct as dispatch_writes: BUG_ON(RB_EMPTY(&ad->sort_list[REQ_ASYNC])); - if (ad->batch_data_dir == REQ_SYNC) { - ad->changed_batch = 1; + if (ad->batch_data_dir == REQ_SYNC) { + ad->changed_batch = 1; /* * new_batch might be 1 when the queue runs out of @@ -1291,8 +1347,6 @@ fifo_expired: ad->new_batch = 1; ad->changed_batch = 0; - - arq->request->flags |= REQ_SOFTBARRIER; } /* @@ -1369,8 +1423,8 @@ static void as_add_request(struct as_dat arq->io_context = as_get_io_context(); if (arq->io_context) { + as_update_iohist(ad, arq->io_context->aic, arq->request); atomic_inc(&arq->io_context->aic->nr_queued); - as_update_iohist(arq->io_context->aic, arq->request); } alias = as_add_arq_rb(ad, arq); @@ -1391,6 +1445,7 @@ static void as_add_request(struct as_dat } else { as_add_aliased_request(ad, arq, alias); + /* * have we been anticipating this request? * or does it come from the same process as the one we are @@ -1416,6 +1471,11 @@ static void as_requeue_request(request_q struct as_rq *arq = RQ_DATA(rq); if (arq) { + if (arq->state != AS_RQ_REMOVED) { + printk("arq->state %d\n", arq->state); + WARN_ON(1); + } + arq->state = AS_RQ_DISPATCHED; if (arq->io_context && arq->io_context->aic) atomic_inc(&arq->io_context->aic->nr_dispatched); @@ -1427,8 +1487,6 @@ static void as_requeue_request(request_q /* Stop anticipating - let this request get through */ as_antic_stop(ad); - - return; } static void @@ -1437,10 +1495,20 @@ as_insert_request(request_queue_t *q, st struct as_data *ad = q->elevator.elevator_data; struct as_rq *arq = RQ_DATA(rq); + if (arq) { + if (arq->state != AS_RQ_PRESCHED) { + printk("arq->state: %d\n", arq->state); + WARN_ON(1); + } + arq->state = AS_RQ_NEW; + } + /* barriers must flush the reorder queue */ if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) + && where == ELEVATOR_INSERT_SORT)) { + WARN_ON(1); where = ELEVATOR_INSERT_BACK; + } switch (where) { case ELEVATOR_INSERT_BACK: @@ -1675,7 +1743,8 @@ as_merged_requests(request_queue_t *q, s * kill knowledge of next, this one is a goner */ as_remove_queued_request(q, next); - put_io_context(anext->io_context); + + anext->state = AS_RQ_MERGED; } /* @@ -1708,6 +1777,11 @@ static void as_put_request(request_queue return; } + if (arq->state != AS_RQ_POSTSCHED && arq->state != AS_RQ_PRESCHED) { + printk("arq->state %d\n", arq->state); + WARN_ON(1); + } + mempool_free(arq, ad->arq_pool); rq->elevator_private = NULL; } @@ -1721,7 +1795,7 @@ static int as_set_request(request_queue_ memset(arq, 0, sizeof(*arq)); RB_CLEAR(&arq->rb_node); arq->request = rq; - arq->state = AS_RQ_NEW; + arq->state = AS_RQ_PRESCHED; arq->io_context = NULL; INIT_LIST_HEAD(&arq->hash); arq->on_hash = 0; @@ -1823,8 +1897,6 @@ static int as_init(request_queue_t *q, e if (ad->write_batch_count < 2) ad->write_batch_count = 2; - ad->new_success = 512; - return 0; } @@ -1860,6 +1932,17 @@ as_var_store(unsigned long *var, const c return count; } +static ssize_t as_est_show(struct as_data *ad, char *page) +{ + int pos = 0; + + pos += sprintf(page+pos, "%lu %% exit probability\n", 100*ad->exit_prob/256); + pos += sprintf(page+pos, "%lu ms new thinktime\n", ad->new_ttime_mean); + pos += sprintf(page+pos, "%llu sectors new seek distance\n", (unsigned long long)ad->new_seek_mean); + + return pos; +} + #define SHOW_FUNCTION(__FUNC, __VAR) \ static ssize_t __FUNC(struct as_data *ad, char *page) \ { \ @@ -1891,6 +1974,10 @@ STORE_FUNCTION(as_write_batchexpire_stor &ad->batch_expire[REQ_ASYNC], 0, INT_MAX); #undef STORE_FUNCTION +static struct as_fs_entry as_est_entry = { + .attr = {.name = "est_time", .mode = S_IRUGO }, + .show = as_est_show, +}; static struct as_fs_entry as_readexpire_entry = { .attr = {.name = "read_expire", .mode = S_IRUGO | S_IWUSR }, .show = as_readexpire_show, @@ -1918,6 +2005,7 @@ static struct as_fs_entry as_write_batch }; static struct attribute *default_attrs[] = { + &as_est_entry.attr, &as_readexpire_entry.attr, &as_writeexpire_entry.attr, &as_anticexpire_entry.attr, --- linux-2.6.1-rc1/drivers/block/ataflop.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/ataflop.c 2003-12-30 22:49:33.000000000 -0800 @@ -364,13 +364,12 @@ static void finish_fdc_done( int dummy ) static __inline__ void copy_buffer( void *from, void *to); static void setup_req_params( int drive ); static void redo_fd_request( void); -static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param); static void fd_probe( int drive ); static int fd_test_drive_present( int drive ); static void config_types( void ); -static int floppy_open( struct inode *inode, struct file *filp ); -static int floppy_release( struct inode * inode, struct file * filp ); +static int floppy_open(struct block_device *bdev, struct file *filp ); /************************* End of Prototypes **************************/ @@ -1496,10 +1495,10 @@ void do_fd_request(request_queue_t * q) atari_enable_irq( IRQ_MFP_FDC ); } -static int fd_ioctl(struct inode *inode, struct file *filp, +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct atari_floppy_struct *floppy = disk->private_data; int drive = floppy - unit; int type = floppy->type; @@ -1673,7 +1672,7 @@ static int fd_ioctl(struct inode *inode, /* invalidate the buffer track to force a reread */ BufferDrive = -1; set_bit(drive, &fake_change); - check_disk_change(inode->i_bdev); + check_disk_change(bdev); return 0; default: return -EINVAL; @@ -1816,10 +1815,10 @@ static void __init config_types( void ) * drive with different device numbers. */ -static int floppy_open( struct inode *inode, struct file *filp ) +static int floppy_open(struct block_device *bdev, struct file *filp ) { - struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data; - int type = iminor(inode) >> 2; + struct atari_floppy_struct *p = bdev->bd_disk->private_data; + int type = MINOR(bdev->bd_dev) >> 2; DPRINT(("fd_open: type=%d\n",type)); if (p->ref && p->type != type) @@ -1839,14 +1838,13 @@ static int floppy_open( struct inode *in return 0; if (filp->f_mode & 3) { - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (filp->f_mode & 2) { if (p->wpstat) { if (p->ref < 0) p->ref = 0; else p->ref--; - floppy_release(inode, filp); return -EROFS; } } @@ -1855,9 +1853,9 @@ static int floppy_open( struct inode *in } -static int floppy_release( struct inode * inode, struct file * filp ) +static int floppy_release(struct gendisk *disk) { - struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data; + struct atari_floppy_struct *p = disk->private_data; if (p->ref < 0) p->ref = 0; else if (!p->ref--) { --- linux-2.6.1-rc1/drivers/block/cciss.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/cciss.c 2003-12-30 22:49:33.000000000 -0800 @@ -112,9 +112,9 @@ static struct board_type products[] = { static ctlr_info_t *hba[MAX_CTLR]; static void do_cciss_request(request_queue_t *q); -static int cciss_open(struct inode *inode, struct file *filep); -static int cciss_release(struct inode *inode, struct file *filep); -static int cciss_ioctl(struct inode *inode, struct file *filep, +static int cciss_open(struct block_device *bdev, struct file *filep); +static int cciss_release(struct gendisk *disk); +static int cciss_ioctl(struct block_device *bdev, struct file *filep, unsigned int cmd, unsigned long arg); static int revalidate_allvol(ctlr_info_t *host); @@ -362,13 +362,13 @@ static inline drive_info_struct *get_drv /* * Open. Make sure the device is really there. */ -static int cciss_open(struct inode *inode, struct file *filep) +static int cciss_open(struct block_device *bdev, struct file *filep) { - ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); - drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk); + ctlr_info_t *host = get_host(bdev->bd_disk); + drive_info_struct *drv = get_drv(bdev->bd_disk); #ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name); + printk(KERN_DEBUG "cciss_open %s\n", bdev->bd_disk->disk_name); #endif /* CCISS_DEBUG */ /* @@ -378,7 +378,7 @@ static int cciss_open(struct inode *inod * for "raw controller". */ if (drv->nr_blocks == 0) { - if (iminor(inode) != 0) + if (bdev != bdev->bd_contains || drv != host->drv) return -ENXIO; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -390,13 +390,13 @@ static int cciss_open(struct inode *inod /* * Close. Sync first. */ -static int cciss_release(struct inode *inode, struct file *filep) +static int cciss_release(struct gendisk *disk) { - ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); - drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk); + ctlr_info_t *host = get_host(disk); + drive_info_struct *drv = get_drv(disk); #ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name); + printk(KERN_DEBUG "cciss_release %s\n", disk->disk_name); #endif /* CCISS_DEBUG */ drv->usage_count--; @@ -407,10 +407,9 @@ static int cciss_release(struct inode *i /* * ioctl */ -static int cciss_ioctl(struct inode *inode, struct file *filep, +static int cciss_ioctl(struct block_device *bdev, struct file *filep, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; struct gendisk *disk = bdev->bd_disk; ctlr_info_t *host = get_host(disk); drive_info_struct *drv = get_drv(disk); @@ -433,7 +432,7 @@ static int cciss_ioctl(struct inode *ino driver_geo.sectors = 0x3f; driver_geo.cylinders = (int)drv->nr_blocks / (0xff*0x3f); } - driver_geo.start= get_start_sect(inode->i_bdev); + driver_geo.start= get_start_sect(bdev); if (copy_to_user((void *) arg, &driver_geo, sizeof( struct hd_geometry))) return -EFAULT; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/block/cfq-iosched.c 2003-12-30 22:49:43.000000000 -0800 @@ -0,0 +1,707 @@ +/* + * linux/drivers/block/cfq-iosched.c + * + * CFQ, or complete fairness queueing, disk scheduler. + * + * Based on ideas from a previously unfinished io + * scheduler (round robin per-process disk scheduling) and Andrea Arcangeli. + * + * Copyright (C) 2003 Jens Axboe + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * tunables + */ +static int cfq_quantum = 4; +static int cfq_queued = 8; + +#define CFQ_QHASH_SHIFT 6 +#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) +#define list_entry_qhash(entry) list_entry((entry), struct cfq_queue, cfq_hash) + +#define CFQ_MHASH_SHIFT 8 +#define CFQ_MHASH_BLOCK(sec) ((sec) >> 3) +#define CFQ_MHASH_ENTRIES (1 << CFQ_MHASH_SHIFT) +#define CFQ_MHASH_FN(sec) (hash_long(CFQ_MHASH_BLOCK((sec)),CFQ_MHASH_SHIFT)) +#define ON_MHASH(crq) !list_empty(&(crq)->hash) +#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) +#define list_entry_hash(ptr) list_entry((ptr), struct cfq_rq, hash) + +#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list) + +#define RQ_DATA(rq) ((struct cfq_rq *) (rq)->elevator_private) + +static kmem_cache_t *crq_pool; +static kmem_cache_t *cfq_pool; +static mempool_t *cfq_mpool; + +struct cfq_data { + struct list_head rr_list; + struct list_head *dispatch; + struct list_head *cfq_hash; + + struct list_head *crq_hash; + + unsigned int busy_queues; + unsigned int max_queued; + + mempool_t *crq_pool; +}; + +struct cfq_queue { + struct list_head cfq_hash; + struct list_head cfq_list; + struct rb_root sort_list; + int pid; + int queued[2]; +#if 0 + /* + * with a simple addition like this, we can do io priorities. almost. + * does need a split request free list, too. + */ + int io_prio +#endif +}; + +struct cfq_rq { + struct rb_node rb_node; + sector_t rb_key; + + struct request *request; + + struct cfq_queue *cfq_queue; + + struct list_head hash; +}; + +static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq); +static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid); +static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq); + +/* + * lots of deadline iosched dupes, can be abstracted later... + */ +static inline void __cfq_del_crq_hash(struct cfq_rq *crq) +{ + list_del_init(&crq->hash); +} + +static inline void cfq_del_crq_hash(struct cfq_rq *crq) +{ + if (ON_MHASH(crq)) + __cfq_del_crq_hash(crq); +} + +static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq) +{ + cfq_del_crq_hash(crq); + + if (q->last_merge == crq->request) + q->last_merge = NULL; +} + +static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) +{ + struct request *rq = crq->request; + + BUG_ON(ON_MHASH(crq)); + + list_add(&crq->hash, &cfqd->crq_hash[CFQ_MHASH_FN(rq_hash_key(rq))]); +} + +static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) +{ + struct list_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)]; + struct list_head *entry, *next = hash_list->next; + + while ((entry = next) != hash_list) { + struct cfq_rq *crq = list_entry_hash(entry); + struct request *__rq = crq->request; + + next = entry->next; + + BUG_ON(!ON_MHASH(crq)); + + if (!rq_mergeable(__rq)) { + __cfq_del_crq_hash(crq); + continue; + } + + if (rq_hash_key(__rq) == offset) + return __rq; + } + + return NULL; +} + +/* + * rb tree support functions + */ +#define RB_NONE (2) +#define RB_EMPTY(node) ((node)->rb_node == NULL) +#define RB_CLEAR(node) ((node)->rb_color = RB_NONE) +#define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) +#define ON_RB(node) ((node)->rb_color != RB_NONE) +#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) +#define rq_rb_key(rq) (rq)->sector + +static inline void cfq_del_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) +{ + if (ON_RB(&crq->rb_node)) { + cfqq->queued[rq_data_dir(crq->request)]--; + rb_erase(&crq->rb_node, &cfqq->sort_list); + crq->cfq_queue = NULL; + } +} + +static struct cfq_rq * +__cfq_add_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) +{ + struct rb_node **p = &cfqq->sort_list.rb_node; + struct rb_node *parent = NULL; + struct cfq_rq *__crq; + + while (*p) { + parent = *p; + __crq = rb_entry_crq(parent); + + if (crq->rb_key < __crq->rb_key) + p = &(*p)->rb_left; + else if (crq->rb_key > __crq->rb_key) + p = &(*p)->rb_right; + else + return __crq; + } + + rb_link_node(&crq->rb_node, parent, p); + return 0; +} + +static void +cfq_add_crq_rb(struct cfq_data *cfqd, struct cfq_queue *cfqq,struct cfq_rq *crq) +{ + struct request *rq = crq->request; + struct cfq_rq *__alias; + + crq->rb_key = rq_rb_key(rq); + cfqq->queued[rq_data_dir(rq)]++; +retry: + __alias = __cfq_add_crq_rb(cfqq, crq); + if (!__alias) { + rb_insert_color(&crq->rb_node, &cfqq->sort_list); + crq->cfq_queue = cfqq; + return; + } + + cfq_del_crq_rb(cfqq, __alias); + cfq_dispatch_sort(cfqd->dispatch, __alias); + goto retry; +} + +static struct request * +cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector) +{ + struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->tgid); + struct rb_node *n; + + if (!cfqq) + goto out; + + n = cfqq->sort_list.rb_node; + while (n) { + struct cfq_rq *crq = rb_entry_crq(n); + + if (sector < crq->rb_key) + n = n->rb_left; + else if (sector > crq->rb_key) + n = n->rb_right; + else + return crq->request; + } + +out: + return NULL; +} + +static void cfq_remove_request(request_queue_t *q, struct request *rq) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct cfq_rq *crq = RQ_DATA(rq); + + if (crq) { + struct cfq_queue *cfqq = crq->cfq_queue; + + cfq_remove_merge_hints(q, crq); + list_del_init(&rq->queuelist); + + if (cfqq) { + cfq_del_crq_rb(cfqq, crq); + + if (RB_EMPTY(&cfqq->sort_list)) + cfq_put_queue(cfqd, cfqq); + } + } +} + +static int +cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct request *__rq; + int ret; + + ret = elv_try_last_merge(q, bio); + if (ret != ELEVATOR_NO_MERGE) { + __rq = q->last_merge; + goto out_insert; + } + + __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); + if (__rq) { + BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); + + if (elv_rq_merge_ok(__rq, bio)) { + ret = ELEVATOR_BACK_MERGE; + goto out; + } + } + + __rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio)); + if (__rq) { + if (elv_rq_merge_ok(__rq, bio)) { + ret = ELEVATOR_FRONT_MERGE; + goto out; + } + } + + return ELEVATOR_NO_MERGE; +out: + q->last_merge = __rq; +out_insert: + *req = __rq; + return ret; +} + +static void cfq_merged_request(request_queue_t *q, struct request *req) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct cfq_rq *crq = RQ_DATA(req); + + cfq_del_crq_hash(crq); + cfq_add_crq_hash(cfqd, crq); + + if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) { + struct cfq_queue *cfqq = crq->cfq_queue; + + cfq_del_crq_rb(cfqq, crq); + cfq_add_crq_rb(cfqd, cfqq, crq); + } + + q->last_merge = req; +} + +static void +cfq_merged_requests(request_queue_t *q, struct request *req, + struct request *next) +{ + cfq_merged_request(q, req); + cfq_remove_request(q, next); +} + +static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq) +{ + struct list_head *entry = head; + struct request *__rq; + + if (!list_empty(head)) { + __rq = list_entry_rq(head->next); + + if (crq->request->sector < __rq->sector) { + entry = head->prev; + goto link; + } + } + + while ((entry = entry->prev) != head) { + __rq = list_entry_rq(entry); + + if (crq->request->sector <= __rq->sector) + break; + } + +link: + list_add_tail(&crq->request->queuelist, entry); +} + +static inline void +__cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd, + struct cfq_queue *cfqq) +{ + struct cfq_rq *crq = rb_entry_crq(rb_first(&cfqq->sort_list)); + + cfq_del_crq_rb(cfqq, crq); + cfq_remove_merge_hints(q, crq); + cfq_dispatch_sort(cfqd->dispatch, crq); +} + +static int cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd) +{ + struct cfq_queue *cfqq; + struct list_head *entry, *tmp; + int ret, queued, good_queues; + + if (list_empty(&cfqd->rr_list)) + return 0; + + queued = ret = 0; +restart: + good_queues = 0; + list_for_each_safe(entry, tmp, &cfqd->rr_list) { + cfqq = list_entry_cfqq(cfqd->rr_list.next); + + BUG_ON(RB_EMPTY(&cfqq->sort_list)); + + __cfq_dispatch_requests(q, cfqd, cfqq); + + if (RB_EMPTY(&cfqq->sort_list)) + cfq_put_queue(cfqd, cfqq); + else + good_queues++; + + queued++; + ret = 1; + } + + if ((queued < cfq_quantum) && good_queues) + goto restart; + + return ret; +} + +static struct request *cfq_next_request(request_queue_t *q) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct request *rq; + + if (!list_empty(cfqd->dispatch)) { + struct cfq_rq *crq; +dispatch: + rq = list_entry_rq(cfqd->dispatch->next); + + BUG_ON(q->last_merge == rq); + crq = RQ_DATA(rq); + if (crq) + BUG_ON(ON_MHASH(crq)); + + return rq; + } + + if (cfq_dispatch_requests(q, cfqd)) + goto dispatch; + + return NULL; +} + +static inline struct cfq_queue * +__cfq_find_cfq_hash(struct cfq_data *cfqd, int pid, const int hashval) +{ + struct list_head *hash_list = &cfqd->cfq_hash[hashval]; + struct list_head *entry; + + list_for_each(entry, hash_list) { + struct cfq_queue *__cfqq = list_entry_qhash(entry); + + if (__cfqq->pid == pid) + return __cfqq; + } + + return NULL; +} + +static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid) +{ + const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT); + + return __cfq_find_cfq_hash(cfqd, pid, hashval); +} + +static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) +{ + cfqd->busy_queues--; + list_del(&cfqq->cfq_list); + list_del(&cfqq->cfq_hash); + mempool_free(cfqq, cfq_mpool); +} + +static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, int pid) +{ + const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT); + struct cfq_queue *cfqq = __cfq_find_cfq_hash(cfqd, pid, hashval); + + if (!cfqq) { + cfqq = mempool_alloc(cfq_mpool, GFP_NOIO); + + INIT_LIST_HEAD(&cfqq->cfq_hash); + INIT_LIST_HEAD(&cfqq->cfq_list); + RB_CLEAR_ROOT(&cfqq->sort_list); + + cfqq->pid = pid; + cfqq->queued[0] = cfqq->queued[1] = 0; + list_add(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]); + } + + return cfqq; +} + +static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq) +{ + struct cfq_queue *cfqq; + + cfqq = cfq_get_queue(cfqd, current->tgid); + + cfq_add_crq_rb(cfqd, cfqq, crq); + + if (list_empty(&cfqq->cfq_list)) { + list_add(&cfqq->cfq_list, &cfqd->rr_list); + cfqd->busy_queues++; + } +} + +static void +cfq_insert_request(request_queue_t *q, struct request *rq, int where) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct cfq_rq *crq = RQ_DATA(rq); + + switch (where) { + case ELEVATOR_INSERT_BACK: + while (cfq_dispatch_requests(q, cfqd)) + ; + list_add_tail(&rq->queuelist, cfqd->dispatch); + break; + case ELEVATOR_INSERT_FRONT: + list_add(&rq->queuelist, cfqd->dispatch); + break; + case ELEVATOR_INSERT_SORT: + BUG_ON(!blk_fs_request(rq)); + cfq_enqueue(cfqd, crq); + break; + default: + printk("%s: bad insert point %d\n", __FUNCTION__,where); + return; + } + + if (rq_mergeable(rq)) { + cfq_add_crq_hash(cfqd, crq); + + if (!q->last_merge) + q->last_merge = rq; + } +} + +static int cfq_queue_empty(request_queue_t *q) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + + if (list_empty(cfqd->dispatch) && list_empty(&cfqd->rr_list)) + return 1; + + return 0; +} + +static struct request * +cfq_former_request(request_queue_t *q, struct request *rq) +{ + struct cfq_rq *crq = RQ_DATA(rq); + struct rb_node *rbprev = rb_prev(&crq->rb_node); + + if (rbprev) + return rb_entry_crq(rbprev)->request; + + return NULL; +} + +static struct request * +cfq_latter_request(request_queue_t *q, struct request *rq) +{ + struct cfq_rq *crq = RQ_DATA(rq); + struct rb_node *rbnext = rb_next(&crq->rb_node); + + if (rbnext) + return rb_entry_crq(rbnext)->request; + + return NULL; +} + +static int cfq_may_queue(request_queue_t *q, int rw) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct cfq_queue *cfqq; + int ret = 1; + + if (!cfqd->busy_queues) + goto out; + + cfqq = cfq_find_cfq_hash(cfqd, current->tgid); + if (cfqq) { + int limit = (q->nr_requests - cfq_queued) / cfqd->busy_queues; + + if (limit < 3) + limit = 3; + else if (limit > cfqd->max_queued) + limit = cfqd->max_queued; + + if (cfqq->queued[rw] > limit) + ret = 0; + } +out: + return ret; +} + +static void cfq_put_request(request_queue_t *q, struct request *rq) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct cfq_rq *crq = RQ_DATA(rq); + + if (crq) { + BUG_ON(q->last_merge == rq); + BUG_ON(ON_MHASH(crq)); + + mempool_free(crq, cfqd->crq_pool); + rq->elevator_private = NULL; + } +} + +static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask) +{ + struct cfq_data *cfqd = q->elevator.elevator_data; + struct cfq_rq *crq = mempool_alloc(cfqd->crq_pool, gfp_mask); + + if (crq) { + RB_CLEAR(&crq->rb_node); + crq->request = rq; + crq->cfq_queue = NULL; + INIT_LIST_HEAD(&crq->hash); + rq->elevator_private = crq; + return 0; + } + + return 1; +} + +static void cfq_exit(request_queue_t *q, elevator_t *e) +{ + struct cfq_data *cfqd = e->elevator_data; + + e->elevator_data = NULL; + mempool_destroy(cfqd->crq_pool); + kfree(cfqd->crq_hash); + kfree(cfqd->cfq_hash); + kfree(cfqd); +} + +static int cfq_init(request_queue_t *q, elevator_t *e) +{ + struct cfq_data *cfqd; + int i; + + cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL); + if (!cfqd) + return -ENOMEM; + + memset(cfqd, 0, sizeof(*cfqd)); + INIT_LIST_HEAD(&cfqd->rr_list); + + cfqd->crq_hash = kmalloc(sizeof(struct list_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); + if (!cfqd->crq_hash) + goto out_crqhash; + + cfqd->cfq_hash = kmalloc(sizeof(struct list_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL); + if (!cfqd->cfq_hash) + goto out_cfqhash; + + cfqd->crq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, crq_pool); + if (!cfqd->crq_pool) + goto out_crqpool; + + for (i = 0; i < CFQ_MHASH_ENTRIES; i++) + INIT_LIST_HEAD(&cfqd->crq_hash[i]); + for (i = 0; i < CFQ_QHASH_ENTRIES; i++) + INIT_LIST_HEAD(&cfqd->cfq_hash[i]); + + cfqd->dispatch = &q->queue_head; + e->elevator_data = cfqd; + + /* + * just set it to some high value, we want anyone to be able to queue + * some requests. fairness is handled differently + */ + cfqd->max_queued = q->nr_requests; + q->nr_requests = 8192; + + return 0; +out_crqpool: + kfree(cfqd->cfq_hash); +out_cfqhash: + kfree(cfqd->crq_hash); +out_crqhash: + kfree(cfqd); + return -ENOMEM; +} + +static int __init cfq_slab_setup(void) +{ + crq_pool = kmem_cache_create("crq_pool", sizeof(struct cfq_rq), 0, 0, + NULL, NULL); + + if (!crq_pool) + panic("cfq_iosched: can't init crq pool\n"); + + cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0, + NULL, NULL); + + if (!cfq_pool) + panic("cfq_iosched: can't init cfq pool\n"); + + cfq_mpool = mempool_create(64, mempool_alloc_slab, mempool_free_slab, cfq_pool); + + if (!cfq_mpool) + panic("cfq_iosched: can't init cfq mpool\n"); + + return 0; +} + +subsys_initcall(cfq_slab_setup); + +elevator_t iosched_cfq = { + .elevator_name = "cfq", + .elevator_merge_fn = cfq_merge, + .elevator_merged_fn = cfq_merged_request, + .elevator_merge_req_fn = cfq_merged_requests, + .elevator_next_req_fn = cfq_next_request, + .elevator_add_req_fn = cfq_insert_request, + .elevator_remove_req_fn = cfq_remove_request, + .elevator_queue_empty_fn = cfq_queue_empty, + .elevator_former_req_fn = cfq_former_request, + .elevator_latter_req_fn = cfq_latter_request, + .elevator_set_req_fn = cfq_set_request, + .elevator_put_req_fn = cfq_put_request, + .elevator_may_queue_fn = cfq_may_queue, + .elevator_init_fn = cfq_init, + .elevator_exit_fn = cfq_exit, +}; + +EXPORT_SYMBOL(iosched_cfq); --- linux-2.6.1-rc1/drivers/block/cpqarray.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/cpqarray.c 2003-12-30 22:49:33.000000000 -0800 @@ -128,9 +128,9 @@ static int sendcmd( unsigned int blkcnt, unsigned int log_unit ); -static int ida_open(struct inode *inode, struct file *filep); -static int ida_release(struct inode *inode, struct file *filep); -static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int ida_open(struct block_device *bdev, struct file *filep); +static int ida_release(struct gendisk *disk); +static int ida_ioctl(struct block_device *bdev, struct file *filep, unsigned int cmd, unsigned long arg); static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io); static void do_ida_request(request_queue_t *q); @@ -715,12 +715,12 @@ DBGINFO( /* * Open. Make sure the device is really there. */ -static int ida_open(struct inode *inode, struct file *filep) +static int ida_open(struct block_device *bdev, struct file *filep) { - drv_info_t *drv = get_drv(inode->i_bdev->bd_disk); - ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); + drv_info_t *drv = get_drv(bdev->bd_disk); + ctlr_info_t *host = get_host(bdev->bd_disk); - DBGINFO(printk("ida_open %s\n", inode->i_bdev->bd_disk->disk_name)); + DBGINFO(printk("ida_open %s\n", bdev->bd_disk->disk_name)); /* * Root is allowed to open raw volume zero even if it's not configured * so array config can still work. I don't think I really like this, @@ -740,9 +740,9 @@ static int ida_open(struct inode *inode, /* * Close. Sync first. */ -static int ida_release(struct inode *inode, struct file *filep) +static int ida_release(struct gendisk *disk) { - ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); + ctlr_info_t *host = get_host(disk); host->usage_count--; return 0; } @@ -1022,10 +1022,10 @@ static void ida_timer(unsigned long tdat * ida_ioctl does some miscellaneous stuff like reporting drive geometry, * setting readahead and submitting commands from userspace to the controller. */ -static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) +static int ida_ioctl(struct block_device *bdev, struct file *filep, unsigned int cmd, unsigned long arg) { - drv_info_t *drv = get_drv(inode->i_bdev->bd_disk); - ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); + drv_info_t *drv = get_drv(bdev->bd_disk); + ctlr_info_t *host = get_host(bdev->bd_disk); int error; int diskinfo[4]; struct hd_geometry *geo = (struct hd_geometry *)arg; @@ -1046,7 +1046,7 @@ static int ida_ioctl(struct inode *inode put_user(diskinfo[0], &geo->heads); put_user(diskinfo[1], &geo->sectors); put_user(diskinfo[2], &geo->cylinders); - put_user(get_start_sect(inode->i_bdev), &geo->start); + put_user(get_start_sect(bdev), &geo->start); return 0; case IDAGETDRVINFO: if (copy_to_user(&io->c.drv, drv, sizeof(drv_info_t))) @@ -1076,7 +1076,7 @@ out_passthru: put_user(host->ctlr_sig, (int*)arg); return 0; case IDAREVALIDATEVOLS: - if (iminor(inode) != 0) + if (bdev != bdev->bd_contains || drv != host->drv) return -ENXIO; return revalidate_allvol(host); case IDADRIVERVERSION: --- linux-2.6.1-rc1/drivers/block/cryptoloop.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/cryptoloop.c 2003-12-30 22:49:51.000000000 -0800 @@ -87,43 +87,49 @@ typedef int (*encdec_ecb_t)(struct crypt static int -cryptoloop_transfer_ecb(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t IV) +cryptoloop_transfer_ecb(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; struct scatterlist sg_out = { 0, }; struct scatterlist sg_in = { 0, }; encdec_ecb_t encdecfunc; - char const *in; - char *out; + struct page *in_page, *out_page; + unsigned in_offs, out_offs; if (cmd == READ) { - in = raw_buf; - out = loop_buf; + in_page = raw_page; + in_offs = raw_off; + out_page = loop_page; + out_offs = loop_off; encdecfunc = tfm->crt_u.cipher.cit_decrypt; } else { - in = loop_buf; - out = raw_buf; + in_page = loop_page; + in_offs = loop_off; + out_page = raw_page; + out_offs = raw_off; encdecfunc = tfm->crt_u.cipher.cit_encrypt; } while (size > 0) { const int sz = min(size, LOOP_IV_SECTOR_SIZE); - sg_in.page = virt_to_page(in); - sg_in.offset = (unsigned long)in & ~PAGE_MASK; + sg_in.page = in_page; + sg_in.offset = in_offs; sg_in.length = sz; - sg_out.page = virt_to_page(out); - sg_out.offset = (unsigned long)out & ~PAGE_MASK; + sg_out.page = out_page; + sg_out.offset = out_offs; sg_out.length = sz; encdecfunc(tfm, &sg_out, &sg_in, sz); size -= sz; - in += sz; - out += sz; + in_offs += sz; + out_offs += sz; } return 0; @@ -135,24 +141,30 @@ typedef int (*encdec_cbc_t)(struct crypt unsigned int nsg, u8 *iv); static int -cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t IV) +cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; struct scatterlist sg_out = { 0, }; struct scatterlist sg_in = { 0, }; encdec_cbc_t encdecfunc; - char const *in; - char *out; + struct page *in_page, *out_page; + unsigned in_offs, out_offs; if (cmd == READ) { - in = raw_buf; - out = loop_buf; + in_page = raw_page; + in_offs = raw_off; + out_page = loop_page; + out_offs = loop_off; encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv; } else { - in = loop_buf; - out = raw_buf; + in_page = loop_page; + in_offs = loop_off; + out_page = raw_page; + out_offs = raw_off; encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv; } @@ -161,39 +173,43 @@ cryptoloop_transfer_cbc(struct loop_devi u32 iv[4] = { 0, }; iv[0] = cpu_to_le32(IV & 0xffffffff); - sg_in.page = virt_to_page(in); - sg_in.offset = offset_in_page(in); + sg_in.page = in_page; + sg_in.offset = in_offs; sg_in.length = sz; - sg_out.page = virt_to_page(out); - sg_out.offset = offset_in_page(out); + sg_out.page = out_page; + sg_out.offset = out_offs; sg_out.length = sz; encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv); IV++; size -= sz; - in += sz; - out += sz; + in_offs += sz; + out_offs += sz; } return 0; } static int -cryptoloop_transfer(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t IV) +cryptoloop_transfer(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB) { lo->transfer = cryptoloop_transfer_ecb; - return cryptoloop_transfer_ecb(lo, cmd, raw_buf, loop_buf, size, IV); + return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off, + loop_page, loop_off, size, IV); } if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC) { lo->transfer = cryptoloop_transfer_cbc; - return cryptoloop_transfer_cbc(lo, cmd, raw_buf, loop_buf, size, IV); + return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off, + loop_page, loop_off, size, IV); } /* This is not supposed to happen */ --- linux-2.6.1-rc1/drivers/block/DAC960.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/drivers/block/DAC960.c 2003-12-30 22:49:31.000000000 -0800 @@ -67,9 +67,9 @@ static long disk_size(DAC960_Controller_ } } -static int DAC960_open(struct inode *inode, struct file *file) +static int DAC960_open(struct block_device *bdev, struct file *file) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; DAC960_Controller_T *p = disk->queue->queuedata; int drive_nr = (long)disk->private_data; @@ -84,17 +84,17 @@ static int DAC960_open(struct inode *ino return -ENXIO; } - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (!get_capacity(p->disks[drive_nr])) return -ENXIO; return 0; } -static int DAC960_ioctl(struct inode *inode, struct file *file, +static int DAC960_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; DAC960_Controller_T *p = disk->queue->queuedata; int drive_nr = (long)disk->private_data; struct hd_geometry g, *loc = (struct hd_geometry *)arg; @@ -128,7 +128,7 @@ static int DAC960_ioctl(struct inode *in g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors); } - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } --- linux-2.6.1-rc1/drivers/block/floppy98.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/block/floppy98.c 2003-12-30 22:49:33.000000000 -0800 @@ -3484,14 +3484,14 @@ static int get_floppy_geometry(int drive return 0; } -static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { #define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data) #define OUT(c,x) case c: outparam = (const char *) (x); break #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0 - int drive = (long)inode->i_bdev->bd_disk->private_data; + int drive = (long)bdev->bd_disk->private_data; int i, type = ITYPE(UDRS->fd_device); int ret; int size; @@ -3566,11 +3566,11 @@ static int fd_ioctl(struct inode *inode, current_type[drive] = NULL; floppy_sizes[drive] = MAX_DISK_SIZE << 1; UDRS->keep_data = 0; - return invalidate_drive(inode->i_bdev); + return invalidate_drive(bdev); case FDSETPRM: case FDDEFPRM: return set_geometry(cmd, & inparam.g, - drive, type, inode->i_bdev); + drive, type, bdev); case FDGETPRM: ECALL(get_floppy_geometry(drive, type, (struct floppy_struct**) @@ -3625,7 +3625,7 @@ static int fd_ioctl(struct inode *inode, case FDFMTEND: case FDFLUSH: LOCK_FDC(drive,1); - return invalidate_drive(inode->i_bdev); + return invalidate_drive(bdev); case FDSETEMSGTRESH: UDP->max_errors.reporting = @@ -3735,9 +3735,9 @@ static void __init config_types(void) printk("\n"); } -static int floppy_release(struct inode * inode, struct file * filp) +static int floppy_release(struct gendisk *disk) { - int drive = (long)inode->i_bdev->bd_disk->private_data; + int drive = (long)disk->private_data; down(&open_lock); if (UDRS->fd_ref < 0) @@ -3758,11 +3758,10 @@ static int floppy_release(struct inode * * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */ -#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0) -static int floppy_open(struct inode * inode, struct file * filp) +static int floppy_open(struct block_device *bdev, struct file *filp) { - int drive = (long)inode->i_bdev->bd_disk->private_data; + int drive = (long)bdev->bd_disk->private_data; int old_dev; int try; int res = -EBUSY; @@ -3789,7 +3788,7 @@ static int floppy_open(struct inode * in down(&open_lock); old_dev = UDRS->fd_device; - if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev) + if (opened_bdev[drive] && opened_bdev[drive] != bdev) goto out2; if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){ @@ -3809,7 +3808,7 @@ static int floppy_open(struct inode * in else UDRS->fd_ref++; - opened_bdev[drive] = inode->i_bdev; + opened_bdev[drive] = bdev; res = -ENXIO; @@ -3844,9 +3843,9 @@ static int floppy_open(struct inode * in } } - UDRS->fd_device = iminor(inode); - set_capacity(disks[drive], floppy_sizes[iminor(inode)]); - if (old_dev != -1 && old_dev != iminor(inode)) { + UDRS->fd_device = MINOR(bdev->bd_dev); + set_capacity(disks[drive], floppy_sizes[MINOR(bdev->bd_dev)]); + if (old_dev != -1 && old_dev != MINOR(bdev->bd_dev)) { if (buffer_drive == drive) buffer_track = -1; } @@ -3859,8 +3858,7 @@ static int floppy_open(struct inode * in /* Allow ioctls if we have write-permissions even if read-only open. * Needed so that programs such as fdrawcmd still can work on write * protected disks */ - if ((filp->f_mode & 2) || - (inode->i_sb && (permission(inode,2) == 0))) + if ((filp->f_mode & 2) || permission(filp->f_dentry->d_inode,2) == 0) filp->private_data = (void*) 8; if (UFDCS->rawcmd == 1) @@ -3873,7 +3871,7 @@ static int floppy_open(struct inode * in if (!(filp->f_flags & O_NDELAY)) { if (filp->f_mode & 3) { UDRS->last_checked = 0; - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (UTESTF(FD_DISK_CHANGED)) goto out; } --- linux-2.6.1-rc1/drivers/block/floppy.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/block/floppy.c 2003-12-30 22:49:33.000000000 -0800 @@ -3456,14 +3456,14 @@ static int get_floppy_geometry(int drive return 0; } -static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, +static int fd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { #define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data) #define OUT(c,x) case c: outparam = (const char *) (x); break #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0 - int drive = (long)inode->i_bdev->bd_disk->private_data; + int drive = (long)bdev->bd_disk->private_data; int i, type = ITYPE(UDRS->fd_device); int ret; int size; @@ -3539,11 +3539,11 @@ static int fd_ioctl(struct inode *inode, current_type[drive] = NULL; floppy_sizes[drive] = MAX_DISK_SIZE << 1; UDRS->keep_data = 0; - return invalidate_drive(inode->i_bdev); + return invalidate_drive(bdev); case FDSETPRM: case FDDEFPRM: return set_geometry(cmd, & inparam.g, - drive, type, inode->i_bdev); + drive, type, bdev); case FDGETPRM: ECALL(get_floppy_geometry(drive, type, (struct floppy_struct**) @@ -3574,7 +3574,7 @@ static int fd_ioctl(struct inode *inode, case FDFMTEND: case FDFLUSH: LOCK_FDC(drive,1); - return invalidate_drive(inode->i_bdev); + return invalidate_drive(bdev); case FDSETEMSGTRESH: UDP->max_errors.reporting = @@ -3685,9 +3685,9 @@ static void __init config_types(void) printk("\n"); } -static int floppy_release(struct inode * inode, struct file * filp) +static int floppy_release(struct gendisk *disk) { - int drive = (long)inode->i_bdev->bd_disk->private_data; + int drive = (long)disk->private_data; down(&open_lock); if (UDRS->fd_ref < 0) @@ -3708,9 +3708,9 @@ static int floppy_release(struct inode * * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */ -static int floppy_open(struct inode * inode, struct file * filp) +static int floppy_open(struct block_device *bdev, struct file * filp) { - int drive = (long)inode->i_bdev->bd_disk->private_data; + int drive = (long)bdev->bd_disk->private_data; int old_dev; int try; int res = -EBUSY; @@ -3719,7 +3719,7 @@ static int floppy_open(struct inode * in filp->private_data = (void*) 0; down(&open_lock); old_dev = UDRS->fd_device; - if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev) + if (opened_bdev[drive] && opened_bdev[drive] != bdev) goto out2; if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){ @@ -3739,7 +3739,7 @@ static int floppy_open(struct inode * in else UDRS->fd_ref++; - opened_bdev[drive] = inode->i_bdev; + opened_bdev[drive] = bdev; res = -ENXIO; @@ -3774,9 +3774,9 @@ static int floppy_open(struct inode * in } } - UDRS->fd_device = iminor(inode); - set_capacity(disks[drive], floppy_sizes[iminor(inode)]); - if (old_dev != -1 && old_dev != iminor(inode)) { + UDRS->fd_device = MINOR(bdev->bd_dev); + set_capacity(disks[drive], floppy_sizes[MINOR(bdev->bd_dev)]); + if (old_dev != -1 && old_dev != MINOR(bdev->bd_dev)) { if (buffer_drive == drive) buffer_track = -1; } @@ -3784,8 +3784,7 @@ static int floppy_open(struct inode * in /* Allow ioctls if we have write-permissions even if read-only open. * Needed so that programs such as fdrawcmd still can work on write * protected disks */ - if ((filp->f_mode & 2) || - (inode->i_sb && (permission(inode,2, NULL) == 0))) + if ((filp->f_mode & 2) || permission(filp->f_dentry->d_inode,2,NULL) == 0) filp->private_data = (void*) 8; if (UFDCS->rawcmd == 1) @@ -3794,7 +3793,7 @@ static int floppy_open(struct inode * in if (!(filp->f_flags & O_NDELAY)) { if (filp->f_mode & 3) { UDRS->last_checked = 0; - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (UTESTF(FD_DISK_CHANGED)) goto out; } --- linux-2.6.1-rc1/drivers/block/ioctl.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/ioctl.c 2003-12-30 22:49:38.000000000 -0800 @@ -132,10 +132,9 @@ static int put_u64(unsigned long arg, u6 return put_user(val, (u64 *)arg); } -int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, +int blkdev_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; struct gendisk *disk = bdev->bd_disk; struct backing_dev_info *bdi; int holder; @@ -194,7 +193,7 @@ int blkdev_ioctl(struct inode *inode, st if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (disk->fops->ioctl) { - ret = disk->fops->ioctl(inode, file, cmd, arg); + ret = disk->fops->ioctl(bdev, file, cmd, arg); if (ret != -EINVAL) return ret; } @@ -203,7 +202,7 @@ int blkdev_ioctl(struct inode *inode, st return 0; case BLKROSET: if (disk->fops->ioctl) { - ret = disk->fops->ioctl(inode, file, cmd, arg); + ret = disk->fops->ioctl(bdev, file, cmd, arg); if (ret != -EINVAL) return ret; } @@ -215,7 +214,7 @@ int blkdev_ioctl(struct inode *inode, st return 0; default: if (disk->fops->ioctl) - return disk->fops->ioctl(inode, file, cmd, arg); + return disk->fops->ioctl(bdev, file, cmd, arg); } return -ENOTTY; } --- linux-2.6.1-rc1/drivers/block/Kconfig.iosched 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/Kconfig.iosched 2003-12-30 22:49:43.000000000 -0800 @@ -27,3 +27,10 @@ config IOSCHED_DEADLINE a disk at any one time, its behaviour is almost identical to the anticipatory I/O scheduler and so is a good choice. +config IOSCHED_CFQ + bool "CFQ I/O scheduler" if EMBEDDED + default y + ---help--- + The CFQ I/O scheduler tries to distribute bandwidth equally + among all processes in the system. It should provide a fair + working environment, suitable for desktop systems. --- linux-2.6.1-rc1/drivers/block/ll_rw_blk.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/block/ll_rw_blk.c 2003-12-30 22:50:22.000000000 -0800 @@ -517,10 +517,10 @@ init_tag_map(request_queue_t *q, struct { int bits, i; - if (depth > q->nr_requests * 2) { - depth = q->nr_requests * 2; - printk(KERN_ERR "%s: adjusted depth to %d\n", - __FUNCTION__, depth); + if (depth > q->nr_requests / 2) { + q->nr_requests = depth * 2; + printk(KERN_INFO "%s: large TCQ depth: adjusted nr_requests " + "to %lu\n", __FUNCTION__, q->nr_requests); } tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); @@ -780,11 +780,6 @@ static char *rq_flags[] = { "REQ_PM_SUSPEND", "REQ_PM_RESUME", "REQ_PM_SHUTDOWN", - "REQ_IDETAPE_PC1", - "REQ_IDETAPE_PC2", - "REQ_IDETAPE_READ", - "REQ_IDETAPE_WRITE", - "REQ_IDETAPE_READ_BUFFER", }; void blk_dump_rq_flags(struct request *rq, char *msg) @@ -1335,6 +1330,8 @@ static elevator_t *chosen_elevator = &iosched_as; #elif defined(CONFIG_IOSCHED_DEADLINE) &iosched_deadline; +#elif defined(CONFIG_IOSCHED_CFQ) + &iosched_cfq; #elif defined(CONFIG_IOSCHED_NOOP) &elevator_noop; #else @@ -1353,6 +1350,10 @@ static int __init elevator_setup(char *s if (!strcmp(str, "as")) chosen_elevator = &iosched_as; #endif +#ifdef CONFIG_IOSCHED_CFQ + if (!strcmp(str, "cfq")) + chosen_elevator = &iosched_cfq; +#endif #ifdef CONFIG_IOSCHED_NOOP if (!strcmp(str, "noop")) chosen_elevator = &elevator_noop; @@ -1875,29 +1876,52 @@ void blk_put_request(struct request *req spin_unlock_irqrestore(q->queue_lock, flags); } } - EXPORT_SYMBOL(blk_put_request); /** - * blk_congestion_wait - wait for a queue to become uncongested + * blk_congestion_wait_wq - wait for a queue to become uncongested, * @rw: READ or WRITE * @timeout: timeout in jiffies + * @wait : wait queue entry to use for waiting or async notification + * (NULL defaults to synchronous behaviour) * * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion. * If no queues are congested then just wait for the next request to be * returned. + * + * If the wait queue parameter specifies an async i/o callback, + * then instead of blocking, just register the callback on the wait + * queue for async notification when the queue gets uncongested. */ -void blk_congestion_wait(int rw, long timeout) +int blk_congestion_wait_wq(int rw, long timeout, wait_queue_t *wait) { - DEFINE_WAIT(wait); wait_queue_head_t *wqh = &congestion_wqh[rw]; + DEFINE_WAIT(local_wait); + + if (!wait) + wait = &local_wait; blk_run_queues(); - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE); + if (!is_sync_wait(wait)) { + /* + * if we've queued an async wait queue + * callback do not block; just tell the + * caller to return and retry later when + * the callback is notified + */ + return -EIOCBRETRY; + } io_schedule_timeout(timeout); - finish_wait(wqh, &wait); + finish_wait(wqh, wait); + return 0; } +EXPORT_SYMBOL(blk_congestion_wait_wq); +void blk_congestion_wait(int rw, long timeout) +{ + blk_congestion_wait_wq(rw, timeout, NULL); +} EXPORT_SYMBOL(blk_congestion_wait); /* --- linux-2.6.1-rc1/drivers/block/loop.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/loop.c 2003-12-30 22:49:51.000000000 -0800 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -75,24 +76,34 @@ static struct gendisk **disks; /* * Transfer functions */ -static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t real_block) +static int transfer_none(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t real_block) { - if (raw_buf != loop_buf) { - if (cmd == READ) - memcpy(loop_buf, raw_buf, size); - else - memcpy(raw_buf, loop_buf, size); - } + char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; + char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; + if (cmd == READ) + memcpy(loop_buf, raw_buf, size); + else + memcpy(raw_buf, loop_buf, size); + + kunmap_atomic(raw_buf, KM_USER0); + kunmap_atomic(loop_buf, KM_USER1); + cond_resched(); return 0; } -static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t real_block) -{ - char *in, *out, *key; - int i, keysize; +static int transfer_xor(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t real_block) +{ + char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; + char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; + char *in, *out, *key; + int i, keysize; if (cmd == READ) { in = raw_buf; @@ -106,6 +117,10 @@ static int transfer_xor(struct loop_devi keysize = lo->lo_encrypt_key_size; for (i = 0; i < size; i++) *out++ = *in++ ^ key[(i & 511) % keysize]; + + kunmap_atomic(raw_buf, KM_USER0); + kunmap_atomic(loop_buf, KM_USER1); + cond_resched(); return 0; } @@ -140,8 +155,7 @@ figure_loop_size(struct loop_device *lo) sector_t x; /* Compute loopsize in bytes */ - size = i_size_read(lo->lo_backing_file->f_dentry-> - d_inode->i_mapping->host); + size = i_size_read(lo->lo_backing_file->f_mapping->host); offset = lo->lo_offset; loopsize = size - offset; if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize) @@ -162,32 +176,33 @@ figure_loop_size(struct loop_device *lo) } static inline int -lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf, - char *lbuf, int size, sector_t rblock) +lo_do_transfer(struct loop_device *lo, int cmd, + struct page *rpage, unsigned roffs, + struct page *lpage, unsigned loffs, + int size, sector_t rblock) { if (!lo->transfer) return 0; - return lo->transfer(lo, cmd, rbuf, lbuf, size, rblock); + return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); } static int do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos) { struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; struct address_space_operations *aops = mapping->a_ops; struct page *page; - char *kaddr, *data; pgoff_t index; - unsigned size, offset; + unsigned size, offset, bv_offs; int len; int ret = 0; down(&mapping->host->i_sem); index = pos >> PAGE_CACHE_SHIFT; offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1); - data = kmap(bvec->bv_page) + bvec->bv_offset; + bv_offs = bvec->bv_offset; len = bvec->bv_len; while (len > 0) { sector_t IV; @@ -204,25 +219,28 @@ do_lo_send(struct loop_device *lo, struc goto fail; if (aops->prepare_write(file, page, offset, offset+size)) goto unlock; - kaddr = kmap(page); - transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, - data, size, IV); + transfer_result = lo_do_transfer(lo, WRITE, page, offset, + bvec->bv_page, bv_offs, + size, IV); if (transfer_result) { + char *kaddr; + /* * The transfer failed, but we still write the data to * keep prepare/commit calls balanced. */ printk(KERN_ERR "loop: transfer error block %llu\n", (unsigned long long)index); + kaddr = kmap_atomic(page, KM_USER0); memset(kaddr + offset, 0, size); + kunmap_atomic(kaddr, KM_USER0); } flush_dcache_page(page); - kunmap(page); if (aops->commit_write(file, page, offset, offset+size)) goto unlock; if (transfer_result) goto unlock; - data += size; + bv_offs += size; len -= size; offset = 0; index++; @@ -232,7 +250,6 @@ do_lo_send(struct loop_device *lo, struc } up(&mapping->host->i_sem); out: - kunmap(bvec->bv_page); return ret; unlock: @@ -247,12 +264,10 @@ fail: static int lo_send(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) { - unsigned vecnr; - int ret = 0; - - for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) { - struct bio_vec *bvec = &bio->bi_io_vec[vecnr]; + struct bio_vec *bvec; + int i, ret = 0; + bio_for_each_segment(bvec, bio, i) { ret = do_lo_send(lo, bvec, bsize, pos); if (ret < 0) break; @@ -263,7 +278,8 @@ lo_send(struct loop_device *lo, struct b struct lo_read_data { struct loop_device *lo; - char *data; + struct page *page; + unsigned offset; int bsize; }; @@ -271,7 +287,6 @@ static int lo_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size) { - char *kaddr; unsigned long count = desc->count; struct lo_read_data *p = (struct lo_read_data*)desc->buf; struct loop_device *lo = p->lo; @@ -282,18 +297,16 @@ lo_read_actor(read_descriptor_t *desc, s if (size > count) size = count; - kaddr = kmap(page); - if (lo_do_transfer(lo, READ, kaddr + offset, p->data, size, IV)) { + if (lo_do_transfer(lo, READ, page, offset, p->page, p->offset, size, IV)) { size = 0; printk(KERN_ERR "loop: transfer error block %ld\n", page->index); desc->error = -EINVAL; } - kunmap(page); desc->count = count - size; desc->written += size; - p->data += size; + p->offset += size; return size; } @@ -306,24 +319,22 @@ do_lo_receive(struct loop_device *lo, int retval; cookie.lo = lo; - cookie.data = kmap(bvec->bv_page) + bvec->bv_offset; + cookie.page = bvec->bv_page; + cookie.offset = bvec->bv_offset; cookie.bsize = bsize; file = lo->lo_backing_file; retval = file->f_op->sendfile(file, &pos, bvec->bv_len, lo_read_actor, &cookie); - kunmap(bvec->bv_page); return (retval < 0)? retval: 0; } static int lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) { - unsigned vecnr; - int ret = 0; - - for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) { - struct bio_vec *bvec = &bio->bi_io_vec[vecnr]; + struct bio_vec *bvec; + int i, ret = 0; + bio_for_each_segment(bvec, bio, i) { ret = do_lo_receive(lo, bvec, bsize, pos); if (ret < 0) break; @@ -353,10 +364,12 @@ static void loop_put_buffer(struct bio * * check bi_end_io, may just be a remapped bio */ if (bio && bio->bi_end_io == loop_end_io_transfer) { + struct bio_vec *bv; int i; - for (i = 0; i < bio->bi_vcnt; i++) - __free_page(bio->bi_io_vec[i].bv_page); + if (!bio_flagged(bio, BIO_CLONED)) + bio_for_each_segment(bv, bio, i) + __free_page(bv->bv_page); bio_put(bio); } @@ -413,7 +426,7 @@ static int loop_end_io_transfer(struct b if (bio->bi_size) return 1; - if (err || bio_rw(bio) == WRITE) { + if (err || (bio_rw(bio) == WRITE && bio->bi_vcnt == rbh->bi_vcnt)) { bio_endio(rbh, rbh->bi_size, err); if (atomic_dec_and_test(&lo->lo_pending)) up(&lo->lo_bh_mutex); @@ -430,35 +443,41 @@ static struct bio *loop_copy_bio(struct struct bio_vec *bv; int i; - bio = bio_alloc(__GFP_NOWARN, rbh->bi_vcnt); + if (bio_rw(rbh) != WRITE) { + bio = bio_clone(rbh, GFP_NOIO); + return bio; + } + + bio = bio_alloc(GFP_NOIO, rbh->bi_vcnt); if (!bio) return NULL; /* * iterate iovec list and alloc pages */ - __bio_for_each_segment(bv, rbh, i, 0) { + bio_for_each_segment(bv, rbh, i) { struct bio_vec *bbv = &bio->bi_io_vec[i]; - bbv->bv_page = alloc_page(__GFP_NOWARN|__GFP_HIGHMEM); + /* We need one page; the rest we can live without */ + bbv->bv_page = alloc_page((bio->bi_vcnt ? __GFP_NOWARN : GFP_NOIO) | __GFP_HIGHMEM); if (bbv->bv_page == NULL) - goto oom; + break; - bbv->bv_len = bv->bv_len; bbv->bv_offset = bv->bv_offset; + bio->bi_size += (bbv->bv_len = bv->bv_len); + bio->bi_vcnt++; } - bio->bi_vcnt = rbh->bi_vcnt; - bio->bi_size = rbh->bi_size; - - return bio; + /* Can't get anything done if we didn't get any pages */ + if (unlikely(!bio->bi_vcnt)) { + bio_put(bio); + return NULL; + } -oom: - while (--i >= 0) - __free_page(bio->bi_io_vec[i].bv_page); + bio->bi_vcnt += (bio->bi_idx = rbh->bi_idx); + bio->bi_rw = rbh->bi_rw; - bio_put(bio); - return NULL; + return bio; } static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh) @@ -479,40 +498,102 @@ static struct bio *loop_get_buffer(struc if (flags & PF_MEMALLOC) current->flags |= PF_MEMALLOC; - if (bio == NULL) + if (unlikely(bio == NULL)) { + printk("loop: alloc failed\n"); blk_congestion_wait(WRITE, HZ/10); + } } while (bio == NULL); bio->bi_end_io = loop_end_io_transfer; bio->bi_private = rbh; bio->bi_sector = rbh->bi_sector + (lo->lo_offset >> 9); - bio->bi_rw = rbh->bi_rw; bio->bi_bdev = lo->lo_device; return bio; } +static void loop_recycle_buffer(struct loop_device *lo, struct bio *bio) +{ + struct bio *rbh = bio->bi_private; + struct bio_vec *bv, *bbv, *rbv; + int i, flags, nvecs = bio->bi_vcnt - bio->bi_idx; + + /* + * Comments in ll_rw_blk.c reserve for generic_make_request the right to + * "change bi_dev and bi_sector for remaps as it sees fit." Doh! + * Workaround: reset the bi_bdev and recompute the starting sector for + * the next write. + */ + bio->bi_bdev = lo->lo_device; + bio->bi_sector = rbh->bi_sector + (lo->lo_offset >> 9); + /* Clean up the flags too */ + bio->bi_flags &= (~(BIO_POOL_MASK - 1) | (1 << BIO_UPTODATE)); + + /* + * Move the allocated pages into position to transfer more data. + */ + __bio_for_each_segment(bv, bio, i, rbh->bi_idx) { + rbv = &rbh->bi_io_vec[i]; + bbv = bv + nvecs; + + /* Workaround -- see note above */ + bio->bi_sector += rbv->bv_len >> 9; + if (i < bio->bi_idx) + continue; + + if (i + nvecs < rbh->bi_vcnt) { + bbv->bv_page = bv->bv_page; + bbv->bv_offset = rbv->bv_offset; + bio->bi_size += (bbv->bv_len = rbv->bv_len); + } else + __free_page(bv->bv_page); + memset(bv, 0, sizeof(*bv)); + } + + bio->bi_idx = bio->bi_vcnt; + bio->bi_vcnt += nvecs; + bio->bi_vcnt = min(bio->bi_vcnt, rbh->bi_vcnt); + + /* + * If we need more pages, try to get some. + * Clear PF_MEMALLOC to avoid consuming all available memory. + */ + flags = current->flags; + current->flags &= ~PF_MEMALLOC; + + __bio_for_each_segment(rbv, rbh, i, bio->bi_vcnt) { + bv = &bio->bi_io_vec[i]; + + bv->bv_page = alloc_page(__GFP_NOWARN|__GFP_HIGHMEM); + if (bv->bv_page == NULL) + break; + + bv->bv_offset = rbv->bv_offset; + bio->bi_size += (bv->bv_len = rbv->bv_len); + bio->bi_vcnt++; + } + + if (flags & PF_MEMALLOC) + current->flags |= PF_MEMALLOC; +} + static int loop_transfer_bio(struct loop_device *lo, struct bio *to_bio, struct bio *from_bio) { sector_t IV; struct bio_vec *from_bvec, *to_bvec; - char *vto, *vfrom; int ret = 0, i; IV = from_bio->bi_sector + (lo->lo_offset >> 9); - __bio_for_each_segment(from_bvec, from_bio, i, 0) { - to_bvec = &to_bio->bi_io_vec[i]; - - kmap(from_bvec->bv_page); - kmap(to_bvec->bv_page); - vfrom = page_address(from_bvec->bv_page) + from_bvec->bv_offset; - vto = page_address(to_bvec->bv_page) + to_bvec->bv_offset; - ret |= lo_do_transfer(lo, bio_data_dir(to_bio), vto, vfrom, - from_bvec->bv_len, IV); - kunmap(from_bvec->bv_page); - kunmap(to_bvec->bv_page); + __bio_for_each_segment(to_bvec, to_bio, i, from_bio->bi_idx) { + from_bvec = &from_bio->bi_io_vec[i]; + if (i >= to_bio->bi_idx) { + ret |= lo_do_transfer(lo, bio_data_dir(to_bio), + to_bvec->bv_page, to_bvec->bv_offset, + from_bvec->bv_page, from_bvec->bv_offset, + from_bvec->bv_len, IV); + } IV += from_bvec->bv_len >> 9; } @@ -579,16 +660,30 @@ inactive: static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio) { int ret; + struct bio *rbh; - /* - * For block backed loop, we know this is a READ - */ if (lo->lo_flags & LO_FLAGS_DO_BMAP) { ret = do_bio_filebacked(lo, bio); bio_endio(bio, bio->bi_size, ret); - } else { - struct bio *rbh = bio->bi_private; + } else if (bio_rw(bio) == WRITE) { + /* + * Write complete, but more pages remain; + * encrypt and write some more pages + */ + loop_recycle_buffer(lo, bio); + + rbh = bio->bi_private; + if ((ret = loop_transfer_bio(lo, bio, rbh))) { + bio_endio(bio, bio->bi_size, ret); + return; + } + generic_make_request(bio); + } else { + /* + * Read complete; do decryption now + */ + rbh = bio->bi_private; ret = loop_transfer_bio(lo, bio, rbh); bio_endio(rbh, rbh->bi_size, ret); @@ -606,6 +701,7 @@ static int loop_thread(void *data) { struct loop_device *lo = data; struct bio *bio; + int x; daemonize("loop%d", lo->lo_number); @@ -640,7 +736,11 @@ static int loop_thread(void *data) printk("loop: missing bio\n"); continue; } + + x = (lo->lo_flags & LO_FLAGS_DO_BMAP) || bio_rw(bio) != WRITE; loop_handle_bio(lo, bio); + if (!x) + continue; /* * upped both for pending work and tear-down, lo_pending @@ -660,6 +760,7 @@ static int loop_set_fd(struct loop_devic struct file *file; struct inode *inode; struct block_device *lo_device = NULL; + struct address_space *mapping; unsigned lo_blocksize; int lo_flags = 0; int error; @@ -676,14 +777,16 @@ static int loop_set_fd(struct loop_devic if (!file) goto out; - error = -EINVAL; - inode = file->f_dentry->d_inode; + mapping = file->f_mapping; + inode = mapping->host; if (!(file->f_mode & FMODE_WRITE)) lo_flags |= LO_FLAGS_READ_ONLY; + error = -EINVAL; + if (S_ISBLK(inode->i_mode)) { - lo_device = inode->i_bdev; + lo_device = I_BDEV(inode); if (lo_device == bdev) { error = -EBUSY; goto out; @@ -692,7 +795,7 @@ static int loop_set_fd(struct loop_devic if (bdev_read_only(lo_device)) lo_flags |= LO_FLAGS_READ_ONLY; } else if (S_ISREG(inode->i_mode)) { - struct address_space_operations *aops = inode->i_mapping->a_ops; + struct address_space_operations *aops = mapping->a_ops; /* * If we can't read - sorry. If we only can't write - well, * it's going to be read-only. @@ -728,9 +831,8 @@ static int loop_set_fd(struct loop_devic fput(file); goto out_putf; } - lo->old_gfp_mask = mapping_gfp_mask(inode->i_mapping); - mapping_set_gfp_mask(inode->i_mapping, - lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); + lo->old_gfp_mask = mapping_gfp_mask(mapping); + mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); set_blocksize(bdev, lo_blocksize); @@ -752,6 +854,7 @@ static int loop_set_fd(struct loop_devic blk_queue_max_sectors(lo->lo_queue, q->max_sectors); blk_queue_max_phys_segments(lo->lo_queue,q->max_phys_segments); blk_queue_max_hw_segments(lo->lo_queue, q->max_hw_segments); + blk_queue_hardsect_size(lo->lo_queue, queue_hardsect_size(q)); blk_queue_max_segment_size(lo->lo_queue, q->max_segment_size); blk_queue_segment_boundary(lo->lo_queue, q->seg_boundary_mask); blk_queue_merge_bvec(lo->lo_queue, q->merge_bvec_fn); @@ -846,7 +949,7 @@ static int loop_clr_fd(struct loop_devic memset(lo->lo_file_name, 0, LO_NAME_SIZE); invalidate_bdev(bdev, 0); set_capacity(disks[lo->lo_number], 0); - mapping_set_gfp_mask(filp->f_dentry->d_inode->i_mapping, gfp); + mapping_set_gfp_mask(filp->f_mapping, gfp); lo->lo_state = Lo_unbound; fput(filp); /* This is safe: open() is still holding a reference. */ @@ -1056,19 +1159,19 @@ loop_get_status64(struct loop_device *lo return err; } -static int lo_ioctl(struct inode * inode, struct file * file, +static int lo_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + struct loop_device *lo = bdev->bd_disk->private_data; int err; down(&lo->lo_ctl_mutex); switch (cmd) { case LOOP_SET_FD: - err = loop_set_fd(lo, file, inode->i_bdev, arg); + err = loop_set_fd(lo, file, bdev, arg); break; case LOOP_CLR_FD: - err = loop_clr_fd(lo, inode->i_bdev); + err = loop_clr_fd(lo, bdev); break; case LOOP_SET_STATUS: err = loop_set_status_old(lo, (struct loop_info *) arg); @@ -1089,9 +1192,9 @@ static int lo_ioctl(struct inode * inode return err; } -static int lo_open(struct inode *inode, struct file *file) +static int lo_open(struct block_device *bdev, struct file *file) { - struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + struct loop_device *lo = bdev->bd_disk->private_data; down(&lo->lo_ctl_mutex); lo->lo_refcnt++; @@ -1100,9 +1203,9 @@ static int lo_open(struct inode *inode, return 0; } -static int lo_release(struct inode *inode, struct file *file) +static int lo_release(struct gendisk *disk) { - struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + struct loop_device *lo = disk->private_data; down(&lo->lo_ctl_mutex); --lo->lo_refcnt; @@ -1124,6 +1227,7 @@ static struct block_device_operations lo MODULE_PARM(max_loop, "i"); MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR); int loop_register_transfer(struct loop_func_table *funcs) { --- linux-2.6.1-rc1/drivers/block/Makefile 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/Makefile 2003-12-30 22:49:43.000000000 -0800 @@ -18,6 +18,7 @@ obj-y := elevator.o ll_rw_blk.o ioctl.o obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o obj-$(CONFIG_IOSCHED_AS) += as-iosched.o obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o +obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_BLK_DEV_FD98) += floppy98.o --- linux-2.6.1-rc1/drivers/block/nbd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/nbd.c 2003-12-30 22:49:29.000000000 -0800 @@ -535,10 +535,10 @@ static void do_nbd_request(request_queue return; } -static int nbd_ioctl(struct inode *inode, struct file *file, +static int nbd_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; + struct nbd_device *lo = bdev->bd_disk->private_data; int error; struct request sreq ; @@ -593,7 +593,7 @@ static int nbd_ioctl(struct inode *inode error = -EINVAL; file = fget(arg); if (file) { - inode = file->f_dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; if (inode->i_sock) { lo->file = file; lo->sock = SOCKET_I(inode); @@ -606,20 +606,20 @@ static int nbd_ioctl(struct inode *inode case NBD_SET_BLKSIZE: lo->blksize = arg; lo->bytesize &= ~(lo->blksize-1); - inode->i_bdev->bd_inode->i_size = lo->bytesize; - set_blocksize(inode->i_bdev, lo->blksize); + bdev->bd_inode->i_size = lo->bytesize; + set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; case NBD_SET_SIZE: lo->bytesize = arg & ~(lo->blksize-1); - inode->i_bdev->bd_inode->i_size = lo->bytesize; - set_blocksize(inode->i_bdev, lo->blksize); + bdev->bd_inode->i_size = lo->bytesize; + set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; case NBD_SET_SIZE_BLOCKS: lo->bytesize = ((u64) arg) * lo->blksize; - inode->i_bdev->bd_inode->i_size = lo->bytesize; - set_blocksize(inode->i_bdev, lo->blksize); + bdev->bd_inode->i_size = lo->bytesize; + set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; case NBD_DO_IT: @@ -664,11 +664,11 @@ static int nbd_ioctl(struct inode *inode case NBD_PRINT_DEBUG: #ifdef PARANOIA printk(KERN_INFO "%s: next = %p, prev = %p. Global: in %d, out %d\n", - inode->i_bdev->bd_disk->disk_name, lo->queue_head.next, + bdev->bd_disk->disk_name, lo->queue_head.next, lo->queue_head.prev, requests_in, requests_out); #else printk(KERN_INFO "%s: next = %p, prev = %p\n", - inode->i_bdev->bd_disk->disk_name, + bdev->bd_disk->disk_name, lo->queue_head.next, lo->queue_head.prev); #endif return 0; --- linux-2.6.1-rc1/drivers/block/paride/pcd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/paride/pcd.c 2003-12-30 22:49:33.000000000 -0800 @@ -243,23 +243,23 @@ static int pcd_warned; /* Have we logge /* kernel glue structures */ -static int pcd_block_open(struct inode *inode, struct file *file) +static int pcd_block_open(struct block_device *bdev, struct file *file) { - struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; - return cdrom_open(&cd->info, inode, file); + struct pcd_unit *cd = bdev->bd_disk->private_data; + return cdrom_open(&cd->info, bdev, file); } -static int pcd_block_release(struct inode *inode, struct file *file) +static int pcd_block_release(struct gendisk *disk) { - struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; - return cdrom_release(&cd->info, file); + struct pcd_unit *cd = disk->private_data; + return cdrom_release(&cd->info); } -static int pcd_block_ioctl(struct inode *inode, struct file *file, +static int pcd_block_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; - return cdrom_ioctl(&cd->info, inode, cmd, arg); + struct pcd_unit *cd = bdev->bd_disk->private_data; + return cdrom_ioctl(&cd->info, bdev, cmd, arg); } static int pcd_block_media_changed(struct gendisk *disk) --- linux-2.6.1-rc1/drivers/block/paride/pd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/paride/pd.c 2003-12-30 22:49:33.000000000 -0800 @@ -236,11 +236,11 @@ MODULE_PARM(drive3, "1-8i"); #define IDE_EJECT 0xed void pd_setup(char *str, int *ints); -static int pd_open(struct inode *inode, struct file *file); +static int pd_open(struct block_device *bdev, struct file *file); static void do_pd_request(request_queue_t * q); -static int pd_ioctl(struct inode *inode, struct file *file, +static int pd_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg); -static int pd_release(struct inode *inode, struct file *file); +static int pd_release(struct gendisk *disk); static int pd_revalidate(struct gendisk *p); static int pd_detect(void); static void do_pd_read(void); @@ -304,8 +304,6 @@ static char *pd_errs[17] = { "ERR", "IND /* kernel glue structures */ -extern struct block_device_operations pd_fops; - static struct block_device_operations pd_fops = { .owner = THIS_MODULE, .open = pd_open, @@ -337,9 +335,9 @@ static void pd_init_units(void) } } -static int pd_open(struct inode *inode, struct file *file) +static int pd_open(struct block_device *bdev, struct file *file) { - struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; + struct pd_unit *disk = bdev->bd_disk->private_data; disk->access++; @@ -350,10 +348,10 @@ static int pd_open(struct inode *inode, return 0; } -static int pd_ioctl(struct inode *inode, struct file *file, +static int pd_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; + struct pd_unit *disk = bdev->bd_disk->private_data; struct hd_geometry *geo = (struct hd_geometry *) arg; struct hd_geometry g; @@ -372,7 +370,7 @@ static int pd_ioctl(struct inode *inode, g.sectors = disk->sectors; g.cylinders = disk->cylinders; } - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); if (copy_to_user(geo, &g, sizeof(struct hd_geometry))) return -EFAULT; return 0; @@ -381,9 +379,9 @@ static int pd_ioctl(struct inode *inode, } } -static int pd_release(struct inode *inode, struct file *file) +static int pd_release(struct gendisk *p) { - struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; + struct pd_unit *disk = p->private_data; if (!--disk->access && disk->removable) pd_doorlock(disk, IDE_DOORUNLOCK); --- linux-2.6.1-rc1/drivers/block/paride/pf.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/paride/pf.c 2003-12-30 22:49:33.000000000 -0800 @@ -222,12 +222,12 @@ MODULE_PARM(drive3, "1-7i"); #define ATAPI_READ_10 0x28 #define ATAPI_WRITE_10 0x2a -static int pf_open(struct inode *inode, struct file *file); +static int pf_open(struct block_device *bdev, struct file *file); static void do_pf_request(request_queue_t * q); -static int pf_ioctl(struct inode *inode, struct file *file, +static int pf_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg); -static int pf_release(struct inode *inode, struct file *file); +static int pf_release(struct gendisk *disk); static int pf_detect(void); static void do_pf_read(void); @@ -315,9 +315,9 @@ void pf_init_units(void) } } -static int pf_open(struct inode *inode, struct file *file) +static int pf_open(struct block_device *bdev, struct file *file) { - struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; + struct pf_unit *pf = bdev->bd_disk->private_data; pf_identify(pf); @@ -334,9 +334,9 @@ static int pf_open(struct inode *inode, return 0; } -static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int pf_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; + struct pf_unit *pf = bdev->bd_disk->private_data; struct hd_geometry *geo = (struct hd_geometry *) arg; struct hd_geometry g; sector_t capacity; @@ -365,9 +365,9 @@ static int pf_ioctl(struct inode *inode, return 0; } -static int pf_release(struct inode *inode, struct file *file) +static int pf_release(struct gendisk *disk) { - struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; + struct pf_unit *pf = disk->private_data; if (pf->access <= 0) return -EINVAL; --- linux-2.6.1-rc1/drivers/block/ps2esdi.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/ps2esdi.c 2003-12-30 22:49:29.000000000 -0800 @@ -81,7 +81,7 @@ static void (*current_int_handler) (u_in static void ps2esdi_normal_interrupt_handler(u_int); static void ps2esdi_initial_reset_int_handler(u_int); static void ps2esdi_geometry_int_handler(u_int); -static int ps2esdi_ioctl(struct inode *inode, struct file *file, +static int ps2esdi_ioctl(struct block_device *bdev, struct file *file, u_int cmd, u_long arg); static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer); @@ -1059,10 +1059,10 @@ static void dump_cmd_complete_status(u_i } -static int ps2esdi_ioctl(struct inode *inode, +static int ps2esdi_ioctl(struct block_device *bdev, struct file *file, u_int cmd, u_long arg) { - struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data; + struct ps2esdi_i_struct *p = bdev->bd_disk->private_data; struct ps2esdi_geometry *geometry = (struct ps2esdi_geometry *) arg; int err; @@ -1073,7 +1073,7 @@ static int ps2esdi_ioctl(struct inode *i put_user(p->head, (char *) &geometry->heads); put_user(p->sect, (char *) &geometry->sectors); put_user(p->cyl, (short *) &geometry->cylinders); - put_user(get_start_sect(inode->i_bdev), (long *) &geometry->start); + put_user(get_start_sect(bdev), (long *) &geometry->start); return 0; } --- linux-2.6.1-rc1/drivers/block/rd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/rd.c 2003-12-30 22:49:46.000000000 -0800 @@ -1,15 +1,15 @@ /* * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta. - * - * (C) Chad Page, Theodore Ts'o, et. al, 1995. + * + * (C) Chad Page, Theodore Ts'o, et. al, 1995. * * This RAM disk is designed to have filesystems created on it and mounted - * just like a regular floppy disk. - * + * just like a regular floppy disk. + * * It also does something suggested by Linus: use the buffer cache as the * RAM disk data. This makes it possible to dynamically allocate the RAM disk - * buffer - with some consequences I have to deal with as I write this. - * + * buffer - with some consequences I have to deal with as I write this. + * * This code is based on the original ramdisk.c, written mostly by * Theodore Ts'o (TYT) in 1991. The code was largely rewritten by * Chad Page to use the buffer cache to store the RAM disk data in @@ -33,7 +33,7 @@ * * Added initrd: Werner Almesberger & Hans Lermen, Feb '96 * - * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) + * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) * - Chad Page * * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98 @@ -60,7 +60,7 @@ #include /* The RAM disk size is now a parameter */ -#define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ +#define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ /* Various static variables go here. Most are used only in the RAM disk code. */ @@ -73,7 +73,7 @@ static struct request_queue *rd_queue[NU * Parameters for the boot-loading of the RAM disk. These are set by * init/main.c (from arguments to the kernel command line) or from the * architecture-specific setup routine (from the stored boot sector - * information). + * information). */ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */ /* @@ -94,7 +94,7 @@ int rd_blocksize = BLOCK_SIZE; /* bloc * 2000 Transmeta Corp. * aops copied from ramfs. */ -static int ramdisk_readpage(struct file *file, struct page * page) +static int ramdisk_readpage(struct file *file, struct page *page) { if (!PageUptodate(page)) { void *kaddr = kmap_atomic(page, KM_USER0); @@ -108,7 +108,8 @@ static int ramdisk_readpage(struct file return 0; } -static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +static int ramdisk_prepare_write(struct file *file, struct page *page, + unsigned offset, unsigned to) { if (!PageUptodate(page)) { void *kaddr = kmap_atomic(page, KM_USER0); @@ -122,7 +123,8 @@ static int ramdisk_prepare_write(struct return 0; } -static int ramdisk_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +static int ramdisk_commit_write(struct file *file, struct page *page, + unsigned offset, unsigned to) { return 0; } @@ -212,7 +214,7 @@ static int rd_blkdev_pagecache_IO(int rw * 19-JAN-1998 Richard Gooch Added devfs support * */ -static int rd_make_request(request_queue_t * q, struct bio *bio) +static int rd_make_request(request_queue_t *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct address_space * mapping = bdev->bd_inode->i_mapping; @@ -242,17 +244,19 @@ fail: return 0; } -static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int rd_ioctl(struct block_device *bdev, struct file *file, + unsigned int cmd, unsigned long arg) { int error; - struct block_device *bdev = inode->i_bdev; if (cmd != BLKFLSBUF) return -EINVAL; - /* special: we want to release the ramdisk memory, - it's not like with the other blockdevices where - this ioctl only flushes away the buffer cache. */ + /* + * special: we want to release the ramdisk memory, it's not like with + * the other blockdevices where this ioctl only flushes away the buffer + * cache + */ error = -EBUSY; down(&bdev->bd_sem); if (bdev->bd_openers <= 2) { @@ -268,16 +272,15 @@ static struct backing_dev_info rd_backin .memory_backed = 1, /* Does not contribute to dirty memory */ }; -static int rd_open(struct inode * inode, struct file * filp) +static int rd_open(struct block_device *bdev, struct file *filp) { - unsigned unit = iminor(inode); + unsigned unit = MINOR(bdev->bd_dev); /* * Immunize device against invalidate_buffers() and prune_icache(). */ if (rd_bdev[unit] == NULL) { - struct block_device *bdev = inode->i_bdev; - inode = igrab(bdev->bd_inode); + struct inode *inode = igrab(bdev->bd_inode); rd_bdev[unit] = bdev; bdev->bd_openers++; bdev->bd_block_size = rd_blocksize; @@ -295,12 +298,14 @@ static struct block_device_operations rd .ioctl = rd_ioctl, }; -/* Before freeing the module, invalidate all of the protected buffers! */ -static void __exit rd_cleanup (void) +/* + * Before freeing the module, invalidate all of the protected buffers! + */ +static void __exit rd_cleanup(void) { int i; - for (i = 0 ; i < NUM_RAMDISKS; i++) { + for (i = 0; i < NUM_RAMDISKS; i++) { struct block_device *bdev = rd_bdev[i]; rd_bdev[i] = NULL; if (bdev) { @@ -311,17 +316,19 @@ static void __exit rd_cleanup (void) put_disk(rd_disks[i]); } devfs_remove("rd"); - unregister_blkdev(RAMDISK_MAJOR, "ramdisk" ); + unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); } -/* This is the registration and initialization section of the RAM disk driver */ -static int __init rd_init (void) +/* + * This is the registration and initialization section of the RAM disk driver + */ +static int __init rd_init(void) { int i; int err = -ENOMEM; if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 || - (rd_blocksize & (rd_blocksize-1))) { + (rd_blocksize & (rd_blocksize-1))) { printk("RAMDISK: wrong blocksize %d, reverting to defaults\n", rd_blocksize); rd_blocksize = BLOCK_SIZE; @@ -362,8 +369,8 @@ static int __init rd_init (void) /* rd_size is given in kB */ printk("RAMDISK driver initialized: " - "%d RAM disks of %dK size %d blocksize\n", - NUM_RAMDISKS, rd_size, rd_blocksize); + "%d RAM disks of %dK size %d blocksize\n", + NUM_RAMDISKS, rd_size, rd_blocksize); return 0; out_queue: --- linux-2.6.1-rc1/drivers/block/scsi_ioctl.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/block/scsi_ioctl.c 2003-12-30 22:50:18.000000000 -0800 @@ -312,7 +312,7 @@ static int sg_scsi_ioctl(request_queue_t return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; - if (get_user(opcode, sic->data)) + if (get_user(opcode, (int *)sic->data)) return -EFAULT; bytes = max(in_len, out_len); --- linux-2.6.1-rc1/drivers/block/swim3.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/swim3.c 2003-12-30 22:49:33.000000000 -0800 @@ -239,10 +239,9 @@ static int grab_drive(struct floppy_stat int interruptible); static void release_drive(struct floppy_state *fs); static int fd_eject(struct floppy_state *fs); -static int floppy_ioctl(struct inode *inode, struct file *filp, +static int floppy_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param); -static int floppy_open(struct inode *inode, struct file *filp); -static int floppy_release(struct inode *inode, struct file *filp); +static int floppy_open(struct block_device *bdev, struct file *filp); static int floppy_check_change(struct gendisk *disk); static int floppy_revalidate(struct gendisk *disk); static int swim3_add_device(struct device_node *swims); @@ -811,10 +810,10 @@ static int fd_eject(struct floppy_state static struct floppy_struct floppy_type = { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ -static int floppy_ioctl(struct inode *inode, struct file *filp, +static int floppy_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + struct floppy_state *fs = bdev->bd_disk->private_data; int err; if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) @@ -838,9 +837,9 @@ static int floppy_ioctl(struct inode *in return -ENOTTY; } -static int floppy_open(struct inode *inode, struct file *filp) +static int floppy_open(struct block_device *bdev, struct file *filp) { - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + struct floppy_state *fs = bdev->bd_disk->private_data; volatile struct swim3 *sw = fs->swim3; int n, err = 0; @@ -876,7 +875,7 @@ static int floppy_open(struct inode *ino if (err == 0 && (filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) { - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (fs->ejected) err = -ENXIO; } @@ -904,9 +903,9 @@ static int floppy_open(struct inode *ino return 0; } -static int floppy_release(struct inode *inode, struct file *filp) +static int floppy_release(struct gendisk *disk) { - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + struct floppy_state *fs = disk->private_data; volatile struct swim3 *sw = fs->swim3; if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); --- linux-2.6.1-rc1/drivers/block/swim_iop.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/swim_iop.c 2003-12-30 22:49:33.000000000 -0800 @@ -98,10 +98,10 @@ static void swimiop_receive(struct iop_m static void swimiop_status_update(int, struct swim_drvstatus *); static int swimiop_eject(struct floppy_state *fs); -static int floppy_ioctl(struct inode *inode, struct file *filp, +static int floppy_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param); -static int floppy_open(struct inode *inode, struct file *filp); -static int floppy_release(struct inode *inode, struct file *filp); +static int floppy_open(struct block_device *bdev, struct file *filp); +static int floppy_release(struct gendisk *disk); static int floppy_check_change(struct gendisk *disk); static int floppy_revalidate(struct gendisk *disk); static int grab_drive(struct floppy_state *fs, enum swim_state state, @@ -348,10 +348,10 @@ static int swimiop_eject(struct floppy_s static struct floppy_struct floppy_type = { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ -static int floppy_ioctl(struct inode *inode, struct file *filp, +static int floppy_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long param) { - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + struct floppy_state *fs = bdev->bd_disk->private_data; int err; if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) @@ -372,15 +372,15 @@ static int floppy_ioctl(struct inode *in return -ENOTTY; } -static int floppy_open(struct inode *inode, struct file *filp) +static int floppy_open(struct block_device *bdev, struct file *filp) { - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + struct floppy_state *fs = bdev->bd_disk->private_data; if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; if ((filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) { - check_disk_change(inode->i_bdev); + check_disk_change(bdev); if (fs->ejected) return -ENXIO; } @@ -396,9 +396,9 @@ static int floppy_open(struct inode *ino return 0; } -static int floppy_release(struct inode *inode, struct file *filp) +static int floppy_release(struct gendisk *disk) { - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; + struct floppy_state *fs = disk->private_data; if (fs->ref_count > 0) fs->ref_count--; return 0; --- linux-2.6.1-rc1/drivers/block/umem.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/umem.c 2003-12-30 22:49:31.000000000 -0800 @@ -153,7 +153,6 @@ struct cardinfo { }; static struct cardinfo cards[MM_MAXCARDS]; -static struct block_device_operations mm_fops; static struct timer_list battery_timer; static int num_cards = 0; @@ -818,10 +817,10 @@ static int mm_revalidate(struct gendisk -- mm_ioctl ----------------------------------------------------------------------------------- */ -static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) +static int mm_ioctl(struct block_device *bdev, struct file *f, unsigned int cmd, unsigned long arg) { if (cmd == HDIO_GETGEO) { - struct cardinfo *card = i->i_bdev->bd_disk->private_data; + struct cardinfo *card = bdev->bd_disk->private_data; int size = card->mm_size * (1024 / MM_HARDSECT); struct hd_geometry geo; /* @@ -831,7 +830,7 @@ static int mm_ioctl(struct inode *i, str */ geo.heads = 64; geo.sectors = 32; - geo.start = get_start_sect(i->i_bdev); + geo.start = get_start_sect(bdev); geo.cylinders = size / (geo.heads * geo.sectors); if (copy_to_user((void *) arg, &geo, sizeof(geo))) --- linux-2.6.1-rc1/drivers/block/xd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/xd.c 2003-12-30 22:49:29.000000000 -0800 @@ -322,9 +322,9 @@ static void do_xd_request (request_queue } /* xd_ioctl: handle device ioctl's */ -static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) +static int xd_ioctl (struct block_device *bdev,struct file *file,u_int cmd,u_long arg) { - XD_INFO *p = inode->i_bdev->bd_disk->private_data; + XD_INFO *p = bdev->bd_disk->private_data; switch (cmd) { case HDIO_GETGEO: @@ -334,7 +334,7 @@ static int xd_ioctl (struct inode *inode g.heads = p->heads; g.sectors = p->sectors; g.cylinders = p->cylinders; - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case HDIO_SET_DMA: --- linux-2.6.1-rc1/drivers/block/xd.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/xd.h 2003-12-30 22:49:29.000000000 -0800 @@ -105,7 +105,7 @@ static u_char xd_detect (u_char *control static u_char xd_initdrives (void (*init_drive)(u_char drive)); static void do_xd_request (request_queue_t * q); -static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg); +static int xd_ioctl (struct block_device *bdev,struct file *file,unsigned int cmd,unsigned long arg); static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count); static void xd_recalibrate (u_char drive); --- linux-2.6.1-rc1/drivers/block/z2ram.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/block/z2ram.c 2003-12-30 22:49:33.000000000 -0800 @@ -67,7 +67,6 @@ static int current_device = -1; static spinlock_t z2ram_lock = SPIN_LOCK_UNLOCKED; -static struct block_device_operations z2_fops; static struct gendisk *z2ram_gendisk; static void do_z2_request(request_queue_t *q) @@ -141,7 +140,7 @@ get_chipram( void ) } static int -z2_open( struct inode *inode, struct file *filp ) +z2_open( struct block_device *bdev, struct file *filp ) { int device; int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) * @@ -150,7 +149,7 @@ z2_open( struct inode *inode, struct fil sizeof( z2ram_map[0] ); int rc = -ENOMEM; - device = iminor(inode); + device = MINOR(bdev->bd_dev); if ( current_device != -1 && current_device != device ) { @@ -301,8 +300,7 @@ err_out: return rc; } -static int -z2_release( struct inode *inode, struct file *filp ) +static int z2_release(struct gendisk *disk) { if ( current_device == -1 ) return 0; --- linux-2.6.1-rc1/drivers/bluetooth/bluecard_cs.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/bluetooth/bluecard_cs.c 2003-12-30 22:50:03.000000000 -0800 @@ -869,7 +869,7 @@ dev_link_t *bluecard_attach(void) client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); bluecard_detach(link); @@ -898,7 +898,7 @@ void bluecard_detach(dev_link_t *link) bluecard_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -910,25 +910,21 @@ void bluecard_detach(dev_link_t *link) } -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { int i; - i = CardServices(fn, handle, tuple); + i = pcmcia_get_first_tuple(handle, tuple); if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS; - i = CardServices(GetTupleData, handle, tuple); + i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return pcmcia_parse_tuple(handle, tuple, parse); } - -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) - void bluecard_config(dev_link_t *link) { client_handle_t handle = link->handle; @@ -956,7 +952,7 @@ void bluecard_config(dev_link_t *link) /* Configure card */ link->state |= DEV_CONFIG; - i = CardServices(GetConfigurationInfo, handle, &config); + i = pcmcia_get_configuration_info(handle, &config); link->conf.Vcc = config.Vcc; link->conf.ConfigIndex = 0x20; @@ -965,7 +961,7 @@ void bluecard_config(dev_link_t *link) for (n = 0; n < 0x400; n += 0x40) { link->io.BasePort1 = n ^ 0x300; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } @@ -975,13 +971,13 @@ void bluecard_config(dev_link_t *link) goto failed; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); goto failed; @@ -1013,9 +1009,9 @@ void bluecard_release(dev_link_t *link) link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } @@ -1043,14 +1039,14 @@ int bluecard_event(event_t event, int pr /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } --- linux-2.6.1-rc1/drivers/bluetooth/bt3c_cs.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/bluetooth/bt3c_cs.c 2003-12-30 22:50:03.000000000 -0800 @@ -615,7 +615,7 @@ dev_link_t *bt3c_attach(void) client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); bt3c_detach(link); @@ -644,7 +644,7 @@ void bt3c_detach(dev_link_t *link) bt3c_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -655,25 +655,30 @@ void bt3c_detach(dev_link_t *link) kfree(info); } - -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { int i; - i = CardServices(fn, handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; - - i = CardServices(GetTupleData, handle, tuple); + i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return pcmcia_parse_tuple(handle, tuple, parse); } +static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + return get_tuple(handle, tuple, parse); +} -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + return get_tuple(handle, tuple, parse); +} void bt3c_config(dev_link_t *link) { @@ -704,7 +709,7 @@ void bt3c_config(dev_link_t *link) /* Configure card */ link->state |= DEV_CONFIG; - i = CardServices(GetConfigurationInfo, handle, &config); + i = pcmcia_get_configuration_info(handle, &config); link->conf.Vcc = config.Vcc; /* First pass: look for a config entry that looks normal. */ @@ -725,7 +730,7 @@ void bt3c_config(dev_link_t *link) link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -744,7 +749,7 @@ next_entry: for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -759,13 +764,13 @@ found_port: goto failed; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); goto failed; @@ -797,9 +802,9 @@ void bt3c_release(dev_link_t *link) link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } @@ -827,14 +832,14 @@ int bt3c_event(event_t event, int priori /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } --- linux-2.6.1-rc1/drivers/bluetooth/btuart_cs.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/bluetooth/btuart_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -622,7 +622,7 @@ dev_link_t *btuart_attach(void) client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); btuart_detach(link); @@ -651,7 +651,7 @@ void btuart_detach(dev_link_t *link) btuart_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -662,25 +662,30 @@ void btuart_detach(dev_link_t *link) kfree(info); } - -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { int i; - i = CardServices(fn, handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; - - i = CardServices(GetTupleData, handle, tuple); + i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return pcmcia_parse_tuple(handle, tuple, parse); } +static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + return get_tuple(handle, tuple, parse); +} -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + return get_tuple(handle, tuple, parse); +} void btuart_config(dev_link_t *link) { @@ -711,7 +716,7 @@ void btuart_config(dev_link_t *link) /* Configure card */ link->state |= DEV_CONFIG; - i = CardServices(GetConfigurationInfo, handle, &config); + i = pcmcia_get_configuration_info(handle, &config); link->conf.Vcc = config.Vcc; /* First pass: look for a config entry that looks normal. */ @@ -732,7 +737,7 @@ void btuart_config(dev_link_t *link) link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -752,7 +757,7 @@ next_entry: for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -767,13 +772,13 @@ found_port: goto failed; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); goto failed; @@ -805,9 +810,9 @@ void btuart_release(dev_link_t *link) link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } @@ -835,14 +840,14 @@ int btuart_event(event_t event, int prio /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } --- linux-2.6.1-rc1/drivers/bluetooth/dtl1_cs.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/bluetooth/dtl1_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -601,7 +601,7 @@ dev_link_t *dtl1_attach(void) client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); dtl1_detach(link); @@ -630,7 +630,7 @@ void dtl1_detach(dev_link_t *link) dtl1_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -641,25 +641,30 @@ void dtl1_detach(dev_link_t *link) kfree(info); } - -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { int i; - i = CardServices(fn, handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; - - i = CardServices(GetTupleData, handle, tuple); + i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return pcmcia_parse_tuple(handle, tuple, parse); } +static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + return get_tuple(handle, tuple, parse); +} -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + return get_tuple(handle, tuple, parse); +} void dtl1_config(dev_link_t *link) { @@ -689,7 +694,7 @@ void dtl1_config(dev_link_t *link) /* Configure card */ link->state |= DEV_CONFIG; - i = CardServices(GetConfigurationInfo, handle, &config); + i = pcmcia_get_configuration_info(handle, &config); link->conf.Vcc = config.Vcc; tuple.TupleData = (cisdata_t *)buf; @@ -707,7 +712,7 @@ void dtl1_config(dev_link_t *link) link->io.BasePort1 = cf->io.win[0].base; link->io.NumPorts1 = cf->io.win[0].len; /*yo */ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } @@ -719,13 +724,13 @@ void dtl1_config(dev_link_t *link) goto failed; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); goto failed; @@ -757,9 +762,9 @@ void dtl1_release(dev_link_t *link) link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } @@ -787,14 +792,14 @@ int dtl1_event(event_t event, int priori /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } --- linux-2.6.1-rc1/drivers/cdrom/aztcd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/aztcd.c 2003-12-30 22:49:33.000000000 -0800 @@ -330,10 +330,10 @@ static int aztGetToc(int multi); /* Kernel Interface Functions */ static int check_aztcd_media_change(struct gendisk *disk); -static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, +static int aztcd_ioctl(struct block_device *bdev, struct file *fp, unsigned int cmd, unsigned long arg); -static int aztcd_open(struct inode *ip, struct file *fp); -static int aztcd_release(struct inode *inode, struct file *file); +static int aztcd_open(struct block_device *bdev, struct file *fp); +static int aztcd_release(struct gendisk *disk); static struct block_device_operations azt_fops = { .owner = THIS_MODULE, @@ -1153,7 +1153,7 @@ static int check_aztcd_media_change(stru /* * Kernel IO-controls */ -static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, +static int aztcd_ioctl(struct block_device *bdev, struct file *fp, unsigned int cmd, unsigned long arg) { int i; @@ -1171,8 +1171,6 @@ static int aztcd_ioctl(struct inode *ip, cmd, jiffies); printk("aztcd Status %x\n", getAztStatus()); #endif - if (!ip) - RETURNM("aztcd_ioctl 1", -EINVAL); if (getAztStatus() < 0) RETURNM("aztcd_ioctl 2", -EIO); if ((!aztTocUpToDate) || (aztDiskChanged)) { @@ -1624,7 +1622,7 @@ static void azt_invalidate_buffers(void) /* * Open the device special file. Check that a disk is in. */ -static int aztcd_open(struct inode *ip, struct file *fp) +static int aztcd_open(struct block_device *bdev, struct file *fp) { int st; @@ -1673,12 +1671,11 @@ static int aztcd_open(struct inode *ip, /* * On close, we flush all azt blocks from the buffer cache. */ -static int aztcd_release(struct inode *inode, struct file *file) +static int aztcd_release(struct gendisk *disk) { #ifdef AZT_DEBUG printk("aztcd: executing aztcd_release\n"); - printk("inode: %p, device: %s file: %p\n", inode, - inode->i_bdev->bd_disk->disk_name, file); + printk("disk: %p, device: %s\n", disk, disk->disk_name); #endif if (!--azt_open_count) { azt_invalidate_buffers(); --- linux-2.6.1-rc1/drivers/cdrom/cdrom.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/cdrom.c 2003-12-30 22:50:00.000000000 -0800 @@ -228,10 +228,16 @@ 3.12 Oct 18, 2000 - Jens Axboe -- Use quiet bit on packet commands not known to work + 3.20 Dec 17, 2003 - Jens Axboe + -- Various fixes and lots of cleanups not listed :-) + -- Locking fixes + -- Mt Rainier support + -- DVD-RAM write open fixes + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.12" -#define VERSION "Id: cdrom.c 3.12 2000/10/18" +#define REVISION "Revision: 3.20" +#define VERSION "Id: cdrom.c 3.20 2003/12/17" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -282,11 +288,25 @@ static int autoeject; static int lockdoor = 1; /* will we ever get to use this... sigh. */ static int check_media_type; +/* automatically restart mrw format */ +static int mrw_format_restart = 1; MODULE_PARM(debug, "i"); MODULE_PARM(autoclose, "i"); MODULE_PARM(autoeject, "i"); MODULE_PARM(lockdoor, "i"); MODULE_PARM(check_media_type, "i"); +MODULE_PARM(mrw_format_restart, "i"); + +static spinlock_t cdrom_lock = SPIN_LOCK_UNLOCKED; + +static const char *mrw_format_status[] = { + "not mrw", + "bgformat inactive", + "bgformat active", + "mrw complete", +}; + +static const char *mrw_address_space[] = { "DMA", "GAA" }; #if (ERRLOGMASK!=CD_NOTHING) #define cdinfo(type, fmt, args...) \ @@ -325,6 +345,10 @@ int cdrom_get_last_written(struct cdrom_ static int cdrom_get_next_writable(struct cdrom_device_info *, long *); static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*); +static int cdrom_mrw_exit(struct cdrom_device_info *cdi); + +static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di); + #ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); #endif /* CONFIG_SYSCTL */ @@ -347,13 +371,14 @@ int register_cdrom(struct cdrom_device_i if (cdo->open == NULL || cdo->release == NULL) return -2; - if ( !banner_printed ) { + if (!banner_printed) { printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n"); banner_printed = 1; #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); #endif /* CONFIG_SYSCTL */ } + ENSURE(drive_status, CDC_DRIVE_STATUS ); ENSURE(media_changed, CDC_MEDIA_CHANGED); ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); @@ -367,6 +392,7 @@ int register_cdrom(struct cdrom_device_i ENSURE(generic_packet, CDC_GENERIC_PACKET); cdi->mc_flags = 0; cdo->n_minors = 0; + cdi->for_data = 0; cdi->options = CDO_USE_FFLAGS; if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY)) @@ -378,9 +404,14 @@ int register_cdrom(struct cdrom_device_i if (check_media_type==1) cdi->options |= (int) CDO_CHECK_TYPE; + if (CDROM_CAN(CDC_MRW_W)) + cdi->exit = cdrom_mrw_exit; + cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + spin_lock(&cdrom_lock); cdi->next = topCdromPtr; topCdromPtr = cdi; + spin_unlock(&cdrom_lock); return 0; } #undef ENSURE @@ -391,23 +422,310 @@ int unregister_cdrom(struct cdrom_device cdinfo(CD_OPEN, "entering unregister_cdrom\n"); prev = NULL; + spin_lock(&cdrom_lock); cdi = topCdromPtr; while (cdi && cdi != unreg) { prev = cdi; cdi = cdi->next; } - if (cdi == NULL) + if (cdi == NULL) { + spin_unlock(&cdrom_lock); return -2; + } if (prev) prev->next = cdi->next; else topCdromPtr = cdi->next; + + spin_unlock(&cdrom_lock); + + if (cdi->exit) + cdi->exit(cdi); + cdi->ops->n_minors--; cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); return 0; } +int cdrom_get_media_event(struct cdrom_device_info *cdi, + struct media_event_desc *med) +{ + struct cdrom_generic_command cgc; + unsigned char buffer[8]; + struct event_header *eh = (struct event_header *) buffer; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; + cgc.cmd[1] = 1; /* IMMED */ + cgc.cmd[4] = 1 << 4; /* media event */ + cgc.cmd[8] = sizeof(buffer); + cgc.quiet = 1; + + if (cdi->ops->generic_packet(cdi, &cgc)) + return 1; + + if (be16_to_cpu(eh->data_len) < sizeof(*med)) + return 1; + + memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); + return 0; +} + +/* + * the first prototypes used 0x2c as the page code for the mrw mode page, + * subsequently this was changed to 0x03. probe the one used by this drive + */ +int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi) +{ + struct cdrom_generic_command cgc; + char buffer[16]; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.timeout = HZ; + cgc.quiet = 1; + + if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { + cdi->mrw_mode_page = MRW_MODE_PC; + return 0; + } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { + cdi->mrw_mode_page = MRW_MODE_PC_PRE1; + return 0; + } + + printk(KERN_ERR "cdrom: %s: unknown mrw mode page\n", cdi->name); + return 1; +} + +int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write) +{ + struct cdrom_generic_command cgc; + struct mrw_feature_desc *mfd; + unsigned char buffer[16]; + int ret; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.cmd[0] = GPCMD_GET_CONFIGURATION; + cgc.cmd[3] = CDF_MRW; + cgc.cmd[8] = sizeof(buffer); + cgc.quiet = 1; + + if ((ret = cdi->ops->generic_packet(cdi, &cgc))) + return ret; + + mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; + *write = mfd->write; + + if ((ret = cdrom_mrw_probe_pc(cdi))) + return ret; + + return 0; +} + +static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) +{ + struct cdrom_generic_command cgc; + unsigned char buffer[12]; + int ret; + + printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); + + /* + * FmtData bit set (bit 4), format type is 1 + */ + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); + cgc.cmd[0] = GPCMD_FORMAT_UNIT; + cgc.cmd[1] = (1 << 4) | 1; + + cgc.timeout = 5 * 60 * HZ; + + /* + * 4 byte format list header, 8 byte format list descriptor + */ + buffer[1] = 1 << 1; + buffer[3] = 8; + + /* + * nr_blocks field + */ + buffer[4] = 0xff; + buffer[5] = 0xff; + buffer[6] = 0xff; + buffer[7] = 0xff; + + buffer[8] = 0x24 << 2; + buffer[11] = cont; + + ret = cdi->ops->generic_packet(cdi, &cgc); + if (ret) + printk(KERN_INFO "cdrom: bgformat failed\n"); + + return ret; +} + +static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed) +{ + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_CLOSE_TRACK; + + /* + * Session = 1, Track = 0 + */ + cgc.cmd[1] = !!immed; + cgc.cmd[2] = 1 << 1; + + cgc.timeout = 5 * 60 * HZ; + + return cdi->ops->generic_packet(cdi, &cgc); +} + +static int cdrom_flush_cache(struct cdrom_device_info *cdi) +{ + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + + cgc.timeout = 5 * 60 * HZ; + + return cdi->ops->generic_packet(cdi, &cgc); +} + +static int cdrom_mrw_exit(struct cdrom_device_info *cdi) +{ + disc_information di; + int ret = 0; + + if (cdrom_get_disc_info(cdi, &di)) + return 1; + + if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { + printk(KERN_INFO "cdrom: issuing MRW back ground format suspend\n"); + ret = cdrom_mrw_bgformat_susp(cdi, 0); + } + + if (!ret) + ret = cdrom_flush_cache(cdi); + + return ret; +} + +static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) +{ + struct cdrom_generic_command cgc; + struct mode_page_header *mph; + char buffer[16]; + int ret, offset, size; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.buffer = buffer; + cgc.buflen = sizeof(buffer); + + if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) + return ret; + + mph = (struct mode_page_header *) buffer; + offset = be16_to_cpu(mph->desc_length); + size = be16_to_cpu(mph->mode_data_length) + 2; + + buffer[offset + 3] = space; + cgc.buflen = size; + + if ((ret = cdrom_mode_select(cdi, &cgc))) + return ret; + + printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); + return 0; +} + +static int cdrom_media_erasable(struct cdrom_device_info *cdi) +{ + disc_information di; + + if (cdrom_get_disc_info(cdi, &di)) + return 0; + + return di.erasable; +} + +/* + * FIXME: check RO bit + */ +static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi) +{ + return !cdrom_media_erasable(cdi); +} + +static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) +{ + disc_information di; + int ret; + + /* + * always reset to DMA lba space on open + */ + if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) { + printk(KERN_ERR "cdrom: failed setting lba address space\n"); + return 1; + } + + if (cdrom_get_disc_info(cdi, &di)) + return 1; + + if (!di.erasable) + return 1; + + /* + * mrw_status + * 0 - not MRW formatted + * 1 - MRW bgformat started, but not running or complete + * 2 - MRW bgformat in progress + * 3 - MRW formatting complete + */ + ret = 0; + printk(KERN_INFO "cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]); + if (!di.mrw_status) + ret = 1; + else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart) + ret = cdrom_mrw_bgformat(cdi, 1); + + return ret; +} + +/* + * returns 0 for ok to open write, non-0 to disallow + */ +static int cdrom_open_write(struct cdrom_device_info *cdi) +{ + int ret = 1; + + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) + ret = cdrom_dvdram_open_write(cdi); + /* + * needs to really check whether media is writeable + */ + else if (CDROM_CAN(CDC_MO_DRIVE)) + ret = 0; + + return ret; +} + +static int cdrom_close_write(struct cdrom_device_info *cdi) +{ +#if 0 + return cdrom_flush_cache(cdi); +#else + return 0; +#endif +} + /* We use the open-option O_NONBLOCK to indicate that the * purpose of opening is only for subsequent ioctl() calls; no device * integrity checks are performed. @@ -416,28 +734,35 @@ int unregister_cdrom(struct cdrom_device * is in their own interest: device control becomes a lot easier * this way. */ -int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) +int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, struct file *fp) { int ret; cdinfo(CD_OPEN, "entering cdrom_open\n"); + cdi->use_count++; + /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) ret = cdi->ops->open(cdi, 1); else { - if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM)) - return -EROFS; - + if (fp->f_mode & FMODE_WRITE) { + ret = -EROFS; + if (!CDROM_CAN(CDC_RAM)) + goto out; + if (cdrom_open_write(cdi)) + goto out; + } ret = open_for_data(cdi); } - if (!ret) cdi->use_count++; - cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count); /* Do this on open. Don't wait for mount, because they might not be mounting, but opening with O_NONBLOCK */ - check_disk_change(ip->i_bdev); + check_disk_change(bdev); +out: + if (ret) + cdi->use_count--; return ret; } @@ -525,11 +850,12 @@ int open_for_data(struct cdrom_device_in cdinfo(CD_OPEN, "open device failed.\n"); goto clean_up_and_return; } - if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { + if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) { cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); } cdinfo(CD_OPEN, "device opened successfully.\n"); + cdi->for_data = 1; return ret; /* Something failed. Try to unlock the drive, because some drivers @@ -603,32 +929,39 @@ int check_for_audio_disc(struct cdrom_de return 0; } - /* Admittedly, the logic below could be performed in a nicer way. */ -int cdrom_release(struct cdrom_device_info *cdi, struct file *fp) +int cdrom_release(struct cdrom_device_info *cdi) { struct cdrom_device_ops *cdo = cdi->ops; - int opened_for_data; cdinfo(CD_CLOSE, "entering cdrom_release\n"); if (cdi->use_count > 0) cdi->use_count--; - if (cdi->use_count == 0) - cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); - if (cdi->use_count == 0 && - cdo->capability & CDC_LOCK && !keeplocked) { + + if (cdi->use_count) { + cdo->release(cdi); + return 0; + } + + cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); + if ((cdo->capability & CDC_LOCK) && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); } - opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || - !(fp && fp->f_flags & O_NONBLOCK); + + /* + * flush cache on last write release + */ + if (CDROM_CAN(CDC_RAM) && !cdi->use_count && cdi->for_data) + cdrom_close_write(cdi); + cdo->release(cdi); - if (cdi->use_count == 0) { /* last process that closes dev*/ - if (opened_for_data && - cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) - cdo->tray_move(cdi, 1); - } + if (cdi->for_data && + cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) + cdo->tray_move(cdi, 1); + + cdi->for_data = 0; return 0; } @@ -1433,14 +1766,14 @@ static int cdrom_read_block(struct cdrom * these days. ATAPI / SCSI specific code now mainly resides in * mmc_ioct(). */ -int cdrom_ioctl(struct cdrom_device_info *cdi, struct inode *ip, +int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, unsigned int cmd, unsigned long arg) { struct cdrom_device_ops *cdo = cdi->ops; int ret; /* Try the generic SCSI command ioctl's first.. */ - ret = scsi_cmd_ioctl(ip->i_bdev, cmd, arg); + ret = scsi_cmd_ioctl(bdev, cmd, arg); if (ret != -ENOTTY) return ret; @@ -1593,7 +1926,7 @@ int cdrom_ioctl(struct cdrom_device_info cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); if (!CDROM_CAN(CDC_RESET)) return -ENOSYS; - invalidate_bdev(ip->i_bdev, 0); + invalidate_bdev(bdev, 0); return cdo->reset(cdi); } @@ -2203,7 +2536,6 @@ static int cdrom_get_disc_info(struct cd return cdo->generic_packet(cdi, &cgc); } - /* return the last written block on the CD-R media. this is for the udf file system. */ int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) @@ -2310,6 +2642,8 @@ EXPORT_SYMBOL(cdrom_number_of_slots); EXPORT_SYMBOL(cdrom_mode_select); EXPORT_SYMBOL(cdrom_mode_sense); EXPORT_SYMBOL(init_cdrom_command); +EXPORT_SYMBOL(cdrom_get_media_event); +EXPORT_SYMBOL(cdrom_is_mrw); #ifdef CONFIG_SYSCTL @@ -2406,6 +2740,14 @@ int cdrom_sysctl_info(ctl_table *ctl, in for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); + pos += sprintf(info+pos, "\nCan read MRW:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW) != 0); + + pos += sprintf(info+pos, "\nCan write MRW:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW_W) != 0); + strcpy(info+pos,"\n\n"); return proc_dostring(ctl, write, filp, buffer, lenp); --- linux-2.6.1-rc1/drivers/cdrom/cdu31a.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/cdu31a.c 2003-12-30 22:49:33.000000000 -0800 @@ -3167,20 +3167,20 @@ static struct cdrom_device_info scd_info .name = "cdu31a" }; -static int scd_block_open(struct inode *inode, struct file *file) +static int scd_block_open(struct block_device *bdev, struct file *file) { - return cdrom_open(&scd_info, inode, file); + return cdrom_open(&scd_info, bdev, file); } -static int scd_block_release(struct inode *inode, struct file *file) +static int scd_block_release(struct gendisk *disk) { - return cdrom_release(&scd_info, file); + return cdrom_release(&scd_info); } -static int scd_block_ioctl(struct inode *inode, struct file *file, +static int scd_block_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - return cdrom_ioctl(&scd_info, inode, cmd, arg); + return cdrom_ioctl(&scd_info, bdev, cmd, arg); } static int scd_block_media_changed(struct gendisk *disk) --- linux-2.6.1-rc1/drivers/cdrom/cm206.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/cm206.c 2003-12-30 22:49:33.000000000 -0800 @@ -1350,20 +1350,20 @@ static struct cdrom_device_info cm206_in .name = "cm206", }; -static int cm206_block_open(struct inode *inode, struct file *file) +static int cm206_block_open(struct block_device *bdev, struct file *file) { - return cdrom_open(&cm206_info, inode, file); + return cdrom_open(&cm206_info, bdev, file); } -static int cm206_block_release(struct inode *inode, struct file *file) +static int cm206_block_release(struct gendisk *disk) { - return cdrom_release(&cm206_info, file); + return cdrom_release(&cm206_info); } -static int cm206_block_ioctl(struct inode *inode, struct file *file, +static int cm206_block_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - return cdrom_ioctl(&cm206_info, inode, cmd, arg); + return cdrom_ioctl(&cm206_info, bdev, cmd, arg); } static int cm206_block_media_changed(struct gendisk *disk) --- linux-2.6.1-rc1/drivers/cdrom/gscd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/gscd.c 2003-12-30 22:49:33.000000000 -0800 @@ -91,10 +91,10 @@ static void gscd_bin2bcd(unsigned char * /* Schnittstellen zum Kern/FS */ static void __do_gscd_request(unsigned long dummy); -static int gscd_ioctl(struct inode *, struct file *, unsigned int, +static int gscd_ioctl(struct block_device *, struct file *, unsigned int, unsigned long); -static int gscd_open(struct inode *, struct file *); -static int gscd_release(struct inode *, struct file *); +static int gscd_open(struct block_device *, struct file *); +static int gscd_release(struct gendisk *disk); static int check_gscd_med_chg(struct gendisk *disk); /* GoldStar Funktionen */ @@ -190,8 +190,8 @@ __setup("gscd=", gscd_setup); #endif -static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, - unsigned long arg) +static int gscd_ioctl(struct block_device *bdev, struct file *fp, + unsigned int cmd, unsigned long arg) { unsigned char to_do[10]; unsigned char dummy; @@ -338,7 +338,7 @@ static void gscd_read_cmd(struct request * Open the device special file. Check that a disk is in. */ -static int gscd_open(struct inode *ip, struct file *fp) +static int gscd_open(struct block_device *bdev, struct file *fp) { int st; @@ -368,7 +368,7 @@ static int gscd_open(struct inode *ip, s * On close, we flush all gscd blocks from the buffer cache. */ -static int gscd_release(struct inode *inode, struct file *file) +static int gscd_release(struct gendisk *disk) { #ifdef GSCD_DEBUG --- linux-2.6.1-rc1/drivers/cdrom/mcd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/mcd.c 2003-12-30 22:49:33.000000000 -0800 @@ -214,20 +214,20 @@ static struct cdrom_device_info mcd_info .name = "mcd", }; -static int mcd_block_open(struct inode *inode, struct file *file) +static int mcd_block_open(struct block_device *bdev, struct file *file) { - return cdrom_open(&mcd_info, inode, file); + return cdrom_open(&mcd_info, bdev, file); } -static int mcd_block_release(struct inode *inode, struct file *file) +static int mcd_block_release(struct gendisk *disk) { - return cdrom_release(&mcd_info, file); + return cdrom_release(&mcd_info); } -static int mcd_block_ioctl(struct inode *inode, struct file *file, +static int mcd_block_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - return cdrom_ioctl(&mcd_info, inode, cmd, arg); + return cdrom_ioctl(&mcd_info, bdev, cmd, arg); } static int mcd_block_media_changed(struct gendisk *disk) --- linux-2.6.1-rc1/drivers/cdrom/mcdx.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/mcdx.c 2003-12-30 22:49:33.000000000 -0800 @@ -221,23 +221,23 @@ struct s_drive_stuff { int mcdx_init(void); void do_mcdx_request(request_queue_t * q); -static int mcdx_block_open(struct inode *inode, struct file *file) +static int mcdx_block_open(struct block_device *bdev, struct file *file) { - struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; - return cdrom_open(&p->info, inode, file); + struct s_drive_stuff *p = bdev->bd_disk->private_data; + return cdrom_open(&p->info, bdev, file); } -static int mcdx_block_release(struct inode *inode, struct file *file) +static int mcdx_block_release(struct gendisk *disk) { - struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; - return cdrom_release(&p->info, file); + struct s_drive_stuff *p = disk->private_data; + return cdrom_release(&p->info); } -static int mcdx_block_ioctl(struct inode *inode, struct file *file, +static int mcdx_block_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; - return cdrom_ioctl(&p->info, inode, cmd, arg); + struct s_drive_stuff *p = bdev->bd_disk->private_data; + return cdrom_ioctl(&p->info, bdev, cmd, arg); } static int mcdx_block_media_changed(struct gendisk *disk) --- linux-2.6.1-rc1/drivers/cdrom/optcd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/optcd.c 2003-12-30 22:49:33.000000000 -0800 @@ -1713,16 +1713,13 @@ static int cdromreset(void) /* VFS calls */ -static int opt_ioctl(struct inode *ip, struct file *fp, +static int opt_ioctl(struct block_device *bdev, struct file *fp, unsigned int cmd, unsigned long arg) { int status, err, retval = 0; DEBUG((DEBUG_VFS, "starting opt_ioctl")); - if (!ip) - return -EINVAL; - if (cmd == CDROMRESET) return cdromreset(); @@ -1844,7 +1841,7 @@ static int opt_ioctl(struct inode *ip, s static int open_count = 0; /* Open device special file; check that a disk is in. */ -static int opt_open(struct inode *ip, struct file *fp) +static int opt_open(struct block_device *bdev, struct file *fp) { DEBUG((DEBUG_VFS, "starting opt_open")); @@ -1904,13 +1901,12 @@ err_out: /* Release device special file; flush all blocks from the buffer cache */ -static int opt_release(struct inode *ip, struct file *fp) +static int opt_release(struct gendisk *disk) { int status; DEBUG((DEBUG_VFS, "executing opt_release")); - DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n", - ip, ip->i_bdev->bd_disk->disk_name, fp)); + DEBUG((DEBUG_VFS, "disk: %p, device: %s\n", disk, disk->disk_name)); if (!--open_count) { toc_uptodate = 0; --- linux-2.6.1-rc1/drivers/cdrom/sbpcd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/sbpcd.c 2003-12-30 22:49:33.000000000 -0800 @@ -5356,23 +5356,23 @@ static int sbp_data(struct request *req) } /*==========================================================================*/ -static int sbpcd_block_open(struct inode *inode, struct file *file) +static int sbpcd_block_open(struct block_device *bdev, struct file *file) { - struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; - return cdrom_open(p->sbpcd_infop, inode, file); + struct sbpcd_drive *p = bdev->bd_disk->private_data; + return cdrom_open(p->sbpcd_infop, bdev, file); } -static int sbpcd_block_release(struct inode *inode, struct file *file) +static int sbpcd_block_release(struct gendisk *disk) { - struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; - return cdrom_release(p->sbpcd_infop, file); + struct sbpcd_drive *p = disk->private_data; + return cdrom_release(p->sbpcd_infop); } -static int sbpcd_block_ioctl(struct inode *inode, struct file *file, +static int sbpcd_block_ioctl(struct block_device *bdev, struct file *file, unsigned cmd, unsigned long arg) { - struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; - return cdrom_ioctl(p->sbpcd_infop, inode, cmd, arg); + struct sbpcd_drive *p = bdev->bd_disk->private_data; + return cdrom_ioctl(p->sbpcd_infop, bdev, cmd, arg); } static int sbpcd_block_media_changed(struct gendisk *disk) --- linux-2.6.1-rc1/drivers/cdrom/sjcd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/sjcd.c 2003-12-30 22:49:33.000000000 -0800 @@ -713,16 +713,13 @@ static int sjcd_tray_open(void) /* * Do some user commands. */ -static int sjcd_ioctl(struct inode *ip, struct file *fp, +static int sjcd_ioctl(struct block_device *bdev, struct file *fp, unsigned int cmd, unsigned long arg) { #if defined( SJCD_TRACE ) printk("SJCD:ioctl\n"); #endif - if (ip == NULL) - return (-EINVAL); - sjcd_get_status(); if (!sjcd_status_valid) return (-EIO); @@ -1526,7 +1523,7 @@ static void do_sjcd_request(request_queu /* * Open the device special file. Check disk is in. */ -static int sjcd_open(struct inode *ip, struct file *fp) +static int sjcd_open(struct block_device *bdev, struct file *fp) { /* * Check the presence of device. @@ -1611,7 +1608,7 @@ static int sjcd_open(struct inode *ip, s /* * On close, we flush all sjcd blocks from the buffer cache. */ -static int sjcd_release(struct inode *inode, struct file *file) +static int sjcd_release(struct gendisk *disk) { int s; --- linux-2.6.1-rc1/drivers/cdrom/sonycd535.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/cdrom/sonycd535.c 2003-12-30 22:49:33.000000000 -0800 @@ -201,7 +201,7 @@ static int read_subcode(void); static void sony_get_toc(void); -static int cdu_open(struct inode *inode, struct file *filp); +static int cdu_open(struct block_device *bdev, struct file *filp); static inline unsigned int int_to_bcd(unsigned int val); static unsigned int bcd_to_int(unsigned int bcd); static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2], @@ -1061,7 +1061,7 @@ sony_get_subchnl_info(long arg) * The big ugly ioctl handler. */ static int -cdu_ioctl(struct inode *inode, +cdu_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) @@ -1360,9 +1360,7 @@ cdu_ioctl(struct inode *inode, * Open the drive for operations. Spin the drive up and read the table of * contents if these have not already been done. */ -static int -cdu_open(struct inode *inode, - struct file *filp) +static int cdu_open(struct block_device *bdev, struct file *filp) { Byte status[2], cmd_buff[2]; @@ -1385,7 +1383,7 @@ cdu_open(struct inode *inode, sony_inuse = 0; return -EIO; } - check_disk_change(inode->i_bdev); + check_disk_change(bdev); sony_usage++; #ifdef LOCK_DOORS @@ -1402,9 +1400,7 @@ cdu_open(struct inode *inode, * Close the drive. Spin it down if no task is using it. The spin * down will fail if playing audio, so audio play is OK. */ -static int -cdu_release(struct inode *inode, - struct file *filp) +static int cdu_release(struct gendisk *disk) { Byte status[2], cmd_no; --- linux-2.6.1-rc1/drivers/char/keyboard.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/char/keyboard.c 2003-12-30 22:49:25.000000000 -0800 @@ -1059,6 +1059,9 @@ void kbd_keycode(unsigned int keycode, i } if (sysrq_down && down && !rep) { handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); +#ifdef CONFIG_KGDB_SYSRQ + sysrq_down = 0; /* in case we miss the "up" event */ +#endif return; } #endif --- linux-2.6.1-rc1/drivers/char/mem.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/char/mem.c 2003-12-30 22:50:06.000000000 -0800 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ extern void fbmem_init(void); extern void tapechar_init(void); #endif +#ifdef pgprot_noncached /* * Architectures vary in how they handle caching for addresses * outside of main memory. @@ -65,19 +67,21 @@ static inline int uncached_access(struct && addr >= __pa(high_memory); #elif defined(CONFIG_IA64) /* - * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. + * On ia64, we ignore O_SYNC because we cannot tolerate memory + * attribute aliases. */ return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); #else /* - * Accessing memory above the top the kernel knows about or through a file pointer - * that was marked O_SYNC will be done non-cached. + * Accessing memory above the top the kernel knows about or through a + * file pointer that was marked O_SYNC will be done non-cached. */ if (file->f_flags & O_SYNC) return 1; return addr >= __pa(high_memory); #endif } +#endif /* pgprot_noncached */ #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE static inline int valid_phys_addr_range(unsigned long addr, size_t *count) @@ -167,28 +171,24 @@ static ssize_t write_mem(struct file * f return do_write_mem(file, __va(p), p, buf, count, ppos); } -static int mmap_mem(struct file * file, struct vm_area_struct * vma) +static int mmap_mem(struct file *file, struct vm_area_struct *vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int uncached; - uncached = uncached_access(file, offset); #ifdef pgprot_noncached - if (uncached) + if (uncached_access(file, offset)) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #endif - /* Don't try to swap out physical pages.. */ - vma->vm_flags |= VM_RESERVED; - /* - * Don't dump addresses that are not real memory to a core file. + * Don't try to swap out physical pages.. + * And treat /dev/mem mappings as "IO" regions: they may not + * describe valid pageframes. */ - if (uncached) - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED|VM_IO; - if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start, - vma->vm_page_prot)) + if (remap_page_range(vma, vma->vm_start, offset, + vma->vm_end-vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; } @@ -676,6 +676,10 @@ static const struct { {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, }; +static struct class mem_class = { + .name = "mem", +}; + static int __init chr_dev_init(void) { int i; @@ -683,7 +687,11 @@ static int __init chr_dev_init(void) if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); + class_register(&mem_class); for (i = 0; i < ARRAY_SIZE(devlist); i++) { + simple_add_class_device(&mem_class, + MKDEV(MEM_MAJOR, devlist[i].minor), + NULL, devlist[i].name); devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), S_IFCHR | devlist[i].mode, devlist[i].name); } --- linux-2.6.1-rc1/drivers/char/misc.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/char/misc.c 2003-12-30 22:50:06.000000000 -0800 @@ -47,7 +47,7 @@ #include #include #include - +#include #include #include @@ -180,6 +180,15 @@ fail: return err; } +/* + * TODO for 2.7: + * - add a struct class_device to struct miscdevice and make all usages of + * them dynamic. + */ +static struct class misc_class = { + .name = "misc", +}; + static struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, @@ -234,6 +243,8 @@ int misc_register(struct miscdevice * mi "misc/%s", misc->name); } + simple_add_class_device(&misc_class, MKDEV(MISC_MAJOR, misc->minor), + misc->dev, misc->name); devfs_mk_cdev(MKDEV(MISC_MAJOR, misc->minor), S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name); @@ -265,6 +276,7 @@ int misc_deregister(struct miscdevice * down(&misc_sem); list_del(&misc->list); + simple_remove_class_device(MKDEV(MISC_MAJOR, misc->minor)); devfs_remove(misc->devfs_name); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); @@ -285,6 +297,7 @@ static int __init misc_init(void) if (ent) ent->proc_fops = &misc_proc_fops; #endif + class_register(&misc_class); #ifdef CONFIG_MVME16x rtc_MK48T08_init(); #endif @@ -319,4 +332,4 @@ static int __init misc_init(void) } return 0; } -module_init(misc_init); +subsys_initcall(misc_init); --- linux-2.6.1-rc1/drivers/char/pcmcia/synclink_cs.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/char/pcmcia/synclink_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -244,7 +244,6 @@ typedef struct _mgslpc_info { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } MGSLPC_INFO; @@ -592,7 +591,7 @@ static dev_link_t *mgslpc_attach(void) client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); mgslpc_detach(link); @@ -607,8 +606,8 @@ static dev_link_t *mgslpc_attach(void) /* Card has been inserted. */ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void mgslpc_config(dev_link_t *link) { @@ -631,9 +630,9 @@ static void mgslpc_config(dev_link_t *li tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -641,17 +640,17 @@ static void mgslpc_config(dev_link_t *li link->state |= DEV_CONFIG; /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* get CIS configuration entry */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); cfg = &(parse.cftable_entry); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) @@ -672,7 +671,7 @@ static void mgslpc_config(dev_link_t *li link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; - CS_CHECK(RequestIO, link->handle, &link->io); + CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); } link->conf.Attributes = CONF_ENABLE_IRQ; @@ -684,9 +683,9 @@ static void mgslpc_config(dev_link_t *li link->irq.Attributes |= IRQ_HANDLE_PRESENT; link->irq.Handler = mgslpc_isr; link->irq.Instance = info; - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); info->io_base = link->io.BasePort1; info->irq_level = link->irq.AssignedIRQ; @@ -728,11 +727,11 @@ static void mgslpc_release(u_long arg) link->dev = NULL; link->state &= ~DEV_CONFIG; - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_irq(link->handle, &link->irq); if (link->state & DEV_STALE_LINK) mgslpc_detach(link); } @@ -763,7 +762,7 @@ static void mgslpc_detach(dev_link_t *li /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, and free it */ *linkp = link->next; @@ -798,14 +797,14 @@ static int mgslpc_event(event_t event, i /* Mark the device as stopped, to block IO until later */ info->stop = 1; if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); info->stop = 0; break; } @@ -4206,35 +4205,46 @@ void tx_timeout(unsigned long context) #ifdef CONFIG_SYNCLINK_SYNCPPP /* syncppp net device routines */ + +static void mgslpc_setup(struct net_device *dev) +{ + dev->open = mgslpc_sppp_open; + dev->stop = mgslpc_sppp_close; + dev->hard_start_xmit = mgslpc_sppp_tx; + dev->do_ioctl = mgslpc_sppp_ioctl; + dev->get_stats = mgslpc_net_stats; + dev->tx_timeout = mgslpc_sppp_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} void mgslpc_sppp_init(MGSLPC_INFO *info) { struct net_device *d; sprintf(info->netname,"mgslp%d",info->line); + + d = alloc_netdev(0, info->netname, mgslpc_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->priv = info; - d->init = NULL; - d->open = mgslpc_sppp_open; - d->stop = mgslpc_sppp_close; - d->hard_start_xmit = mgslpc_sppp_tx; - d->do_ioctl = mgslpc_sppp_ioctl; - d->get_stats = mgslpc_net_stats; - d->tx_timeout = mgslpc_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; + free_netdev(d); return; } @@ -4246,8 +4256,11 @@ void mgslpc_sppp_delete(MGSLPC_INFO *inf { if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } int mgslpc_sppp_open(struct net_device *d) --- linux-2.6.1-rc1/drivers/char/raw.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/char/raw.c 2003-12-30 22:49:34.000000000 -0800 @@ -74,6 +74,7 @@ static int raw_open(struct inode *inode, goto out; } filp->f_flags |= O_DIRECT; + filp->f_mapping = bdev->bd_inode->i_mapping; if (++raw_devices[minor].inuse == 1) filp->f_dentry->d_inode->i_mapping = bdev->bd_inode->i_mapping; --- linux-2.6.1-rc1/drivers/char/sn_serial.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/drivers/char/sn_serial.c 2003-12-30 22:49:45.000000000 -0800 @@ -21,8 +21,9 @@ #include #include #include +#include #include -#include /* this is needed for get_console_nasid */ +#include #include #include @@ -771,7 +772,7 @@ sn_sal_read_proc(char *page, char **star off_t begin = 0; len += sprintf(page, "sn_serial: nasid:%d irq:%d tx:%d rx:%d\n", - get_console_nasid(), sn_sal_irq, + (int)ia64_sn_get_console_nasid(), sn_sal_irq, sn_total_tx_count, sn_total_rx_count); *eof = 1; @@ -813,13 +814,18 @@ sn_sal_switch_to_asynch(void) { unsigned long flags; - sn_debug_printf("sn_serial: about to switch to asynchronous console\n"); - /* without early_printk, we may be invoked late enough to race * with other cpus doing console IO at this point, however * console interrupts will never be enabled */ spin_lock_irqsave(&sn_sal_lock, flags); + if (sn_sal_is_asynch) { + spin_unlock_irqrestore(&sn_sal_lock, flags); + return; + } + + sn_debug_printf("sn_serial: switch to asynchronous console\n"); + /* early_printk invocation may have done this for us */ if (!sn_func) { if (IS_RUNNING_ON_SIMULATOR()) @@ -901,8 +907,7 @@ sn_sal_module_init(void) /* when this driver is compiled in, the console initialization * will have already switched us into asynchronous operation * before we get here through the module initcalls */ - if (!sn_sal_is_asynch) - sn_sal_switch_to_asynch(); + sn_sal_switch_to_asynch(); /* at this point (module_init) we can try to turn on interrupts */ if (!IS_RUNNING_ON_SIMULATOR()) --- linux-2.6.1-rc1/drivers/char/synclink.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/char/synclink.c 2003-12-30 22:49:19.000000000 -0800 @@ -327,7 +327,6 @@ struct mgsl_struct { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif }; @@ -737,8 +736,8 @@ int mgsl_ioctl_common(struct mgsl_struct #ifdef CONFIG_SYNCLINK_SYNCPPP /* SPPP/HDLC stuff */ -void mgsl_sppp_init(struct mgsl_struct *info); -void mgsl_sppp_delete(struct mgsl_struct *info); +static void mgsl_sppp_init(struct mgsl_struct *info); +static void mgsl_sppp_delete(struct mgsl_struct *info); int mgsl_sppp_open(struct net_device *d); int mgsl_sppp_close(struct net_device *d); void mgsl_sppp_tx_timeout(struct net_device *d); @@ -7820,36 +7819,45 @@ int usc_loopmode_send_active( struct mgs #ifdef CONFIG_SYNCLINK_SYNCPPP /* syncppp net device routines */ +static void mgsl_setup(struct net_device *dev) +{ + dev->open = mgsl_sppp_open; + dev->stop = mgsl_sppp_close; + dev->hard_start_xmit = mgsl_sppp_tx; + dev->do_ioctl = mgsl_sppp_ioctl; + dev->get_stats = mgsl_net_stats; + dev->tx_timeout = mgsl_sppp_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} -void mgsl_sppp_init(struct mgsl_struct *info) +static void mgsl_sppp_init(struct mgsl_struct *info) { struct net_device *d; sprintf(info->netname,"mgsl%d",info->line); + d = alloc_netdev(0, info->netname, mgsl_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } + info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->dma = info->dma_level; d->priv = info; - d->init = NULL; - d->open = mgsl_sppp_open; - d->stop = mgsl_sppp_close; - d->hard_start_xmit = mgsl_sppp_tx; - d->do_ioctl = mgsl_sppp_ioctl; - d->get_stats = mgsl_net_stats; - d->tx_timeout = mgsl_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + free_netdev(d); return; } @@ -7861,8 +7869,11 @@ void mgsl_sppp_delete(struct mgsl_struct { if (debug_level >= DEBUG_LEVEL_INFO) printk("mgsl_sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } int mgsl_sppp_open(struct net_device *d) --- linux-2.6.1-rc1/drivers/char/synclinkmp.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/char/synclinkmp.c 2003-12-30 22:49:19.000000000 -0800 @@ -289,7 +289,6 @@ typedef struct _synclinkmp_info { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } SLMP_INFO; @@ -1627,35 +1626,44 @@ static void set_break(struct tty_struct /* syncppp support and callbacks */ +static void cb_setup(struct net_device *dev) +{ + dev->open = sppp_cb_open; + dev->stop = sppp_cb_close; + dev->hard_start_xmit = sppp_cb_tx; + dev->do_ioctl = sppp_cb_ioctl; + dev->get_stats = sppp_cb_net_stats; + dev->tx_timeout = sppp_cb_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} + static void sppp_init(SLMP_INFO *info) { struct net_device *d; sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num); + d = alloc_netdev(0, info->netname, cb_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } + info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); - d->base_addr = 0; d->irq = info->irq_level; - d->dma = 0; d->priv = info; - d->init = NULL; - d->open = sppp_cb_open; - d->stop = sppp_cb_close; - d->hard_start_xmit = sppp_cb_tx; - d->do_ioctl = sppp_cb_ioctl; - d->get_stats = sppp_cb_net_stats; - d->tx_timeout = sppp_cb_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; + free_netdev(d); return; } @@ -1667,8 +1675,11 @@ static void sppp_delete(SLMP_INFO *info) { if (debug_level >= DEBUG_LEVEL_INFO) printk("sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } static int sppp_cb_open(struct net_device *d) --- linux-2.6.1-rc1/drivers/char/sysrq.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/char/sysrq.c 2003-12-30 22:49:25.000000000 -0800 @@ -35,6 +35,25 @@ #include #include +#ifdef CONFIG_KGDB_SYSRQ + +#define GDB_OP &kgdb_op +static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +{ + printk("kgdb sysrq\n"); + breakpoint(); +} + +static struct sysrq_key_op kgdb_op = { + .handler = kgdb_sysrq, + .help_msg = "kGdb|Fgdb", + .action_msg = "Debug breakpoint\n", +}; + +#else +#define GDB_OP NULL +#endif + extern void reset_vc(unsigned int); @@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta /* c */ NULL, /* d */ NULL, /* e */ &sysrq_term_op, -/* f */ NULL, -/* g */ NULL, +/* f */ GDB_OP, +/* g */ GDB_OP, /* h */ NULL, /* i */ &sysrq_kill_op, /* j */ NULL, --- linux-2.6.1-rc1/drivers/char/tty_io.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/drivers/char/tty_io.c 2003-12-30 22:50:06.000000000 -0800 @@ -2069,80 +2069,10 @@ static void tty_default_put_char(struct tty->driver->write(tty, 0, &ch, 1); } -struct tty_dev { - struct list_head node; - dev_t dev; - struct class_device class_dev; -}; -#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) - -static void release_tty_dev(struct class_device *class_dev) -{ - struct tty_dev *tty_dev = to_tty_dev(class_dev); - kfree(tty_dev); -} - static struct class tty_class = { - .name = "tty", - .release = &release_tty_dev, + .name = "tty", }; -static LIST_HEAD(tty_dev_list); -static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; - -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - struct tty_dev *tty_dev = to_tty_dev(class_dev); - return print_dev_t(buf, tty_dev->dev); -} -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - -static void tty_add_class_device(char *name, dev_t dev, struct device *device) -{ - struct tty_dev *tty_dev = NULL; - int retval; - - tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL); - if (!tty_dev) - return; - memset(tty_dev, 0x00, sizeof(*tty_dev)); - - tty_dev->class_dev.dev = device; - tty_dev->class_dev.class = &tty_class; - snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", name); - retval = class_device_register(&tty_dev->class_dev); - if (retval) - goto error; - class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev); - tty_dev->dev = dev; - spin_lock(&tty_dev_list_lock); - list_add(&tty_dev->node, &tty_dev_list); - spin_unlock(&tty_dev_list_lock); - return; -error: - kfree(tty_dev); -} - -static void tty_remove_class_device(dev_t dev) -{ - struct tty_dev *tty_dev = NULL; - struct list_head *tmp; - int found = 0; - - spin_lock(&tty_dev_list_lock); - list_for_each (tmp, &tty_dev_list) { - tty_dev = list_entry(tmp, struct tty_dev, node); - if (tty_dev->dev == dev) { - list_del(&tty_dev->node); - found = 1; - break; - } - } - spin_unlock(&tty_dev_list_lock); - if (found) - class_device_unregister(&tty_dev->class_dev); -} - /** * tty_register_device - register a tty device * @driver: the tty driver that describes the tty device @@ -2174,7 +2104,7 @@ void tty_register_device(struct tty_driv if (driver->type != TTY_DRIVER_TYPE_PTY) { char name[64]; tty_line_name(driver, index, name); - tty_add_class_device(name, dev, device); + simple_add_class_device(&tty_class, dev, device, name); } } @@ -2189,7 +2119,7 @@ void tty_register_device(struct tty_driv void tty_unregister_device(struct tty_driver *driver, unsigned index) { devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); - tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index); + simple_remove_class_device(MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -2431,7 +2361,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL); + simple_add_class_device(&tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); strcpy(console_cdev.kobj.name, "dev.console"); cdev_init(&console_cdev, &console_fops); @@ -2439,7 +2369,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL); + simple_add_class_device(&tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); tty_kobj.kset = tty_cdev.kobj.kset; kobject_register(&tty_kobj); @@ -2451,7 +2381,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - tty_add_class_device ("ptmx", MKDEV(TTYAUX_MAJOR, 2), NULL); + simple_add_class_device(&tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -2461,7 +2391,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - tty_add_class_device ("tty0", MKDEV(TTY_MAJOR, 0), NULL); + simple_add_class_device(&tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif --- linux-2.6.1-rc1/drivers/char/vc_screen.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/char/vc_screen.c 2003-12-30 22:50:06.000000000 -0800 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -469,6 +470,10 @@ static struct file_operations vcs_fops = .open = vcs_open, }; +static struct class vc_class = { + .name = "vc", +}; + void vcs_make_devfs(struct tty_struct *tty) { devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1), @@ -477,19 +482,26 @@ void vcs_make_devfs(struct tty_struct *t devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a%u", tty->index + 1); + simple_add_class_device(&vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); + simple_add_class_device(&vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); } void vcs_remove_devfs(struct tty_struct *tty) { devfs_remove("vcc/%u", tty->index + 1); devfs_remove("vcc/a%u", tty->index + 1); + simple_remove_class_device(MKDEV(VCS_MAJOR, tty->index + 1)); + simple_remove_class_device(MKDEV(VCS_MAJOR, tty->index + 129)); } int __init vcs_init(void) { if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) panic("unable to get major %d for vcs device", VCS_MAJOR); + class_register(&vc_class); devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); + simple_add_class_device(&vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + simple_add_class_device(&vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; } --- linux-2.6.1-rc1/drivers/char/vt.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/char/vt.c 2003-12-30 22:50:07.000000000 -0800 @@ -2539,6 +2539,8 @@ static struct tty_operations con_ops = { int __init vty_init(void) { + vcs_init(); + console_driver = alloc_tty_driver(MAX_NR_CONSOLES); if (!console_driver) panic("Couldn't allocate console driver\n"); @@ -2566,7 +2568,6 @@ int __init vty_init(void) #ifdef CONFIG_FRAMEBUFFER_CONSOLE fb_console_init(); #endif - vcs_init(); return 0; } --- linux-2.6.1-rc1/drivers/ide/ide.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/ide/ide.c 2003-12-30 22:49:31.000000000 -0800 @@ -458,7 +458,7 @@ void ide_probe_module (void) EXPORT_SYMBOL(ide_probe_module); -static int ide_open (struct inode * inode, struct file * filp) +static int ide_open (struct block_device *bdev, struct file * filp) { return -ENXIO; } --- linux-2.6.1-rc1/drivers/ide/ide-cd.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/ide/ide-cd.c 2003-12-30 22:50:00.000000000 -0800 @@ -291,10 +291,13 @@ * - Use extended sense on drives that support it for * correctly reporting tray status -- from * Michael D Johnson + * 4.60 Dec 17, 2003 - Add mt rainier support + * - Bump timeout for packet commands, matches sr + * - Odd stuff * *************************************************************************/ -#define IDECD_VERSION "4.59-ac1" +#define IDECD_VERSION "4.60" #include #include @@ -774,11 +777,36 @@ static int cdrom_decode_status(ide_drive if (sense_key == NOT_READY) { /* Tray open. */ - cdrom_saw_media_change (drive); + if (rq_data_dir(rq) == READ) { + cdrom_saw_media_change (drive); - /* Fail the request. */ - printk ("%s: tray open\n", drive->name); - do_end_request = 1; + /* Fail the request. */ + printk ("%s: tray open\n", drive->name); + do_end_request = 1; + } else { + struct cdrom_info *info = drive->driver_data; + + /* allow the drive 5 seconds to recover, some + * devices will return this error while flushing + * data from cache */ + if (!rq->errors) + info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY; + rq->errors = 1; + if (time_after(jiffies, info->write_timeout)) + do_end_request = 1; + else { + unsigned long flags; + + /* + * take a breather relying on the + * unplug timer to kick us again + */ + spin_lock_irqsave(&ide_lock, flags); + blk_plug_device(drive->queue); + spin_unlock_irqrestore(&ide_lock,flags); + return 1; + } + } } else if (sense_key == UNIT_ATTENTION) { /* Media change. */ cdrom_saw_media_change (drive); @@ -844,9 +872,13 @@ static int cdrom_timer_expiry(ide_drive_ case GPCMD_BLANK: case GPCMD_FORMAT_UNIT: case GPCMD_RESERVE_RZONE_TRACK: - wait = WAIT_CMD; + case GPCMD_CLOSE_TRACK: + case GPCMD_FLUSH_CACHE: + wait = ATAPI_WAIT_PC; break; default: + if (!(rq->flags & REQ_QUIET)) + printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]); wait = 0; break; } @@ -894,7 +926,7 @@ static ide_startstop_t cdrom_start_packe if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* packet command */ - ide_execute_command(drive, WIN_PACKETCMD, handler, WAIT_CMD, cdrom_timer_expiry); + ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } else { /* packet command */ @@ -1167,7 +1199,7 @@ static ide_startstop_t cdrom_read_intr ( } /* Done moving data! Wait for another interrupt. */ - ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); + ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL); return ide_started; } @@ -1277,7 +1309,7 @@ static ide_startstop_t cdrom_start_read_ (65534 / CD_FRAMESIZE) : 65535); /* Set up the command */ - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr); @@ -1286,7 +1318,7 @@ static ide_startstop_t cdrom_start_read_ #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ #define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ -#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ +#define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) { @@ -1326,7 +1358,7 @@ static ide_startstop_t cdrom_start_seek_ rq->cmd[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]); - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr); } @@ -1502,7 +1534,7 @@ confused: } /* Now we wait for another interrupt. */ - ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); + ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } @@ -1511,7 +1543,7 @@ static ide_startstop_t cdrom_do_pc_conti struct request *rq = HWGROUP(drive)->rq; if (!rq->timeout) - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr); @@ -1716,11 +1748,8 @@ static ide_startstop_t cdrom_newpc_intr( /* * If DRQ is clear, the command has completed. */ - if ((stat & DRQ_STAT) == 0) { - if (rq->data_len) - printk("%s: %u residual after xfer\n", __FUNCTION__, rq->data_len); + if ((stat & DRQ_STAT) == 0) goto end_request; - } /* * check which way to transfer data @@ -1826,10 +1855,8 @@ static ide_startstop_t cdrom_write_intr( } } - if (cdrom_decode_status(drive, 0, &stat)) { - printk("ide-cd: write_intr decode_status bad\n"); + if (cdrom_decode_status(drive, 0, &stat)) return ide_stopped; - } /* * using dma, transfer is complete now @@ -1904,7 +1931,7 @@ static ide_startstop_t cdrom_write_intr( } /* re-arm handler */ - ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); + ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL); return ide_started; } @@ -1915,7 +1942,7 @@ static ide_startstop_t cdrom_start_write #if 0 /* the immediate bit */ rq->cmd[1] = 1 << 3; #endif - rq->timeout = 2 * WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr); } @@ -1956,7 +1983,7 @@ static ide_startstop_t cdrom_do_newpc_co struct request *rq = HWGROUP(drive)->rq; if (!rq->timeout) - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr); } @@ -2242,6 +2269,7 @@ static int cdrom_read_toc(ide_drive_t *d struct atapi_toc_header hdr; struct atapi_toc_entry ent; } ms_tmp; + long last_written; if (toc == NULL) { /* Try to allocate space. */ @@ -2261,6 +2289,13 @@ static int cdrom_read_toc(ide_drive_t *d if (CDROM_STATE_FLAGS(drive)->toc_valid) return 0; + /* Try to get the total cdrom capacity. */ + stat = cdrom_read_capacity(drive, &toc->capacity, sense); + if (stat) + toc->capacity = 0x1fffff; + + set_capacity(drive->disk, toc->capacity * SECTORS_PER_FRAME); + /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, sizeof(struct atapi_toc_header), sense); @@ -2368,13 +2403,11 @@ static int cdrom_read_toc(ide_drive_t *d toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); /* Now try to get the total cdrom capacity. */ - stat = cdrom_get_last_written(cdi, (long *) &toc->capacity); - if (stat || !toc->capacity) - stat = cdrom_read_capacity(drive, &toc->capacity, sense); - if (stat) - toc->capacity = 0x1fffff; - - set_capacity(drive->disk, toc->capacity * SECTORS_PER_FRAME); + stat = cdrom_get_last_written(cdi, &last_written); + if (!stat && last_written) { + toc->capacity = last_written; + set_capacity(drive->disk, toc->capacity * SECTORS_PER_FRAME); + } /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS(drive)->toc_valid = 1; @@ -2483,7 +2516,7 @@ static int ide_cdrom_packet(struct cdrom ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (cgc->timeout <= 0) - cgc->timeout = WAIT_CMD; + cgc->timeout = ATAPI_WAIT_PC; /* here we queue the commands from the uniform CD-ROM layer. the packet must be complete, as we do not @@ -2688,37 +2721,49 @@ int ide_cdrom_select_speed (struct cdrom return 0; } +/* + * add logic to try GET_EVENT command first to check for media and tray + * status. this should be supported by newer cd-r/w and all DVD etc + * drives + */ static int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct media_event_desc med; + struct request_sense sense; + int stat; - if (slot_nr == CDSL_CURRENT) { - struct request_sense sense; - int stat = cdrom_check_status(drive, &sense); - if (stat == 0 || sense.sense_key == UNIT_ATTENTION) - return CDS_DISC_OK; + if (slot_nr != CDSL_CURRENT) + return -EINVAL; - if (sense.sense_key == NOT_READY && sense.asc == 0x04 && - sense.ascq == 0x04) - return CDS_DISC_OK; + stat = cdrom_check_status(drive, &sense); + if (!stat || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; + if (!cdrom_get_media_event(cdi, &med)) { + if (med.media_present) + return CDS_DISC_OK; + if (med.door_open) + return CDS_TRAY_OPEN; + } - /* - * If not using Mt Fuji extended media tray reports, - * just return TRAY_OPEN since ATAPI doesn't provide - * any other way to detect this... - */ - if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a && sense.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; - } + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04) + return CDS_DISC_OK; - return CDS_DRIVE_NOT_READY; + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ + if (sense.sense_key == NOT_READY) { + if (sense.asc == 0x3a && sense.ascq == 1) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; } - return -EINVAL; + + return CDS_DRIVE_NOT_READY; } static @@ -2826,7 +2871,8 @@ static struct cdrom_device_ops ide_cdrom CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM | - CDC_GENERIC_PACKET | CDC_MO_DRIVE, + CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW | + CDC_MRW_W | CDC_RAM, .generic_packet = ide_cdrom_packet, }; @@ -2861,6 +2907,10 @@ static int ide_cdrom_register (ide_drive devinfo->mask |= CDC_CLOSE_TRAY; if (!CDROM_CONFIG_FLAGS(drive)->mo_drive) devinfo->mask |= CDC_MO_DRIVE; + if (!CDROM_CONFIG_FLAGS(drive)->mrw) + devinfo->mask |= CDC_MRW; + if (!CDROM_CONFIG_FLAGS(drive)->mrw_w) + devinfo->mask |= CDC_MRW_W; return register_cdrom(devinfo); } @@ -2881,14 +2931,6 @@ int ide_cdrom_get_capabilities(ide_drive !strcmp(drive->id->model, "WPI CDS-32X"))) size -= sizeof(cap->pad); - /* we have to cheat a little here. the packet will eventually - * be queued with ide_cdrom_packet(), which extracts the - * drive from cdi->handle. Since this device hasn't been - * registered with the Uniform layer yet, it can't do this. - * Same goes for cdi->ops. - */ - cdi->handle = (ide_drive_t *) drive; - cdi->ops = &ide_cdrom_dops; init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN); do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); @@ -2904,23 +2946,43 @@ int ide_cdrom_probe_capabilities (ide_dr struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; struct atapi_capabilities_page cap; - int nslots = 1; + int nslots = 1, mrw_write = 0; if (drive->media == ide_optical) { CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; + CDROM_CONFIG_FLAGS(drive)->ram = 1; printk("%s: ATAPI magneto-optical drive\n", drive->name); return nslots; } - if (CDROM_CONFIG_FLAGS(drive)->nec260) { - CDROM_CONFIG_FLAGS(drive)->no_eject = 0; - CDROM_CONFIG_FLAGS(drive)->audio_play = 1; + if (CDROM_CONFIG_FLAGS(drive)->nec260 || + !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) { + CDROM_CONFIG_FLAGS(drive)->no_eject = 0; + CDROM_CONFIG_FLAGS(drive)->audio_play = 1; return nslots; } + /* + * we have to cheat a little here. the packet will eventually + * be queued with ide_cdrom_packet(), which extracts the + * drive from cdi->handle. Since this device hasn't been + * registered with the Uniform layer yet, it can't do this. + * Same goes for cdi->ops. + */ + cdi->handle = (ide_drive_t *) drive; + cdi->ops = &ide_cdrom_dops; + if (ide_cdrom_get_capabilities(drive, &cap)) return 0; + if (!cdrom_is_mrw(cdi, &mrw_write)) { + CDROM_CONFIG_FLAGS(drive)->mrw = 1; + if (mrw_write) { + CDROM_CONFIG_FLAGS(drive)->mrw_w = 1; + CDROM_CONFIG_FLAGS(drive)->ram = 1; + } + } + if (cap.lock == 0) CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; if (cap.eject) @@ -2933,8 +2995,10 @@ int ide_cdrom_probe_capabilities (ide_dr CDROM_CONFIG_FLAGS(drive)->test_write = 1; if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) CDROM_CONFIG_FLAGS(drive)->dvd = 1; - if (cap.dvd_ram_write) + if (cap.dvd_ram_write) { CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1; + CDROM_CONFIG_FLAGS(drive)->ram = 1; + } if (cap.dvd_r_write) CDROM_CONFIG_FLAGS(drive)->dvd_r = 1; if (cap.audio_play) @@ -2998,6 +3062,9 @@ int ide_cdrom_probe_capabilities (ide_dr (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : ""); + if (CDROM_CONFIG_FLAGS(drive)->mrw || CDROM_CONFIG_FLAGS(drive)->mrw_w) + printk(" CD-MR%s", CDROM_CONFIG_FLAGS(drive)->mrw_w ? "W" : ""); + if (CDROM_CONFIG_FLAGS(drive)->is_changer) printk(" changer w/%d slots", nslots); else @@ -3105,14 +3172,11 @@ int ide_cdrom_setup (ide_drive_t *drive) struct cdrom_device_info *cdi = &info->devinfo; int nslots; - /* - * default to read-only always and fix latter at the bottom - */ - set_disk_ro(drive->disk, 1); - blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE); - blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn); blk_queue_dma_alignment(drive->queue, 3); + drive->queue->unplug_delay = (1 * HZ) / 1000; + if (!drive->queue->unplug_delay) + drive->queue->unplug_delay = 1; drive->special.all = 0; drive->ready_stat = 0; @@ -3215,8 +3279,11 @@ int ide_cdrom_setup (ide_drive_t *drive) nslots = ide_cdrom_probe_capabilities (drive); - if (CDROM_CONFIG_FLAGS(drive)->dvd_ram) - set_disk_ro(drive->disk, 0); + /* + * set correct block size and read-only for non-ram media + */ + set_disk_ro(drive->disk, !CDROM_CONFIG_FLAGS(drive)->ram); + blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE); #if 0 drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1; @@ -3335,9 +3402,9 @@ static ide_driver_t ide_cdrom_driver = { .complete_power_step = ide_cdrom_complete_power_step, }; -static int idecd_open(struct inode * inode, struct file * file) +static int idecd_open(struct block_device *bdev, struct file * file) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = bdev->bd_disk->private_data; struct cdrom_info *info = drive->driver_data; int rc = -ENOMEM; drive->usage++; @@ -3345,30 +3412,29 @@ static int idecd_open(struct inode * ino if (!info->buffer) info->buffer = kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL|__GFP_REPEAT); - if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file))) + if (!info->buffer || (rc = cdrom_open(&info->devinfo, bdev, file))) drive->usage--; return rc; } -static int idecd_release(struct inode * inode, struct file * file) +static int idecd_release(struct gendisk *disk) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = disk->private_data; struct cdrom_info *info = drive->driver_data; - cdrom_release (&info->devinfo, file); + cdrom_release(&info->devinfo); drive->usage--; return 0; } -static int idecd_ioctl (struct inode *inode, struct file *file, +static int idecd_ioctl (struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; ide_drive_t *drive = bdev->bd_disk->private_data; int err = generic_ide_ioctl(bdev, cmd, arg); if (err == -EINVAL) { struct cdrom_info *info = drive->driver_data; - err = cdrom_ioctl(&info->devinfo, inode, cmd, arg); + err = cdrom_ioctl(&info->devinfo, bdev, cmd, arg); } return err; } --- linux-2.6.1-rc1/drivers/ide/ide-cd.h 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/ide/ide-cd.h 2003-12-30 22:50:00.000000000 -0800 @@ -35,6 +35,12 @@ #define NO_DOOR_LOCKING 0 #endif +/* + * typical timeout for packet command + */ +#define ATAPI_WAIT_PC (60 * HZ) +#define ATAPI_WAIT_WRITE_BUSY (10 * HZ) + /************************************************************************/ #define SECTOR_BITS 9 @@ -75,6 +81,9 @@ struct ide_cd_config_flags { __u8 dvd : 1; /* Drive is a DVD-ROM */ __u8 dvd_r : 1; /* Drive can write DVD-R */ __u8 dvd_ram : 1; /* Drive can write DVD-RAM */ + __u8 mrw : 1; /* drive can read mrw */ + __u8 mrw_w : 1; /* drive can write mrw */ + __u8 ram : 1; /* generic WRITE (dvd-ram/mrw) */ __u8 test_write : 1; /* Drive can fake writes */ __u8 supp_disc_present : 1; /* Changer can report exact contents of slots. */ @@ -482,6 +491,8 @@ struct cdrom_info { /* Per-device info needed by cdrom.c generic driver. */ struct cdrom_device_info devinfo; + + unsigned long write_timeout; }; /**************************************************************************** --- linux-2.6.1-rc1/drivers/ide/ide-disk.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/ide/ide-disk.c 2003-12-30 22:49:33.000000000 -0800 @@ -1734,9 +1734,9 @@ static ide_driver_t idedisk_driver = { .complete_power_step = idedisk_complete_power_step, }; -static int idedisk_open(struct inode *inode, struct file *filp) +static int idedisk_open(struct block_device *bdev, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = bdev->bd_disk->private_data; drive->usage++; if (drive->removable && drive->usage == 1) { ide_task_t args; @@ -1744,7 +1744,7 @@ static int idedisk_open(struct inode *in memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; args.command_type = ide_cmd_type_parser(&args); - check_disk_change(inode->i_bdev); + check_disk_change(bdev); /* * Ignore the return code from door_lock, * since the open() has already succeeded, @@ -1782,9 +1782,9 @@ static int ide_cacheflush_p(ide_drive_t return 0; } -static int idedisk_release(struct inode *inode, struct file *filp) +static int idedisk_release(struct gendisk *disk) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = disk->private_data; if (drive->removable && drive->usage == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); @@ -1798,10 +1798,9 @@ static int idedisk_release(struct inode return 0; } -static int idedisk_ioctl(struct inode *inode, struct file *file, +static int idedisk_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; return generic_ide_ioctl(bdev, cmd, arg); } --- linux-2.6.1-rc1/drivers/ide/ide-floppy.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/ide/ide-floppy.c 2003-12-30 22:49:33.000000000 -0800 @@ -1866,9 +1866,9 @@ static ide_driver_t idefloppy_driver = { .drives = LIST_HEAD_INIT(idefloppy_driver.drives), }; -static int idefloppy_open(struct inode *inode, struct file *filp) +static int idefloppy_open(struct block_device *bdev, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = bdev->bd_disk->private_data; idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_pc_t pc; @@ -1908,7 +1908,7 @@ static int idefloppy_open(struct inode * idefloppy_create_prevent_cmd(&pc, 1); (void) idefloppy_queue_pc_tail(drive, &pc); } - check_disk_change(inode->i_bdev); + check_disk_change(bdev); } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) { drive->usage--; return -EBUSY; @@ -1916,9 +1916,9 @@ static int idefloppy_open(struct inode * return 0; } -static int idefloppy_release(struct inode *inode, struct file *filp) +static int idefloppy_release(struct gendisk *disk) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = disk->private_data; idefloppy_pc_t pc; debug_log(KERN_INFO "Reached idefloppy_release\n"); @@ -1938,10 +1938,9 @@ static int idefloppy_release(struct inod return 0; } -static int idefloppy_ioctl(struct inode *inode, struct file *file, +static int idefloppy_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; ide_drive_t *drive = bdev->bd_disk->private_data; idefloppy_floppy_t *floppy = drive->driver_data; int err = generic_ide_ioctl(bdev, cmd, arg); --- linux-2.6.1-rc1/drivers/ide/ide-io.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/ide/ide-io.c 2003-12-30 22:50:14.000000000 -0800 @@ -54,37 +54,6 @@ #include #include -#if (DISK_RECOVERY_TIME > 0) - -#error So the User Has To Fix the Compilation And Stop Hacking Port 0x43. Does anyone ever use this anyway ?? - -/* - * For really screwy hardware (hey, at least it *can* be used with Linux) - * we can enforce a minimum delay time between successive operations. - */ -static unsigned long read_timer (ide_hwif_t *hwif) -{ - unsigned long t, flags; - int i; - - /* FIXME this is completely unsafe! */ - local_irq_save(flags); - t = jiffies * 11932; - outb_p(0, 0x43); - i = inb_p(0x40); - i |= inb_p(0x40) << 8; - local_irq_restore(flags); - return (t - i); -} -#endif /* DISK_RECOVERY_TIME */ - -static inline void set_recovery_timer (ide_hwif_t *hwif) -{ -#if (DISK_RECOVERY_TIME > 0) - hwif->last_time = read_timer(hwif); -#endif /* DISK_RECOVERY_TIME */ -} - /** * ide_end_request - complete an IDE I/O * @drive: IDE device for the I/O @@ -653,10 +622,6 @@ ide_startstop_t start_request (ide_drive if (block == 0 && drive->remap_0_to_1 == 1) block = 1; /* redirect MBR access to EZ-Drive partn table */ -#if (DISK_RECOVERY_TIME > 0) - while ((read_timer() - HWIF(drive)->last_time) < DISK_RECOVERY_TIME); -#endif - if (blk_pm_suspend_request(rq) && rq->pm->pm_step == ide_pm_state_start_suspend) /* Mark drive blocked when starting the suspend sequence. */ @@ -1116,7 +1081,6 @@ void ide_timer_expiry (unsigned long dat startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); } - set_recovery_timer(hwif); drive->service_time = jiffies - drive->service_start; spin_lock_irq(&ide_lock); enable_irq(hwif->irq); @@ -1313,7 +1277,6 @@ irqreturn_t ide_intr (int irq, void *dev * same irq as is currently being serviced here, and Linux * won't allow another of the same (on any CPU) until we return. */ - set_recovery_timer(HWIF(drive)); drive->service_time = jiffies - drive->service_start; if (startstop == ide_stopped) { if (hwgroup->handler == NULL) { /* paranoia */ --- linux-2.6.1-rc1/drivers/ide/ide-tape.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/ide/ide-tape.c 2003-12-30 22:50:11.000000000 -0800 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-tape.c Version 1.18 Nov, 2003 + * linux/drivers/ide/ide-tape.c Version 1.19 Nov, 2003 * * Copyright (C) 1995 - 1999 Gadi Oxman * @@ -422,7 +422,7 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.18" +#define IDETAPE_VERSION "1.19" #include #include @@ -1216,10 +1216,14 @@ typedef struct { * requests to the tail of our block device request queue and wait * for their completion. */ -#define idetape_request(rq) \ - ((rq)->flags & (REQ_IDETAPE_PC1 | REQ_IDETAPE_PC2 | \ - REQ_IDETAPE_READ | REQ_IDETAPE_WRITE | \ - REQ_IDETAPE_READ_BUFFER)) + +enum { + REQ_IDETAPE_PC1 = (1 << 0), /* packet command (first stage) */ + REQ_IDETAPE_PC2 = (1 << 1), /* packet command (second stage) */ + REQ_IDETAPE_READ = (1 << 2), + REQ_IDETAPE_WRITE = (1 << 3), + REQ_IDETAPE_READ_BUFFER = (1 << 4), +}; /* * Error codes which are returned in rq->errors to the higher part @@ -1892,7 +1896,7 @@ static int idetape_end_request(ide_drive tape->active_stage = NULL; tape->active_data_request = NULL; tape->nr_pending_stages--; - if (rq->flags & REQ_IDETAPE_WRITE) { + if (rq->cmd[0] & REQ_IDETAPE_WRITE) { #if ONSTREAM_DEBUG if (tape->debug_level >= 2) { if (tape->onstream) { @@ -1938,7 +1942,7 @@ static int idetape_end_request(ide_drive } } } - } else if (rq->flags & REQ_IDETAPE_READ) { + } else if (rq->cmd[0] & REQ_IDETAPE_READ) { if (error == IDETAPE_ERROR_EOD) { set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); idetape_abort_pipeline(drive, active_stage); @@ -1996,6 +2000,13 @@ static void idetape_create_request_sense pc->callback = &idetape_request_sense_callback; } +static void idetape_init_rq(struct request *rq, u8 cmd) +{ + memset(rq, 0, sizeof(*rq)); + rq->flags = REQ_SPECIAL; + rq->cmd[0] = cmd; +} + /* * idetape_queue_pc_head generates a new packet command request in front * of the request queue, before the current request, so that it will be @@ -2017,8 +2028,7 @@ static void idetape_create_request_sense */ static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq) { - memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_IDETAPE_PC1; + idetape_init_rq(rq, REQ_IDETAPE_PC1); rq->buffer = (char *) pc; (void) ide_do_drive_cmd(drive, rq, ide_preempt); } @@ -2729,7 +2739,7 @@ static ide_startstop_t idetape_do_reques if (tape->debug_level >= 5) printk(KERN_INFO "ide-tape: rq_status: %d, " "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status, - rq->rq_disk->disk_name, rq->flags, rq->errors); + rq->rq_disk->disk_name, rq->cmd[0], rq->errors); #endif if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: sector: %ld, " @@ -2737,11 +2747,11 @@ static ide_startstop_t idetape_do_reques rq->sector, rq->nr_sectors, rq->current_nr_sectors); #endif /* IDETAPE_DEBUG_LOG */ - if (!idetape_request(rq)) { + if ((rq->flags & REQ_SPECIAL) == 0) { /* * We do not support buffer cache originated requests. */ - printk(KERN_NOTICE "ide-tape: %s: Unsupported command in " + printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " "request queue (%ld)\n", drive->name, rq->flags); ide_end_request(drive, 0, 0); return ide_stopped; @@ -2778,7 +2788,7 @@ static ide_startstop_t idetape_do_reques */ if (tape->onstream) status.b.dsc = 1; - if (!drive->dsc_overlap && !(rq->flags & REQ_IDETAPE_PC2)) + if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2)) set_bit(IDETAPE_IGNORE_DSC, &tape->flags); /* @@ -2792,7 +2802,7 @@ static ide_startstop_t idetape_do_reques if (tape->tape_still_time > 100 && tape->tape_still_time < 200) tape->measure_insert_time = 1; if (tape->req_buffer_fill && - (rq->flags & (REQ_IDETAPE_WRITE | REQ_IDETAPE_READ))) { + (rq->cmd[0] & (REQ_IDETAPE_WRITE | REQ_IDETAPE_READ))) { tape->req_buffer_fill = 0; tape->writes_since_buffer_fill = 0; tape->reads_since_buffer_fill = 0; @@ -2806,12 +2816,12 @@ static ide_startstop_t idetape_do_reques tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); calculate_speeds(drive); if (tape->onstream && tape->max_frames && - (((rq->flags & REQ_IDETAPE_WRITE) && + (((rq->cmd[0] & REQ_IDETAPE_WRITE) && ( tape->cur_frames == tape->max_frames || ( tape->speed_control && tape->cur_frames > 5 && (tape->insert_speed > tape->max_insert_speed || (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) || - ((rq->flags & REQ_IDETAPE_READ) && + ((rq->cmd[0] & REQ_IDETAPE_READ) && ( tape->cur_frames == 0 || ( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) { @@ -2819,7 +2829,7 @@ static ide_startstop_t idetape_do_reques if (tape->debug_level >= 4) printk(KERN_INFO "ide-tape: postponing request, " "cmd %ld, cur %d, max %d\n", - rq->flags, tape->cur_frames, tape->max_frames); + rq->cmd[0], tape->cur_frames, tape->max_frames); #endif if (tape->postpone_cnt++ < 500) { status.b.dsc = 0; @@ -2840,7 +2850,7 @@ static ide_startstop_t idetape_do_reques } else if ((signed long) (jiffies - tape->dsc_timeout) > 0) { printk(KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name); - if (rq->flags & REQ_IDETAPE_PC2) { + if (rq->cmd[0] & REQ_IDETAPE_PC2) { idetape_media_access_finished(drive); return ide_stopped; } else { @@ -2851,7 +2861,7 @@ static ide_startstop_t idetape_do_reques idetape_postpone_request(drive); return ide_stopped; } - if (rq->flags & REQ_IDETAPE_READ) { + if (rq->cmd[0] & REQ_IDETAPE_READ) { tape->buffer_head++; #if USE_IOTRACE IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); @@ -2868,7 +2878,7 @@ static ide_startstop_t idetape_do_reques idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); goto out; } - if (rq->flags & REQ_IDETAPE_WRITE) { + if (rq->cmd[0] & REQ_IDETAPE_WRITE) { tape->buffer_head++; #if USE_IOTRACE IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); @@ -2886,19 +2896,19 @@ static ide_startstop_t idetape_do_reques idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); goto out; } - if (rq->flags & REQ_IDETAPE_READ_BUFFER) { + if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) { tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); goto out; } - if (rq->flags & REQ_IDETAPE_PC1) { + if (rq->cmd[0] & REQ_IDETAPE_PC1) { pc = (idetape_pc_t *) rq->buffer; - rq->flags &= ~(REQ_IDETAPE_PC1); - rq->flags |= REQ_IDETAPE_PC2; + rq->cmd[0] &= ~(REQ_IDETAPE_PC1); + rq->cmd[0] |= REQ_IDETAPE_PC2; goto out; } - if (rq->flags & REQ_IDETAPE_PC2) { + if (rq->cmd[0] & REQ_IDETAPE_PC2) { idetape_media_access_finished(drive); return ide_stopped; } @@ -3195,7 +3205,7 @@ static void idetape_wait_for_request (id idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS - if (rq == NULL || !idetape_request(rq)) { + if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) { printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); return; } @@ -3301,8 +3311,7 @@ static int __idetape_queue_pc_tail (ide_ { struct request rq; - memset(&rq, 0, sizeof(rq)); - rq.flags = REQ_IDETAPE_PC1; + idetape_init_rq(&rq, REQ_IDETAPE_PC1); rq.buffer = (char *) pc; return ide_do_drive_cmd(drive, &rq, ide_wait); } @@ -3571,8 +3580,7 @@ static int idetape_queue_rw_tail(ide_dri } #endif /* IDETAPE_DEBUG_BUGS */ - memset(&rq, 0, sizeof(rq)); - rq.flags = cmd; + idetape_init_rq(&rq, cmd); rq.special = (void *)bh; rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks; @@ -3621,8 +3629,7 @@ static void idetape_onstream_read_back_b printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++); #endif rq = &stage->rq; - memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_IDETAPE_WRITE; + idetape_init_rq(rq, REQ_IDETAPE_WRITE); rq->sector = tape->first_frame_position; rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl; idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++); @@ -3896,8 +3903,7 @@ static int idetape_add_chrdev_write_requ } } rq = &new_stage->rq; - memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_IDETAPE_WRITE; + idetape_init_rq(rq, REQ_IDETAPE_WRITE); /* Doesn't actually matter - We always assume sequential access */ rq->sector = tape->first_frame_position; rq->nr_sectors = rq->current_nr_sectors = blocks; @@ -4099,8 +4105,7 @@ static int idetape_initiate_read (ide_dr } if (tape->restart_speed_control_req) idetape_restart_speed_control(drive); - memset(&rq, 0, sizeof(rq)); - rq.flags = REQ_IDETAPE_READ; + idetape_init_rq(&rq, REQ_IDETAPE_READ); rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks; if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && @@ -6389,24 +6394,23 @@ static struct file_operations idetape_fo .release = idetape_chrdev_release, }; -static int idetape_open(struct inode *inode, struct file *filp) +static int idetape_open(struct block_device *bdev, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = bdev->bd_disk->private_data; drive->usage++; return 0; } -static int idetape_release(struct inode *inode, struct file *filp) +static int idetape_release(struct gendisk *disk) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = disk->private_data; drive->usage--; return 0; } -static int idetape_ioctl(struct inode *inode, struct file *file, +static int idetape_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; ide_drive_t *drive = bdev->bd_disk->private_data; int err = generic_ide_ioctl(bdev, cmd, arg); if (err == -EINVAL) --- linux-2.6.1-rc1/drivers/ide/Kconfig 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/ide/Kconfig 2003-12-30 22:50:11.000000000 -0800 @@ -734,10 +734,10 @@ config BLK_DEV_PDC202XX_NEW # FIXME - probably wants to be one for old and for new config PDC202XX_FORCE - bool "Special FastTrak Feature" + bool "Enable controller even if disabled by BIOS" depends on BLK_DEV_PDC202XX_NEW=y help - For FastTrak enable overriding BIOS. + Enable the PDC202xx controller even if it has been disabled in the BIOS setup. config BLK_DEV_SVWKS tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" --- linux-2.6.1-rc1/drivers/ide/legacy/hd98.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/ide/legacy/hd98.c 2003-12-30 22:49:29.000000000 -0800 @@ -652,10 +652,10 @@ static void do_hd_request (request_queue enable_irq(HD_IRQ); } -static int hd_ioctl(struct inode * inode, struct file * file, +static int hd_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data; + struct hd_i_struct *disk = bdev->bd_disk->private_data; struct hd_geometry *loc = (struct hd_geometry *) arg; struct hd_geometry g; @@ -666,7 +666,7 @@ static int hd_ioctl(struct inode * inode g.heads = disk->head; g.sectors = disk->sect; g.cylinders = disk->cyl; - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } --- linux-2.6.1-rc1/drivers/ide/legacy/hd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/ide/legacy/hd.c 2003-12-30 22:49:29.000000000 -0800 @@ -656,10 +656,10 @@ static void do_hd_request (request_queue enable_irq(HD_IRQ); } -static int hd_ioctl(struct inode * inode, struct file * file, +static int hd_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data; + struct hd_i_struct *disk = bdev->bd_disk->private_data; struct hd_geometry *loc = (struct hd_geometry *) arg; struct hd_geometry g; @@ -670,7 +670,7 @@ static int hd_ioctl(struct inode * inode g.heads = disk->head; g.sectors = disk->sect; g.cylinders = disk->cyl; - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } --- linux-2.6.1-rc1/drivers/ide/legacy/ide-cs.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/ide/legacy/ide-cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -152,7 +152,7 @@ static dev_link_t *ide_attach(void) client_reg.event_handler = &ide_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); ide_detach(link); @@ -188,7 +188,7 @@ static void ide_detach(dev_link_t *link) ide_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -207,11 +207,8 @@ static void ide_detach(dev_link_t *link) ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq) { @@ -241,16 +238,16 @@ void ide_config(dev_link_t *link) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; tuple.DesiredTuple = CISTPL_MANFID; - if (!CardServices(GetFirstTuple, handle, &tuple) && - !CardServices(GetTupleData, handle, &tuple) && - !CardServices(ParseTuple, handle, &tuple, &parse)) + if (!pcmcia_get_first_tuple(handle, &tuple) && + !pcmcia_get_tuple_data(handle, &tuple) && + !pcmcia_parse_tuple(handle, &tuple, &parse)) is_kme = ((parse.manfid.manf == MANFID_KME) && ((parse.manfid.card == PRODID_KME_KXLC005_A) || (parse.manfid.card == PRODID_KME_KXLC005_B))); @@ -259,16 +256,16 @@ void ide_config(dev_link_t *link) link->state |= DEV_CONFIG; /* Not sure if this is right... look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; pass = io_base = ctl_base = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0) goto next_entry; + if (pcmcia_parse_tuple(handle, &tuple, &parse) != 0) goto next_entry; /* Check for matching Vcc, unless we're desperate */ if (!pass) { @@ -299,13 +296,15 @@ void ide_config(dev_link_t *link) link->io.NumPorts1 = 8; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = (is_kme) ? 2 : 1; - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort2; } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { link->io.NumPorts1 = io->win[0].len; link->io.NumPorts2 = 0; - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort1+0x0e; } else goto next_entry; @@ -316,16 +315,16 @@ void ide_config(dev_link_t *link) next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (pass) { - CS_CHECK(GetNextTuple, handle, &tuple); - } else if (CardServices(GetNextTuple, handle, &tuple) != 0) { - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + } else if (pcmcia_get_next_tuple(handle, &tuple) != 0) { + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); memset(&dflt, 0, sizeof(dflt)); pass++; } } - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); /* deal with brain dead IDE resource management */ release_region(link->io.BasePort1, link->io.NumPorts1); @@ -413,9 +412,9 @@ void ide_release(dev_link_t *link) info->ndev = 0; link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; @@ -452,14 +451,14 @@ int ide_event(event_t event, int priorit /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; --- linux-2.6.1-rc1/drivers/ide/pci/cmd640.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/ide/pci/cmd640.c 2003-12-30 22:50:12.000000000 -0800 @@ -213,13 +213,13 @@ static unsigned int cmd640_chip_version; static void put_cmd640_reg_pci1 (u16 reg, u8 val) { - outb_p((reg & 0xfc) | cmd640_key, 0xcf8); + outl_p((reg & 0xfc) | cmd640_key, 0xcf8); outb_p(val, (reg & 3) | 0xcfc); } static u8 get_cmd640_reg_pci1 (u16 reg) { - outb_p((reg & 0xfc) | cmd640_key, 0xcf8); + outl_p((reg & 0xfc) | cmd640_key, 0xcf8); return inb_p((reg & 3) | 0xcfc); } --- linux-2.6.1-rc1/drivers/ide/pci/pdc202xx_new.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/ide/pci/pdc202xx_new.c 2003-12-30 22:50:14.000000000 -0800 @@ -36,60 +36,20 @@ #define PDC202_DEBUG_CABLE 0 -#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) -#include -#include - -static u8 pdcnew_proc = 0; -#define PDC202_MAX_DEVS 5 -static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS]; -static int n_pdc202_devs; - -static char * pdcnew_info(char *buf, struct pci_dev *dev) -{ - char *p = buf; - - p += sprintf(p, "\n "); - switch(dev->device) { - case PCI_DEVICE_ID_PROMISE_20277: - p += sprintf(p, "SBFastTrak 133 Lite"); break; - case PCI_DEVICE_ID_PROMISE_20276: - p += sprintf(p, "MBFastTrak 133 Lite"); break; - case PCI_DEVICE_ID_PROMISE_20275: - p += sprintf(p, "MBUltra133"); break; - case PCI_DEVICE_ID_PROMISE_20271: - p += sprintf(p, "FastTrak TX2000"); break; - case PCI_DEVICE_ID_PROMISE_20270: - p += sprintf(p, "FastTrak LP/TX2/TX4"); break; - case PCI_DEVICE_ID_PROMISE_20269: - p += sprintf(p, "Ultra133 TX2"); break; - case PCI_DEVICE_ID_PROMISE_20268: - p += sprintf(p, "Ultra100 TX2"); break; - default: - p += sprintf(p, "Ultra series"); break; - break; - } - p += sprintf(p, " Chipset.\n"); - return (char *)p; -} - -static int pdcnew_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - int i, len; - - for (i = 0; i < n_pdc202_devs; i++) { - struct pci_dev *dev = pdc202_devs[i]; - p = pdcnew_info(buffer, dev); - } - /* p - buffer must be less than 4k! */ - len = (p - buffer) - offset; - *addr = buffer + offset; - - return len > count ? count : len; -} -#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ +struct pdcnew_name { + u16 dev_id; + const char *name; +}; +static struct pdcnew_name __initdata pdcnew_names[] = { + { PCI_DEVICE_ID_PROMISE_20277, "SBFastTrak 133 Lite" }, + { PCI_DEVICE_ID_PROMISE_20276, "MBFastTrak 133 Lite" }, + { PCI_DEVICE_ID_PROMISE_20275, "MBUltra133", }, + { PCI_DEVICE_ID_PROMISE_20271, "FastTrak TX2000", }, + { PCI_DEVICE_ID_PROMISE_20270, "FastTrak LP/TX2/TX4", }, + { PCI_DEVICE_ID_PROMISE_20269, "Ultra133 TX2" }, + { PCI_DEVICE_ID_PROMISE_20268, "Ultra100 TX2" }, +}; static u8 pdcnew_ratemask (ide_drive_t *drive) { @@ -515,6 +475,15 @@ void pdcnew_reset (ide_drive_t *drive) static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name) { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pdcnew_names); i++) + if (pdcnew_names[i].dev_id == dev->device) { + printk(KERN_INFO "%s: %s on pci%s\n", name, + pdcnew_names[i].name, pci_name(dev)); + break; + } + if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); @@ -522,15 +491,6 @@ static unsigned int __init init_chipset_ name, dev->resource[PCI_ROM_RESOURCE].start); } -#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) - pdc202_devs[n_pdc202_devs++] = dev; - - if (!pdcnew_proc) { - pdcnew_proc = 1; - ide_pci_register_host_proc(&pdcnew_procs[0]); - } -#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ - return dev->irq; } --- linux-2.6.1-rc1/drivers/ide/pci/pdc202xx_new.h 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/ide/pci/pdc202xx_new.h 2003-12-30 22:50:14.000000000 -0800 @@ -5,8 +5,6 @@ #include #include -#define DISPLAY_PDC202XX_TIMINGS - #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif @@ -162,27 +160,6 @@ static void decode_registers (u8 registe set_2regs(0x13,(c)); \ } while(0) -#define DISPLAY_PDC202XX_TIMINGS - -#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) -#include -#include - -static u8 pdcnew_proc; - -static int pdcnew_get_info(char *, char **, off_t, int); - -static ide_pci_host_proc_t pdcnew_procs[] __initdata = { - { - .name = "pdcnew", - .set = 1, - .get_info = pdcnew_get_info, - .parent = NULL, - }, -}; -#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ - - static void init_setup_pdcnew(struct pci_dev *, ide_pci_device_t *); static void init_setup_pdc20270(struct pci_dev *, ide_pci_device_t *); static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d); --- linux-2.6.1-rc1/drivers/ide/pci/pdc202xx_old.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/ide/pci/pdc202xx_old.c 2003-12-30 22:50:13.000000000 -0800 @@ -361,16 +361,38 @@ static u8 pdc202xx_old_cable_detect (ide return ((u8)(CIS & mask)); } +/* + * Set the control register to use the 66MHz system + * clock for UDMA 3/4/5 mode operation when necessary. + * + * It may also be possible to leave the 66MHz clock on + * and readjust the timing parameters. + */ +static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) +{ + unsigned long clock_reg = hwif->dma_master + 0x11; + u8 clock = hwif->INB(clock_reg); + + hwif->OUTB(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); +} + +static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) +{ + unsigned long clock_reg = hwif->dma_master + 0x11; + u8 clock = hwif->INB(clock_reg); + + hwif->OUTB(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); +} + static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u32 drive_conf = 0; - u8 mask = hwif->channel ? 0x08 : 0x02; u8 drive_pci = 0x60 + (drive->dn << 2); u8 test1 = 0, test2 = 0, speed = -1; - u8 AP = 0, CLKSPD = 0, cable = 0; + u8 AP = 0, cable = 0; u8 ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; @@ -394,21 +416,6 @@ static int config_chipset_for_dma (ide_d BUG(); } - CLKSPD = hwif->INB(hwif->dma_master + 0x11); - - /* - * Set the control register to use the 66Mhz system - * clock for UDMA 3/4 mode operation. If one drive on - * a channel is U66 capable but the other isn't we - * fall back to U33 mode. The BIOS INT 13 hooks turn - * the clock on then off for each read/write issued. I don't - * do that here because it would require modifying the - * kernel, separating the fop routines from the kernel or - * somehow hooking the fops calls. It may also be possible to - * leave the 66Mhz clock on and readjust the timing - * parameters. - */ - if ((ultra_66) && (cable)) { #ifdef DEBUG printk(KERN_DEBUG "ULTRA 66/100/133: %s channel of Ultra 66/100/133 " @@ -416,29 +423,12 @@ static int config_chipset_for_dma (ide_d hwif->channel ? "Secondary" : "Primary"); printk(KERN_DEBUG " Switching to Ultra33 mode.\n"); #endif /* DEBUG */ - /* Primary : zero out second bit */ - /* Secondary : zero out fourth bit */ - hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11)); printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary"); printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name); - } else { - if (ultra_66) { - /* - * check to make sure drive on same channel - * is u66 capable - */ - if (hwif->drives[!(drive->dn%2)].id) { - if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) { - hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11)); - } else { - hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11)); - } - } else { /* udma4 drive by itself */ - hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11)); - } - } } + pdc_old_disable_66MHz_clock(drive->hwif); + drive_pci = 0x60 + (drive->dn << 2); pci_read_config_dword(dev, drive_pci, &drive_conf); if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) @@ -536,6 +526,8 @@ static int pdc202xx_quirkproc (ide_drive static int pdc202xx_old_ide_dma_begin(ide_drive_t *drive) { + if (drive->current_speed > XFER_UDMA_2) + pdc_old_enable_66MHz_clock(drive->hwif); if (drive->addressing == 1) { struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); @@ -569,6 +561,8 @@ static int pdc202xx_old_ide_dma_end(ide_ clock = hwif->INB(high_16 + 0x11); hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11); } + if (drive->current_speed > XFER_UDMA_2) + pdc_old_disable_66MHz_clock(drive->hwif); return __ide_dma_end(drive); } @@ -757,10 +751,7 @@ static void __init init_hwif_pdc202xx (i hwif->speedproc = &pdc202xx_tune_chipset; - if (!hwif->dma_base) { - hwif->drives[0].autotune = hwif->drives[1].autotune = 1; - return; - } + hwif->drives[0].autotune = hwif->drives[1].autotune = 1; hwif->ultra_mask = 0x3f; hwif->mwdma_mask = 0x07; --- linux-2.6.1-rc1/drivers/ide/pci/siimage.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/drivers/ide/pci/siimage.c 2003-12-30 22:50:12.000000000 -0800 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.06 June 11, 2003 + * linux/drivers/ide/pci/siimage.c Version 1.09 Dec 7, 2003 * * Copyright (C) 2001-2002 Andre Hedrick * Copyright (C) 2003 Red Hat @@ -56,6 +56,7 @@ static int pdev_is_sata(struct pci_dev * { case PCI_DEVICE_ID_SII_3112: case PCI_DEVICE_ID_SII_1210SA: + case PCI_DEVICE_ID_SII_3114: return 1; case PCI_DEVICE_ID_SII_680: return 0; @@ -266,7 +267,7 @@ static byte siimage_taskfile_timing (ide static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted) { ide_hwif_t *hwif = HWIF(drive); - u32 speedt = 0; + u16 speedt = 0; u16 speedp = 0; unsigned long addr = siimage_seldev(drive, 0x04); unsigned long tfaddr = siimage_selreg(hwif, 0x02); @@ -1047,6 +1048,27 @@ static void __init init_mmio_iops_siimag hwif->mmio = 2; } +static int is_dev_seagate_sata(ide_drive_t *drive) +{ + const char *s = &drive->id->model[0]; + unsigned len; + + if (!drive->present) + return 0; + + len = strnlen(s, sizeof(drive->id->model)); + + if ((len > 4) && (!memcmp(s, "ST", 2))) { + if ((!memcmp(s + len - 2, "AS", 2)) || + (!memcmp(s + len - 3, "ASL", 3))) { + printk(KERN_INFO "%s: applying pessimistic Seagate " + "errata fix\n", drive->name); + return 1; + } + } + return 0; +} + /** * init_iops_siimage - set up iops * @hwif: interface to set up @@ -1068,7 +1090,7 @@ static void __init init_iops_siimage (id hwif->hwif_data = 0; hwif->rqsize = 128; - if (is_sata(hwif)) + if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0])) hwif->rqsize = 15; if (pci_get_drvdata(dev) == NULL) @@ -1179,6 +1201,7 @@ static struct pci_device_id siimage_pci_ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, { 0, }, }; --- linux-2.6.1-rc1/drivers/ide/pci/siimage.h 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/ide/pci/siimage.h 2003-12-30 22:50:12.000000000 -0800 @@ -82,6 +82,16 @@ static ide_pci_device_t siimage_chipsets .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, .extra = 0, + },{ /* 3 */ + .vendor = PCI_VENDOR_ID_CMD, + .device = PCI_DEVICE_ID_SII_3114, + .name = "SiI3114 Serial ATA", + .init_chipset = init_chipset_siimage, + .init_iops = init_iops_siimage, + .init_hwif = init_hwif_siimage, + .channels = 2, + .autodma = AUTODMA, + .bootable = ON_BOARD, },{ .vendor = 0, .device = 0, --- linux-2.6.1-rc1/drivers/ieee1394/eth1394.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/ieee1394/eth1394.c 2003-12-30 22:49:19.000000000 -0800 @@ -375,8 +375,8 @@ static void ether1394_reset_priv (struct } } -/* This function is called by register_netdev */ -static int ether1394_init_dev (struct net_device *dev) +/* This function is called right before register_netdev */ +static void ether1394_init_dev (struct net_device *dev) { /* Our functions */ dev->open = ether1394_open; @@ -403,8 +403,6 @@ static int ether1394_init_dev (struct ne dev->type = ARPHRD_IEEE1394; ether1394_reset_priv (dev, 1); - - return 0; } /* @@ -437,8 +435,6 @@ static void ether1394_add_host (struct h SET_MODULE_OWNER(dev); - dev->init = ether1394_init_dev; - priv = (struct eth1394_priv *)dev->priv; spin_lock_init(&priv->lock); @@ -459,6 +455,8 @@ static void ether1394_add_host (struct h goto out; } + ether1394_init_dev(dev); + if (register_netdev (dev)) { ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); goto out; @@ -483,7 +481,7 @@ static void ether1394_add_host (struct h out: if (dev != NULL) - kfree(dev); + free_netdev(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); --- linux-2.6.1-rc1/drivers/input/keyboard/atkbd.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/input/keyboard/atkbd.c 2003-12-30 22:49:39.000000000 -0800 @@ -585,6 +585,7 @@ static void atkbd_disconnect(struct seri struct atkbd *atkbd = serio->private; input_unregister_device(&atkbd->dev); serio_close(serio); + serio->private = NULL; kfree(atkbd); } @@ -644,6 +645,7 @@ static void atkbd_connect(struct serio * serio->private = atkbd; if (serio_open(serio, dev)) { + serio->private = NULL; kfree(atkbd); return; } @@ -652,6 +654,7 @@ static void atkbd_connect(struct serio * if (atkbd_probe(atkbd)) { serio_close(serio); + serio->private = NULL; kfree(atkbd); return; } --- linux-2.6.1-rc1/drivers/input/mousedev.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/input/mousedev.c 2003-12-30 22:49:39.000000000 -0800 @@ -53,12 +53,14 @@ struct mousedev_list { struct fasync_struct *fasync; struct mousedev *mousedev; struct list_head node; - int dx, dy, dz, oldx, oldy; - signed char ps2[6]; + int dx, dy, dz; + int old_x[4], old_y[4]; unsigned long buttons; + signed char ps2[6]; unsigned char ready, buffer, bufsiz; unsigned char mode, imexseq, impsseq; - int finger; + unsigned int pkt_count; + unsigned char touch; }; #define MOUSEDEV_SEQ_LEN 6 @@ -74,49 +76,49 @@ static struct mousedev mousedev_mix; static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; +#define fx(i) (list->old_x[(list->pkt_count - (i)) & 03]) +#define fy(i) (list->old_y[(list->pkt_count - (i)) & 03]) + static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, unsigned int code, int value) { int size; + int touchpad; /* Ignore joysticks */ if (test_bit(BTN_TRIGGER, handle->dev->keybit)) return; - /* Handle touchpad data */ - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { + touchpad = test_bit(BTN_TOOL_FINGER, handle->dev->keybit); - if (list->finger && list->finger < 3) - list->finger++; - - switch (code) { - case ABS_X: - if (list->finger == 3) - list->dx += (value - list->oldx) / 8; - list->oldx = value; - return; - case ABS_Y: - if (list->finger == 3) - list->dy -= (value - list->oldy) / 8; - list->oldy = value; - return; - } - return; - } - - /* Handle tablet data */ switch (code) { case ABS_X: - size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - if (size == 0) size = xres; - list->dx += (value * xres - list->oldx) / size; - list->oldx += list->dx * size; - return; + if (touchpad) { + if (list->touch) { + fx(0) = value; + if (list->pkt_count >= 2) + list->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; + } + } else { + size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; + if (size == 0) size = xres; + list->dx += (value * xres - list->old_x[0]) / size; + list->old_x[0] += list->dx * size; + } + break; case ABS_Y: - size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - if (size == 0) size = yres; - list->dy -= (value * yres - list->oldy) / size; - list->oldy -= list->dy * size; - return; + if (touchpad) { + if (list->touch) { + fy(0) = value; + if (list->pkt_count >= 2) + list->dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; + } + } else { + size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; + if (size == 0) size = yres; + list->dy -= (value * yres - list->old_y[0]) / size; + list->old_y[0] -= list->dy * size; + } + break; } } @@ -146,12 +148,16 @@ static void mousedev_event(struct input_ break; case EV_KEY: + if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { + /* Handle touchpad data */ + list->touch = value; + if (!list->touch) + list->pkt_count = 0; + break; + } + switch (code) { - case BTN_TOUCH: /* Handle touchpad data */ - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { - list->finger = value; - return; - } + case BTN_TOUCH: case BTN_0: case BTN_FORWARD: case BTN_LEFT: index = 0; break; @@ -178,6 +184,16 @@ static void mousedev_event(struct input_ case EV_SYN: switch (code) { case SYN_REPORT: + if (list->touch) { + list->pkt_count++; + /* Input system eats duplicate events, + * but we need all of them to do correct + * averaging so apply present one forward + */ + fx(0) = fx(1); + fy(0) = fy(1); + } + list->ready = 1; kill_fasync(&list->fasync, SIGIO, POLL_IN); wake = 1; --- linux-2.6.1-rc1/drivers/input/mouse/psmouse-base.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/input/mouse/psmouse-base.c 2003-12-30 22:49:39.000000000 -0800 @@ -22,6 +22,15 @@ #include "synaptics.h" #include "logips2pp.h" +/* + * Reset module param prefix regardless of whether we build psmouse as + * a module or directly into kernel, otherwise for build-in case + * parameters will have to be specified as psmouse.psmouse_proto which + * is unsightly + */ +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX /* empty */ + MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/input/mouse/synaptics.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/input/mouse/synaptics.c 2003-12-30 22:49:39.000000000 -0800 @@ -553,16 +553,19 @@ static void synaptics_process_packet(str finger_width = 0; } - /* Post events */ + /* Post events + * BTN_TOUCH has to be first as mousedev relies on it when doing + * absolute -> relative conversion + */ + if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); + if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); + if (hw.z > 0) { input_report_abs(dev, ABS_X, hw.x); input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); } input_report_abs(dev, ABS_PRESSURE, hw.z); - if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); - if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); - input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); --- linux-2.6.1-rc1/drivers/isdn/hardware/avm/avm_cs.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/avm/avm_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -186,7 +186,7 @@ static dev_link_t *avmcs_attach(void) client_reg.event_handler = &avmcs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); avmcs_detach(link); @@ -232,7 +232,7 @@ static void avmcs_detach(dev_link_t *lin /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; @@ -251,19 +251,29 @@ static void avmcs_detach(dev_link_t *lin ======================================================================*/ -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, +static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { - int i; - i = CardServices(fn, handle, tuple); + int i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - i = CardServices(GetTupleData, handle, tuple); + return pcmcia_parse_tuple(handle, tuple, parse); +} + +static int first_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_first_tuple(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return get_tuple(handle, tuple, parse); } -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_next_tuple(handle, tuple); + if (i != CS_SUCCESS) return i; + return get_tuple(handle, tuple, parse); +} static void avmcs_config(dev_link_t *link) { @@ -287,14 +297,14 @@ static void avmcs_config(dev_link_t *lin */ do { tuple.DesiredTuple = CISTPL_CONFIG; - i = CardServices(GetFirstTuple, handle, &tuple); + i = pcmcia_get_first_tuple(handle, &tuple); if (i != CS_SUCCESS) break; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = CardServices(GetTupleData, handle, &tuple); + i = pcmcia_get_tuple_data(handle, &tuple); if (i != CS_SUCCESS) break; - i = CardServices(ParseTuple, handle, &tuple, &parse); + i = pcmcia_parse_tuple(handle, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); @@ -337,7 +347,7 @@ static void avmcs_config(dev_link_t *lin printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } i = next_tuple(handle, &tuple, &parse); @@ -352,21 +362,21 @@ found_port: /* * allocate an interrupt line */ - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); break; } /* * configure the PCMCIA socket */ - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); break; } @@ -437,9 +447,9 @@ static void avmcs_release(dev_link_t *li link->dev = NULL; /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) @@ -481,14 +491,14 @@ static int avmcs_event(event_t event, in /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; --- linux-2.6.1-rc1/drivers/isdn/hisax/avma1_cs.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hisax/avma1_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -204,7 +204,7 @@ static dev_link_t *avma1cs_attach(void) client_reg.event_handler = &avma1cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); avma1cs_detach(link); @@ -252,7 +252,7 @@ static void avma1cs_detach(dev_link_t *l /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; @@ -271,19 +271,29 @@ static void avma1cs_detach(dev_link_t *l ======================================================================*/ -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, +static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { - int i; - i = CardServices(fn, handle, tuple); + int i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - i = CardServices(GetTupleData, handle, tuple); + return pcmcia_parse_tuple(handle, tuple, parse); +} + +static int first_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_first_tuple(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return get_tuple(handle, tuple, parse); } -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_next_tuple(handle, tuple); + if (i != CS_SUCCESS) return i; + return get_tuple(handle, tuple, parse); +} static void avma1cs_config(dev_link_t *link) { @@ -308,14 +318,14 @@ static void avma1cs_config(dev_link_t *l */ do { tuple.DesiredTuple = CISTPL_CONFIG; - i = CardServices(GetFirstTuple, handle, &tuple); + i = pcmcia_get_first_tuple(handle, &tuple); if (i != CS_SUCCESS) break; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = CardServices(GetTupleData, handle, &tuple); + i = pcmcia_get_tuple_data(handle, &tuple); if (i != CS_SUCCESS) break; - i = CardServices(ParseTuple, handle, &tuple, &parse); + i = pcmcia_parse_tuple(handle, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); @@ -358,7 +368,7 @@ static void avma1cs_config(dev_link_t *l printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1 - 1); - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } i = next_tuple(handle, &tuple, &parse); @@ -373,21 +383,21 @@ found_port: /* * allocate an interrupt line */ - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); break; } /* * configure the PCMCIA socket */ - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); break; } @@ -445,9 +455,9 @@ static void avma1cs_release(dev_link_t * link->dev = NULL; /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) @@ -490,14 +500,14 @@ static int avma1cs_event(event_t event, /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; --- linux-2.6.1-rc1/drivers/isdn/hisax/elsa_cs.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hisax/elsa_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -235,7 +235,7 @@ static dev_link_t *elsa_cs_attach(void) client_reg.event_handler = &elsa_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); elsa_cs_detach(link); @@ -286,7 +286,7 @@ static void elsa_cs_detach(dev_link_t *l /* Break the link with Card Services */ if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -304,19 +304,29 @@ static void elsa_cs_detach(dev_link_t *l device available to the system. ======================================================================*/ -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, +static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { - int i; - i = CardServices(fn, handle, tuple); + int i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - i = CardServices(GetTupleData, handle, tuple); + return pcmcia_parse_tuple(handle, tuple, parse); +} + +static int first_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_first_tuple(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return get_tuple(handle, tuple, parse); } -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i = pcmcia_get_next_tuple(handle, tuple); + if (i != CS_SUCCESS) return i; + return get_tuple(handle, tuple, parse); +} static void elsa_cs_config(dev_link_t *link) { @@ -362,14 +372,14 @@ static void elsa_cs_config(dev_link_t *l printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } else { printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); link->conf.ConfigIndex = cf->index; for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { link->io.BasePort1 = j; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } break; @@ -382,14 +392,14 @@ static void elsa_cs_config(dev_link_t *l goto cs_failed; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { link->irq.AssignedIRQ = 0; last_fn = RequestIRQ; goto cs_failed; } - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { last_fn = RequestConfiguration; goto cs_failed; @@ -447,10 +457,10 @@ static void elsa_cs_release(dev_link_t * /* Don't bother checking to see if these succeed or not */ if (link->win) - CardServices(ReleaseWindow, link->win); - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) @@ -499,14 +509,14 @@ static int elsa_cs_event(event_t event, /* Mark the device as stopped, to block IO until later */ dev->busy = 1; if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); dev->busy = 0; break; } --- linux-2.6.1-rc1/drivers/isdn/hisax/sedlbauer_cs.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hisax/sedlbauer_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -247,7 +247,7 @@ static dev_link_t *sedlbauer_attach(void client_reg.event_handler = &sedlbauer_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); sedlbauer_detach(link); @@ -295,7 +295,7 @@ static void sedlbauer_detach(dev_link_t /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, and free it */ *linkp = link->next; @@ -310,12 +310,8 @@ static void sedlbauer_detach(dev_link_t device available to the system. ======================================================================*/ - -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void sedlbauer_config(dev_link_t *link) { @@ -341,9 +337,9 @@ static void sedlbauer_config(dev_link_t tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -351,7 +347,7 @@ static void sedlbauer_config(dev_link_t link->state |= DEV_CONFIG; /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* @@ -367,12 +363,13 @@ static void sedlbauer_config(dev_link_t will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto next_entry; @@ -425,7 +422,8 @@ static void sedlbauer_config(dev_link_t link->io.NumPorts2 = io->win[1].len; } /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; } /* @@ -451,10 +449,11 @@ static void sedlbauer_config(dev_link_t req.Size = 0x1000; */ req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - CFG_CHECK(RequestWindow, &link->win, &req); + if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) + goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - CFG_CHECK(MapMemPage, link->win, &map); + if (pcmcia_map_mem_page(link->win, &map) != 0) + goto next_entry; } /* If we got this far, we're cool! */ break; @@ -462,9 +461,9 @@ static void sedlbauer_config(dev_link_t next_entry: /* new in dummy.cs 2001/01/28 MN if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); */ - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } /* @@ -473,14 +472,14 @@ static void sedlbauer_config(dev_link_t irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); /* At this point, the dev_node_t structure(s) need to be @@ -545,12 +544,12 @@ static void sedlbauer_release(dev_link_t /* Don't bother checking to see if these succeed or not */ if (link->win) - CardServices(ReleaseWindow, link->win); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) @@ -597,14 +596,14 @@ static int sedlbauer_event(event_t event /* Mark the device as stopped, to block IO until later */ dev->stop = 1; if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); dev->stop = 0; /* In a normal driver, additional code may go here to restore --- linux-2.6.1-rc1/drivers/md/dm.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/md/dm.c 2003-12-30 22:49:33.000000000 -0800 @@ -160,20 +160,16 @@ static void __exit dm_exit(void) /* * Block device functions */ -static int dm_blk_open(struct inode *inode, struct file *file) +static int dm_blk_open(struct block_device *bdev, struct file *file) { - struct mapped_device *md; - - md = inode->i_bdev->bd_disk->private_data; + struct mapped_device *md = bdev->bd_disk->private_data; dm_get(md); return 0; } -static int dm_blk_close(struct inode *inode, struct file *file) +static int dm_blk_close(struct gendisk *disk) { - struct mapped_device *md; - - md = inode->i_bdev->bd_disk->private_data; + struct mapped_device *md = disk->private_data; dm_put(md); return 0; } --- linux-2.6.1-rc1/drivers/md/md.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/md/md.c 2003-12-30 22:49:33.000000000 -0800 @@ -2360,11 +2360,10 @@ static int set_disk_faulty(mddev_t *mdde return 1; } -static int md_ioctl(struct inode *inode, struct file *file, +static int md_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { char b[BDEVNAME_SIZE]; - unsigned int minor = iminor(inode); int err = 0; struct hd_geometry *loc = (struct hd_geometry *) arg; mddev_t *mddev = NULL; @@ -2372,11 +2371,6 @@ static int md_ioctl(struct inode *inode, if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (minor >= MAX_MD_DEVS) { - MD_BUG(); - return -EINVAL; - } - /* * Commands dealing with the RAID driver but not any * particular array: @@ -2405,7 +2399,7 @@ static int md_ioctl(struct inode *inode, * Commands creating/starting a new array: */ - mddev = inode->i_bdev->bd_inode->u.generic_ip; + mddev = bdev->bd_inode->u.generic_ip; if (!mddev) { BUG(); @@ -2527,7 +2521,7 @@ static int md_ioctl(struct inode *inode, (short *) &loc->cylinders); if (err) goto abort_unlock; - err = put_user (get_start_sect(inode->i_bdev), + err = put_user (get_start_sect(bdev), (long *) &loc->start); goto done_unlock; } @@ -2605,12 +2599,12 @@ abort: return err; } -static int md_open(struct inode *inode, struct file *file) +static int md_open(struct block_device *bdev, struct file *file) { /* * Succeed if we can find or allocate a mddev structure. */ - mddev_t *mddev = mddev_find(iminor(inode)); + mddev_t *mddev = mddev_find(MINOR(bdev->bd_dev)); int err = -ENOMEM; if (!mddev) @@ -2621,16 +2615,16 @@ static int md_open(struct inode *inode, err = 0; mddev_unlock(mddev); - inode->i_bdev->bd_inode->u.generic_ip = mddev_get(mddev); + bdev->bd_inode->u.generic_ip = mddev_get(mddev); put: mddev_put(mddev); out: return err; } -static int md_release(struct inode *inode, struct file * file) +static int md_release(struct gendisk *disk) { - mddev_t *mddev = inode->i_bdev->bd_inode->u.generic_ip; + mddev_t *mddev = disk->private_data; if (!mddev) BUG(); --- linux-2.6.1-rc1/drivers/message/i2o/i2o_block.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/message/i2o/i2o_block.c 2003-12-30 22:49:33.000000000 -0800 @@ -885,10 +885,10 @@ static void i2o_block_biosparam( * Issue device specific ioctl calls. */ -static int i2ob_ioctl(struct inode *inode, struct file *file, +static int i2ob_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct i2ob_device *dev = disk->private_data; /* Anyone capable of this syscall can do *real bad* things */ @@ -901,7 +901,7 @@ static int i2ob_ioctl(struct inode *inod struct hd_geometry g; i2o_block_biosparam(get_capacity(disk), &g.cylinders, &g.heads, &g.sectors); - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0; } @@ -927,9 +927,8 @@ static int i2ob_ioctl(struct inode *inod * Close the block device down */ -static int i2ob_release(struct inode *inode, struct file *file) +static int i2ob_release(struct gendisk *disk) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct i2ob_device *dev = disk->private_data; /* @@ -999,9 +998,9 @@ static int i2ob_release(struct inode *in * Open the block device. */ -static int i2ob_open(struct inode *inode, struct file *file) +static int i2ob_open(struct block_device *bdev, struct file *file) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct i2ob_device *dev = disk->private_data; if(!dev->i2odev) --- linux-2.6.1-rc1/drivers/mtd/maps/pcmciamtd.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/mtd/maps/pcmciamtd.c 2003-12-30 22:50:04.000000000 -0800 @@ -125,7 +125,7 @@ static caddr_t remap_window(struct map_i DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", dev->offset, mrq.CardOffset); mrq.Page = 0; - if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) { + if( (ret = pcmcia_map_mem_page(win, &mrq)) != CS_SUCCESS) { cs_error(dev->link.handle, MapMemPage, ret); return NULL; } @@ -332,7 +332,7 @@ static void pcmciamtd_set_vpp(struct map mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0; DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); - ret = CardServices(ModifyConfiguration, link->handle, &mod); + ret = pcmcia_modify_configuration(link->handle, &mod); if(ret != CS_SUCCESS) { cs_error(link->handle, ModifyConfiguration, ret); } @@ -355,9 +355,9 @@ static void pcmciamtd_release(dev_link_t iounmap(dev->win_base); dev->win_base = NULL; } - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); } - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); link->state &= ~DEV_CONFIG; } @@ -375,14 +375,14 @@ static void card_settings(struct pcmciam tuple.TupleOffset = 0; tuple.DesiredTuple = RETURN_FIRST_TUPLE; - rc = CardServices(GetFirstTuple, link->handle, &tuple); + rc = pcmcia_get_first_tuple(link->handle, &tuple); while(rc == CS_SUCCESS) { - rc = CardServices(GetTupleData, link->handle, &tuple); + rc = pcmcia_get_tuple_data(link->handle, &tuple); if(rc != CS_SUCCESS) { cs_error(link->handle, GetTupleData, rc); break; } - rc = CardServices(ParseTuple, link->handle, &tuple, &parse); + rc = pcmcia_parse_tuple(link->handle, &tuple, &parse); if(rc != CS_SUCCESS) { cs_error(link->handle, ParseTuple, rc); break; @@ -455,7 +455,7 @@ static void card_settings(struct pcmciam DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); } - rc = CardServices(GetNextTuple, link->handle, &tuple, &parse); + rc = pcmcia_get_next_tuple(link->handle, &tuple); } if(!dev->pcmcia_map.size) dev->pcmcia_map.size = MAX_PCMCIA_ADDR; @@ -489,8 +489,8 @@ static void card_settings(struct pcmciam * MTD device available to the system. */ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void pcmciamtd_config(dev_link_t *link) { @@ -512,7 +512,7 @@ static void pcmciamtd_config(dev_link_t link->state |= DEV_CONFIG; DEBUG(2, "Validating CIS"); - ret = CardServices(ValidateCIS, link->handle, &cisinfo); + ret = pcmcia_validate_cis(link->handle, &cisinfo); if(ret != CS_SUCCESS) { cs_error(link->handle, GetTupleData, ret); } else { @@ -547,8 +547,7 @@ static void pcmciamtd_config(dev_link_t int ret; DEBUG(2, "requesting window with size = %dKiB memspeed = %d", req.Size >> 10, req.AccessSpeed); - link->win = (window_handle_t)link->handle; - ret = CardServices(RequestWindow, &link->win, &req); + ret = pcmcia_request_window(&link->handle, &req, &link->win); DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); if(ret) { req.Size >>= 1; @@ -569,7 +568,7 @@ static void pcmciamtd_config(dev_link_t DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ - CS_CHECK(GetStatus, link->handle, &status); + CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", status.CardState, (unsigned long)link->win); dev->win_base = ioremap(req.Base, req.Size); @@ -586,7 +585,7 @@ static void pcmciamtd_config(dev_link_t dev->pcmcia_map.map_priv_2 = (unsigned long)link->win; DEBUG(2, "Getting configuration"); - CS_CHECK(GetConfigurationInfo, link->handle, &t); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link->handle, &t)); DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2); dev->vpp = (vpp) ? vpp : t.Vpp1; link->conf.Attributes = 0; @@ -608,7 +607,7 @@ static void pcmciamtd_config(dev_link_t link->conf.ConfigIndex = 0; link->conf.Present = t.Present; DEBUG(2, "Setting Configuration"); - ret = CardServices(RequestConfiguration, link->handle, &link->conf); + ret = pcmcia_request_configuration(link->handle, &link->conf); if(ret != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, ret); } @@ -757,7 +756,7 @@ static void pcmciamtd_detach(dev_link_t if (link->handle) { int ret; DEBUG(2, "Deregistering with card services"); - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -804,7 +803,7 @@ static dev_link_t *pcmciamtd_attach(void client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; DEBUG(2, "Calling RegisterClient"); - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); pcmciamtd_detach(link); --- linux-2.6.1-rc1/drivers/mtd/mtd_blkdevs.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/mtd/mtd_blkdevs.c 2003-12-30 22:49:33.000000000 -0800 @@ -141,14 +141,12 @@ static void mtd_blktrans_request(struct } -int blktrans_open(struct inode *i, struct file *f) +static int blktrans_open(struct block_device *bdev, struct file *f) { - struct mtd_blktrans_dev *dev; - struct mtd_blktrans_ops *tr; + struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; + struct mtd_blktrans_ops *tr = dev->tr; int ret = -ENODEV; - dev = i->i_bdev->bd_disk->private_data; - tr = dev->tr; if (!try_module_get(dev->mtd->owner)) goto out; @@ -172,15 +170,12 @@ int blktrans_open(struct inode *i, struc return ret; } -int blktrans_release(struct inode *i, struct file *f) +static int blktrans_release(struct gendisk *disk) { - struct mtd_blktrans_dev *dev; - struct mtd_blktrans_ops *tr; + struct mtd_blktrans_dev *dev = disk->private_data; + struct mtd_blktrans_ops *tr = dev->tr; int ret = 0; - dev = i->i_bdev->bd_disk->private_data; - tr = dev->tr; - if (tr->release) ret = tr->release(dev); @@ -194,10 +189,10 @@ int blktrans_release(struct inode *i, st } -static int blktrans_ioctl(struct inode *inode, struct file *file, +static int blktrans_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; + struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; struct mtd_blktrans_ops *tr = dev->tr; switch (cmd) { @@ -217,7 +212,7 @@ static int blktrans_ioctl(struct inode * if (ret) return ret; - g.start = get_start_sect(inode->i_bdev); + g.start = get_start_sect(bdev); if (copy_to_user((void *)arg, &g, sizeof(g))) return -EFAULT; return 0; --- linux-2.6.1-rc1/drivers/net/3c501.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/net/3c501.c 2003-12-30 22:49:19.000000000 -0800 @@ -136,17 +136,14 @@ static const char version[] = #include "3c501.h" -/* A zero-terminated list of I/O addresses to be probed. - The 3c501 can be at many locations, but here are the popular ones. */ -static unsigned int netcard_portlist[] __initdata = { - 0x280, 0x300, 0 -}; - - /* * The boilerplate probe code. */ +static int io=0x280; +static int irq=5; +static int mem_start; + /** * el1_probe: - probe for a 3c501 * @dev: The device structure passed in to probe. @@ -160,23 +157,47 @@ static unsigned int netcard_portlist[] _ * probe and failing to find anything. */ -int __init el1_probe(struct net_device *dev) +struct net_device * __init el1_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + static unsigned ports[] = { 0x280, 0x300, 0}; + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + mem_start = dev->mem_start & 7; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el1_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; netcard_portlist[i]; i++) - if (el1_probe1(dev, netcard_portlist[i]) == 0) - return 0; - - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = el1_probe1(dev, io); + } else if (io != 0) { + err = -ENXIO; /* Don't probe at all. */ + } else { + for (port = ports; *port && el1_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, EL1_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /** @@ -240,6 +261,8 @@ static int __init el1_probe1(struct net_ * high. */ + dev->irq = irq; + if (dev->irq < 2) { unsigned long irq_mask; @@ -267,8 +290,8 @@ static int __init el1_probe1(struct net_ dev->base_addr = ioaddr; memcpy(dev->dev_addr, station_addr, ETH_ALEN); - if (dev->mem_start & 0xf) - el_debug = dev->mem_start & 0x7; + if (mem_start & 0xf) + el_debug = mem_start & 0x7; if (autoirq) dev->irq = autoirq; @@ -282,17 +305,7 @@ static int __init el1_probe1(struct net_ if (el_debug) printk(KERN_DEBUG "%s", version); - /* - * Initialize the device structure. - */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - release_region(ioaddr, EL1_IO_EXTENT); - return -ENOMEM; - } memset(dev->priv, 0, sizeof(struct net_local)); - lp=dev->priv; spin_lock_init(&lp->lock); @@ -308,13 +321,6 @@ static int __init el1_probe1(struct net_ dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; dev->ethtool_ops = &netdev_ethtool_ops; - - /* - * Setup the generic properties - */ - - ether_setup(dev); - return 0; } @@ -884,14 +890,8 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE -static struct net_device dev_3c501 = { - .init = el1_probe, - .base_addr = 0x280, - .irq = 5, -}; +static struct net_device *dev_3c501; -static int io=0x280; -static int irq=5; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(io, "EtherLink I/O base address"); @@ -911,10 +911,9 @@ MODULE_PARM_DESC(irq, "EtherLink IRQ num int init_module(void) { - dev_3c501.irq=irq; - dev_3c501.base_addr=io; - if (register_netdev(&dev_3c501) != 0) - return -EIO; + dev_3c501 = el1_probe(-1); + if (IS_ERR(dev_3c501)) + return PTR_ERR(dev_3c501); return 0; } @@ -927,19 +926,10 @@ int init_module(void) void cleanup_module(void) { - unregister_netdev(&dev_3c501); - - /* - * Free up the private structure, or leak memory :-) - */ - - kfree(dev_3c501.priv); - dev_3c501.priv = NULL; /* gets re-allocated by el1_probe1 */ - - /* - * If we don't do this, we can't re-insmod it later. - */ - release_region(dev_3c501.base_addr, EL1_IO_EXTENT); + struct net_device *dev = dev_3c501; + unregister_netdev(dev); + release_region(dev->base_addr, EL1_IO_EXTENT); + free_netdev(dev); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/3c501.h 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/3c501.h 2003-12-30 22:49:19.000000000 -0800 @@ -3,7 +3,6 @@ * Index to functions. */ -int el1_probe(struct net_device *dev); static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); static void el_timeout(struct net_device *dev); --- linux-2.6.1-rc1/drivers/net/3c503.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/net/3c503.c 2003-12-30 22:49:19.000000000 -0800 @@ -60,7 +60,6 @@ static const char version[] = #include "3c503.h" #define WRD_COUNT 4 -int el2_probe(struct net_device *dev); static int el2_pio_probe(struct net_device *dev); static int el2_probe1(struct net_device *dev, int ioaddr); @@ -90,11 +89,11 @@ static struct ethtool_ops netdev_ethtool If the ethercard isn't found there is an optional probe for ethercard jumpered to programmed-I/O mode. */ -int __init -el2_probe(struct net_device *dev) +static int __init do_el2_probe(struct net_device *dev) { int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0}; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -104,16 +103,13 @@ el2_probe(struct net_device *dev) return -ENXIO; for (addr = addrs; *addr; addr++) { - int i; - unsigned int base_bits = isa_readb(*addr); - /* Find first set bit. */ - for(i = 7; i >= 0; i--, base_bits >>= 1) - if (base_bits & 0x1) - break; - if (base_bits != 1) + unsigned base_bits = isa_readb(*addr); + int i = ffs(base_bits) - 1; + if (i == -1 || base_bits != (1 << i)) continue; if (el2_probe1(dev, netcard_portlist[i]) == 0) return 0; + dev->irq = irq; } #if ! defined(no_probe_nonshared_memory) return el2_pio_probe(dev); @@ -128,20 +124,54 @@ static int __init el2_pio_probe(struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; + int base_addr = dev->base_addr; + int irq = dev->irq; if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; netcard_portlist[i]; i++) + for (i = 0; netcard_portlist[i]; i++) { if (el2_probe1(dev, netcard_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: el2_close() handles free_irq */ + release_region(dev->base_addr, EL2_IO_EXTENT); +} + +struct net_device * __init el2_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_el2_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ @@ -152,15 +182,19 @@ el2_probe1(struct net_device *dev, int i static unsigned version_printed; unsigned long vendor_id; - /* FIXME: code reads ioaddr + 0x400, we request ioaddr + 16 */ if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name)) return -EBUSY; + if (!request_region(ioaddr + 0x400, 8, dev->name)) { + retval = -EBUSY; + goto out; + } + /* Reset and/or avoid any lurking NE2000 */ if (inb(ioaddr + 0x408) == 0xff) { mdelay(1); retval = -ENODEV; - goto out; + goto out1; } /* We verify that it's a 3C503 board by checking the first three octets @@ -171,7 +205,7 @@ el2_probe1(struct net_device *dev, int i if ( (iobase_reg & (iobase_reg - 1)) || (membase_reg & (membase_reg - 1))) { retval = -ENODEV; - goto out; + goto out1; } saved_406 = inb_p(ioaddr + 0x406); outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */ @@ -184,19 +218,13 @@ el2_probe1(struct net_device *dev, int i /* Restore the register we frobbed. */ outb(saved_406, ioaddr + 0x406); retval = -ENODEV; - goto out; + goto out1; } if (ei_debug && version_printed++ == 0) printk(version); dev->base_addr = ioaddr; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("3c503: unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); @@ -322,7 +350,10 @@ el2_probe1(struct net_device *dev, int i printk("\n%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", dev->name, ei_status.name, (wordlength+1)<<3); } + release_region(ioaddr + 0x400, 8); return 0; +out1: + release_region(ioaddr + 0x400, 8); out: release_region(ioaddr, EL2_IO_EXTENT); return retval; @@ -633,7 +664,7 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE #define MAX_EL2_CARDS 4 /* Max number of EL2 cards per module */ -static struct net_device dev_el2[MAX_EL2_CARDS]; +static struct net_device *dev_el2[MAX_EL2_CARDS]; static int io[MAX_EL2_CARDS]; static int irq[MAX_EL2_CARDS]; static int xcvr[MAX_EL2_CARDS]; /* choose int. or ext. xcvr */ @@ -651,28 +682,34 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { - struct net_device *dev = &dev_el2[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ - dev->init = el2_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ + if (do_el2_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_el2[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -681,13 +718,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { - struct net_device *dev = &dev_el2[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - /* NB: el2_close() handles free_irq */ - release_region(dev->base_addr, EL2_IO_EXTENT); + struct net_device *dev = dev_el2[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/3c505.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/net/3c505.c 2003-12-30 22:49:19.000000000 -0800 @@ -1293,42 +1293,6 @@ static void elp_set_mc_list(struct net_d } } -/****************************************************** - * - * initialise Etherlink Plus board - * - ******************************************************/ - -static inline void elp_init(struct net_device *dev) -{ - elp_device *adapter = dev->priv; - - /* - * set ptrs to various functions - */ - dev->open = elp_open; /* local */ - dev->stop = elp_close; /* local */ - dev->get_stats = elp_get_stats; /* local */ - dev->hard_start_xmit = elp_start_xmit; /* local */ - dev->tx_timeout = elp_timeout; /* local */ - dev->watchdog_timeo = 10*HZ; - dev->set_multicast_list = elp_set_mc_list; /* local */ - dev->ethtool_ops = &netdev_ethtool_ops; /* local */ - - /* Setup the generic properties */ - ether_setup(dev); - - /* - * setup ptr to adapter specific information - */ - memset(&(adapter->stats), 0, sizeof(struct net_device_stats)); - - /* - * memory information - */ - dev->mem_start = dev->mem_end = 0; -} - /************************************************************ * * A couple of tests to see if there's 3C505 or not @@ -1442,12 +1406,13 @@ static int __init elp_autodetect(struct * work at all if it was in a weird state). */ -int __init elplus_probe(struct net_device *dev) +static int __init elplus_setup(struct net_device *dev) { - elp_device *adapter; + elp_device *adapter = dev->priv; int i, tries, tries1, okay; unsigned long timeout; unsigned long cookie = 0; + int err = -ENODEV; SET_MODULE_OWNER(dev); @@ -1456,17 +1421,8 @@ int __init elplus_probe(struct net_devic */ dev->base_addr = elp_autodetect(dev); - if (!(dev->base_addr)) - return -ENODEV; - - /* - * setup ptr to adapter specific information - */ - adapter = (elp_device *) (dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL)); - if (adapter == NULL) { - printk(KERN_ERR "%s: out of memory\n", dev->name); + if (!dev->base_addr) return -ENODEV; - } adapter->send_pcb_semaphore = 0; @@ -1544,8 +1500,7 @@ int __init elplus_probe(struct net_devic outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev); } printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name); - release_region(dev->base_addr, ELP_IO_EXTENT); - return -ENODEV; + goto out; okay: if (dev->irq) { /* Is there a preset IRQ? */ @@ -1560,14 +1515,14 @@ int __init elplus_probe(struct net_devic case 0: printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n", dev->name); - return -ENODEV; + goto out; case 1: case 6: case 8: case 13: printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n", dev->name, dev->irq); - return -ENODEV; + goto out; } /* * Now we have the IRQ number so we can disable the interrupts from @@ -1636,16 +1591,48 @@ int __init elplus_probe(struct net_devic printk(KERN_ERR "%s: adapter configuration failed\n", dev->name); } - /* - * initialise the device - */ - elp_init(dev); + dev->open = elp_open; /* local */ + dev->stop = elp_close; /* local */ + dev->get_stats = elp_get_stats; /* local */ + dev->hard_start_xmit = elp_start_xmit; /* local */ + dev->tx_timeout = elp_timeout; /* local */ + dev->watchdog_timeo = 10*HZ; + dev->set_multicast_list = elp_set_mc_list; /* local */ + dev->ethtool_ops = &netdev_ethtool_ops; /* local */ + + memset(&(adapter->stats), 0, sizeof(struct net_device_stats)); + dev->mem_start = dev->mem_end = 0; + + err = register_netdev(dev); + if (err) + goto out; return 0; +out: + release_region(dev->base_addr, ELP_IO_EXTENT); + return err; +} + +struct net_device * __init elplus_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(elp_device)); + int err; + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = elplus_setup(dev); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + return dev; } #ifdef MODULE -static struct net_device dev_3c505[ELP_MAX_CARDS]; +static struct net_device *dev_3c505[ELP_MAX_CARDS]; static int io[ELP_MAX_CARDS]; static int irq[ELP_MAX_CARDS]; static int dma[ELP_MAX_CARDS]; @@ -1661,10 +1648,12 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_3c505[this_dev]; + struct net_device *dev = alloc_etherdev(sizeof(elp_device)); + if (!dev) + break; + dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->init = elplus_probe; if (dma[this_dev]) { dev->dma = dma[this_dev]; } else { @@ -1672,16 +1661,22 @@ int init_module(void) printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n"); } if (io[this_dev] == 0) { - if (this_dev) break; + if (this_dev) { + free_netdev(dev); + break; + } printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n"); } - if (register_netdev(dev) != 0) { + if (elplus_setup(dev) != 0) { printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); - if (found != 0) return 0; - return -ENXIO; + free_netdev(dev); + break; } + dev_3c505[this_dev] = dev; found++; } + if (!found) + return -ENODEV; return 0; } @@ -1690,12 +1685,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_3c505[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_3c505[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; release_region(dev->base_addr, ELP_IO_EXTENT); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/3c507.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/3c507.c 2003-12-30 22:49:19.000000000 -0800 @@ -74,10 +74,6 @@ static unsigned int net_debug = NET_DEBU #define debug net_debug -/* A zero-terminated list of common I/O addresses to be probed. */ -static unsigned int netcard_portlist[] __initdata = - { 0x300, 0x320, 0x340, 0x280, 0}; - /* Details of the i82586. @@ -286,8 +282,6 @@ static unsigned short init_words[] = { /* Index to functions, as function prototypes. */ -extern int el16_probe(struct net_device *dev); /* Called from Space.c */ - static int el16_probe1(struct net_device *dev, int ioaddr); static int el16_open(struct net_device *dev); static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -301,6 +295,10 @@ static void hardware_send_packet(struct static void init_82586_mem(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static int io = 0x300; +static int irq; +static int mem_start; + /* Check for a network adaptor of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. @@ -309,23 +307,50 @@ static struct ethtool_ops netdev_ethtool device and return success. */ -int __init el16_probe(struct net_device *dev) +struct net_device * __init el16_probe(int unit) { - int base_addr = dev->base_addr; - int i; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + static unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0}; + unsigned *port; + int err = -ENODEV; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + mem_start = dev->mem_start & 15; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el16_probe1(dev, base_addr); - else if (base_addr != 0) - return -ENXIO; /* Don't probe at all. */ - - for (i = 0; netcard_portlist[i]; i++) - if (el16_probe1(dev, netcard_portlist[i]) == 0) - return 0; + if (io > 0x1ff) /* Check a single specified location. */ + err = el16_probe1(dev, io); + else if (io != 0) + err = -ENXIO; /* Don't probe at all. */ + else { + for (port = ports; *port; port++) { + err = el16_probe1(dev, *port); + if (!err) + break; + } + } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, EL16_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init el16_probe1(struct net_device *dev, int ioaddr) @@ -383,8 +408,8 @@ static int __init el16_probe1(struct net printk(" %02x", dev->dev_addr[i]); } - if ((dev->mem_start & 0xf) > 0) - net_debug = dev->mem_start & 7; + if (mem_start) + net_debug = mem_start & 7; #ifdef MEM_BASE dev->mem_start = MEM_BASE; @@ -416,27 +441,18 @@ static int __init el16_probe1(struct net if (net_debug) printk(version); - /* Initialize the device structure. */ - lp = dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto out; - } - memset(dev->priv, 0, sizeof(struct net_local)); + lp = dev->priv; + memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); - dev->open = el16_open; - dev->stop = el16_close; + dev->open = el16_open; + dev->stop = el16_close; dev->hard_start_xmit = el16_send_packet; dev->get_stats = el16_get_stats; dev->tx_timeout = el16_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->ethtool_ops = &netdev_ethtool_ops; - - ether_setup(dev); /* Generic ethernet behaviour */ - - dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */ - + dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ return 0; out: release_region(ioaddr, EL16_IO_EXTENT); @@ -899,9 +915,7 @@ static struct ethtool_ops netdev_ethtool }; #ifdef MODULE -static struct net_device dev_3c507; -static int io = 0x300; -static int irq; +static struct net_device *dev_3c507; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(io, "EtherLink16 I/O base address"); @@ -911,26 +925,18 @@ int init_module(void) { if (io == 0) printk("3c507: You should not use auto-probing with insmod!\n"); - dev_3c507.base_addr = io; - dev_3c507.irq = irq; - dev_3c507.init = el16_probe; - if (register_netdev(&dev_3c507) != 0) { - printk("3c507: register_netdev() returned non-zero.\n"); - return -EIO; - } - return 0; + dev_3c507 = el16_probe(-1); + return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0; } void cleanup_module(void) { - unregister_netdev(&dev_3c507); - kfree(dev_3c507.priv); - dev_3c507.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_3c507.irq, &dev_3c507); - release_region(dev_3c507.base_addr, EL16_IO_EXTENT); + struct net_device *dev = dev_3c507; + unregister_netdev(dev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, EL16_IO_EXTENT); + free_netdev(dev); } #endif /* MODULE */ MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/3c515.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/net/3c515.c 2003-12-30 22:49:19.000000000 -0800 @@ -307,7 +307,8 @@ struct boom_tx_desc { struct corkscrew_private { const char *product_name; - struct net_device *next_module; + struct list_head list; + struct net_device *our_dev; /* The Rx and Tx rings are here to keep them quad-word-aligned. */ struct boom_rx_desc rx_ring[RX_RING_SIZE]; struct boom_tx_desc tx_ring[TX_RING_SIZE]; @@ -329,6 +330,7 @@ struct corkscrew_private { full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ tx_full:1; spinlock_t lock; + struct device *dev; }; /* The action to take with a media selection timer tick. @@ -367,17 +369,12 @@ static struct isapnp_device_id corkscrew MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); -static int corkscrew_isapnp_phys_addr[3]; - static int nopnp; #endif /* __ISAPNP__ */ -static int corkscrew_scan(struct net_device *dev); -static struct net_device *corkscrew_found_device(struct net_device *dev, - int ioaddr, int irq, - int product_index, - int options); -static int corkscrew_probe1(struct net_device *dev); +static struct net_device *corkscrew_scan(int unit); +static void corkscrew_setup(struct net_device *dev, int ioaddr, + struct pnp_dev *idev, int card_number); static int corkscrew_open(struct net_device *dev); static void corkscrew_timer(unsigned long arg); static int corkscrew_start_xmit(struct sk_buff *skb, @@ -413,47 +410,99 @@ static int options[MAX_UNITS] = { -1, -1 #ifdef MODULE static int debug = -1; /* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_corkscrew_dev; +/* we will need locking (and refcounting) if we ever use it for more */ +static LIST_HEAD(root_corkscrew_dev); int init_module(void) { - int cards_found; - + int found = 0; if (debug >= 0) corkscrew_debug = debug; if (corkscrew_debug) printk(version); - - root_corkscrew_dev = NULL; - cards_found = corkscrew_scan(NULL); - return cards_found ? 0 : -ENODEV; + while (corkscrew_scan(-1)) + found++; + return found ? 0 : -ENODEV; } #else -int tc515_probe(struct net_device *dev) +struct net_device *tc515_probe(int unit) { - int cards_found = 0; + struct net_device *dev = corkscrew_scan(unit); + static int printed; - SET_MODULE_OWNER(dev); - - cards_found = corkscrew_scan(dev); + if (!dev) + return ERR_PTR(-ENODEV); - if (corkscrew_debug > 0 && cards_found) + if (corkscrew_debug > 0 && !printed) { + printed = 1; printk(version); + } - return cards_found ? 0 : -ENODEV; + return dev; } #endif /* not MODULE */ -static int corkscrew_scan(struct net_device *dev) +static int check_device(unsigned ioaddr) +{ + int timer; + + if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515")) + return 0; + /* Check the resource configuration for a matching ioaddr. */ + if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { + release_region(ioaddr, CORKSCREW_TOTAL_SIZE); + return 0; + } + /* Verify by reading the device ID from the EEPROM. */ + outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 4; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) + break; + } + if (inw(ioaddr + Wn0EepromData) != 0x6d50) { + release_region(ioaddr, CORKSCREW_TOTAL_SIZE); + return 0; + } + return 1; +} + +static void cleanup_card(struct net_device *dev) { - int cards_found = 0; + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; + list_del_init(&vp->list); + if (dev->dma) + free_dma(dev->dma); + outw(TotalReset, dev->base_addr + EL3_CMD); + release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE); + if (vp->dev) + pnp_device_detach(to_pnp_dev(vp->dev)); +} + +static struct net_device *corkscrew_scan(int unit) +{ + struct net_device *dev; + static int cards_found = 0; static int ioaddr; + int err; #ifdef __ISAPNP__ short i; static int pnp_cards; #endif + dev = alloc_etherdev(sizeof(struct corkscrew_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + SET_MODULE_OWNER(dev); + #ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; @@ -470,7 +519,7 @@ static int corkscrew_scan(struct net_dev if (pnp_activate_dev(idev) < 0) { printk("pnp activate failed (out of resources?)\n"); pnp_device_detach(idev); - return -ENOMEM; + continue; } if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { pnp_device_detach(idev); @@ -478,40 +527,22 @@ static int corkscrew_scan(struct net_dev } ioaddr = pnp_port_start(idev, 0); irq = pnp_irq(idev, 0); - if(corkscrew_debug) - printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", - (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { + if (!check_device(ioaddr)) { pnp_device_detach(idev); continue; } - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) - == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) { - pnp_device_detach(idev); - continue; - } - } + if(corkscrew_debug) + printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", + (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ - corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr; - corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev - && dev->mem_start ? dev-> - mem_start : options[cards_found]); - dev = 0; + corkscrew_setup(dev, ioaddr, idev, cards_found++); pnp_cards++; - cards_found++; + err = register_netdev(dev); + if (!err) + return dev; + cleanup_card(dev); } } no_pnp: @@ -519,122 +550,64 @@ no_pnp: /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - int irq; -#ifdef __ISAPNP__ - /* Make sure this was not already picked up by isapnp */ - if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; - if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; - if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue; -#endif /* __ISAPNP__ */ - if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) + if (!check_device(ioaddr)) continue; - /* Check the resource configuration for a matching ioaddr. */ - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) - continue; - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) - == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) - continue; - } + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - irq = inw(ioaddr + 0x2002) & 15; - corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, - dev && dev->mem_start ? dev->mem_start : - (cards_found >= MAX_UNITS ? -1 : - options[cards_found])); - dev = 0; - cards_found++; + corkscrew_setup(dev, ioaddr, NULL, cards_found++); + err = register_netdev(dev); + if (!err) + return dev; + cleanup_card(dev); } - if (corkscrew_debug) - printk(KERN_INFO "%d 3c515 cards found.\n", cards_found); - return cards_found; + free_netdev(dev); + return NULL; } -static struct net_device *corkscrew_found_device(struct net_device *dev, - int ioaddr, int irq, - int product_index, - int options) +static void corkscrew_setup(struct net_device *dev, int ioaddr, + struct pnp_dev *idev, int card_number) { - struct corkscrew_private *vp; - -#ifdef MODULE - /* Allocate and fill new device structure. */ - int dev_size = sizeof(struct net_device) + sizeof(struct corkscrew_private) + 15; /* Pad for alignment */ + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; + unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ + int i; + int irq; - dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, dev_size); - /* Align the Rx and Tx ring entries. */ - dev->priv = (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15); - vp = (struct corkscrew_private *) dev->priv; - dev->base_addr = ioaddr; - dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - dev->init = corkscrew_probe1; - vp->product_name = "3c515"; - vp->options = options; - if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; - vp->bus_master = (options & 16) ? 1 : 0; + if (idev) { + irq = pnp_irq(idev, 0); + vp->dev = &idev->dev; } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; + irq = inw(ioaddr + 0x2002) & 15; } - ether_setup(dev); - vp->next_module = root_corkscrew_dev; - root_corkscrew_dev = dev; - SET_MODULE_OWNER(dev); - if (register_netdev(dev) != 0) { - kfree(dev); - return NULL; - } -#else /* not a MODULE */ - /* Caution: quad-word alignment required for rings! */ - dev->priv = kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL); - if (!dev->priv) - return NULL; - memset(dev->priv, 0, sizeof(struct corkscrew_private)); - dev = init_etherdev(dev, sizeof(struct corkscrew_private)); + dev->base_addr = ioaddr; dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - vp = (struct corkscrew_private *) dev->priv; + dev->dma = inw(ioaddr + 0x2000) & 7; vp->product_name = "3c515"; - vp->options = options; - if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; - vp->bus_master = (options & 16) ? 1 : 0; + vp->options = dev->mem_start; + vp->our_dev = dev; + + if (!vp->options) { + if (card_number >= MAX_UNITS) + vp->options = -1; + else + vp->options = options[card_number]; + } + + if (vp->options >= 0) { + vp->media_override = vp->options & 7; + if (vp->media_override == 2) + vp->media_override = 0; + vp->full_duplex = (vp->options & 8) ? 1 : 0; + vp->bus_master = (vp->options & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } - - corkscrew_probe1(dev); -#endif /* MODULE */ - return dev; -} - -static int corkscrew_probe1(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i; +#ifdef MODULE + list_add(&vp->list, &root_corkscrew_dev); +#endif printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); @@ -706,9 +679,6 @@ static int corkscrew_probe1(struct net_d /* vp->full_bus_master_rx = 0; */ vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0; - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name); - /* The 3c51x-specific entries in the device structure. */ dev->open = &corkscrew_open; dev->hard_start_xmit = &corkscrew_start_xmit; @@ -718,8 +688,6 @@ static int corkscrew_probe1(struct net_d dev->get_stats = &corkscrew_get_stats; dev->set_multicast_list = &set_rx_mode; dev->ethtool_ops = &netdev_ethtool_ops; - - return 0; } @@ -1607,20 +1575,16 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE void cleanup_module(void) { - struct net_device *next_dev; - - while (root_corkscrew_dev) { - next_dev = - ((struct corkscrew_private *) root_corkscrew_dev-> - priv)->next_module; - if (root_corkscrew_dev->dma) - free_dma(root_corkscrew_dev->dma); - unregister_netdev(root_corkscrew_dev); - outw(TotalReset, root_corkscrew_dev->base_addr + EL3_CMD); - release_region(root_corkscrew_dev->base_addr, - CORKSCREW_TOTAL_SIZE); - free_netdev(root_corkscrew_dev); - root_corkscrew_dev = next_dev; + while (!list_empty(&root_corkscrew_dev)) { + struct net_device *dev; + struct corkscrew_private *vp; + + vp = list_entry(root_corkscrew_dev.next, + struct corkscrew_private, list); + dev = vp->our_dev; + unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); } } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/3c523.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/3c523.c 2003-12-30 22:49:19.000000000 -0800 @@ -410,7 +410,7 @@ static int elmc_getinfo(char *buf, int s /*****************************************************************/ -int __init elmc_probe(struct net_device *dev) +static int __init do_elmc_probe(struct net_device *dev) { static int slot; int base_addr = dev->base_addr; @@ -420,7 +420,7 @@ int __init elmc_probe(struct net_device int i = 0; unsigned int size = 0; int retval; - struct priv *pr; + struct priv *pr = dev->priv; SET_MODULE_OWNER(dev); if (MCA_bus == 0) { @@ -455,10 +455,9 @@ int __init elmc_probe(struct net_device } /* we didn't find any 3c523 in the slots we checked for */ - if (slot == MCA_NOTFOUND) { - retval = ((base_addr || irq) ? -ENXIO : -ENODEV); - goto err_out; - } + if (slot == MCA_NOTFOUND) + return ((base_addr || irq) ? -ENXIO : -ENODEV); + mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC"); mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); @@ -497,13 +496,7 @@ int __init elmc_probe(struct net_device break; } - pr = dev->priv = kmalloc(sizeof(struct priv), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } memset(pr, 0, sizeof(struct priv)); - pr->slot = slot; printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, @@ -530,8 +523,6 @@ int __init elmc_probe(struct net_device if (!check586(dev, dev->mem_start, size)) { printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); - kfree(dev->priv); - dev->priv = NULL; retval = -ENODEV; goto err_out; } @@ -573,8 +564,6 @@ int __init elmc_probe(struct net_device #endif dev->ethtool_ops = &netdev_ethtool_ops; - ether_setup(dev); - /* note that we haven't actually requested the IRQ from the kernel. That gets done in elmc_open(). I'm not sure that's such a good idea, but it works, so I'll go with it. */ @@ -585,9 +574,41 @@ int __init elmc_probe(struct net_device return 0; err_out: + mca_set_adapter_procfn(slot, NULL, NULL); release_region(dev->base_addr, ELMC_IO_EXTENT); return retval; } + +static void cleanup_card(struct net_device *dev) +{ + mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); + release_region(dev->base_addr, ELMC_IO_EXTENT); +} + +struct net_device * __init elmc_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_elmc_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} /********************************************** * init the chip (elmc-interrupt should be disabled?!) @@ -1245,7 +1266,7 @@ static struct ethtool_ops netdev_ethtool /* Increase if needed ;) */ #define MAX_3C523_CARDS 4 -static struct net_device dev_elmc[MAX_3C523_CARDS]; +static struct net_device *dev_elmc[MAX_3C523_CARDS]; static int irq[MAX_3C523_CARDS]; static int io[MAX_3C523_CARDS]; MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); @@ -1258,16 +1279,24 @@ int init_module(void) int this_dev,found = 0; /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ - for(this_dev=0; this_devirq=irq[this_dev]; dev->base_addr=io[this_dev]; - dev->init=elmc_probe; - if(register_netdev(dev)!=0) { - if(io[this_dev]==0) break; - printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); - } else found++; + if (do_elmc_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_elmc[this_dev] = dev; + found++; + continue; + } + cleanup_card(dev); + } + free_netdev(dev); + if (io[this_dev]==0) + break; + printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } if(found==0) { @@ -1279,31 +1308,12 @@ int init_module(void) void cleanup_module(void) { int this_dev; - for(this_dev=0; this_devpriv) { - /* shutdown interrupts on the card */ - elmc_id_reset586(); - if (dev->irq != 0) { - /* this should be done by close, but if we failed to - initialize properly something may have gotten hosed. */ - free_irq(dev->irq, dev); - dev->irq = 0; - } - if (dev->base_addr != 0) { - release_region(dev->base_addr, ELMC_IO_EXTENT); - dev->base_addr = 0; - } - irq[this_dev] = 0; - io[this_dev] = 0; + for (this_dev=0; this_devpriv))->slot, - NULL, NULL); - - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/3c527.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/3c527.c 2003-12-30 22:49:19.000000000 -0800 @@ -1,9 +1,10 @@ -/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 +/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6. * * (c) Copyright 1998 Red Hat Software Inc * Written by Alan Cox. * Further debugging by Carl Drougge. - * Modified by Richard Procter (rnp@netlink.co.nz) + * Initial SMP support by Felipe W Damasio + * Heavily modified by Richard Procter * * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c * (for the MCA stuff) written by Wim Dumon. @@ -17,11 +18,11 @@ */ #define DRV_NAME "3c527" -#define DRV_VERSION "0.6a" -#define DRV_RELDATE "2001/11/17" +#define DRV_VERSION "0.7-SMP" +#define DRV_RELDATE "2003/09/21" static const char *version = -DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Proctor (rnp@netlink.co.nz)\n"; +DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter \n"; /** * DOC: Traps for the unwary @@ -100,7 +101,9 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELD #include #include #include +#include +#include #include #include #include @@ -143,19 +146,19 @@ static unsigned int mc32_debug = NET_DEB static const int WORKAROUND_82586=1; /* Pointers to buffers and their on-card records */ - struct mc32_ring_desc { volatile struct skb_header *p; struct sk_buff *skb; }; - /* Information that needs to be kept for each board. */ struct mc32_local { - struct net_device_stats net_stats; int slot; + + u32 base; + struct net_device_stats net_stats; volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; @@ -165,22 +168,23 @@ struct mc32_local u16 tx_len; /* Transmit list count */ u16 rx_len; /* Receive list count */ - u32 base; - u16 exec_pending; - u16 mc_reload_wait; /* a multicast load request is pending */ + u16 xceiver_desired_state; /* HALTED or RUNNING */ + u16 cmd_nonblocking; /* Thread is uninterested in command result */ + u16 mc_reload_wait; /* A multicast load request is pending */ u32 mc_list_valid; /* True when the mclist is set */ - u16 xceiver_state; /* Current transceiver state. bitmapped */ - u16 desired_state; /* The state we want the transceiver to be in */ - atomic_t tx_count; /* buffers left */ - wait_queue_head_t event; struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */ + atomic_t tx_count; /* buffers left */ + atomic_t tx_ring_head; /* index to tx en-queue end */ u16 tx_ring_tail; /* index to tx de-queue end */ - u16 tx_ring_head; /* index to tx en-queue end */ u16 rx_ring_tail; /* index to rx de-queue end */ + + struct semaphore cmd_mutex; /* Serialises issuing of execute commands */ + struct completion execution_cmd; /* Card has completed an execute command */ + struct completion xceiver_cmd; /* Card has completed a tx or rx command */ }; /* The station (ethernet) address prefix, used for a sanity check. */ @@ -208,8 +212,6 @@ static inline u16 next_tx(u16 tx) { retu /* Index to functions, as function prototypes. */ -extern int mc32_probe(struct net_device *dev); - static int mc32_probe1(struct net_device *dev, int ioaddr); static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); @@ -222,9 +224,19 @@ static void mc32_set_multicast_list(stru static void mc32_reset_multicast_list(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static void cleanup_card(struct net_device *dev) +{ + struct mc32_local *lp=dev->priv; + unsigned slot = lp->slot; + mca_mark_as_unused(slot); + mca_set_adapter_name(slot, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, MC32_IO_EXTENT); +} + /** * mc32_probe - Search for supported boards - * @dev: device to probe + * @unit: interface number to use * * Because MCA bus is a real bus and we can scan for cards we could do a * single scan for all boards here. Right now we use the passed in device @@ -232,11 +244,18 @@ static struct ethtool_ops netdev_ethtool * in particular. */ -int __init mc32_probe(struct net_device *dev) +struct net_device *__init mc32_probe(int unit) { + struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local)); static int current_mca_slot = -1; int i; - int adapter_found = 0; + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); SET_MODULE_OWNER(dev); @@ -247,22 +266,28 @@ int __init mc32_probe(struct net_device Autodetecting MCA cards is extremely simple. Just search for the card. */ - for(i = 0; (mc32_adapters[i].name != NULL) && !adapter_found; i++) { + for(i = 0; (mc32_adapters[i].name != NULL); i++) { current_mca_slot = mca_find_unused_adapter(mc32_adapters[i].id, 0); - if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { + if(current_mca_slot != MCA_NOTFOUND) { if(!mc32_probe1(dev, current_mca_slot)) { mca_set_adapter_name(current_mca_slot, mc32_adapters[i].name); mca_mark_as_used(current_mca_slot); - return 0; + err = register_netdev(dev); + if (err) { + cleanup_card(dev); + free_netdev(dev); + dev = ERR_PTR(err); + } + return dev; } } } - return -ENODEV; + return ERR_PTR(-ENODEV); } /** @@ -282,7 +307,7 @@ static int __init mc32_probe1(struct net int i, err; u8 POS; u32 base; - struct mc32_local *lp; + struct mc32_local *lp = dev->priv; static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, @@ -409,24 +434,14 @@ static int __init mc32_probe1(struct net * Grab the IRQ */ - i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); - if (i) { + err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return i; + goto err_exit_ports; } - - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); - if (dev->priv == NULL) - { - err = -ENOMEM; - goto err_exit_irq; - } - - memset(dev->priv, 0, sizeof(struct mc32_local)); - lp = dev->priv; + memset(lp, 0, sizeof(struct mc32_local)); lp->slot = slot; i=0; @@ -440,7 +455,7 @@ static int __init mc32_probe1(struct net { printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) @@ -455,7 +470,7 @@ static int __init mc32_probe1(struct net else printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } base=0; @@ -471,7 +486,7 @@ static int __init mc32_probe1(struct net { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } } @@ -498,7 +513,9 @@ static int __init mc32_probe1(struct net lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ - init_waitqueue_head(&lp->event); + init_MUTEX_LOCKED(&lp->cmd_mutex); + init_completion(&lp->execution_cmd); + init_completion(&lp->xceiver_cmd); printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); @@ -511,20 +528,12 @@ static int __init mc32_probe1(struct net dev->tx_timeout = mc32_timeout; dev->watchdog_timeo = HZ*5; /* Board does all the work */ dev->ethtool_ops = &netdev_ethtool_ops; - - lp->xceiver_state = HALTED; - - lp->tx_ring_tail=lp->tx_ring_head=0; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - return 0; -err_exit_free: - kfree(dev->priv); err_exit_irq: free_irq(dev->irq, dev); +err_exit_ports: release_region(dev->base_addr, MC32_IO_EXTENT); return err; } @@ -539,7 +548,7 @@ err_exit_irq: * status of any pending commands and takes very little time at all. */ -static void mc32_ready_poll(struct net_device *dev) +static inline void mc32_ready_poll(struct net_device *dev) { int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); @@ -554,31 +563,38 @@ static void mc32_ready_poll(struct net_d * @len: Length of the data block * * Send a command from interrupt state. If there is a command - * currently being executed then we return an error of -1. It simply - * isn't viable to wait around as commands may be slow. Providing we - * get in, we busy wait for the board to become ready to accept the - * command and issue it. We do not wait for the command to complete - * --- the card will interrupt us when it's done. + * currently being executed then we return an error of -1. It + * simply isn't viable to wait around as commands may be + * slow. This can theoretically be starved on SMP, but it's hard + * to see a realistic situation. We do not wait for the command + * to complete --- we rely on the interrupt handler to tidy up + * after us. */ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; + int ret = -1; - if(lp->exec_pending) - return -1; - - lp->exec_pending=3; - lp->exec_box->mbox=0; - lp->exec_box->mbox=cmd; - memcpy((void *)lp->exec_box->data, data, len); - barrier(); /* the memcpy forgot the volatile so be sure */ + if (down_trylock(&lp->cmd_mutex) == 0) + { + lp->cmd_nonblocking=1; + lp->exec_box->mbox=0; + lp->exec_box->mbox=cmd; + memcpy((void *)lp->exec_box->data, data, len); + barrier(); /* the memcpy forgot the volatile so be sure */ + + /* Send the command */ + mc32_ready_poll(dev); + outb(1<<6, ioaddr+HOST_CMD); - /* Send the command */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(1<<6, ioaddr+HOST_CMD); - return 0; + ret = 0; + + /* Interrupt handler will signal mutex on completion */ + } + + return ret; } @@ -592,76 +608,47 @@ static int mc32_command_nowait(struct ne * Sends exec commands in a user context. This permits us to wait around * for the replies and also to wait for the command buffer to complete * from a previous command before we execute our command. After our - * command completes we will complete any pending multicast reload + * command completes we will attempt any pending multicast reload * we blocked off by hogging the exec buffer. * * You feed the card a command, you wait, it interrupts you get a * reply. All well and good. The complication arises because you use * commands for filter list changes which come in at bh level from things * like IPV6 group stuff. - * - * We have a simple state machine - * - * 0 - nothing issued - * - * 1 - command issued, wait reply - * - * 2 - reply waiting - reader then goes to state 0 - * - * 3 - command issued, trash reply. In which case the irq - * takes it back to state 0 - * */ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - unsigned long flags; int ret = 0; + down(&lp->cmd_mutex); + /* - * Wait for a command - */ - - save_flags(flags); - cli(); - - while(lp->exec_pending) - sleep_on(&lp->event); - - /* - * Issue mine + * My Turn */ - lp->exec_pending=1; - - restore_flags(flags); - + lp->cmd_nonblocking=0; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ - /* Send the command */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(1<<6, ioaddr+HOST_CMD); + mc32_ready_poll(dev); + outb(1<<6, ioaddr+HOST_CMD); - save_flags(flags); - cli(); - - while(lp->exec_pending!=2) - sleep_on(&lp->event); - lp->exec_pending=0; - restore_flags(flags); + wait_for_completion(&lp->execution_cmd); if(lp->exec_box->mbox&(1<<13)) ret = -1; + up(&lp->cmd_mutex); + /* - * A multicast set got blocked - do it now - */ - + * A multicast set got blocked - try it now + */ + if(lp->mc_reload_wait) { mc32_reset_multicast_list(dev); @@ -678,11 +665,9 @@ static int mc32_command(struct net_devic * This may be called from the interrupt state, where it is used * to restart the rx ring if the card runs out of rx buffers. * - * First, we check if it's ok to start the transceiver. We then show - * the card where to start in the rx ring and issue the - * commands to start reception and transmission. We don't wait - * around for these to complete. - */ + * We must first check if it's ok to (re)start the transceiver. See + * mc32_close for details. + */ static void mc32_start_transceiver(struct net_device *dev) { @@ -690,24 +675,20 @@ static void mc32_start_transceiver(struc int ioaddr = dev->base_addr; /* Ignore RX overflow on device closure */ - if (lp->desired_state==HALTED) + if (lp->xceiver_desired_state==HALTED) return; + /* Give the card the offset to the post-EOL-bit RX descriptor */ mc32_ready_poll(dev); - - lp->tx_box->mbox=0; lp->rx_box->mbox=0; - - /* Give the card the offset to the post-EOL-bit RX descriptor */ lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; - outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); mc32_ready_poll(dev); + lp->tx_box->mbox=0; outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ /* We are not interrupted on start completion */ - lp->xceiver_state=RUNNING; } @@ -727,25 +708,17 @@ static void mc32_halt_transceiver(struct { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - unsigned long flags; mc32_ready_poll(dev); - - lp->tx_box->mbox=0; lp->rx_box->mbox=0; - outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); + wait_for_completion(&lp->xceiver_cmd); + mc32_ready_poll(dev); + lp->tx_box->mbox=0; outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); - - save_flags(flags); - cli(); - - while(lp->xceiver_state!=HALTED) - sleep_on(&lp->event); - - restore_flags(flags); -} + wait_for_completion(&lp->xceiver_cmd); +} /** @@ -756,7 +729,7 @@ static void mc32_halt_transceiver(struct * the point where mc32_start_transceiver() can be called. * * The card sets up the receive ring for us. We are required to use the - * ring it provides although we can change the size of the ring. + * ring it provides, although the size of the ring is configurable. * * We allocate an sk_buff for each ring entry in turn and * initalise its house-keeping info. At the same time, we read @@ -777,7 +750,7 @@ static int mc32_load_rx_ring(struct net_ rx_base=lp->rx_chain; - for(i=0;irx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); skb_reserve(lp->rx_ring[i].skb, 18); @@ -814,21 +787,19 @@ static int mc32_load_rx_ring(struct net_ * * Free the buffer for each ring slot. This may be called * before mc32_load_rx_ring(), eg. on error in mc32_open(). + * Requires rx skb pointers to point to a valid skb, or NULL. */ static void mc32_flush_rx_ring(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - - struct sk_buff *skb; int i; for(i=0; i < RX_RING_LEN; i++) { - skb = lp->rx_ring[i].skb; - if (skb!=NULL) { - kfree_skb(skb); - skb=NULL; + if (lp->rx_ring[i].skb) { + dev_kfree_skb(lp->rx_ring[i].skb); + lp->rx_ring[i].skb = NULL; } lp->rx_ring[i].p=NULL; } @@ -860,7 +831,7 @@ static void mc32_load_tx_ring(struct net tx_base=lp->tx_box->data[0]; - for(i=0;itx_len;i++) + for(i=0 ; ibase+tx_base); lp->tx_ring[i].p=p; @@ -869,11 +840,12 @@ static void mc32_load_tx_ring(struct net tx_base=p->next; } - /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */ - /* which would be bad news for mc32_tx_ring as cur. implemented */ + /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */ + /* see mc32_tx_ring */ atomic_set(&lp->tx_count, TX_RING_LEN-1); - lp->tx_ring_head=lp->tx_ring_tail=0; + atomic_set(&lp->tx_ring_head, 0); + lp->tx_ring_tail=0; } @@ -881,47 +853,29 @@ static void mc32_load_tx_ring(struct net * mc32_flush_tx_ring - free transmit ring * @lp: Local data of 3c527 to flush the tx ring of * - * We have to consider two cases here. We want to free the pending - * buffers only. If the ring buffer head is past the start then the - * ring segment we wish to free wraps through zero. The tx ring - * house-keeping variables are then reset. + * If the ring is non-empty, zip over the it, freeing any + * allocated skb_buffs. The tx ring house-keeping variables are + * then reset. Requires rx skb pointers to point to a valid skb, + * or NULL. */ static void mc32_flush_tx_ring(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - - if(lp->tx_ring_tail!=lp->tx_ring_head) + int i; + + for (i=0; i < TX_RING_LEN; i++) { - int i; - if(lp->tx_ring_tail < lp->tx_ring_head) + if (lp->tx_ring[i].skb) { - for(i=lp->tx_ring_tail;itx_ring_head;i++) - { - dev_kfree_skb(lp->tx_ring[i].skb); - lp->tx_ring[i].skb=NULL; - lp->tx_ring[i].p=NULL; - } - } - else - { - for(i=lp->tx_ring_tail; itx_ring[i].skb); - lp->tx_ring[i].skb=NULL; - lp->tx_ring[i].p=NULL; - } - for(i=0; itx_ring_head; i++) - { - dev_kfree_skb(lp->tx_ring[i].skb); - lp->tx_ring[i].skb=NULL; - lp->tx_ring[i].p=NULL; - } + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb = NULL; } } - + atomic_set(&lp->tx_count, 0); - lp->tx_ring_tail=lp->tx_ring_head=0; + atomic_set(&lp->tx_ring_head, 0); + lp->tx_ring_tail=0; } @@ -958,6 +912,12 @@ static int mc32_open(struct net_device * regs|=HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); + /* + * Allow ourselves to issue commands + */ + + up(&lp->cmd_mutex); + /* * Send the indications on command @@ -1010,7 +970,7 @@ static int mc32_open(struct net_device * return -ENOBUFS; } - lp->desired_state = RUNNING; + lp->xceiver_desired_state = RUNNING; /* And finally, set the ball rolling... */ mc32_start_transceiver(dev); @@ -1047,61 +1007,64 @@ static void mc32_timeout(struct net_devi * Transmit a buffer. This normally means throwing the buffer onto * the transmit queue as the queue is quite large. If the queue is * full then we set tx_busy and return. Once the interrupt handler - * gets messages telling it to reclaim transmit queue entries we will + * gets messages telling it to reclaim transmit queue entries, we will * clear tx_busy and the kernel will start calling this again. * - * We use cli rather than spinlocks. Since I have no access to an SMP - * MCA machine I don't plan to change it. It is probably the top - * performance hit for this driver on SMP however. + * We do not disable interrupts or acquire any locks; this can + * run concurrently with mc32_tx_ring(), and the function itself + * is serialised at a higher layer. However, similarly for the + * card itself, we must ensure that we update tx_ring_head only + * after we've established a valid packet on the tx ring (and + * before we let the card "see" it, to prevent it racing with the + * irq handler). + * */ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - unsigned long flags; - + u32 head = atomic_read(&lp->tx_ring_head); + volatile struct skb_header *p, *np; netif_stop_queue(dev); - save_flags(flags); - cli(); - - if(atomic_read(&lp->tx_count)==0) - { - restore_flags(flags); + if(atomic_read(&lp->tx_count)==0) { return 1; } + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) { + netif_wake_queue(dev); + return 0; + } + atomic_dec(&lp->tx_count); /* P is the last sending/sent buffer as a pointer */ - p=lp->tx_ring[lp->tx_ring_head].p; + p=lp->tx_ring[head].p; - lp->tx_ring_head=next_tx(lp->tx_ring_head); + head = next_tx(head); /* NP is the buffer we will be loading */ - np=lp->tx_ring[lp->tx_ring_head].p; - - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - goto out; - } - + np=lp->tx_ring[head].p; + /* We will need this to flush the buffer out */ - lp->tx_ring[lp->tx_ring_head].skb = skb; - - np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - + lp->tx_ring[head].skb=skb; + + np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = isa_virt_to_bus(skb->data); np->status = 0; np->control = CONTROL_EOP | CONTROL_EOL; wmb(); - p->control &= ~CONTROL_EOL; /* Clear EOL on p */ -out: - restore_flags(flags); + /* + * The new frame has been setup; we can now + * let the interrupt handler and card "see" it + */ + + atomic_set(&lp->tx_ring_head, head); + p->control &= ~CONTROL_EOL; netif_wake_queue(dev); return 0; @@ -1182,10 +1145,11 @@ static void mc32_rx_ring(struct net_devi { struct mc32_local *lp=dev->priv; volatile struct skb_header *p; - u16 rx_ring_tail = lp->rx_ring_tail; - u16 rx_old_tail = rx_ring_tail; - + u16 rx_ring_tail; + u16 rx_old_tail; int x=0; + + rx_old_tail = rx_ring_tail = lp->rx_ring_tail; do { @@ -1275,9 +1239,14 @@ static void mc32_tx_ring(struct net_devi struct mc32_local *lp=(struct mc32_local *)dev->priv; volatile struct skb_header *np; - /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */ + /* + * We rely on head==tail to mean 'queue empty'. + * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent + * tx_ring_head wrapping to tail and confusing a 'queue empty' + * condition with 'queue full' + */ - while (lp->tx_ring_tail != lp->tx_ring_head) + while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head)) { u16 t; @@ -1388,8 +1357,7 @@ static irqreturn_t mc32_interrupt(int ir break; case 3: /* Halt */ case 4: /* Abort */ - lp->xceiver_state |= TX_HALTED; - wake_up(&lp->event); + complete(&lp->xceiver_cmd); break; default: printk("%s: strange tx ack %d\n", dev->name, status&7); @@ -1404,8 +1372,7 @@ static irqreturn_t mc32_interrupt(int ir break; case 3: /* Halt */ case 4: /* Abort */ - lp->xceiver_state |= RX_HALTED; - wake_up(&lp->event); + complete(&lp->xceiver_cmd); break; case 6: /* Out of RX buffers stat */ @@ -1421,26 +1388,17 @@ static irqreturn_t mc32_interrupt(int ir status>>=3; if(status&1) { - - /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ - - if(lp->exec_pending!=3) { - lp->exec_pending=2; - wake_up(&lp->event); - } - else - { - lp->exec_pending=0; - - /* A new multicast set may have been - blocked while the old one was - running. If so, do it now. */ + /* + * No thread is waiting: we need to tidy + * up ourself. + */ + if (lp->cmd_nonblocking) { + up(&lp->cmd_mutex); if (lp->mc_reload_wait) mc32_reset_multicast_list(dev); - else - wake_up(&lp->event); } + else complete(&lp->execution_cmd); } if(status&2) { @@ -1493,12 +1451,12 @@ static irqreturn_t mc32_interrupt(int ir static int mc32_close(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; + u8 regs; u16 one=1; - lp->desired_state = HALTED; + lp->xceiver_desired_state = HALTED; netif_stop_queue(dev); /* @@ -1511,11 +1469,10 @@ static int mc32_close(struct net_device mc32_halt_transceiver(dev); - /* Catch any waiting commands */ + /* Ensure we issue no more commands beyond this point */ + + down(&lp->cmd_mutex); - while(lp->exec_pending==1) - sleep_on(&lp->event); - /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); @@ -1542,12 +1499,9 @@ static int mc32_close(struct net_device static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp; + struct mc32_local *lp = (struct mc32_local *)dev->priv; mc32_update_stats(dev); - - lp = (struct mc32_local *)dev->priv; - return &lp->net_stats; } @@ -1684,7 +1638,7 @@ static struct ethtool_ops netdev_ethtool #ifdef MODULE -static struct net_device this_device; +static struct net_device *this_device; /** * init_module - entry point @@ -1696,12 +1650,9 @@ static struct net_device this_device; int init_module(void) { - int result; - - this_device.init = mc32_probe; - if ((result = register_netdev(&this_device)) != 0) - return result; - + this_device = mc32_probe(-1); + if (IS_ERR(this_device)) + return PTR_ERR(this_device); return 0; } @@ -1718,24 +1669,9 @@ int init_module(void) void cleanup_module(void) { - int slot; - - unregister_netdev(&this_device); - - /* - * If we don't do this, we can't re-insmod it later. - */ - - if (this_device.priv) - { - struct mc32_local *lp=this_device.priv; - slot = lp->slot; - mca_mark_as_unused(slot); - mca_set_adapter_name(slot, NULL); - kfree(this_device.priv); - } - free_irq(this_device.irq, &this_device); - release_region(this_device.base_addr, MC32_IO_EXTENT); + unregister_netdev(this_device); + cleanup_card(this_device); + free_netdev(this_device); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/3c527.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/3c527.h 2003-12-30 22:49:19.000000000 -0800 @@ -27,10 +27,8 @@ #define HOST_RAMPAGE 8 -#define RX_HALTED (1<<0) -#define TX_HALTED (1<<1) -#define HALTED (RX_HALTED | TX_HALTED) -#define RUNNING 0 +#define HALTED 0 +#define RUNNING 1 struct mc32_mailbox { --- linux-2.6.1-rc1/drivers/net/3c59x.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/3c59x.c 2003-12-30 22:49:19.000000000 -0800 @@ -920,6 +920,18 @@ static struct net_device *compaq_net_dev static int vortex_cards_found; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_vortex(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); + local_irq_restore(flags); +} +#endif + #ifdef CONFIG_PM static int vortex_suspend (struct pci_dev *pdev, u32 state) @@ -1450,6 +1462,9 @@ static int __devinit vortex_probe1(struc dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = poll_vortex; +#endif if (pdev) { vp->pm_state_valid = 1; pci_save_state(VORTEX_PCI(vp), vp->power_state); --- linux-2.6.1-rc1/drivers/net/68360enet.c 2003-06-14 12:17:59.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,951 +0,0 @@ -/* - * Ethernet driver for Motorola MPC8xx. - * Copyright (c) 2000 Michael Leslie - * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) - * - * I copied the basic skeleton from the lance driver, because I did not - * know how to write the Linux driver, but I did know how the LANCE worked. - * - * This version of the driver is somewhat selectable for the different - * processor/board combinations. It works for the boards I know about - * now, and should be easily modified to include others. Some of the - * configuration information is contained in "commproc.h" and the - * remainder is here. - * - * Buffer descriptors are kept in the CPM dual port RAM, and the frame - * buffers are in the host memory. - * - * Right now, I am very watseful with the buffers. I allocate memory - * pages and then divide them into 2K frame buffers. This way I know I - * have buffers large enough to hold one frame within one buffer descriptor. - * Once I get this working, I will use 64 or 128 byte CPM buffers, which - * will be much more memory efficient and will easily handle lots of - * small packets. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -/* #include */ -/* #include */ -/* #include */ -#include -/* #include */ -#include - - -/* - * Theory of Operation - * - * The MPC8xx CPM performs the Ethernet processing on SCC1. It can use - * an aribtrary number of buffers on byte boundaries, but must have at - * least two receive buffers to prevent constant overrun conditions. - * - * The buffer descriptors are allocated from the CPM dual port memory - * with the data buffers allocated from host memory, just like all other - * serial communication protocols. The host memory buffers are allocated - * from the free page pool, and then divided into smaller receive and - * transmit buffers. The size of the buffers should be a power of two, - * since that nicely divides the page. This creates a ring buffer - * structure similar to the LANCE and other controllers. - * - * Like the LANCE driver: - * The driver runs as two independent, single-threaded flows of control. One - * is the send-packet routine, which enforces single-threaded use by the - * cep->tx_busy flag. The other thread is the interrupt handler, which is - * single threaded by the hardware and other software. - * - * The send packet thread has partial control over the Tx ring and the - * 'cep->tx_busy' flag. It sets the tx_busy flag whenever it's queuing a Tx - * packet. If the next queue slot is empty, it clears the tx_busy flag when - * finished otherwise it sets the 'lp->tx_full' flag. - * - * The MBX has a control register external to the MPC8xx that has some - * control of the Ethernet interface. Information is in the manual for - * your board. - * - * The RPX boards have an external control/status register. Consult the - * programming documents for details unique to your board. - * - * For the TQM8xx(L) modules, there is no control register interface. - * All functions are directly controlled using I/O pins. See commproc.h. - */ - - -/* The transmitter timeout - */ -#define TX_TIMEOUT (2*HZ) - -/* The number of Tx and Rx buffers. These are allocated statically here. - * We don't need to allocate pages for the transmitter. We just use - * the skbuffer directly. - */ -#ifdef CONFIG_ENET_BIG_BUFFERS -#define RX_RING_SIZE 64 -#define TX_RING_SIZE 64 /* Must be power of two */ -#define TX_RING_MOD_MASK 63 /* for this to work */ -#else -#define RX_RING_SIZE 8 -#define TX_RING_SIZE 8 /* Must be power of two */ -#define TX_RING_MOD_MASK 7 /* for this to work */ -#endif - -#define CPM_ENET_RX_FRSIZE 2048 /* overkill left over from ppc page-based allocation */ -static char rx_buf_pool[RX_RING_SIZE * CPM_ENET_RX_FRSIZE]; - - -/* The CPM stores dest/src/type, data, and checksum for receive packets. - */ -#define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 -#define PKT_MAXBLR_SIZE 1520 - -/* The CPM buffer descriptors track the ring buffers. The rx_bd_base and - * tx_bd_base always point to the base of the buffer descriptors. The - * cur_rx and cur_tx point to the currently available buffer. - * The dirty_tx tracks the current buffer that is being sent by the - * controller. The cur_tx and dirty_tx are equal under both completely - * empty and completely full conditions. The empty/ready indicator in - * the buffer descriptor determines the actual condition. - */ -struct scc_enet_private { - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - ushort skb_cur; - ushort skb_dirty; - - /* CPM dual port RAM relative addresses. - */ - QUICC_BD *rx_bd_base; /* Address of Rx and Tx buffers. */ - QUICC_BD *tx_bd_base; - QUICC_BD *cur_rx, *cur_tx; /* The next free ring entry */ - QUICC_BD *dirty_tx; /* The ring entries to be free()ed. */ - volatile struct scc_regs *sccp; - /* struct net_device_stats stats; */ - struct net_device_stats stats; - uint tx_full; - /* spinlock_t lock; */ - volatile unsigned int lock; -}; - - - -static int scc_enet_open(struct net_device *dev); -static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int scc_enet_rx(struct net_device *dev); -static irqreturn_t scc_enet_interrupt(int vec, void *dev_id, struct pt_regs *fp); -static int scc_enet_close(struct net_device *dev); -/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); */ -static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); - -/* Get this from various configuration locations (depends on board). -*/ -/*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/ - -/* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards - * use SCC2. This is easily extended if necessary. - */ - -#define CONFIG_SCC1_ENET /* by default */ - -#ifdef CONFIG_SCC1_ENET -#define CPM_CR_ENET CPM_CR_CH_SCC1 -#define PROFF_ENET PROFF_SCC1 -#define SCC_ENET 0 -#define CPMVEC_ENET CPMVEC_SCC1 -#endif - -#ifdef CONFIG_SCC2_ENET -#define CPM_CR_ENET CPM_CR_CH_SCC2 -#define PROFF_ENET PROFF_SCC2 -#define SCC_ENET 1 /* Index, not number! */ -#define CPMVEC_ENET CPMVEC_SCC2 -#endif - -static int -scc_enet_open(struct net_device *dev) -{ - - /* I should reset the ring buffers here, but I don't yet know - * a simple way to do that. - * mleslie: That's no biggie. Worth doing, too. - */ - - /* netif_start_queue(dev); */ - return 0; /* Always succeed */ -} - - -static int -scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - volatile QUICC_BD *bdp; - - /* Fill in a Tx ring entry */ - bdp = cep->cur_tx; - -#ifndef final_version - if (bdp->status & BD_ENET_TX_READY) { - /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since cep->tx_busy should be set. - */ - printk("%s: tx queue full!.\n", dev->name); - return 1; - } -#endif - - /* Clear all of the status flags. - */ - bdp->status &= ~BD_ENET_TX_STATS; - - /* If the frame is short, tell CPM to pad it. - */ - if (skb->len <= ETH_ZLEN) - bdp->status |= BD_ENET_TX_PAD; - else - bdp->status &= ~BD_ENET_TX_PAD; - - /* Set buffer length and buffer pointer. - */ - bdp->length = skb->len; - /* bdp->buf = __pa(skb->data); */ - bdp->buf = skb->data; - - /* Save skb pointer. - */ - cep->tx_skbuff[cep->skb_cur] = skb; - - /* cep->stats.tx_bytes += skb->len; */ /* TODO: It would really be nice... */ - - cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; - - - /* Push the data cache so the CPM does not get stale memory - * data. - */ -/* flush_dcache_range((unsigned long)(skb->data), */ -/* (unsigned long)(skb->data + skb->len)); */ - - /* spin_lock_irq(&cep->lock); */ /* TODO: SPINLOCK */ - local_irq_disable(); - if (cep->lock > 0) { - printk ("scc_enet_start_xmit() lock == %d\n", cep->lock); - } else { - cep->lock++; - } - - /* Send it on its way. Tell CPM its ready, interrupt when done, - * its the last BD of the frame, and to put the CRC on the end. - */ - bdp->status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); - - dev->trans_start = jiffies; - - /* If this was the last BD in the ring, start at the beginning again. - */ - if (bdp->status & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - if (bdp->status & BD_ENET_TX_READY) { - /* netif_stop_queue(dev); */ - cep->tx_full = 1; - } - - cep->cur_tx = (QUICC_BD *)bdp; - - /* spin_unlock_irq(&cep->lock); */ /* TODO: SPINLOCK */ - cep->lock--; - sti(); - - return 0; -} - -#if 0 -static void -scc_enet_timeout(struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - - printk("%s: transmit timed out.\n", dev->name); - cep->stats.tx_errors++; -#ifndef final_version - { - int i; - QUICC_BD *bdp; - printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", - cep->cur_tx, cep->tx_full ? " (full)" : "", - cep->cur_rx); - bdp = cep->tx_bd_base; - for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->status, - bdp->length, - (int)(bdp->buf)); - bdp = cep->rx_bd_base; - for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->status, - bdp->length, - (int)(bdp->buf)); - } -#endif -/* if (!cep->tx_full) */ -/* netif_wake_queue(dev); */ -} -#endif - -/* The interrupt handler. - * This is called from the CPM handler, not the MPC core interrupt. - */ -static irqreturn_t scc_enet_interrupt(int vec, void *dev_id, struct pt_regs *fp) -{ - struct net_device *dev = (struct net_device *)dev_id; - volatile struct scc_enet_private *cep; - volatile QUICC_BD *bdp; - ushort int_events; - int must_restart; - - cep = (struct scc_enet_private *)dev->priv; - - /* Get the interrupt events that caused us to be here. - */ - int_events = cep->sccp->scc_scce; - cep->sccp->scc_scce = int_events; - must_restart = 0; - - /* Handle receive event in its own function. - */ - if (int_events & SCCE_ENET_RXF) - scc_enet_rx(dev_id); - - /* Check for a transmit error. The manual is a little unclear - * about this, so the debug code until I get it figured out. It - * appears that if TXE is set, then TXB is not set. However, - * if carrier sense is lost during frame transmission, the TXE - * bit is set, "and continues the buffer transmission normally." - * I don't know if "normally" implies TXB is set when the buffer - * descriptor is closed.....trial and error :-). - */ - - /* Transmit OK, or non-fatal error. Update the buffer descriptors. - */ - if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { - /* spin_lock(&cep->lock); */ /* TODO: SPINLOCK */ - /* local_irq_disable(); */ - if (cep->lock > 0) { - printk ("scc_enet_interrupt() lock == %d\n", cep->lock); - } else { - cep->lock++; - } - - bdp = cep->dirty_tx; - while ((bdp->status&BD_ENET_TX_READY)==0) { - if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) - break; - - if (bdp->status & BD_ENET_TX_HB) /* No heartbeat */ - cep->stats.tx_heartbeat_errors++; - if (bdp->status & BD_ENET_TX_LC) /* Late collision */ - cep->stats.tx_window_errors++; - if (bdp->status & BD_ENET_TX_RL) /* Retrans limit */ - cep->stats.tx_aborted_errors++; - if (bdp->status & BD_ENET_TX_UN) /* Underrun */ - cep->stats.tx_fifo_errors++; - if (bdp->status & BD_ENET_TX_CSL) /* Carrier lost */ - cep->stats.tx_carrier_errors++; - - - /* No heartbeat or Lost carrier are not really bad errors. - * The others require a restart transmit command. - */ - if (bdp->status & - (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { - must_restart = 1; - cep->stats.tx_errors++; - } - - cep->stats.tx_packets++; - - /* Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (bdp->status & BD_ENET_TX_DEF) - cep->stats.collisions++; - - /* Free the sk buffer associated with this last transmit. - */ - /* dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); */ - dev_kfree_skb (cep->tx_skbuff[cep->skb_dirty]); - cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; - - /* Update pointer to next buffer descriptor to be transmitted. - */ - if (bdp->status & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - /* I don't know if we can be held off from processing these - * interrupts for more than one frame time. I really hope - * not. In such a case, we would now want to check the - * currently available BD (cur_tx) and determine if any - * buffers between the dirty_tx and cur_tx have also been - * sent. We would want to process anything in between that - * does not have BD_ENET_TX_READY set. - */ - - /* Since we have freed up a buffer, the ring is no longer - * full. - */ - if (cep->tx_full) { - cep->tx_full = 0; -/* if (netif_queue_stopped(dev)) */ -/* netif_wake_queue(dev); */ - } - - cep->dirty_tx = (QUICC_BD *)bdp; - } - - if (must_restart) { - volatile QUICC *cp; - - /* Some transmit errors cause the transmitter to shut - * down. We now issue a restart transmit. Since the - * errors close the BD and update the pointers, the restart - * _should_ pick up without having to reset any of our - * pointers either. - */ - cp = pquicc; - cp->cp_cr = - mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - } - /* spin_unlock(&cep->lock); */ /* TODO: SPINLOCK */ - /* sti(); */ - cep->lock--; - } - - /* Check for receive busy, i.e. packets coming but no place to - * put them. This "can't happen" because the receive interrupt - * is tossing previous frames. - */ - if (int_events & SCCE_ENET_BSY) { - cep->stats.rx_dropped++; - printk("CPM ENET: BSY can't happen.\n"); - } - - return IRQ_HANDLED; -} - -/* During a receive, the cur_rx points to the current incoming buffer. - * When we update through the ring, if the next incoming buffer has - * not been given to the system, we just set the empty indicator, - * effectively tossing the packet. - */ -static int -scc_enet_rx(struct net_device *dev) -{ - struct scc_enet_private *cep; - volatile QUICC_BD *bdp; - struct sk_buff *skb; - ushort pkt_len; - - cep = (struct scc_enet_private *)dev->priv; - - /* First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = cep->cur_rx; - - for (;;) { - if (bdp->status & BD_ENET_RX_EMPTY) - break; - -#ifndef final_version - /* Since we have allocated space to hold a complete frame, both - * the first and last indicators should be set. - */ - if ((bdp->status & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != - (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) - printk("CPM ENET: rcv is not first+last\n"); -#endif - - /* Frame too long or too short. - */ - if (bdp->status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - cep->stats.rx_length_errors++; - if (bdp->status & BD_ENET_RX_NO) /* Frame alignment */ - cep->stats.rx_frame_errors++; - if (bdp->status & BD_ENET_RX_CR) /* CRC Error */ - cep->stats.rx_crc_errors++; - if (bdp->status & BD_ENET_RX_OV) /* FIFO overrun */ - cep->stats.rx_crc_errors++; - - /* Report late collisions as a frame error. - * On this error, the BD is closed, but we don't know what we - * have in the buffer. So, just drop this frame on the floor. - */ - if (bdp->status & BD_ENET_RX_CL) { - cep->stats.rx_frame_errors++; - } - else { - - /* Process the incoming frame. - */ - cep->stats.rx_packets++; - pkt_len = bdp->length; - /* cep->stats.rx_bytes += pkt_len; */ /* TODO: It would really be nice... */ - - /* This does 16 byte alignment, much more than we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = dev_alloc_skb(pkt_len-4); - - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - cep->stats.rx_dropped++; - } - else { - skb->dev = dev; - skb_put(skb,pkt_len-4); /* Make room */ - eth_copy_and_sum(skb, (unsigned char *)bdp->buf, pkt_len-4, 0); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - } - - /* Clear the status flags for this buffer. - */ - bdp->status &= ~BD_ENET_RX_STATS; - - /* Mark the buffer empty. - */ - bdp->status |= BD_ENET_RX_EMPTY; - - /* Update BD pointer to next entry. - */ - if (bdp->status & BD_ENET_RX_WRAP) - bdp = cep->rx_bd_base; - else - bdp++; - - } - cep->cur_rx = (QUICC_BD *)bdp; - - return 0; -} - -static int -scc_enet_close(struct net_device *dev) -{ - /* Don't know what to do yet. - */ - /* netif_stop_queue(dev); */ - - return 0; -} - -/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) */ -static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - - return &cep->stats; -} - -/* Set or clear the multicast filter for this adaptor. - * Skeleton taken from sunlance driver. - * The CPM Ethernet implementation allows Multicast as well as individual - * MAC address filtering. Some of the drivers check to make sure it is - * a group multicast address, and discard those that are not. I guess I - * will do the same for now, but just remove the test if you want - * individual filtering as well (do the upper net layers want or support - * this kind of feature?). - */ - -static void set_multicast_list(struct net_device *dev) -{ - struct scc_enet_private *cep; - struct dev_mc_list *dmi; - u_char *mcptr, *tdptr; - volatile scc_enet_t *ep; - int i, j; - volatile QUICC *cp = pquicc; - - cep = (struct scc_enet_private *)dev->priv; - - /* Get pointer to SCC area in parameter RAM. - */ - ep = (scc_enet_t *)dev->base_addr; - - if (dev->flags&IFF_PROMISC) { - - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->sccp->scc_psmr |= ETHER_PRO; - } else { - - cep->sccp->scc_psmr &= ~ETHER_PRO; - - if (dev->flags & IFF_ALLMULTI) { - /* Catch all multicast addresses, so set the - * filter to all 1's. - */ - ep->sen_gaddr1 = 0xffff; - ep->sen_gaddr2 = 0xffff; - ep->sen_gaddr3 = 0xffff; - ep->sen_gaddr4 = 0xffff; - } - else { - /* Clear filter and add the addresses in the list. - */ - ep->sen_gaddr1 = 0; - ep->sen_gaddr2 = 0; - ep->sen_gaddr3 = 0; - ep->sen_gaddr4 = 0; - - dmi = dev->mc_list; - - for (i=0; imc_count; i++) { - - /* Only support group multicast for now. - */ - if (!(dmi->dmi_addr[0] & 1)) - continue; - - /* The address in dmi_addr is LSB first, - * and taddr is MSB first. We have to - * copy bytes MSB first from dmi_addr. - */ - mcptr = (u_char *)dmi->dmi_addr + 5; - tdptr = (u_char *)&ep->sen_taddrh; - for (j=0; j<6; j++) - *tdptr++ = *mcptr--; - - /* Ask CPM to run CRC and set bit in - * filter mask. - */ - cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG; - /* this delay is necessary here -- Cort */ - udelay(10); - while (cp->cp_cr & CPM_CR_FLG); - } - } - } -} - - -/* Initialize the CPM Ethernet on SCC. - */ -int scc_enet_init(void) -{ - struct net_device *dev; - struct scc_enet_private *cep; - int i, j; - unsigned char *eap; - /* unsigned long mem_addr; */ - /* pte_t *pte; */ - /* bd_t *bd; */ /* `board tag' used by ppc - TODO: integrate uC bootloader vars */ - volatile QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct scc_regs *sccp; - volatile struct ethernet_pram *ep; - /* volatile immap_t *immap; */ - - cp = pquicc; /* Get pointer to Communication Processor */ - - /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ - - /* bd = (bd_t *)__res; */ - - /* Allocate some private information. - */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - memset(cep, 0, sizeof(*cep)); - /* __clear_user(cep,sizeof(*cep)); */ - /* spin_lock_init(&cep->lock); */ /* TODO: SPINLOCK */ - - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - - /* Get pointer to SCC area in parameter RAM. - */ - /* ep = (ethernet_pram *)(&cp->cp_dparam[PROFF_ENET]); */ - ep = &pquicc->pram[SCC_ENET].enet_scc; - - /* And another to the SCC register area. - */ - sccp = &pquicc->scc_regs[SCC_ENET]; - cep->sccp = sccp; /* Keep the pointer handy */ - - /* Disable receive and transmit in case EPPC-Bug started it. - */ - sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - /* Set up 360 pins for SCC interface to ethernet transceiver. - * Pin mappings (PA_xx and PC_xx) are defined in commproc.h - */ - - /* Configure port A pins for Txd and Rxd. - */ - pquicc->pio_papar |= (PA_ENET_RXD | PA_ENET_TXD); - pquicc->pio_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); - pquicc->pio_paodr &= ~PA_ENET_TXD; - - /* Configure port C pins to enable CLSN and RENA. - */ - pquicc->pio_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); - pquicc->pio_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); - pquicc->pio_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); - - /* Configure port A for TCLK and RCLK. - */ - pquicc->pio_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); - pquicc->pio_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); - - /* Configure Serial Interface clock routing. - * First, clear all SCC bits to zero, then set the ones we want. - */ - pquicc->si_sicr &= ~SICR_ENET_MASK; - pquicc->si_sicr |= SICR_ENET_CLKRT; - - - /* Allocate space for the buffer descriptors in the DP ram. - * These are relative offsets in the DP ram address space. - * Initialize base addresses for the buffer descriptors. - */ - i = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_RING_SIZE); - ep->rbase = i; - cep->rx_bd_base = (QUICC_BD *)((uint)pquicc + i); - - i = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_RING_SIZE); - ep->tbase = i; - cep->tx_bd_base = (QUICC_BD *)((uint)pquicc + i); - - cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; - cep->cur_rx = cep->rx_bd_base; - - /* Issue init Rx BD command for SCC. - * Manual says to perform an Init Rx parameters here. We have - * to perform both Rx and Tx because the SCC may have been - * already running. [In uCquicc's case, I don't think that is so - mles] - * In addition, we have to do it later because we don't yet have - * all of the BD control/status set properly. - cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - */ - - /* Initialize function code registers for big-endian. - */ - ep->rfcr = (SCC_EB | SCC_FC_DMA); - ep->tfcr = (SCC_EB | SCC_FC_DMA); - - /* Set maximum bytes per receive buffer. - * This appears to be an Ethernet frame size, not the buffer - * fragment size. It must be a multiple of four. - */ - ep->mrblr = PKT_MAXBLR_SIZE; - - /* Set CRC preset and mask. - */ - ep->c_pres = 0xffffffff; - ep->c_mask = 0xdebb20e3; /* see 360UM p. 7-247 */ - - ep->crcec = 0; /* CRC Error counter */ - ep->alec = 0; /* alignment error counter */ - ep->disfc = 0; /* discard frame counter */ - - ep->pads = 0x8888; /* Tx short frame pad character */ - ep->ret_lim = 0x000f; /* Retry limit threshold */ - - ep->mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ - ep->minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ - - ep->maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ - ep->maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ - - /* Clear hash tables, group and individual. - */ - ep->gaddr1 = ep->gaddr2 = ep->gaddr3 = ep->gaddr4 = 0; - ep->iaddr1 = ep->iaddr2 = ep->iaddr3 = ep->iaddr4 = 0; - - /* Set Ethernet station address. - * - * The uCbootloader provides a hook to the kernel to retrieve - * stuff like the MAC address. This is retrieved in config_BSP() - */ -#if defined (CONFIG_UCQUICC) - { - extern unsigned char *scc1_hwaddr; - - eap = (char *)ep->paddr.b; - for (i=5; i>=0; i--) - *eap++ = dev->dev_addr[i] = scc1_hwaddr[i]; - } -#endif - - -/* #ifndef CONFIG_MBX */ -/* eap = (unsigned char *)&(ep->paddrh); */ - -/* for (i=5; i>=0; i--) */ -/* *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; */ -/* #else */ -/* for (i=5; i>=0; i--) */ -/* dev->dev_addr[i] = *eap++; */ -/* #endif */ - - ep->p_per = 0; /* 'cause the book says so */ - ep->taddr_l = 0; /* temp address (LSB) */ - ep->taddr_m = 0; - ep->taddr_h = 0; /* temp address (MSB) */ - - /* Now allocate the host memory pages and initialize the - * buffer descriptors. - */ - /* initialize rx buffer descriptors */ - bdp = cep->tx_bd_base; - for (j=0; j<(TX_RING_SIZE-1); j++) { - bdp->buf = 0; - bdp->status = 0; - bdp++; - } - bdp->buf = 0; - bdp->status = BD_SC_WRAP; - - - /* initialize rx buffer descriptors */ - bdp = cep->rx_bd_base; - for (j=0; j<(RX_RING_SIZE-1); j++) { - bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; - bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; - bdp++; - } - bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; - bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - - - - /* Let's re-initialize the channel now. We have to do it later - * than the manual describes because we have just now finished - * the BD initialization. - */ - cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - cep->skb_cur = cep->skb_dirty = 0; - - sccp->scc_scce = 0xffff; /* Clear any pending events */ - - /* Enable interrupts for transmit error, complete frame - * received, and any transmit buffer we have also set the - * interrupt flag. - */ - sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); - - /* Install our interrupt handler. - */ - /* cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev); */ - request_irq(CPMVEC_ENET, scc_enet_interrupt, - IRQ_FLG_LOCK, dev->name, (void *)dev); - - /* Set GSMR_H to enable all normal operating modes. - * Set GSMR_L to enable Ethernet to MC68160. - */ - sccp->scc_gsmr.w.high = 0; - sccp->scc_gsmr.w.low = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | - SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); - - /* Set sync/delimiters. - */ - sccp->scc_dsr = 0xd555; - - /* Set processing mode. Use Ethernet CRC, catch broadcast, and - * start frame search 22 bit times after RENA. - */ - sccp->scc_psmr = (SCC_PMSR_ENCRC /* Ethernet CRC mode */ - /* | SCC_PSMR_HBC */ /* Enable heartbeat */ - /* | SCC_PMSR_PRO */ /* Promiscuous mode */ - /* | SCC_PMSR_FDE */ /* Full duplex enable */ - | ETHER_NIB_22); - /* sccp->scc_psmr = (SCC_PMSR_PRO | ETHER_CRC_32 | ETHER_NIB_22); */ - - - /* It is now OK to enable the Ethernet transmitter. - * Unfortunately, there are board implementation differences here. - */ -#if defined(CONFIG_UCQUICC) -/* immap->im_ioport.iop_pcpar |= PC_ENET_TENA; */ -/* immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; */ - cp->pio_pcpar |= PC_ENET_TENA; /* t_en */ - cp->pio_pcdir &= ~PC_ENET_TENA; - - cp->pip_pbpar &= ~(0x00000200); /* power up ethernet transceiver */ - cp->pip_pbdir |= (0x00000200); - cp->pip_pbdat |= (0x00000200); -#endif - - - dev->base_addr = (unsigned long)ep; - dev->priv = cep; -#if 0 - dev->name = "CPM_ENET"; -#endif - - /* The CPM Ethernet specific entries in the device structure. */ - dev->open = scc_enet_open; - dev->hard_start_xmit = scc_enet_start_xmit; - /* dev->tx_timeout = scc_enet_timeout; */ - /* dev->watchdog_timeo = TX_TIMEOUT; */ - dev->stop = scc_enet_close; - dev->get_stats = scc_enet_get_stats; - dev->set_multicast_list = set_multicast_list; - - /* And last, enable the transmit and receive processing. - */ - sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - printk("%s: CPM ENET Version 0.3, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); - - return 0; -} - - - -int m68360_enet_probe(struct device *dev) -{ - return(scc_enet_init ()); -} - - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ --- linux-2.6.1-rc1/drivers/net/8139too.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/8139too.c 2003-12-30 22:49:19.000000000 -0800 @@ -92,7 +92,7 @@ */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.26" +#define DRV_VERSION "0.9.27" #include @@ -117,17 +117,17 @@ #define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " +/* Default Message level */ +#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK) + /* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ #ifdef CONFIG_8139TOO_PIO #define USE_IO_OPS 1 #endif -/* use a 16K rx ring buffer instead of the default 32K */ -#ifdef CONFIG_SH_DREAMCAST -#define USE_BUF16K 1 -#endif - /* define to 1 to enable copious debugging info */ #undef RTL8139_DEBUG @@ -146,9 +146,9 @@ # define assert(expr) do {} while (0) #else # define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + if(unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ } #endif @@ -159,9 +159,6 @@ static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 32; @@ -169,16 +166,16 @@ static int multicast_filter_limit = 32; /* bitmapped message enable number */ static int debug = -1; -/* Size of the in-memory receive ring. */ -#ifdef USE_BUF16K -#define RX_BUF_LEN_IDX 1 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#else -#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#endif -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +/* Ring size is now a config option */ +#define RX_BUF_LEN (8192 << CONFIG_8139_RXBUF_IDX) #define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ + +#if RX_BUF_LEN == 65536 +#define RX_BUF_TOT_LEN RX_BUF_LEN +#else #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) +#endif /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -251,6 +248,10 @@ static struct pci_device_id rtl8139_pci_ {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, #ifdef CONFIG_SH_SECUREEDGE5410 /* Bogus 8139 silicon reports 8129 without external PROM :-( */ @@ -450,7 +451,7 @@ enum RxConfigBits { RxCfgRcv32K = (1 << 12), RxCfgRcv64K = (1 << 11) | (1 << 12), - /* Disable packet wrap at end of Rx buffer */ + /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ RxNoWrap = (1 << 7), }; @@ -560,6 +561,7 @@ struct rtl8139_private { int drv_flags; struct pci_dev *pci_dev; u32 pci_state[16]; + u32 msg_enable; struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -574,6 +576,7 @@ struct rtl8139_private { char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int default_port:4; /* Last dev->if_port value. */ spinlock_t lock; + spinlock_t rx_lock; chip_t chipset; pid_t thr_pid; wait_queue_head_t thr_wait; @@ -590,13 +593,11 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fa MODULE_LICENSE("GPL"); MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM (max_interrupt_work, "i"); MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (debug, "i"); MODULE_PARM_DESC (debug, "8139too bitmapped message enable number"); MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses"); -MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt"); MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"); MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)"); @@ -610,6 +611,10 @@ static void rtl8139_tx_timeout (struct n static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev); +static int rtl8139_poll(struct net_device *dev, int *budget); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void rtl8139_poll_controller(struct net_device *dev); +#endif static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int rtl8139_close (struct net_device *dev); @@ -682,16 +687,32 @@ static const u16 rtl8139_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; -#ifdef USE_BUF16K +static const u16 rtl8139_norx_intr_mask = + PCIErr | PCSTimeout | RxUnderrun | + TxErr | TxOK | RxErr ; + +#if CONFIG_8139_RXBUF_IDX == 0 +static const unsigned int rtl8139_rx_config = + RxCfgRcv8K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +#elif CONFIG_8139_RXBUF_IDX == 1 static const unsigned int rtl8139_rx_config = RxCfgRcv16K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); -#else +#elif CONFIG_8139_RXBUF_IDX == 2 static const unsigned int rtl8139_rx_config = RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); +#elif CONFIG_8139_RXBUF_IDX == 3 +static const unsigned int rtl8139_rx_config = + RxCfgRcv64K | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +#else +#error "Invalid configuration for 8139_RXBUF_IDX" #endif static const unsigned int rtl8139_tx_config = @@ -868,9 +889,7 @@ static int __devinit rtl8139_init_board match: DPRINTK ("chipset id (%d) == index %d, '%s'\n", - tmp, - tp->chipset, - rtl_chip_info[tp->chipset].name); + version, i, rtl_chip_info[i].name); if (tp->chipset >= CH_8139B) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); @@ -964,6 +983,8 @@ static int __devinit rtl8139_init_one (s /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; dev->hard_start_xmit = rtl8139_start_xmit; + dev->poll = rtl8139_poll; + dev->weight = 64; dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; @@ -971,6 +992,9 @@ static int __devinit rtl8139_init_one (s dev->ethtool_ops = &rtl8139_ethtool_ops; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = rtl8139_poll_controller; +#endif /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -986,7 +1010,10 @@ static int __devinit rtl8139_init_one (s /* note: tp->chipset set in rtl8139_init_board */ tp->drv_flags = board_info[ent->driver_data].hw_flags; tp->mmio_addr = ioaddr; + tp->msg_enable = + (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); + spin_lock_init (&tp->rx_lock); init_waitqueue_head (&tp->thr_wait); init_completion (&tp->thr_exited); tp->mii.dev = dev; @@ -1288,9 +1315,7 @@ static int rtl8139_open (struct net_devi { struct rtl8139_private *tp = dev->priv; int retval; -#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; -#endif retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); if (retval) @@ -1319,8 +1344,10 @@ static int rtl8139_open (struct net_devi rtl8139_init_ring (dev); rtl8139_hw_start (dev); + netif_start_queue (dev); - DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" + if (netif_msg_ifup(tp)) + printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), @@ -1337,7 +1364,7 @@ static void rtl_check_media (struct net_ struct rtl8139_private *tp = dev->priv; if (tp->phys[0] >= 0) { - mii_check_media(&tp->mii, 1, init_media); + mii_check_media(&tp->mii, netif_msg_link(tp), init_media); } } @@ -1407,8 +1434,6 @@ static void rtl8139_hw_start (struct net /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - - netif_start_queue (dev); } @@ -1631,7 +1656,7 @@ static inline void rtl8139_start_thread( } } -static void rtl8139_tx_clear (struct rtl8139_private *tp) +static inline void rtl8139_tx_clear (struct rtl8139_private *tp) { tp->cur_tx = 0; tp->dirty_tx = 0; @@ -1661,6 +1686,7 @@ static void rtl8139_tx_timeout (struct n if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, CmdRxEnb); + spin_lock(&tp->rx_lock); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1679,9 +1705,12 @@ static void rtl8139_tx_timeout (struct n spin_unlock_irqrestore (&tp->lock, flags); /* ...and finally, reset everything */ - rtl8139_hw_start (dev); - - netif_wake_queue (dev); + if (netif_running(dev)) { + rtl8139_hw_start (dev); + netif_wake_queue (dev); + } + spin_unlock(&tp->rx_lock); + } @@ -1695,6 +1724,7 @@ static int rtl8139_start_xmit (struct sk /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; + /* Note: the chip doesn't have auto-pad! */ if (likely(len < TX_BUF_SIZE)) { if (len < ETH_ZLEN) memset(tp->tx_buf[entry], 0, ETH_ZLEN); @@ -1706,7 +1736,6 @@ static int rtl8139_start_xmit (struct sk return 0; } - /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); @@ -1720,8 +1749,9 @@ static int rtl8139_start_xmit (struct sk netif_stop_queue (dev); spin_unlock_irq(&tp->lock); - DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n", - dev->name, len, entry); + if (netif_msg_tx_queued(tp)) + printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", + dev->name, len, entry); return 0; } @@ -1751,8 +1781,9 @@ static void rtl8139_tx_interrupt (struct /* Note: TxCarrierLost is always asserted at 100mbps. */ if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ - DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); + if (netif_msg_tx_err(tp)) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; @@ -1792,8 +1823,7 @@ static void rtl8139_tx_interrupt (struct if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; mb(); - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); + netif_wake_queue (dev); } } @@ -1807,8 +1837,9 @@ static void rtl8139_rx_err (u32 rx_statu int tmp_work; #endif - DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", - dev->name, rx_status); + if (netif_msg_rx_err (tp)) + printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", + dev->name, rx_status); tp->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { @@ -1880,30 +1911,41 @@ static void rtl8139_rx_err (u32 rx_statu #endif } -static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr) -{ - unsigned char *rx_ring; - u16 cur_rx; - - assert (dev != NULL); - assert (tp != NULL); - assert (ioaddr != NULL); +#if CONFIG_8139_RXBUF_IDX == 3 +static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring, + u32 offset, unsigned int size) +{ + u32 left = RX_BUF_LEN - offset; + + if (size > left) { + memcpy(skb->data, ring + offset, left); + memcpy(skb->data+left, ring, size - left); + } else + memcpy(skb->data, ring + offset, size); +} +#endif - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; +static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, + int budget) +{ + void *ioaddr = tp->mmio_addr; + int received = 0; + unsigned char *rx_ring = tp->rx_ring; + unsigned int cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; + while (netif_running(dev) && received < budget + && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { + u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int rx_size; unsigned int pkt_size; struct sk_buff *skb; + u16 status; rmb(); @@ -1912,8 +1954,9 @@ static void rtl8139_rx_interrupt (struct rx_size = rx_status >> 16; pkt_size = rx_size - 4; - DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," - " cur %4.4x.\n", dev->name, rx_status, + if (netif_msg_rx_status(tp)) + printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," + " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); #if RTL8139_DEBUG > 2 { @@ -1930,9 +1973,9 @@ static void rtl8139_rx_interrupt (struct * Theoretically, this should never happen * since EarlyRx is disabled. */ - if (rx_size == 0xfff0) { + if (unlikely(rx_size == 0xfff0)) { tp->xstats.early_rx++; - break; + goto done; } /* If Rx err or invalid rx_size/rx_status received @@ -1940,55 +1983,69 @@ static void rtl8139_rx_interrupt (struct * Rx process gets reset, so we abort any further * Rx processing. */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (rx_size < 8) || - (!(rx_status & RxStatusOK))) { + if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) || + (rx_size < 8) || + (!(rx_status & RxStatusOK)))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); - return; + return -1; } /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - /* TODO: consider allocating skb's outside of - * interrupt context, both to speed interrupt processing, - * and also to reduce the chances of having to - * drop packets here under memory pressure. - */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { + if (likely(skb)) { skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields. */ - +#if CONFIG_8139_RXBUF_IDX == 3 + wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); +#else eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); +#endif skb_put (skb, pkt_size); skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); + dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; + + netif_receive_skb (skb); } else { - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", - dev->name); + if (net_ratelimit()) + printk (KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + dev->name); tp->stats.rx_dropped++; } + received++; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - RTL_W16 (RxBufPtr, cur_rx - 16); + RTL_W16 (RxBufPtr, (u16) (cur_rx - 16)); - if (RTL_R16 (IntrStatus) & RxAckBits) + /* Clear out errors and receive interrupts */ + status = RTL_R16 (IntrStatus) & RxAckBits; + if (likely(status != 0)) { + if (unlikely(status & (RxFIFOOver | RxOverflow))) { + tp->stats.rx_errors++; + if (status & RxFIFOOver) + tp->stats.rx_fifo_errors++; + } RTL_W16_F (IntrStatus, RxAckBits); + } } + done: + +#if RTL8139_DEBUG > 1 DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); +#endif tp->cur_rx = cur_rx; + return received; } @@ -2014,14 +2071,12 @@ static void rtl8139_weird_interrupt (str status &= ~RxUnderrun; } - /* XXX along with rtl8139_rx_err, are we double-counting errors? */ - if (status & - (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) + if (status & (RxUnderrun | RxErr)) tp->stats.rx_errors++; if (status & PCSTimeout) tp->stats.rx_length_errors++; - if (status & (RxUnderrun | RxFIFOOver)) + if (status & RxUnderrun) tp->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; @@ -2033,6 +2088,39 @@ static void rtl8139_weird_interrupt (str } } +static int rtl8139_poll(struct net_device *dev, int *budget) +{ + struct rtl8139_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + int orig_budget = min(*budget, dev->quota); + int done = 1; + + spin_lock(&tp->rx_lock); + if (likely(RTL_R16(IntrStatus) & RxAckBits)) { + int work_done; + + work_done = rtl8139_rx(dev, tp, orig_budget); + if (likely(work_done > 0)) { + *budget -= work_done; + dev->quota -= work_done; + done = (work_done < orig_budget); + } + } + + if (done) { + /* + * Order is important since data can get interrupted + * again when we think we are done. + */ + local_irq_disable(); + RTL_W16_F(IntrMask, rtl8139_intr_mask); + __netif_rx_complete(dev); + local_irq_enable(); + } + spin_unlock(&tp->rx_lock); + + return !done; +} /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -2041,68 +2129,59 @@ static irqreturn_t rtl8139_interrupt (in { struct net_device *dev = (struct net_device *) dev_instance; struct rtl8139_private *tp = dev->priv; - int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int ackstat, status; + u16 status, ackstat; int link_changed = 0; /* avoid bogus "uninit" warning */ int handled = 0; spin_lock (&tp->lock); + status = RTL_R16 (IntrStatus); - do { - status = RTL_R16 (IntrStatus); + /* shared irq? */ + if (unlikely((status & rtl8139_intr_mask) == 0)) + goto out; - /* h/w no longer present (hotplug?) or major error, bail */ - if (status == 0xFFFF) - break; + handled = 1; - if ((status & - (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) - break; + /* h/w no longer present (hotplug?) or major error, bail */ + if (unlikely(status == 0xFFFF)) + goto out; - handled = 1; + /* close possible race's with dev_close */ + if (unlikely(!netif_running(dev))) { + RTL_W16 (IntrMask, 0); + goto out; + } - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if (unlikely(status & RxUnderrun)) + link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; - /* The chip takes special action when we clear RxAckBits, - * so we clear them later in rtl8139_rx_interrupt - */ - ackstat = status & ~(RxAckBits | TxErr); + ackstat = status & ~(RxAckBits | TxErr); + if (ackstat) RTL_W16 (IntrStatus, ackstat); - DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, ackstat, RTL_R16 (IntrStatus)); - - if (netif_running (dev) && (status & RxAckBits)) - rtl8139_rx_interrupt (dev, tp, ioaddr); - - /* Check uncommon events with one test. */ - if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | RxErr)) - rtl8139_weird_interrupt (dev, tp, ioaddr, - status, link_changed); - - if (netif_running (dev) && (status & (TxOK | TxErr))) { - rtl8139_tx_interrupt (dev, tp, ioaddr); - if (status & TxErr) - RTL_W16 (IntrStatus, TxErr); + /* Receive packets are processed by poll routine. + If not running start it now. */ + if (status & RxAckBits){ + if (netif_rx_schedule_prep(dev)) { + RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); + __netif_rx_schedule (dev); } - - boguscnt--; - } while (boguscnt > 0); - - if (boguscnt <= 0) { - printk (KERN_WARNING "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, status); - - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); } + /* Check uncommon events with one test. */ + if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr))) + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); + + if (status & (TxOK | TxErr)) { + rtl8139_tx_interrupt (dev, tp, ioaddr); + if (status & TxErr) + RTL_W16 (IntrStatus, TxErr); + } + out: spin_unlock (&tp->lock); DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", @@ -2110,6 +2189,18 @@ static irqreturn_t rtl8139_interrupt (in return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void rtl8139_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + rtl8139_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static int rtl8139_close (struct net_device *dev) { @@ -2130,8 +2221,9 @@ static int rtl8139_close (struct net_dev } wait_for_completion (&tp->thr_exited); } - - DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", + + if (netif_msg_ifdown(tp)) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); spin_lock_irqsave (&tp->lock, flags); @@ -2289,12 +2381,14 @@ static u32 rtl8139_get_link(struct net_d static u32 rtl8139_get_msglevel(struct net_device *dev) { - return debug; + struct rtl8139_private *np = dev->priv; + return np->msg_enable; } static void rtl8139_set_msglevel(struct net_device *dev, u32 datum) { - debug = datum; + struct rtl8139_private *np = dev->priv; + np->msg_enable = datum; } /* TODO: we are too slack to do reg dumping for pio, for now */ --- linux-2.6.1-rc1/drivers/net/82596.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/82596.c 2003-12-30 22:49:19.000000000 -0800 @@ -1129,21 +1129,40 @@ static void print_eth(unsigned char *add printk(" %02X%02X, %s\n", add[12], add[13], str); } -int __init i82596_probe(struct net_device *dev) +static int io = 0x300; +static int irq = 10; + +struct net_device * __init i82596_probe(int unit) { + struct net_device *dev; int i; struct i596_private *lp; char eth_addr[8]; static int probed; + int err; if (probed) - return -ENODEV; + return ERR_PTR(-ENODEV); probed++; + + dev = alloc_etherdev(0); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } else { + dev->base_addr = io; + dev->irq = irq; + } + #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n"); - return -ENODEV; + err = -ENODEV; + goto out; } memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ dev->base_addr = MVME_I596_BASE; @@ -1174,7 +1193,8 @@ int __init i82596_probe(struct net_devic if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) { printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr); - return -EBUSY; + err = -EBUSY; + goto out; } for (i = 0; i < 8; i++) { @@ -1190,8 +1210,8 @@ int __init i82596_probe(struct net_devic if ((checksum % 0x100) || (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) { - release_region(ioaddr, I596_TOTAL_SIZE); - return -ENODEV; + err = -ENODEV; + goto out1; } dev->base_addr = ioaddr; @@ -1200,13 +1220,10 @@ int __init i82596_probe(struct net_devic #endif dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); if (!dev->mem_start) { -#ifdef ENABLE_APRICOT - release_region(dev->base_addr, I596_TOTAL_SIZE); -#endif - return -ENOMEM; + err = -ENOMEM; + goto out1; } - ether_setup(dev); DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) @@ -1244,7 +1261,26 @@ int __init i82596_probe(struct net_devic lp->scb.rfd = I596_NULL; lp->lock = SPIN_LOCK_UNLOCKED; - return 0; + err = register_netdev(dev); + if (err) + goto out2; + return dev; +out2: +#ifdef __mc68000__ + /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, + * XXX which may be invalid (CONFIG_060_WRITETHROUGH) + */ + kernel_set_cachemode((void *)(dev->mem_start), 4096, + IOMAP_FULL_CACHING); +#endif + free_page ((u32)(dev->mem_start)); +out1: +#ifdef ENABLE_APRICOT + release_region(dev->base_addr, I596_TOTAL_SIZE); +#endif +out: + free_netdev(dev); + return ERR_PTR(err); } static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -1532,11 +1568,9 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_82596 = { .init = i82596_probe }; +static struct net_device *dev_82596; #ifdef ENABLE_APRICOT -static int io = 0x300; -static int irq = 10; MODULE_PARM(irq, "i"); MODULE_PARM_DESC(irq, "Apricot IRQ number"); #endif @@ -1547,34 +1581,31 @@ static int debug = -1; int init_module(void) { -#ifdef ENABLE_APRICOT - dev_82596.base_addr = io; - dev_82596.irq = irq; -#endif if (debug >= 0) i596_debug = debug; - if (register_netdev(&dev_82596) != 0) - return -EIO; + dev_82596 = i82596_probe(-1); + if (IS_ERR(dev_82596)) + return PTR_ERR(dev_82596); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_82596); + unregister_netdev(dev_82596); #ifdef __mc68000__ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, * XXX which may be invalid (CONFIG_060_WRITETHROUGH) */ - kernel_set_cachemode((void *)(dev_82596.mem_start), 4096, + kernel_set_cachemode((void *)(dev_82596->mem_start), 4096, IOMAP_FULL_CACHING); #endif - free_page ((u32)(dev_82596.mem_start)); - dev_82596.priv = NULL; + free_page ((u32)(dev_82596->mem_start)); #ifdef ENABLE_APRICOT /* If we don't do this, we can't re-insmod it later. */ - release_region(dev_82596.base_addr, I596_TOTAL_SIZE); + release_region(dev_82596->base_addr, I596_TOTAL_SIZE); #endif + free_netdev(dev_82596); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/8390.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/net/8390.c 2003-12-30 22:49:19.000000000 -0800 @@ -157,15 +157,8 @@ static void do_set_multicast_list(struct int ei_open(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); - /* This can't happen unless somebody forgot to call ethdev_init(). */ - if (ei_local == NULL) - { - printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); - return -ENXIO; - } - /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout wrapper that does e.g. media check & then calls ei_tx_timeout. */ if (dev->tx_timeout == NULL) @@ -196,7 +189,7 @@ int ei_open(struct net_device *dev) */ int ei_close(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* @@ -221,7 +214,7 @@ int ei_close(struct net_device *dev) void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; @@ -267,7 +260,7 @@ void ei_tx_timeout(struct net_device *de static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int length, send_length, output_page; unsigned long flags; char scratch[ETH_ZLEN]; @@ -435,7 +428,7 @@ irqreturn_t ei_interrupt(int irq, void * } e8390_base = dev->base_addr; - ei_local = (struct ei_device *) dev->priv; + ei_local = (struct ei_device *) netdev_priv(dev); /* * Protect the irq test too. @@ -540,7 +533,7 @@ irqreturn_t ei_interrupt(int irq, void * static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -583,7 +576,7 @@ static void ei_tx_err(struct net_device static void ei_tx_intr(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int status = inb(e8390_base + EN0_TSR); outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */ @@ -675,7 +668,7 @@ static void ei_tx_intr(struct net_device static void ei_receive(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; int rx_pkt_count = 0; @@ -813,7 +806,7 @@ static void ei_rx_overrun(struct net_dev { long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -881,7 +874,7 @@ static void ei_rx_overrun(struct net_dev static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* If the card is stopped, just return the present stats. */ @@ -936,7 +929,7 @@ static void do_set_multicast_list(struct { long e8390_base = dev->base_addr; int i; - struct ei_device *ei_local = (struct ei_device*)dev->priv; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { @@ -990,53 +983,34 @@ static void do_set_multicast_list(struct static void set_multicast_list(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device*)dev->priv; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); spin_lock_irqsave(&ei_local->page_lock, flags); do_set_multicast_list(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); } -static inline void ei_device_init(struct ei_device *ei_local) -{ - spin_lock_init(&ei_local->page_lock); -} - /** - * ethdev_init - init rest of 8390 device struct + * ethdev_setup - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -int ethdev_init(struct net_device *dev) +static void ethdev_setup(struct net_device *dev) { + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); if (ei_debug > 1) printk(version); - if (dev->priv == NULL) - { - dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ei_device)); - ei_device_init(dev->priv); - } - dev->hard_start_xmit = &ei_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - - return 0; -} -/* wrapper to make alloc_netdev happy; probably should just cast... */ -static void __ethdev_init(struct net_device *dev) -{ - ethdev_init(dev); + spin_lock_init(&ei_local->page_lock); } /** @@ -1044,15 +1018,10 @@ static void __ethdev_init(struct net_dev * * Allocate 8390-specific net_device. */ -struct net_device *alloc_ei_netdev(void) +struct net_device *__alloc_ei_netdev(int size) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct ei_device), "eth%d", __ethdev_init); - if (dev) - ei_device_init(dev->priv); - - return dev; + return alloc_netdev(sizeof(struct ei_device) + size, "eth%d", + ethdev_setup); } @@ -1072,7 +1041,7 @@ struct net_device *alloc_ei_netdev(void) void NS8390_init(struct net_device *dev, int startp) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0)) @@ -1136,7 +1105,7 @@ static void NS8390_trigger_send(struct n int start_page) { long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev); outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); @@ -1156,9 +1125,8 @@ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); EXPORT_SYMBOL(ei_tx_timeout); -EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); -EXPORT_SYMBOL(alloc_ei_netdev); +EXPORT_SYMBOL(__alloc_ei_netdev); #if defined(MODULE) --- linux-2.6.1-rc1/drivers/net/8390.h 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/8390.h 2003-12-30 22:49:19.000000000 -0800 @@ -39,12 +39,15 @@ extern int ei_debug; #define ei_debug 1 #endif -extern int ethdev_init(struct net_device *dev); extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); -extern struct net_device *alloc_ei_netdev(void); +extern struct net_device *__alloc_ei_netdev(int size); +static inline struct net_device *alloc_ei_netdev(void) +{ + return __alloc_ei_netdev(0); +} /* You have one of these per-board */ struct ei_device { @@ -84,7 +87,7 @@ struct ei_device { /* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */ #define TX_TIMEOUT (20*HZ/100) -#define ei_status (*(struct ei_device *)(dev->priv)) +#define ei_status (*(struct ei_device *)netdev_priv(dev)) /* Some generic ethernet register configurations. */ #define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ --- linux-2.6.1-rc1/drivers/net/a2065.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/a2065.c 2003-12-30 22:49:19.000000000 -0800 @@ -737,7 +737,7 @@ static int __init a2065_probe(void) continue; } - dev = init_etherdev(NULL, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (dev == NULL) { release_resource(r1); @@ -791,17 +791,22 @@ static int __init a2065_probe(void) dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; -#ifdef MODULE - priv->next_module = root_a2065_dev; - root_a2065_dev = priv; -#endif - ether_setup(dev); init_timer(&priv->multicast_timer); priv->multicast_timer.data = (unsigned long) dev; priv->multicast_timer.function = (void (*)(unsigned long)) &lance_set_multicast; - res = 0; + res = register_netdev(dev); + if (res) { + release_resource(r1); + release_resource(r2); + free_netdev(dev); + break; + } +#ifdef MODULE + priv->next_module = root_a2065_dev; + root_a2065_dev = priv; +#endif } return res; } --- linux-2.6.1-rc1/drivers/net/ac3200.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ac3200.c 2003-12-30 22:49:19.000000000 -0800 @@ -75,7 +75,6 @@ static const char *port_name[4] = { "10b #define AC_START_PG 0x00 /* First page of 8390 TX buffer */ #define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */ -int ac3200_probe(struct net_device *dev); static int ac_probe1(int ioaddr, struct net_device *dev); static int ac_open(struct net_device *dev); @@ -96,9 +95,11 @@ static int ac_close_card(struct net_devi or the unique value in the station address PROM. */ -int __init ac3200_probe(struct net_device *dev) +static int __init do_ac3200_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; SET_MODULE_OWNER(dev); @@ -110,13 +111,50 @@ int __init ac3200_probe(struct net_devic if ( ! EISA_bus) return -ENXIO; - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (ac_probe1(ioaddr, dev) == 0) return 0; + dev->irq = irq; + dev->mem_start = mem_start; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* Someday free_irq may be in ac_close_card() */ + free_irq(dev->irq, dev); + release_region(dev->base_addr, AC_IO_EXTENT); + if (ei_status.reg0) + iounmap((void *)dev->mem_start); +} + +struct net_device * __init ac3200_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ac3200_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; @@ -156,13 +194,6 @@ static int __init ac_probe1(int ioaddr, } #endif - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* Assign and allocate the interrupt now. */ if (dev->irq == 0) { dev->irq = config2irq(inb(ioaddr + AC_CONFIG)); @@ -210,7 +241,7 @@ static int __init ac_probe1(int ioaddr, printk(KERN_CRIT "ac3200.c: or to an address above 0x%lx.\n", virt_to_phys(high_memory)); printk(KERN_CRIT "ac3200.c: Driver NOT installed.\n"); retval = -EINVAL; - goto out2; + goto out1; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, AC_STOP_PG*0x100); if (dev->mem_start == 0) { @@ -218,7 +249,7 @@ static int __init ac_probe1(int ioaddr, printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n"); printk(KERN_ERR "ac3200.c: Driver NOT installed.\n"); retval = -EINVAL; - goto out2; + goto out1; } ei_status.reg0 = 1; /* Use as remap flag */ printk("ac3200.c: remapped %dkB card memory to virtual address %#lx\n", @@ -247,11 +278,8 @@ static int __init ac_probe1(int ioaddr, dev->stop = &ac_close_card; NS8390_init(dev, 0); return 0; -out2: - free_irq(dev->irq, dev); out1: - kfree(dev->priv); - dev->priv = NULL; + free_irq(dev->irq, dev); out: release_region(ioaddr, AC_IO_EXTENT); return retval; @@ -338,7 +366,7 @@ static int ac_close_card(struct net_devi #ifdef MODULE #define MAX_AC32_CARDS 4 /* Max number of AC32 cards per module */ -static struct net_device dev_ac32[MAX_AC32_CARDS]; +static struct net_device *dev_ac32[MAX_AC32_CARDS]; static int io[MAX_AC32_CARDS]; static int irq[MAX_AC32_CARDS]; static int mem[MAX_AC32_CARDS]; @@ -354,26 +382,32 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { - struct net_device *dev = &dev_ac32[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ - dev->init = ac3200_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ac3200_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ac32[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; - } - return 0; + free_netdev(dev); + printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); + break; + } + if (found) + return 0; + return -ENXIO; } void @@ -382,16 +416,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { - struct net_device *dev = &dev_ac32[this_dev]; - if (dev->priv != NULL) { - /* Someday free_irq may be in ac_close_card() */ - free_irq(dev->irq, dev); - release_region(dev->base_addr, AC_IO_EXTENT); - if (ei_status.reg0) - iounmap((void *)dev->mem_start); + struct net_device *dev = dev_ac32[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/amd8111e.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/amd8111e.c 2003-12-30 22:49:19.000000000 -0800 @@ -1153,6 +1153,17 @@ err_no_interrupt: return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void amd8111e_poll(struct net_device *dev) +{ + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + amd8111e_interrupt(0, dev, NULL); + local_irq_restore(flags); +} +#endif + /* This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. */ @@ -1884,6 +1895,9 @@ static int __devinit amd8111e_probe_one( dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = amd8111e_poll; +#endif #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; --- linux-2.6.1-rc1/drivers/net/apne.c 2003-06-14 12:18:51.000000000 -0700 +++ 25/drivers/net/apne.c 2003-12-30 22:49:19.000000000 -0800 @@ -72,7 +72,7 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int apne_probe(struct net_device *dev); +struct net_device * __init apne_probe(int unit); static int apne_probe1(struct net_device *dev, int ioaddr); static int apne_open(struct net_device *dev); @@ -116,28 +116,37 @@ static const char version[] = static int apne_owned; /* signal if card already owned */ -int __init apne_probe(struct net_device *dev) +struct net_device * __init apne_probe(int unit) { + struct net_device *dev; #ifndef MANUAL_CONFIG char tuple[8]; #endif + int err; if (apne_owned) - return -ENODEV; - - SET_MODULE_OWNER(dev); + return ERR_PTR(-ENODEV); if ( !(AMIGAHW_PRESENT(PCMCIA)) ) - return (-ENODEV); + return ERR_PTR(-ENODEV); printk("Looking for PCMCIA ethernet card : "); /* check if a card is inserted */ if (!(PCMCIA_INSERTED)) { printk("NO PCMCIA card inserted\n"); - return (-ENODEV); + return ERR_PTR(-ENODEV); } - + + dev = alloc_ei_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); + /* disable pcmcia irq for readtuple */ pcmcia_disable_irq(); @@ -145,17 +154,41 @@ int __init apne_probe(struct net_device if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) || (tuple[2] != CISTPL_FUNCID_NETWORK)) { printk("not an ethernet card\n"); - return (-ENODEV); + /* XXX: shouldn't we re-enable irq here? */ + free_netdev(dev); + return ERR_PTR(-ENODEV); } #endif printk("ethernet PCMCIA card inserted\n"); - if (init_pcmcia()) - return apne_probe1(dev, IOBASE); - else - return (-ENODEV); + if (!init_pcmcia()) { + /* XXX: shouldn't we re-enable irq here? */ + free_netdev(dev); + return ERR_PTR(-ENODEV); + } + if (!request_region(IOBASE, 0x20, dev->name)) { + free_netdev(dev); + return ERR_PTR(-EBUSY); + } + + err = apne_probe1(dev, IOBASE); + if (err) { + release_region(IOBASE, 0x20); + free_netdev(dev); + return ERR_PTR(err); + } + err = register_netdev(dev); + if (!err) + return dev; + + pcmcia_disable_irq(); + free_irq(IRQ_AMIGA_PORTS, dev); + pcmcia_reset(); + release_region(IOBASE, 0x20); + free_netdev(dev); + return ERR_PTR(err); } static int __init apne_probe1(struct net_device *dev, int ioaddr) @@ -280,13 +313,6 @@ static int __init apne_probe1(struct net i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - free_irq(IRQ_AMIGA_PORTS, dev); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; @@ -534,32 +560,27 @@ static irqreturn_t apne_interrupt(int ir } #ifdef MODULE -static struct net_device apne_dev; +static struct net_device *apne_dev; int init_module(void) { - int err; - - apne_dev.init = apne_probe; - if ((err = register_netdev(&apne_dev))) { - if (err == -EIO) - printk("No PCMCIA NEx000 ethernet card found.\n"); - return (err); - } - return (0); + apne_dev = apne_probe(-1); + if (IS_ERR(apne_dev)) + return PTR_ERR(apne_dev); + return 0; } void cleanup_module(void) { - unregister_netdev(&apne_dev); + unregister_netdev(apne_dev); pcmcia_disable_irq(); - free_irq(IRQ_AMIGA_PORTS, &apne_dev); + free_irq(IRQ_AMIGA_PORTS, apne_dev); pcmcia_reset(); - apne_owned = 0; + free_netdev(apne_dev); } #endif --- linux-2.6.1-rc1/drivers/net/appletalk/ipddp.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/drivers/net/appletalk/ipddp.c 2003-12-30 22:49:19.000000000 -0800 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -55,34 +56,24 @@ static struct ipddp_route* ipddp_find_ro static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int __init ipddp_init(struct net_device *dev) +static struct net_device * __init ipddp_init(void) { static unsigned version_printed; + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev); + strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) printk(version); - /* Let the user now what mode we are in */ - if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", - dev->name); - if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", - dev->name); - - /* Fill in the device structure with ethernet-generic values. */ - ether_setup(dev); - /* Initalize the device structure. */ dev->hard_start_xmit = ipddp_xmit; - - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if(!dev->priv) - return -ENOMEM; - memset(dev->priv,0,sizeof(struct net_device_stats)); - dev->get_stats = ipddp_get_stats; dev->do_ioctl = ipddp_ioctl; @@ -97,7 +88,21 @@ static int __init ipddp_init(struct net_ */ dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; - return 0; + err = register_netdev(dev); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + + /* Let the user now what mode we are in */ + if(ipddp_mode == IPDDP_ENCAP) + printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", + dev->name); + if(ipddp_mode == IPDDP_DECAP) + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", + dev->name); + + return dev; } /* @@ -281,23 +286,16 @@ static int ipddp_ioctl(struct net_device } } -static struct net_device dev_ipddp; +static struct net_device *dev_ipddp; MODULE_LICENSE("GPL"); MODULE_PARM(ipddp_mode, "i"); static int __init ipddp_init_module(void) { - int err; - - dev_ipddp.init = ipddp_init; - err=dev_alloc_name(&dev_ipddp, "ipddp%d"); - if(err < 0) - return err; - - if(register_netdev(&dev_ipddp) != 0) - return -EIO; - + dev_ipddp = ipddp_init(); + if (IS_ERR(dev_ipddp)) + return PTR_ERR(dev_ipddp); return 0; } @@ -305,8 +303,8 @@ static void __exit ipddp_cleanup_module( { struct ipddp_route *p; - unregister_netdev(&dev_ipddp); - kfree(dev_ipddp.priv); + unregister_netdev(dev_ipddp); + free_netdev(dev_ipddp); while (ipddp_route_list) { p = ipddp_route_list->next; --- linux-2.6.1-rc1/drivers/net/appletalk/ltpc.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/appletalk/ltpc.c 2003-12-30 22:49:19.000000000 -0800 @@ -1213,7 +1213,7 @@ out3: out2: release_region(io, 8); out1: - kfree(dev); + free_netdev(dev); out: return ERR_PTR(err); } --- linux-2.6.1-rc1/drivers/net/arcnet/arcnet.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/arcnet/arcnet.c 2003-12-30 22:49:19.000000000 -0800 @@ -92,6 +92,7 @@ EXPORT_SYMBOL(arc_proto_null); EXPORT_SYMBOL(arcnet_unregister_proto); EXPORT_SYMBOL(arcnet_debug); EXPORT_SYMBOL(arcdev_setup); +EXPORT_SYMBOL(alloc_arcdev); EXPORT_SYMBOL(arcnet_interrupt); /* Internal function prototypes */ @@ -331,6 +332,11 @@ void arcdev_setup(struct net_device *dev dev->rebuild_header = arcnet_rebuild_header; } +struct net_device *alloc_arcdev(char *name) +{ + return alloc_netdev(sizeof(struct arcnet_local), + name && *name ? name : "arc%d", arcdev_setup); +} /* * Open/initialize the board. This is called sometime after booting when --- linux-2.6.1-rc1/drivers/net/arcnet/arc-rimi.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/arcnet/arc-rimi.c 2003-12-30 22:49:19.000000000 -0800 @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include @@ -85,8 +86,6 @@ static void arcrimi_copy_from_card(struc */ static int __init arcrimi_probe(struct net_device *dev) { - int retval; - BUGLVL(D_NORMAL) printk(VERSION); BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n"); @@ -114,11 +113,7 @@ static int __init arcrimi_probe(struct n "ID!\n"); return -ENODEV; } - retval = arcrimi_found(dev); - if (retval < 0) { - release_mem_region(dev->mem_start, BUFFER_SIZE); - } - return retval; + return arcrimi_found(dev); } @@ -129,11 +124,13 @@ static int __init arcrimi_probe(struct n static int __init arcrimi_found(struct net_device *dev) { struct arcnet_local *lp; - u_long first_mirror, last_mirror, shmem; + unsigned long first_mirror, last_mirror, shmem; int mirror_size; + int err; /* reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { + release_mem_region(dev->mem_start, BUFFER_SIZE); BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; } @@ -168,11 +165,7 @@ static int __init arcrimi_found(struct n /* initialize the rest of the device structure. */ - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - BUGMSG(D_NORMAL, "Can't allocate device data!\n"); - goto err_free_irq; - } + lp = dev->priv; lp->card_name = "RIM I"; lp->hw.command = arcrimi_command; lp->hw.status = arcrimi_status; @@ -181,18 +174,6 @@ static int __init arcrimi_found(struct n lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = arcrimi_copy_to_card; lp->hw.copy_from_card = arcrimi_copy_from_card; - lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); - if (!lp->mem_start) { - BUGMSG(D_NORMAL, "Can't remap device memory!\n"); - goto err_free_dev_priv; - } - /* Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - - /* get and check the station ID from offset 1 in shmem */ - dev->dev_addr[0] = readb(lp->mem_start + 1); /* * re-reserve the memory region - arcrimi_probe() alloced this reqion @@ -200,25 +181,40 @@ static int __init arcrimi_found(struct n * with the correct size. There is a VERY slim chance this could * fail. */ - release_mem_region(dev->mem_start, BUFFER_SIZE); + release_mem_region(shmem, BUFFER_SIZE); if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) { BUGMSG(D_NORMAL, "Card memory already allocated\n"); - goto err_free_dev_priv; + goto err_free_irq; } + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_release_mem; + } + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, " "ShMem %lXh (%ld*%d bytes).\n", dev->dev_addr[0], dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + err = register_netdev(dev); + if (err) + goto err_unmap; + return 0; - err_free_dev_priv: - kfree(dev->priv); - err_free_irq: +err_unmap: + iounmap(lp->mem_start); +err_release_mem: + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); +err_free_irq: free_irq(dev->irq, dev); return -EIO; } @@ -294,94 +290,79 @@ static void arcrimi_copy_from_card(struc TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } -#ifdef MODULE +static int node; +static int io; /* use the insmod io= irq= node= options */ +static int irq; +static char device[9]; /* use eg. device=arc1 to change name */ + +module_param(node, int, 0); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); +MODULE_LICENSE("GPL"); static struct net_device *my_dev; -/* Module parameters */ - -static int node = 0; -static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(node, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_LICENSE("GPL"); - -int init_module(void) +static int __init arc_rimi_init(void) { struct net_device *dev; - int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; + return -ENOMEM; if (node && node != 0xff) dev->dev_addr[0] = node; - dev->base_addr = io; + dev->mem_start = io; dev->irq = irq; if (dev->irq == 2) dev->irq = 9; - if (arcrimi_probe(dev)) + if (arcrimi_probe(dev)) { + free_netdev(dev); return -EIO; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit arc_rimi_exit(void) { struct net_device *dev = my_dev; struct arcnet_local *lp = (struct arcnet_local *) dev->priv; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(lp->mem_start); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - kfree(dev->priv); + free_irq(dev->irq, dev); free_netdev(dev); } -#else - +#ifndef MODULE static int __init arcrimi_setup(char *s) { - struct net_device *dev; int ints[8]; - s = get_options(s, 8, ints); if (!ints[0]) return 1; - dev = alloc_bootmem(sizeof(struct net_device)); - memset(dev, 0, sizeof(struct net_device)); - dev->init = arcrimi_probe; - switch (ints[0]) { default: /* ERROR */ printk("arcrimi: Too many arguments.\n"); case 3: /* Node ID */ - dev->dev_addr[0] = ints[3]; + node = ints[3]; case 2: /* IRQ */ - dev->irq = ints[2]; + irq = ints[2]; case 1: /* IO address */ - dev->mem_start = ints[1]; + io = ints[1]; } if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "arc-rimi: Cannot register arcnet device\n"); - + snprintf(device, sizeof(device), "%s", s); return 1; } - __setup("arcrimi=", arcrimi_setup); - #endif /* MODULE */ + +module_init(arc_rimi_init) +module_exit(arc_rimi_exit) --- linux-2.6.1-rc1/drivers/net/arcnet/com20020.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/arcnet/com20020.c 2003-12-30 22:49:19.000000000 -0800 @@ -172,11 +172,6 @@ int com20020_found(struct net_device *de dev->set_multicast_list = com20020_set_mc_list; - /* Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - if (!dev->dev_addr[0]) dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */ @@ -221,7 +216,7 @@ int com20020_found(struct net_device *de lp->setup >> 1, clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]); - if (!dev->init && register_netdev(dev)) { + if (register_netdev(dev)) { free_irq(dev->irq, dev); return -EIO; } @@ -332,19 +327,10 @@ static void com20020_set_mc_list(struct } } -void com20020_remove(struct net_device *dev) -{ - unregister_netdev(dev); - free_irq(dev->irq, dev); - kfree(dev->priv); - free_netdev(dev); -} - #ifdef MODULE EXPORT_SYMBOL(com20020_check); EXPORT_SYMBOL(com20020_found); -EXPORT_SYMBOL(com20020_remove); MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/arcnet/com20020-isa.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/arcnet/com20020-isa.c 2003-12-30 22:49:19.000000000 -0800 @@ -26,6 +26,7 @@ * ********************** */ #include +#include #include #include #include @@ -117,49 +118,41 @@ out: return err; } - -#ifdef MODULE - -static struct net_device *my_dev; - -/* Module parameters */ - static int node = 0; static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ +static char device[9]; /* use eg. device="arc1" to change name */ static int timeout = 3; static int backplane = 0; static int clockp = 0; static int clockm = 0; -MODULE_PARM(node, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout, "i"); -MODULE_PARM(backplane, "i"); -MODULE_PARM(clockp, "i"); -MODULE_PARM(clockm, "i"); +module_param(node, int, 0); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); + MODULE_LICENSE("GPL"); -int init_module(void) +static struct net_device *my_dev; + +static int __init com20020_init(void) { struct net_device *dev; struct arcnet_local *lp; - int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) return -ENOMEM; - memset(lp, 0, sizeof(struct arcnet_local)); if (node && node != 0xff) dev->dev_addr[0] = node; + lp = dev->priv; lp->backplane = backplane; lp->clockp = clockp & 7; lp->clockm = clockm & 3; @@ -172,21 +165,24 @@ int init_module(void) if (dev->irq == 2) dev->irq = 9; - if (com20020isa_probe(dev)) + if (com20020isa_probe(dev)) { + free_netdev(dev); return -EIO; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit com20020_exit(void) { - com20020_remove(my_dev); + unregister_netdev(my_dev); + free_irq(my_dev->irq, my_dev); release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE); + free_netdev(my_dev); } -#else - +#ifndef MODULE static int __init com20020isa_setup(char *s) { struct net_device *dev; @@ -196,37 +192,31 @@ static int __init com20020isa_setup(char s = get_options(s, 8, ints); if (!ints[0]) return 1; - dev = alloc_bootmem(sizeof(struct net_device) + sizeof(struct arcnet_local)); - memset(dev, 0, sizeof(struct net_device) + sizeof(struct arcnet_local)); - lp = dev->priv = (struct arcnet_local *) (dev + 1); - dev->init = com20020isa_probe; switch (ints[0]) { default: /* ERROR */ printk("com90xx: Too many arguments.\n"); case 6: /* Timeout */ - lp->timeout = ints[6]; + timeout = ints[6]; case 5: /* CKP value */ - lp->clockp = ints[5]; + clockp = ints[5]; case 4: /* Backplane flag */ - lp->backplane = ints[4]; + backplane = ints[4]; case 3: /* Node ID */ - dev->dev_addr[0] = ints[3]; + node = ints[3]; case 2: /* IRQ */ - dev->irq = ints[2]; + irq = ints[2]; case 1: /* IO address */ - dev->base_addr = ints[1]; + io = ints[1]; } if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "com20020: Cannot register arcnet device\n"); - + snprintf(device, sizeof(device), "%s", s); return 1; } __setup("com20020=", com20020isa_setup); #endif /* MODULE */ + +module_init(com20020_init) +module_exit(com20020_exit) --- linux-2.6.1-rc1/drivers/net/arcnet/com20020-pci.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/arcnet/com20020-pci.c 2003-12-30 22:49:19.000000000 -0800 @@ -27,6 +27,7 @@ * ********************** */ #include +#include #include #include #include @@ -46,18 +47,18 @@ /* Module parameters */ static int node; -static char *device; /* use eg. device="arc1" to change name */ +static char device[9]; /* use eg. device="arc1" to change name */ static int timeout = 3; static int backplane; static int clockp; static int clockm; -MODULE_PARM(node, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout, "i"); -MODULE_PARM(backplane, "i"); -MODULE_PARM(clockp, "i"); -MODULE_PARM(clockm, "i"); +module_param(node, int, 0); +module_param_string(device, device, sizeof(device), 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); MODULE_LICENSE("GPL"); static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -68,15 +69,11 @@ static int __devinit com20020pci_probe(s if (pci_enable_device(pdev)) return -EIO; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - err = -ENOMEM; - goto out_dev; - } - memset(lp, 0, sizeof(struct arcnet_local)); + return -ENOMEM; + lp = dev->priv; + pci_set_drvdata(pdev, dev); // SOHARD needs PCI base addr 4 @@ -89,6 +86,13 @@ static int __devinit com20020pci_probe(s ioaddr = pci_resource_start(pdev, 2); } + if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { + BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + err = -EBUSY; + goto out_dev; + } + // Dummy access after Reset // ARCNET controller needs this access to detect bustype outb(0x00,ioaddr+1); @@ -105,12 +109,6 @@ static int __devinit com20020pci_probe(s lp->timeout = timeout; lp->hw.owner = THIS_MODULE; - if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { - BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", - ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - err = -EBUSY; - goto out_priv; - } if (ASTATUS() == 0xFF) { BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " "but seems empty!\n", ioaddr); @@ -129,18 +127,18 @@ static int __devinit com20020pci_probe(s out_port: release_region(ioaddr, ARCNET_TOTAL_SIZE); -out_priv: - kfree(dev->priv); out_dev: - kfree(dev); + free_netdev(dev); return err; } static void __devexit com20020pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - com20020_remove(dev); + unregister_netdev(dev); + free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + free_netdev(dev); } static struct pci_device_id com20020pci_id_table[] = { --- linux-2.6.1-rc1/drivers/net/arcnet/com90io.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/arcnet/com90io.c 2003-12-30 22:49:19.000000000 -0800 @@ -27,6 +27,7 @@ */ #include #include +#include #include #include #include @@ -234,6 +235,7 @@ static int __init com90io_found(struct n { struct arcnet_local *lp; int ioaddr = dev->base_addr; + int err; /* Reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { @@ -246,15 +248,6 @@ static int __init com90io_found(struct n return -EBUSY; } - /* Initialize the rest of the device structure. */ - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!dev->priv) { - free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct arcnet_local)); - lp = (struct arcnet_local *) (dev->priv); lp->card_name = "COM90xx I/O"; lp->hw.command = com90io_command; @@ -265,12 +258,6 @@ static int __init com90io_found(struct n lp->hw.copy_to_card = com90io_copy_to_card; lp->hw.copy_from_card = com90io_copy_from_card; - /* - * Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; SETCONF(); @@ -278,6 +265,14 @@ static int __init com90io_found(struct n dev->dev_addr[0] = get_buffer_byte(dev, 1); + err = register_netdev(dev); + if (err) { + outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + return err; + } + BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", dev->dev_addr[0], dev->base_addr, dev->irq); @@ -361,44 +356,67 @@ static void com90io_copy_from_card(struc TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); } - -#ifdef MODULE - -static struct net_device *my_dev; - -/* Module parameters */ - static int io; /* use the insmod io= irq= shmem= options */ static int irq; -static char *device; /* use eg. device=arc1 to change name */ +static char device[9]; /* use eg. device=arc1 to change name */ -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); MODULE_LICENSE("GPL"); -int init_module(void) +#ifndef MODULE +static int __init com90io_setup(char *s) +{ + int ints[4]; + s = get_options(s, 4, ints); + if (!ints[0]) + return 0; + switch (ints[0]) { + default: /* ERROR */ + printk("com90io: Too many arguments.\n"); + case 2: /* IRQ */ + irq = ints[2]; + case 1: /* IO address */ + io = ints[1]; + } + if (*s) + snprintf(device, sizeof(device), "%s", s); + return 1; +} +__setup("com90io=", com90io_setup); +#endif + +static struct net_device *my_dev; + +static int __init com90io_init(void) { struct net_device *dev; int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; + return -ENOMEM; + + SET_MODULE_OWNER(dev); dev->base_addr = io; dev->irq = irq; if (dev->irq == 2) dev->irq = 9; - if (com90io_probe(dev)) - return -EIO; + err = com90io_probe(dev); + + if (err) { + free_netdev(dev); + return err; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit com90io_exit(void) { struct net_device *dev = my_dev; int ioaddr = dev->base_addr; @@ -410,42 +428,8 @@ void cleanup_module(void) free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - kfree(dev->priv); free_netdev(dev); } -#else - -static int __init com90io_setup(char *s) -{ - struct net_device *dev; - int ints[4]; - - s = get_options(s, 4, ints); - if (!ints[0]) - return 0; - dev = alloc_bootmem(sizeof(struct net_device)); - memset(dev, 0, sizeof(struct net_device)); - dev->init = com90io_probe; - - switch (ints[0]) { - default: /* ERROR */ - printk("com90io: Too many arguments.\n"); - case 2: /* IRQ */ - dev->irq = ints[2]; - case 1: /* IO address */ - dev->base_addr = ints[1]; - } - if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "com90io: Cannot register arcnet device\n"); - - return 1; -} - -__setup("com90io=", com90io_setup); - -#endif /* MODULE */ +module_init(com90io_init) +module_exit(com90io_exit) --- linux-2.6.1-rc1/drivers/net/arcnet/com90xx.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/arcnet/com90xx.c 2003-12-30 22:49:19.000000000 -0800 @@ -25,6 +25,7 @@ * ********************** */ #include +#include #include #include #include @@ -52,8 +53,7 @@ /* Internal function declarations */ -static int com90xx_found(struct net_device *dev, int ioaddr, int airq, - u_long shmem); +static int com90xx_found(int ioaddr, int airq, u_long shmem); static void com90xx_command(struct net_device *dev, int command); static int com90xx_status(struct net_device *dev); static void com90xx_setmask(struct net_device *dev, int mask); @@ -98,32 +98,43 @@ static int numcards; static int com90xx_skip_probe __initdata = 0; -static int __init com90xx_probe(struct net_device *dev) +/* Module parameters */ + +static int io; /* use the insmod io= irq= shmem= options */ +static int irq; +static int shmem; +static char device[9]; /* use eg. device=arc1 to change name */ + +module_param(io, int, 0); +module_param(irq, int, 0); +module_param(shmem, int, 0); +module_param_string(device, device, sizeof(device), 0); + +static void __init com90xx_probe(void) { - int count, status, ioaddr, numprint, airq, retval = -ENODEV, - openparen = 0; + int count, status, ioaddr, numprint, airq, openparen = 0; unsigned long airqmask; int ports[(0x3f0 - 0x200) / 16 + 1] = {0}; u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = {0}; int numports, numshmems, *port; - u_long *shmem; + u_long *p; - if (!dev && com90xx_skip_probe) - return -ENODEV; + if (!io && !irq && !shmem && !*device && com90xx_skip_probe) + return; BUGLVL(D_NORMAL) printk(VERSION); /* set up the arrays where we'll store the possible probe addresses */ numports = numshmems = 0; - if (dev && dev->base_addr) - ports[numports++] = dev->base_addr; + if (io) + ports[numports++] = io; else for (count = 0x200; count <= 0x3f0; count += 16) ports[numports++] = count; - if (dev && dev->mem_start) - shmems[numshmems++] = dev->mem_start; + if (shmem) + shmems[numshmems++] = shmem; else for (count = 0xA0000; count <= 0xFF800; count += 2048) shmems[numshmems++] = count; @@ -143,22 +154,19 @@ static int __init com90xx_probe(struct n ioaddr = *port; - if (check_region(*port, ARCNET_TOTAL_SIZE)) { + if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(check_region)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + *port-- = ports[--numports]; continue; } if (ASTATUS() == 0xFF) { BUGMSG2(D_INIT_REASONS, "(empty)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } inb(_RESET); /* begin resetting card */ @@ -171,14 +179,14 @@ static int __init com90xx_probe(struct n if (!numports) { BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); - return -ENODEV; + return; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't * do anything until they finish. If D_INIT, print the list of * cards that are left. */ numprint = -1; - for (port = &ports[0]; port - ports < numports; port++) { + for (port = &ports[0]; port < ports + numports; port++) { numprint++; numprint %= 8; if (!numprint) { @@ -194,8 +202,8 @@ static int __init com90xx_probe(struct n * 0xD1 byte in the right place, or are read-only. */ numprint = -1; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - u_long ptr = *shmem; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + u_long ptr = *p; numprint++; numprint %= 8; @@ -203,15 +211,13 @@ static int __init com90xx_probe(struct n BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S3: "); } - BUGMSG2(D_INIT, "%lXh ", *shmem); + BUGMSG2(D_INIT, "%lXh ", *p); - if (check_mem_region(*shmem, BUFFER_SIZE)) { + if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n"); BUGMSG2(D_INIT_REASONS, "Stage 3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + *p-- = shmems[--numshmems]; continue; } if (isa_readb(ptr) != TESTvalue) { @@ -219,9 +225,8 @@ static int __init com90xx_probe(struct n isa_readb(ptr), TESTvalue); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + release_mem_region(*p, BUFFER_SIZE); + *p-- = shmems[--numshmems]; continue; } /* By writing 0x42 to the TESTvalue location, we also make @@ -233,9 +238,8 @@ static int __init com90xx_probe(struct n if (isa_readb(ptr) != 0x42) { BUGMSG2(D_INIT_REASONS, "(read only)\n"); BUGMSG2(D_INIT_REASONS, "S3: "); - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + release_mem_region(*p, BUFFER_SIZE); + *p-- = shmems[--numshmems]; continue; } BUGMSG2(D_INIT_REASONS, "\n"); @@ -246,20 +250,22 @@ static int __init com90xx_probe(struct n if (!numshmems) { BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); - return -ENODEV; + for (port = &ports[0]; port < ports + numports; port++) + release_region(*port, ARCNET_TOTAL_SIZE); + return; } /* Stage 4: something of a dummy, to report the shmems that are * still possible after stage 3. */ numprint = -1; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + for (p = &shmems[0]; p < shmems + numshmems; p++) { numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S4: "); } - BUGMSG2(D_INIT, "%lXh ", *shmem); + BUGMSG2(D_INIT, "%lXh ", *p); } BUGMSG2(D_INIT, "\n"); @@ -271,7 +277,8 @@ static int __init com90xx_probe(struct n * after the first one is found. */ numprint = -1; - for (port = &ports[0]; port - ports < numports; port++) { + for (port = &ports[0]; port < ports + numports; port++) { + int found = 0; numprint++; numprint %= 8; if (!numprint) { @@ -288,9 +295,8 @@ static int __init com90xx_probe(struct n BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); @@ -300,15 +306,14 @@ static int __init com90xx_probe(struct n status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } /* skip this completely if an IRQ was given, because maybe * we're on a machine that locks during autoirq! */ - if (!dev || !dev->irq) { + if (!irq) { /* if we do this, we're sure to get an IRQ since the * card has just reset and the NORXflag is on until * we tell it to start receiving. @@ -323,13 +328,12 @@ static int __init com90xx_probe(struct n BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } } else { - airq = dev->irq; + airq = irq; } BUGMSG2(D_INIT, "(%d,", airq); @@ -354,21 +358,20 @@ static int __init com90xx_probe(struct n mdelay(RESETtime); #endif - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - u_long ptr = *shmem; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + u_long ptr = *p; if (isa_readb(ptr) == TESTvalue) { /* found one */ - BUGMSG2(D_INIT, "%lXh)\n", *shmem); + BUGMSG2(D_INIT, "%lXh)\n", *p); openparen = 0; /* register the card */ - retval = com90xx_found(dev, *port, airq, *shmem); + if (com90xx_found(*port, airq, *p) == 0) + found = 1; numprint = -1; /* remove shmem from the list */ - *shmem = shmems[numshmems - 1]; - numshmems--; - + *p = shmems[--numshmems]; break; /* go to the next I/O port */ } else { BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); @@ -380,44 +383,39 @@ static int __init com90xx_probe(struct n BUGLVL(D_INIT_REASONS) printk("S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; } - *port = ports[numports - 1]; - numports--; - port--; + if (!found) + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; } BUGLVL(D_INIT_REASONS) printk("\n"); /* Now put back TESTvalue on all leftover shmems. */ - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) - isa_writeb(TESTvalue, *shmem); - - if (retval && dev && !numcards) - BUGMSG2(D_NORMAL, "S5: No ARCnet cards found.\n"); - return retval; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + isa_writeb(TESTvalue, *p); + release_mem_region(*p, BUFFER_SIZE); + } } /* Set up the struct net_device associated with this card. Called after * probing succeeds. */ -static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, - u_long shmem) +static int __init com90xx_found(int ioaddr, int airq, u_long shmem) { - struct net_device *dev = dev0; + struct net_device *dev = NULL; struct arcnet_local *lp; u_long first_mirror, last_mirror; - int mirror_size, err; + int mirror_size; - /* allocate struct net_device if we don't have one yet */ - if (!dev && !(dev = dev_alloc("arc%d", &err))) { + /* allocate struct net_device */ + dev = alloc_arcdev(device); + if (!dev) { BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n"); - return err; - } - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - BUGMSG(D_NORMAL, "Can't allocate device data!\n"); - goto err_free_dev; + release_mem_region(shmem, BUFFER_SIZE); + return -ENOMEM; } + lp = dev->priv; /* find the real shared memory start/end points, including mirrors */ /* guess the actual size of one "memory mirror" - the number of @@ -442,8 +440,18 @@ static int __init com90xx_found(struct n dev->mem_start = first_mirror; dev->mem_end = last_mirror + MIRROR_SIZE - 1; + release_mem_region(shmem, BUFFER_SIZE); + if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) + goto err_free_dev; + + /* reserve the irq */ + if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); + goto err_release_mem; + } + dev->irq = airq; + /* Initialize the rest of the device structure. */ - memset(lp, 0, sizeof(struct arcnet_local)); lp->card_name = "COM90xx"; lp->hw.command = com90xx_command; lp->hw.status = com90xx_status; @@ -455,24 +463,12 @@ static int __init com90xx_found(struct n lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); if (!lp->mem_start) { BUGMSG(D_NORMAL, "Can't remap device memory!\n"); - goto err_free_dev_priv; + goto err_free_irq; } - /* Fill in the fields of the device structure with generic values. */ - arcdev_setup(dev); /* get and check the station ID from offset 1 in shmem */ dev->dev_addr[0] = readb(lp->mem_start + 1); - /* reserve the irq */ - if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { - BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); - goto err_unmap; - } - dev->irq = airq; - - /* reserve the I/O and memory regions - guaranteed to work by check_region */ - request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); - request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); dev->base_addr = ioaddr; BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, " @@ -481,23 +477,20 @@ static int __init com90xx_found(struct n dev->base_addr, dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); - if (!dev0 && register_netdev(dev)) - goto err_release; + if (register_netdev(dev)) + goto err_unmap; cards[numcards++] = dev; return 0; - err_release: +err_unmap: + iounmap(lp->mem_start); +err_free_irq: free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); +err_release_mem: release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - err_unmap: - iounmap(lp->mem_start); - err_free_dev_priv: - kfree(dev->priv); - err_free_dev: - if (!dev0) - kfree(dev); +err_free_dev: + free_netdev(dev); return -EIO; } @@ -587,37 +580,13 @@ static void com90xx_copy_from_card(struc } -/* Module parameters */ - -static int io; /* use the insmod io= irq= shmem= options */ -static int irq; -static int shmem; -static char *device; /* use eg. device=arc1 to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(shmem, "i"); -MODULE_PARM(device, "s"); MODULE_LICENSE("GPL"); static int __init com90xx_init(void) { - struct net_device *dev; - int err; - - if (io || irq || shmem || device) { - dev = dev_alloc(device ? : "arc%d", &err); - if (!dev) - return err; - dev->base_addr = io; - dev->irq = irq; - if (dev->irq == 2) - dev->irq = 9; - dev->mem_start = shmem; - com90xx_probe(dev); - } else - com90xx_probe(NULL); - + if (irq == 2) + irq = 9; + com90xx_probe(); if (!numcards) return -EIO; return 0; @@ -638,7 +607,6 @@ static void __exit com90xx_exit(void) iounmap(lp->mem_start); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - kfree(dev->priv); free_netdev(dev); } } @@ -669,9 +637,7 @@ static int __init com90xx_setup(char *s) } if (*s) - strncpy(device, s, 9); - else - strcpy(device, "arc%d"); + snprintf(device, sizeof(device), "%s", s); return 1; } --- linux-2.6.1-rc1/drivers/net/ariadne.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/ariadne.c 2003-12-30 22:49:19.000000000 -0800 @@ -168,7 +168,7 @@ static int __init ariadne_probe(void) continue; } - dev = init_etherdev(NULL, sizeof(struct ariadne_private)); + dev = alloc_etherdev(sizeof(struct ariadne_private)); if (dev == NULL) { release_resource(r1); @@ -205,11 +205,17 @@ static int __init ariadne_probe(void) dev->get_stats = &ariadne_get_stats; dev->set_multicast_list = &set_multicast_list; + res = register_netdev(dev); + if (res) { + release_resource(r1); + release_resource(r2); + free_netdev(dev); + break; + } #ifdef MODULE priv->next_module = root_ariadne_dev; root_ariadne_dev = priv; #endif - res = 0; } return res; } --- linux-2.6.1-rc1/drivers/net/arm/am79c961a.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/arm/am79c961a.c 2003-12-30 22:49:19.000000000 -0800 @@ -722,7 +722,7 @@ static int __init am79c961_init(void) release: release_region(dev->base_addr, 0x18); nodev: - kfree(dev); + free_netdev(dev); out: return ret; } --- linux-2.6.1-rc1/drivers/net/arm/ether00.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/arm/ether00.c 2003-12-30 22:49:19.000000000 -0800 @@ -923,8 +923,6 @@ static int ether00_add_device(struct pld result = -ENOMEM; goto out_release; } - memset(dev,0,sizeof(struct net_device)); - memset(dev->priv, 0, sizeof(struct net_priv)); priv = dev->priv; priv->tq_memupdate.routine=ether00_mem_update; @@ -966,7 +964,7 @@ static int ether00_add_device(struct pld out_unmap: iounmap(map_addr); out_kfree: - kfree(dev); + free_netdev(dev); out_release: release_mem_region(dev_info->base_addr, MAC_REG_SIZE); return result; --- linux-2.6.1-rc1/drivers/net/arm/ether1.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/arm/ether1.c 2003-12-30 22:49:19.000000000 -0800 @@ -1068,7 +1068,7 @@ ether1_probe(struct expansion_card *ec, release: release_region(dev->base_addr, 16); release_region(dev->base_addr + 0x800, 4096); - kfree(dev); + free_netdev(dev); out: return ret; } --- linux-2.6.1-rc1/drivers/net/arm/ether3.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/arm/ether3.c 2003-12-30 22:49:19.000000000 -0800 @@ -908,7 +908,7 @@ ether3_probe(struct expansion_card *ec, failed: release_region(dev->base_addr, 128); free: - kfree(dev); + free_netdev(dev); out: return ret; } --- linux-2.6.1-rc1/drivers/net/arm/etherh.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/arm/etherh.c 2003-12-30 22:49:19.000000000 -0800 @@ -551,15 +551,12 @@ etherh_probe(struct expansion_card *ec, etherh_banner(); - dev = alloc_etherdev(sizeof(struct etherh_priv)); + dev = alloc_ei_netdev(); if (!dev) { ret = -ENOMEM; goto out; } - /* - * alloc_etherdev allocs and zeros dev->priv - */ eh = dev->priv; spin_lock_init(&eh->eidev.page_lock); @@ -622,21 +619,12 @@ etherh_probe(struct expansion_card *ec, goto free; } - if (ethdev_init(dev)) { - ret = -ENODEV; - goto release; - } - /* * If we're in the NIC slot, make sure the IRQ is enabled */ if (dev->irq == 11) etherh_set_ctrl(eh, ETHERH_CP_IE); - /* - * Unfortunately, ethdev_init eventually calls - * ether_setup, which re-writes dev->flags. - */ switch (ec->cid.product) { case PROD_ANT_ETHERM: dev_type = "ANT EtherM"; @@ -705,7 +693,7 @@ etherh_probe(struct expansion_card *ec, release: release_region(dev->base_addr, 16); free: - kfree(dev); + free_netdev(dev); out: return ret; } --- linux-2.6.1-rc1/drivers/net/at1700.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/at1700.c 2003-12-30 22:49:19.000000000 -0800 @@ -81,12 +81,12 @@ static int fmv18x_probe_list[] __initdat */ #ifndef CONFIG_X86_PC9800 -static int at1700_probe_list[] __initdata = { +static unsigned at1700_probe_list[] __initdata = { 0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; #else /* CONFIG_X86_PC9800 */ -static int at1700_probe_list[] __initdata = { +static unsigned at1700_probe_list[] __initdata = { 0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0 }; @@ -196,8 +196,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int at1700_probe(struct net_device *dev); - static int at1700_probe1(struct net_device *dev, int ioaddr); static int read_eeprom(long ioaddr, int location); static int net_open(struct net_device *dev); @@ -232,24 +230,78 @@ static struct at1720_mca_adapters_struct (detachable devices only). */ -int __init at1700_probe(struct net_device *dev) +#ifndef CONFIG_X86_PC9800 +static int io = 0x260; +#else +static int io = 0xd0; +#endif + +static int irq; + +static void cleanup_card(struct net_device *dev) { - int i; - int base_addr = dev->base_addr; +#ifdef CONFIG_MCA + struct net_local *lp = dev->priv; + if (lp->mca_slot) + mca_mark_as_unused(lp->mca_slot); +#endif + free_irq(dev->irq, NULL); +#ifndef CONFIG_X86_PC9800 + release_region(dev->base_addr, AT1700_IO_EXTENT); +#else + { + int i; + for (i = 0; i < 0x2000; i += 0x200) + release_region(dev->base_addr + i, 2); + } +#endif +} + +struct net_device * __init at1700_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } else { + dev->base_addr = io; + dev->irq = irq; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return at1700_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; at1700_probe_list[i]; i++) { - int ioaddr = at1700_probe_list[i]; - if (at1700_probe1(dev, ioaddr) == 0) - return 0; + if (io > 0x1ff) { /* Check a single specified location. */ + err = at1700_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = at1700_probe_list; *port; port++) { + if (at1700_probe1(dev, *port) == 0) + break; + dev->irq = irq; + } + if (!*port) + err = -ENODEV; } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -267,7 +319,7 @@ static int __init at1700_probe1(struct n char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; - struct net_local *lp; + struct net_local *lp = dev->priv; #ifndef CONFIG_X86_PC9800 if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name)) @@ -284,9 +336,10 @@ static int __init at1700_probe1(struct n } #endif - /* Resetting the chip doesn't reset the ISA interface, so don't bother. - That means we have to be careful with the register values we probe for. - */ + /* Resetting the chip doesn't reset the ISA interface, so don't bother. + That means we have to be careful with the register values we probe + for. + */ #ifdef notdef printk("at1700 probe at %#x, eeprom is %4.4x %4.4x %4.4x ctrl %4.4x.\n", ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5), @@ -331,15 +384,13 @@ static int __init at1700_probe1(struct n break; /* probing for a card at a particular IO/IRQ */ - if (dev && - ((dev->irq && dev->irq != irq) || - (dev->base_addr && dev->base_addr != ioaddr))) { + if ((dev->irq && dev->irq != irq) || + (dev->base_addr && dev->base_addr != ioaddr)) { slot++; /* probing next slot */ continue; } - if (dev) - dev->irq = irq; + dev->irq = irq; /* claim the slot */ mca_set_adapter_name( slot, at1720_mca_adapters[j].name ); @@ -476,13 +527,7 @@ found: if (net_debug) printk(version); - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - ret = -ENOMEM; - goto err_out; - } - memset(dev->priv, 0, sizeof(struct net_local)); + memset(lp, 0, sizeof(struct net_local)); dev->open = net_open; dev->stop = net_close; @@ -492,11 +537,7 @@ found: dev->tx_timeout = net_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - lp = (struct net_local *)dev->priv; - lp->lock = SPIN_LOCK_UNLOCKED; - - /* Fill in the fields of 'dev' with ethernet-generic values. */ - ether_setup(dev); + spin_lock_init(&lp->lock); lp->jumpered = is_fmv18x; lp->mca_slot = slot; @@ -505,14 +546,11 @@ found: if (ret) { printk (" AT1700 at %#3x is unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); - goto err_out_priv; + goto err_out; } return 0; -err_out_priv: - kfree(dev->priv); - dev->priv = NULL; err_out: #ifndef CONFIG_X86_PC9800 release_region(ioaddr, AT1700_IO_EXTENT); @@ -940,14 +978,7 @@ set_rx_mode(struct net_device *dev) } #ifdef MODULE -static struct net_device dev_at1700; -#ifndef CONFIG_X86_PC9800 -static int io = 0x260; -#else -static int io = 0xd0; -#endif - -static int irq; +static struct net_device *dev_at1700; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -960,41 +991,18 @@ int init_module(void) { if (io == 0) printk("at1700: You should not use auto-probing with insmod!\n"); - dev_at1700.base_addr = io; - dev_at1700.irq = irq; - dev_at1700.init = at1700_probe; - if (register_netdev(&dev_at1700) != 0) { - printk("at1700: register_netdev() returned non-zero.\n"); - return -EIO; - } + dev_at1700 = at1700_probe(-1); + if (IS_ERR(dev_at1700)) + return PTR_ERR(dev_at1700); return 0; } void cleanup_module(void) { -#ifdef CONFIG_MCA - struct net_local *lp = dev_at1700.priv; - if(lp->mca_slot) - { - mca_mark_as_unused(lp->mca_slot); - } -#endif - unregister_netdev(&dev_at1700); - kfree(dev_at1700.priv); - dev_at1700.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_at1700.irq, NULL); -#ifndef CONFIG_X86_PC9800 - release_region(dev_at1700.base_addr, AT1700_IO_EXTENT); -#else - { - int i; - for (i = 0; i < 0x2000; i += 0x200) - release_region(dev_at1700.base_addr + i, 2); - } -#endif + unregister_netdev(dev_at1700); + cleanup_card(dev_at1700); + free_netdev(dev_at1700); } #endif /* MODULE */ MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/atari_bionet.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/drivers/net/atari_bionet.c 2003-12-30 22:49:19.000000000 -0800 @@ -148,8 +148,6 @@ unsigned char *phys_nic_packet; /* Index to functions, as function prototypes. */ -extern int bionet_probe(struct net_device *dev); - static int bionet_open(struct net_device *dev); static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev); static void bionet_poll_rx(struct net_device *); @@ -321,15 +319,26 @@ end: /* Check for a network adaptor of this type, and return '0' if one exists. */ -int __init -bionet_probe(struct net_device *dev){ +struct net_device * __init bionet_probe(int unit) +{ + struct net_device *dev; unsigned char station_addr[6]; static unsigned version_printed; static int no_more_found; /* avoid "Probing for..." printed 4 times */ int i; + int err; if (!MACH_IS_ATARI || no_more_found) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); printk("Probing for BioNet 100 Adapter...\n"); @@ -347,11 +356,10 @@ bionet_probe(struct net_device *dev){ || station_addr[2] != 'O' ) { no_more_found = 1; printk( "No BioNet 100 found.\n" ); - return -ENODEV; + free_netdev(dev); + return ERR_PTR(-ENODEV); } - SET_MODULE_OWNER(dev); - if (bionet_debug > 0 && version_printed++ == 0) printk(version); @@ -369,12 +377,6 @@ bionet_probe(struct net_device *dev){ nic_packet, phys_nic_packet ); } - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = bionet_open; dev->stop = bionet_close; dev->hard_start_xmit = bionet_send_packet; @@ -390,8 +392,11 @@ bionet_probe(struct net_device *dev){ #endif dev->dev_addr[i] = station_addr[i]; } - ether_setup(dev); - return 0; + err = register_netdev(dev); + if (!err) + return dev; + free_netdev(dev); + return ERR_PTR(err); } /* Open/initialize the board. This is called (in the current kernel) @@ -640,25 +645,20 @@ static struct net_device_stats *net_get_ #ifdef MODULE -static struct net_device bio_dev; - -int -init_module(void) { - int err; +static struct net_device *bio_dev; - bio_dev.init = bionet_probe; - if ((err = register_netdev(&bio_dev))) { - if (err == -EEXIST) { - printk("BIONET: devices already present. Module not loaded.\n"); - } - return err; - } +int init_module(void) +{ + bio_dev = bionet_probe(-1); + if (IS_ERR(bio_dev)) + return PTR_ERR(bio_dev); return 0; } -void -cleanup_module(void) { - unregister_netdev(&bio_dev); +void cleanup_module(void) +{ + unregister_netdev(bio_dev); + free_netdev(bio_dev); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/atarilance.c 2003-06-14 12:18:03.000000000 -0700 +++ 25/drivers/net/atarilance.c 2003-12-30 22:49:19.000000000 -0800 @@ -371,26 +371,39 @@ static void *slow_memcpy( void *dst, con } -int __init atarilance_probe( struct net_device *dev ) -{ +struct net_device * __init atarilance_probe(int unit) +{ int i; static int found; - - SET_MODULE_OWNER(dev); + struct net_device *dev; + int err = -ENODEV; if (!MACH_IS_ATARI || found) /* Assume there's only one board possible... That seems true, since * the Riebl/PAM board's address cannot be changed. */ - return( ENODEV ); + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { found = 1; - return( 0 ); + err = register_netdev(dev); + if (!err) + return dev; + free_irq(dev->irq, dev); + break; } } - - return( ENODEV ); + free_netdev(dev); + return ERR_PTR(err); } @@ -511,12 +524,6 @@ static unsigned long __init lance_probe1 return( 0 ); probe_ok: - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; @@ -1171,26 +1178,21 @@ static int lance_set_mac_address( struct #ifdef MODULE -static struct net_device atarilance_dev; +static struct net_device *atarilance_dev; int init_module(void) - -{ int err; - - atarilance_dev.init = atarilance_probe; - if ((err = register_netdev( &atarilance_dev ))) { - if (err == -EIO) { - printk( "No Atari Lance board found. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); +{ + atarilance_dev = atarilance_probe(-1); + if (IS_ERR(atarilance_dev)) + return PTR_ERR(atarilance_dev); + return 0; } void cleanup_module(void) - { - unregister_netdev( &atarilance_dev ); + unregister_netdev(atarilance_dev); + free_irq(atarilance_dev->irq, atarilance_dev); + free_netdev(atarilance_dev); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/atari_pamsnet.c 2003-07-27 12:14:39.000000000 -0700 +++ 25/drivers/net/atari_pamsnet.c 2003-12-30 22:49:19.000000000 -0800 @@ -110,8 +110,6 @@ static char *version = #undef READ #undef WRITE -extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private); - /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG @@ -158,8 +156,6 @@ static int send_1_5 (int lun, unsigned c static int get_status (void); static int calc_received (void *start_address); -extern int pamsnet_probe(struct net_device *dev); - static int pamsnet_open(struct net_device *dev); static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev); static void pamsnet_poll_rx(struct net_device *); @@ -562,12 +558,12 @@ bad: /* Check for a network adaptor of this type, and return '0' if one exists. */ -int __init -pamsnet_probe (dev) - struct net_device *dev; +struct net_device * __init pamsnet_probe (int unit) { + struct net_device *dev; int i; HADDR *hwaddr; + int err; unsigned char station_addr[6]; static unsigned version_printed; @@ -575,12 +571,18 @@ pamsnet_probe (dev) static int no_more_found; if (no_more_found) - return -ENODEV; + return ERR_PTR(-ENODEV); + no_more_found = 1; + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - no_more_found = 1; - printk("Probing for PAM's Net/GK Adapter...\n"); /* Allocate the DMA buffer here since we need it for probing! */ @@ -618,11 +620,12 @@ pamsnet_probe (dev) ENABLE_IRQ(); stdma_release(); - if (lance_target < 0) + if (lance_target < 0) { printk("No PAM's Net/GK found.\n"); + free_netdev(dev); + return ERR_PTR(-ENODEV); + } - if ((dev == NULL) || (lance_target < 0)) - return -ENODEV; if (pamsnet_debug > 0 && version_printed++ == 0) printk(version); @@ -632,12 +635,6 @@ pamsnet_probe (dev) station_addr[3], station_addr[4], station_addr[5]); /* Initialize the device structure. */ - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = pamsnet_open; dev->stop = pamsnet_close; dev->hard_start_xmit = pamsnet_send_packet; @@ -653,9 +650,12 @@ pamsnet_probe (dev) #endif dev->dev_addr[i] = station_addr[i]; } - ether_setup(dev); + err = register_netdev(dev); + if (!err) + return dev; - return(0); + free_netdev(dev); + return ERR_PTR(err); } /* Open/initialize the board. This is called (in the current kernel) @@ -866,25 +866,20 @@ static struct net_device_stats *net_get_ #ifdef MODULE -static struct net_device pam_dev; - -int -init_module(void) { - int err; +static struct net_device *pam_dev; - pam_dev.init = pamsnet_probe; - if ((err = register_netdev(&pam_dev))) { - if (err == -EEXIST) { - printk("PAM's Net/GK: devices already present. Module not loaded.\n"); - } - return err; - } +int init_module(void) +{ + pam_dev = pamsnet_probe(-1); + if (IS_ERR(pam_dev)) + return PTR_ERR(pam_dev); return 0; } -void -cleanup_module(void) { - unregister_netdev(&pam_dev); +void cleanup_module(void) +{ + unregister_netdev(pam_dev); + free_netdev(pam_dev); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/atp.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/atp.c 2003-12-30 22:49:19.000000000 -0800 @@ -195,7 +195,7 @@ static void atp_timed_checker(unsigned l /* Index to functions, as function prototypes. */ -static int atp_probe1(struct net_device *dev, long ioaddr); +static int atp_probe1(long ioaddr); static void get_node_ID(struct net_device *dev); static unsigned short eeprom_op(long ioaddr, unsigned int cmd); static int net_open(struct net_device *dev); @@ -224,13 +224,13 @@ static struct net_device *root_atp_dev; FIXME: we should use the parport layer for this */ -static int __init atp_init(struct net_device *dev) +static int __init atp_init(void) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; - int base_addr = dev ? dev->base_addr : io[0]; + int base_addr = io[0]; if (base_addr > 0x1ff) /* Check a single specified location. */ - return atp_probe1(dev, base_addr); + return atp_probe1(base_addr); else if (base_addr == 1) /* Don't probe at all. */ return -ENXIO; @@ -239,17 +239,19 @@ static int __init atp_init(struct net_de outb(0x57, ioaddr + PAR_DATA); if (inb(ioaddr + PAR_DATA) != 0x57) continue; - if (atp_probe1(dev, ioaddr) == 0) + if (atp_probe1(ioaddr) == 0) return 0; } return -ENODEV; } -static int __init atp_probe1(struct net_device *dev, long ioaddr) +static int __init atp_probe1(long ioaddr) { + struct net_device *dev = NULL; struct net_local *lp; int saved_ctrl_reg, status, i; + int res; outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -296,7 +298,7 @@ static int __init atp_probe1(struct net_ return -ENODEV; } - dev = init_etherdev(dev, sizeof(struct net_local)); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); @@ -331,24 +333,13 @@ static int __init atp_probe1(struct net_ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Reset the ethernet hardware and activate the printer pass-through. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); - - /* Initialize the device structure. */ - ether_setup(dev); - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); lp = (struct net_local *)dev->priv; lp->chip_type = RTL8002; lp->addr_mode = CMR2h_Normal; spin_lock_init(&lp->lock); - lp->next_module = root_atp_dev; - root_atp_dev = dev; - /* For the ATP adapter the "if_port" is really the data transfer mode. */ if (xcvr[0]) dev->if_port = xcvr[0]; @@ -366,6 +357,15 @@ static int __init atp_probe1(struct net_ dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + res = register_netdev(dev); + if (res) { + free_netdev(dev); + return res; + } + + lp->next_module = root_atp_dev; + root_atp_dev = dev; + return 0; } @@ -933,7 +933,7 @@ static void set_rx_mode_8012(struct net_ static int __init atp_init_module(void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - return atp_init(NULL); + return atp_init(); } static void __exit atp_cleanup_module(void) { --- linux-2.6.1-rc1/drivers/net/au1000_eth.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/au1000_eth.c 2003-12-30 22:49:19.000000000 -0800 @@ -56,7 +56,7 @@ static void *dma_alloc(size_t, dma_addr_ static void dma_free(void *, size_t); static void hard_stop(struct net_device *); static void enable_rx_tx(struct net_device *dev); -static int __init au1000_probe1(struct net_device *, long, int, int); +static int __init au1000_probe1(long, int, int); static int au1000_init(struct net_device *); static int au1000_open(struct net_device *); static int au1000_close(struct net_device *); @@ -644,17 +644,17 @@ static int __init au1000_init_module(voi } // check for valid entries, au1100 only has one entry if (base_addr && irq) { - if (au1000_probe1(NULL, base_addr, irq, i) != 0) { + if (au1000_probe1(base_addr, irq, i) != 0) return -ENODEV; - } } } return 0; } static int __init -au1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +au1000_probe1(long ioaddr, int irq, int port_num) { + struct net_device *dev; static unsigned version_printed = 0; struct au1000_private *aup = NULL; int i, retval = 0; @@ -668,15 +668,16 @@ au1000_probe1(struct net_device *dev, lo if (version_printed++ == 0) printk(version); - if (!dev) - dev = init_etherdev(NULL, sizeof(struct au1000_private)); + retval = -ENOMEM; + dev = alloc_etherdev(sizeof(struct au1000_private)); if (!dev) { - printk (KERN_ERR "au1000 eth: init_etherdev failed\n"); - release_region(ioaddr, MAC_IOSIZE); - return -ENODEV; + printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n"); + goto out; } + SET_MODULE_OWNER(dev); + printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", dev->name, ioaddr, irq); @@ -685,10 +686,8 @@ au1000_probe1(struct net_device *dev, lo /* Allocate the data buffers */ aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); - if (!aup->vaddr) { - retval = -ENOMEM; - goto free_region; - } + if (!aup->vaddr) + goto out1; /* aup->mac is the base address of the MAC's registers */ aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr); @@ -749,10 +748,11 @@ au1000_probe1(struct net_device *dev, lo MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; au_sync_delay(2); - if (mii_probe(dev) != 0) { - goto free_region; - } + retval = mii_probe(dev); + if (retval) + goto out2; + retval = -EINVAL; pDBfree = NULL; /* setup the data buffer descriptors and attach a buffer to each one */ pDB = aup->db; @@ -767,13 +767,13 @@ au1000_probe1(struct net_device *dev, lo for (i=0; irx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->rx_db_inuse[i] = pDB; } for (i=0; itx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->tx_dma_ring[i]->len = 0; aup->tx_db_inuse[i] = pDB; @@ -792,26 +792,25 @@ au1000_probe1(struct net_device *dev, lo dev->tx_timeout = au1000_tx_timeout; dev->watchdog_timeo = ETH_TX_TIMEOUT; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - /* * The boot code uses the ethernet controller, so reset it to start * fresh. au1000_init() expects that the device is in reset state. */ reset_mac(dev); + + retval = register_netdev(dev); + if (retval) + goto out2; return 0; -free_region: +out2: + dma_free(aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); +out1: + free_netdev(dev); +out: release_region(PHYSADDR(ioaddr), MAC_IOSIZE); - unregister_netdev(dev); - if (aup->vaddr) - dma_free((void *)aup->vaddr, - MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); printk(KERN_ERR "%s: au1000_probe1 failed. Returns %d\n", dev->name, retval); - free_netdev(dev); return retval; } @@ -933,15 +932,12 @@ static int au1000_open(struct net_device int retval; struct au1000_private *aup = (struct au1000_private *) dev->priv; - MOD_INC_USE_COUNT; - if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); if ((retval = au1000_init(dev))) { printk(KERN_ERR "%s: error in au1000_init\n", dev->name); free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return retval; } netif_start_queue(dev); @@ -950,7 +946,6 @@ static int au1000_open(struct net_device dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; return retval; } @@ -984,8 +979,6 @@ static int au1000_close(struct net_devic spin_unlock_irqrestore(&aup->lock, flags); reset_mac(dev); - kfree(dev); - MOD_DEC_USE_COUNT; return 0; } --- linux-2.6.1-rc1/drivers/net/bagetlance.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/drivers/net/bagetlance.c 2003-12-30 22:49:19.000000000 -0800 @@ -465,30 +465,43 @@ void *slow_memcpy( void *dst, const void } -int __init bagetlance_probe( struct net_device *dev ) - -{ int i; +struct net_device * __init bagetlance_probe(int unit) +{ + struct net_device *dev; + int i; static int found; - - SET_MODULE_OWNER(dev); + int err = -ENODEV; if (found) /* Assume there's only one board possible... That seems true, since * the Riebl/PAM board's address cannot be changed. */ - return( -ENODEV ); + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { found = 1; - return( 0 ); + break; } } - - return( -ENODEV ); + if (!found) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); } - - /* Derived from hwreg_present() in vme/config.c: */ static int __init addr_accessible( volatile void *regp, @@ -527,6 +540,7 @@ static int __init lance_probe1( struct n if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail; if ((unsigned long)memaddr >= KSEG2) { + /* FIXME: do we need to undo that on cleanup paths? */ extern int kseg2_alloc_io (unsigned long addr, unsigned long size); if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) { printk("bagetlance: unable map lance memory\n"); @@ -580,12 +594,6 @@ static int __init lance_probe1( struct n return( 0 ); probe_ok: - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; @@ -617,8 +625,9 @@ static int __init lance_probe1( struct n if (lp->cardtype == PAM_CARD || memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ - request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev); + if (request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, + "PAM/Riebl-ST Ethernet", dev)) + goto probe_fail; dev->irq = (unsigned short)BAGET_LANCE_IRQ; } else { @@ -629,10 +638,11 @@ static int __init lance_probe1( struct n unsigned long irq = BAGET_LANCE_IRQ; if (!irq) { printk( "Lance: request for VME interrupt failed\n" ); - return( 0 ); + goto probe_fail; } - request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, - "Riebl-VME Ethernet", dev); + if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, + "Riebl-VME Ethernet", dev)) + goto probe_fail; dev->irq = irq; } @@ -1331,26 +1341,21 @@ static int lance_set_mac_address( struct #ifdef MODULE -static struct net_device bagetlance_dev; +static struct net_device *bagetlance_dev; int init_module(void) - -{ int err; - - bagetlance_dev.init = bagetlance_probe; - if ((err = register_netdev( &bagetlance_dev ))) { - if (err == -EIO) { - printk( "No Vme Lance board found. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); +{ + bagetlance_dev = bagetlance_probe(-1); + if (IS_ERR(bagetlance_dev)) + return PTR_ERR(bagetlance_dev); + return 0; } void cleanup_module(void) - { - unregister_netdev( &bagetlance_dev ); + unregister_netdev(bagetlance_dev); + free_irq(bagetlance_dev->irq, bagetlance_dev); + free_netdev(bagetlance_dev); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/bonding/bond_3ad.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/bonding/bond_3ad.c 2003-12-30 22:49:19.000000000 -0800 @@ -47,8 +47,13 @@ * - Send LACPDU as highest priority packet to further fix the above * problem on very high Tx traffic load where packets may get dropped * by the slave. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -119,6 +124,7 @@ static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; static u16 ad_ticks_per_sec; +static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; // ================= 3AD api to bonding and kernel code ================== static u16 __get_link_speed(struct port *port); @@ -196,13 +202,11 @@ static inline struct bonding *__get_bond */ static inline struct port *__get_first_port(struct bonding *bond) { - struct slave *slave = bond->next; - - if (slave == (struct slave *)bond) { + if (bond->slave_cnt == 0) { return NULL; } - return &(SLAVE_AD_INFO(slave).port); + return &(SLAVE_AD_INFO(bond->first_slave).port); } /** @@ -218,7 +222,7 @@ static inline struct port *__get_next_po struct slave *slave = port->slave; // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -236,12 +240,12 @@ static inline struct aggregator *__get_f { struct bonding *bond = __get_bond_by_port(port); - // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (bond->next == (struct slave *)bond)) { + // If there's no bond for this port, or bond has no slaves + if ((bond == NULL) || (bond->slave_cnt == 0)) { return NULL; } - return &(SLAVE_AD_INFO(bond->next).aggregator); + return &(SLAVE_AD_INFO(bond->first_slave).aggregator); } /** @@ -257,7 +261,7 @@ static inline struct aggregator *__get_n struct bonding *bond = bond_get_bond_by_slave(slave); // If there's no bond for this aggregator, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -392,7 +396,7 @@ static u16 __get_link_speed(struct port } } - BOND_PRINT_DBG(("Port %d Received link speed %d update from adapter", port->actor_port_number, speed)); + dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); return speed; } @@ -418,12 +422,12 @@ static u8 __get_duplex(struct port *port switch (slave->duplex) { case DUPLEX_FULL: retval=0x1; - BOND_PRINT_DBG(("Port %d Received status full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: retval=0x0; - BOND_PRINT_DBG(("Port %d Received status NOT full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; } } @@ -1059,7 +1063,7 @@ static void ad_mux_machine(struct port * // check if the state machine was changed if (port->sm_mux_state != last_state) { - BOND_PRINT_DBG(("Mux Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_mux_state)); + dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: __detach_bond_from_agg(port); @@ -1158,7 +1162,7 @@ static void ad_rx_machine(struct lacpdu // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { - BOND_PRINT_DBG(("Rx Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_rx_state)); + dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { @@ -1204,7 +1208,7 @@ static void ad_rx_machine(struct lacpdu // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES - printk(KERN_ERR "bonding: An illegal loopback occurred on adapter (%s)\n", + printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n", port->slave->dev->name); printk(KERN_ERR "Check the configuration to verify that all Adapters " "are connected to 802.3ad compliant switch ports\n"); @@ -1245,7 +1249,7 @@ static void ad_tx_machine(struct port *p __update_lacpdu_from_port(port); // send the lacpdu if (ad_lacpdu_send(port) >= 0) { - BOND_PRINT_DBG(("Sent LACPDU on port %d", port->actor_port_number)); + dprintk("Sent LACPDU on port %d\n", port->actor_port_number); // mark ntt as false, so it will not be sent again until demanded port->ntt = 0; } @@ -1318,7 +1322,7 @@ static void ad_periodic_machine(struct p // check if the state machine was changed if (port->sm_periodic_state != last_state) { - BOND_PRINT_DBG(("Periodic Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_periodic_state)); + dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer @@ -1375,7 +1379,7 @@ static void ad_port_selection_logic(stru port->next_port_in_aggregator=NULL; port->actor_port_aggregator_identifier=0; - BOND_PRINT_DBG(("Port %d left LAG %d", port->actor_port_number, temp_aggregator->aggregator_identifier)); + dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached if (!temp_aggregator->lag_ports) { ad_clear_agg(temp_aggregator); @@ -1384,7 +1388,7 @@ static void ad_port_selection_logic(stru } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - printk(KERN_WARNING "bonding: Warning: Port %d (on %s) was " + printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was " "related to aggregator %d but was not on its port list\n", port->actor_port_number, port->slave->dev->name, port->aggregator->aggregator_identifier); @@ -1417,7 +1421,7 @@ static void ad_port_selection_logic(stru port->next_port_in_aggregator=aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports=port; - BOND_PRINT_DBG(("Port %d joined LAG %d(existing LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; @@ -1454,9 +1458,9 @@ static void ad_port_selection_logic(stru // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; - BOND_PRINT_DBG(("Port %d joined LAG %d(new LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { - printk(KERN_ERR "bonding: Port %d (on %s) did not find a suitable aggregator\n", + printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n", port->actor_port_number, port->slave->dev->name); } } @@ -1580,30 +1584,30 @@ static void ad_agg_selection_logic(struc aggregator; aggregator = __get_next_agg(aggregator)) { - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", aggregator->aggregator_identifier, aggregator->num_of_ports, aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, - aggregator->is_individual, aggregator->is_active)); + aggregator->is_individual, aggregator->is_active); } // check if any partner replys if (best_aggregator->is_individual) { - printk(KERN_WARNING "bonding: Warning: No 802.3ad response from the link partner " + printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner " "for any adapters in the bond\n"); } // check if there are more than one aggregator if (num_of_aggs > 1) { - BOND_PRINT_DBG(("Warning: More than one Link Aggregation Group was " - "found in the bond. Only one group will function in the bond")); + dprintk("Warning: More than one Link Aggregation Group was " + "found in the bond. Only one group will function in the bond\n"); } best_aggregator->is_active = 1; - BOND_PRINT_DBG(("LAG %d choosed as the active LAG", best_aggregator->aggregator_identifier)); - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, - best_aggregator->is_individual, best_aggregator->is_active)); + best_aggregator->is_individual, best_aggregator->is_active); // disable the ports that were related to the former active_aggregator if (last_active_aggregator) { @@ -1644,7 +1648,7 @@ static void ad_clear_agg(struct aggregat aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; - BOND_PRINT_DBG(("LAG %d was cleared", aggregator->aggregator_identifier)); + dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); } } @@ -1729,7 +1733,7 @@ static void ad_initialize_port(struct po static void ad_enable_collecting_distributing(struct port *port) { if (port->aggregator->is_active) { - BOND_PRINT_DBG(("Enabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); } } @@ -1742,7 +1746,7 @@ static void ad_enable_collecting_distrib static void ad_disable_collecting_distributing(struct port *port) { if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { - BOND_PRINT_DBG(("Disabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); } } @@ -1780,7 +1784,7 @@ static void ad_marker_info_send(struct p // send the marker information if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Information on port %d", port->actor_port_number)); + dprintk("Sent Marker Information on port %d\n", port->actor_port_number); } } #endif @@ -1803,7 +1807,7 @@ static void ad_marker_info_received(stru // send the marker response if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Response on port %d", port->actor_port_number)); + dprintk("Sent Marker Response on port %d\n", port->actor_port_number); } } @@ -1890,13 +1894,13 @@ static u16 aggregator_identifier; void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast) { // check that the bond is not initialized yet - if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->device->dev_addr))) { + if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) { aggregator_identifier = 0; BOND_AD_INFO(bond).lacp_fast = lacp_fast; BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; - BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->device->dev_addr); + BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); // initialize how many times this module is called in one second(should be about every 100ms) ad_ticks_per_sec = tick_resolution; @@ -1921,7 +1925,7 @@ int bond_3ad_bind_slave(struct slave *sl struct aggregator *aggregator; if (bond == NULL) { - printk(KERN_CRIT "The slave %s is not attached to its bond\n", slave->dev->name); + printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name); return -1; } @@ -1964,7 +1968,7 @@ int bond_3ad_bind_slave(struct slave *sl ad_initialize_agg(aggregator); - aggregator->aggregator_mac_address = *((struct mac_addr *)bond->device->dev_addr); + aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr); aggregator->aggregator_identifier = (++aggregator_identifier); aggregator->slave = slave; aggregator->is_active = 0; @@ -1996,11 +2000,11 @@ void bond_3ad_unbind_slave(struct slave // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Trying to unbind an uninitialized port on %s\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name); return; } - BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier)); + dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -2024,10 +2028,10 @@ void bond_3ad_unbind_slave(struct slave // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - BOND_PRINT_DBG(("Some port(s) related to LAG %d - replaceing with LAG %d", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier)); + dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - printk(KERN_INFO "bonding: Removing an active aggregator\n"); + printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n"); // select new active aggregator select_new_active_agg = 1; } @@ -2057,7 +2061,7 @@ void bond_3ad_unbind_slave(struct slave ad_agg_selection_logic(__get_first_agg(port)); } } else { - printk(KERN_WARNING "bonding: Warning: unbinding aggregator, " + printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, " "and could not find a new aggregator for its ports\n"); } } else { // in case that the only port related to this aggregator is the one we want to remove @@ -2072,7 +2076,7 @@ void bond_3ad_unbind_slave(struct slave } } - BOND_PRINT_DBG(("Unbinding port %d", port->actor_port_number)); + dprintk("Unbinding port %d\n", port->actor_port_number); // find the aggregator that this port is connected to temp_aggregator = __get_first_agg(port); for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { @@ -2123,13 +2127,13 @@ void bond_3ad_state_machine_handler(stru read_lock(&bond->lock); - //check if there are any slaves - if (bond->next == (struct slave *)bond) { - goto end; + if (bond->kill_timers) { + goto out; } - if ((bond->device->flags & IFF_UP) != IFF_UP) { - goto end; + //check if there are any slaves + if (bond->slave_cnt == 0) { + goto re_arm; } // check if agg_select_timer timer after initialize is timed out @@ -2137,8 +2141,8 @@ void bond_3ad_state_machine_handler(stru // select the active aggregator for the bond if ((port = __get_first_port(bond))) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: bond's first port is uninitialized\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n"); + goto re_arm; } aggregator = __get_first_agg(port); @@ -2149,8 +2153,8 @@ void bond_3ad_state_machine_handler(stru // for each port run the state machines for (port = __get_first_port(bond); port; port = __get_next_port(port)) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: Found an uninitialized port\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n"); + goto re_arm; } ad_rx_machine(NULL, port); @@ -2165,14 +2169,10 @@ void bond_3ad_state_machine_handler(stru } } -end: +re_arm: + mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks); +out: read_unlock(&bond->lock); - - - if ((bond->device->flags & IFF_UP) == IFF_UP) { - /* re-arm the timer */ - mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + (AD_TIMER_INTERVAL * HZ / 1000)); - } } /** @@ -2194,14 +2194,14 @@ void bond_3ad_rx_indication(struct lacpd port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: port of slave %s is uninitialized\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name); return; } switch (lacpdu->subtype) { case AD_TYPE_LACPDU: __ntohs_lacpdu(lacpdu); - BOND_PRINT_DBG(("Received LACPDU on port %d", port->actor_port_number)); + dprintk("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; @@ -2210,17 +2210,17 @@ void bond_3ad_rx_indication(struct lacpd switch (((struct marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Information on port %d", port->actor_port_number)); + dprintk("Received Marker Information on port %d\n", port->actor_port_number); ad_marker_info_received((struct marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Response on port %d", port->actor_port_number)); + dprintk("Received Marker Response on port %d\n", port->actor_port_number); ad_marker_response_received((struct marker *)lacpdu, port); break; default: - BOND_PRINT_DBG(("Received an unknown Marker subtype on slot %d", port->actor_port_number)); + dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); } } } @@ -2240,14 +2240,14 @@ void bond_3ad_adapter_speed_changed(stru // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: speed changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); - BOND_PRINT_DBG(("Port %d changed speed", port->actor_port_number)); + dprintk("Port %d changed speed\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2267,14 +2267,14 @@ void bond_3ad_adapter_duplex_changed(str // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: duplex changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); - BOND_PRINT_DBG(("Port %d changed duplex", port->actor_port_number)); + dprintk("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2295,10 +2295,8 @@ void bond_3ad_handle_link_change(struct // if slave is null, the whole port is not initialized if (!port->slave) { -#ifdef BONDING_DEBUG - printk(KERN_WARNING "bonding: Warning: link status changed for uninitialized port on %s\n", - slave->dev->name); -#endif + printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2356,41 +2354,27 @@ int bond_3ad_get_active_agg_info(struct int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct slave *slave, *start_at; + struct bonding *bond = dev->priv; struct ethhdr *data = (struct ethhdr *)skb->data; int slave_agg_no; int slaves_in_agg; int agg_id; + int i; struct ad_info ad_info; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - if (bond == NULL) { - printk(KERN_CRIT "bonding: Error: bond is NULL on device %s\n", dev->name); - dev_kfree_skb(skb); - return 0; - } - + /* make sure that the slaves list will + * not change during tx + */ read_lock(&bond->lock); - slave = bond->prev; - /* check if bond is empty */ - if ((slave == (struct slave *) bond) || (bond->slave_cnt == 0)) { - printk(KERN_DEBUG "ERROR: bond is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto free_out; } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto free_out; } slaves_in_agg = ad_info.ports; @@ -2399,21 +2383,12 @@ int bond_3ad_xmit_xor(struct sk_buff *sk if (slaves_in_agg == 0) { /*the aggregator is empty*/ printk(KERN_DEBUG "ERROR: active aggregator is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto free_out; } - /* we're at the root, get the first slave */ - if ((slave == NULL) || (slave->dev == NULL)) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } + slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg; - slave_agg_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % slaves_in_agg; - while (slave != (slave_t *)bond) { + bond_for_each_slave(bond, slave, i) { struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg && (agg->aggregator_identifier == agg_id)) { @@ -2422,37 +2397,18 @@ int bond_3ad_xmit_xor(struct sk_buff *sk break; } } - - slave = slave->prev; - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } } - if (slave == (slave_t *)bond) { - printk(KERN_ERR "bonding: Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (slave_agg_no >= 0) { + printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); + goto free_out; } start_at = slave; - do { + bond_for_each_slave_from(bond, slave, i, start_at) { int slave_agg_id = 0; - struct aggregator *agg; - - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - agg = SLAVE_AD_INFO(slave).port.aggregator; + struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg) { slave_agg_id = agg->aggregator_identifier; @@ -2463,20 +2419,24 @@ int bond_3ad_xmit_xor(struct sk_buff *sk skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; + + goto out; } - } while ((slave = slave->next) != start_at); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); +out: read_unlock(&bond->lock); return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype) { - struct bonding *bond = (struct bonding *)dev->priv; + struct bonding *bond = dev->priv; struct slave *slave = NULL; int ret = NET_RX_DROP; --- linux-2.6.1-rc1/drivers/net/bonding/bond_3ad.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/bonding/bond_3ad.h 2003-12-30 22:49:19.000000000 -0800 @@ -28,6 +28,9 @@ * 2003/05/01 - Shmulik Hen * - Renamed bond_3ad_link_status_changed() to * bond_3ad_handle_link_change() for compatibility with TLB. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_3AD_H__ --- linux-2.6.1-rc1/drivers/net/bonding/bond_alb.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/bonding/bond_alb.c 2003-12-30 22:49:19.000000000 -0800 @@ -28,8 +28,13 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -50,11 +55,11 @@ #define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */ -#define BOND_TLB_REBALANCE_INTERVAL 10 /* in seconds, periodic re-balancing - * used for division - never set +#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing. + * Used for division - never set * to zero !!! */ -#define BOND_ALB_LP_INTERVAL 1 /* in seconds periodic send of +#define BOND_ALB_LP_INTERVAL 1 /* In seconds, periodic send of * learning packets to the switch */ @@ -66,7 +71,7 @@ #define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table. * Note that this value MUST NOT be smaller - * because the key hash table BYTE wide ! + * because the key hash table is BYTE wide ! */ @@ -86,12 +91,15 @@ */ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC +static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; + #pragma pack(1) struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; u16 type; - u8 padding[ETH_ZLEN - (2*ETH_ALEN + 2)]; + u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { @@ -110,13 +118,12 @@ struct arp_pkt { /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); -static inline u8 -_simple_hash(u8 *hash_start, int hash_size) +static inline u8 _simple_hash(u8 *hash_start, int hash_size) { int i; u8 hash = 0; - for (i=0; iload_history = 1 + entry->tx_bytes / - BOND_TLB_REBALANCE_INTERVAL; + BOND_TLB_REBALANCE_INTERVAL; entry->tx_bytes = 0; } + entry->tx_slave = NULL; entry->next = TLB_NULL_INDEX; entry->prev = TLB_NULL_INDEX; } -static inline void -tlb_init_slave(struct slave *slave) +static inline void tlb_init_slave(struct slave *slave) { - struct tlb_slave_info *slave_info = &(SLAVE_TLB_INFO(slave)); - - slave_info->load = 0; - slave_info->head = TLB_NULL_INDEX; + SLAVE_TLB_INFO(slave).load = 0; + SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX; } /* Caller must hold bond lock for read */ -static inline void -tlb_clear_slave(struct bonding *bond, struct slave *slave, u8 save_load) +static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) { - struct tlb_client_info *tx_hash_table = NULL; - u32 index, next_index; + struct tlb_client_info *tx_hash_table; + u32 index; - /* clear slave from tx_hashtbl */ _lock_tx_hashtbl(bond); + + /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - if (tx_hash_table) { - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - next_index = tx_hash_table[index].next; - tlb_init_table_entry(bond, index, save_load); - index = next_index; - } + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; } + _unlock_tx_hashtbl(bond); tlb_init_slave(slave); } /* Must be called before starting the monitor timer */ -static int -tlb_initialize(struct bonding *bond) +static int tlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); int i; - size_t size; - -#if(TLB_HASH_TABLE_SIZE != 256) - /* Key to the hash table is byte wide. Check the size! */ - #error Hash Table size is wrong. -#endif spin_lock_init(&(bond_info->tx_hashtbl_lock)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl != NULL) { - printk (KERN_ERR "%s: TLB hash table is not NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return -1; - } - size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->tx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate TLB hash table\n", - bond->device->name); + if (!bond_info->tx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate TLB hash table\n", + bond->dev->name); _unlock_tx_hashtbl(bond); return -1; } memset(bond_info->tx_hashtbl, 0, size); - for (i=0; itx_hashtbl[i], 1); } + _unlock_tx_hashtbl(bond); return 0; } /* Must be called only after all slaves have been released */ -static void -tlb_deinitialize(struct bonding *bond) +static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl == NULL) { - _unlock_tx_hashtbl(bond); - return; - } + kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; + _unlock_tx_hashtbl(bond); } /* Caller must hold bond lock for read */ -static struct slave* -tlb_get_least_loaded_slave(struct bonding *bond) +static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) { - struct slave *slave; - struct slave *least_loaded; - s64 curr_gap, max_gap; + struct slave *slave, *least_loaded; + s64 max_gap; + int i, found = 0; /* Find the first enabled slave */ - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { if (SLAVE_IS_OK(slave)) { + found = 1; break; } - slave = bond_get_next_slave(bond, slave); } - if (!slave) { + if (!found) { return NULL; } least_loaded = slave; - max_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); + max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */ + (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ /* Find the slave with the largest gap */ - slave = bond_get_next_slave(bond, slave); - while (slave) { + bond_for_each_slave_from(bond, slave, i, least_loaded) { if (SLAVE_IS_OK(slave)) { - curr_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); - if (max_gap < curr_gap) { + s64 gap = (s64)(slave->speed << 20) - + (s64)(SLAVE_TLB_INFO(slave).load << 3); + if (max_gap < gap) { least_loaded = slave; - max_gap = curr_gap; + max_gap = gap; } } - slave = bond_get_next_slave(bond, slave); } return least_loaded; } /* Caller must hold bond lock for read */ -struct slave* -tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) +struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct tlb_client_info *hash_table = NULL; - struct slave *assigned_slave = NULL; + struct tlb_client_info *hash_table; + struct slave *assigned_slave; _lock_tx_hashtbl(bond); hash_table = bond_info->tx_hashtbl; - if (hash_table == NULL) { - printk (KERN_ERR "%s: TLB hash table is NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return NULL; - } - assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { assigned_slave = tlb_get_least_loaded_slave(bond); @@ -345,14 +310,12 @@ tlb_choose_channel(struct bonding *bond, } /*********************** rlb specific functions ***************************/ -static inline void -_lock_rx_hashtbl(struct bonding *bond) +static inline void _lock_rx_hashtbl(struct bonding *bond) { spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } -static inline void -_unlock_rx_hashtbl(struct bonding *bond) +static inline void _unlock_rx_hashtbl(struct bonding *bond) { spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } @@ -360,26 +323,20 @@ _unlock_rx_hashtbl(struct bonding *bond) /* when an ARP REPLY is received from a client update its info * in the rx_hashtbl */ -static void -rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) +static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = _simple_hash((u8*)&(arp->ip_src), 4); + hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && (client_info->ip_dst == arp->ip_src)) { - /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; @@ -389,66 +346,60 @@ rlb_update_entry_from_arp(struct bonding _unlock_rx_hashtbl(bond); } -static int -rlb_arp_recv(struct sk_buff *skb, - struct net_device *dev, - struct packet_type* ptype) +static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype) { - struct bonding *bond = (struct bonding *)dev->priv; - int ret = NET_RX_DROP; + struct bonding *bond = bond_dev->priv; struct arp_pkt *arp = (struct arp_pkt *)skb->data; + int res = NET_RX_DROP; - if (!(dev->flags & IFF_MASTER)) { + if (!(bond_dev->flags & IFF_MASTER)) { goto out; } if (!arp) { - printk(KERN_ERR "Packet has no ARP data\n"); + dprintk("Packet has no ARP data\n"); goto out; } if (skb->len < sizeof(struct arp_pkt)) { - printk(KERN_ERR "Packet is too small to be an ARP\n"); + dprintk("Packet is too small to be an ARP\n"); goto out; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ rlb_update_entry_from_arp(bond, arp); - BOND_PRINT_DBG(("Server received an ARP Reply from client")); + dprintk("Server received an ARP Reply from client\n"); } - ret = NET_RX_SUCCESS; + res = NET_RX_SUCCESS; out: dev_kfree_skb(skb); - return ret; + return res; } /* Caller must hold bond lock for read */ -static struct slave* -rlb_next_rx_slave(struct bonding *bond) +static struct slave *rlb_next_rx_slave(struct bonding *bond) { - struct slave *rx_slave = NULL, *slave = NULL; - unsigned int i = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct slave *rx_slave, *slave, *start_at; + int i = 0; - slave = bond_info->next_rx_slave; - if (slave == NULL) { - slave = bond->next; + if (bond_info->next_rx_slave) { + start_at = bond_info->next_rx_slave; + } else { + start_at = bond->first_slave; } - /* this loop uses the circular linked list property of the - * slave's list to go through all slaves - */ - for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) { + rx_slave = NULL; + bond_for_each_slave_from(bond, slave, i, start_at) { if (SLAVE_IS_OK(slave)) { if (!rx_slave) { rx_slave = slave; - } - else if (slave->speed > rx_slave->speed) { + } else if (slave->speed > rx_slave->speed) { rx_slave = slave; } } @@ -464,48 +415,41 @@ rlb_next_rx_slave(struct bonding *bond) /* teach the switch the mac of a disabled slave * on the primary for fault tolerance * - * Caller must hold bond->ptrlock for write or bond lock for write + * Caller must hold bond->curr_slave_lock for write or bond lock for write */ -static void -rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) +static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { - if (!bond->current_slave) { + if (!bond->curr_active_slave) { return; } + if (!bond->alb_info.primary_is_promisc) { bond->alb_info.primary_is_promisc = 1; - dev_set_promiscuity(bond->current_slave->dev, 1); + dev_set_promiscuity(bond->curr_active_slave->dev, 1); } + bond->alb_info.rlb_promisc_timeout_counter = 0; - alb_send_learning_packets(bond->current_slave, addr); + alb_send_learning_packets(bond->curr_active_slave, addr); } /* slave being removed should not be active at this point * * Caller must hold bond lock for read */ -static void -rlb_clear_slave(struct bonding *bond, struct slave *slave) +static void rlb_clear_slave(struct bonding *bond, struct slave *slave) { - struct rlb_client_info *rx_hash_table = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; + struct rlb_client_info *rx_hash_table; u32 index, next_index; /* clear slave from rx_hashtbl */ _lock_rx_hashtbl(bond); - rx_hash_table = bond_info->rx_hashtbl; - - if (rx_hash_table == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + rx_hash_table = bond_info->rx_hashtbl; index = bond_info->rx_hashtbl_head; for (; index != RLB_NULL_INDEX; index = next_index) { next_index = rx_hash_table[index].next; - if (rx_hash_table[index].slave == slave) { struct slave *assigned_slave = rlb_next_rx_slave(bond); @@ -533,23 +477,24 @@ rlb_clear_slave(struct bonding *bond, st _unlock_rx_hashtbl(bond); - write_lock(&bond->ptrlock); - if (slave != bond->current_slave) { + write_lock(&bond->curr_slave_lock); + + if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } - write_unlock(&bond->ptrlock); + + write_unlock(&bond->curr_slave_lock); } -static void -rlb_update_client(struct rlb_client_info *client_info) +static void rlb_update_client(struct rlb_client_info *client_info) { - int i = 0; + int i; - if (client_info->slave == NULL) { + if (!client_info->slave) { return; } - for (i=0; iip_dst, client_info->slave->dev, @@ -561,20 +506,14 @@ rlb_update_client(struct rlb_client_info } /* sends ARP REPLIES that update the clients that need updating */ -static void -rlb_update_rx_clients(struct bonding *bond) +static void rlb_update_rx_clients(struct bonding *bond) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -595,22 +534,15 @@ rlb_update_rx_clients(struct bonding *bo } /* The slave was assigned a new mac address - update the clients */ -static void -rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) +static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) { - u32 hash_index; - u8 ntt = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info* client_info = NULL; + struct rlb_client_info *client_info; + int ntt = 0; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -633,37 +565,31 @@ rlb_req_update_slave_clients(struct bond } /* mark all clients using src_ip to be updated */ -static void -rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) { - u32 hash_index; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info *client_info = NULL; + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - printk(KERN_ERR "Bonding: Error: found a client with no" - " channel in the client's hash table\n"); + printk(KERN_ERR DRV_NAME + ": Error: found a client with no channel in " + "the client's hash table\n"); continue; } /*update all clients using this src_ip, that are not assigned - * to the team's address (current_slave) and have a known + * to the team's address (curr_active_slave) and have a known * unicast mac address. */ if ((client_info->ip_src == src_ip) && memcmp(client_info->slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN) && + bond->dev->dev_addr, ETH_ALEN) && memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond_info->rx_ntt = 1; @@ -674,30 +600,22 @@ rlb_req_update_subnet_clients(struct bon } /* Caller must hold both bond and ptr locks for read */ -struct slave* -rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) +struct slave *rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct rlb_client_info *client_info = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; u32 hash_index = 0; - struct slave *assigned_slave = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return NULL; - } - - hash_index = _simple_hash((u8 *)&arp->ip_dst, 4); + hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); - if (client_info->assigned == 1) { + if (client_info->assigned) { if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); @@ -710,12 +628,12 @@ rlb_choose_channel(struct bonding *bond, } } else { /* the entry is already assigned to some other client, - * move the old client to primary (current_slave) so + * move the old client to primary (curr_active_slave) so * that the new client can be assigned to this entry. */ - if (bond->current_slave && - client_info->slave != bond->current_slave) { - client_info->slave = bond->current_slave; + if (bond->curr_active_slave && + client_info->slave != bond->curr_active_slave) { + client_info->slave = bond->curr_active_slave; rlb_update_client(client_info); } } @@ -736,8 +654,7 @@ rlb_choose_channel(struct bonding *bond, if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond->alb_info.rx_ntt = 1; - } - else { + } else { client_info->ntt = 0; } @@ -760,10 +677,9 @@ rlb_choose_channel(struct bonding *bond, /* chooses (and returns) transmit channel for arp reply * does not choose channel for other arp types since they are - * sent on the current_slave + * sent on the curr_active_slave */ -static struct slave* -rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) +static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *tx_slave = NULL; @@ -776,9 +692,8 @@ rlb_arp_xmit(struct sk_buff *skb, struct if (tx_slave) { memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } - BOND_PRINT_DBG(("Server sent ARP Reply packet")); + dprintk("Server sent ARP Reply packet\n"); } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { - /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated @@ -797,34 +712,29 @@ rlb_arp_xmit(struct sk_buff *skb, struct * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - BOND_PRINT_DBG(("Server sent ARP Request packet")); + dprintk("Server sent ARP Request packet\n"); } return tx_slave; } /* Caller must hold bond lock for read */ -static void -rlb_rebalance(struct bonding *bond) +static void rlb_rebalance(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *assigned_slave = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; + int ntt; u32 hash_index; - struct rlb_client_info *client_info = NULL; - u8 ntt = 0; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - + ntt = 0; hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); assigned_slave = rlb_next_rx_slave(bond); - if (assigned_slave && (client_info->slave != assigned_slave)){ + if (assigned_slave && (client_info->slave != assigned_slave)) { client_info->slave = assigned_slave; client_info->ntt = 1; ntt = 1; @@ -839,96 +749,83 @@ rlb_rebalance(struct bonding *bond) } /* Caller must hold rx_hashtbl lock */ -static inline void -rlb_init_table_entry(struct rlb_client_info *entry) +static void rlb_init_table_entry(struct rlb_client_info *entry) { + memset(entry, 0, sizeof(struct rlb_client_info)); entry->next = RLB_NULL_INDEX; entry->prev = RLB_NULL_INDEX; - entry->assigned = 0; - entry->ntt = 0; } -static int -rlb_initialize(struct bonding *bond) +static int rlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type); + int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); int i; - size_t size; spin_lock_init(&(bond_info->rx_hashtbl_lock)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl != NULL) { - printk (KERN_ERR "%s: RLB hash table is not NULL\n", - bond->device->name); - _unlock_rx_hashtbl(bond); - return -1; - } - size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->rx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate" - " RLB hash table\n", bond->device->name); + if (!bond_info->rx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate RLB hash table\n", + bond->dev->name); _unlock_rx_hashtbl(bond); return -1; } bond_info->rx_hashtbl_head = RLB_NULL_INDEX; - for (i=0; irx_hashtbl + i); } - _unlock_rx_hashtbl(bond); - /* register to receive ARPs */ + _unlock_rx_hashtbl(bond); /*initialize packet type*/ pk_type->type = __constant_htons(ETH_P_ARP); - pk_type->dev = bond->device; + pk_type->dev = bond->dev; pk_type->func = rlb_arp_recv; + /* register to receive ARPs */ dev_add_pack(pk_type); return 0; } -static void -rlb_deinitialize(struct bonding *bond) +static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); dev_remove_pack(&(bond_info->rlb_pkt_type)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; + _unlock_rx_hashtbl(bond); } /*********************** tlb/rlb shared functions *********************/ -static void -alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) +static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) { - struct sk_buff *skb = NULL; struct learning_pkt pkt; - char *data = NULL; + int size = sizeof(struct learning_pkt); int i; - unsigned int size = sizeof(struct learning_pkt); memset(&pkt, 0, size); memcpy(pkt.mac_dst, mac_addr, ETH_ALEN); memcpy(pkt.mac_src, mac_addr, ETH_ALEN); pkt.type = __constant_htons(ETH_P_LOOP); - for (i=0; i < MAX_LP_RETRY; i++) { - skb = NULL; + for (i = 0; i < MAX_LP_RETRY; i++) { + struct sk_buff *skb; + char *data; + skb = dev_alloc_skb(size); if (!skb) { return; @@ -936,28 +833,26 @@ alb_send_learning_packets(struct slave * data = skb_put(skb, size); memcpy(data, &pkt, size); + skb->mac.raw = data; skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; + dev_queue_xmit(skb); } - } /* hw is a boolean parameter that determines whether we should try and * set the hw address of the device as well as the hw address of the * net_device */ -static int -alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) { - struct net_device *dev = NULL; + struct net_device *dev = slave->dev; struct sockaddr s_addr; - dev = slave->dev; - if (!hw) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; @@ -968,26 +863,23 @@ alb_set_slave_mac_addr(struct slave *sla memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev->set_mac_address(dev, &s_addr)) { - printk(KERN_DEBUG "bonding: Error: alb_set_slave_mac_addr:" - " dev->set_mac_address of dev %s failed!" - " ALB mode requires that the base driver" - " support setting the hw address also when" - " the network device's interface is open\n", - dev->name); + printk(KERN_ERR DRV_NAME + ": Error: dev->set_mac_address of dev %s failed! ALB " + "mode requires that the base driver support setting " + "the hw address also when the network device's " + "interface is open\n", + dev->name); return -EOPNOTSUPP; } return 0; } -/* Caller must hold bond lock for write or ptrlock for write*/ -static void -alb_swap_mac_addr(struct bonding *bond, - struct slave *slave1, - struct slave *slave2) +/* Caller must hold bond lock for write or curr_slave_lock for write*/ +static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) { - u8 tmp_mac_addr[ETH_ALEN]; struct slave *disabled_slave = NULL; - u8 slaves_state_differ; + u8 tmp_mac_addr[ETH_ALEN]; + int slaves_state_differ; slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); @@ -1004,8 +896,7 @@ alb_swap_mac_addr(struct bonding *bond, */ rlb_req_update_slave_clients(bond, slave1); } - } - else { + } else { disabled_slave = slave1; } @@ -1017,15 +908,14 @@ alb_swap_mac_addr(struct bonding *bond, */ rlb_req_update_slave_clients(bond, slave2); } - } - else { + } else { disabled_slave = slave2; } if (bond->alb_info.rlb_enabled && slaves_state_differ) { - /* A disabled slave was assigned an active mac addr */ - rlb_teach_disabled_mac_on_primary(bond, - disabled_slave->dev->dev_addr); + /* A disabled slave was assigned an active mac addr */ + rlb_teach_disabled_mac_on_primary(bond, + disabled_slave->dev->dev_addr); } } @@ -1043,10 +933,8 @@ alb_swap_mac_addr(struct bonding *bond, * * Caller must hold bond lock */ -static void -alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) +static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave; int perm_curr_diff; int perm_bond_diff; @@ -1054,20 +942,23 @@ alb_change_hw_addr_on_detach(struct bond slave->dev->dev_addr, ETH_ALEN); perm_bond_diff = memcmp(slave->perm_hwaddr, - bond->device->dev_addr, + bond->dev->dev_addr, ETH_ALEN); + if (perm_curr_diff && perm_bond_diff) { - tmp_slave = bond_get_first_slave(bond); - while (tmp_slave) { + struct slave *tmp_slave; + int i, found = 0; + + bond_for_each_slave(bond, tmp_slave, i) { if (!memcmp(slave->perm_hwaddr, - tmp_slave->dev->dev_addr, - ETH_ALEN)) { + tmp_slave->dev->dev_addr, + ETH_ALEN)) { + found = 1; break; } - tmp_slave = bond_get_next_slave(bond, tmp_slave); } - if (tmp_slave) { + if (found) { alb_swap_mac_addr(bond, slave, tmp_slave); } } @@ -1098,10 +989,11 @@ alb_change_hw_addr_on_detach(struct bond * caller must hold the bond lock for write since the mac addresses are compared * and may be swapped. */ -static int -alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) +static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave1, *tmp_slave2; + struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave; + struct slave *has_bond_addr = bond->curr_active_slave; + int i, j, found = 0; if (bond->slave_cnt == 0) { /* this is the first slave */ @@ -1112,65 +1004,78 @@ alb_handle_addr_collision_on_attach(stru * check uniqueness of slave's mac address against the other * slaves in the bond. */ - if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) { - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { + if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave1, i) { if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, ETH_ALEN)) { + found = 1; break; } } - if (tmp_slave1) { + + if (found) { /* a slave was found that is using the mac address * of the new slave */ - printk(KERN_ERR "bonding: Warning: the hw address " - "of slave %s is not unique - cannot enslave it!" - , slave->dev->name); + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is not " + "unique - cannot enslave it!", + slave->dev->name); return -EINVAL; } + return 0; } - /* the slave's address is equal to the address of the bond - * search for a spare address in the bond for this slave. + /* The slave's address is equal to the address of the bond. + * Search for a spare address in the bond for this slave. */ - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { - - tmp_slave2 = bond_get_first_slave(bond); - for (; tmp_slave2; tmp_slave2 = bond_get_next_slave(bond, tmp_slave2)) { + free_mac_slave = NULL; + bond_for_each_slave(bond, tmp_slave1, i) { + found = 0; + bond_for_each_slave(bond, tmp_slave2, j) { if (!memcmp(tmp_slave1->perm_hwaddr, tmp_slave2->dev->dev_addr, ETH_ALEN)) { - + found = 1; break; } } - if (!tmp_slave2) { + if (!found) { /* no slave has tmp_slave1's perm addr * as its curr addr */ + free_mac_slave = tmp_slave1; break; } + + if (!has_bond_addr) { + if (!memcmp(tmp_slave1->dev->dev_addr, + bond->dev->dev_addr, + ETH_ALEN)) { + + has_bond_addr = tmp_slave1; + } + } } - if (tmp_slave1) { - alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr, + if (free_mac_slave) { + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); - printk(KERN_WARNING "bonding: Warning: the hw address " - "of slave %s is in use by the bond; " - "giving it the hw address of %s\n", - slave->dev->name, tmp_slave1->dev->name); - } else { - printk(KERN_CRIT "bonding: Error: the hw address " - "of slave %s is in use by the bond; " - "couldn't find a slave with a free hw " - "address to give it (this should not have " - "happened)\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning: the hw address of slave %s is in use by " + "the bond; giving it the hw address of %s\n", + slave->dev->name, free_mac_slave->dev->name); + + } else if (has_bond_addr) { + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is in use by the " + "bond; couldn't find a slave with a free hw address to " + "give it (this should not have happened)\n", + slave->dev->name); return -EFAULT; } @@ -1188,37 +1093,36 @@ alb_handle_addr_collision_on_attach(stru * * For each slave, this function sets the interface to the new address and then * changes its dev_addr field to its previous value. - * + * * Unwinding assumes bond's mac address has not yet changed. */ -static inline int -alb_set_mac_address(struct bonding *bond, void *addr) +static int alb_set_mac_address(struct bonding *bond, void *addr) { struct sockaddr sa; - struct slave *slave; + struct slave *slave, *stop_at; char tmp_addr[ETH_ALEN]; - int error; + int res; + int i; if (bond->alb_info.rlb_enabled) { return 0; } - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + bond_for_each_slave(bond, slave, i) { if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; + res = -EOPNOTSUPP; goto unwind; } /* save net_device's current hw address */ memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); - error = slave->dev->set_mac_address(slave->dev, addr); + res = slave->dev->set_mac_address(slave->dev, addr); /* restore net_device's hw address */ memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); - if (error) { + if (res) { goto unwind; } } @@ -1226,22 +1130,23 @@ alb_set_mac_address(struct bonding *bond return 0; unwind: - memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len); - sa.sa_family = bond->device->type; - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len); + sa.sa_family = bond->dev->type; + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); slave->dev->set_mac_address(slave->dev, &sa); memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); } - return error; + return res; } /************************ exported alb funcions ************************/ -int -bond_alb_initialize(struct bonding *bond, int rlb_enabled) +int bond_alb_initialize(struct bonding *bond, int rlb_enabled) { int res; @@ -1263,8 +1168,7 @@ bond_alb_initialize(struct bonding *bond return 0; } -void -bond_alb_deinitialize(struct bonding *bond) +void bond_alb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1275,49 +1179,38 @@ bond_alb_deinitialize(struct bonding *bo } } -int -bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *eth_data = (struct ethhdr *)skb->data; + struct bonding *bond = bond_dev->priv; + struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - char do_tx_balance = 1; + static u32 ip_bcast = 0xffffffff; int hash_size = 0; + int do_tx_balance = 1; u32 hash_index = 0; u8 *hash_start = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - /* make sure that the current_slave and the slaves list do + /* make sure that the curr_active_slave and the slaves list do * not change during tx */ read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto free_out; } - read_lock(&bond->ptrlock); - switch (ntohs(skb->protocol)) { case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || - (skb->nh.iph->daddr == 0xffffffff)) { + (skb->nh.iph->daddr == ip_bcast)) { do_tx_balance = 0; break; } hash_start = (char*)&(skb->nh.iph->daddr); - hash_size = 4; + hash_size = sizeof(skb->nh.iph->daddr); break; - case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; @@ -1325,9 +1218,8 @@ bond_alb_xmit(struct sk_buff *skb, struc } hash_start = (char*)&(skb->nh.ipv6h->daddr); - hash_size = 16; + hash_size = sizeof(skb->nh.ipv6h->daddr); break; - case ETH_P_IPX: if (ipx_hdr(skb)->ipx_checksum != __constant_htons(IPX_NO_CHECKSUM)) { @@ -1349,14 +1241,12 @@ bond_alb_xmit(struct sk_buff *skb, struc hash_start = (char*)eth_data->h_dest; hash_size = ETH_ALEN; break; - case ETH_P_ARP: do_tx_balance = 0; if (bond_info->rlb_enabled) { tx_slave = rlb_arp_xmit(skb, bond); } break; - default: do_tx_balance = 0; break; @@ -1369,16 +1259,16 @@ bond_alb_xmit(struct sk_buff *skb, struc if (!tx_slave) { /* unbalanced or unassigned, send through primary */ - tx_slave = bond->current_slave; + tx_slave = bond->curr_active_slave; bond_info->unbalanced_load += skb->len; } if (tx_slave && SLAVE_IS_OK(tx_slave)) { skb->dev = tx_slave->dev; - if (tx_slave != bond->current_slave) { + if (tx_slave != bond->curr_active_slave) { memcpy(eth_data->h_source, - tx_slave->dev->dev_addr, - ETH_ALEN); + tx_slave->dev->dev_addr, + ETH_ALEN); } dev_queue_xmit(skb); } else { @@ -1386,26 +1276,35 @@ bond_alb_xmit(struct sk_buff *skb, struc if (tx_slave) { tlb_clear_slave(bond, tx_slave, 0); } - dev_kfree_skb(skb); + goto free_out; } - read_unlock(&bond->ptrlock); +out: + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); return 0; + +free_out: + dev_kfree_skb(skb); + goto out; } -void -bond_alb_monitor(struct bonding *bond) +void bond_alb_monitor(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *slave = NULL; + struct slave *slave; + int i; read_lock(&bond->lock); - if ((bond->slave_cnt == 0) || !(bond->device->flags & IFF_UP)) { + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { bond_info->tx_rebalance_counter = 0; bond_info->lp_counter = 0; - goto out; + goto re_arm; } bond_info->tx_rebalance_counter++; @@ -1413,51 +1312,53 @@ bond_alb_monitor(struct bonding *bond) /* send learning packets */ if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) { - /* change of current_slave involves swapping of mac addresses. + /* change of curr_active_slave involves swapping of mac addresses. * in order to avoid this swapping from happening while - * sending the learning packets, the ptrlock must be held for + * sending the learning packets, the curr_slave_lock must be held for * read. */ - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { alb_send_learning_packets(slave,slave->dev->dev_addr); - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); bond_info->lp_counter = 0; } /* rebalance tx traffic */ if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { tlb_clear_slave(bond, slave, 1); - if (slave == bond->current_slave) { + if (slave == bond->curr_active_slave) { SLAVE_TLB_INFO(slave).load = bond_info->unbalanced_load / BOND_TLB_REBALANCE_INTERVAL; bond_info->unbalanced_load = 0; } - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + bond_info->tx_rebalance_counter = 0; } /* handle rlb stuff */ if (bond_info->rlb_enabled) { /* the following code changes the promiscuity of the - * the current_slave. It needs to be locked with a + * the curr_active_slave. It needs to be locked with a * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + if (bond_info->primary_is_promisc && - (++bond_info->rlb_promisc_timeout_counter >= - RLB_PROMISC_TIMEOUT)) { + (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { bond_info->rlb_promisc_timeout_counter = 0; @@ -1465,12 +1366,13 @@ bond_alb_monitor(struct bonding *bond) * because a slave was disabled then * it can now leave promiscuous mode. */ - dev_set_promiscuity(bond->current_slave->dev, -1); + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; } - write_unlock(&bond->ptrlock); - if (bond_info->rlb_rebalance == 1) { + write_unlock(&bond->curr_slave_lock); + + if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; rlb_rebalance(bond); } @@ -1490,28 +1392,23 @@ bond_alb_monitor(struct bonding *bond) } } +re_arm: + mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); out: read_unlock(&bond->lock); - - if (bond->device->flags & IFF_UP) { - /* re-arm the timer */ - mod_timer(&(bond_info->alb_timer), - jiffies + (HZ/ALB_TIMER_TICKS_PER_SEC)); - } } -/* assumption: called before the slave is attched to the bond +/* assumption: called before the slave is attached to the bond * and not locked by the bond lock */ -int -bond_alb_init_slave(struct bonding *bond, struct slave *slave) +int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { - int err = 0; + int res; - err = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, bond->alb_info.rlb_enabled); - if (err) { - return err; + if (res) { + return res; } /* caller must hold the bond lock for write since the mac addresses @@ -1519,12 +1416,12 @@ bond_alb_init_slave(struct bonding *bond */ write_lock_bh(&bond->lock); - err = alb_handle_addr_collision_on_attach(bond, slave); + res = alb_handle_addr_collision_on_attach(bond, slave); write_unlock_bh(&bond->lock); - if (err) { - return err; + if (res) { + return res; } tlb_init_slave(slave); @@ -1540,8 +1437,7 @@ bond_alb_init_slave(struct bonding *bond } /* Caller must hold bond lock for write */ -void -bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) +void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) { if (bond->slave_cnt > 1) { alb_change_hw_addr_on_detach(bond, slave); @@ -1556,9 +1452,7 @@ bond_alb_deinit_slave(struct bonding *bo } /* Caller must hold bond lock for read */ -void -bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, - char link) +void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1582,109 +1476,111 @@ bond_alb_handle_link_change(struct bondi } /** - * bond_alb_assign_current_slave - assign new current_slave + * bond_alb_handle_active_change - assign new curr_active_slave * @bond: our bonding struct * @new_slave: new slave to assign * - * Set the bond->current_slave to @new_slave and handle + * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * - * Caller must hold bond ptrlock for write (or bond lock for write) + * Caller must hold bond curr_slave_lock for write (or bond lock for write) */ -void -bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) { - struct slave *swap_slave = bond->current_slave; + struct slave *swap_slave; + int i; - if (bond->current_slave == new_slave) { + if (bond->curr_active_slave == new_slave) { return; } - if (bond->current_slave && bond->alb_info.primary_is_promisc) { - dev_set_promiscuity(bond->current_slave->dev, -1); + if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) { + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond->alb_info.primary_is_promisc = 0; bond->alb_info.rlb_promisc_timeout_counter = 0; } - bond->current_slave = new_slave; + swap_slave = bond->curr_active_slave; + bond->curr_active_slave = new_slave; if (!new_slave || (bond->slave_cnt == 0)) { return; } - /* set the new current_slave to the bonds mac address - * i.e. swap mac addresses of old current_slave and new current_slave + /* set the new curr_active_slave to the bonds mac address + * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave */ if (!swap_slave) { + struct slave *tmp_slave; /* find slave that is holding the bond's mac address */ - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave, i) { + if (!memcmp(tmp_slave->dev->dev_addr, + bond->dev->dev_addr, ETH_ALEN)) { + swap_slave = tmp_slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } } - /* current_slave must be set before calling alb_swap_mac_addr */ + /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->device->dev_addr, + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, bond->alb_info.rlb_enabled); /* fasten bond mac on new current slave */ - alb_send_learning_packets(new_slave, bond->device->dev_addr); + alb_send_learning_packets(new_slave, bond->dev->dev_addr); } } -int -bond_alb_set_mac_address(struct net_device *dev, void *addr) +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr; - struct slave *swap_slave = NULL; - int error = 0; + struct slave *slave, *swap_slave; + int res; + int i; if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - error = alb_set_mac_address(bond, addr); - if (error) { - return error; + res = alb_set_mac_address(bond, addr); + if (res) { + return res; } - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); - /* If there is no current_slave there is nothing else to do. + /* If there is no curr_active_slave there is nothing else to do. * Otherwise we'll need to pass the new address to it and handle * duplications. */ - if (bond->current_slave == NULL) { + if (!bond->curr_active_slave) { return 0; } - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) { + swap_slave = NULL; + + bond_for_each_slave(bond, slave, i) { + if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) { + swap_slave = slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } if (swap_slave) { - alb_swap_mac_addr(bond, swap_slave, bond->current_slave); + alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr, + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, bond->alb_info.rlb_enabled); - alb_send_learning_packets(bond->current_slave, dev->dev_addr); + alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); if (bond->alb_info.rlb_enabled) { /* inform clients mac address has changed */ - rlb_req_update_slave_clients(bond, bond->current_slave); + rlb_req_update_slave_clients(bond, bond->curr_active_slave); } } --- linux-2.6.1-rc1/drivers/net/bonding/bond_alb.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/bonding/bond_alb.h 2003-12-30 22:49:19.000000000 -0800 @@ -24,6 +24,9 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_ALB_H__ @@ -126,10 +129,10 @@ void bond_alb_deinitialize(struct bondin int bond_alb_init_slave(struct bonding *bond, struct slave *slave); void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); -void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave); -int bond_alb_xmit(struct sk_buff *skb, struct net_device *dev); +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); void bond_alb_monitor(struct bonding *bond); -int bond_alb_set_mac_address(struct net_device *dev, void *addr); +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); #endif /* __BOND_ALB_H__ */ --- linux-2.6.1-rc1/drivers/net/bonding/bonding.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/bonding/bonding.h 2003-12-30 22:49:19.000000000 -0800 @@ -9,7 +9,7 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * * 2003/03/18 - Amir Noam , * Tsippy Mendelson and @@ -22,159 +22,205 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. + * + * 2003/09/24 - Shmulik Hen + * - Code cleanup and style changes */ - + #ifndef _LINUX_BONDING_H #define _LINUX_BONDING_H #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" -#ifdef BONDING_DEBUG - -// use this like so: BOND_PRINT_DBG(("foo = %d, bar = %d", foo, bar)); -#define BOND_PRINT_DBG(X) \ -do { \ - printk(KERN_DEBUG "%s (%d)", __FUNCTION__, __LINE__); \ - printk X; \ - printk("\n"); \ -} while(0) +#define DRV_VERSION "2.5.0" +#define DRV_RELDATE "December 1, 2003" +#define DRV_NAME "bonding" +#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" +#ifdef BONDING_DEBUG +#define dprintk(fmt, args...) \ + printk(KERN_DEBUG \ + DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args ) #else -#define BOND_PRINT_DBG(X) +#define dprintk(fmt, args...) #endif /* BONDING_DEBUG */ -#define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ - (netif_running(dev) && netif_carrier_ok(dev))) +#define IS_UP(dev) \ + ((((dev)->flags & IFF_UP) == IFF_UP) && \ + netif_running(dev) && \ + netif_carrier_ok(dev)) -/* Checks whether the dev is ready for transmit. We do not check netif_running - * since a device can be stopped by the driver for short periods of time for - * maintainance. dev_queue_xmit() handles this by queing the packet until the - * the dev is running again. Keeping packets ordering requires sticking the - * same dev as much as possible - */ -#define SLAVE_IS_OK(slave) \ - ((((slave)->dev->flags & (IFF_UP)) == (IFF_UP)) && \ - netif_carrier_ok((slave)->dev) && \ +/* + * Checks whether bond is ready for transmit. + * + * Caller must hold bond->lock + */ +#define BOND_IS_OK(bond) \ + (((bond)->dev->flags & IFF_UP) && \ + netif_running((bond)->dev) && \ + ((bond)->slave_cnt > 0)) + +/* + * Checks whether slave is ready for transmit. + */ +#define SLAVE_IS_OK(slave) \ + (((slave)->dev->flags & IFF_UP) && \ + netif_running((slave)->dev) && \ ((slave)->link == BOND_LINK_UP) && \ ((slave)->state == BOND_STATE_ACTIVE)) -typedef struct slave { +#define USES_PRIMARY(mode) \ + (((mode) == BOND_MODE_ACTIVEBACKUP) || \ + ((mode) == BOND_MODE_TLB) || \ + ((mode) == BOND_MODE_ALB)) + +/* + * Less bad way to call ioctl from within the kernel; this needs to be + * done some other way to get the call out of interrupt context. + * Needs "ioctl" variable to be supplied by calling context. + */ +#define IOCTL(dev, arg, cmd) ({ \ + int res = 0; \ + mm_segment_t fs = get_fs(); \ + set_fs(get_ds()); \ + res = ioctl(dev, arg, cmd); \ + set_fs(fs); \ + res; }) + +/** + * bond_for_each_slave_from - iterate the slaves list from a starting point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * @start: starting point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from(bond, pos, cnt, start) \ + for (cnt = 0, pos = start; \ + cnt < (bond)->slave_cnt; \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for number max of moves + * @start: start point. + * @stop: stop point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \ + for (cnt = 0, pos = start; \ + ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave - iterate the slaves list from head + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave(bond, pos, cnt) \ + bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) + + +struct slave { + struct net_device *dev; /* first - usefull for panic debug */ struct slave *next; struct slave *prev; - struct net_device *dev; - short delay; - unsigned long jiffies; - char link; /* one of BOND_LINK_XXXX */ - char state; /* one of BOND_STATE_XXXX */ - unsigned short original_flags; - u32 link_failure_count; + s16 delay; + u32 jiffies; + s8 link; /* one of BOND_LINK_XXXX */ + s8 state; /* one of BOND_STATE_XXXX */ + u32 original_flags; + u32 link_failure_count; u16 speed; u8 duplex; u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; -} slave_t; +}; /* * Here are the locking policies for the two bonding locks: * * 1) Get bond->lock when reading/writing slave list. - * 2) Get bond->ptrlock when reading/writing bond->current_slave. + * 2) Get bond->curr_slave_lock when reading/writing bond->curr_active_slave. * (It is unnecessary when the write-lock is put with bond->lock.) - * 3) When we lock with bond->ptrlock, we must lock with bond->lock + * 3) When we lock with bond->curr_slave_lock, we must lock with bond->lock * beforehand. */ -typedef struct bonding { - slave_t *next; - slave_t *prev; - slave_t *current_slave; - slave_t *primary_slave; - slave_t *current_arp_slave; - __s32 slave_cnt; +struct bonding { + struct net_device *dev; /* first - usefull for panic debug */ + struct slave *first_slave; + struct slave *curr_active_slave; + struct slave *current_arp_slave; + struct slave *primary_slave; + s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ rwlock_t lock; - rwlock_t ptrlock; - struct timer_list mii_timer; - struct timer_list arp_timer; - struct net_device_stats stats; + rwlock_t curr_slave_lock; + struct timer_list mii_timer; + struct timer_list arp_timer; + s8 kill_timers; + struct net_device_stats stats; #ifdef CONFIG_PROC_FS - struct proc_dir_entry *bond_proc_file; - char procdir_name[IFNAMSIZ]; + struct proc_dir_entry *proc_entry; + char proc_file_name[IFNAMSIZ]; #endif /* CONFIG_PROC_FS */ - struct list_head bond_list; - struct net_device *device; - struct dev_mc_list *mc_list; - unsigned short flags; - struct ad_bond_info ad_info; - struct alb_bond_info alb_info; -} bonding_t; - -/* Forward declarations */ -void bond_set_slave_active_flags(slave_t *slave); -void bond_set_slave_inactive_flags(slave_t *slave); - -/** - * These functions can be used for iterating the slave list - * (which is circular) - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_first_slave(struct bonding *bond) -{ - /* if there are no slaves return NULL */ - if (bond->next == (slave_t *)bond) { - return NULL; - } - return bond->next; -} - -/** - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_next_slave(struct bonding *bond, struct slave *slave) -{ - /* If we have reached the last slave return NULL */ - if (slave->next == bond->next) { - return NULL; - } - return slave->next; -} + struct list_head bond_list; + struct dev_mc_list *mc_list; + u16 flags; + struct ad_bond_info ad_info; + struct alb_bond_info alb_info; +}; /** * Returns NULL if the net_device does not belong to any of the bond's slaves * * Caller must hold bond lock for read */ -extern inline struct slave* -bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) +extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { - struct slave *our_slave = bond->next; - - /* check if the list of slaves is empty */ - if (our_slave == (slave_t *)bond) { - return NULL; - } + struct slave *slave = NULL; + int i; - for (; our_slave; our_slave = bond_get_next_slave(bond, our_slave)) { - if (our_slave->dev == slave_dev) { + bond_for_each_slave(bond, slave, i) { + if (slave->dev == slave_dev) { break; } } - return our_slave; + + return slave; } -extern inline struct bonding* -bond_get_bond_by_slave(struct slave *slave) +extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) { if (!slave || !slave->dev->master) { return NULL; } - return (struct bonding *)(slave->dev->master->priv); + return (struct bonding *)slave->dev->master->priv; +} + +extern inline void bond_set_slave_inactive_flags(struct slave *slave) +{ + slave->state = BOND_STATE_BACKUP; + slave->dev->flags |= IFF_NOARP; +} + +extern inline void bond_set_slave_active_flags(struct slave *slave) +{ + slave->state = BOND_STATE_ACTIVE; + slave->dev->flags &= ~IFF_NOARP; } #endif /* _LINUX_BONDING_H */ --- linux-2.6.1-rc1/drivers/net/bonding/bond_main.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/bonding/bond_main.c 2003-12-30 22:49:19.000000000 -0800 @@ -1,7 +1,7 @@ /* * originally based on the dummy device. * - * Copyright 1999, Thomas Davis, tadavis@lbl.gov. + * Copyright 1999, Thomas Davis, tadavis@lbl.gov. * Licensed under the GPL. Based on dummy.c, and eql.c devices. * * bonding.c: an Ethernet Bonding driver @@ -15,9 +15,9 @@ * * How it works: * ifconfig bond0 ipaddress netmask up - * will setup a network device, with an ip address. No mac address - * will be assigned at this time. The hw mac address will come from - * the first slave bonded to the channel. All slaves will then use + * will setup a network device, with an ip address. No mac address + * will be assigned at this time. The hw mac address will come from + * the first slave bonded to the channel. All slaves will then use * this hw mac address. * * ifconfig bond0 down @@ -26,7 +26,7 @@ * ifenslave bond0 eth0 * will attach eth0 to bond0 as a slave. eth0 hw mac address will either * a: be used as initial mac address - * b: if a hw mac address already is there, eth0's hw mac address + * b: if a hw mac address already is there, eth0's hw mac address * will then be set from bond0. * * v0.1 - first working version. @@ -93,14 +93,14 @@ * * 2001/4/5 - Chad N. Tindel * - Ported to 2.4 Kernel - * + * * 2001/5/2 - Jeffrey E. Mast * - When a device is detached from a bond, the slave device is no longer * left thinking that is has a master. * * 2001/5/16 - Jeffrey E. Mast - * - memset did not appropriately initialized the bond rw_locks. Used - * rwlock_init to initialize to unlocked state to prevent deadlock when + * - memset did not appropriately initialized the bond rw_locks. Used + * rwlock_init to initialize to unlocked state to prevent deadlock when * first attempting a lock * - Called SET_MODULE_OWNER for bond device * @@ -119,7 +119,7 @@ * * 2001/6/01 - Chad N. Tindel * - Added /proc support for getting bond and slave information. - * Information is in /proc/net//info. + * Information is in /proc/net//info. * - Changed the locking when calling bond_close to prevent deadlock. * * 2001/8/05 - Janice Girouard @@ -144,8 +144,8 @@ * but only for an up link. * * 2001/9/20 - Chad N. Tindel - * - Add the device field to bonding_t. Previously the net_device - * corresponding to a bond wasn't available from the bonding_t + * - Add the device field to bonding_t. Previously the net_device + * corresponding to a bond wasn't available from the bonding_t * structure. * * 2001/9/25 - Janice Girouard @@ -155,10 +155,10 @@ * - Various memory leak fixes * * 2001/11/5 - Mark Huth - * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under - * certain hotswap conditions. + * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under + * certain hotswap conditions. * Note: this same change may be required in bond_arp_monitor ??? - * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr + * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr * - Handle hot swap ethernet interface deregistration events to remove * kernel oops following hot swap of enslaved interface * @@ -222,23 +222,23 @@ * - fix deletion of multicast groups after unloading module * * 2002/11/06 - Kameshwara Rayaprolu - * - Changes to prevent panic from closing the device twice; if we close - * the device in bond_release, we must set the original_flags to down + * - Changes to prevent panic from closing the device twice; if we close + * the device in bond_release, we must set the original_flags to down * so it won't be closed again by the network layer. * * 2002/11/07 - Tony Cureington * - Fix arp_target_hw_addr memory leak - * - Created activebackup_arp_monitor function to handle arp monitoring - * in active backup mode - the bond_arp_monitor had several problems... - * such as allowing slaves to tx arps sequentially without any delay + * - Created activebackup_arp_monitor function to handle arp monitoring + * in active backup mode - the bond_arp_monitor had several problems... + * such as allowing slaves to tx arps sequentially without any delay * for a response * - Renamed bond_arp_monitor to loadbalance_arp_monitor and re-wrote * this function to just handle arp monitoring in load-balancing mode; * it is a lot more compact now - * - Changes to ensure one and only one slave transmits in active-backup + * - Changes to ensure one and only one slave transmits in active-backup * mode - * - Robustesize parameters; warn users about bad combinations of - * parameters; also if miimon is specified and a network driver does + * - Robustesize parameters; warn users about bad combinations of + * parameters; also if miimon is specified and a network driver does * not support MII or ETHTOOL, inform the user of this * - Changes to support link_failure_count when in arp monitoring mode * - Fix up/down delay reported in /proc @@ -248,7 +248,7 @@ * * 2002/11/16 - Laurent Deniel * - fix multicast handling in activebackup_arp_monitor - * - remove one unnecessary and confusing current_slave == slave test + * - remove one unnecessary and confusing curr_active_slave == slave test * in activebackup_arp_monitor * * 2002/11/17 - Laurent Deniel @@ -267,7 +267,7 @@ * One change: an invalid choice will cause module load failure, * rather than the previous behavior of just picking one. * - Minor cleanups; got rid of dup ctype stuff, atoi function - * + * * 2003/02/07 - Jay Vosburgh * - Added use_carrier module parameter that causes miimon to * use netif_carrier_ok() test instead of MII/ETHTOOL ioctls. @@ -330,7 +330,7 @@ * new/old ifenslave and new/old bonding. * * 2003/05/01 - Shmulik Hen - * - Fixed bug in bond_release_all(): save old value of current_slave + * - Fixed bug in bond_release_all(): save old value of curr_active_slave * before setting it to NULL. * - Changed driver versioning scheme to include version number instead * of release date (that is already in another field). There are 3 @@ -358,7 +358,7 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. - * - Concentrate all assignments of current_slave to a single point + * - Concentrate all assignments of curr_active_slave to a single point * so specific modes can take actions when the primary adapter is * changed. * - Take the updelay parameter into consideration during bond_enslave @@ -426,8 +426,36 @@ * - Convert /proc to seq_file interface. * Change /proc/net/bondX/info to /proc/net/bonding/bondX. * Set version to 2.4.1. + * + * 2003/11/20 - Amir Noam + * - Fix /proc creation/destruction. + * + * 2003/12/01 - Shmulik Hen + * - Massive cleanup - Set version to 2.5.0 + * Code changes: + * o Consolidate format of prints and debug prints. + * o Remove bonding_t/slave_t typedefs and consolidate all casts. + * o Remove dead code and unnecessary checks. + * o Consolidate starting/stopping timers. + * o Consolidate handling of primary module param throughout the code. + * o Removed multicast module param support - all settings are done + * according to mode. + * o Slave list iteration - bond is no longer part of the list, + * added cyclic list iteration macros. + * o Consolidate error handling in all xmit functions. + * Style changes: + * o Consolidate function naming and declarations. + * o Consolidate function params and local variables names. + * o Consolidate return values. + * o Consolidate curly braces. + * o Consolidate conditionals format. + * o Change struct member names and types. + * o Chomp trailing spaces, remove empty lines, fix indentations. + * o Re-organize code according to context. */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -452,7 +480,6 @@ #include #include #include - #include #include #include @@ -461,58 +488,72 @@ #include #include #include - -#include #include #include #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "2.4.1" -#define DRV_RELDATE "September 15, 2003" -#define DRV_NAME "bonding" -#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" - -static const char *version = -DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n"; +/*---------------------------- Module parameters ----------------------------*/ /* monitor all links that often (in milliseconds). <=0 disables monitoring */ -#ifndef BOND_LINK_MON_INTERV #define BOND_LINK_MON_INTERV 0 -#endif - -#ifndef BOND_LINK_ARP_INTERV #define BOND_LINK_ARP_INTERV 0 -#endif +#define MAX_ARP_IP_TARGETS 16 -#ifndef MAX_ARP_IP_TARGETS -#define MAX_ARP_IP_TARGETS 16 -#endif +static int max_bonds = BOND_DEFAULT_MAX_BONDS; +static int miimon = BOND_LINK_MON_INTERV; +static int updelay = 0; +static int downdelay = 0; +static int use_carrier = 1; +static char *mode = NULL; +static char *primary = NULL; +static char *lacp_rate = NULL; +static int arp_interval = BOND_LINK_ARP_INTERV; +static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, }; + +MODULE_PARM(max_bonds, "i"); +MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +MODULE_PARM(miimon, "i"); +MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); +MODULE_PARM(updelay, "i"); +MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); +MODULE_PARM(downdelay, "i"); +MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); +MODULE_PARM(use_carrier, "i"); +MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); +MODULE_PARM(primary, "s"); +MODULE_PARM_DESC(primary, "Primary network device to use"); +MODULE_PARM(lacp_rate, "s"); +MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); +MODULE_PARM(arp_interval, "i"); +MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); +MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); +MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -#define USES_PRIMARY(mode) \ - (((mode) == BOND_MODE_ACTIVEBACKUP) || \ - ((mode) == BOND_MODE_TLB) || \ - ((mode) == BOND_MODE_ALB)) +/*----------------------------- Global variables ----------------------------*/ -struct bond_parm_tbl { - char *modename; - int mode; -}; +static const char *version = + DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; -static int arp_interval = BOND_LINK_ARP_INTERV; -static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, }; -static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ; -static int arp_ip_count = 0; -static u32 my_ip = 0; -char *arp_target_hw_addr = NULL; +static LIST_HEAD(bond_dev_list); -static char *primary= NULL; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *bond_proc_dir = NULL; +#endif -static int app_abi_ver = 0; +static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ; +static int arp_ip_count = 0; +static u32 my_ip = 0; +static int bond_mode = BOND_MODE_ROUNDROBIN; +static int lacp_fast = 0; +static int app_abi_ver = 0; static int orig_app_abi_ver = -1; /* This is used to save the first ABI version * we receive from the application. Once set, * it won't be changed, and the module will @@ -521,14 +562,16 @@ static int orig_app_abi_ver = -1; /* Thi * another ABI version. */ -static int max_bonds = BOND_DEFAULT_MAX_BONDS; -static int miimon = BOND_LINK_MON_INTERV; -static int use_carrier = 1; -static int bond_mode = BOND_MODE_ROUNDROBIN; -static int updelay = 0; -static int downdelay = 0; +struct bond_parm_tbl { + char *modename; + int mode; +}; -static char *mode = NULL; +static struct bond_parm_tbl bond_lacp_tbl[] = { +{ "slow", AD_LACP_SLOW}, +{ "fast", AD_LACP_FAST}, +{ NULL, -1}, +}; static struct bond_parm_tbl bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN}, @@ -541,101 +584,9 @@ static struct bond_parm_tbl bond_mode_tb { NULL, -1}, }; -static int multicast_mode = BOND_MULTICAST_ALL; -static char *multicast = NULL; - -static struct bond_parm_tbl bond_mc_tbl[] = { -{ "disabled", BOND_MULTICAST_DISABLED}, -{ "active", BOND_MULTICAST_ACTIVE}, -{ "all", BOND_MULTICAST_ALL}, -{ NULL, -1}, -}; - -static int lacp_fast = 0; -static char *lacp_rate = NULL; - -static struct bond_parm_tbl bond_lacp_tbl[] = { -{ "slow", AD_LACP_SLOW}, -{ "fast", AD_LACP_FAST}, -{ NULL, -1}, -}; - -static LIST_HEAD(bond_dev_list); -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *bond_proc_dir = NULL; -#endif - -MODULE_PARM(max_bonds, "i"); -MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); -MODULE_PARM(miimon, "i"); -MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); -MODULE_PARM(use_carrier, "i"); -MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); -MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); -MODULE_PARM(arp_interval, "i"); -MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); -MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); -MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -MODULE_PARM(updelay, "i"); -MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); -MODULE_PARM(downdelay, "i"); -MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); -MODULE_PARM(primary, "s"); -MODULE_PARM_DESC(primary, "Primary network device to use"); -MODULE_PARM(multicast, "s"); -MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)"); -MODULE_PARM(lacp_rate, "s"); -MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); - -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bond_get_stats(struct net_device *dev); -static void bond_mii_monitor(struct net_device *dev); -static void loadbalance_arp_monitor(struct net_device *dev); -static void activebackup_arp_monitor(struct net_device *dev); -static void bond_mc_list_destroy(struct bonding *bond); -static void bond_mc_add(bonding_t *bond, void *addr, int alen); -static void bond_mc_delete(bonding_t *bond, void *addr, int alen); -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, int gpf_flag); -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2); -static void bond_set_promiscuity(bonding_t *bond, int inc); -static void bond_set_allmulti(bonding_t *bond, int inc); -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list); -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old); -static int bond_enslave(struct net_device *master, struct net_device *slave); -static int bond_release(struct net_device *master, struct net_device *slave); -static int bond_release_all(struct net_device *master); -static int bond_sethwaddr(struct net_device *master, struct net_device *slave); -static void change_active_interface(struct bonding *bond, struct slave *new); -static void reselect_active_interface(struct bonding *bond); -static struct slave *find_best_interface(struct bonding *bond); - - -/* #define BONDING_DEBUG 1 */ -#ifdef BONDING_DEBUG -#define dprintk(x...) printk(x...) -#else /* BONDING_DEBUG */ -#define dprintk(x...) do {} while (0) -#endif /* BONDING_DEBUG */ - -/* several macros */ - -static void arp_send_all(slave_t *slave) -{ - int i; - - for (i = 0; (idev, - my_ip, arp_target_hw_addr, slave->dev->dev_addr, - arp_target_hw_addr); - } -} - +/*---------------------------- General routines -----------------------------*/ -static const char * -bond_mode_name(void) +static const char *bond_mode_name(void) { switch (bond_mode) { case BOND_MODE_ROUNDROBIN : @@ -657,149 +608,7 @@ bond_mode_name(void) } } -static const char * -multicast_mode_name(void) -{ - switch(multicast_mode) { - case BOND_MULTICAST_DISABLED : - return "disabled"; - case BOND_MULTICAST_ACTIVE : - return "active slave only"; - case BOND_MULTICAST_ALL : - return "all slaves"; - default : - return "unknown"; - } -} - -void bond_set_slave_inactive_flags(slave_t *slave) -{ - slave->state = BOND_STATE_BACKUP; - slave->dev->flags |= IFF_NOARP; -} - -void bond_set_slave_active_flags(slave_t *slave) -{ - slave->state = BOND_STATE_ACTIVE; - slave->dev->flags &= ~IFF_NOARP; -} - -/* - * This function counts and verifies the the number of attached - * slaves, checking the count against the expected value (given that incr - * is either 1 or -1, for add or removal of a slave). Only - * bond_xmit_xor() uses the slave_cnt value, but this is still a good - * consistency check. - */ -static inline void -update_slave_cnt(bonding_t *bond, int incr) -{ - slave_t *slave = NULL; - int expect = bond->slave_cnt + incr; - - bond->slave_cnt = 0; - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - bond->slave_cnt++; - } - - if (expect != bond->slave_cnt) - BUG(); -} - -/* - * This function detaches the slave from the list . - * WARNING: no check is made to verify if the slave effectively - * belongs to . It returns in case it's needed. - * Nothing is freed on return, structures are just unchained. - * If the bond->current_slave pointer was pointing to , - * it should be changed by the calling function. - * - * bond->lock held for writing by caller. - */ -static slave_t * -bond_detach_slave(bonding_t *bond, slave_t *slave) -{ - if ((bond == NULL) || (slave == NULL) || - ((void *)bond == (void *)slave)) { - printk(KERN_ERR - "bond_detach_slave(): trying to detach " - "slave %p from bond %p\n", bond, slave); - return slave; - } - - if (bond->next == slave) { /* is the slave at the head ? */ - if (bond->prev == slave) { /* is the slave alone ? */ - bond->prev = bond->next = (slave_t *)bond; - } else { /* not alone */ - bond->next = slave->next; - slave->next->prev = (slave_t *)bond; - bond->prev->next = slave->next; - } - } else { - slave->prev->next = slave->next; - if (bond->prev == slave) { /* is this slave the last one ? */ - bond->prev = slave->prev; - } else { - slave->next->prev = slave->prev; - } - } - - update_slave_cnt(bond, -1); - - return slave; -} - -/* - * This function attaches the slave to the list . - * - * bond->lock held for writing by caller. - */ -static void -bond_attach_slave(struct bonding *bond, struct slave *new_slave) -{ - /* - * queue to the end of the slaves list, make the first element its - * successor, the last one its predecessor, and make it the bond's - * predecessor. - * - * Just to clarify, so future bonding driver hackers don't go through - * the same confusion stage I did trying to figure this out, the - * slaves are stored in a double linked circular list, sortof. - * In the ->next direction, the last slave points to the first slave, - * bypassing bond; only the slaves are in the ->next direction. - * In the ->prev direction, however, the first slave points to bond - * and bond points to the last slave. - * - * It looks like a circle with a little bubble hanging off one side - * in the ->prev direction only. - * - * When going through the list once, its best to start at bond->prev - * and go in the ->prev direction, testing for bond. Doing this - * in the ->next direction doesn't work. Trust me, I know this now. - * :) -mts 2002.03.14 - */ - new_slave->prev = bond->prev; - new_slave->prev->next = new_slave; - bond->prev = new_slave; - new_slave->next = bond->next; - - update_slave_cnt(bond, 1); -} - - -/* - * Less bad way to call ioctl from within the kernel; this needs to be - * done some other way to get the call out of interrupt context. - * Needs "ioctl" variable to be supplied by calling context. - */ -#define IOCTL(dev, arg, cmd) ({ \ - int ret; \ - mm_segment_t fs = get_fs(); \ - set_fs(get_ds()); \ - ret = ioctl(dev, arg, cmd); \ - set_fs(fs); \ - ret; }) +/*------------------------------- Link status -------------------------------*/ /* * Get link speed and duplex from the slave's base driver @@ -809,52 +618,63 @@ bond_attach_slave(struct bonding *bond, */ static int bond_update_speed_duplex(struct slave *slave) { - struct net_device *dev = slave->dev; + struct net_device *slave_dev = slave->dev; static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct ethtool_cmd etool; - ioctl = dev->do_ioctl; - if (ioctl) { - etool.cmd = ETHTOOL_GSET; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { - slave->speed = etool.speed; - slave->duplex = etool.duplex; - } else { - goto err_out; + /* Fake speed and duplex */ + slave->speed = SPEED_100; + slave->duplex = DUPLEX_FULL; + + if (slave_dev->ethtool_ops) { + u32 res; + + if (!slave_dev->ethtool_ops->get_settings) { + return -1; } - } else { - goto err_out; + + res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool); + if (res < 0) { + return -1; + } + + goto verify; } - switch (slave->speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - break; - default: - goto err_out; + ioctl = slave_dev->do_ioctl; + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GSET; + ifr.ifr_data = (char*)&etool; + if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) { + return -1; + } + +verify: + switch (etool.speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + break; + default: + return -1; } - switch (slave->duplex) { - case DUPLEX_FULL: - case DUPLEX_HALF: - break; - default: - goto err_out; + switch (etool.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: + return -1; } - return 0; + slave->speed = etool.speed; + slave->duplex = etool.duplex; -err_out: - /* Fake speed and duplex */ - slave->speed = SPEED_100; - slave->duplex = DUPLEX_FULL; - return -1; + return 0; } -/* +/* * if supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), @@ -870,8 +690,7 @@ err_out: * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */ -static int -bond_check_dev_link(struct net_device *dev, int reporting) +static int bond_check_dev_link(struct net_device *slave_dev, int reporting) { static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; @@ -879,10 +698,10 @@ bond_check_dev_link(struct net_device *d struct ethtool_value etool; if (use_carrier) { - return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0; + return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; } - ioctl = dev->do_ioctl; + ioctl = slave_dev->do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ /* bases to make this more efficient. that is, once */ @@ -897,477 +716,510 @@ bond_check_dev_link(struct net_device *d */ /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); mii = (struct mii_ioctl_data *)&ifr.ifr_data; - if (IOCTL(dev, &ifr, SIOCGMIIPHY) == 0) { + if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; - if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) { - return mii->val_out & BMSR_LSTATUS; + if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { + return (mii->val_out & BMSR_LSTATUS); } } + } + + /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ + /* for a period of time so we attempt to get link status */ + /* from it last if the above MII ioctls fail... */ + if (slave_dev->ethtool_ops) { + if (slave_dev->ethtool_ops->get_link) { + u32 link; + + link = slave_dev->ethtool_ops->get_link(slave_dev); + + return link ? BMSR_LSTATUS : 0; + } + } - /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ - /* for a period of time so we attempt to get link status */ - /* from it last if the above MII ioctls fail... */ - etool.cmd = ETHTOOL_GLINK; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { + if (ioctl) { + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (char*)&etool; + if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { if (etool.data == 1) { return BMSR_LSTATUS; - } else { -#ifdef BONDING_DEBUG - printk(KERN_INFO - ":: SIOCETHTOOL shows link down \n"); -#endif + } else { + dprintk("SIOCETHTOOL shows link down\n"); return 0; - } + } } - } - + /* * If reporting, report that either there's no dev->do_ioctl, * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we * cannot report link status). If not reporting, pretend * we're ok. */ - return reporting ? -1 : BMSR_LSTATUS; + return (reporting ? -1 : BMSR_LSTATUS); } -static u16 bond_check_mii_link(bonding_t *bond) -{ - int has_active_interface = 0; - - read_lock_bh(&bond->lock); - read_lock(&bond->ptrlock); - has_active_interface = (bond->current_slave != NULL); - read_unlock(&bond->ptrlock); - read_unlock_bh(&bond->lock); +/*----------------------------- Multicast list ------------------------------*/ - return (has_active_interface ? BMSR_LSTATUS : 0); +/* + * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise + */ +static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) +{ + return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && + dmi1->dmi_addrlen == dmi2->dmi_addrlen; } -/* register to receive lacpdus on a bond */ -static void bond_register_lacpdu(struct bonding *bond) +/* + * returns dmi entry if found, NULL otherwise + */ +static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) { - struct packet_type* pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); + struct dev_mc_list *idmi; - /* initialize packet type */ - pk_type->type = PKT_TYPE_LACPDU; - pk_type->dev = bond->device; - pk_type->func = bond_3ad_lacpdu_recv; + for (idmi = mc_list; idmi; idmi = idmi->next) { + if (bond_is_dmi_same(dmi, idmi)) { + return idmi; + } + } - dev_add_pack(pk_type); + return NULL; } -/* unregister to receive lacpdus on a bond */ -static void bond_unregister_lacpdu(struct bonding *bond) +/* + * Push the promiscuity flag down to appropriate slaves + */ +static void bond_set_promiscuity(struct bonding *bond, int inc) { - dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_promiscuity(bond->curr_active_slave->dev, inc); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_promiscuity(slave->dev, inc); + } + } } -static int bond_open(struct net_device *dev) +/* + * Push the allmulti flag down to all slaves + */ +static void bond_set_allmulti(struct bonding *bond, int inc) { - struct bonding *bond = (struct bonding *)(dev->priv); - struct timer_list *timer = &((struct bonding *)(dev->priv))->mii_timer; - struct timer_list *arp_timer = &((struct bonding *)(dev->priv))->arp_timer; - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); - - /* bond_alb_initialize must be called before the timer - * is started. - */ - if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) { - /* something went wrong - fail the open operation */ - return -1; + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_allmulti(bond->curr_active_slave->dev, inc); } - - init_timer(alb_timer); - alb_timer->expires = jiffies + 1; - alb_timer->data = (unsigned long)bond; - alb_timer->function = (void *)&bond_alb_monitor; - add_timer(alb_timer); - } - - if (miimon > 0) { /* link check interval, in milliseconds. */ - init_timer(timer); - timer->expires = jiffies + (miimon * HZ / 1000); - timer->data = (unsigned long)dev; - timer->function = (void *)&bond_mii_monitor; - add_timer(timer); - } - - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - init_timer(arp_timer); - arp_timer->expires = jiffies + (arp_interval * HZ / 1000); - arp_timer->data = (unsigned long)dev; - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - arp_timer->function = (void *)&activebackup_arp_monitor; - } else { - arp_timer->function = (void *)&loadbalance_arp_monitor; + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_allmulti(slave->dev, inc); } - add_timer(arp_timer); } +} - if (bond_mode == BOND_MODE_8023AD) { - struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); - init_timer(ad_timer); - ad_timer->expires = jiffies + (AD_TIMER_INTERVAL * HZ / 1000); - ad_timer->data = (unsigned long)bond; - ad_timer->function = (void *)&bond_3ad_state_machine_handler; - add_timer(ad_timer); - - /* register to receive LACPDUs */ - bond_register_lacpdu(bond); +/* + * Add a Multicast address to slaves + * according to mode + */ +static void bond_mc_add(struct bonding *bond, void *addr, int alen) +{ + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_mc_add(slave->dev, addr, alen, 0); + } } - - return 0; } -static int bond_close(struct net_device *master) +/* + * Remove a multicast address from slave + * according to mode + */ +static void bond_mc_delete(struct bonding *bond, void *addr, int alen) { - bonding_t *bond = (struct bonding *) master->priv; - - write_lock_bh(&bond->lock); - - if (miimon > 0) { /* link check interval, in milliseconds. */ - del_timer(&bond->mii_timer); - } - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - del_timer(&bond->arp_timer); - if (arp_target_hw_addr != NULL) { - kfree(arp_target_hw_addr); - arp_target_hw_addr = NULL; + if (USES_PRIMARY(bond_mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_mc_delete(slave->dev, addr, alen, 0); } } +} - if (bond_mode == BOND_MODE_8023AD) { - del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); +/* + * Totally destroys the mc_list in bond + */ +static void bond_mc_list_destroy(struct bonding *bond) +{ + struct dev_mc_list *dmi; - /* Unregister the receive of LACPDUs */ - bond_unregister_lacpdu(bond); + dmi = bond->mc_list; + while (dmi) { + bond->mc_list = dmi->next; + kfree(dmi); + dmi = bond->mc_list; } +} - bond_mc_list_destroy (bond); - - write_unlock_bh(&bond->lock); +/* + * Copy all the Multicast addresses from src to the bonding device dst + */ +static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, int gpf_flag) +{ + struct dev_mc_list *dmi, *new_dmi; - /* Release the bonded slaves */ - bond_release_all(master); + for (dmi = mc_list; dmi; dmi = dmi->next) { + new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + if (!new_dmi) { + /* FIXME: Potential memory leak !!! */ + return -ENOMEM; + } - bond_alb_deinitialize(bond); + new_dmi->next = bond->mc_list; + bond->mc_list = new_dmi; + new_dmi->dmi_addrlen = dmi->dmi_addrlen; + memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); + new_dmi->dmi_users = dmi->dmi_users; + new_dmi->dmi_gusers = dmi->dmi_gusers; } return 0; } -/* +/* * flush all members of flush->mc_list from device dev->mc_list */ -static void bond_mc_list_flush(struct net_device *dev, struct net_device *flush) -{ - struct dev_mc_list *dmi; - - for (dmi = flush->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); +static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct dev_mc_list *dmi; + + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } if (bond_mode == BOND_MODE_8023AD) { /* del lacpdu mc addr from mc list */ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; - dev_mc_delete(dev, lacpdu_multicast, ETH_ALEN, 0); + dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0); } } +/*--------------------------- Active slave change ---------------------------*/ + /* - * Totally destroys the mc_list in bond + * Update the mc list and multicast-related flags for the new and + * old active slaves (if any) according to the multicast mode, and + * promiscuous flags unconditionally. */ -static void bond_mc_list_destroy(struct bonding *bond) +static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) { struct dev_mc_list *dmi; - dmi = bond->mc_list; - while (dmi) { - bond->mc_list = dmi->next; - kfree(dmi); - dmi = bond->mc_list; - } -} - -/* - * Add a Multicast address to every slave in the bonding group - */ -static void bond_mc_add(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_add(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_mc_add(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; + if (!USES_PRIMARY(bond_mode)) { + /* nothing to do - mc list is already up-to-date on + * all slaves + */ + return; } -} -/* - * Remove a multicast address from every slave in the bonding group - */ -static void bond_mc_delete(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_delete(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_mc_delete(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; - } -} + if (old_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(old_active->dev, -1); + } -/* - * Copy all the Multicast addresses from src to the bonding device dst - */ -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, - int gpf_flag) -{ - struct dev_mc_list *dmi, *new_dmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(old_active->dev, -1); + } - for (dmi = src; dmi != NULL; dmi = dmi->next) { - new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } - if (new_dmi == NULL) { - return -ENOMEM; + if (new_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(new_active->dev, 1); } - new_dmi->next = dst->mc_list; - dst->mc_list = new_dmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(new_active->dev, 1); + } - new_dmi->dmi_addrlen = dmi->dmi_addrlen; - memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); - new_dmi->dmi_users = dmi->dmi_users; - new_dmi->dmi_gusers = dmi->dmi_gusers; - } - return 0; + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } } -/* - * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise - */ -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) -{ - return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && - dmi1->dmi_addrlen == dmi2->dmi_addrlen; -} - -/* - * Push the promiscuity flag down to appropriate slaves +/** + * find_best_interface - select the best available slave to be the active one + * @bond: our bonding struct + * + * Warning: Caller must hold curr_slave_lock for writing. */ -static void bond_set_promiscuity(bonding_t *bond, int inc) -{ - slave_t *slave; +static struct slave *bond_find_best_slave(struct bonding *bond) +{ + struct slave *new_active, *old_active; + struct slave *bestslave = NULL; + int mintime; + int i; - if (USES_PRIMARY(bond_mode)) { - if (bond->current_slave) { - dev_set_promiscuity(bond->current_slave->dev, inc); - } + new_active = old_active = bond->curr_active_slave; - } else { - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - dev_set_promiscuity(slave->dev, inc); + if (!new_active) { /* there were no active slaves left */ + if (bond->slave_cnt > 0) { /* found one slave */ + new_active = bond->first_slave; + } else { + return NULL; /* still no slave, return NULL */ } } -} -/* - * Push the allmulti flag down to all slaves - */ -static void bond_set_allmulti(bonding_t *bond, int inc) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_set_allmulti(bond->current_slave->dev, inc); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_set_allmulti(slave->dev, inc); - break; - case BOND_MULTICAST_DISABLED : - break; + mintime = updelay; + + /* first try the primary link; if arping, a link must tx/rx traffic + * before it can be considered the curr_active_slave - also, we would skip + * slaves between the curr_active_slave and primary_slave that may be up + * and able to arp + */ + if ((bond->primary_slave) && + (!arp_interval) && + (IS_UP(bond->primary_slave->dev))) { + new_active = bond->primary_slave; } -} -/* - * returns dmi entry if found, NULL otherwise - */ -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, - struct dev_mc_list *mc_list) -{ - struct dev_mc_list *idmi; + /* remember where to stop iterating over the slaves */ + old_active = new_active; - for (idmi = mc_list; idmi != NULL; idmi = idmi->next) { - if (dmi_same(dmi, idmi)) { - return idmi; + bond_for_each_slave_from(bond, new_active, i, old_active) { + if (IS_UP(new_active->dev)) { + if (new_active->link == BOND_LINK_UP) { + return new_active; + } else if (new_active->link == BOND_LINK_BACK) { + /* link up, but waiting for stabilization */ + if (new_active->delay < mintime) { + mintime = new_active->delay; + bestslave = new_active; + } + } } } - return NULL; -} -static void set_multicast_list(struct net_device *master) + return bestslave; +} + +/** + * change_active_interface - change the active slave into the specified one + * @bond: our bonding struct + * @new: the new slave to make the active one + * + * Set the new slave to the bond's settings and unset them on the old + * curr_active_slave. + * Setting include flags, mc-list, promiscuity, allmulti, etc. + * + * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, + * because it is apparently the best available slave we have, even though its + * updelay hasn't timed out yet. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { - bonding_t *bond = master->priv; - struct dev_mc_list *dmi; + struct slave *old_active = bond->curr_active_slave; - write_lock_bh(&bond->lock); + if (old_active == new_active) { + return; + } - /* - * Do promisc before checking multicast_mode - */ - if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, 1); + if (new_active) { + if (new_active->link == BOND_LINK_BACK) { + if (USES_PRIMARY(bond_mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one %d ms earlier.\n", + bond->dev->name, new_active->dev->name, + (updelay - new_active->delay) * miimon); + } - if ( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, -1); + new_active->delay = 0; + new_active->link = BOND_LINK_UP; + new_active->jiffies = jiffies; - if (multicast_mode == BOND_MULTICAST_DISABLED) { - bond->flags = master->flags; - write_unlock_bh(&bond->lock); - return; + if (bond_mode == BOND_MODE_8023AD) { + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + } + + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } + } else { + if (USES_PRIMARY(bond_mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one.\n", + bond->dev->name, new_active->dev->name); + } + } } - /* set allmulti flag to slaves */ - if ( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, 1); + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { + if (old_active) { + bond_set_slave_inactive_flags(old_active); + } + + if (new_active) { + bond_set_slave_active_flags(new_active); + } + } - if ( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, -1); + if (USES_PRIMARY(bond_mode)) { + bond_mc_swap(bond, new_active, old_active); + } - bond->flags = master->flags; + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + bond_alb_handle_active_change(bond, new_active); + } else { + bond->curr_active_slave = new_active; + } +} - /* looking for addresses to add to slaves' mc list */ - for (dmi = master->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, bond->mc_list) == NULL) - bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } +/** + * bond_select_active_slave - select a new active slave, if needed + * @bond: our bonding struct + * + * This functions shoud be called when one of the following occurs: + * - The old curr_active_slave has been released or lost its link. + * - The primary_slave has got its link back. + * - A slave has got its link back and there's no old curr_active_slave. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_select_active_slave(struct bonding *bond) +{ + struct slave *best_slave; - /* looking for addresses to delete from slaves' list */ - for (dmi = bond->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, master->mc_list) == NULL) - bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); + best_slave = bond_find_best_slave(bond); + if (best_slave != bond->curr_active_slave) { + bond_change_active_slave(bond, best_slave); } +} +/*--------------------------- slave list handling ---------------------------*/ - /* save master's multicast list */ - bond_mc_list_destroy (bond); - bond_mc_list_copy (master->mc_list, bond, GFP_ATOMIC); +/* + * This function attaches the slave to the end of list. + * + * bond->lock held for writing by caller. + */ +static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) +{ + if (bond->first_slave == NULL) { /* attaching the first slave */ + new_slave->next = new_slave; + new_slave->prev = new_slave; + bond->first_slave = new_slave; + } else { + new_slave->next = bond->first_slave; + new_slave->prev = bond->first_slave->prev; + new_slave->next->prev = new_slave; + new_slave->prev->next = new_slave; + } - write_unlock_bh(&bond->lock); + bond->slave_cnt++; } /* - * Update the mc list and multicast-related flags for the new and - * old active slaves (if any) according to the multicast mode, and - * promiscuous flags unconditionally. + * This function detaches the slave from the list. + * WARNING: no check is made to verify if the slave effectively + * belongs to . + * Nothing is freed on return, structures are just unchained. + * If any slave pointer in bond was pointing to , + * it should be changed by the calling function. + * + * bond->lock held for writing by caller. */ -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old) +static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - struct dev_mc_list *dmi; + if (slave->next) { + slave->next->prev = slave->prev; + } - if (USES_PRIMARY(bond_mode)) { - if (bond->device->flags & IFF_PROMISC) { - if (old) - dev_set_promiscuity(old->dev, -1); - if (new) - dev_set_promiscuity(new->dev, 1); - } + if (slave->prev) { + slave->prev->next = slave->next; } - switch(multicast_mode) { - case BOND_MULTICAST_ACTIVE : - if (bond->device->flags & IFF_ALLMULTI) { - if (old) - dev_set_allmulti(old->dev, -1); - if (new) - dev_set_allmulti(new->dev, 1); - } - /* first remove all mc addresses from old slave if any, - and _then_ add them to new active slave */ - if (old) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(old->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } - if (new) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + if (bond->first_slave == slave) { /* slave is the first slave */ + if (bond->slave_cnt > 1) { /* there are more slave */ + bond->first_slave = slave->next; + } else { + bond->first_slave = NULL; /* slave was the last one */ } - break; - case BOND_MULTICAST_ALL : - /* nothing to do: mc list is already up-to-date on all slaves */ - break; - case BOND_MULTICAST_DISABLED : - break; } + + slave->next = NULL; + slave->prev = NULL; + bond->slave_cnt--; +} + +/*---------------------------------- IOCTL ----------------------------------*/ + +static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) +{ + dprintk("bond_dev=%p\n", bond_dev); + dprintk("slave_dev=%p\n", slave_dev); + dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len); + memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); + return 0; } /* enslave device to bond device */ -static int bond_enslave(struct net_device *master_dev, - struct net_device *slave_dev) +static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond = NULL; - slave_t *new_slave = NULL; - unsigned long rflags = 0; - int err = 0; + struct bonding *bond = bond_dev->priv; + struct slave *new_slave = NULL; struct dev_mc_list *dmi; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; - int link_reporting; struct sockaddr addr; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } - bond = (struct bonding *) master_dev->priv; + int link_reporting; + int res = 0; if (slave_dev->do_ioctl == NULL) { - printk(KERN_DEBUG - "Warning : no link monitoring support for %s\n", - slave_dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning : no link monitoring support for %s\n", + slave_dev->name); } - /* bond must be initialized by bond_open() before enslaving */ - if (!(master_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, master_dev is not up\n"); -#endif + if (!(bond_dev->flags & IFF_UP)) { + dprintk("Error, master_dev is not up\n"); return -EPERM; } /* already enslaved */ - if (master_dev->flags & IFF_SLAVE || slave_dev->flags & IFF_SLAVE) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, Device was already enslaved\n"); -#endif + if (slave_dev->flags & IFF_SLAVE) { + dprintk("Error, Device was already enslaved\n"); return -EBUSY; } @@ -1376,19 +1228,19 @@ static int bond_enslave(struct net_devic * slave interface to be closed. */ if ((slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is up\n"); -#endif + printk(KERN_ERR DRV_NAME + ": Error: %s is up\n", + slave_dev->name); return -EPERM; } if (slave_dev->set_mac_address == NULL) { - printk(KERN_CRIT - "The slave device you specified does not support" - " setting the MAC address.\n"); - printk(KERN_CRIT - "Your kernel likely does not support slave" - " devices.\n"); + printk(KERN_ERR DRV_NAME + ": Error: The slave device you specified does " + "not support setting the MAC address.\n"); + printk(KERN_ERR + "Your kernel likely does not support slave " + "devices.\n"); return -EOPNOTSUPP; } @@ -1397,26 +1249,29 @@ static int bond_enslave(struct net_devic * slave interface to be open. */ if (!(slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is not running\n"); -#endif + printk(KERN_ERR DRV_NAME + ": Error: %s is not running\n", + slave_dev->name); return -EINVAL; } if ((bond_mode == BOND_MODE_8023AD) || - (bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - printk(KERN_ERR - "bonding: Error: to use %s mode, you must " - "upgrade ifenslave.\n", bond_mode_name()); + printk(KERN_ERR DRV_NAME + ": Error: to use %s mode, you must upgrade " + "ifenslave.\n", + bond_mode_name()); return -EOPNOTSUPP; } } - if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { + new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + if (!new_slave) { return -ENOMEM; } - memset(new_slave, 0, sizeof(slave_t)); + + memset(new_slave, 0, sizeof(struct slave)); /* save slave's original flags before calling * netdev_set_master and dev_open @@ -1430,37 +1285,29 @@ static int bond_enslave(struct net_devic */ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); - if (bond->slave_cnt > 0) { - /* set slave to master's mac address - * The application already set the master's - * mac address to that of the first slave - */ - memcpy(addr.sa_data, master_dev->dev_addr, master_dev->addr_len); - addr.sa_family = slave_dev->type; - err = slave_dev->set_mac_address(slave_dev, &addr); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling set_mac_address\n", err); -#endif - goto err_free; - } + /* set slave to master's mac address + * The application already set the master's + * mac address to that of the first slave + */ + memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + addr.sa_family = slave_dev->type; + res = slave_dev->set_mac_address(slave_dev, &addr); + if (res) { + dprintk("Error %d calling set_mac_address\n", res); + goto err_free; } /* open the slave since the application closed it */ - err = dev_open(slave_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Openning slave %s failed\n", slave_dev->name); -#endif + res = dev_open(slave_dev); + if (res) { + dprintk("Openning slave %s failed\n", slave_dev->name); goto err_restore_mac; } } - err = netdev_set_master(slave_dev, master_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling netdev_set_master\n", err); -#endif + res = netdev_set_master(slave_dev, bond_dev); + if (res) { + dprintk("Error %d calling netdev_set_master\n", res); if (app_abi_ver < 1) { goto err_free; } else { @@ -1475,32 +1322,32 @@ static int bond_enslave(struct net_devic /* bond_alb_init_slave() must be called before all other stages since * it might fail and we do not want to have to undo everything */ - err = bond_alb_init_slave(bond, new_slave); - if (err) { + res = bond_alb_init_slave(bond, new_slave); + if (res) { goto err_unset_master; } } - /* set promiscuity level to new slave */ - if (master_dev->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then the new slave gets the - * master's promisc (and mc) settings only if it becomes the - * current_slave, and that is taken care of later when calling - * bond_change_active() - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, 1); + /* If the mode USES_PRIMARY, then the new slave gets the + * master's promisc (and mc) settings only if it becomes the + * curr_active_slave, and that is taken care of later when calling + * bond_change_active() + */ + if (!USES_PRIMARY(bond_mode)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, 1); } - } - - if (multicast_mode == BOND_MULTICAST_ALL) { + /* set allmulti level to new slave */ - if (master_dev->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, 1); - - /* upload master's mc_list to new slave */ - for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, 1); + } + + /* upload master's mc_list to new slave */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } } if (bond_mode == BOND_MODE_8023AD) { @@ -1511,15 +1358,16 @@ static int bond_enslave(struct net_devic } write_lock_bh(&bond->lock); - + bond_attach_slave(bond, new_slave); + new_slave->delay = 0; new_slave->link_failure_count = 0; - if (miimon > 0 && !use_carrier) { + if (miimon && !use_carrier) { link_reporting = bond_check_dev_link(slave_dev, 1); - if ((link_reporting == -1) && (arp_interval == 0)) { + if ((link_reporting == -1) && !arp_interval) { /* * miimon is set but a bonded network driver * does not support ETHTOOL/MII and @@ -1528,115 +1376,97 @@ static int bond_enslave(struct net_devic * here (because netif_carrier is always * supported); thus, we don't need to change * the messages for netif_carrier. - */ - printk(KERN_ERR - "bond_enslave(): MII and ETHTOOL support not " - "available for interface %s, and " - "arp_interval/arp_ip_target module parameters " - "not specified, thus bonding will not detect " - "link failures! see bonding.txt for details.\n", - slave_dev->name); + */ + printk(KERN_WARNING DRV_NAME + ": Warning: MII and ETHTOOL support not " + "available for interface %s, and " + "arp_interval/arp_ip_target module parameters " + "not specified, thus bonding will not detect " + "link failures! see bonding.txt for details.\n", + slave_dev->name); } else if (link_reporting == -1) { - /* unable get link status using mii/ethtool */ - printk(KERN_WARNING - "bond_enslave: can't get link status from " + /* unable get link status using mii/ethtool */ + printk(KERN_WARNING DRV_NAME + ": Warning: can't get link status from " "interface %s; the network driver associated " - "with this interface does not support " - "MII or ETHTOOL link status reporting, thus " - "miimon has no effect on this interface.\n", + "with this interface does not support MII or " + "ETHTOOL link status reporting, thus miimon " + "has no effect on this interface.\n", slave_dev->name); } } /* check for initial state */ - if ((miimon <= 0) || + if (!miimon || (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) { if (updelay) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " - "BOND_LINK_BACK\n"); -#endif + dprintk("Initial state of slave_dev is " + "BOND_LINK_BACK\n"); new_slave->link = BOND_LINK_BACK; new_slave->delay = updelay; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "Initial state of slave_dev is " + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_UP\n"); -#endif new_slave->link = BOND_LINK_UP; } new_slave->jiffies = jiffies; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_DOWN\n"); -#endif new_slave->link = BOND_LINK_DOWN; } if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - - printk(KERN_WARNING - "bond_enslave(): failed to get speed/duplex from %s, " - "speed forced to 100Mbps, duplex forced to Full.\n", + printk(KERN_WARNING DRV_NAME + ": Warning: failed to get speed/duplex from %s, speed " + "forced to 100Mbps, duplex forced to Full.\n", new_slave->dev->name); + if (bond_mode == BOND_MODE_8023AD) { printk(KERN_WARNING - "Operation of 802.3ad mode requires ETHTOOL support " - "in base driver for proper aggregator selection.\n"); + "Operation of 802.3ad mode requires ETHTOOL " + "support in base driver for proper aggregator " + "selection.\n"); } } - /* if we're in active-backup mode, we need one and only one active - * interface. The backup interfaces will have their NOARP flag set - * because we need them to be completely deaf and not to respond to - * any ARP request on the network to avoid fooling a switch. Thus, - * since we guarantee that current_slave always point to the last - * usable interface, we just have to verify this interface's flag. - */ - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (((bond->current_slave == NULL) - || (bond->current_slave->dev->flags & IFF_NOARP)) - && (new_slave->link != BOND_LINK_DOWN)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is the first active slave\n"); -#endif + if (USES_PRIMARY(bond_mode) && primary) { + /* if there is a primary slave, remember it */ + if (strcmp(primary, new_slave->dev->name) == 0) { + bond->primary_slave = new_slave; + } + } + + switch (bond_mode) { + case BOND_MODE_ACTIVEBACKUP: + /* if we're in active-backup mode, we need one and only one active + * interface. The backup interfaces will have their NOARP flag set + * because we need them to be completely deaf and not to respond to + * any ARP request on the network to avoid fooling a switch. Thus, + * since we guarantee that curr_active_slave always point to the last + * usable interface, we just have to verify this interface's flag. + */ + if (((!bond->curr_active_slave) || + (bond->curr_active_slave->dev->flags & IFF_NOARP)) && + (new_slave->link != BOND_LINK_DOWN)) { + dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is just a backup slave\n"); -#endif + bond_change_active_slave(bond, new_slave); + } else { + dprintk("This is just a backup slave\n"); bond_set_slave_inactive_flags(new_slave); } - if (((struct in_device *)slave_dev->ip_ptr) != NULL) { - read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list); - ifa = *ifap; - if (ifa != NULL) - my_ip = ifa->ifa_address; - read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - } - - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else if (bond_mode == BOND_MODE_8023AD) { + break; + case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism * will activate the slaves in the selected * aggregator */ bond_set_slave_inactive_flags(new_slave); /* if this is the first slave */ - if (new_slave == bond->next) { + if (bond->slave_cnt == 1) { SLAVE_AD_INFO(new_slave).id = 1; /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set @@ -1645,40 +1475,37 @@ static int bond_enslave(struct net_devic lacp_fast); } else { SLAVE_AD_INFO(new_slave).id = - SLAVE_AD_INFO(new_slave->prev).id + 1; + SLAVE_AD_INFO(new_slave->prev).id + 1; } bond_3ad_bind_slave(new_slave); - } else if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: new_slave->state = BOND_STATE_ACTIVE; - if ((bond->current_slave == NULL) && (new_slave->link != BOND_LINK_DOWN)) { + if ((!bond->curr_active_slave) && + (new_slave->link != BOND_LINK_DOWN)) { /* first slave or no active slave yet, and this link * is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); + bond_change_active_slave(bond, new_slave); } + break; + default: + dprintk("This slave is always active in trunk mode\n"); - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This slave is always active in trunk mode\n"); -#endif /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; - /* In trunking mode there is little meaning to current_slave + /* In trunking mode there is little meaning to curr_active_slave * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (bond->current_slave == NULL) - bond->current_slave = new_slave; - } + if (!bond->curr_active_slave) { + bond->curr_active_slave = new_slave; + } + break; + } /* switch(bond_mode) */ write_unlock_bh(&bond->lock); @@ -1692,38 +1519,34 @@ static int bond_enslave(struct net_devic */ int ndx = 0; - for (ndx = 0; ndx < slave_dev->addr_len; ndx++) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Checking ndx=%d of master_dev->dev_addr\n", ndx); -#endif - if (master_dev->dev_addr[ndx] != 0) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Found non-zero byte at ndx=%d\n", ndx); -#endif + for (ndx = 0; ndx < bond_dev->addr_len; ndx++) { + dprintk("Checking ndx=%d of bond_dev->dev_addr\n", + ndx); + if (bond_dev->dev_addr[ndx] != 0) { + dprintk("Found non-zero byte at ndx=%d\n", + ndx); break; } } - if (ndx == slave_dev->addr_len) { + + if (ndx == bond_dev->addr_len) { /* * We got all the way through the address and it was * all 0's. */ -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "%s doesn't have a MAC address yet. ", - master_dev->name); - printk(KERN_DEBUG "Going to give assign it from %s.\n", - slave_dev->name); -#endif - bond_sethwaddr(master_dev, slave_dev); + dprintk("%s doesn't have a MAC address yet. \n", + bond_dev->name); + dprintk("Going to give assign it from %s.\n", + slave_dev->name); + bond_sethwaddr(bond_dev, slave_dev); } } - printk (KERN_INFO "%s: enslaving %s as a%s interface with a%s link.\n", - master_dev->name, slave_dev->name, - new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", - new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); + printk(KERN_INFO DRV_NAME + ": %s: enslaving %s as a%s interface with a%s link.\n", + bond_dev->name, slave_dev->name, + new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", + new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); /* enslave is successful */ return 0; @@ -1742,435 +1565,210 @@ err_restore_mac: err_free: kfree(new_slave); - return err; + return res; } -/* - * This function changes the active slave to slave . - * It returns -EINVAL in the following cases. - * - is not found in the list. - * - There is not active slave now. - * - is already active. - * - The link state of is not BOND_LINK_UP. - * - is not running. - * In these cases, this fuction does nothing. - * In the other cases, currnt_slave pointer is changed and 0 is returned. +/* + * Try to release the slave device from the bond device + * It is legal to access curr_active_slave without a lock because all the function + * is write-locked. + * + * The rules for slave state should be: + * for Active/Backup: + * Active stays on all backups go down + * for Bonded connections: + * The first up interface should be left on and all others downed. */ -static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) +static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond; - slave_t *slave; - slave_t *oldactive = NULL; - slave_t *newactive = NULL; - int ret = 0; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; + struct sockaddr addr; + int mac_addr_differ; - /* Verify that master_dev is indeed the master of slave_dev */ + /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || - (slave_dev->master != master_dev)) { - + (slave_dev->master != bond_dev)) { + printk(KERN_ERR DRV_NAME + ": Error: %s: cannot release %s.\n", + bond_dev->name, slave_dev->name); return -EINVAL; } - bond = (struct bonding *) master_dev->priv; write_lock_bh(&bond->lock); - slave = (slave_t *)bond; - oldactive = bond->current_slave; - while ((slave = slave->prev) != (slave_t *)bond) { - if(slave_dev == slave->dev) { - newactive = slave; - break; - } + slave = bond_get_slave_by_dev(bond, slave_dev); + if (!slave) { + /* not a slave of this bond */ + printk(KERN_INFO DRV_NAME + ": %s: %s not enslaved\n", + bond_dev->name, slave_dev->name); + return -EINVAL; } - /* - * Changing to the current active: do nothing; return success. - */ - if (newactive && (newactive == oldactive)) { - write_unlock_bh(&bond->lock); - return 0; + mac_addr_differ = memcmp(bond_dev->dev_addr, + slave->perm_hwaddr, + ETH_ALEN); + if (!mac_addr_differ && (bond->slave_cnt > 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: the permanent HWaddr of %s " + "- %02X:%02X:%02X:%02X:%02X:%02X - is " + "still in use by %s. Set the HWaddr of " + "%s to a different address to avoid " + "conflicts.\n", + slave_dev->name, + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5], + bond_dev->name, + slave_dev->name); } - if ((newactive != NULL)&& - (oldactive != NULL)&& - (newactive->link == BOND_LINK_UP)&& - IS_UP(newactive->dev)) { - change_active_interface(bond, newactive); - } else { - ret = -EINVAL; + /* Inform AD package of unbinding of slave. */ + if (bond_mode == BOND_MODE_8023AD) { + /* must be called before the slave is + * detached from the list + */ + bond_3ad_unbind_slave(slave); } - write_unlock_bh(&bond->lock); - return ret; -} -/** - * find_best_interface - select the best available slave to be the active one - * @bond: our bonding struct - * - * Warning: Caller must hold ptrlock for writing. - */ -static struct slave *find_best_interface(struct bonding *bond) -{ - struct slave *newslave, *oldslave; - struct slave *bestslave = NULL; - int mintime; + printk(KERN_INFO DRV_NAME + ": %s: releasing %s interface %s\n", + bond_dev->name, + (slave->state == BOND_STATE_ACTIVE) + ? "active" : "backup", + slave_dev->name); - newslave = oldslave = bond->current_slave; + oldcurrent = bond->curr_active_slave; - if (newslave == NULL) { /* there were no active slaves left */ - if (bond->next != (slave_t *)bond) { /* found one slave */ - newslave = bond->next; - } else { - return NULL; /* still no slave, return NULL */ - } - } + bond->current_arp_slave = NULL; - mintime = updelay; + /* release the slave from its bond */ + bond_detach_slave(bond, slave); - /* first try the primary link; if arping, a link must tx/rx traffic - * before it can be considered the current_slave - also, we would skip - * slaves between the current_slave and primary_slave that may be up - * and able to arp - */ - if ((bond->primary_slave != NULL) && (arp_interval == 0)) { - if (IS_UP(bond->primary_slave->dev)) - newslave = bond->primary_slave; + if (bond->primary_slave == slave) { + bond->primary_slave = NULL; } - /* remember where to stop iterating over the slaves */ - oldslave = newslave; - - do { - if (IS_UP(newslave->dev)) { - if (newslave->link == BOND_LINK_UP) { - return newslave; - } - else if (newslave->link == BOND_LINK_BACK) { - /* link up, but waiting for stabilization */ - if (newslave->delay < mintime) { - mintime = newslave->delay; - bestslave = newslave; - } - } - } - } while ((newslave = newslave->next) != oldslave); - - return bestslave; -} - -/** - * change_active_interface - change the active slave into the specified one - * @bond: our bonding struct - * @new: the new slave to make the active one - * - * Set the new slave to the bond's settings and unset them on the old - * current_slave. - * Setting include flags, mc-list, promiscuity, allmulti, etc. - * - * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, - * because it is apparently the best available slave we have, even though its - * updelay hasn't timed out yet. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void change_active_interface(struct bonding *bond, struct slave *new) -{ - struct slave *old = bond->current_slave; - - if (old == new) { - return; + if (oldcurrent == slave) { + bond_change_active_slave(bond, NULL); } - if (new) { - if (new->link == BOND_LINK_BACK) { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new " - "active one %d ms earlier.\n", - bond->device->name, new->dev->name, - (updelay - new->delay) * miimon); - } - - new->delay = 0; - new->link = BOND_LINK_UP; - new->jiffies = jiffies; - - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_handle_link_change(new, BOND_LINK_UP); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_handle_link_change(bond, new, BOND_LINK_UP); - } - } else { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new active one.\n", - bond->device->name, new->dev->name); - } - } + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + /* Must be called only after the slave has been + * detached from the list and the curr_active_slave + * has been cleared (if our_slave == old_current), + * but before a new active slave is selected. + */ + bond_alb_deinit_slave(bond, slave); } - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (old) { - bond_set_slave_inactive_flags(old); - } + if (oldcurrent == slave) { + bond_select_active_slave(bond); - if (new) { - bond_set_slave_active_flags(new); + if (!bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } } - if (USES_PRIMARY(bond_mode)) { - bond_mc_update(bond, new, old); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_assign_current_slave(bond, new); - } else { - bond->current_slave = new; - } -} - -/** - * reselect_active_interface - select a new active slave, if needed - * @bond: our bonding struct - * - * This functions shoud be called when one of the following occurs: - * - The old current_slave has been released or lost its link. - * - The primary_slave has got its link back. - * - A slave has got its link back and there's no old current_slave. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void reselect_active_interface(struct bonding *bond) -{ - struct slave *best_slave; - - best_slave = find_best_interface(bond); - - if (best_slave != bond->current_slave) { - change_active_interface(bond, best_slave); - } -} - -/* - * Try to release the slave device from the bond device - * It is legal to access current_slave without a lock because all the function - * is write-locked. - * - * The rules for slave state should be: - * for Active/Backup: - * Active stays on all backups go down - * for Bonded connections: - * The first up interface should be left on and all others downed. - */ -static int bond_release(struct net_device *master, struct net_device *slave) -{ - bonding_t *bond; - slave_t *our_slave, *old_current; - struct sockaddr addr; - - if (master == NULL || slave == NULL) { - return -ENODEV; - } - - bond = (struct bonding *) master->priv; - - /* master already enslaved, or slave not enslaved, - or no slave for this master */ - if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { - printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); - return -EINVAL; - } - - write_lock_bh(&bond->lock); - bond->current_arp_slave = NULL; - our_slave = (slave_t *)bond; - old_current = bond->current_slave; - while ((our_slave = our_slave->prev) != (slave_t *)bond) { - if (our_slave->dev == slave) { - int mac_addr_differ = memcmp(bond->device->dev_addr, - our_slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) { - printk(KERN_WARNING "WARNING: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - " - "is still in use by %s. Set the HWaddr " - "of %s to a different address " - "to avoid conflicts.\n", - slave->name, - our_slave->perm_hwaddr[0], - our_slave->perm_hwaddr[1], - our_slave->perm_hwaddr[2], - our_slave->perm_hwaddr[3], - our_slave->perm_hwaddr[4], - our_slave->perm_hwaddr[5], - bond->device->name, - slave->name); - } - - /* Inform AD package of unbinding of slave. */ - if (bond_mode == BOND_MODE_8023AD) { - /* must be called before the slave is - * detached from the list - */ - bond_3ad_unbind_slave(our_slave); - } - - printk (KERN_INFO "%s: releasing %s interface %s\n", - master->name, - (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", - slave->name); - - /* release the slave from its bond */ - bond_detach_slave(bond, our_slave); - - if (bond->primary_slave == our_slave) { - bond->primary_slave = NULL; - } - - if (bond->current_slave == our_slave) { - change_active_interface(bond, NULL); - reselect_active_interface(bond); - } - - if (bond->current_slave == NULL) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - /* must be called only after the slave has been - * detached from the list and the current_slave - * has been replaced (if our_slave == old_current) - */ - bond_alb_deinit_slave(bond, our_slave); - } - - break; - } - - } write_unlock_bh(&bond->lock); - - if (our_slave == (slave_t *)bond) { - /* if we get here, it's because the device was not found */ - printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); - return -EINVAL; - } - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then we should only remove its - * promisc settings if it was the current_slave, but that was - * already taken care of above when we detached the slave - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave, -1); + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond_mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); } - } - /* undo settings and restore original values */ - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave, master); + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); + } - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave, -1); + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } - netdev_set_master(slave, NULL); + netdev_set_master(slave_dev, NULL); /* close slave before restoring its mac address */ - dev_close(slave); + dev_close(slave_dev); if (app_abi_ver >= 1) { /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave->type; - slave->set_mac_address(slave, &addr); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + slave_dev->set_mac_address(slave_dev, &addr); } /* restore the original state of the * IFF_NOARP flag that might have been * set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { - slave->flags &= ~IFF_NOARP; + if ((slave->original_flags & IFF_NOARP) == 0) { + slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* if the last slave was removed, zero the mac address * of the master so it will be set by the application * to the mac address of the first slave */ - if (bond->next == (slave_t*)bond) { - memset(master->dev_addr, 0, master->addr_len); + if (bond->slave_cnt == 0) { + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); } return 0; /* deletion OK */ } -/* +/* * This function releases all slaves. */ -static int bond_release_all(struct net_device *master) +static int bond_release_all(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *our_slave, *old_current; + struct bonding *bond = bond_dev->priv; + struct slave *slave; struct net_device *slave_dev; struct sockaddr addr; - int err = 0; - - if (master == NULL) { - return -ENODEV; - } - - if (master->flags & IFF_SLAVE) { - return -EINVAL; - } - - bond = (struct bonding *) master->priv; write_lock_bh(&bond->lock); - if (bond->next == (struct slave *) bond) { - err = -EINVAL; + + if (bond->slave_cnt == 0) { goto out; } - old_current = bond->current_slave; - change_active_interface(bond, NULL); bond->current_arp_slave = NULL; bond->primary_slave = NULL; + bond_change_active_slave(bond, NULL); - while ((our_slave = bond->prev) != (slave_t *)bond) { + while ((slave = bond->first_slave) != NULL) { /* Inform AD package of unbinding of slave * before slave is detached from the list. */ if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_unbind_slave(our_slave); + bond_3ad_unbind_slave(slave); } - slave_dev = our_slave->dev; - bond_detach_slave(bond, our_slave); + slave_dev = slave->dev; + bond_detach_slave(bond, slave); if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { /* must be called only after the slave * has been detached from the list */ - bond_alb_deinit_slave(bond, our_slave); + bond_alb_deinit_slave(bond, slave); } /* now that the slave is detached, unlock and perform @@ -2179,20 +1777,23 @@ static int bond_release_all(struct net_d */ write_unlock_bh(&bond->lock); - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, -1); + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond_mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); + } + + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); } - } - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave_dev, master); - - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, -1); + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } netdev_set_master(slave_dev, NULL); @@ -2202,7 +1803,7 @@ static int bond_release_all(struct net_d if (app_abi_ver >= 1) { /* restore original ("permanent") mac address*/ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; slave_dev->set_mac_address(slave_dev, &addr); } @@ -2210,11 +1811,11 @@ static int bond_release_all(struct net_d /* restore the original state of the IFF_NOARP flag that might have * been set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { + if ((slave->original_flags & IFF_NOARP) == 0) { slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* re-acquire the lock before getting the next slave */ write_lock_bh(&bond->lock); @@ -2224,72 +1825,234 @@ static int bond_release_all(struct net_d * set by the application to the mac address of the * first slave */ - memset(master->dev_addr, 0, master->addr_len); + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - printk (KERN_INFO "%s: released all slaves\n", master->name); + printk(KERN_INFO DRV_NAME + ": %s: released all slaves\n", + bond_dev->name); out: write_unlock_bh(&bond->lock); - return err; + return 0; +} + +/* + * This function changes the active slave to slave . + * It returns -EINVAL in the following cases. + * - is not found in the list. + * - There is not active slave now. + * - is already active. + * - The link state of is not BOND_LINK_UP. + * - is not running. + * In these cases, this fuction does nothing. + * In the other cases, currnt_slave pointer is changed and 0 is returned. + */ +static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *old_active = NULL; + struct slave *new_active = NULL; + int res = 0; + + /* Verify that master_dev is indeed the master of slave_dev */ + if (!(slave_dev->flags & IFF_SLAVE) || + (slave_dev->master != bond_dev)) { + return -EINVAL; + } + + write_lock_bh(&bond->lock); + + old_active = bond->curr_active_slave; + new_active = bond_get_slave_by_dev(bond, slave_dev); + + /* + * Changing to the current active: do nothing; return success. + */ + if (new_active && (new_active == old_active)) { + write_unlock_bh(&bond->lock); + return 0; + } + + if ((new_active) && + (old_active) && + (new_active->link == BOND_LINK_UP) && + IS_UP(new_active->dev)) { + bond_change_active_slave(bond, new_active); + } else { + res = -EINVAL; + } + + write_unlock_bh(&bond->lock); + + return res; +} + +static int bond_ethtool_ioctl(struct net_device *bond_dev, struct ifreq *ifr) +{ + struct ethtool_drvinfo info; + void *addr = ifr->ifr_data; + uint32_t cmd; + + if (get_user(cmd, (uint32_t *)addr)) { + return -EFAULT; + } + + switch (cmd) { + case ETHTOOL_GDRVINFO: + if (copy_from_user(&info, addr, sizeof(info))) { + return -EFAULT; + } + + if (strcmp(info.driver, "ifenslave") == 0) { + int new_abi_ver; + char *endptr; + + new_abi_ver = simple_strtoul(info.fw_version, + &endptr, 0); + if (*endptr) { + printk(KERN_ERR DRV_NAME + ": Error: got invalid ABI " + "version from application\n"); + + return -EINVAL; + } + + if (orig_app_abi_ver == -1) { + orig_app_abi_ver = new_abi_ver; + } + + app_abi_ver = new_abi_ver; + } + + strncpy(info.driver, DRV_NAME, 32); + strncpy(info.version, DRV_VERSION, 32); + snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + + if (copy_to_user(addr, &info, sizeof(info))) { + return -EFAULT; + } + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) +{ + struct bonding *bond = bond_dev->priv; + + info->bond_mode = bond_mode; + info->miimon = miimon; + + read_lock_bh(&bond->lock); + info->num_slaves = bond->slave_cnt; + read_unlock_bh(&bond->lock); + + return 0; +} + +static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int i, found = 0; + + if (info->slave_id < 0) { + return -ENODEV; + } + + read_lock_bh(&bond->lock); + + bond_for_each_slave(bond, slave, i) { + if (i == (int)info->slave_id) { + found = 1; + break; + } + } + + read_unlock_bh(&bond->lock); + + if (found) { + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = slave->state; + info->link_failure_count = slave->link_failure_count; + } else { + return -ENODEV; + } + + return 0; } +/*-------------------------------- Monitoring -------------------------------*/ + /* this function is called regularly to monitor each slave's link. */ -static void bond_mii_monitor(struct net_device *master) +static void bond_mii_monitor(struct net_device *bond_dev) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave, *oldcurrent; - int slave_died = 0; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks = (miimon * HZ) / 1000; + int i; read_lock(&bond->lock); + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { + goto re_arm; + } + /* we will try to read the link status of each of our slaves, and * set their IFF_RUNNING flag appropriately. For each slave not * supporting MII status, we won't do anything so that a user-space * program could monitor the link itself if needed. */ - slave = (slave_t *)bond; - - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); - while ((slave = slave->prev) != (slave_t *)bond) { - struct net_device *dev = slave->dev; + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; int link_state; u16 old_speed = slave->speed; u8 old_duplex = slave->duplex; - - link_state = bond_check_dev_link(dev, 0); + + link_state = bond_check_dev_link(slave_dev, 0); switch (slave->link) { case BOND_LINK_UP: /* the link was up */ if (link_state == BMSR_LSTATUS) { /* link stays up, nothing more to do */ break; - } - else { /* link going down */ + } else { /* link going down */ slave->link = BOND_LINK_FAIL; slave->delay = downdelay; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - if (downdelay > 0) { - printk (KERN_INFO - "%s: link status down for %sinterface " - "%s, disabling it in %d ms.\n", - master->name, - IS_UP(dev) - ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) - ? ((slave == oldcurrent) - ? "active " : "backup ") - : "") - : "idle ", - dev->name, - downdelay * miimon); - } + + if (downdelay) { + printk(KERN_INFO DRV_NAME + ": %s: link status down for %s " + "interface %s, disabling it in " + "%d ms.\n", + bond_dev->name, + IS_UP(slave_dev) + ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) + ? ((slave == oldcurrent) + ? "active " : "backup ") + : "") + : "idle ", + slave_dev->name, + downdelay * miimon); + } } /* no break ! fall through the BOND_LINK_FAIL test to ensure proper action to be taken @@ -2300,6 +2063,7 @@ static void bond_mii_monitor(struct net_ if (slave->delay <= 0) { /* link down for too long time */ slave->link = BOND_LINK_DOWN; + /* in active/backup mode, we must * completely disable this interface */ @@ -2308,11 +2072,12 @@ static void bond_mii_monitor(struct net_ bond_set_slave_inactive_flags(slave); } - printk(KERN_INFO - "%s: link status definitely down " - "for interface %s, disabling it", - master->name, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "down for interface %s, " + "disabling it\n", + bond_dev->name, + slave_dev->name); /* notify ad that the link status has changed */ if (bond_mode == BOND_MODE_8023AD) { @@ -2327,8 +2092,6 @@ static void bond_mii_monitor(struct net_ if (slave == oldcurrent) { do_failover = 1; } - - slave_died = 1; } else { slave->delay--; } @@ -2336,12 +2099,12 @@ static void bond_mii_monitor(struct net_ /* link up again */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - printk(KERN_INFO - "%s: link status up again after %d ms " - "for interface %s.\n", - master->name, - (downdelay - slave->delay) * miimon, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status up again after %d " + "ms for interface %s.\n", + bond_dev->name, + (downdelay - slave->delay) * miimon, + slave_dev->name); } break; case BOND_LINK_DOWN: /* the link was down */ @@ -2351,16 +2114,17 @@ static void bond_mii_monitor(struct net_ } else { /* link going up */ slave->link = BOND_LINK_BACK; slave->delay = updelay; - - if (updelay > 0) { + + if (updelay) { /* if updelay == 0, no need to advertise about a 0 ms delay */ - printk (KERN_INFO - "%s: link status up for interface" - " %s, enabling it in %d ms.\n", - master->name, - dev->name, - updelay * miimon); + printk(KERN_INFO DRV_NAME + ": %s: link status up for " + "interface %s, enabling it " + "in %d ms.\n", + bond_dev->name, + slave_dev->name, + updelay * miimon); } } /* no break ! fall through the BOND_LINK_BACK state in @@ -2370,12 +2134,13 @@ static void bond_mii_monitor(struct net_ if (link_state != BMSR_LSTATUS) { /* link down again */ slave->link = BOND_LINK_DOWN; - printk(KERN_INFO - "%s: link status down again after %d ms " - "for interface %s.\n", - master->name, - (updelay - slave->delay) * miimon, - dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: link status down again after %d " + "ms for interface %s.\n", + bond_dev->name, + (updelay - slave->delay) * miimon, + slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { @@ -2386,8 +2151,7 @@ static void bond_mii_monitor(struct net_ if (bond_mode == BOND_MODE_8023AD) { /* prevent it from being the active one */ slave->state = BOND_STATE_BACKUP; - } - else if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + } else if (bond_mode != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; } else if (slave != bond->primary_slave) { @@ -2395,12 +2159,12 @@ static void bond_mii_monitor(struct net_ slave->state = BOND_STATE_BACKUP; } - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s.\n", - master->name, - dev->name); - + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s.\n", + bond_dev->name, + slave_dev->name); + /* notify ad that the link status has changed */ if (bond_mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(slave, BOND_LINK_UP); @@ -2411,7 +2175,7 @@ static void bond_mii_monitor(struct net_ bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); } - if ((oldcurrent == NULL) || + if ((!oldcurrent) || (slave == bond->primary_slave)) { do_failover = 1; } @@ -2420,7 +2184,12 @@ static void bond_mii_monitor(struct net_ } } break; - } /* end of switch */ + default: + /* Should not happen */ + printk(KERN_ERR "bonding: Error: %s Illegal value (link=%d)\n", + slave->dev->name, slave->link); + goto out; + } /* end of switch (slave->link) */ bond_update_speed_duplex(slave); @@ -2428,112 +2197,110 @@ static void bond_mii_monitor(struct net_ if (old_speed != slave->speed) { bond_3ad_adapter_speed_changed(slave); } + if (old_duplex != slave->duplex) { bond_3ad_adapter_duplex_changed(slave); } } - } /* end of while */ + } /* end of for */ if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + bond_select_active_slave(bond); + + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + mod_timer(&bond->mii_timer, jiffies + delta_in_ticks); +out: read_unlock(&bond->lock); - /* re-arm the timer */ - mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000)); } -/* - * this function is called regularly to monitor each slave's link +static void bond_arp_send_all(struct slave *slave) +{ + int i; + + for (i = 0; (idev, + my_ip, NULL, slave->dev->dev_addr, + NULL); + } +} + +/* + * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring - * is used in load-balancing mode. if the adapter has been dormant, then an - * arp is transmitted to generate traffic. see activebackup_arp_monitor for - * arp monitoring in active backup mode. + * is used in load-balancing mode. if the adapter has been dormant, then an + * arp is transmitted to generate traffic. see activebackup_arp_monitor for + * arp monitoring in active backup mode. */ -static void loadbalance_arp_monitor(struct net_device *master) +static void bond_loadbalance_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave, *oldcurrent; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks = (arp_interval * HZ) / 1000; + int i; - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + read_lock(&bond->lock); - /* TODO: investigate why rtnl_shlock_nowait and rtnl_exlock_nowait - * are called below and add comment why they are required... - */ - if ((!IS_UP(master)) || rtnl_shlock_nowait()) { - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->kill_timers) { + goto out; } - if (rtnl_exlock_nowait()) { - rtnl_shunlock(); - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->slave_cnt == 0) { + goto re_arm; } - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); /* see if any of the previous devices are up now (i.e. they have - * xmt and rcv traffic). the current_slave does not come into + * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->jiffies is not needed * here because we send an arp on each slave and give a slave as * long as it needs to get the tx/rx within the delta. * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - - if (((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks) && - ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks)) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) && + ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) { slave->link = BOND_LINK_UP; slave->state = BOND_STATE_ACTIVE; /* primary_slave has no meaning in round-robin - * mode. the window of a slave being up and - * current_slave being null after enslaving + * mode. the window of a slave being up and + * curr_active_slave being null after enslaving * is closed. */ - if (oldcurrent == NULL) { - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s, ", - master->name, - slave->dev->name); + if (!oldcurrent) { + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s, ", + bond_dev->name, + slave->dev->name); do_failover = 1; } else { - printk(KERN_INFO - "%s: interface %s is now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now up\n", + bond_dev->name, + slave->dev->name); } - } + } } else { /* slave->link == BOND_LINK_UP */ @@ -2541,224 +2308,233 @@ static void loadbalance_arp_monitor(stru * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && my_ip !=0)) { + if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) { + slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO - "%s: interface %s is now down.\n", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now down.\n", + bond_dev->name, slave->dev->name); if (slave == oldcurrent) { do_failover = 1; } } - } + } - /* note: if switch is in round-robin mode, all links + /* note: if switch is in round-robin mode, all links * must tx arp to ensure all links rx an arp - otherwise - * links may oscillate or not come up at all; if switch is - * in something like xor mode, there is nothing we can - * do - all replies will be rx'ed on same link causing slaves + * links may oscillate or not come up at all; if switch is + * in something like xor mode, there is nothing we can + * do - all replies will be rx'ed on same link causing slaves * to be unstable during low/no traffic periods */ if (IS_UP(slave->dev)) { - arp_send_all(slave); + bond_arp_send_all(slave); } } if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); +out: read_unlock(&bond->lock); - rtnl_exunlock(); - rtnl_shunlock(); - - /* re-arm the timer */ - mod_timer(&bond->arp_timer, next_timer); } -/* +/* * When using arp monitoring in active-backup mode, this function is * called to determine if any backup slaves have went down or a new * current slave needs to be found. - * The backup slaves never generate traffic, they are considered up by merely - * receiving traffic. If the current slave goes down, each backup slave will - * be given the opportunity to tx/rx an arp before being taken down - this - * prevents all slaves from being taken down due to the current slave not + * The backup slaves never generate traffic, they are considered up by merely + * receiving traffic. If the current slave goes down, each backup slave will + * be given the opportunity to tx/rx an arp before being taken down - this + * prevents all slaves from being taken down due to the current slave not * sending any traffic for the backups to receive. The arps are not necessarily - * necessary, any tx and rx traffic will keep the current slave up. While any - * rx traffic will keep the backup slaves up, the current slave is responsible - * for generating traffic to keep them up regardless of any other traffic they + * necessary, any tx and rx traffic will keep the current slave up. While any + * rx traffic will keep the backup slaves up, the current slave is responsible + * for generating traffic to keep them up regardless of any other traffic they * may have received. * see loadbalance_arp_monitor for arp monitoring in load balancing mode */ -static void activebackup_arp_monitor(struct net_device *master) +static void bond_activebackup_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); - - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int delta_in_ticks = (arp_interval * HZ) / 1000; + int i; - if (!IS_UP(master)) { - mod_timer(&bond->arp_timer, next_timer); - return; + read_lock(&bond->lock); + + if (bond->kill_timers) { + goto out; } - read_lock(&bond->lock); + if (bond->slave_cnt == 0) { + goto re_arm; + } - /* determine if any slave has come up or any backup slave has - * gone down + /* determine if any slave has come up or any backup slave has + * gone down * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { slave->link = BOND_LINK_UP; - write_lock(&bond->ptrlock); - if ((bond->current_slave == NULL) && - ((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks)) { - change_active_interface(bond, slave); + + write_lock(&bond->curr_slave_lock); + + if ((!bond->curr_active_slave) && + ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { + bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; - } else if (bond->current_slave != slave) { - /* this slave has just come up but we + } else if (bond->curr_active_slave != slave) { + /* this slave has just come up but we * already have a current slave; this * can also happen if bond_enslave adds - * a new slave that is up while we are + * a new slave that is up while we are * searching for a new slave */ bond_set_slave_inactive_flags(slave); bond->current_arp_slave = NULL; } - if (slave == bond->current_slave) { - printk(KERN_INFO - "%s: %s is up and now the " - "active interface\n", - master->name, - slave->dev->name); + if (slave == bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: %s is up and now the " + "active interface\n", + bond_dev->name, + slave->dev->name); } else { - printk(KERN_INFO - "%s: backup interface %s is " - "now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now up\n", + bond_dev->name, + slave->dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } } else { - read_lock(&bond->ptrlock); - if ((slave != bond->current_slave) && - (bond->current_arp_slave == NULL) && - (((jiffies - slave->dev->last_rx) >= - 3*the_delta_in_ticks) && (my_ip != 0))) { - /* a backup slave has gone down; three times - * the delta allows the current slave to be + read_lock(&bond->curr_slave_lock); + + if ((slave != bond->curr_active_slave) && + (!bond->current_arp_slave) && + (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + my_ip)) { + /* a backup slave has gone down; three times + * the delta allows the current slave to be * taken out before the backup slave. * note: a non-null current_arp_slave indicates - * the current_slave went down and we are - * searching for a new one; under this - * condition we only take the current_slave - * down - this gives each slave a chance to + * the curr_active_slave went down and we are + * searching for a new one; under this + * condition we only take the curr_active_slave + * down - this gives each slave a chance to * tx/rx traffic before being taken out */ - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface %s is now down\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now down\n", + bond_dev->name, + slave->dev->name); } else { - read_unlock(&bond->ptrlock); + read_unlock(&bond->curr_slave_lock); } } } - read_lock(&bond->ptrlock); - slave = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave != NULL) { + read_lock(&bond->curr_slave_lock); + slave = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + if (slave) { /* if we have sent traffic in the past 2*arp_intervals but - * haven't xmit and rx traffic in that time interval, select + * haven't xmit and rx traffic in that time interval, select * a different slave. slave->jiffies is only updated when - * a slave first becomes the current_slave - not necessarily - * after every arp; this ensures the slave has a full 2*delta - * before being taken out. if a primary is being used, check - * if it is up and needs to take over as the current_slave + * a slave first becomes the curr_active_slave - not necessarily + * after every arp; this ensures the slave has a full 2*delta + * before being taken out. if a primary is being used, check + * if it is up and needs to take over as the curr_active_slave */ - if ((((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && (my_ip != 0))) && - ((jiffies - slave->jiffies) >= 2*the_delta_in_ticks)) { + if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) && + ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO "%s: link status down for " - "active interface %s, disabling it", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: link status down for active interface " + "%s, disabling it\n", + bond_dev->name, slave->dev->name); - write_lock(&bond->ptrlock); - reselect_active_interface(bond); - slave = bond->current_slave; - write_unlock(&bond->ptrlock); + + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); + slave = bond->curr_active_slave; + + write_unlock(&bond->curr_slave_lock); + bond->current_arp_slave = slave; - if (slave != NULL) { + + if (slave) { slave->jiffies = jiffies; } - - } else if ((bond->primary_slave != NULL) && - (bond->primary_slave != slave) && + } else if ((bond->primary_slave) && + (bond->primary_slave != slave) && (bond->primary_slave->link == BOND_LINK_UP)) { - /* at this point, slave is the current_slave */ - printk(KERN_INFO - "%s: changing from interface %s to primary " + /* at this point, slave is the curr_active_slave */ + printk(KERN_INFO DRV_NAME + ": %s: changing from interface %s to primary " "interface %s\n", - master->name, - slave->dev->name, + bond_dev->name, + slave->dev->name, bond->primary_slave->dev->name); - + /* primary is up so switch to it */ - write_lock(&bond->ptrlock); - change_active_interface(bond, bond->primary_slave); - write_unlock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + bond_change_active_slave(bond, bond->primary_slave); + write_unlock(&bond->curr_slave_lock); + slave = bond->primary_slave; slave->jiffies = jiffies; } else { @@ -2768,567 +2544,606 @@ static void activebackup_arp_monitor(str /* the current slave must tx an arp to ensure backup slaves * rx traffic */ - if ((slave != NULL) && (my_ip != 0)) { - arp_send_all(slave); + if (slave && my_ip) { + bond_arp_send_all(slave); } } - /* if we don't have a current_slave, search for the next available - * backup slave from the current_arp_slave and make it the candidate - * for becoming the current_slave + /* if we don't have a curr_active_slave, search for the next available + * backup slave from the current_arp_slave and make it the candidate + * for becoming the curr_active_slave */ - if (slave == NULL) { - - if ((bond->current_arp_slave == NULL) || - (bond->current_arp_slave == (slave_t *)bond)) { - bond->current_arp_slave = bond->prev; - } + if (!slave) { + if (!bond->current_arp_slave) { + bond->current_arp_slave = bond->first_slave; + } - if (bond->current_arp_slave != (slave_t *)bond) { + if (bond->current_arp_slave) { bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->current_arp_slave->next; /* search for next candidate */ - do { + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) { if (IS_UP(slave->dev)) { slave->link = BOND_LINK_BACK; bond_set_slave_active_flags(slave); - arp_send_all(slave); + bond_arp_send_all(slave); slave->jiffies = jiffies; bond->current_arp_slave = slave; break; } - /* if the link state is up at this point, we - * mark it down - this can happen if we have - * simultaneous link failures and - * reselect_active_interface doesn't make this - * one the current slave so it is still marked + /* if the link state is up at this point, we + * mark it down - this can happen if we have + * simultaneous link failures and + * reselect_active_interface doesn't make this + * one the current slave so it is still marked * up when it is actually down */ if (slave->link == BOND_LINK_UP) { slave->link = BOND_LINK_DOWN; - if (slave->link_failure_count < - UINT_MAX) { + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface " - "%s is now down.\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now down.\n", + bond_dev->name, + slave->dev->name); } - } while ((slave = slave->next) != - bond->current_arp_slave->next); + } } } +re_arm: + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); +out: read_unlock(&bond->lock); - mod_timer(&bond->arp_timer, next_timer); } -static int bond_sethwaddr(struct net_device *master, struct net_device *slave) -{ -#ifdef BONDING_DEBUG - printk(KERN_CRIT "bond_sethwaddr: master=%x\n", (unsigned int)master); - printk(KERN_CRIT "bond_sethwaddr: slave=%x\n", (unsigned int)slave); - printk(KERN_CRIT "bond_sethwaddr: slave->addr_len=%d\n", slave->addr_len); -#endif - memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); - return 0; -} +/*------------------------------ proc/seq_file-------------------------------*/ -static int bond_info_query(struct net_device *master, struct ifbond *info) -{ - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; +#ifdef CONFIG_PROC_FS - info->bond_mode = bond_mode; - info->num_slaves = 0; - info->miimon = miimon; +#define SEQ_START_TOKEN ((void *)1) +static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct bonding *bond = seq->private; + loff_t off = 0; + struct slave *slave; + int i; + + /* make sure the bond won't be taken away */ + read_lock(&dev_base_lock); read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { - info->num_slaves++; + + if (*pos == 0) { + return SEQ_START_TOKEN; } - read_unlock_bh(&bond->lock); - return 0; + bond_for_each_slave(bond, slave, i) { + if (++off == *pos) { + return slave; + } + } + + return NULL; } -static int bond_slave_info_query(struct net_device *master, - struct ifslave *info) +static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; - int cur_ndx = 0; + struct bonding *bond = seq->private; + struct slave *slave = v; - if (info->slave_id < 0) { - return -ENODEV; + ++*pos; + if (v == SEQ_START_TOKEN) { + return bond->first_slave; } - read_lock_bh(&bond->lock); - for (slave = bond->prev; - slave != (slave_t *)bond && cur_ndx < info->slave_id; - slave = slave->prev) { - cur_ndx++; - } - read_unlock_bh(&bond->lock); + slave = slave->next; - if (slave != (slave_t *)bond) { - strcpy(info->slave_name, slave->dev->name); - info->link = slave->link; - info->state = slave->state; - info->link_failure_count = slave->link_failure_count; - } else { - return -ENODEV; - } + return (slave == bond->first_slave) ? NULL : slave; +} - return 0; +static void bond_info_seq_stop(struct seq_file *seq, void *v) +{ + struct bonding *bond = seq->private; + + read_unlock_bh(&bond->lock); + read_unlock(&dev_base_lock); } -static int bond_ethtool_ioctl(struct net_device *master_dev, struct ifreq *ifr) +static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) { - void *addr = ifr->ifr_data; - uint32_t cmd; + struct slave *curr; - if (get_user(cmd, (uint32_t *) addr)) - return -EFAULT; + read_lock(&bond->curr_slave_lock); + curr = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); - switch (cmd) { + seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name()); - case ETHTOOL_GDRVINFO: - { - struct ethtool_drvinfo info; - char *endptr; + if (USES_PRIMARY(bond_mode)) { + if (curr) { + seq_printf(seq, + "Currently Active Slave: %s\n", + curr->dev->name); + } + } - if (copy_from_user(&info, addr, sizeof(info))) - return -EFAULT; + seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); + seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon); + seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon); + seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon); - if (strcmp(info.driver, "ifenslave") == 0) { - int new_abi_ver; + if (bond_mode == BOND_MODE_8023AD) { + struct ad_info ad_info; - new_abi_ver = simple_strtoul(info.fw_version, - &endptr, 0); - if (*endptr) { - printk(KERN_ERR - "bonding: Error: got invalid ABI" - " version from application\n"); + seq_puts(seq, "\n802.3ad info\n"); - return -EINVAL; - } + if (bond_3ad_get_active_agg_info(bond, &ad_info)) { + seq_printf(seq, "bond %s has no active aggregator\n", + bond->dev->name); + } else { + seq_printf(seq, "Active Aggregator Info:\n"); - if (orig_app_abi_ver == -1) { - orig_app_abi_ver = new_abi_ver; - } + seq_printf(seq, "\tAggregator ID: %d\n", + ad_info.aggregator_id); + seq_printf(seq, "\tNumber of ports: %d\n", + ad_info.ports); + seq_printf(seq, "\tActor Key: %d\n", + ad_info.actor_key); + seq_printf(seq, "\tPartner Key: %d\n", + ad_info.partner_key); + seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + ad_info.partner_system[0], + ad_info.partner_system[1], + ad_info.partner_system[2], + ad_info.partner_system[3], + ad_info.partner_system[4], + ad_info.partner_system[5]); + } + } +} - app_abi_ver = new_abi_ver; - } +static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) +{ + seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); + seq_printf(seq, "MII Status: %s\n", + (slave->link == BOND_LINK_UP) ? "up" : "down"); + seq_printf(seq, "Link Failure Count: %d\n", + slave->link_failure_count); - strncpy(info.driver, DRV_NAME, 32); - strncpy(info.version, DRV_VERSION, 32); - snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + if (app_abi_ver >= 1) { + seq_printf(seq, + "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5]); + } - if (copy_to_user(addr, &info, sizeof(info))) - return -EFAULT; + if (bond_mode == BOND_MODE_8023AD) { + const struct aggregator *agg + = SLAVE_AD_INFO(slave).port.aggregator; - return 0; + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", + agg->aggregator_identifier); + } else { + seq_puts(seq, "Aggregator ID: N/A\n"); } - break; - default: - return -EOPNOTSUPP; } } -static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) +static int bond_info_seq_show(struct seq_file *seq, void *v) { - struct net_device *slave_dev = NULL; - struct ifbond *u_binfo = NULL, k_binfo; - struct ifslave *u_sinfo = NULL, k_sinfo; - struct mii_ioctl_data *mii = NULL; - int prev_abi_ver = orig_app_abi_ver; - int ret = 0; + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%s\n", version); + bond_info_show_master(seq, seq->private); + } else { + bond_info_show_slave(seq, v); + } -#ifdef BONDING_DEBUG - printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n", - master_dev->name, cmd); -#endif + return 0; +} - switch (cmd) { - case SIOCETHTOOL: - return bond_ethtool_ioctl(master_dev, ifr); +static struct seq_operations bond_info_seq_ops = { + .start = bond_info_seq_start, + .next = bond_info_seq_next, + .stop = bond_info_seq_stop, + .show = bond_info_seq_show, +}; - case SIOCGMIIPHY: - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - mii->phy_id = 0; - /* Fall Through */ - case SIOCGMIIREG: - /* - * We do this again just in case we were called by SIOCGMIIREG - * instead of SIOCGMIIPHY. - */ - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - if (mii->reg_num == 1) { - mii->val_out = bond_check_mii_link( - (struct bonding *)master_dev->priv); - } - return 0; - case BOND_INFO_QUERY_OLD: - case SIOCBONDINFOQUERY: - u_binfo = (struct ifbond *)ifr->ifr_data; - if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { - return -EFAULT; - } - ret = bond_info_query(master_dev, &k_binfo); - if (ret == 0) { - if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { - return -EFAULT; - } +static int bond_info_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + struct proc_dir_entry *proc; + int res; + + res = seq_open(file, &bond_info_seq_ops); + if (!res) { + /* recover the pointer buried in proc_dir_entry data */ + seq = file->private_data; + proc = PDE(inode); + seq->private = proc->data; + } + + return res; +} + +static struct file_operations bond_info_fops = { + .owner = THIS_MODULE, + .open = bond_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int bond_create_proc_entry(struct bonding *bond) +{ + struct net_device *bond_dev = bond->dev; + + if (bond_proc_dir) { + bond->proc_entry = create_proc_entry(bond_dev->name, + S_IRUGO, + bond_proc_dir); + if (bond->proc_entry == NULL) { + printk(KERN_WARNING DRV_NAME + ": Warning: Cannot create /proc/net/%s/%s\n", + DRV_NAME, bond_dev->name); + } else { + bond->proc_entry->data = bond; + bond->proc_entry->proc_fops = &bond_info_fops; + bond->proc_entry->owner = THIS_MODULE; + memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } - return ret; - case BOND_SLAVE_INFO_QUERY_OLD: - case SIOCBONDSLAVEINFOQUERY: - u_sinfo = (struct ifslave *)ifr->ifr_data; - if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { - return -EFAULT; + } + + return 0; +} + +static void bond_remove_proc_entry(struct bonding *bond) +{ + if (bond_proc_dir && bond->proc_entry) { + remove_proc_entry(bond->proc_file_name, bond_proc_dir); + memset(bond->proc_file_name, 0, IFNAMSIZ); + bond->proc_entry = NULL; + } +} + +/* Create the bonding directory under /proc/net, if doesn't exist yet. + * Caller must hold rtnl_lock. + */ +static void bond_create_proc_dir(void) +{ + int len = strlen(DRV_NAME); + + for (bond_proc_dir = proc_net->subdir; bond_proc_dir; + bond_proc_dir = bond_proc_dir->next) { + if ((bond_proc_dir->namelen == len) && + !memcmp(bond_proc_dir->name, DRV_NAME, len)) { + break; } - ret = bond_slave_info_query(master_dev, &k_sinfo); - if (ret == 0) { - if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { - return -EFAULT; - } + } + + if (!bond_proc_dir) { + bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); + if (bond_proc_dir) { + bond_proc_dir->owner = THIS_MODULE; + } else { + printk(KERN_WARNING DRV_NAME + ": Warning: cannot create /proc/net/%s\n", + DRV_NAME); } - return ret; } +} - if (!capable(CAP_NET_ADMIN)) { - return -EPERM; +/* Destroy the bonding directory under /proc/net, if empty. + * Caller must hold rtnl_lock. + */ +static void bond_destroy_proc_dir(void) +{ + struct proc_dir_entry *de; + + if (!bond_proc_dir) { + return; } - if (orig_app_abi_ver == -1) { - /* no orig_app_abi_ver was provided yet, so we'll use the - * current one from now on, even if it's 0 - */ - orig_app_abi_ver = app_abi_ver; + /* verify that the /proc dir is empty */ + for (de = bond_proc_dir->subdir; de; de = de->next) { + /* ignore . and .. */ + if (*(de->name) != '.') { + break; + } + } - } else if (orig_app_abi_ver != app_abi_ver) { - printk(KERN_ERR - "bonding: Error: already using ifenslave ABI " - "version %d; to upgrade ifenslave to version %d, " - "you must first reload bonding.\n", - orig_app_abi_ver, app_abi_ver); - return -EINVAL; + if (de) { + if (bond_proc_dir->owner == THIS_MODULE) { + bond_proc_dir->owner = NULL; + } + } else { + remove_proc_entry(DRV_NAME, proc_net); + bond_proc_dir = NULL; } +} +#endif /* CONFIG_PROC_FS */ - slave_dev = dev_get_by_name(ifr->ifr_slave); +/*-------------------------- netdev event handling --------------------------*/ -#ifdef BONDING_DEBUG - printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev); - printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name); +/* + * Change device name + */ +static int bond_event_changename(struct bonding *bond) +{ +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); + bond_create_proc_entry(bond); #endif - if (slave_dev == NULL) { - ret = -ENODEV; - } else { - switch (cmd) { - case BOND_ENSLAVE_OLD: - case SIOCBONDENSLAVE: - ret = bond_enslave(master_dev, slave_dev); - break; - case BOND_RELEASE_OLD: - case SIOCBONDRELEASE: - ret = bond_release(master_dev, slave_dev); - break; - case BOND_SETHWADDR_OLD: - case SIOCBONDSETHWADDR: - ret = bond_sethwaddr(master_dev, slave_dev); - break; - case BOND_CHANGE_ACTIVE_OLD: - case SIOCBONDCHANGEACTIVE: - if (USES_PRIMARY(bond_mode)) { - ret = bond_change_active(master_dev, slave_dev); - } - else { - ret = -EINVAL; - } - break; - default: - ret = -EOPNOTSUPP; - } - dev_put(slave_dev); + return NOTIFY_DONE; +} + +static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) +{ + struct bonding *event_bond = bond_dev->priv; + + switch (event) { + case NETDEV_CHANGENAME: + return bond_event_changename(event_bond); + case NETDEV_UNREGISTER: + /* + * TODO: remove a bond from the list? + */ + break; + default: + break; } - if (ret < 0) { - /* The ioctl failed, so there's no point in changing the - * orig_app_abi_ver. We'll restore it's value just in case - * we've changed it earlier in this function. + return NOTIFY_DONE; +} + +static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) +{ + struct net_device *bond_dev = slave_dev->master; + + switch (event) { + case NETDEV_UNREGISTER: + if (bond_dev) { + bond_release(bond_dev, slave_dev); + } + break; + case NETDEV_CHANGE: + /* + * TODO: is this what we get if somebody + * sets up a hierarchical bond, then rmmod's + * one of the slave bonding devices? + */ + break; + case NETDEV_DOWN: + /* + * ... Or is it this? + */ + break; + case NETDEV_CHANGEMTU: + /* + * TODO: Should slaves be allowed to + * independently alter their MTU? For + * an active-backup bond, slaves need + * not be the same type of device, so + * MTUs may vary. For other modes, + * slaves arguably should have the + * same MTUs. To do this, we'd need to + * take over the slave's change_mtu + * function for the duration of their + * servitude. + */ + break; + case NETDEV_CHANGENAME: + /* + * TODO: handle changing the primary's name */ - orig_app_abi_ver = prev_abi_ver; + break; + default: + break; } - return ret; -} - -#ifdef CONFIG_NET_FASTROUTE -static int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst) -{ - return -1; + return NOTIFY_DONE; } -#endif -/* - * in broadcast mode, we send everything to all usable interfaces. +/* + * bond_netdev_event: handle netdev notifier chain events. + * + * This function receives events for the netdev chain. The caller (an + * ioctl handler calling notifier_call_chain) holds the necessary + * locks for us to safely manipulate the slave devices (RTNL lock, + * dev_probe_lock). */ -static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) +static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct net_device *device_we_should_send_to = 0; + struct net_device *event_dev = (struct net_device *)ptr; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + dprintk("event_dev: %s, event: %lx\n", + (event_dev ? event_dev->name : "None"), + event); + + if (event_dev->flags & IFF_MASTER) { + dprintk("IFF_MASTER\n"); + return bond_master_netdev_event(event, event_dev); } - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - read_unlock(&bond->lock); - dev_kfree_skb(skb); - return 0; + if (event_dev->flags & IFF_SLAVE) { + dprintk("IFF_SLAVE\n"); + return bond_slave_netdev_event(event, event_dev); } - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - if (device_we_should_send_to) { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { - printk(KERN_ERR "bond_xmit_broadcast: skb_clone() failed\n"); - continue; - } - - skb2->dev = device_we_should_send_to; - skb2->priority = 1; - dev_queue_xmit(skb2); - } - device_we_should_send_to = slave->dev; - } - } while ((slave = slave->next) != start_at); + return NOTIFY_DONE; +} - if (device_we_should_send_to) { - skb->dev = device_we_should_send_to; - skb->priority = 1; - dev_queue_xmit(skb); - } else - dev_kfree_skb(skb); +static struct notifier_block bond_netdev_notifier = { + .notifier_call = bond_netdev_event, +}; - /* frame sent to all suitable interfaces */ - read_unlock(&bond->lock); - return 0; -} +/*-------------------------- Packet type handling ---------------------------*/ -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) +/* register to receive lacpdus on a bond */ +static void bond_register_lacpdu(struct bonding *bond) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } + /* initialize packet type */ + pk_type->type = PKT_TYPE_LACPDU; + pk_type->dev = bond->dev; + pk_type->func = bond_3ad_lacpdu_recv; - read_lock(&bond->lock); + dev_add_pack(pk_type); +} - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } +/* unregister to receive lacpdus on a bond */ +static void bond_unregister_lacpdu(struct bonding *bond) +{ + dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); +} - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { +/*-------------------------- Device entry points ----------------------------*/ - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); +static int bond_open(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct timer_list *mii_timer = &bond->mii_timer; + struct timer_list *arp_timer = &bond->arp_timer; + + bond->kill_timers = 0; - write_lock(&bond->ptrlock); - bond->current_slave = slave->next; - write_unlock(&bond->ptrlock); + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); - read_unlock(&bond->lock); - return 0; + /* bond_alb_initialize must be called before the timer + * is started. + */ + if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) { + /* something went wrong - fail the open operation */ + return -1; } - } while ((slave = slave->next) != start_at); - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} + init_timer(alb_timer); + alb_timer->expires = jiffies + 1; + alb_timer->data = (unsigned long)bond; + alb_timer->function = (void *)&bond_alb_monitor; + add_timer(alb_timer); + } -/* - * in XOR mode, we determine the output device by performing xor on - * the source and destination hw adresses. If this device is not - * enabled, find the next slave following this xor slave. - */ -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) -{ - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *data = (struct ethhdr *)skb->data; - int slave_no; + if (miimon) { /* link check interval, in milliseconds. */ + init_timer(mii_timer); + mii_timer->expires = jiffies + 1; + mii_timer->data = (unsigned long)bond_dev; + mii_timer->function = (void *)&bond_mii_monitor; + add_timer(mii_timer); + } - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + if (arp_interval) { /* arp interval, in milliseconds. */ + init_timer(arp_timer); + arp_timer->expires = jiffies + 1; + arp_timer->data = (unsigned long)bond_dev; + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { + arp_timer->function = (void *)&bond_activebackup_arp_mon; + } else { + arp_timer->function = (void *)&bond_loadbalance_arp_mon; + } + add_timer(arp_timer); } - read_lock(&bond->lock); - slave = bond->prev; + if (bond_mode == BOND_MODE_8023AD) { + struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); + init_timer(ad_timer); + ad_timer->expires = jiffies + 1; + ad_timer->data = (unsigned long)bond; + ad_timer->function = (void *)&bond_3ad_state_machine_handler; + add_timer(ad_timer); - /* we're at the root, get the first slave */ - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + /* register to receive LACPDUs */ + bond_register_lacpdu(bond); } - slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; + return 0; +} - while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { - slave = slave->prev; - slave_no--; - } - start_at = slave; +static int bond_close(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { + write_lock_bh(&bond->lock); - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); + bond_mc_list_destroy(bond); - read_unlock(&bond->lock); - return 0; - } - } while ((slave = slave->next) != start_at); + if (bond_mode == BOND_MODE_8023AD) { + /* Unregister the receive of LACPDUs */ + bond_unregister_lacpdu(bond); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} + /* signal timers not to re-arm */ + bond->kill_timers = 1; -/* - * in active-backup mode, we know that bond->current_slave is always valid if - * the bond has a usable interface. - */ -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev) -{ - struct bonding *bond = (struct bonding *) dev->priv; - int ret; + write_unlock_bh(&bond->lock); - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + /* del_timer_sync must run without holding the bond->lock + * because a running timer might be trying to hold it too + */ + + if (miimon) { /* link check interval, in milliseconds. */ + del_timer_sync(&bond->mii_timer); } - /* if we are sending arp packets, try to at least - identify our own ip address */ - if ( (arp_interval > 0) && (my_ip == 0) && - (skb->protocol == __constant_htons(ETH_P_ARP) ) ) { - char *the_ip = (((char *)skb->data)) - + sizeof(struct ethhdr) - + sizeof(struct arphdr) + - ETH_ALEN; - memcpy(&my_ip, the_ip, 4); + if (arp_interval) { /* arp interval, in milliseconds. */ + del_timer_sync(&bond->arp_timer); } - /* if we are sending arp packets and don't know - * the target hw address, save it so we don't need - * to use a broadcast address. - * don't do this if in active backup mode because the slaves must - * receive packets to stay up, and the only ones they receive are - * broadcasts. - */ - if ( (bond_mode != BOND_MODE_ACTIVEBACKUP) && - (arp_ip_count == 1) && - (arp_interval > 0) && (arp_target_hw_addr == NULL) && - (skb->protocol == __constant_htons(ETH_P_IP) ) ) { - struct ethhdr *eth_hdr = - (struct ethhdr *) (((char *)skb->data)); - struct iphdr *ip_hdr = (struct iphdr *)(eth_hdr + 1); - - if (arp_target[0] == ip_hdr->daddr) { - arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL); - if (arp_target_hw_addr != NULL) - memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN); - } + switch (bond_mode) { + case BOND_MODE_8023AD: + del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: + del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + break; + default: + break; } - read_lock(&bond->lock); + /* Release the bonded slaves */ + bond_release_all(bond_dev); - read_lock(&bond->ptrlock); - if (bond->current_slave != NULL) { /* one usable interface */ - skb->dev = bond->current_slave->dev; - read_unlock(&bond->ptrlock); - skb->priority = 1; - ret = dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; - } - else { - read_unlock(&bond->ptrlock); + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + /* Must be called only after all + * slaves have been released + */ + bond_alb_deinitialize(bond); } - /* no suitable interface, frame not sent */ -#ifdef BONDING_DEBUG - printk(KERN_INFO "There was no suitable interface, so we don't transmit\n"); -#endif - dev_kfree_skb(skb); - read_unlock(&bond->lock); return 0; } -static struct net_device_stats *bond_get_stats(struct net_device *dev) +static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) { - bonding_t *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct net_device_stats *stats = &(bond->stats), *sstats; - slave_t *slave; + struct slave *slave; + int i; memset(stats, 0, sizeof(struct net_device_stats)); read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { + bond_for_each_slave(bond, slave, i) { sstats = slave->dev->get_stats(slave->dev); - + stats->rx_packets += sstats->rx_packets; stats->rx_bytes += sstats->rx_bytes; stats->rx_errors += sstats->rx_errors; @@ -3346,290 +3161,294 @@ static struct net_device_stats *bond_get stats->rx_over_errors += sstats->rx_over_errors; stats->rx_crc_errors += sstats->rx_crc_errors; stats->rx_frame_errors += sstats->rx_frame_errors; - stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; stats->rx_missed_errors += sstats->rx_missed_errors; - + stats->tx_aborted_errors += sstats->tx_aborted_errors; stats->tx_carrier_errors += sstats->tx_carrier_errors; stats->tx_fifo_errors += sstats->tx_fifo_errors; stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors; - } read_unlock_bh(&bond->lock); + return stats; } -#ifdef CONFIG_PROC_FS - -#define SEQ_START_TOKEN ((void *)1) - -static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) +static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) { - struct bonding *bond = seq->private; - loff_t off = 0; - struct slave *slave; - - /* make sure the bond won't be taken away */ - read_lock(&dev_base_lock); - read_lock_bh(&bond->lock); - - if (*pos == 0) { - return SEQ_START_TOKEN; - } + struct net_device *slave_dev = NULL; + struct ifbond *u_binfo = NULL, k_binfo; + struct ifslave *u_sinfo = NULL, k_sinfo; + struct mii_ioctl_data *mii = NULL; + int prev_abi_ver = orig_app_abi_ver; + int res = 0; - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { + dprintk("bond_ioctl: master=%s, cmd=%d\n", + bond_dev->name, cmd); - if (++off == *pos) { - return slave; + switch (cmd) { + case SIOCETHTOOL: + return bond_ethtool_ioctl(bond_dev, ifr); + case SIOCGMIIPHY: + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; + } + mii->phy_id = 0; + /* Fall Through */ + case SIOCGMIIREG: + /* + * We do this again just in case we were called by SIOCGMIIREG + * instead of SIOCGMIIPHY. + */ + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; } - } - - return NULL; -} - -static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct bonding *bond = seq->private; - struct slave *slave = v; - - ++*pos; - if (v == SEQ_START_TOKEN) { - slave = bond->prev; - } else { - slave = slave->prev; - } - - return (slave == (struct slave *) bond) ? NULL : slave; -} - -static void bond_info_seq_stop(struct seq_file *seq, void *v) -{ - struct bonding *bond = seq->private; - - read_unlock_bh(&bond->lock); - read_unlock(&dev_base_lock); -} - -static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) -{ - struct slave *curr; - read_lock(&bond->ptrlock); - curr = bond->current_slave; - read_unlock(&bond->ptrlock); + if (mii->reg_num == 1) { + struct bonding *bond = bond_dev->priv; + mii->val_out = 0; + read_lock_bh(&bond->lock); + read_lock(&bond->curr_slave_lock); + if (bond->curr_active_slave) { + mii->val_out = BMSR_LSTATUS; + } + read_unlock(&bond->curr_slave_lock); + read_unlock_bh(&bond->lock); + } - seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name()); + return 0; + case BOND_INFO_QUERY_OLD: + case SIOCBONDINFOQUERY: + u_binfo = (struct ifbond *)ifr->ifr_data; - if (USES_PRIMARY(bond_mode)) { - if (curr) { - seq_printf(seq, - "Currently Active Slave: %s\n", - curr->dev->name); + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + return -EFAULT; } - } - - seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); - seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon); - seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon); - seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon); - seq_printf(seq, "Multicast Mode: %s\n", multicast_mode_name()); - if (bond_mode == BOND_MODE_8023AD) { - struct ad_info ad_info; + res = bond_info_query(bond_dev, &k_binfo); + if (res == 0) { + if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { + return -EFAULT; + } + } - seq_puts(seq, "\n802.3ad info\n"); + return res; + case BOND_SLAVE_INFO_QUERY_OLD: + case SIOCBONDSLAVEINFOQUERY: + u_sinfo = (struct ifslave *)ifr->ifr_data; - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - seq_printf(seq, "bond %s has no active aggregator\n", - bond->device->name); - } else { - seq_printf(seq, "Active Aggregator Info:\n"); + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + return -EFAULT; + } - seq_printf(seq, "\tAggregator ID: %d\n", - ad_info.aggregator_id); - seq_printf(seq, "\tNumber of ports: %d\n", - ad_info.ports); - seq_printf(seq, "\tActor Key: %d\n", - ad_info.actor_key); - seq_printf(seq, "\tPartner Key: %d\n", - ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]); + res = bond_slave_info_query(bond_dev, &k_sinfo); + if (res == 0) { + if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { + return -EFAULT; + } } + + return res; + default: + /* Go on */ + break; } -} -static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) -{ - seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); - seq_printf(seq, "MII Status: %s\n", - (slave->link == BOND_LINK_UP) ? "up" : "down"); - seq_printf(seq, "Link Failure Count: %d\n", - slave->link_failure_count); + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } - if (app_abi_ver >= 1) { - seq_printf(seq, - "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", - slave->perm_hwaddr[0], - slave->perm_hwaddr[1], - slave->perm_hwaddr[2], - slave->perm_hwaddr[3], - slave->perm_hwaddr[4], - slave->perm_hwaddr[5]); + if (orig_app_abi_ver == -1) { + /* no orig_app_abi_ver was provided yet, so we'll use the + * current one from now on, even if it's 0 + */ + orig_app_abi_ver = app_abi_ver; + + } else if (orig_app_abi_ver != app_abi_ver) { + printk(KERN_ERR DRV_NAME + ": Error: already using ifenslave ABI version %d; to " + "upgrade ifenslave to version %d, you must first " + "reload bonding.\n", + orig_app_abi_ver, app_abi_ver); + return -EINVAL; } - if (bond_mode == BOND_MODE_8023AD) { - const struct aggregator *agg - = SLAVE_AD_INFO(slave).port.aggregator; + slave_dev = dev_get_by_name(ifr->ifr_slave); - if (agg) { - seq_printf(seq, "Aggregator ID: %d\n", - agg->aggregator_identifier); - } else { - seq_puts(seq, "Aggregator ID: N/A\n"); + dprintk("slave_dev=%p: \n", slave_dev); + + if (!slave_dev) { + res = -ENODEV; + } else { + dprintk("slave_dev->name=%s: \n", slave_dev->name); + switch (cmd) { + case BOND_ENSLAVE_OLD: + case SIOCBONDENSLAVE: + res = bond_enslave(bond_dev, slave_dev); + break; + case BOND_RELEASE_OLD: + case SIOCBONDRELEASE: + res = bond_release(bond_dev, slave_dev); + break; + case BOND_SETHWADDR_OLD: + case SIOCBONDSETHWADDR: + res = bond_sethwaddr(bond_dev, slave_dev); + break; + case BOND_CHANGE_ACTIVE_OLD: + case SIOCBONDCHANGEACTIVE: + if (USES_PRIMARY(bond_mode)) { + res = bond_ioctl_change_active(bond_dev, slave_dev); + } else { + res = -EINVAL; + } + break; + default: + res = -EOPNOTSUPP; } + + dev_put(slave_dev); } -} -static int bond_info_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "%s\n", version); - bond_info_show_master(seq, seq->private); - } else { - bond_info_show_slave(seq, v); + if (res < 0) { + /* The ioctl failed, so there's no point in changing the + * orig_app_abi_ver. We'll restore it's value just in case + * we've changed it earlier in this function. + */ + orig_app_abi_ver = prev_abi_ver; } - return 0; + return res; } -static struct seq_operations bond_info_seq_ops = { - .start = bond_info_seq_start, - .next = bond_info_seq_next, - .stop = bond_info_seq_stop, - .show = bond_info_seq_show, -}; - -static int bond_info_open(struct inode *inode, struct file *file) +static void bond_set_multicast_list(struct net_device *bond_dev) { - struct seq_file *seq; - struct proc_dir_entry *proc; - int rc; - - rc = seq_open(file, &bond_info_seq_ops); - if (!rc) { - /* recover the pointer buried in proc_dir_entry data */ - seq = file->private_data; - proc = PDE(inode); - seq->private = proc->data; - } - return rc; -} + struct bonding *bond = bond_dev->priv; + struct dev_mc_list *dmi; -static struct file_operations bond_info_fops = { - .owner = THIS_MODULE, - .open = bond_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; + write_lock_bh(&bond->lock); -static int bond_create_proc_info(struct bonding *bond) -{ - struct net_device *dev = bond->device; + /* + * Do promisc before checking multicast_mode + */ + if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, 1); + } - if (bond_proc_dir) { - bond->bond_proc_file = create_proc_entry(dev->name, - S_IRUGO, - bond_proc_dir); - if (bond->bond_proc_file == NULL) { - printk(KERN_WARNING - "%s: Cannot create /proc/net/bonding/%s\n", - dev->name, dev->name); - } else { - bond->bond_proc_file->data = bond; - bond->bond_proc_file->proc_fops = &bond_info_fops; - bond->bond_proc_file->owner = THIS_MODULE; - memcpy(bond->procdir_name, dev->name, IFNAMSIZ); - } + if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, -1); } - return 0; -} + /* set allmulti flag to slaves */ + if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, 1); + } -static void bond_destroy_proc_info(struct bonding *bond) -{ - if (bond_proc_dir && bond->bond_proc_file) { - remove_proc_entry(bond->procdir_name, bond_proc_dir); - memset(bond->procdir_name, 0, IFNAMSIZ); - bond->bond_proc_file = NULL; + if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, -1); } -} -/* Create the bonding directory under /proc/net, if doesn't exist yet. - * Caller must hold rtnl_lock. - */ -static void bond_create_proc_dir(void) -{ - int len = strlen(DRV_NAME); + bond->flags = bond_dev->flags; - for (bond_proc_dir = proc_net->subdir; bond_proc_dir; - bond_proc_dir = bond_proc_dir->next) { - if ((bond_proc_dir->namelen == len) && - !memcmp(bond_proc_dir->name, DRV_NAME, len)) { - break; + /* looking for addresses to add to slaves' mc list */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) { + bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); } } - if (!bond_proc_dir) { - bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); - if (bond_proc_dir) { - bond_proc_dir->owner = THIS_MODULE; - } else { - printk(KERN_WARNING DRV_NAME - ": Warning: cannot create /proc/net/%s\n", - DRV_NAME); + /* looking for addresses to delete from slaves' list */ + for (dmi = bond->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) { + bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); } } + + /* save master's multicast list */ + bond_mc_list_destroy(bond); + bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC); + + write_unlock_bh(&bond->lock); } -/* Destroy the bonding directory under /proc/net, if empty. - * Caller must hold rtnl_lock. +/* + * Change the MTU of all of a master's slaves to match the master */ -static void bond_destroy_proc_dir(void) +static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { - struct proc_dir_entry *de; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *stop_at; + int res = 0; + int i; - if (!bond_proc_dir) { - return; - } + dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, + (bond_dev ? bond_dev->name : "None"), new_mtu); - /* verify that the /proc dir is empty */ - for (de = bond_proc_dir->subdir; de; de = de->next) { - /* ignore . and .. */ - if (*(de->name) != '.') { - break; + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's MTU while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("s %p s->p %p c_m %p\n", slave, + slave->prev, slave->dev->change_mtu); + if (slave->dev->change_mtu) { + res = slave->dev->change_mtu(slave->dev, new_mtu); + } else { + slave->dev->mtu = new_mtu; + res = 0; + } + + if (res) { + /* If we failed to set the slave's mtu to the new value + * we must abort the operation even in ACTIVE_BACKUP + * mode, because if we allow the backup slaves to have + * different mtu values than the active slave we'll + * need to change their mtu when doing a failover. That + * means changing their mtu from timer context, which + * is probably not a good idea. + */ + dprintk("err %d %s\n", res, slave->dev->name); + goto unwind; } } - if (de) { - if (bond_proc_dir->owner == THIS_MODULE) { - bond_proc_dir->owner = NULL; + bond_dev->mtu = new_mtu; + + return 0; + +unwind: + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + if (slave->dev->change_mtu) { + tmp_res = slave->dev->change_mtu(slave->dev, bond_dev->mtu); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); + } + } else { + slave->dev->mtu = bond_dev->mtu; } - } else { - remove_proc_entry(DRV_NAME, proc_net); - bond_proc_dir = NULL; } + + return res; } -#endif /* CONFIG_PROC_FS */ /* * Change HW address @@ -3638,352 +3457,366 @@ static void bond_destroy_proc_dir(void) * downing the master releases all slaves. We can make bonds full of * bonding devices to test this, however. */ -static inline int -bond_set_mac_address(struct net_device *dev, void *addr) +static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr, tmp_sa; - struct slave *slave; - int error; + struct slave *slave, *stop_at; + int res = 0; + int i; - dprintk(KERN_INFO "bond_set_mac_address %p %s\n", dev, - dev->name); + dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "bond_set_mac: slave %p %s\n", slave, - slave->dev->name); + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's hw address while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("slave %p %s\n", slave, slave->dev->name); + if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; - dprintk(KERN_INFO "bond_set_mac EOPNOTSUPP %s\n", - slave->dev->name); + res = -EOPNOTSUPP; + dprintk("EOPNOTSUPP %s\n", slave->dev->name); goto unwind; } - error = slave->dev->set_mac_address(slave->dev, addr); - if (error) { - /* TODO: consider downing the slave + res = slave->dev->set_mac_address(slave->dev, addr); + if (res) { + /* TODO: consider downing the slave * and retry ? * User should expect communications * breakage anyway until ARP finish * updating, so... */ - dprintk(KERN_INFO "bond_set_mac err %d %s\n", - error, slave->dev->name); + dprintk("err %d %s\n", res, slave->dev->name); goto unwind; } } /* success */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); return 0; unwind: - memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len); - tmp_sa.sa_family = dev->type; - - for (slave = slave->next; slave != bond->next; - slave = slave->next) { - int tmp_error; + memcpy(tmp_sa.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + tmp_sa.sa_family = bond_dev->type; - tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa); - if (tmp_error) { - dprintk(KERN_INFO "bond_set_mac_address: " - "unwind err %d dev %s\n", - tmp_error, slave->dev->name); + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + tmp_res = slave->dev->set_mac_address(slave->dev, &tmp_sa); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); } } - return error; + return res; } -/* - * Change the MTU of all of a master's slaves to match the master - */ -static inline int -bond_change_mtu(struct net_device *dev, int newmtu) +static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) { - bonding_t *bond = dev->priv; - slave_t *slave; - int error; - - dprintk(KERN_INFO "CM: b %p nm %d\n", bond, newmtu); - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "CM: s %p s->p %p c_m %p\n", slave, - slave->prev, slave->dev->change_mtu); - if (slave->dev->change_mtu) { - error = slave->dev->change_mtu(slave->dev, newmtu); - } else { - slave->dev->mtu = newmtu; - error = 0; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + int i; - if (error) { - /* If we failed to set the slave's mtu to the new value - * we must abort the operation even in ACTIVE_BACKUP - * mode, because if we allow the backup slaves to have - * different mtu values than the active slave we'll - * need to change their mtu when doing a failover. That - * means changing their mtu from timer context, which - * is probably not a good idea. - */ - dprintk(KERN_INFO "bond_change_mtu err %d %s\n", - error, slave->dev->name); - goto unwind; - } + read_lock(&bond->lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; } - dev->mtu = newmtu; - return 0; + read_lock(&bond->curr_slave_lock); + slave = start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!slave) { + goto free_out; + } + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); -unwind: - for (slave = slave->next; slave != bond->next; - slave = slave->next) { + write_lock(&bond->curr_slave_lock); + bond->curr_active_slave = slave->next; + write_unlock(&bond->curr_slave_lock); - if (slave->dev->change_mtu) { - slave->dev->change_mtu(slave->dev, dev->mtu); - } else { - slave->dev->mtu = dev->mtu; + goto out; } } - return error; +out: + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } /* - * Change device name + * in active-backup mode, we know that bond->curr_active_slave is always valid if + * the bond has a usable interface. */ -static inline int bond_event_changename(struct bonding *bond) +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); - bond_create_proc_info(bond); -#endif + struct bonding *bond = bond_dev->priv; - return NOTIFY_DONE; + /* if we are sending arp packets, try to at least + identify our own ip address */ + if (arp_interval && !my_ip && + (skb->protocol == __constant_htons(ETH_P_ARP))) { + char *the_ip = (char *)skb->data + + sizeof(struct ethhdr) + + sizeof(struct arphdr) + + ETH_ALEN; + memcpy(&my_ip, the_ip, 4); + } + + read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; + } + + if (bond->curr_active_slave) { /* one usable interface */ + skb->dev = bond->curr_active_slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); + goto out; + } else { + goto free_out; + } +out: + read_unlock(&bond->curr_slave_lock); + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } -static int bond_master_netdev_event(unsigned long event, struct net_device *event_dev) +/* + * in XOR mode, we determine the output device by performing xor on + * the source and destination hw adresses. If this device is not + * enabled, find the next slave following this xor slave. + */ +static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond, *event_bond = NULL; + struct bonding *bond = bond_dev->priv; + struct ethhdr *data = (struct ethhdr *)skb->data; + struct slave *slave, *start_at; + int slave_no; + int i; - list_for_each_entry(bond, &bond_dev_list, bond_list) { - if (bond == event_dev->priv) { - event_bond = bond; - break; - } - } + read_lock(&bond->lock); - if (event_bond == NULL) { - return NOTIFY_DONE; + if (!BOND_IS_OK(bond)) { + goto free_out; } - switch (event) { - case NETDEV_CHANGENAME: - return bond_event_changename(event_bond); - case NETDEV_UNREGISTER: - /* - * TODO: remove a bond from the list? - */ - break; - default: - break; + slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt; + + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) { + break; + } } - return NOTIFY_DONE; -} + start_at = slave; -static int bond_slave_netdev_event(unsigned long event, struct net_device *event_dev) -{ - struct net_device *master = event_dev->master; + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); - switch (event) { - case NETDEV_UNREGISTER: - if (master != NULL) { - bond_release(master, event_dev); + goto out; } - break; - case NETDEV_CHANGE: - /* - * TODO: is this what we get if somebody - * sets up a hierarchical bond, then rmmod's - * one of the slave bonding devices? - */ - break; - case NETDEV_DOWN: - /* - * ... Or is it this? - */ - break; - case NETDEV_CHANGEMTU: - /* - * TODO: Should slaves be allowed to - * independently alter their MTU? For - * an active-backup bond, slaves need - * not be the same type of device, so - * MTUs may vary. For other modes, - * slaves arguably should have the - * same MTUs. To do this, we'd need to - * take over the slave's change_mtu - * function for the duration of their - * servitude. - */ - break; - case NETDEV_CHANGENAME: - /* - * TODO: handle changing the primary's name - */ - break; - default: - break; } - return NOTIFY_DONE; +out: + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } /* - * bond_netdev_event: handle netdev notifier chain events. - * - * This function receives events for the netdev chain. The caller (an - * ioctl handler calling notifier_call_chain) holds the necessary - * locks for us to safely manipulate the slave devices (RTNL lock, - * dev_probe_lock). + * in broadcast mode, we send everything to all usable interfaces. */ -static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) { - struct net_device *event_dev = (struct net_device *)ptr; - unsigned short flags; - int res = NOTIFY_DONE; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + struct net_device *tx_dev = NULL; + int i; - dprintk(KERN_INFO "bond_netdev_event n_b %p ev %lx ptr %p\n", - this, event, ptr); + read_lock(&bond->lock); - flags = event_dev->flags & (IFF_MASTER | IFF_SLAVE); - switch (flags) { - case IFF_MASTER: - res = bond_master_netdev_event(event, event_dev); - break; - case IFF_SLAVE: - res = bond_slave_netdev_event(event, event_dev); - break; - default: - /* A master that is also a slave ? */ - break; + if (!BOND_IS_OK(bond)) { + goto free_out; } - return res; -} + read_lock(&bond->curr_slave_lock); + start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!start_at) { + goto free_out; + } + + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + if (tx_dev) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + printk(KERN_ERR DRV_NAME + ": Error: bond_xmit_broadcast(): " + "skb_clone() failed\n"); + continue; + } -static struct notifier_block bond_netdev_notifier = { - .notifier_call = bond_netdev_event, -}; + skb2->dev = tx_dev; + skb2->priority = 1; + dev_queue_xmit(skb2); + } + tx_dev = slave->dev; + } + } -/* De-initialize device specific data. - * Caller must hold rtnl_lock. - */ -static inline void bond_deinit(struct net_device *dev) -{ - struct bonding *bond = dev->priv; + if (tx_dev) { + skb->dev = tx_dev; + skb->priority = 1; + dev_queue_xmit(skb); + } else { + goto free_out; + } - list_del(&bond->bond_list); +out: + /* frame sent to all suitable interfaces */ + read_unlock(&bond->lock); + return 0; -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); -#endif +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } -/* Unregister and free all bond devices. - * Caller must hold rtnl_lock. - */ -static void bond_free_all(void) +#ifdef CONFIG_NET_FASTROUTE +static int bond_accept_fastpath(struct net_device *bond_dev, struct dst_entry *dst) { - struct bonding *bond, *nxt; - - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { - struct net_device *dev = bond->device; - - unregister_netdevice(dev); - bond_deinit(dev); - } - -#ifdef CONFIG_PROC_FS - bond_destroy_proc_dir(); -#endif + return -1; } +#endif + +/*------------------------- Device initialization ---------------------------*/ /* * Does not allocate but creates a /proc entry. * Allowed to fail. */ -static int __init bond_init(struct net_device *dev) +static int __init bond_init(struct net_device *bond_dev) { - struct bonding *bond; + struct bonding *bond = bond_dev->priv; int count; -#ifdef BONDING_DEBUG - printk (KERN_INFO "Begin bond_init for %s\n", dev->name); -#endif - bond = dev->priv; + dprintk("Begin bond_init for %s\n", bond_dev->name); /* initialize rwlocks */ rwlock_init(&bond->lock); - rwlock_init(&bond->ptrlock); + rwlock_init(&bond->curr_slave_lock); /* Initialize pointers */ - bond->next = bond->prev = (slave_t *)bond; - bond->current_slave = NULL; + bond->first_slave = NULL; + bond->curr_active_slave = NULL; bond->current_arp_slave = NULL; - bond->device = dev; + bond->primary_slave = NULL; + bond->dev = bond_dev; - /* Initialize the device structure. */ - dev->set_mac_address = bond_set_mac_address; + /* Initialize the device entry points */ + bond_dev->open = bond_open; + bond_dev->stop = bond_close; + bond_dev->get_stats = bond_get_stats; + bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->set_multicast_list = bond_set_multicast_list; + bond_dev->change_mtu = bond_change_mtu; + bond_dev->set_mac_address = bond_set_mac_address; switch (bond_mode) { - case BOND_MODE_ACTIVEBACKUP: - dev->hard_start_xmit = bond_xmit_activebackup; - break; case BOND_MODE_ROUNDROBIN: - dev->hard_start_xmit = bond_xmit_roundrobin; + bond_dev->hard_start_xmit = bond_xmit_roundrobin; + break; + case BOND_MODE_ACTIVEBACKUP: + bond_dev->hard_start_xmit = bond_xmit_activebackup; break; case BOND_MODE_XOR: - dev->hard_start_xmit = bond_xmit_xor; + bond_dev->hard_start_xmit = bond_xmit_xor; break; case BOND_MODE_BROADCAST: - dev->hard_start_xmit = bond_xmit_broadcast; + bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: - dev->hard_start_xmit = bond_3ad_xmit_xor; + bond_dev->hard_start_xmit = bond_3ad_xmit_xor; /* extern */ break; case BOND_MODE_TLB: case BOND_MODE_ALB: - dev->hard_start_xmit = bond_alb_xmit; - dev->set_mac_address = bond_alb_set_mac_address; + bond_dev->hard_start_xmit = bond_alb_xmit; /* extern */ + bond_dev->set_mac_address = bond_alb_set_mac_address; /* extern */ break; default: - printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); + printk(KERN_ERR DRV_NAME + ": Error: Unknown bonding mode %d\n", + bond_mode); return -EINVAL; } - dev->get_stats = bond_get_stats; - dev->open = bond_open; - dev->stop = bond_close; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = bond_ioctl; - dev->change_mtu = bond_change_mtu; - dev->tx_queue_len = 0; - dev->flags |= IFF_MASTER|IFF_MULTICAST; + bond_dev->destructor = free_netdev; #ifdef CONFIG_NET_FASTROUTE - dev->accept_fastpath = bond_accept_fastpath; + bond_dev->accept_fastpath = bond_accept_fastpath; #endif - printk(KERN_INFO "%s registered with", dev->name); - if (miimon > 0) { + /* Initialize the device options */ + bond_dev->tx_queue_len = 0; + bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + + printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name); + if (miimon) { printk(" MII link monitoring set to %d ms", miimon); updelay /= miimon; downdelay /= miimon; @@ -3992,50 +3825,75 @@ static int __init bond_init(struct net_d } printk(", in %s mode.\n", bond_mode_name()); - printk(KERN_INFO "%s registered with", dev->name); + printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name); if (arp_interval > 0) { - printk(" ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); - for (count=0 ; countdestructor = free_netdev; - list_add_tail(&bond->bond_list, &bond_dev_list); return 0; } -/* -static int __init bond_probe(struct net_device *dev) +/* De-initialize device specific data. + * Caller must hold rtnl_lock. + */ +static inline void bond_deinit(struct net_device *bond_dev) { - bond_init(dev); - return 0; + struct bonding *bond = bond_dev->priv; + + list_del(&bond->bond_list); + +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); +#endif } + +/* Unregister and free all bond devices. + * Caller must hold rtnl_lock. */ +static void bond_free_all(void) +{ + struct bonding *bond, *nxt; + + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + struct net_device *bond_dev = bond->dev; + + unregister_netdevice(bond_dev); + bond_deinit(bond_dev); + } + +#ifdef CONFIG_PROC_FS + bond_destroy_proc_dir(); +#endif +} + +/*------------------------- Module initialization ---------------------------*/ /* * Convert string input module parms. Accept either the * number of the mode or its string name. */ -static inline int -bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) +static inline int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) { int i; - for (i = 0; tbl[i].modename != NULL; i++) { + for (i = 0; tbl[i].modename; i++) { if ((isdigit(*mode_arg) && - tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || - (0 == strncmp(mode_arg, tbl[i].modename, - strlen(tbl[i].modename)))) { + tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || + (strncmp(mode_arg, tbl[i].modename, + strlen(tbl[i].modename)) == 0)) { return tbl[i].mode; } } @@ -4043,88 +3901,64 @@ bond_parse_parm(char *mode_arg, struct b return -1; } - -static int __init bonding_init(void) +static int bond_check_params(void) { - int no; - int err; - - printk(KERN_INFO "%s", version); - /* * Convert string parameters. */ if (mode) { bond_mode = bond_parse_parm(mode, bond_mode_tbl); if (bond_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid bonding mode \"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid bonding mode \"%s\"\n", mode == NULL ? "NULL" : mode); return -EINVAL; } } - if (USES_PRIMARY(bond_mode)) { - multicast_mode = BOND_MULTICAST_ACTIVE; - } else { - multicast_mode = BOND_MULTICAST_ALL; - } - - if (multicast) { - multicast_mode = bond_parse_parm(multicast, bond_mc_tbl); - if (multicast_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid multicast mode \"%s\"\n", - multicast == NULL ? "NULL" : multicast); - return -EINVAL; - } - } - if (lacp_rate) { if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_WARNING - "lacp_rate param is irrelevant in mode %s\n", + printk(KERN_INFO DRV_NAME + ": lacp_rate param is irrelevant in mode %s\n", bond_mode_name()); } else { lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); if (lacp_fast == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid lacp rate " - "\"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); - return -EINVAL; } } } if (max_bonds < 1 || max_bonds > INT_MAX) { - printk(KERN_WARNING - "bonding_init(): max_bonds (%d) not in range %d-%d, " - "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)", + printk(KERN_WARNING DRV_NAME + ": Warning: max_bonds (%d) not in range %d-%d, so it " + "was reset to BOND_DEFAULT_MAX_BONDS (%d)", max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } if (miimon < 0) { - printk(KERN_WARNING - "bonding_init(): miimon module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter (%d), " "not in range 0-%d, so it was reset to %d\n", miimon, INT_MAX, BOND_LINK_MON_INTERV); miimon = BOND_LINK_MON_INTERV; } if (updelay < 0) { - printk(KERN_WARNING - "bonding_init(): updelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", updelay, INT_MAX); updelay = 0; } if (downdelay < 0) { - printk(KERN_WARNING - "bonding_init(): downdelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", downdelay, INT_MAX); downdelay = 0; @@ -4132,82 +3966,69 @@ static int __init bonding_init(void) /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { - if (arp_interval != 0) { - printk(KERN_WARNING "bonding_init(): ARP monitoring" - "can't be used simultaneously with 802.3ad, " - "disabling ARP monitoring\n"); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: ARP monitoring can't be used " + "simultaneously with 802.3ad, disabling ARP " + "monitoring\n"); arp_interval = 0; } - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure, " - "speed and duplex which are essential " - "for 802.3ad operation\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + if (miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure, speed and duplex which are " + "essential for 802.3ad operation\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ALL) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ALL for 802.3ad\n"); - printk(KERN_ERR "Forcing Multicast mode to ALL\n"); - multicast_mode = BOND_MULTICAST_ALL; - } } /* reset values for TLB/ALB */ if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure " - "and link speed which are essential " + if (!miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure and link speed which are essential " "for TLB/ALB load balancing\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ACTIVE) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ACTIVE for TLB/ALB\n"); - printk(KERN_ERR "Forcing Multicast mode to ACTIVE\n"); - multicast_mode = BOND_MULTICAST_ACTIVE; - } } if (bond_mode == BOND_MODE_ALB) { - printk(KERN_INFO - "In ALB mode you might experience client disconnections" - " upon reconnection of a link if the bonding module" - " updelay parameter (%d msec) is incompatible with the" - " forwarding delay time of the switch\n", updelay); + printk(KERN_NOTICE DRV_NAME + ": In ALB mode you might experience client " + "disconnections upon reconnection of a link if the " + "bonding module updelay parameter (%d msec) is " + "incompatible with the forwarding delay time of the " + "switch\n", + updelay); } - if (miimon == 0) { - if ((updelay != 0) || (downdelay != 0)) { + if (!miimon) { + if (updelay || downdelay) { /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - printk(KERN_WARNING - "bonding_init(): miimon module parameter not " - "set and updelay (%d) or downdelay (%d) module " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter not set " + "and updelay (%d) or downdelay (%d) module " "parameter is set; updelay and downdelay have " "no effect unless miimon is set\n", - updelay, downdelay); + updelay, downdelay); } } else { /* don't allow arp monitoring */ - if (arp_interval != 0) { - printk(KERN_WARNING - "bonding_init(): miimon (%d) and arp_interval " - "(%d) can't be used simultaneously, " - "disabling ARP monitoring\n", - miimon, arp_interval); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon (%d) and arp_interval (%d) " + "can't be used simultaneously, disabling ARP " + "monitoring\n", + miimon, arp_interval); arp_interval = 0; } @@ -4215,103 +4036,114 @@ static int __init bonding_init(void) /* updelay will be rounded in bond_init() when it * is divided by miimon, we just inform user here */ - printk(KERN_WARNING - "bonding_init(): updelay (%d) is not a multiple " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay (%d) is not a multiple " "of miimon (%d), updelay rounded to %d ms\n", - updelay, miimon, (updelay / miimon) * miimon); + updelay, miimon, (updelay / miimon) * miimon); } if ((downdelay % miimon) != 0) { /* downdelay will be rounded in bond_init() when it * is divided by miimon, we just inform user here */ - printk(KERN_WARNING - "bonding_init(): downdelay (%d) is not a " - "multiple of miimon (%d), downdelay rounded " - "to %d ms\n", - downdelay, miimon, + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay (%d) is not a multiple " + "of miimon (%d), downdelay rounded to %d ms\n", + downdelay, miimon, (downdelay / miimon) * miimon); } } if (arp_interval < 0) { - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter (%d), " - "not in range 0-%d, so it was reset to %d\n", + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + ", not in range 0-%d, so it was reset to %d\n", arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); arp_interval = BOND_LINK_ARP_INTERV; } - for (arp_ip_count=0 ; - (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; - arp_ip_count++ ) { + for (arp_ip_count = 0; + (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; + arp_ip_count++) { /* not complete check, but should be good enough to catch mistakes */ - if (!isdigit(arp_ip_target[arp_ip_count][0])) { - printk(KERN_WARNING - "bonding_init(): bad arp_ip_target module " - "parameter (%s), ARP monitoring will not be " - "performed\n", - arp_ip_target[arp_ip_count]); - arp_interval = 0; - } else { - u32 ip = in_aton(arp_ip_target[arp_ip_count]); + if (!isdigit(arp_ip_target[arp_ip_count][0])) { + printk(KERN_WARNING DRV_NAME + ": Warning: bad arp_ip_target module parameter " + "(%s), ARP monitoring will not be performed\n", + arp_ip_target[arp_ip_count]); + arp_interval = 0; + } else { + u32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } - } - + } - if ( (arp_interval > 0) && (arp_ip_count==0)) { + if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter " - "(%d) specified without providing an arp_ip_target " + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + "specified without providing an arp_ip_target " "parameter, arp_interval was reset to 0\n", arp_interval); arp_interval = 0; } - if ((miimon == 0) && (arp_interval == 0)) { + if (!miimon && !arp_interval) { /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - printk(KERN_ERR - "bonding_init(): either miimon or " - "arp_interval and arp_ip_target module parameters " - "must be specified, otherwise bonding will not detect " - "link failures! see bonding.txt for details.\n"); + printk(KERN_WARNING DRV_NAME + ": Warning: either miimon or arp_interval and " + "arp_ip_target module parameters must be specified, " + "otherwise bonding will not detect link failures! see " + "bonding.txt for details.\n"); } - if ((primary != NULL) && !USES_PRIMARY(bond_mode)) { + if (primary && !USES_PRIMARY(bond_mode)) { /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - printk(KERN_WARNING - "bonding_init(): %s primary device specified but has " - "no effect in %s mode\n", + printk(KERN_WARNING DRV_NAME + ": Warning: %s primary device specified but has no " + "effect in %s mode\n", primary, bond_mode_name()); primary = NULL; } + return 0; +} + +static int __init bonding_init(void) +{ + int i; + int res; + + printk(KERN_INFO "%s", version); + + res = bond_check_params(); + if (res) { + return res; + } + rtnl_lock(); #ifdef CONFIG_PROC_FS bond_create_proc_dir(); #endif - err = 0; - for (no = 0; no < max_bonds; no++) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); - if (!dev) { - err = -ENOMEM; + for (i = 0; i < max_bonds; i++) { + struct net_device *bond_dev; + + bond_dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); + if (!bond_dev) { + res = -ENOMEM; goto out_err; } - err = dev_alloc_name(dev, "bond%d"); - if (err < 0) { - free_netdev(dev); + res = dev_alloc_name(bond_dev, "bond%d"); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } @@ -4319,18 +4151,18 @@ static int __init bonding_init(void) * /proc files), but before register_netdevice(), because we * need to set function pointers. */ - err = bond_init(dev); - if (err < 0) { - free_netdev(dev); + res = bond_init(bond_dev); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(bond_dev); - err = register_netdevice(dev); - if (err < 0) { - bond_deinit(dev); - free_netdev(dev); + res = register_netdevice(bond_dev); + if (res < 0) { + bond_deinit(bond_dev); + free_netdev(bond_dev); goto out_err; } } @@ -4346,7 +4178,7 @@ out_err: rtnl_unlock(); - return err; + return res; } static void __exit bonding_exit(void) @@ -4362,6 +4194,8 @@ module_init(bonding_init); module_exit(bonding_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); +MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); +MODULE_SUPPORTED_DEVICE("most ethernet devices"); /* * Local variables: @@ -4370,3 +4204,4 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" * tab-width: 8 * End: */ + --- linux-2.6.1-rc1/drivers/net/cs89x0.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/cs89x0.c 2003-12-30 22:49:19.000000000 -0800 @@ -212,9 +212,7 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int cs89x0_probe(struct net_device *dev); - -static int cs89x0_probe1(struct net_device *dev, int ioaddr); +static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -274,27 +272,51 @@ __setup("cs89x0_media=", media_fn); Return 0 on success. */ -int __init cs89x0_probe(struct net_device *dev) +struct net_device * __init cs89x0_probe(int unit) { - int i; - int base_addr = dev ? dev->base_addr : 0; - - SET_MODULE_OWNER(dev); + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + int irq; + int io; + + if (!dev) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; if (net_debug) - printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr); + printk("cs89x0:cs89x0_probe(0x%x)\n", io); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return cs89x0_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; netcard_portlist[i]; i++) { - if (cs89x0_probe1(dev, netcard_portlist[i]) == 0) - return 0; + if (io > 0x1ff) { /* Check a single specified location. */ + err = cs89x0_probe1(dev, io, 0); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = netcard_portlist; *port; port++) { + if (cs89x0_probe1(dev, *port, 0) == 0) + break; + dev->irq = irq; + } + if (!*port) + err = -ENODEV; } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + outw(PP_ChipID, dev->base_addr + ADD_PORT); + release_region(dev->base_addr, NETCARD_IO_EXTENT); +out: + free_netdev(dev); printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); - return -ENODEV; + return ERR_PTR(err); } static int @@ -375,39 +397,34 @@ get_eeprom_cksum(int off, int len, int * */ static int __init -cs89x0_probe1(struct net_device *dev, int ioaddr) +cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) { - struct net_local *lp; + struct net_local *lp = (struct net_local *)dev->priv; static unsigned version_printed; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; + SET_MODULE_OWNER(dev); /* Initialize the device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == 0) { - retval = -ENOMEM; - goto out; - } - lp = (struct net_local *)dev->priv; + if (!modular) { memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); -#if !defined(MODULE) && (ALLOW_DMA != 0) +#ifndef MODULE +#if ALLOW_DMA if (g_cs89x0_dma) { lp->use_dma = 1; lp->dma = g_cs89x0_dma; lp->dmasize = 16; /* Could make this an option... */ } #endif -#ifndef MODULE lp->force = g_cs89x0_media__force; #endif } - lp = (struct net_local *)dev->priv; /* Grab the region so we can find another board if autoIRQ fails. */ + /* WTF is going on here? */ if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) { printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", dev->name, ioaddr, NETCARD_IO_EXTENT); @@ -696,9 +713,6 @@ printk("PP_addr=0x%x\n", inw(ioaddr + AD dev->set_multicast_list = set_multicast_list; dev->set_mac_address = set_mac_address; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - printk("\n"); if (net_debug) printk("cs89x0_probe1() successful\n"); @@ -706,9 +720,6 @@ printk("PP_addr=0x%x\n", inw(ioaddr + AD out2: release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: - kfree(dev->priv); - dev->priv = 0; -out: return retval; } @@ -1655,7 +1666,7 @@ static int set_mac_address(struct net_de #ifdef MODULE -static struct net_device dev_cs89x0; +static struct net_device *dev_cs89x0; /* * Support the 'debug' module parm even if we're compiled for non-debug to @@ -1733,6 +1744,7 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); struct net_local *lp; int ret = 0; @@ -1741,18 +1753,12 @@ init_module(void) #else debug = 0; #endif - - dev_cs89x0.irq = irq; - dev_cs89x0.base_addr = io; - - dev_cs89x0.init = cs89x0_probe; - dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev_cs89x0.priv == 0) { - printk(KERN_ERR "cs89x0.c: Out of memory.\n"); + if (!dev) return -ENOMEM; - } - memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - lp = (struct net_local *)dev_cs89x0.priv; + + dev->irq = irq; + dev->base_addr = io; + lp = dev->priv; #if ALLOW_DMA if (use_dma) { @@ -1782,7 +1788,10 @@ init_module(void) printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); ret = -EPERM; goto out; - } + } else if (io <= 0x1ff) { + ret = -ENXIO; + goto out; + } #if ALLOW_DMA if (use_dma && dmasize != 16 && dmasize != 64) { @@ -1791,30 +1800,31 @@ init_module(void) goto out; } #endif + ret = cs89x0_probe1(dev, io, 1); + if (ret) + goto out; - if (register_netdev(&dev_cs89x0) != 0) { + if (register_netdev(dev) != 0) { printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); ret = -ENXIO; + outw(PP_ChipID, dev->base_addr + ADD_PORT); + release_region(dev->base_addr, NETCARD_IO_EXTENT); goto out; } + dev_cs89x0 = dev; + return 0; out: - if (ret) - kfree(dev_cs89x0.priv); + free_netdev(dev); return ret; } void cleanup_module(void) { - if (dev_cs89x0.priv != NULL) { - /* Free up the private structure, or leak memory :-) */ - unregister_netdev(&dev_cs89x0); - outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); - kfree(dev_cs89x0.priv); - dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ - /* If we don't do this, we can't re-insmod it later. */ - release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); - } + unregister_netdev(dev_cs89x0); + outw(PP_ChipID, dev_cs89x0->base_addr + ADD_PORT); + release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); + free_netdev(dev_cs89x0); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/de600.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/drivers/net/de600.c 2003-12-30 22:49:19.000000000 -0800 @@ -99,7 +99,7 @@ static volatile int tx_fifo_in; static volatile int tx_fifo_out; static volatile int free_tx_pages = TX_PAGES; static int was_down; -static spinlock_t de600_lock; +static spinlock_t de600_lock = SPIN_LOCK_UNLOCKED; static inline u8 de600_read_status(struct net_device *dev) { @@ -398,20 +398,31 @@ static void de600_rx_intr(struct net_dev */ } -int __init de600_probe(struct net_device *dev) +static struct net_device * __init de600_probe(void) { int i; - static struct net_device_stats de600_netstats; - /*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/ + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev); + if (!request_region(DE600_IO, 3, "de600")) { + printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); + err = -EBUSY; + goto out; + } + printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name); /* Alpha testers must have the version number to report bugs. */ if (de600_debug > 1) printk(version); /* probe for adapter */ + err = -ENODEV; rx_page = 0; select_nic(); (void)de600_read_status(dev); @@ -419,7 +430,7 @@ int __init de600_probe(struct net_device de600_put_command(STOP_RESET); if (de600_read_status(dev) & 0xf0) { printk(": not at I/O %#3x.\n", DATA_PORT); - return -ENODEV; + goto out1; } /* @@ -444,12 +455,7 @@ int __init de600_probe(struct net_device dev->dev_addr[3] |= 0x70; } else { printk(" not identified in the printer port\n"); - return -ENODEV; - } - - if (!request_region(DE600_IO, 3, "de600")) { - printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); - return -EBUSY; + goto out1; } printk(", Ethernet Address: %02X", dev->dev_addr[0]); @@ -457,22 +463,27 @@ int __init de600_probe(struct net_device printk(":%02X",dev->dev_addr[i]); printk("\n"); - /* Initialize the device structure. */ - dev->priv = &de600_netstats; - - memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; dev->open = de600_open; dev->stop = de600_close; dev->hard_start_xmit = &de600_start_xmit; - ether_setup(dev); - dev->flags&=~IFF_MULTICAST; select_prn(); - return 0; + + err = register_netdev(dev); + if (err) + goto out1; + + return dev; + +out1: + release_region(DE600_IO, 3); +out: + free_netdev(dev); + return ERR_PTR(err); } static int adapter_init(struct net_device *dev) @@ -527,21 +538,21 @@ static int adapter_init(struct net_devic return 0; /* OK */ } -static struct net_device de600_dev; +static struct net_device *de600_dev; static int __init de600_init(void) { - spin_lock_init(&de600_lock); - de600_dev.init = de600_probe; - if (register_netdev(&de600_dev) != 0) - return -EIO; + de600_dev = de600_probe(); + if (IS_ERR(de600_dev)) + return PTR_ERR(de600_dev); return 0; } static void __exit de600_exit(void) { - unregister_netdev(&de600_dev); + unregister_netdev(de600_dev); release_region(DE600_IO, 3); + free_netdev(de600_dev); } module_init(de600_init); --- linux-2.6.1-rc1/drivers/net/de600.h 2003-06-14 12:18:23.000000000 -0700 +++ 25/drivers/net/de600.h 2003-12-30 22:49:19.000000000 -0800 @@ -131,7 +131,6 @@ static void de600_rx_intr(struct net_dev /* Initialization */ static void trigger_interrupt(struct net_device *dev); -int de600_probe(struct net_device *dev); static int adapter_init(struct net_device *dev); /* --- linux-2.6.1-rc1/drivers/net/de620.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/net/de620.c 2003-12-30 22:49:19.000000000 -0800 @@ -226,7 +226,6 @@ static int de620_rx_intr(struct net_devi /* Initialization */ static int adapter_init(struct net_device *); -int de620_probe(struct net_device *); static int read_eeprom(struct net_device *); @@ -814,11 +813,16 @@ static int adapter_init(struct net_devic * * Check if there is a DE-620 connected */ -int __init de620_probe(struct net_device *dev) +struct net_device * __init de620_probe(int unit) { - static struct net_device_stats de620_netstats; - int i; byte checkbyte = 0xa5; + struct net_device *dev; + int err = -ENOMEM; + int i; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + goto out; SET_MODULE_OWNER(dev); @@ -831,11 +835,23 @@ int __init de620_probe(struct net_device dev->base_addr = io; dev->irq = irq; + /* allow overriding parameters on command line */ + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + if (de620_debug) printk(version); printk(KERN_INFO "D-Link DE-620 pocket adapter"); + if (!request_region(dev->base_addr, 3, "de620")) { + printk(" io 0x%3lX, which is busy.\n", dev->base_addr); + err = -EBUSY; + goto out1; + } + /* Initially, configure basic nibble mode, so we can read the EEPROM */ NIC_Cmd = DEF_NIC_CMD; de620_set_register(dev, W_EIP, EIPRegister); @@ -846,12 +862,8 @@ int __init de620_probe(struct net_device if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) { printk(" not identified in the printer port\n"); - return -ENODEV; - } - - if (!request_region(dev->base_addr, 3, "de620")) { - printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr); - return -EBUSY; + err = -ENODEV; + goto out2; } /* else, got it! */ @@ -870,10 +882,6 @@ int __init de620_probe(struct net_device else printk(" UTP)\n"); - /* Initialize the device structure. */ - dev->priv = &de620_netstats; - - memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; dev->open = de620_open; dev->stop = de620_close; @@ -884,8 +892,6 @@ int __init de620_probe(struct net_device /* base_addr and irq are already set, see above! */ - ether_setup(dev); - /* dump eeprom */ if (de620_debug) { printk("\nEEPROM contents:\n"); @@ -899,7 +905,17 @@ int __init de620_probe(struct net_device printk("SCR = 0x%02x\n", nic_data.SCR); } - return 0; + err = register_netdev(dev); + if (err) + goto out2; + return dev; + +out2: + release_region(dev->base_addr, 3); +out1: + free_netdev(dev); +out: + return ERR_PTR(err); } /********************************** @@ -994,20 +1010,21 @@ static int __init read_eeprom(struct net * */ #ifdef MODULE -static struct net_device de620_dev; +static struct net_device *de620_dev; int init_module(void) { - de620_dev.init = de620_probe; - if (register_netdev(&de620_dev) != 0) - return -EIO; + de620_dev = de620_probe(-1); + if (IS_ERR(de620_dev)) + return PTR_ERR(de620_dev); return 0; } void cleanup_module(void) { - unregister_netdev(&de620_dev); - release_region(de620_dev.base_addr, 3); + unregister_netdev(de620_dev); + release_region(de620_dev->base_addr, 3); + free_netdev(de620_dev); } #endif /* MODULE */ MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/declance.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/declance.c 2003-12-30 22:49:19.000000000 -0800 @@ -1039,13 +1039,13 @@ static int __init dec_lance_init(const i if (dec_lance_debug && version_printed++ == 0) printk(version); - dev = init_etherdev(NULL, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); /* - * init_etherdev ensures the data structures used by the LANCE + * alloc_etherdev ensures the data structures used by the LANCE * are aligned. */ lp = (struct lance_private *) dev->priv; @@ -1188,9 +1188,6 @@ static int __init dec_lance_init(const i } } - lp->next = root_lance_dev; - root_lance_dev = dev; - /* Copy the ethernet address to the device structure, later to the * lance initialization block so the lance gets it every time it's * (re)initialized. @@ -1239,11 +1236,14 @@ static int __init dec_lance_init(const i init_timer(&lp->multicast_timer); lp->multicast_timer.data = (unsigned long) dev; lp->multicast_timer.function = &lance_set_multicast_retry; - + ret = register_netdev(dev); + if (ret) + goto err_out; + lp->next = root_lance_dev; + root_lance_dev = dev; return 0; err_out: - unregister_netdev(dev); free_netdev(dev); return ret; } @@ -1288,13 +1288,12 @@ static void __exit dec_lance_cleanup(voi while (root_lance_dev) { struct net_device *dev = root_lance_dev; struct lance_private *lp = (struct lance_private *)dev->priv; - + unregister_netdev(dev); #ifdef CONFIG_TC if (lp->slot >= 0) release_tc_card(lp->slot); #endif root_lance_dev = lp->next; - unregister_netdev(dev); free_netdev(dev); } } --- linux-2.6.1-rc1/drivers/net/defxx.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/defxx.c 2003-12-30 22:49:19.000000000 -0800 @@ -491,7 +491,7 @@ err_out_kfree: err_out_region: release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); err_out: - kfree(dev); + free_netdev(dev); return err; } --- linux-2.6.1-rc1/drivers/net/depca.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/depca.c 2003-12-30 22:49:19.000000000 -0800 @@ -681,8 +681,7 @@ static int __init depca_hw_init (struct lp->sh_mem = ioremap(mem_start, mem_len); if (lp->sh_mem == NULL) { printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n"); - release_mem_region (mem_start, mem_len); - goto out_priv; + goto out1; } lp->mem_start = mem_start; @@ -771,7 +770,7 @@ static int __init depca_hw_init (struct status = -ENXIO; if (!irqnum) { printk(" and failed to detect IRQ line.\n"); - goto out_priv; + goto out2; } else { for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++) if (irqnum == depca_irq[i]) { @@ -781,7 +780,7 @@ static int __init depca_hw_init (struct if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); - return -ENXIO; + goto out2; } } } else { @@ -807,11 +806,14 @@ static int __init depca_hw_init (struct device->driver_data = dev; SET_NETDEV_DEV (dev, device); - register_netdev (dev); - return 0; - - out_priv: - + status = register_netdev(dev); + if (status == 0) + return 0; +out2: + iounmap(lp->sh_mem); +out1: + release_mem_region (mem_start, mem_len); +out_priv: return status; } --- linux-2.6.1-rc1/drivers/net/dummy.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/dummy.c 2003-12-30 22:49:19.000000000 -0800 @@ -96,7 +96,7 @@ static int __init dummy_init_module(void return -ENOMEM; if ((err = register_netdev(dev_dummy))) { - kfree(dev_dummy); + free_netdev(dev_dummy); dev_dummy = NULL; } return err; --- linux-2.6.1-rc1/drivers/net/e1000/e1000_ethtool.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/e1000/e1000_ethtool.c 2003-12-30 22:49:19.000000000 -0800 @@ -39,6 +39,10 @@ extern int e1000_up(struct e1000_adapter extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_tx_resources(struct e1000_adapter *adapter); struct e1000_stats { char stat_string[ETH_GSTRING_LEN]; @@ -440,6 +444,71 @@ seeprom_error: return ret_val; } +static int +e1000_ethtool_gring(struct e1000_adapter *adapter, + struct ethtool_ringparam *ring) +{ + e1000_mac_type mac_type = adapter->hw.mac_type; + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + + ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; + ring->tx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_TXD : + E1000_MAX_82544_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; + + return 0; +} +static int +e1000_ethtool_sring(struct e1000_adapter *adapter, + struct ethtool_ringparam *ring) +{ + int err; + e1000_mac_type mac_type = adapter->hw.mac_type; + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_free_rx_resources(adapter); + e1000_free_tx_resources(adapter); + } + + rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); + rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? + E1000_MAX_RXD : E1000_MAX_82544_RXD)); + E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); + + txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); + txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? + E1000_MAX_TXD : E1000_MAX_82544_TXD)); + E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if(netif_running(adapter->netdev)) { + if((err = e1000_setup_rx_resources(adapter))) + goto err_setup_rx; + if((err = e1000_setup_tx_resources(adapter))) + goto err_setup_tx; + if((err = e1000_up(adapter))) + goto err_up; + } + + return 0; +err_up: + e1000_free_tx_resources(adapter); +err_setup_tx: + e1000_free_rx_resources(adapter); +err_setup_rx: + e1000_reset(adapter); + return err; +} + #define REG_PATTERN_TEST(R, M, W) \ { \ uint32_t pat, value; \ @@ -579,8 +648,8 @@ e1000_intr_test(struct e1000_adapter *ad *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq - (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) { + if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, + netdev->name, netdev)) { *data = 1; return -1; } @@ -664,7 +733,7 @@ e1000_intr_test(struct e1000_adapter *ad msec_delay(10); /* Unhook test interrupt handler */ - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); return *data; } @@ -770,9 +839,9 @@ e1000_setup_desc_rings(struct e1000_adap PCI_DMA_TODEVICE); tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(skb->len); - tx_desc->lower.data |= E1000_TXD_CMD_EOP; - tx_desc->lower.data |= E1000_TXD_CMD_IFCS; - tx_desc->lower.data |= E1000_TXD_CMD_RPS; + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RPS); tx_desc->upper.data = 0; } @@ -1502,6 +1571,19 @@ err_geeprom_ioctl: addr += offsetof(struct ethtool_eeprom, data); return e1000_ethtool_seeprom(adapter, &eeprom, addr); } + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering = {ETHTOOL_GRINGPARAM}; + e1000_ethtool_gring(adapter, &ering); + if(copy_to_user(addr, &ering, sizeof(ering))) + return -EFAULT; + return 0; + } + case ETHTOOL_SRINGPARAM: { + struct ethtool_ringparam ering; + if(copy_from_user(&ering, addr, sizeof(ering))) + return -EFAULT; + return e1000_ethtool_sring(adapter, &ering); + } case ETHTOOL_GPAUSEPARAM: { struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM}; e1000_ethtool_gpause(adapter, &epause); --- linux-2.6.1-rc1/drivers/net/e1000/e1000.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/e1000/e1000.h 2003-12-30 22:49:19.000000000 -0800 @@ -92,6 +92,16 @@ struct e1000_adapter; #define E1000_MAX_INTR 10 +/* How many descriptors for TX and RX ? */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 256 +#define E1000_MIN_TXD 80 +#define E1000_MAX_82544_TXD 4096 +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 256 +#define E1000_MIN_RXD 80 +#define E1000_MAX_82544_RXD 4096 + /* Supported Rx Buffer Sizes */ #define E1000_RXBUFFER_2048 2048 #define E1000_RXBUFFER_4096 4096 --- linux-2.6.1-rc1/drivers/net/e1000/e1000_hw.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/e1000/e1000_hw.c 2003-12-30 22:49:19.000000000 -0800 @@ -96,8 +96,14 @@ e1000_set_phy_type(struct e1000_hw *hw) hw->phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: - hw->phy_type = e1000_phy_igp; - break; + if(hw->mac_type == e1000_82541 || + hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547 || + hw->mac_type == e1000_82547_rev_2) { + hw->phy_type = e1000_phy_igp; + break; + } + /* Fall Through */ default: /* Should never have loaded on this device */ hw->phy_type = e1000_phy_undefined; @@ -148,7 +154,6 @@ e1000_phy_init_script(struct e1000_hw *h e1000_write_phy_reg(hw, 0x0000, 0x3300); - if(hw->mac_type == e1000_82547) { uint16_t fused, fine, coarse; @@ -1485,8 +1490,8 @@ e1000_phy_force_speed_duplex(struct e100 if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } - if(i == 0) { /* We didn't get link */ - /* Reset the DSP and wait again for link. */ + if((i == 0) && (hw->phy_type == e1000_phy_m88)) { + /* We didn't get link. Reset the DSP and wait again for link. */ if((ret_val = e1000_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; @@ -1533,6 +1538,25 @@ e1000_phy_force_speed_duplex(struct e100 phy_data))) return ret_val; + /* Polarity reversal workaround for forced 10F/10H links. */ + if(hw->mac_type <= e1000_82544 && + (hw->forced_speed_duplex == e1000_10_full || + hw->forced_speed_duplex == e1000_10_half)) { + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F0F))) + return ret_val; + /* IEEE requirement is 150ms */ + msec_delay(200); + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F00))) + return ret_val; + } } return E1000_SUCCESS; } @@ -1916,7 +1940,6 @@ e1000_check_for_link(struct e1000_hw *hw uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; - uint16_t lp_capability; DEBUGFUNC("e1000_check_for_link"); @@ -1996,24 +2019,17 @@ e1000_check_for_link(struct e1000_hw *hw /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to - * determine if TBI Compatibility needs to be turned on or off. If - * the link partner advertises any speed in addition to Gigabit, then - * we assume that they are GMII-based, and TBI compatibility is not - * needed. If no other speeds are advertised, we assume the link - * partner is TBI-based, and we turn on TBI Compatibility. - */ - if(hw->tbi_compatibility_en) { - if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, - &lp_capability))) - return ret_val; - if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | - NWAY_LPAR_10T_FD_CAPS | - NWAY_LPAR_100TX_HD_CAPS | - NWAY_LPAR_100TX_FD_CAPS | - NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to - * gigabit, we do not need to enable TBI compatibility. + * partner capability register. We use the link speed to determine if + * TBI compatibility needs to be turned on or off. If the link is not + * at gigabit speed, then TBI compatibility is not needed. If we are + * at gigabit speed, we turn on TBI compatibility. + */ + if(hw->tbi_compatibility_en) { + uint16_t speed, duplex; + e1000_get_speed_and_duplex(hw, &speed, &duplex); + if(speed != SPEED_1000) { + /* If link speed is not set to gigabit speed, we do not need + * to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ @@ -2081,6 +2097,29 @@ e1000_check_for_link(struct e1000_hw *hw DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); + + hw->serdes_link_down = FALSE; + } + /* If we force link for non-auto-negotiation switch, check link status + * based on MAC synchronization for internal serdes media type. + */ + else if((hw->media_type == e1000_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + /* SYNCH bit and IV bit are sticky. */ + udelay(10); + if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if(!(rxcw & E1000_RXCW_IV)) { + hw->serdes_link_down = FALSE; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + hw->serdes_link_down = TRUE; + DEBUGOUT("SERDES: Link is down.\n"); + } + } + if((hw->media_type == e1000_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); } return E1000_SUCCESS; } @@ -2481,8 +2520,8 @@ e1000_write_phy_reg_ex(struct e1000_hw * E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 64; i++) { - udelay(50); + for(i = 0; i < 640; i++) { + udelay(5); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -3498,10 +3537,12 @@ e1000_write_eeprom(struct e1000_hw *hw, if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; - if(eeprom->type == e1000_eeprom_microwire) + if(eeprom->type == e1000_eeprom_microwire) { status = e1000_write_eeprom_microwire(hw, offset, words, data); - else + } else { status = e1000_write_eeprom_spi(hw, offset, words, data); + msec_delay(10); + } /* Done with writing */ e1000_release_eeprom(hw); @@ -3719,12 +3760,9 @@ e1000_read_mac_addr(struct e1000_hw * hw hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { - if(hw->perm_mac_addr[5] & 0x01) - hw->perm_mac_addr[5] &= ~(0x01); - else - hw->perm_mac_addr[5] |= 0x01; - } + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + hw->perm_mac_addr[5] ^= 0x01; + for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; return E1000_SUCCESS; @@ -3743,22 +3781,13 @@ void e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; - uint32_t addr_low; - uint32_t addr_high; DEBUGFUNC("e1000_init_rx_addrs"); /* Setup the receive address. */ DEBUGOUT("Programming MAC Address into RAR[0]\n"); - addr_low = (hw->mac_addr[0] | - (hw->mac_addr[1] << 8) | - (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24)); - - addr_high = (hw->mac_addr[4] | - (hw->mac_addr[5] << 8) | E1000_RAH_AV); - E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low); - E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high); + e1000_rar_set(hw, hw->mac_addr, 0); /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); @@ -3775,6 +3804,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw) * mc_addr_list - the list of new multicast addresses * mc_addr_count - number of addresses * pad - number of bytes between addresses in the list + * rar_used_count - offset where to start adding mc addresses into the RAR's * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers @@ -3785,11 +3815,11 @@ void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t *mc_addr_list, uint32_t mc_addr_count, - uint32_t pad) + uint32_t pad, + uint32_t rar_used_count) { uint32_t hash_value; uint32_t i; - uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ DEBUGFUNC("e1000_mc_addr_list_update"); @@ -4523,8 +4553,8 @@ uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); @@ -4543,8 +4573,8 @@ e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); e1000_io_write(hw, io_data, value); --- linux-2.6.1-rc1/drivers/net/e1000/e1000_hw.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/e1000/e1000_hw.h 2003-12-30 22:49:19.000000000 -0800 @@ -291,7 +291,7 @@ int32_t e1000_read_mac_addr(struct e1000 /* Filters (multicast, vlan, receive) */ void e1000_init_rx_addrs(struct e1000_hw *hw); -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -317,9 +317,9 @@ void e1000_pci_clear_mwi(struct e1000_hw void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port); +uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); -void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value); +void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up); int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); @@ -978,7 +978,7 @@ struct e1000_hw { e1000_ms_type master_slave; e1000_ms_type original_master_slave; e1000_ffe_config ffe_config_state; - uint32_t io_base; + unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; uint32_t phy_addr; @@ -1021,6 +1021,7 @@ struct e1000_hw { boolean_t speed_downgraded; e1000_dsp_config dsp_config_state; boolean_t get_link_status; + boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; boolean_t phy_reset_disable; @@ -1310,6 +1311,7 @@ struct e1000_hw { #define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ #define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ --- linux-2.6.1-rc1/drivers/net/e1000/e1000_main.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/e1000/e1000_main.c 2003-12-30 22:49:19.000000000 -0800 @@ -30,10 +30,20 @@ /* Change Log * - * 5.2.20 9/30/03 + * 5.2.27 12/14/03 + * o Added netpoll support. + * o Fixed endianess bug causing ethtool loopback diags to fail on ppc. + * o Use pdev->irq rather than netdev->irq in preparation for MSI support. + * o Report driver message on user override of InterruptThrottleRate + * module parameter. + * o Change I/O address storage from uint32_t to unsigned long. + * o Added ethtool RINGPARAM support. + * + * 5.2.22 10/15/03 * o Bug fix: SERDES devices might be connected to a back-plane * switch that doesn't support auto-neg, so add the capability - * to force 1000/Full. + * to force 1000/Full. Also, since forcing 1000/Full, sample + * RxSynchronize bit to detect link state. * o Bug fix: Flow control settings for hi/lo watermark didn't * consider changes in the Rx FIFO size, which could occur with * Jumbo Frames or with the reduced FIFO in 82547. @@ -42,29 +52,18 @@ * o Bug fix: hang under heavy Tx stress when running out of Tx * descriptors; wasn't clearing context descriptor when backing * out of send because of no-resource condition. + * o Bug fix: check netif_running in dev->poll so we don't have to + * hang in dev->close until all polls are finished. [Robert + * Ollson (robert.olsson@data.slu.se)]. + * o Revert TxDescriptor ring size back to 256 since change to 1024 + * wasn't accepted into the kernel. * * 5.2.16 8/8/03 - * o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1 - * o Bug fix: reset h/w before first EEPROM read because we don't know - * who may have been messing with the device before we got there. - * [Dave Johnson (ddj -a-t- cascv.brown.edu)] - * o Bug fix: read the correct work from EEPROM to detect programmed - * WoL settings. - * o Bug fix: TSO would hang if space left in FIFO was being miscalculated - * when mss dropped without a correspoding drop in the DMA buffer size. - * o ASF for Fiber nics isn't supported. - * o Bug fix: Workaround added for potential hang with 82544 running in - * PCI-X if send buffer terminates within an evenly-aligned dword. - * o Feature: Add support for ethtool flow control setting. - * o Feature: Add support for ethtool TSO setting. - * o Feature: Increase default Tx Descriptor count to 1024 for >= 82544. - * - * 5.1.13 5/28/03 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.20-k1"; +char e1000_driver_version[] = "5.2.27-k1"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table @@ -89,7 +88,6 @@ static struct pci_device_id e1000_pci_tb {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -113,12 +111,16 @@ static struct pci_device_id e1000_pci_tb MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -/* Local Function Prototypes */ - int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +int e1000_setup_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_rx_resources(struct e1000_adapter *adapter); +void e1000_free_tx_resources(struct e1000_adapter *adapter); +void e1000_free_rx_resources(struct e1000_adapter *adapter); + +/* Local Function Prototypes */ static int e1000_init_module(void); static void e1000_exit_module(void); @@ -127,15 +129,11 @@ static void __devexit e1000_remove(struc static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); -static int e1000_setup_tx_resources(struct e1000_adapter *adapter); -static int e1000_setup_rx_resources(struct e1000_adapter *adapter); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); static void e1000_clean_tx_ring(struct e1000_adapter *adapter); static void e1000_clean_rx_ring(struct e1000_adapter *adapter); -static void e1000_free_tx_resources(struct e1000_adapter *adapter); -static void e1000_free_rx_resources(struct e1000_adapter *adapter); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -182,6 +180,11 @@ static int e1000_suspend(struct pci_dev static int e1000_resume(struct pci_dev *pdev); #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* for netdump / net console */ +static void e1000_netpoll (struct net_device *dev); +#endif + struct notifier_block e1000_notifier_reboot = { .notifier_call = e1000_notify_reboot, .next = NULL, @@ -268,7 +271,7 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_rx(adapter); e1000_alloc_rx_buffers(adapter); - if((err = request_irq(netdev->irq, &e1000_intr, + if((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) return err; @@ -285,7 +288,7 @@ e1000_down(struct e1000_adapter *adapter struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); @@ -434,8 +437,10 @@ e1000_probe(struct pci_dev *pdev, netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif - netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; netdev->base_addr = adapter->hw.io_base; @@ -749,7 +754,7 @@ e1000_close(struct net_device *netdev) * Return 0 on success, negative on failure **/ -static int +int e1000_setup_tx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *txdr = &adapter->tx_ring; @@ -866,7 +871,7 @@ e1000_configure_tx(struct e1000_adapter * Returns 0 on success, negative on failure **/ -static int +int e1000_setup_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rxdr = &adapter->rx_ring; @@ -1005,7 +1010,7 @@ e1000_configure_rx(struct e1000_adapter * Free all transmit software resources **/ -static void +void e1000_free_tx_resources(struct e1000_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -1073,7 +1078,7 @@ e1000_clean_tx_ring(struct e1000_adapter * Free all receive software resources **/ -static void +void e1000_free_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rx_ring = &adapter->rx_ring; @@ -1281,41 +1286,6 @@ e1000_set_multi(struct net_device *netde e1000_leave_82542_rst(adapter); } -static void -e1000_tx_flush(struct e1000_adapter *adapter) -{ - uint32_t ctrl, tctl, txcw, icr; - - e1000_irq_disable(adapter); - - if(adapter->hw.mac_type < e1000_82543) { - /* Transmit Unit Reset */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); - e1000_clean_tx_ring(adapter); - e1000_configure_tx(adapter); - } else { - txcw = E1000_READ_REG(&adapter->hw, TXCW); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE); - - ctrl = E1000_READ_REG(&adapter->hw, CTRL); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU | - E1000_CTRL_ILOS); - - mdelay(10); - - e1000_clean_tx_irq(adapter); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw); - - /* clear the link status change interrupts this caused */ - icr = E1000_READ_REG(&adapter->hw, ICR); - } - - e1000_irq_enable(adapter); -} - /* need to wait a few seconds after link up to get diagnostic information from the phy */ static void @@ -1379,10 +1349,17 @@ e1000_watchdog(unsigned long data) struct net_device *netdev = adapter->netdev; struct e1000_desc_ring *txdr = &adapter->tx_ring; unsigned int i; + uint32_t link; e1000_check_for_link(&adapter->hw); - if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { + if((adapter->hw.media_type == e1000_media_type_internal_serdes) && + !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) + link = !adapter->hw.serdes_link_down; + else + link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; + + if(link) { if(!netif_carrier_ok(netdev)) { e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, @@ -1419,10 +1396,11 @@ e1000_watchdog(unsigned long data) if(!netif_carrier_ok(netdev)) { if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { - unsigned long flags; - spin_lock_irqsave(&netdev->xmit_lock, flags); - e1000_tx_flush(adapter); - spin_unlock_irqrestore(&netdev->xmit_lock, flags); + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + schedule_work(&adapter->tx_timeout_task); } } @@ -2064,7 +2042,7 @@ e1000_irq_disable(struct e1000_adapter * atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(&adapter->hw, IMC, ~0); E1000_WRITE_FLUSH(&adapter->hw); - synchronize_irq(adapter->netdev->irq); + synchronize_irq(adapter->pdev->irq); } /** @@ -2093,6 +2071,7 @@ e1000_intr(int irq, void *data, struct p { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; + struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; @@ -2102,7 +2081,7 @@ e1000_intr(int irq, void *data, struct p return IRQ_NONE; /* Not our interrupt */ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.get_link_status = 1; + hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } @@ -2114,14 +2093,30 @@ e1000_intr(int irq, void *data, struct p */ atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(&adapter->hw, IMC, ~0); + E1000_WRITE_REG(hw, IMC, ~0); __netif_rx_schedule(netdev); } #else + /* Writing IMC and IMS is needed for 82547. + Due to Hub Link bus being occupied, an interrupt + de-assertion message is not able to be sent. + When an interrupt assertion message is generated later, + two messages are re-ordered and sent out. + That causes APIC to think 82547 is in de-assertion + state, while 82547 is in assertion state, resulting + in dead lock. Writing IMC forces 82547 into + de-assertion state. + */ + if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + e1000_irq_disable(adapter); + for(i = 0; i < E1000_MAX_INTR; i++) if(!e1000_clean_rx_irq(adapter) & !e1000_clean_tx_irq(adapter)) break; + + if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + e1000_irq_enable(adapter); #endif return IRQ_HANDLED; @@ -2146,7 +2141,7 @@ e1000_clean(struct net_device *netdev, i *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do) { + if(work_done < work_to_do || !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); } @@ -2642,13 +2637,13 @@ e1000_write_pci_cfg(struct e1000_hw *hw, } uint32_t -e1000_io_read(struct e1000_hw *hw, uint32_t port) +e1000_io_read(struct e1000_hw *hw, unsigned long port) { return inl(port); } void -e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value) +e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value) { outl(value, port); } @@ -2900,4 +2895,20 @@ e1000_resume(struct pci_dev *pdev) } #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void e1000_netpoll (struct net_device *dev) +{ + struct e1000_adapter *adapter = dev->priv; + disable_irq(adapter->pdev->irq); + e1000_intr (adapter->pdev->irq, dev, NULL); + enable_irq(adapter->pdev->irq); +} +#endif + /* e1000_main.c */ --- linux-2.6.1-rc1/drivers/net/e1000/e1000_param.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/e1000/e1000_param.c 2003-12-30 22:49:19.000000000 -0800 @@ -196,16 +196,6 @@ E1000_PARAM(InterruptThrottleRate, "Inte #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL -#define DEFAULT_TXD 256 -#define MAX_TXD 256 -#define MIN_TXD 80 -#define MAX_82544_TXD 4096 - -#define DEFAULT_RXD 256 -#define MAX_RXD 256 -#define MIN_RXD 80 -#define MAX_82544_RXD 4096 - #define DEFAULT_RDTR 0 #define MAX_RXDELAY 0xFFFF #define MIN_RXDELAY 0 @@ -320,14 +310,15 @@ e1000_check_options(struct e1000_adapter struct e1000_option opt = { .type = range_option, .name = "Transmit Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_TXD), - .def = DEFAULT_TXD, - .arg = { .r = { .min = MIN_TXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_TXD), + .def = E1000_DEFAULT_TXD, + .arg = { .r = { .min = E1000_MIN_TXD }} }; struct e1000_desc_ring *tx_ring = &adapter->tx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? - MAX_TXD : MAX_82544_TXD; + E1000_MAX_TXD : E1000_MAX_82544_TXD; tx_ring->count = TxDescriptors[bd]; e1000_validate_option(&tx_ring->count, &opt); @@ -337,13 +328,15 @@ e1000_check_options(struct e1000_adapter struct e1000_option opt = { .type = range_option, .name = "Receive Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_RXD), - .def = DEFAULT_RXD, - .arg = { .r = { .min = MIN_RXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_RXD), + .def = E1000_DEFAULT_RXD, + .arg = { .r = { .min = E1000_MIN_RXD }} }; struct e1000_desc_ring *rx_ring = &adapter->rx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; - opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD; + opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; rx_ring->count = RxDescriptors[bd]; e1000_validate_option(&rx_ring->count, &opt); @@ -446,13 +439,19 @@ e1000_check_options(struct e1000_adapter }; adapter->itr = InterruptThrottleRate[bd]; - if(adapter->itr == 0) { - printk(KERN_INFO "%s turned off\n", opt.name); - } else if(adapter->itr == 1 || adapter->itr == -1) { - /* Dynamic mode */ + switch(adapter->itr) { + case -1: adapter->itr = 1; - } else { + break; + case 0: + printk(KERN_INFO "%s turned off\n", opt.name); + break; + case 1: + printk(KERN_INFO "%s set to dynamic mode\n", opt.name); + break; + default: e1000_validate_option(&adapter->itr, &opt); + break; } } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/net/e100.c 2003-12-30 22:49:19.000000000 -0800 @@ -0,0 +1,2321 @@ +/******************************************************************************* + + + Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + + 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. + + 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. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * e100.c: Intel(R) PRO/100 ethernet driver + * + * (Re)written 2003 by scott.feldman@intel.com. Based loosely on + * original e100 driver, but better described as a munging of + * e100, e1000, eepro100, tg3, 8139cp, and other drivers. + * + * References: + * Intel 8255x 10/100 Mbps Ethernet Controller Family, + * Open Source Software Developers Manual, + * http://sourceforge.net/projects/e1000 + * + * + * Theory of Operation + * + * I. General + * + * The driver supports Intel(R) 10/100 Mbps PCI Fast Ethernet + * controller family, which includes the 82557, 82558, 82559, 82550, + * 82551, and 82562 devices. 82558 and greater controllers + * integrate the Intel 82555 PHY. The controllers are used in + * server and client network interface cards, as well as in + * LAN-On-Motherboard (LOM), CardBus, MiniPCI, and ICHx + * configurations. 8255x supports a 32-bit linear addressing + * mode and operates at 33Mhz PCI clock rate. + * + * II. Driver Operation + * + * Memory-mapped mode is used exclusively to access the device's + * shared-memory structure, the Control/Status Registers (CSR). All + * setup, configuration, and control of the device, including queuing + * of Tx, Rx, and configuration commands is through the CSR. + * cmd_lock serializes accesses to the CSR command register. cb_lock + * protects the shared Command Block List (CBL). + * + * 8255x is highly MII-compliant and all access to the PHY go + * through the Management Data Interface (MDI). Consequently, the + * driver leverages the mii.c library shared with other MII-compliant + * devices. + * + * Big- and Little-Endian byte order as well as 32- and 64-bit + * archs are supported. Weak-ordered memory and non-cache-coherent + * archs are supported. + * + * III. Transmit + * + * A Tx skb is mapped and hangs off of a TCB. TCBs are linked + * together in a fixed-size ring (CBL) thus forming the flexible mode + * memory structure. A TCB marked with the suspend-bit indicates + * the end of the ring. The last TCB processed suspends the + * controller, and the controller can be restarted by issue a CU + * resume command to continue from the suspend point, or a CU start + * command to start at a given position in the ring. + * + * Non-Tx commands (config, multicast setup, etc) are linked + * into the CBL ring along with Tx commands. The common structure + * used for both Tx and non-Tx commands is the Command Block (CB). + * + * cb_to_use is the next CB to use for queuing a command; cb_to_clean + * is the next CB to check for completion; cb_to_send is the first + * CB to start on in case of a previous failure to resume. CB clean + * up happens in interrupt context in response to a CU interrupt, or + * in dev->poll in the case where NAPI is enabled. cbs_avail keeps + * track of number of free CB resources available. + * + * Hardware padding of short packets to minimum packet size is + * enabled. 82557 pads with 7Eh, while the later controllers pad + * with 00h. + * + * IV. Recieve + * + * The Receive Frame Area (RFA) comprises a ring of Receive Frame + * Descriptors (RFD) + data buffer, thus forming the simplified mode + * memory structure. Rx skbs are allocated to contain both the RFD + * and the data buffer, but the RFD is pulled off before the skb is + * indicated. The data buffer is aligned such that encapsulated + * protocol headers are u32-aligned. Since the RFD is part of the + * mapped shared memory, and completion status is contained within + * the RFD, the RFD must be dma_sync'ed to maintain a consistent + * view from software and hardware. + * + * Under typical operation, the receive unit (RU) is start once, + * and the controller happily fills RFDs as frames arrive. If + * replacement RFDs cannot be allocated, or the RU goes non-active, + * the RU must be restarted. Frame arrival generates an interrupt, + * and Rx indication and re-allocation happen in the same context, + * therefore no locking is required. If NAPI is enabled, this work + * happens in dev->poll. A software-generated interrupt is gen- + * erated from the watchdog to recover from a failed allocation + * senario where all Rx resources have been indicated and none re- + * placed. + * + * V. Miscellaneous + * + * VLAN offloading of tagging, stripping and filtering is not + * supported, but driver will accommodate the extra 4-byte VLAN tag + * for processing by upper layers. Tx/Rx Checksum offloading is not + * supported. Tx Scatter/Gather is not supported. Jumbo Frames is + * not supported (hardware limitation). + * + * NAPI support is enabled with CONFIG_E100_NAPI. + * + * MagicPacket(tm) WoL support is enabled/disabled via ethtool. + * + * Thanks to JC (jchapman@katalix.com) for helping with + * testing/troubleshooting the development driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRV_NAME "e100" +#define DRV_VERSION "3.0.12_dev" +#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 1999-2003 Intel Corporation" +#define PFX DRV_NAME ": " + +#define E100_WATCHDOG_PERIOD 2 * HZ +#define E100_NAPI_WEIGHT 16 + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +static int debug = 3; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +#define DPRINTK(nlevel, klevel, fmt, args...) \ + (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ + printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ + __FUNCTION__ , ## args)) + +#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\ + PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ + PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } +static struct pci_device_id e100_id_table[] = { + INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1031, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1032, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1033, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1034, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1038, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1039, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103A, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103B, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103C, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103D, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103E, 4), + INTEL_8255X_ETHERNET_DEVICE(0x1050, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1051, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1052, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1053, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1054, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1055, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1064, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1065, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1066, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1067, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1068, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1069, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106A, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106B, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1059, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), + INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), + INTEL_8255X_ETHERNET_DEVICE(0x2459, 2), + INTEL_8255X_ETHERNET_DEVICE(0x245D, 2), + { 0, } +}; +MODULE_DEVICE_TABLE(pci, e100_id_table); + +enum mac { + mac_82557_D100_A = 0, + mac_82557_D100_B = 1, + mac_82557_D100_C = 2, + mac_82558_D101_A4 = 4, + mac_82558_D101_B0 = 5, + mac_82559_D101M = 8, + mac_82559_D101S = 9, + mac_82550_D102 = 12, + mac_82550_D102_C = 13, + mac_82551_E = 14, + mac_82551_F = 15, + mac_82551_10 = 16, + mac_unknown = 0xFF, +}; + +enum phy { + phy_100a = 0x000003E0, + phy_100c = 0x035002A8, + phy_82555_tx = 0x015002A8, + phy_nsc_tx = 0x5C002000, + phy_82562_et = 0x033002A8, + phy_82562_em = 0x032002A8, + phy_82562_eh = 0x017002A8, + phy_unknown = 0xFFFFFFFF, +}; + +/* CSR (Control/Status Registers) */ +struct csr { + struct { + u8 status; + u8 stat_ack; + u8 cmd_lo; + u8 cmd_hi; + u32 gen_ptr; + } scb; + u32 port; + u16 flash_ctrl; + u8 eeprom_ctrl_lo; + u8 eeprom_ctrl_hi; + u32 mdi_ctrl; + u32 rx_dma_count; +}; + +enum scb_status { + rus_idle = 0x00, + rus_suspended = 0x04, + rus_no_resources = 0x08, + rus_ready = 0x10, + rus_mask = 0x3C, + cus_idle = 0x00, + cus_suspended = 0x40, + cus_active = 0x80, + cus_mask = 0xC0, +}; + +enum scb_stat_ack { + stat_ack_sw_gen = 0x04, + stat_ack_rnr = 0x10, + stat_ack_cu_idle = 0x20, + stat_ack_frame_rx = 0x40, + stat_ack_cu_cmd_done = 0x80, + stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx), + stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done), +}; + +enum scb_cmd_hi { + irq_mask_none = 0x00, + irq_mask_all = 0x01, + irq_sw_gen = 0x02, +}; + +enum scb_cmd_lo { + ruc_start = 0x01, + ruc_load_base = 0x06, + cuc_start = 0x10, + cuc_resume = 0x20, + cuc_dump_addr = 0x40, + cuc_dump_stats = 0x50, + cuc_load_base = 0x60, + cuc_dump_reset = 0x70, +}; + +enum port { + software_reset = 0x0000, + selftest = 0x0001, + selective_reset = 0x0002, +}; + +enum eeprom_ctrl_lo { + eesk = 0x01, + eecs = 0x02, + eedi = 0x04, + eedo = 0x08, +}; + +enum mdi_ctrl { + mdi_write = 0x04000000, + mdi_read = 0x08000000, + mdi_ready = 0x10000000, +}; + +enum eeprom_op { + op_write = 0x05, + op_read = 0x06, + op_ewds = 0x10, + op_ewen = 0x13, +}; + +enum eeprom_offsets { + eeprom_id = 0x0A, + eeprom_config_asf = 0x0D, + eeprom_smbus_addr = 0x90, +}; + +enum eeprom_id { + eeprom_id_wol = 0x0020, +}; + +enum eeprom_config_asf { + eeprom_asf = 0x8000, + eeprom_gcl = 0x4000, +}; + +enum cb_status { + cb_complete = 0x8000, + cb_ok = 0x2000, +}; + +enum cb_command { + cb_iaaddr = 0x0001, + cb_config = 0x0002, + cb_multi = 0x0003, + cb_tx = 0x0004, + cb_dump = 0x0006, + cb_tx_sf = 0x0008, + cb_cid = 0x1f00, + cb_i = 0x2000, + cb_s = 0x4000, + cb_el = 0x8000, +}; + +struct rfd { + u16 status; + u16 command; + u32 link; + u32 rbd; + u16 actual_size; + u16 size; +}; + +struct rx_list { + struct list_head list; + struct sk_buff *skb; + dma_addr_t dma_addr; + unsigned int length; +}; + +#if defined(__BIG_ENDIAN_BITFIELD) +#define X(a,b) b,a +#else +#define X(a,b) a,b +#endif +struct config { +/*0*/ u8 X(byte_count:6, pad0:2); +/*1*/ u8 X(X(rx_fifo_limit:4, tx_fifo_limit:3), pad1:1); +/*2*/ u8 adaptive_ifs; +/*3*/ u8 X(X(X(X(mwi_enable:1, type_enable:1), read_align_enable:1), + term_write_cache_line:1), pad3:4); +/*4*/ u8 X(rx_dma_max_count:7, pad4:1); +/*5*/ u8 X(tx_dma_max_count:7, dma_max_count_enable:1); +/*6*/ u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1), + tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1), + rx_discard_overruns:1), rx_save_bad_frames:1); +/*7*/ u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2), + pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1), + tx_dynamic_tbd:1); +/*8*/ u8 X(X(mii_mode:1, pad8:6), csma_disabled:1); +/*9*/ u8 X(X(X(X(X(rx_tcpudp_checksum:1, pad9:3), vlan_arp_tco:1), + link_status_wake:1), arp_wake:1), mcmatch_wake:1); +/*10*/ u8 X(X(X(pad10:3, no_source_addr_insertion:1), preamble_length:2), + loopback:2); +/*11*/ u8 X(linear_priority:3, pad11:5); +/*12*/ u8 X(X(linear_priority_mode:1, pad12:3), ifs:4); +/*13*/ u8 ip_addr_lo; +/*14*/ u8 ip_addr_hi; +/*15*/ u8 X(X(X(X(X(X(X(promiscuous_mode:1, broadcast_disabled:1), + wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1), + pad15_2:1), crs_or_cdt:1); +/*16*/ u8 fc_delay_lo; +/*17*/ u8 fc_delay_hi; +/*18*/ u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1), + rx_long_ok:1), fc_priority_threshold:3), pad18:1); +/*19*/ u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1), + fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1), + full_duplex_force:1), full_duplex_pin:1); +/*20*/ u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1); +/*21*/ u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4); +/*22*/ u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6); + u8 pad_d102[9]; +}; + +#define E100_MAX_MULTICAST_ADDRS 64 +struct multi { + u16 count; + u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/]; +}; + +/* Important: keep total struct u32-aligned */ +struct cb { + u16 status; + u16 command; + u32 link; + union { + u8 iaaddr[ETH_ALEN]; + struct config config; + struct multi multi; + struct { + u32 tbd_array; + u16 tcb_byte_count; + u8 threshold; + u8 tbd_count; + struct { + u32 buf_addr; + u16 size; + u16 eol; + } tbd; + } tcb; + u32 dump_buffer_addr; + } u; + struct cb *next, *prev; + dma_addr_t dma_addr; + struct sk_buff *skb; +}; + +enum loopback { + lb_none = 0, lb_mac = 1, lb_phy = 3, +}; + +struct stats { + u32 tx_good_frames, tx_max_collisions, tx_late_collisions, + tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, + tx_multiple_collisions, tx_total_collisions; + u32 rx_good_frames, rx_crc_errors, rx_alignment_errors, + rx_resource_errors, rx_overrun_errors, rx_cdt_errors, + rx_short_frame_errors; + u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; + u16 xmt_tco_frames, rcv_tco_frames; + u32 complete; +}; + +struct mem { + struct { + u32 signature; + u32 result; + } selftest; + struct stats stats; + u8 dump_buf[596]; +}; + +struct param_range { + u32 min; + u32 max; + u32 count; +}; + +struct params { + struct param_range rfds; + struct param_range cbs; +}; + +struct nic { + /* Begin: frequently used values: keep adjacent for cache effect */ + u32 msg_enable ____cacheline_aligned; + struct net_device *netdev; + struct pci_dev *pdev; + + struct list_head rx_list_head ____cacheline_aligned; + struct rx_list *rx_list; + struct rfd blank_rfd; + + spinlock_t cb_lock ____cacheline_aligned; + spinlock_t cmd_lock; + struct csr *csr; + enum scb_cmd_lo cuc_cmd; + unsigned int cbs_avail; + struct cb *cbs; + struct cb *cb_to_use; + struct cb *cb_to_send; + struct cb *cb_to_clean; + u16 tx_command; + /* End: frequently used values: keep adjacent for cache effect */ + + enum { + ich = (1 << 0), + promiscuous = (1 << 1), + multicast_all = (1 << 2), + wol_magic = (1 << 3), + } flags ____cacheline_aligned; + + enum mac mac; + enum phy phy; + struct params params; + struct net_device_stats net_stats; + struct timer_list watchdog; + struct timer_list blink_timer; + struct mii_if_info mii; + enum loopback loopback; + + struct mem *mem; + dma_addr_t dma_addr; + + dma_addr_t cbs_dma_addr; + u8 adaptive_ifs; + u8 tx_threshold; + u32 tx_frames; + u32 tx_collisions; + u32 tx_deferred; + u32 tx_single_collisions; + u32 tx_multiple_collisions; + u32 tx_fc_pause; + u32 tx_tco_frames; + + u32 rx_fc_pause; + u32 rx_fc_unsupported; + u32 rx_tco_frames; + + u8 rev_id; + u16 leds; + u16 eeprom_wc; + u16 eeprom[256]; + u32 pm_state[16]; +}; + +static inline void e100_write_flush(struct nic *nic) +{ + /* Flush previous PCI writes through intermediate bridges + * by doing a benign read */ + (void)readb(&nic->csr->scb.status); +} + +static inline void e100_enable_irq(struct nic *nic) +{ + writeb(irq_mask_none, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); +} + +static inline void e100_disable_irq(struct nic *nic) +{ + writeb(irq_mask_all, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); +} + +static void e100_hw_reset(struct nic *nic) +{ + /* Put CU and RU into idle with a selective reset to get + * device off of PCI bus */ + writel(selective_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* Now fully reset device */ + writel(software_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* TCO workaround - 82559 and greater */ + if(nic->mac >= mac_82559_D101M) { + /* Issue a redundant CU load base without setting + * general pointer, and without waiting for scb to + * clear. This gets us into post-driver. Finally, + * wait 20 msec for reset to take effect. */ + writeb(cuc_load_base, &nic->csr->scb.cmd_lo); + mdelay(20); + } + + /* Mask off our interrupt line - it's unmasked after reset */ + e100_disable_irq(nic); +} + +static int e100_self_test(struct nic *nic) +{ + u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest); + + /* Passing the self-test is a pretty good indication + * that the device can DMA to/from host memory */ + + nic->mem->selftest.signature = 0; + nic->mem->selftest.result = 0xFFFFFFFF; + + writel(selftest | dma_addr, &nic->csr->port); + e100_write_flush(nic); + /* Wait 10 msec for self-test to complete */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + /* Interrupts are enabled after self-test */ + e100_disable_irq(nic); + + /* Check results of self-test */ + if(nic->mem->selftest.result != 0) { + DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n", + nic->mem->selftest.result); + return -ETIMEDOUT; + } + if(nic->mem->selftest.signature == 0) { + DPRINTK(HW, ERR, "Self-test failed: timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) +{ + u32 cmd_addr_data[3]; + u8 ctrl; + int i, j; + + /* Three cmds: write/erase enable, write data, write/erase disable */ + cmd_addr_data[0] = op_ewen << (addr_len - 2); + cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | data; + cmd_addr_data[2] = op_ewds << (addr_len - 2); + + /* Bit-bang cmds to write word to eeprom */ + for(j = 0; j < 3; j++) { + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data[j] & (1 << i)) ? + eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + /* Wait 10 msec for cmd to complete */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + +}; + +/* General technique stolen from the eepro100 driver - very clever */ +static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) +{ + u32 cmd_addr_data; + u16 data = 0; + u8 ctrl; + int i; + + cmd_addr_data = ((op_read << *addr_len) | addr) << 16; + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + /* Bit-bang to read word from eeprom */ + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + /* Eeprom drives a dummy zero to EEDO after receiving + * complete address. Use this to adjust addr_len. */ + ctrl = readb(&nic->csr->eeprom_ctrl_lo); + if(!(ctrl & eedo) && i > 16) { + *addr_len -= (i - 16); + i = 17; + } + data = (data << 1) | (ctrl & eedo ? 1 : 0); + } + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + return data; +}; + +/* Load entire EEPROM image into driver cache and validate checksum */ +static int e100_eeprom_load(struct nic *nic) +{ + u16 addr, addr_len = 8, checksum = 0; + + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + for(addr = 0; addr < nic->eeprom_wc; addr++) { + nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr); + if(addr < nic->eeprom_wc - 1) + checksum += nic->eeprom[addr]; + } + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + checksum = 0xBABA - checksum; + if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { + DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); + return -EAGAIN; + } + + return 0; +} + +/* Save (portion of) driver EEPROM cache to device and update checksum */ +static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) +{ + u16 addr, addr_len = 8, checksum = 0; + + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + if(start + count >= nic->eeprom_wc) + return -EINVAL; + + for(addr = start; addr < start + count; addr++) + e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]); + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + for(addr = 0; addr < nic->eeprom_wc - 1; addr++) + checksum += nic->eeprom[addr]; + nic->eeprom[nic->eeprom_wc - 1] = 0xBABA - checksum; + e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, 0xBABA - checksum); + + return 0; +} + +#define E100_WAIT_SCB_TIMEOUT 40 +static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) +{ + unsigned long flags; + unsigned int i; + int err = 0; + + spin_lock_irqsave(&nic->cmd_lock, flags); + + /* Previous command is accepted when SCB clears */ + for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { + if(likely(!readb(&nic->csr->scb.cmd_lo))) + break; + cpu_relax(); + if(unlikely(i > (E100_WAIT_SCB_TIMEOUT >> 1))) + udelay(5); + } + if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) { + err = -EAGAIN; + goto err_unlock; + } + + if(unlikely(cmd != cuc_resume)) + writel(dma_addr, &nic->csr->scb.gen_ptr); + writeb(cmd, &nic->csr->scb.cmd_lo); + +err_unlock: + spin_unlock_irqrestore(&nic->cmd_lock, flags); + + return err; +} + +static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +{ + struct cb *cb; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&nic->cb_lock, flags); + + if(unlikely(!nic->cbs_avail)) { + err = -ENOMEM; + goto err_unlock; + } + + cb = nic->cb_to_use; + nic->cb_to_use = cb->next; + nic->cbs_avail--; + cb->skb = skb; + + if(unlikely(!nic->cbs_avail)) + err = -ENOSPC; + + cb_prepare(nic, cb, skb); + + /* Order is important otherwise we'll be in a race with h/w: + * set S-bit in current first, then clear S-bit in previous. */ + cb->command |= cpu_to_le16(cb_s); + cb->prev->command &= cpu_to_le16(~cb_s); + + while(nic->cb_to_send != nic->cb_to_use) { + if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd, + nic->cb_to_send->dma_addr)))) { + /* Ok, here's where things get sticky. It's + * possible that we can't schedule the command + * because the controller is too busy, so + * let's just queue the command and try again + * when another command is scheduled. */ + break; + } else { + nic->cuc_cmd = cuc_resume; + nic->cb_to_send = nic->cb_to_send->next; + } + } + +err_unlock: + spin_unlock_irqrestore(&nic->cb_lock, flags); + + return err; +} + +static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) +{ + u32 data_out = 0; + unsigned int i; + + writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); + + for(i = 0; i < 100; i++) { + udelay(20); + if((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) + break; + } + + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out); + return (u16)data_out; +} + +static int mdio_read(struct net_device *netdev, int addr, int reg) +{ + return mdio_ctrl(netdev->priv, addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + mdio_ctrl(netdev->priv, addr, mdi_write, reg, data); +} + +static void e100_get_defaults(struct nic *nic) +{ + struct param_range rfds = { .min = 64, .max = 256, .count = 64 }; + struct param_range cbs = { .min = 64, .max = 256, .count = 64 }; + + pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id); + /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */ + nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->rev_id; + if(nic->mac == mac_unknown) + nic->mac = mac_82557_D100_A; + + nic->params.rfds = rfds; + nic->params.cbs = cbs; + + /* Quadwords to DMA into FIFO before starting frame transmit */ + nic->tx_threshold = 0xE0; + + nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf | + ((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0)); + + /* Template for a freshly allocated RFD */ + nic->blank_rfd.command = cpu_to_le16(cb_el); + nic->blank_rfd.rbd = 0xFFFFFFFF; + nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); + + /* MII setup */ + nic->mii.phy_id_mask = 0x1F; + nic->mii.reg_num_mask = 0x1F; + nic->mii.dev = nic->netdev; + nic->mii.mdio_read = mdio_read; + nic->mii.mdio_write = mdio_write; +} + +static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct config *config = &cb->u.config; + u8 *c = (u8 *)config; + + cb->command = cpu_to_le16(cb_config); + + memset(config, 0, sizeof(struct config)); + + config->byte_count = 0x16; /* bytes in this struct */ + config->rx_fifo_limit = 0x8; /* bytes in FIFO before DMA */ + config->direct_rx_dma = 0x1; /* reserved */ + config->standard_tcb = 0x1; /* 1=standard, 0=extended */ + config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ + config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ + config->tx_underrun_retry = 0x3; /* # of underrun retries */ + config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + config->pad10 = 0x6; + config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ + config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ + config->ifs = 0x6; /* x16 = inter frame spacing */ + config->ip_addr_hi = 0xF2; /* ARP IP filter - not used */ + config->pad15_1 = 0x1; + config->pad15_2 = 0x1; + config->crs_or_cdt = 0x0; /* 0=CRS only, 1=CRS or CDT */ + config->fc_delay_hi = 0x40; /* time delay for fc frame */ + config->tx_padding = 0x1; /* 1=pad short frames */ + config->fc_priority_threshold = 0x7; /* 7=priority fc disabled */ + config->pad18 = 0x1; + config->full_duplex_pin = 0x1; /* 1=examine FDX# pin */ + config->pad20_1 = 0x1F; + config->fc_priority_location = 0x1; /* 1=byte#31, 0=byte#19 */ + config->pad21_1 = 0x5; + + config->adaptive_ifs = nic->adaptive_ifs; + config->loopback = nic->loopback; + + if(nic->mii.force_media && nic->mii.full_duplex) + config->full_duplex_force = 0x1; /* 1=force, 0=auto */ + + if(nic->flags & promiscuous || nic->loopback) { + config->rx_save_bad_frames = 0x1; /* 1=save, 0=discard */ + config->rx_discard_short_frames = 0x0; /* 1=discard, 0=save */ + config->promiscuous_mode = 0x1; /* 1=on, 0=off */ + } + + if(nic->flags & multicast_all) + config->multicast_all = 0x1; /* 1=accept, 0=no */ + + if(!(nic->flags & wol_magic)) + config->magic_packet_disable = 0x1; /* 1=off, 0=on */ + + if(nic->mac >= mac_82558_D101_A4) { + config->fc_disable = 0x1; /* 1=Tx fc off, 0=Tx fc on */ + config->mwi_enable = 0x1; /* 1=enable, 0=disable */ + config->standard_tcb = 0x0; /* 1=standard, 0=extended */ + config->rx_long_ok = 0x1; /* 1=VLANs ok, 0=standard */ + if(nic->mac >= mac_82559_D101M) + config->tno_intr = 0x1; /* TCO stats enable */ + else + config->standard_stat_counter = 0x0; + } + + DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); + DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); + DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); +} + +static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = cpu_to_le16(cb_iaaddr); + memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN); +} + +static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + cb->command = cpu_to_le16(cb_dump); + cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr + + offsetof(struct mem, dump_buf)); +} + +#define NCONFIG_AUTO_SWITCH 0x0080 +#define MII_NSC_CONG MII_RESV1 +#define NSC_CONG_ENABLE 0x0100 +#define NSC_CONG_TXREADY 0x0400 +#define ADVERTISE_FC_SUPPORTED 0x0400 +static int e100_phy_init(struct nic *nic) +{ + struct net_device *netdev = nic->netdev; + u32 addr; + u16 bmcr, stat, id_lo, id_hi, cong; + + /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */ + for(addr = 0; addr < 32; addr++) { + nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr; + bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) + break; + } + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); + if(addr == 32) + return -EAGAIN; + + /* Selected the phy and isolate the rest */ + for(addr = 0; addr < 32; addr++) { + if(addr != nic->mii.phy_id) { + mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); + } else { + bmcr = mdio_read(netdev, addr, MII_BMCR); + mdio_write(netdev, addr, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + } + } + + /* Get phy ID */ + id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); + id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2); + 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) { + /* Disable congestion control */ + cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG); + cong |= NSC_CONG_TXREADY; + cong &= ~NSC_CONG_ENABLE; + mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); + } + + if(nic->mac >= mac_82550_D102) + /* enable/disable MDI/MDI-X auto-switching */ + mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, + nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); + + return 0; +} + +static int e100_hw_init(struct nic *nic) +{ + int err; + + e100_hw_reset(nic); + + DPRINTK(HW, ERR, "e100_hw_init\n"); + if(!in_interrupt() && (err = e100_self_test(nic))) + return err; + + if((err = e100_phy_init(nic))) + return err; + if((err = e100_exec_cmd(nic, cuc_load_base, 0))) + return err; + if((err = e100_exec_cmd(nic, ruc_load_base, 0))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_configure))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_addr, + nic->dma_addr + offsetof(struct mem, stats)))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_reset, 0))) + return err; + + e100_disable_irq(nic); + + return 0; +} + +static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct net_device *netdev = nic->netdev; + struct dev_mc_list *list = netdev->mc_list; + u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS); + + cb->command = cpu_to_le16(cb_multi); + cb->u.multi.count = cpu_to_le16(count * ETH_ALEN); + for(i = 0; list && i < count; i++, list = list->next) + memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr, + ETH_ALEN); +} + +static void e100_set_multicast_list(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + + DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n", + netdev->mc_count, netdev->flags); + + if(netdev->flags & IFF_PROMISC) + nic->flags |= promiscuous; + else + nic->flags &= ~promiscuous; + + if(netdev->flags & IFF_ALLMULTI || + netdev->mc_count > E100_MAX_MULTICAST_ADDRS) + nic->flags |= multicast_all; + else + nic->flags &= ~multicast_all; + + e100_exec_cb(nic, NULL, e100_configure); + e100_exec_cb(nic, NULL, e100_multi); +} + +static void e100_update_stats(struct nic *nic) +{ + struct net_device_stats *ns = &nic->net_stats; + struct stats *s = &nic->mem->stats; + u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : + (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : + &s->complete; + + /* Device's stats reporting may take several microseconds to + * complete, so where always waiting for results of the + * previous command. */ + + if(*complete == le32_to_cpu(0x0000A007)) { + *complete = 0; + nic->tx_frames = le32_to_cpu(s->tx_good_frames); + nic->tx_collisions = le32_to_cpu(s->tx_total_collisions); + ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions); + ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions); + ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs); + ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns); + ns->collisions += nic->tx_collisions; + ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + + le32_to_cpu(s->tx_lost_crs); + ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); + ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors); + ns->rx_over_errors += le32_to_cpu(s->rx_resource_errors); + ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); + ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); + ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + + le32_to_cpu(s->rx_alignment_errors) + + le32_to_cpu(s->rx_short_frame_errors) + + le32_to_cpu(s->rx_cdt_errors); + nic->tx_deferred += le32_to_cpu(s->tx_deferred); + nic->tx_single_collisions += + le32_to_cpu(s->tx_single_collisions); + nic->tx_multiple_collisions += + le32_to_cpu(s->tx_multiple_collisions); + if(nic->mac >= mac_82558_D101_A4) { + nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause); + nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause); + nic->rx_fc_unsupported += + le32_to_cpu(s->fc_rcv_unsupported); + if(nic->mac >= mac_82559_D101M) { + nic->tx_tco_frames += + le16_to_cpu(s->xmt_tco_frames); + nic->rx_tco_frames += + le16_to_cpu(s->rcv_tco_frames); + } + } + } + + e100_exec_cmd(nic, cuc_dump_reset, 0); +} + +static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) +{ + /* Adjust inter-frame-spacing (IFS) between two transmits if + * we're getting collisions on a half-duplex connection. */ + + if(duplex == DUPLEX_HALF) { + u32 prev = nic->adaptive_ifs; + u32 min_frames = (speed == SPEED_100) ? 1000 : 100; + + if((nic->tx_frames / 32 < nic->tx_collisions) && + (nic->tx_frames > min_frames)) { + if(nic->adaptive_ifs < 60) + nic->adaptive_ifs += 5; + } else if (nic->tx_frames < min_frames) { + if(nic->adaptive_ifs >= 5) + nic->adaptive_ifs -= 5; + } + if(nic->adaptive_ifs != prev) + e100_exec_cb(nic, NULL, e100_configure); + } +} + +static void e100_watchdog(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + struct ethtool_cmd cmd; + + DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies); + + /* mii library handles link maintenance tasks */ + + mii_ethtool_gset(&nic->mii, &cmd); + + if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n", + cmd.speed == SPEED_100 ? "100" : "10", + cmd.duplex == DUPLEX_FULL ? "full" : "half"); + } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link down\n"); + } + + mii_check_link(&nic->mii); + + /* Software generated interrupt to recover from (rare) Rx + * allocation failure */ + writeb(irq_sw_gen, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + + e100_update_stats(nic); + e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); + + if(nic->mac <= mac_82557_D100_C) + /* Issue a multicast command to workaround a 557 lock up */ + e100_set_multicast_list(nic->netdev); + + mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); +} + +static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = nic->tx_command; + cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd); + cb->u.tcb.tcb_byte_count = 0; + cb->u.tcb.threshold = nic->tx_threshold; + cb->u.tcb.tbd_count = 1; + cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE)); + cb->u.tcb.tbd.size = cpu_to_le16(skb->len); +} + +static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + int err = e100_exec_cb(nic, skb, e100_xmit_prepare); + + switch(err) { + case -ENOSPC: + /* We queued the skb, but now we're out of space. */ + netif_stop_queue(netdev); + break; + case -ENOMEM: + /* This is a hard error - log it. */ + DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); + netif_stop_queue(netdev); + return 1; + } + + netdev->trans_start = jiffies; + return 0; +} + +static inline int e100_tx_clean(struct nic *nic) +{ + struct cb *cb; + int tx_cleaned = 0; + + spin_lock(&nic->cb_lock); + + DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n", + nic->cb_to_clean->status); + + /* Clean CBs marked complete */ + for(cb = nic->cb_to_clean; + cb->status & cpu_to_le16(cb_complete); + cb = nic->cb_to_clean = cb->next) { + if(likely(cb->skb != NULL)) { + nic->net_stats.tx_packets++; + nic->net_stats.tx_bytes += cb->skb->len; + + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb_any(cb->skb); + tx_cleaned = 1; + } + cb->status = 0; + nic->cbs_avail++; + } + + spin_unlock(&nic->cb_lock); + + /* Recover from running out of Tx resources in xmit_frame */ + if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev))) + netif_wake_queue(nic->netdev); + + return tx_cleaned; +} + +static void e100_clean_cbs(struct nic *nic, int free_mem) +{ + if(nic->cbs) { + while(nic->cb_to_clean != nic->cb_to_use) { + struct cb *cb = nic->cb_to_clean; + if(cb->skb) { + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb(cb->skb); + } + nic->cb_to_clean = nic->cb_to_clean->next; + } + nic->cbs_avail = nic->params.cbs.count; + if(free_mem) { + pci_free_consistent(nic->pdev, + sizeof(struct cb) * nic->params.cbs.count, + nic->cbs, nic->cbs_dma_addr); + nic->cbs = NULL; + nic->cbs_avail = 0; + } + } + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = + nic->cbs; +} + +static int e100_alloc_cbs(struct nic *nic) +{ + struct cb *cb; + unsigned int i, count = nic->params.cbs.count; + + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL; + nic->cbs_avail = 0; + + nic->cbs = pci_alloc_consistent(nic->pdev, + sizeof(struct cb) * count, &nic->cbs_dma_addr); + if(!nic->cbs) + return -ENOMEM; + + for(cb = nic->cbs, i = 0; i < count; cb++, i++) { + cb->next = (i + 1 < count) ? cb + 1 : nic->cbs; + cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1; + + cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); + cb->link = cpu_to_le32(nic->cbs_dma_addr + + ((i+1) % count) * sizeof(struct cb)); + } + + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; + nic->cbs_avail = count; + + return 0; +} + +static inline void e100_start_receiver(struct nic *nic) +{ + /* (Re)start RU if suspended or idle and RFA is fully allocated */ + struct rx_list *curr = + list_entry(nic->rx_list_head.next, struct rx_list, list); + if(curr->skb) { + u8 status = readb(&nic->csr->scb.status); + if(unlikely((status & rus_mask) != rus_ready)) + e100_exec_cmd(nic, ruc_start, curr->dma_addr); + } +} + +static inline int e100_rx_alloc_skb(struct nic *nic, struct rx_list *curr) +{ + unsigned int rx_offset = 2; /* u32 align protocol headers */ + + curr->dma_addr = 0; + curr->length = sizeof(struct rfd) + VLAN_ETH_FRAME_LEN; + + if(!(curr->skb = dev_alloc_skb(curr->length + rx_offset))) + return -ENOMEM; + + skb_reserve(curr->skb, rx_offset); + curr->skb->dev = nic->netdev; + curr->dma_addr = pci_map_single(nic->pdev, curr->skb->data, + curr->length, PCI_DMA_FROMDEVICE); + + return 0; +} + +static inline void e100_rx_rfa_add_tail(struct nic *nic, struct rx_list *curr) +{ + memcpy(curr->skb->data, &nic->blank_rfd, sizeof(struct rfd)); + pci_dma_sync_single(nic->pdev, curr->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); + + if(likely(curr->list.prev != &nic->rx_list_head)) { + struct rx_list *prev = (struct rx_list *)curr->list.prev; + if(likely(prev->skb != NULL)) { + struct rfd *prev_rfd = (struct rfd *)prev->skb->data; + put_unaligned(cpu_to_le32(curr->dma_addr), + (u32 *)&prev_rfd->link); + prev_rfd->command = 0; + pci_dma_sync_single(nic->pdev, prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); + } + } +} + +static inline int e100_rx_indicate(struct nic *nic, struct rx_list *curr, + unsigned int *work_done, unsigned int work_to_do) +{ + struct sk_buff *skb = curr->skb; + struct rfd *rfd = (struct rfd *)skb->data; + u16 rfd_status, actual_size; + + if(unlikely(work_done && *work_done >= work_to_do)) + return -EAGAIN; + + /* Need to sync before taking a peek at cb_complete bit */ + pci_dma_sync_single(nic->pdev, curr->dma_addr, + sizeof(struct rfd), PCI_DMA_FROMDEVICE); + rfd_status = le16_to_cpu(rfd->status); + + DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); + + /* If data isn't ready, nothing to indicate */ + if(unlikely(!(rfd_status & cb_complete))) + return -EAGAIN; + + /* Get actual data size */ + actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; + if(unlikely(actual_size > curr->length - sizeof(struct rfd))) + actual_size = curr->length - sizeof(struct rfd); + + /* Get data */ + pci_dma_sync_single(nic->pdev, curr->dma_addr, + sizeof(struct rfd) + actual_size, + PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, curr->dma_addr, + curr->length, PCI_DMA_FROMDEVICE); + + /* Pull off the RFD and put the actual data (minus eth hdr) */ + skb_reserve(skb, sizeof(struct rfd)); + skb_put(skb, actual_size); + skb->protocol = eth_type_trans(skb, nic->netdev); + + if(unlikely(!(rfd_status & cb_ok)) || + actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) { + /* Don't indicate if errors */ + dev_kfree_skb_any(skb); + } else { + nic->net_stats.rx_packets++; + nic->net_stats.rx_bytes += actual_size; + nic->netdev->last_rx = jiffies; +#ifdef CONFIG_E100_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + if(work_done) + (*work_done)++; + } + + curr->length = 0; + curr->dma_addr = 0; + curr->skb = NULL; + + return 0; +} + +static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done, + unsigned int work_to_do) +{ + struct list_head *list, *tmp; + struct rx_list *curr; + + /* Indicate newly arrived packets */ + list_for_each(list, &nic->rx_list_head) { + curr = list_entry(list, struct rx_list, list); + if(likely(curr->skb != NULL)) + if(e100_rx_indicate(nic, curr, work_done, work_to_do)) + break; + } + + /* Alloc new skbs to refill list */ + list_for_each_safe(list, tmp, &nic->rx_list_head) { + curr = list_entry(list, struct rx_list, list); + if(unlikely(curr->skb != NULL)) + break; /* List is full, done */ + if(unlikely(e100_rx_alloc_skb(nic, curr))) + break; /* Better luck next time (see watchdog) */ + list_del(&curr->list); + list_add_tail(&curr->list, &nic->rx_list_head); + e100_rx_rfa_add_tail(nic, curr); + } + + e100_start_receiver(nic); +} + +static void e100_rx_clean_list(struct nic *nic) +{ + struct list_head *list; + + if(!nic->rx_list) + return; + + list_for_each(list, &nic->rx_list_head) { + struct rx_list *curr = list_entry(list, + struct rx_list, list); + if(curr->skb) { + pci_unmap_single(nic->pdev, curr->dma_addr, + curr->length, PCI_DMA_FROMDEVICE); + dev_kfree_skb(curr->skb); + } + } + + kfree(nic->rx_list); + nic->rx_list = NULL; +} + +static int e100_rx_alloc_list(struct nic *nic) +{ + struct rx_list *curr; + unsigned int i, count = nic->params.rfds.count; + + INIT_LIST_HEAD(&nic->rx_list_head); + + if(!(nic->rx_list = kmalloc(sizeof(struct rx_list)*count, GFP_ATOMIC))) + return -ENOMEM; + + for(curr = nic->rx_list, i = 0; i < count; curr++, i++) { + if(e100_rx_alloc_skb(nic, curr)) { + e100_rx_clean_list(nic); + return -ENOMEM; + } + list_add_tail(&curr->list, &nic->rx_list_head); + e100_rx_rfa_add_tail(nic, curr); + } + + return 0; +} + +static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *netdev = dev_id; + struct nic *nic = netdev->priv; + u8 stat_ack = readb(&nic->csr->scb.stat_ack); + + DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); + + if(stat_ack == 0x00 || /* Not our interrupt */ + stat_ack == 0xFF) /* Hardware is ejected (cardbus, hotswap) */ + return IRQ_NONE; + + /* Ack interrupts */ + writeb(stat_ack, &nic->csr->scb.stat_ack); + e100_write_flush(nic); + +#ifdef CONFIG_E100_NAPI + e100_disable_irq(nic); + netif_rx_schedule(netdev); +#else + if(stat_ack & stat_ack_rx) + e100_rx_clean(nic, NULL, 0); + if(stat_ack & stat_ack_tx) + e100_tx_clean(nic); +#endif + + return IRQ_HANDLED; +} + +#ifdef CONFIG_E100_NAPI +static int e100_poll(struct net_device *netdev, int *budget) +{ + struct nic *nic = netdev->priv; + unsigned int work_to_do = min(netdev->quota, *budget); + unsigned int work_done = 0; + int tx_cleaned; + + e100_rx_clean(nic, &work_done, work_to_do); + tx_cleaned = e100_tx_clean(nic); + + /* If no Rx and Tx cleanup work was done, exit polling mode. */ + if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { + netif_rx_complete(netdev); + e100_enable_irq(nic); + return 0; + } + + *budget -= work_done; + netdev->quota -= work_done; + + return 1; +} +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void e100_netpoll(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + e100_disable_irq(nic); + e100_intr(nic->pdev->irq, netdev, NULL); + e100_enable_irq(nic); +} +#endif + +static struct net_device_stats *e100_get_stats(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return &nic->net_stats; +} + +static int e100_set_mac_address(struct net_device *netdev, void *p) +{ + struct nic *nic = netdev->priv; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + e100_exec_cb(nic, NULL, e100_setup_iaaddr); + + return 0; +} + +static int e100_change_mtu(struct net_device *netdev, int new_mtu) +{ + if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN) + return -EINVAL; + netdev->mtu = new_mtu; + return 0; +} + +static int e100_asf(struct nic *nic) +{ + /* ASF can be enabled from eeprom */ + return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) && + (nic->eeprom[eeprom_config_asf] & eeprom_asf) && + !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && + ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); +} + +static int e100_up(struct nic *nic) +{ + int err; + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_rx_clean_list; + if((err = e100_hw_init(nic))) + goto err_clean_cbs; + e100_set_multicast_list(nic->netdev); + e100_start_receiver(nic); + netif_start_queue(nic->netdev); + mod_timer(&nic->watchdog, jiffies); + if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ, + nic->netdev->name, nic->netdev))) + goto err_no_irq; + e100_enable_irq(nic); + return 0; + +err_no_irq: + del_timer_sync(&nic->watchdog); + netif_stop_queue(nic->netdev); +err_clean_cbs: + e100_clean_cbs(nic, 1); +err_rx_clean_list: + e100_rx_clean_list(nic); + return err; +} + +static void e100_down(struct nic *nic) +{ + e100_disable_irq(nic); + free_irq(nic->pdev->irq, nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + netif_stop_queue(nic->netdev); + e100_clean_cbs(nic, 1); + e100_rx_clean_list(nic); +} + +static void e100_tx_timeout(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + + DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", + readb(&nic->csr->scb.status)); + e100_down(netdev->priv); + e100_up(netdev->priv); +} + +static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) +{ + int err; + struct sk_buff *skb; + struct rx_list *rx; + + /* Use driver resources to perform internal MAC or PHY + * loopback test. A single packet is prepared and transmitted + * in loopback mode, and the test passes if the received + * packet compares byte-for-byte to the transmitted packet. */ + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_clean_rx; + + /* ICH PHY loopback is broken so do MAC loopback instead */ + if(nic->flags & ich && loopback_mode == lb_phy) + loopback_mode = lb_mac; + + nic->loopback = loopback_mode; + if((err = e100_hw_init(nic))) + goto err_loopback_none; + + if(loopback_mode == lb_phy) + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, + BMCR_LOOPBACK); + + e100_start_receiver(nic); + + if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) { + err = -ENOMEM; + goto err_loopback_none; + } + skb_put(skb, ETH_DATA_LEN); + memset(skb->data, 0xFF, ETH_DATA_LEN); + e100_xmit_frame(skb, nic->netdev); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + rx = list_entry(nic->rx_list_head.next, struct rx_list, list); + if(memcmp(rx->skb->data + sizeof(struct rfd), skb->data, ETH_DATA_LEN)) + err = -EAGAIN; + +err_loopback_none: + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0); + nic->loopback = lb_none; + e100_hw_init(nic); + e100_clean_cbs(nic, 1); +err_clean_rx: + e100_rx_clean_list(nic); + return err; +} + +#define MII_LED_CONTROL 0x1B +static void e100_blink_led(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + enum led_state { + led_on = 0x01, + led_off = 0x04, + led_on_559 = 0x05, + led_on_557 = 0x07, + }; + + nic->leds = (nic->leds & led_on) ? led_off : + (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; + mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds); + mod_timer(&nic->blink_timer, jiffies + HZ / 4); +} + +static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev->priv; + return mii_ethtool_gset(&nic->mii, cmd); +} + +static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev->priv; + int err; + + mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET); + err = mii_ethtool_sset(&nic->mii, cmd); + e100_exec_cb(nic, NULL, e100_configure); + + return err; +} + +static void e100_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct nic *nic = netdev->priv; + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, pci_name(nic->pdev)); +} + +static int e100_get_regs_len(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; +#define E100_PHY_REGS 0x1C +#define E100_REGS_LEN 1 + E100_PHY_REGS + \ + sizeof(nic->mem->dump_buf) / sizeof(u32) + return E100_REGS_LEN * sizeof(u32); +} + +static void e100_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct nic *nic = netdev->priv; + u32 *buff = p; + int i; + + regs->version = (1 << 24) | nic->rev_id; + buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 | + readb(&nic->csr->scb.cmd_lo) << 16 | + readw(&nic->csr->scb.status); + for(i = E100_PHY_REGS; i >= 0; i--) + buff[1 + E100_PHY_REGS - i] = + mdio_read(netdev, nic->mii.phy_id, i); + memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf)); + e100_exec_cb(nic, NULL, e100_dump); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf, + sizeof(nic->mem->dump_buf)); +} + +static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev->priv; + wol->supported = (nic->mac >= mac_82558_D101_A4) ? WAKE_MAGIC : 0; + wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0; +} + +static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev->priv; + + if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + return -EOPNOTSUPP; + + if(wol->wolopts) + nic->flags |= wol_magic; + else + nic->flags &= ~wol_magic; + + pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + e100_exec_cb(nic, NULL, e100_configure); + + return 0; +} + +static u32 e100_get_msglevel(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return nic->msg_enable; +} + +static void e100_set_msglevel(struct net_device *netdev, u32 value) +{ + struct nic *nic = netdev->priv; + nic->msg_enable = value; +} + +static int e100_nway_reset(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return mii_nway_restart(&nic->mii); +} + +static u32 e100_get_link(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return mii_link_ok(&nic->mii); +} + +static int e100_get_eeprom_len(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return nic->eeprom_wc << 1; +} + +#define E100_EEPROM_MAGIC 0x1234 +static int e100_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev->priv; + + eeprom->magic = E100_EEPROM_MAGIC; + memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len); + + return 0; +} + +static int e100_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev->priv; + + if(eeprom->magic != E100_EEPROM_MAGIC) + return -EINVAL; + memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len); + + return e100_eeprom_save(nic, eeprom->offset >> 1, + (eeprom->len >> 1) + 1); +} + +static void e100_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev->priv; + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + ring->rx_max_pending = rfds->max; + ring->tx_max_pending = cbs->max; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rfds->count; + ring->tx_pending = cbs->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int e100_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev->priv; + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + if(netif_running(netdev)) + e100_down(nic); + rfds->count = max(ring->rx_pending, rfds->min); + rfds->count = min(rfds->count, rfds->max); + cbs->count = max(ring->tx_pending, cbs->min); + cbs->count = min(cbs->count, cbs->max); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} + +static char e100_gstrings_test[][ETH_GSTRING_LEN] = { + "Link test (on/offline)", + "Eeprom test (on/offline)", + "Self test (offline)", + "Mac loopback (offline)", + "Phy loopback (offline)", +}; +#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN + +static int e100_diag_test_count(struct net_device *netdev) +{ + return E100_TEST_LEN; +} + +static void e100_diag_test(struct net_device *netdev, + struct ethtool_test *test, u64 *data) +{ + struct nic *nic = netdev->priv; + int i; + + memset(data, 0, E100_TEST_LEN * sizeof(u64)); + data[0] = !mii_link_ok(&nic->mii); + data[1] = e100_eeprom_load(nic); + if(test->flags & ETH_TEST_FL_OFFLINE) { + if(netif_running(netdev)) + e100_down(nic); + data[2] = e100_self_test(nic); + data[3] = e100_loopback_test(nic, lb_mac); + data[4] = e100_loopback_test(nic, lb_phy); + if(netif_running(netdev)) + e100_up(nic); + } + for(i = 0; i < E100_TEST_LEN; i++) + test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0; +} + +static int e100_phys_id(struct net_device *netdev, u32 data) +{ + struct nic *nic = netdev->priv; + + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + mod_timer(&nic->blink_timer, jiffies); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(data * HZ); + del_timer_sync(&nic->blink_timer); + mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); + + return 0; +} + +static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + /* device-specific stats */ + "tx_deferred", "tx_single_collisions", "tx_multi_collisions", + "tx_flow_control_pause", "rx_flow_control_pause", + "rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets", +}; +#define E100_NET_STATS_LEN 21 +#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN + +static int e100_get_stats_count(struct net_device *netdev) +{ + return E100_STATS_LEN; +} + +static void e100_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct nic *nic = netdev->priv; + int i; + + for(i = 0; i < E100_NET_STATS_LEN; i++) + data[i] = ((unsigned long *)&nic->net_stats)[i]; + + data[i++] = nic->tx_deferred; + data[i++] = nic->tx_single_collisions; + data[i++] = nic->tx_multiple_collisions; + data[i++] = nic->tx_fc_pause; + data[i++] = nic->rx_fc_pause; + data[i++] = nic->rx_fc_unsupported; + data[i++] = nic->tx_tco_frames; + data[i++] = nic->rx_tco_frames; +} + +static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + switch(stringset) { + case ETH_SS_TEST: + memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test)); + break; + case ETH_SS_STATS: + memcpy(data, *e100_gstrings_stats, sizeof(e100_gstrings_stats)); + break; + } +} + +static struct ethtool_ops e100_ethtool_ops = { + .get_settings = e100_get_settings, + .set_settings = e100_set_settings, + .get_drvinfo = e100_get_drvinfo, + .get_regs_len = e100_get_regs_len, + .get_regs = e100_get_regs, + .get_wol = e100_get_wol, + .set_wol = e100_set_wol, + .get_msglevel = e100_get_msglevel, + .set_msglevel = e100_set_msglevel, + .nway_reset = e100_nway_reset, + .get_link = e100_get_link, + .get_eeprom_len = e100_get_eeprom_len, + .get_eeprom = e100_get_eeprom, + .set_eeprom = e100_set_eeprom, + .get_ringparam = e100_get_ringparam, + .set_ringparam = e100_set_ringparam, + .self_test_count = e100_diag_test_count, + .self_test = e100_diag_test, + .get_strings = e100_get_strings, + .phys_id = e100_phys_id, + .get_stats_count = e100_get_stats_count, + .get_ethtool_stats = e100_get_ethtool_stats, +}; + +static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct nic *nic = netdev->priv; + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data; + + return generic_mii_ioctl(&nic->mii, mii, cmd, NULL); +} + +static int e100_alloc(struct nic *nic) +{ + nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem), + &nic->dma_addr); + return nic->mem ? 0 : -ENOMEM; +} + +static void e100_free(struct nic *nic) +{ + if(nic->mem) { + pci_free_consistent(nic->pdev, sizeof(struct mem), + nic->mem, nic->dma_addr); + nic->mem = NULL; + } +} + +static int e100_open(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + int err = 0; + + netif_carrier_off(netdev); + if((err = e100_up(nic))) + DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n"); + return err; +} + +static int e100_close(struct net_device *netdev) +{ + e100_down(netdev->priv); + return 0; +} + +static int __devinit e100_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct nic *nic; + int err; + + if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { + if(((1 << debug) - 1) & NETIF_MSG_PROBE) + printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n"); + return -ENOMEM; + } + + netdev->open = e100_open; + netdev->stop = e100_close; + netdev->hard_start_xmit = e100_xmit_frame; + netdev->get_stats = e100_get_stats; + netdev->set_multicast_list = e100_set_multicast_list; + netdev->set_mac_address = e100_set_mac_address; + netdev->change_mtu = e100_change_mtu; + netdev->do_ioctl = e100_do_ioctl; + SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); + netdev->tx_timeout = e100_tx_timeout; + netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; +#ifdef CONFIG_E100_NAPI + netdev->poll = e100_poll; + netdev->weight = E100_NAPI_WEIGHT; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e100_netpoll; +#endif + + nic = netdev->priv; + nic->netdev = netdev; + nic->pdev = pdev; + nic->msg_enable = (1 << debug) - 1; + pci_set_drvdata(pdev, netdev); + + if((err = pci_enable_device(pdev))) { + DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n"); + goto err_out_free_dev; + } + + if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + DPRINTK(PROBE, ERR, "Cannot find proper PCI device " + "base address, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } + + if((err = pci_request_regions(pdev, DRV_NAME))) { + DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n"); + goto err_out_disable_pdev; + } + + pci_set_master(pdev); + + if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) { + DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n"); + goto err_out_free_res; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); + if(!nic->csr) { + DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); + err = -ENOMEM; + goto err_out_free_res; + } + + if(ent->driver_data) + nic->flags |= ich; + else + nic->flags &= ~ich; + + spin_lock_init(&nic->cb_lock); + spin_lock_init(&nic->cmd_lock); + + init_timer(&nic->watchdog); + nic->watchdog.function = e100_watchdog; + nic->watchdog.data = (unsigned long)nic; + init_timer(&nic->blink_timer); + nic->blink_timer.function = e100_blink_led; + nic->blink_timer.data = (unsigned long)nic; + + if((err = e100_alloc(nic))) { + DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); + goto err_out_iounmap; + } + + e100_get_defaults(nic); + e100_hw_reset(nic); + e100_phy_init(nic); + + if((err = e100_eeprom_load(nic))) + goto err_out_free; + ((u16 *)netdev->dev_addr)[0] = le16_to_cpu(nic->eeprom[0]); + ((u16 *)netdev->dev_addr)[1] = le16_to_cpu(nic->eeprom[1]); + ((u16 *)netdev->dev_addr)[2] = le16_to_cpu(nic->eeprom[2]); + if(!is_valid_ether_addr(netdev->dev_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC address from " + "EEPROM, aborting.\n"); + err = -EAGAIN; + goto err_out_free; + } + + /* Wol magic packet can be enabled from eeprom */ + if((nic->mac >= mac_82558_D101_A4) && + (nic->eeprom[eeprom_id] & eeprom_id_wol)) + nic->flags |= wol_magic; + + pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + + if((err = register_netdev(netdev))) { + DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); + goto err_out_free; + } + + DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, " + "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", + pci_resource_start(pdev, 0), pdev->irq, + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + + return 0; + +err_out_free: + e100_free(nic); +err_out_iounmap: + iounmap(nic->csr); +err_out_free_res: + pci_release_regions(pdev); +err_out_disable_pdev: + pci_disable_device(pdev); +err_out_free_dev: + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + return err; +} + +static void __devexit e100_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + if(netdev) { + struct nic *nic = netdev->priv; + unregister_netdev(netdev); + e100_free(nic); + iounmap(nic->csr); + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +#ifdef CONFIG_PM +static int e100_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev->priv; + + if(netif_running(netdev)) + e100_down(nic); + e100_hw_reset(nic); + netif_device_detach(netdev); + + pci_save_state(pdev, nic->pm_state); + pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic))); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + + return 0; +} + +static int e100_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev->priv; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev, nic->pm_state); + e100_hw_init(nic); + + netif_device_attach(netdev); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} +#endif + +static struct pci_driver e100_driver = { + .name = DRV_NAME, + .id_table = e100_id_table, + .probe = e100_probe, + .remove = __devexit_p(e100_remove), +#ifdef CONFIG_PM + .suspend = e100_suspend, + .resume = e100_resume, +#endif +}; + +static int __init e100_init_module(void) +{ + if(((1 << debug) - 1) & NETIF_MSG_DRV) { + printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT); + } + return pci_module_init(&e100_driver); +} + +static void __exit e100_cleanup_module(void) +{ + pci_unregister_driver(&e100_driver); +} + +module_init(e100_init_module); +module_exit(e100_cleanup_module); --- linux-2.6.1-rc1/drivers/net/e100/e100_config.c 2003-12-30 22:37:21.000000000 -0800 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,639 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_config.c * -* * -* Abstract: Functions for configuring the network adapter. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100_config.h" - -static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable); - -static const u8 def_config[] = { - CB_CFIG_BYTE_COUNT, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01, - 0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00, - 0x40, 0xf2, 0x80, 0x3f, 0x05 -}; - -/** - * e100_config_init_82557 - config the 82557 adapter - * @bdp: atapter's private data struct - * - * This routine will initialize the 82557 configure block. - * All other init functions will only set values that are - * different from the 82557 default. - */ -void -e100_config_init_82557(struct e100_private *bdp) -{ - /* initialize config block */ - memcpy(bdp->config, def_config, sizeof (def_config)); - bdp->config[0] = CB_CFIG_BYTE_COUNT; /* just in case */ - - e100_config_ifs(bdp); - - /* - * Enable extended statistical counters (82558 and up) and TCO counters - * (82559 and up) and set the statistical counters' mode in bdp - * - * stat. mode | TCO stat. bit (2) | Extended stat. bit (5) - * ------------------------------------------------------------------ - * Basic (557) | 0 | 1 - * ------------------------------------------------------------------ - * Extended (558) | 0 | 0 - * ------------------------------------------------------------------ - * TCO (559) | 1 | 1 - * ------------------------------------------------------------------ - * Reserved | 1 | 0 - * ------------------------------------------------------------------ - */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_BASIC_STATS; - - /* Setup for MII or 503 operation. The CRS+CDT bit should only be set */ - /* when operating in 503 mode. */ - if (bdp->phy_addr == 32) { - bdp->config[8] &= ~CB_CFIG_503_MII; - bdp->config[15] |= CB_CFIG_CRS_OR_CDT; - } else { - bdp->config[8] |= CB_CFIG_503_MII; - bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT; - } - - e100_config_fc(bdp); - e100_config_force_dplx(bdp); - e100_config_promisc(bdp, false); - e100_config_mulcast_enbl(bdp, false); -} - -static void -e100_config_init_82558(struct e100_private *bdp) -{ - /* MWI enable. This should be turned on only if the adapter is a 82558/9 - * and if the PCI command reg. has enabled the MWI bit. */ - bdp->config[3] |= CB_CFIG_MWI_EN; - - bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS; - - if (bdp->rev_id >= D101MA_REV_ID) { - /* this is 82559 and up - enable TCO counters */ - bdp->config[6] |= CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_TCO_STATS; - - if ((bdp->rev_id < D102_REV_ID) && - (bdp->params.b_params & PRM_XSUMRX) && - (bdp->pdev->device != 0x1209)) { - - bdp->flags |= DF_CSUM_OFFLOAD; - bdp->config[9] |= 1; - } - } else { - /* this is 82558 */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_EXTENDED_STATS; - } - - e100_config_long_rx(bdp, true); -} - -static void -e100_config_init_82550(struct e100_private *bdp) -{ - /* The D102 chip allows for 32 config bytes. This value is - * supposed to be in Byte 0. Just add the extra bytes to - * what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - - /* now we need to enable the extended RFD. When this is - * enabled, the immediated receive data buffer starts at offset - * 32 from the RFD base address, instead of at offset 16. */ - bdp->config[7] |= CB_CFIG_EXTENDED_RFD; - - /* put the chip into D102 receive mode. This is necessary - * for any parsing and offloading features. */ - bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE; - - /* set the flag if checksum offloading was enabled */ - if (bdp->params.b_params & PRM_XSUMRX) { - bdp->flags |= DF_CSUM_OFFLOAD; - } -} - -/* Initialize the adapter's configure block */ -void -e100_config_init(struct e100_private *bdp) -{ - e100_config_init_82557(bdp); - - if (bdp->flags & IS_BACHELOR) - e100_config_init_82558(bdp); - - if (bdp->rev_id >= D102_REV_ID) - e100_config_init_82550(bdp); -} - -/** - * e100_force_config - force a configure command - * @bdp: atapter's private data struct - * - * This routine will force a configure command to the adapter. - * The command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_force_config(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - bdp->config[0] = CB_CFIG_BYTE_COUNT; - if (bdp->rev_id >= D102_REV_ID) { - /* The D102 chip allows for 32 config bytes. This value is - supposed to be in Byte 0. Just add the extra bytes to - what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - } - - spin_unlock_bh(&(bdp->config_lock)); - - // although we call config outside the lock, there is no - // race condition because config byte count has maximum value - return e100_config(bdp); -} - -/** - * e100_config - issue a configure command - * @bdp: atapter's private data struct - * - * This routine will issue a configure command to the 82557. - * This command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_config(struct e100_private *bdp) -{ - cb_header_t *pntcb_hdr; - unsigned char res = true; - nxmit_cb_entry_t *cmd; - - if (bdp->config[0] == 0) { - goto exit; - } - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE); - - spin_lock_bh(&bdp->config_lock); - - if (bdp->config[0] < CB_CFIG_MIN_PARAMS) { - bdp->config[0] = CB_CFIG_MIN_PARAMS; - } - - /* Copy the device's config block to the device's memory */ - memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config, - bdp->config[0]); - /* reset number of bytes to config next time */ - bdp->config[0] = 0; - - spin_unlock_bh(&bdp->config_lock); - - res = e100_exec_non_cu_cmd(bdp, cmd); - -exit: - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - return res; -} - -/** - * e100_config_fc - config flow-control state - * @bdp: adapter's private data struct - * - * This routine will enable or disable flow control support in the adapter's - * config block. Flow control will be enable only if requested using the command - * line option, and if the link is flow-contorl capable (both us and the link - * partner). But, if link partner is capable of autoneg, but not capable of - * flow control, received PAUSE frames are still honored. - */ -void -e100_config_fc(struct e100_private *bdp) -{ - unsigned char enable = false; - /* 82557 doesn't support fc. Don't touch this option */ - if (!(bdp->flags & IS_BACHELOR)) - return; - - /* Enable fc if requested and if the link supports it */ - if ((bdp->params.b_params & PRM_FC) && (bdp->flags & - (DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) { - enable = true; - } - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->flags & DF_LINK_FC_TX_ONLY) { - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused by */ - /* incoming PAUSE frames */ - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART); - bdp->config[19] |= CB_CFIG_FC_REJECT; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } else { - bdp->config[16] = DFLT_FC_DELAY_LSB; - bdp->config[17] = DFLT_FC_DELAY_MSB; - bdp->config[19] |= CB_CFIG_FC_OPTS; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } - } else { - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~CB_CFIG_FC_OPTS; - bdp->config[19] |= CB_CFIG_TX_FC_DIS; - } - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); - - return; -} - -/** - * e100_config_promisc - configure promiscuous mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable promiscuous mode - * in the adapter's config block. - */ -void -e100_config_promisc(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* if in promiscuous mode, save bad frames */ - if (enable) { - - if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) { - bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (bdp->config[7] & (u8) BIT_0) { - bdp->config[7] &= (u8) (~BIT_0); - E100_CONFIG(bdp, 7); - } - - if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) { - bdp->config[15] |= CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - - } else { /* not in promiscuous mode */ - - if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) { - bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (!(bdp->config[7] & (u8) BIT_0)) { - bdp->config[7] |= (u8) (BIT_0); - E100_CONFIG(bdp, 7); - } - - if (bdp->config[15] & CB_CFIG_PROMISCUOUS) { - bdp->config[15] &= ~CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_mulcast_enbl - configure allmulti mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of all multicast packets - * in the adapter's config block. - */ -void -e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* this flag is used to enable receiving all multicast packet */ - if (enable) { - if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) { - bdp->config[21] |= CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - - } else { - if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) { - bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_ifs - configure the IFS parameter - * @bdp: atapter's private data struct - * - * This routine will configure the adaptive IFS value - * in the adapter's config block. IFS values are only - * relevant in half duplex, so set to 0 in full duplex. - */ -void -e100_config_ifs(struct e100_private *bdp) -{ - u8 value = 0; - - spin_lock_bh(&(bdp->config_lock)); - - /* IFS value is only needed to be specified at half-duplex mode */ - if (bdp->cur_dplx_mode == HALF_DUPLEX) { - value = (u8) bdp->ifs_value; - } - - if (bdp->config[2] != value) { - bdp->config[2] = value; - E100_CONFIG(bdp, 2); - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_force_dplx - configure the forced full duplex mode - * @bdp: atapter's private data struct - * - * This routine will enable or disable force full duplex - * in the adapter's config block. If the PHY is 503, and - * the duplex is full, consider the adapter forced. - */ -void -e100_config_force_dplx(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* We must force full duplex on if we are using PHY 0, and we are */ - /* supposed to run in FDX mode. We do this because the e100 has only */ - /* one FDX# input pin, and that pin will be connected to PHY 1. */ - /* Changed the 'if' condition below to fix performance problem * at 10 - * full. The Phy was getting forced to full duplex while the MAC * was - * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. * - * This is how the condition was, initially. * This has been changed so - * that the MAC gets forced to full duplex * simply if the user has - * forced full duplex. * * if (( bdp->phy_addr == 0 ) && ( - * bdp->cur_dplx_mode == 2 )) */ - /* The rest of the fix is in the PhyDetect code. */ - if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) || - (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) || - ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) { - if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) { - bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX; - E100_CONFIG(bdp, 19); - } - - } else { - if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) { - bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX); - E100_CONFIG(bdp, 19); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_long_rx - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of larger packets. - * This is needed by VLAN implementations. - */ -static void -e100_config_long_rx(struct e100_private *bdp, unsigned char enable) -{ - if (enable) { - if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] |= CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - - } else { - if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] &= ~CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - } -} - -/** - * e100_config_wol - * @bdp: atapter's private data struct - * - * This sets configuration options for PHY and Magic Packet WoL - */ -void -e100_config_wol(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - if (bdp->wolopts & WAKE_PHY) { - bdp->config[9] |= CB_LINK_STATUS_WOL; - } - else { - /* Disable PHY WoL */ - bdp->config[9] &= ~CB_LINK_STATUS_WOL; - } - - if (bdp->wolopts & WAKE_MAGIC) { - bdp->config[19] &= ~CB_DISABLE_MAGPAK_WAKE; - } - else { - /* Disable Magic Packet WoL */ - bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE; - } - - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); -} - -void -e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - if (enable) { - if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - - } else { - if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - } - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_loopback_mode - * @bdp: atapter's private data struct - * @mode: loopback mode(phy/mac/none) - * - */ -unsigned char -e100_config_loopback_mode(struct e100_private *bdp, u8 mode) -{ - unsigned char bc_changed = false; - u8 config_byte; - - spin_lock_bh(&(bdp->config_lock)); - - switch (mode) { - case NO_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_NORMAL; - break; - case MAC_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_INTERNAL; - break; - case PHY_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_EXTERNAL; - break; - default: - printk(KERN_NOTICE "e100: e100_config_loopback_mode: " - "Invalid argument 'mode': %d\n", mode); - goto exit; - } - - if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) { - - bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE); - bdp->config[10] |= config_byte; - E100_CONFIG(bdp, 10); - bc_changed = true; - } - -exit: - spin_unlock_bh(&(bdp->config_lock)); - return bc_changed; -} -unsigned char -e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) { - - bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS); - E100_CONFIG(bdp, 6); - bc_changed = true; - } - - } else { - if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) { - - bdp->config[6] |= CB_CFIG_EXT_TCB_DIS; - E100_CONFIG(bdp, 6); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} -unsigned char -e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) { - - bdp->config[7] |= CB_CFIG_DYNTBD_EN; - E100_CONFIG(bdp, 7); - bc_changed = true; - } - - } else { - if (bdp->config[7] & CB_CFIG_DYNTBD_EN) { - - bdp->config[7] &= (~CB_CFIG_DYNTBD_EN); - E100_CONFIG(bdp, 7); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} - --- linux-2.6.1-rc1/drivers/net/e100/e100_config.h 2003-09-27 18:57:45.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,168 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_CONFIG_INC_ -#define _E100_CONFIG_INC_ - -#include "e100.h" - -#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1)) - -#define CB_CFIG_MIN_PARAMS 8 - -/* byte 0 bit definitions*/ -#define CB_CFIG_BYTE_COUNT_MASK BIT_0_5 /* Byte count occupies bit 5-0 */ - -/* byte 1 bit definitions*/ -#define CB_CFIG_RXFIFO_LIMIT_MASK BIT_0_4 /* RxFifo limit mask */ -#define CB_CFIG_TXFIFO_LIMIT_MASK BIT_4_7 /* TxFifo limit mask */ - -/* byte 2 bit definitions -- ADAPTIVE_IFS*/ - -/* word 3 bit definitions -- RESERVED*/ -/* Changed for 82558 enhancements */ -/* byte 3 bit definitions */ -#define CB_CFIG_MWI_EN BIT_0 /* Enable MWI on PCI bus */ -#define CB_CFIG_TYPE_EN BIT_1 /* Type Enable */ -#define CB_CFIG_READAL_EN BIT_2 /* Enable Read Align */ -#define CB_CFIG_TERMCL_EN BIT_3 /* Cache line write */ - -/* byte 4 bit definitions*/ -#define CB_CFIG_RX_MIN_DMA_MASK BIT_0_6 /* Rx minimum DMA count mask */ - -/* byte 5 bit definitions*/ -#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6 /* Tx minimum DMA count mask */ -#define CB_CFIG_DMBC_EN BIT_7 /* Enable Tx/Rx min. DMA counts */ - -/* Changed for 82558 enhancements */ -/* byte 6 bit definitions*/ -#define CB_CFIG_LATE_SCB BIT_0 /* Update SCB After New Tx Start */ -#define CB_CFIG_DIRECT_DMA_DIS BIT_1 /* Direct DMA mode */ -#define CB_CFIG_TNO_INT BIT_2 /* Tx Not OK Interrupt */ -#define CB_CFIG_TCO_STAT BIT_2 /* TCO statistics in 559 and above */ -#define CB_CFIG_CI_INT BIT_3 /* Command Complete Interrupt */ -#define CB_CFIG_EXT_TCB_DIS BIT_4 /* Extended TCB */ -#define CB_CFIG_EXT_STAT_DIS BIT_5 /* Extended Stats */ -#define CB_CFIG_SAVE_BAD_FRAMES BIT_7 /* Save Bad Frames Enabled */ - -/* byte 7 bit definitions*/ -#define CB_CFIG_DISC_SHORT_FRAMES BIT_0 /* Discard Short Frames */ -#define CB_CFIG_DYNTBD_EN BIT_7 /* Enable dynamic TBD */ -/* Enable extended RFD's on D102 */ -#define CB_CFIG_EXTENDED_RFD BIT_5 - -/* byte 8 bit definitions*/ -#define CB_CFIG_503_MII BIT_0 /* 503 vs. MII mode */ - -/* byte 9 bit definitions -- pre-defined all zeros*/ -#define CB_LINK_STATUS_WOL BIT_5 - -/* byte 10 bit definitions*/ -#define CB_CFIG_NO_SRCADR BIT_3 /* No Source Address Insertion */ -#define CB_CFIG_PREAMBLE_LEN BIT_4_5 /* Preamble Length */ -#define CB_CFIG_LOOPBACK_MODE BIT_6_7 /* Loopback Mode */ -#define CB_CFIG_LOOPBACK_NORMAL 0 -#define CB_CFIG_LOOPBACK_INTERNAL BIT_6 -#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7 - -/* byte 11 bit definitions*/ -#define CB_CFIG_LINEAR_PRIORITY BIT_0_2 /* Linear Priority */ - -/* byte 12 bit definitions*/ -#define CB_CFIG_LINEAR_PRI_MODE BIT_0 /* Linear Priority mode */ -#define CB_CFIG_IFS_MASK BIT_4_7 /* Interframe Spacing mask */ - -/* byte 13 bit definitions -- pre-defined all zeros*/ - -/* byte 14 bit definitions -- pre-defined 0xf2*/ - -/* byte 15 bit definitions*/ -#define CB_CFIG_PROMISCUOUS BIT_0 /* Promiscuous Mode Enable */ -#define CB_CFIG_BROADCAST_DIS BIT_1 /* Broadcast Mode Disable */ -#define CB_CFIG_CRS_OR_CDT BIT_7 /* CRS Or CDT */ - -/* byte 16 bit definitions -- pre-defined all zeros*/ -#define DFLT_FC_DELAY_LSB 0x1f /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_LSB 0x00 /* no flow control default value */ - -/* byte 17 bit definitions -- pre-defined 0x40*/ -#define DFLT_FC_DELAY_MSB 0x01 /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_MSB 0x40 /* no flow control default value */ - -/* byte 18 bit definitions*/ -#define CB_CFIG_STRIPPING BIT_0 /* Padding Disabled */ -#define CB_CFIG_PADDING BIT_1 /* Padding Disabled */ -#define CB_CFIG_CRC_IN_MEM BIT_2 /* Transfer CRC To Memory */ - -/* byte 19 bit definitions*/ -#define CB_CFIG_TX_ADDR_WAKE BIT_0 /* Address Wakeup */ -#define CB_DISABLE_MAGPAK_WAKE BIT_1 /* Magic Packet Wakeup disable */ -/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */ -#define CB_CFIG_TX_FC_DIS BIT_2 /* Tx Flow Control Disable */ -#define CB_CFIG_FC_RESTOP BIT_3 /* Rx Flow Control Restop */ -#define CB_CFIG_FC_RESTART BIT_4 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_REJECT BIT_5 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT) - -/* end 82558/9 specifics */ - -#define CB_CFIG_FORCE_FDX BIT_6 /* Force Full Duplex */ -#define CB_CFIG_FDX_ENABLE BIT_7 /* Full Duplex Enabled */ - -/* byte 20 bit definitions*/ -#define CB_CFIG_MULTI_IA BIT_6 /* Multiple IA Addr */ - -/* byte 21 bit definitions*/ -#define CB_CFIG_MULTICAST_ALL BIT_3 /* Multicast All */ - -/* byte 22 bit defines */ -#define CB_CFIG_RECEIVE_GAMLA_MODE BIT_0 /* D102 receive mode */ -#define CB_CFIG_VLAN_DROP_ENABLE BIT_1 /* vlan stripping */ - -#define CB_CFIG_LONG_RX_OK BIT_3 - -#define NO_LOOPBACK 0 -#define MAC_LOOPBACK 0x01 -#define PHY_LOOPBACK 0x02 - -/* function prototypes */ -extern void e100_config_init(struct e100_private *bdp); -extern void e100_config_init_82557(struct e100_private *bdp); -extern unsigned char e100_force_config(struct e100_private *bdp); -extern unsigned char e100_config(struct e100_private *bdp); -extern void e100_config_fc(struct e100_private *bdp); -extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable); -extern void e100_config_brdcast_dsbl(struct e100_private *bdp); -extern void e100_config_mulcast_enbl(struct e100_private *bdp, - unsigned char enable); -extern void e100_config_ifs(struct e100_private *bdp); -extern void e100_config_force_dplx(struct e100_private *bdp); -extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode); -extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable); -extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable); -extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable); -#endif /* _E100_CONFIG_INC_ */ --- linux-2.6.1-rc1/drivers/net/e100/e100_eeprom.c 2003-06-14 12:18:07.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,565 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_eeprom.c * -* * -* Abstract: This module contains routines to read and write to a * -* serial EEPROM * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100.h" - -#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl) - -#define CSR_GENERAL_CONTROL2_FIELD(bdp) \ - ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2) - -#define EEPROM_STALL_TIME 4 -#define EEPROM_CHECKSUM ((u16) 0xBABA) -#define EEPROM_MAX_WORD_SIZE 256 - -void e100_eeprom_cleanup(struct e100_private *adapter); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); -static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg, - u16 data); -void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size); -u16 e100_eeprom_size(struct e100_private *adapter); -u16 e100_eeprom_read(struct e100_private *adapter, u16 reg); - -static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count); -static u16 shift_in_bits(struct e100_private *adapter); -static void raise_clock(struct e100_private *adapter, u16 *x); -static void lower_clock(struct e100_private *adapter, u16 *x); -static u16 eeprom_wait_cmd_done(struct e100_private *adapter); -static void eeprom_stand_by(struct e100_private *adapter); - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_set_semaphore -// -// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR). -// -// Arguments: -// Adapter - Adapter context -// -// Returns: true if success -// else return false -// -//---------------------------------------------------------------------------------------- - -inline u8 -eeprom_set_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - do { - // Get current value of General Control 2 - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Set bit 23 word 0x1C in the CSR. - data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE; - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Check to see if this bit set or not. - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) { - return true; - } - - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_reset_semaphore -// -// Description: This function reset (write 0) Gamla EEPROM semaphore bit -// (bit 23 word 0x1C in the CSR). -// -// Arguments: struct e100_private * adapter - Adapter context -//---------------------------------------------------------------------------------------- - -inline void -eeprom_reset_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE); - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_size -// -// Description: This routine determines the size of the EEPROM. This value should be -// checked for validity - ie. is it too big or too small. The size returned -// is then passed to the read/write functions. -// -// Returns: -// Size of the eeprom, or zero if an error occurred -//---------------------------------------------------------------------------------------- -u16 -e100_eeprom_size(struct e100_private *adapter) -{ - u16 x, size = 1; // must be one to accumulate a product - - // if we've already stored this data, read from memory - if (adapter->eeprom_size) { - return adapter->eeprom_size; - } - // otherwise, read from the eeprom - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // enable the eeprom by setting EECS. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - - // experiment to discover the size of the eeprom. request register zero - // and wait for the eeprom to tell us it has accepted the entire address. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - do { - size *= 2; // each bit of address doubles eeprom size - x |= EEDO; // set bit to detect "dummy zero" - x &= ~EEDI; // address consists of all zeros - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - - // check for "dummy zero" - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (size > EEPROM_MAX_WORD_SIZE) { - size = 0; - break; - } - } while (x & EEDO); - - // read in the value requested - (void) shift_in_bits(adapter); - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return size; -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_address_size -// -// Description: determines the number of bits in an address for the eeprom acceptable -// values are 64, 128, and 256 -// Arguments: size of the eeprom -// Returns: bits in an address for that size eeprom -//---------------------------------------------------------------------------------------- - -static inline int -eeprom_address_size(u16 size) -{ - int isize = size; - - return (ffs(isize) - 1); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_read -// -// Description: This routine serially reads one word out of the EEPROM. -// -// Arguments: -// adapter - our adapter context -// reg - EEPROM word to read. -// -// Returns: -// Contents of EEPROM word (reg). -//---------------------------------------------------------------------------------------- - -u16 -e100_eeprom_read(struct e100_private *adapter, u16 reg) -{ - u16 x, data, bits; - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - bits = eeprom_address_size(adapter->eeprom_size); - - // select EEPROM, reset bits, set EECS - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode and register number in that order - // The opcode is 3bits in length, reg is 'bits' bits long - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - shift_out_bits(adapter, reg, bits); - - // Now read the data (16 bits) in from the selected EEPROM word - data = shift_in_bits(adapter); - - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return data; -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_out_bits -// -// Description: This routine shifts data bits out to the EEPROM. -// -// Arguments: -// data - data to send to the EEPROM. -// count - number of data bits to shift out. -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -static void -shift_out_bits(struct e100_private *adapter, u16 data, u16 count) -{ - u16 x, mask; - - mask = 1 << (count - 1); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - - do { - x &= ~EEDI; - if (data & mask) - x |= EEDI; - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - mask = mask >> 1; - } while (mask); - - x &= ~EEDI; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: raise_clock -// -// Description: This routine raises the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -raise_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x | EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: lower_clock -// -// Description: This routine lower's the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -lower_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x & ~EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_in_bits -// -// Description: This routine shifts data bits in from the EEPROM. -// -// Arguments: -// -// Returns: -// The contents of that particular EEPROM word -//---------------------------------------------------------------------------------------- - -static u16 -shift_in_bits(struct e100_private *adapter) -{ - u16 x, d, i; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - d = 0; - - for (i = 0; i < 16; i++) { - d <<= 1; - raise_clock(adapter, &x); - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~EEDI; - if (x & EEDO) - d |= 1; - - lower_clock(adapter, &x); - } - - return d; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_cleanup -// -// Description: This routine returns the EEPROM to an idle state -//---------------------------------------------------------------------------------------- - -void -e100_eeprom_cleanup(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EECS | EEDI); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - raise_clock(adapter, &x); - lower_clock(adapter, &x); -} - -//********************************************************************************** -// Procedure: e100_eeprom_update_chksum -// -// Description: Calculates the checksum and writes it to the EEProm. -// It calculates the checksum accroding to the formula: -// Checksum = 0xBABA - (sum of first 63 words). -// -//----------------------------------------------------------------------------------- -u16 -e100_eeprom_calculate_chksum(struct e100_private *adapter) -{ - u16 idx, xsum_index, checksum = 0; - - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - xsum_index = adapter->eeprom_size - 1; - for (idx = 0; idx < xsum_index; idx++) - checksum += e100_eeprom_read(adapter, idx); - - checksum = EEPROM_CHECKSUM - checksum; - return checksum; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_word -// -// Description: This routine writes a word to a specific EEPROM location without. -// taking EEPROM semaphore and updating checksum. -// Use e100_eeprom_write_block for the EEPROM update -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -static void -e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data) -{ - u16 x; - u16 bits; - - bits = eeprom_address_size(adapter->eeprom_size); - - /* select EEPROM, mask off ASIC and reset bits, set EECS */ - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - /* write the new word to the EEPROM & send the write opcode the EEPORM */ - shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3); - - /* select which word in the EEPROM that we are writing to */ - shift_out_bits(adapter, reg, bits); - - /* write the data to the selected EEPROM word */ - shift_out_bits(adapter, data, 16); - if (!eeprom_wait_cmd_done(adapter)) - return; - - shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - e100_eeprom_cleanup(adapter); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_block -// -// Description: This routine writes a block of words starting from specified EEPROM -// location and updates checksum -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -void -e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size) -{ - u16 checksum; - u16 i; - - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return; - } - - for (i = 0; i < size; i++) { - e100_eeprom_write_word(adapter, start + i, data[i]); - } - //Update checksum - checksum = e100_eeprom_calculate_chksum(adapter); - e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_wait_cmd_done -// -// Description: This routine waits for the the EEPROM to finish its command. -// Specifically, it waits for EEDO (data out) to go high. -// Returns: true - If the command finished -// false - If the command never finished (EEDO stayed low) -//---------------------------------------------------------------------------------------- -static u16 -eeprom_wait_cmd_done(struct e100_private *adapter) -{ - u16 x; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - eeprom_stand_by(adapter); - - do { - rmb(); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (x & EEDO) - return true; - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_stand_by -// -// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds. -//---------------------------------------------------------------------------------------- -static void -eeprom_stand_by(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EECS | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} --- linux-2.6.1-rc1/drivers/net/e100/e100.h 2003-09-27 18:57:45.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,999 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_INC_ -#define _E100_INC_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define E100_CABLE_UNKNOWN 0 -#define E100_CABLE_OK 1 -#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */ -#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */ -#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */ -#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */ - -#define E100_REGS_LEN 2 -/* - * Configure parameters for buffers per controller. - * If the machine this is being used on is a faster machine (i.e. > 150MHz) - * and running on a 10MBS network then more queueing of data occurs. This - * may indicate the some of the numbers below should be adjusted. Here are - * some typical numbers: - * MAX_TCB 64 - * MAX_RFD 64 - * The default numbers give work well on most systems tests so no real - * adjustments really need to take place. Also, if the machine is connected - * to a 100MBS network the numbers described above can be lowered from the - * defaults as considerably less data will be queued. - */ - -#define TX_FRAME_CNT 8 /* consecutive transmit frames per interrupt */ -/* TX_FRAME_CNT must be less than MAX_TCB */ - -#define E100_DEFAULT_TCB 64 -#define E100_MIN_TCB 2*TX_FRAME_CNT + 3 /* make room for at least 2 interrupts */ -#define E100_MAX_TCB 1024 - -#define E100_DEFAULT_RFD 64 -#define E100_MIN_RFD 8 -#define E100_MAX_RFD 1024 - -#define E100_DEFAULT_XSUM true -#define E100_DEFAULT_BER ZLOCK_MAX_ERRORS -#define E100_DEFAULT_SPEED_DUPLEX 0 -#define E100_DEFAULT_FC 0 -#define E100_DEFAULT_IFS true -#define E100_DEFAULT_UCODE true - -#define TX_THRSHLD 8 - -/* IFS parameters */ -#define MIN_NUMBER_OF_TRANSMITS_100 1000 -#define MIN_NUMBER_OF_TRANSMITS_10 100 - -#define E100_MAX_NIC 16 - -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ -#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ - -/* HWI feature related constant */ -#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */ -#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */ - -/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled. - * In some situations, such as the TCP windowing algorithm, it may be - * better to limit the growth of the bundle size than let it go as - * high as it can, because that could cause too much added latency. - * The default is six, because this is the number of packets in the - * default TCP window size. A value of 1 would make CPUSaver indicate - * an interrupt for every frame received. If you do not want to put - * a limit on the bundle size, set this value to xFFFF. - */ -#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX 6 -#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY 0x600 -#define E100_DEFAULT_BUNDLE_SMALL_FR false - -/* end of configurables */ - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/* timeout for command completion */ -#define E100_CMD_WAIT 100 /* iterations */ - -struct driver_stats { - struct net_device_stats net_stats; - - unsigned long tx_late_col; - unsigned long tx_ok_defrd; - unsigned long tx_one_retry; - unsigned long tx_mt_one_retry; - unsigned long rcv_cdt_frames; - unsigned long xmt_fc_pkts; - unsigned long rcv_fc_pkts; - unsigned long rcv_fc_unsupported; - unsigned long xmt_tco_pkts; - unsigned long rcv_tco_pkts; - unsigned long rx_intr_pkts; -}; - -/* TODO: kill me when we can do C99 */ -#define false (0) -#define true (1) - -/* Changed for 82558 and 82559 enhancements */ -/* defines for 82558/9 flow control CSR values */ -#define DFLT_FC_THLD 0x00 /* Rx FIFO threshold of 0.5KB free */ -#define DFLT_FC_CMD 0x00 /* FC Command in CSR */ - -/* ====================================================================== */ -/* equates */ -/* ====================================================================== */ - -/* - * These are general purpose defines - */ - -/* Bit Mask definitions */ -#define BIT_0 0x0001 -#define BIT_1 0x0002 -#define BIT_2 0x0004 -#define BIT_3 0x0008 -#define BIT_4 0x0010 -#define BIT_5 0x0020 -#define BIT_6 0x0040 -#define BIT_7 0x0080 -#define BIT_8 0x0100 -#define BIT_9 0x0200 -#define BIT_10 0x0400 -#define BIT_11 0x0800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_28 0x10000000 - -#define BIT_0_2 0x0007 -#define BIT_0_3 0x000F -#define BIT_0_4 0x001F -#define BIT_0_5 0x003F -#define BIT_0_6 0x007F -#define BIT_0_7 0x00FF -#define BIT_0_8 0x01FF -#define BIT_0_13 0x3FFF -#define BIT_0_15 0xFFFF -#define BIT_1_2 0x0006 -#define BIT_1_3 0x000E -#define BIT_2_5 0x003C -#define BIT_3_4 0x0018 -#define BIT_4_5 0x0030 -#define BIT_4_6 0x0070 -#define BIT_4_7 0x00F0 -#define BIT_5_7 0x00E0 -#define BIT_5_12 0x1FE0 -#define BIT_5_15 0xFFE0 -#define BIT_6_7 0x00c0 -#define BIT_7_11 0x0F80 -#define BIT_8_10 0x0700 -#define BIT_9_13 0x3E00 -#define BIT_12_15 0xF000 -#define BIT_8_15 0xFF00 - -#define BIT_16_20 0x001F0000 -#define BIT_21_25 0x03E00000 -#define BIT_26_27 0x0C000000 - -/* Transmit Threshold related constants */ -#define DEFAULT_TX_PER_UNDERRUN 20000 - -#define MAX_MULTICAST_ADDRS 64 -#define MAX_FILTER 16 - -#define FULL_DUPLEX 2 -#define HALF_DUPLEX 1 - -/* - * These defines are specific to the 82557 - */ - -/* E100 PORT functions -- lower 4 bits */ -#define PORT_SOFTWARE_RESET 0 -#define PORT_SELFTEST 1 -#define PORT_SELECTIVE_RESET 2 -#define PORT_DUMP 3 - -/* SCB Status Word bit definitions */ -/* Interrupt status/ack fields */ -/* ER and FCP interrupts for 82558 masks */ -#define SCB_STATUS_ACK_MASK BIT_8_15 /* Status Mask */ -#define SCB_STATUS_ACK_CX BIT_15 /* CU Completed Action Cmd */ -#define SCB_STATUS_ACK_FR BIT_14 /* RU Received A Frame */ -#define SCB_STATUS_ACK_CNA BIT_13 /* CU Became Inactive (IDLE) */ -#define SCB_STATUS_ACK_RNR BIT_12 /* RU Became Not Ready */ -#define SCB_STATUS_ACK_MDI BIT_11 /* MDI read or write done */ -#define SCB_STATUS_ACK_SWI BIT_10 /* S/W generated interrupt */ -#define SCB_STATUS_ACK_ER BIT_9 /* Early Receive */ -#define SCB_STATUS_ACK_FCP BIT_8 /* Flow Control Pause */ - -/*- CUS Fields */ -#define SCB_CUS_MASK (BIT_6 | BIT_7) /* CUS 2-bit Mask */ -#define SCB_CUS_IDLE 0 /* CU Idle */ -#define SCB_CUS_SUSPEND BIT_6 /* CU Suspended */ -#define SCB_CUS_ACTIVE BIT_7 /* CU Active */ - -/*- RUS Fields */ -#define SCB_RUS_IDLE 0 /* RU Idle */ -#define SCB_RUS_MASK BIT_2_5 /* RUS 3-bit Mask */ -#define SCB_RUS_SUSPEND BIT_2 /* RU Suspended */ -#define SCB_RUS_NO_RESOURCES BIT_3 /* RU Out Of Resources */ -#define SCB_RUS_READY BIT_4 /* RU Ready */ -#define SCB_RUS_SUSP_NO_RBDS (BIT_2 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_NO_RBDS (BIT_3 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_READY_NO_RBDS (BIT_4 | BIT_5) /* RU Ready, No RBDs */ - -/* SCB Command Word bit definitions */ -/*- CUC fields */ -/* Changing mask to 4 bits */ -#define SCB_CUC_MASK BIT_4_7 /* CUC 4-bit Mask */ -#define SCB_CUC_NOOP 0 -#define SCB_CUC_START BIT_4 /* CU Start */ -#define SCB_CUC_RESUME BIT_5 /* CU Resume */ -#define SCB_CUC_UNKNOWN BIT_7 /* CU unknown command */ -/* Changed for 82558 enhancements */ -#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) /* 82558/9 Static Resume */ -#define SCB_CUC_DUMP_ADDR BIT_6 /* CU Dump Counters Address */ -#define SCB_CUC_DUMP_STAT (BIT_4 | BIT_6) /* CU Dump stat. counters */ -#define SCB_CUC_LOAD_BASE (BIT_5 | BIT_6) /* Load the CU base */ -/* Below was defined as BIT_4_7 */ -#define SCB_CUC_DUMP_RST_STAT BIT_4_6 /* CU Dump & reset statistics cntrs */ - -/*- RUC fields */ -#define SCB_RUC_MASK BIT_0_2 /* RUC 3-bit Mask */ -#define SCB_RUC_START BIT_0 /* RU Start */ -#define SCB_RUC_RESUME BIT_1 /* RU Resume */ -#define SCB_RUC_ABORT BIT_2 /* RU Abort */ -#define SCB_RUC_LOAD_HDS (BIT_0 | BIT_2) /* Load RFD Header Data Size */ -#define SCB_RUC_LOAD_BASE (BIT_1 | BIT_2) /* Load the RU base */ -#define SCB_RUC_RBD_RESUME BIT_0_2 /* RBD resume */ - -/* Interrupt fields (assuming byte addressing) */ -#define SCB_INT_MASK BIT_0 /* Mask interrupts */ -#define SCB_SOFT_INT BIT_1 /* Generate a S/W interrupt */ -/* Specific Interrupt Mask Bits (upper byte of SCB Command word) */ -#define SCB_FCP_INT_MASK BIT_2 /* Flow Control Pause */ -#define SCB_ER_INT_MASK BIT_3 /* Early Receive */ -#define SCB_RNR_INT_MASK BIT_4 /* RU Not Ready */ -#define SCB_CNA_INT_MASK BIT_5 /* CU Not Active */ -#define SCB_FR_INT_MASK BIT_6 /* Frame Received */ -#define SCB_CX_INT_MASK BIT_7 /* CU eXecution w/ I-bit done */ -#define SCB_BACHELOR_INT_MASK BIT_2_7 /* 82558 interrupt mask bits */ - -#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7 - -/* EEPROM bit definitions */ -/*- EEPROM control register bits */ -#define EEPROM_FLAG_ASF 0x8000 -#define EEPROM_FLAG_GCL 0x4000 - -#define EN_TRNF 0x10 /* Enable turnoff */ -#define EEDO 0x08 /* EEPROM data out */ -#define EEDI 0x04 /* EEPROM data in (set for writing data) */ -#define EECS 0x02 /* EEPROM chip select (1=hi, 0=lo) */ -#define EESK 0x01 /* EEPROM shift clock (1=hi, 0=lo) */ - -/*- EEPROM opcodes */ -#define EEPROM_READ_OPCODE 06 -#define EEPROM_WRITE_OPCODE 05 -#define EEPROM_ERASE_OPCODE 07 -#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ -#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ - -/*- EEPROM data locations */ -#define EEPROM_NODE_ADDRESS_BYTE_0 0 -#define EEPROM_COMPATIBILITY_WORD 3 -#define EEPROM_PWA_NO 8 -#define EEPROM_ID_WORD 0x0A -#define EEPROM_CONFIG_ASF 0x0D -#define EEPROM_SMBUS_ADDR 0x90 - -#define EEPROM_SUM 0xbaba - -// Zero Locking Algorithm definitions: -#define ZLOCK_ZERO_MASK 0x00F0 -#define ZLOCK_MAX_READS 50 -#define ZLOCK_SET_ZERO 0x2010 -#define ZLOCK_MAX_SLEEP 300 * HZ -#define ZLOCK_MAX_ERRORS 300 - -/* E100 Action Commands */ -#define CB_IA_ADDRESS 1 -#define CB_CONFIGURE 2 -#define CB_MULTICAST 3 -#define CB_TRANSMIT 4 -#define CB_LOAD_MICROCODE 5 -#define CB_LOAD_FILTER 8 -#define CB_MAX_NONTX_CMD 9 -#define CB_IPCB_TRANSMIT 9 - -/* Pre-defined Filter Bits */ -#define CB_FILTER_EL 0x80000000 -#define CB_FILTER_FIX 0x40000000 -#define CB_FILTER_ARP 0x08000000 -#define CB_FILTER_IA_MATCH 0x02000000 - -/* Command Block (CB) Field Definitions */ -/*- CB Command Word */ -#define CB_EL_BIT BIT_15 /* CB EL Bit */ -#define CB_S_BIT BIT_14 /* CB Suspend Bit */ -#define CB_I_BIT BIT_13 /* CB Interrupt Bit */ -#define CB_TX_SF_BIT BIT_3 /* TX CB Flexible Mode */ -#define CB_CMD_MASK BIT_0_3 /* CB 4-bit CMD Mask */ -#define CB_CID_DEFAULT (0x1f << 8) /* CB 5-bit CID (max value) */ - -/*- CB Status Word */ -#define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */ -#define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */ -#define CB_STATUS_OK BIT_13 /* CB OK Bit */ -#define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */ -#define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */ - -/*misc command bits */ -#define CB_TX_EOF_BIT BIT_15 /* TX CB/TBD EOF Bit */ - -/* Config params */ -#define CB_CFIG_BYTE_COUNT 22 /* 22 config bytes */ -#define CB_CFIG_D102_BYTE_COUNT 10 - -/* Receive Frame Descriptor Fields */ - -/*- RFD Status Bits */ -#define RFD_RECEIVE_COLLISION BIT_0 /* Collision detected on Receive */ -#define RFD_IA_MATCH BIT_1 /* Indv Address Match Bit */ -#define RFD_RX_ERR BIT_4 /* RX_ERR pin on Phy was set */ -#define RFD_FRAME_TOO_SHORT BIT_7 /* Receive Frame Short */ -#define RFD_DMA_OVERRUN BIT_8 /* Receive DMA Overrun */ -#define RFD_NO_RESOURCES BIT_9 /* No Buffer Space */ -#define RFD_ALIGNMENT_ERROR BIT_10 /* Alignment Error */ -#define RFD_CRC_ERROR BIT_11 /* CRC Error */ -#define RFD_STATUS_OK BIT_13 /* RFD OK Bit */ -#define RFD_STATUS_COMPLETE BIT_15 /* RFD Complete Bit */ - -/*- RFD Command Bits*/ -#define RFD_EL_BIT BIT_15 /* RFD EL Bit */ -#define RFD_S_BIT BIT_14 /* RFD Suspend Bit */ -#define RFD_H_BIT BIT_4 /* Header RFD Bit */ -#define RFD_SF_BIT BIT_3 /* RFD Flexible Mode */ - -/*- RFD misc bits*/ -#define RFD_EOF_BIT BIT_15 /* RFD End-Of-Frame Bit */ -#define RFD_F_BIT BIT_14 /* RFD Buffer Fetch Bit */ -#define RFD_ACT_COUNT_MASK BIT_0_13 /* RFD Actual Count Mask */ - -/* Receive Buffer Descriptor Fields*/ -#define RBD_EOF_BIT BIT_15 /* RBD End-Of-Frame Bit */ -#define RBD_F_BIT BIT_14 /* RBD Buffer Fetch Bit */ -#define RBD_ACT_COUNT_MASK BIT_0_13 /* RBD Actual Count Mask */ - -#define SIZE_FIELD_MASK BIT_0_13 /* Size of the associated buffer */ -#define RBD_EL_BIT BIT_15 /* RBD EL Bit */ - -/* Self Test Results*/ -#define CB_SELFTEST_FAIL_BIT BIT_12 -#define CB_SELFTEST_DIAG_BIT BIT_5 -#define CB_SELFTEST_REGISTER_BIT BIT_3 -#define CB_SELFTEST_ROM_BIT BIT_2 - -#define CB_SELFTEST_ERROR_MASK ( \ - CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \ - CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT) - -/* adapter vendor & device ids */ -#define PCI_OHIO_BOARD 0x10f0 /* subdevice ID, Ohio dual port nic */ - -/* Values for PCI_REV_ID_REGISTER values */ -#define D101A4_REV_ID 4 /* 82558 A4 stepping */ -#define D101B0_REV_ID 5 /* 82558 B0 stepping */ -#define D101MA_REV_ID 8 /* 82559 A0 stepping */ -#define D101S_REV_ID 9 /* 82559S A-step */ -#define D102_REV_ID 12 -#define D102C_REV_ID 13 /* 82550 step C */ -#define D102E_REV_ID 15 - -/* ############Start of 82555 specific defines################## */ - -#define PHY_82555_LED_SWITCH_CONTROL 0x1b /* 82555 led switch control register */ - -/* 82555 led switch control reg. opcodes */ -#define PHY_82555_LED_NORMAL_CONTROL 0 // control back to the 8255X -#define PHY_82555_LED_DRIVER_CONTROL BIT_2 // the driver is in control -#define PHY_82555_LED_OFF BIT_2 // activity LED is off -#define PHY_82555_LED_ON_559 (BIT_0 | BIT_2) // activity LED is on for 559 and later -#define PHY_82555_LED_ON_PRE_559 (BIT_0 | BIT_1 | BIT_2) // activity LED is on for 558 and before - -// Describe the state of the phy led. -// needed for the function : 'e100_blink_timer' -enum led_state_e { - LED_OFF = 0, - LED_ON, -}; - -/* ############End of 82555 specific defines##################### */ - -#define RFD_PARSE_BIT BIT_3 -#define RFD_TCP_PACKET 0x00 -#define RFD_UDP_PACKET 0x01 -#define TCPUDP_CHECKSUM_BIT_VALID BIT_4 -#define TCPUDP_CHECKSUM_VALID BIT_5 -#define CHECKSUM_PROTOCOL_MASK 0x03 - -#define VLAN_SIZE 4 -#define CHKSUM_SIZE 2 -#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE) - -/* Bits for bdp->flags */ -#define DF_LINK_FC_CAP 0x00000001 /* Link is flow control capable */ -#define DF_CSUM_OFFLOAD 0x00000002 -#define DF_UCODE_LOADED 0x00000004 -#define USE_IPCB 0x00000008 /* set if using ipcb for transmits */ -#define IS_BACHELOR 0x00000010 /* set if 82558 or newer board */ -#define IS_ICH 0x00000020 -#define DF_SPEED_FORCED 0x00000040 /* set if speed is forced */ -#define LED_IS_ON 0x00000080 /* LED is turned ON by the driver */ -#define DF_LINK_FC_TX_ONLY 0x00000100 /* Received PAUSE frames are honored*/ - -typedef struct net_device_stats net_dev_stats_t; - -/* needed macros */ -/* These macros use the bdp pointer. If you use them it better be defined */ -#define PREV_TCB_USED(X) ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1) -#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1) -#define TCB_TO_USE(X) ((X).tail) -#define TCBS_AVAIL(X) (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head) - -#define RFD_POINTER(skb,bdp) ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size))) -#define SKB_RFD_STATUS(skb,bdp) ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status) - -/* ====================================================================== */ -/* 82557 */ -/* ====================================================================== */ - -/* Changed for 82558 enhancement */ -typedef struct _d101_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ -} d101_scb_ext __attribute__ ((__packed__)); - -/* Changed for 82559 enhancement */ -typedef struct _d101m_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u16 scb_reserved; /* Reserved */ - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} d101m_scb_ext __attribute__ ((__packed__)); - -/* Changed for 82550 enhancement */ -typedef struct _d102_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u8 scb_gen_ctrl2; - u8 scb_reserved; /* Reserved */ - u32 scb_scheduling_reg; - u32 scb_reserved2; - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} d102_scb_ext __attribute__ ((__packed__)); - -/* - * 82557 status control block. this will be memory mapped & will hang of the - * the bdp, which hangs of the bdp. This is the brain of it. - */ -typedef struct _scb_t { - u16 scb_status; /* SCB Status register */ - u8 scb_cmd_low; /* SCB Command register (low byte) */ - u8 scb_cmd_hi; /* SCB Command register (high byte) */ - u32 scb_gen_ptr; /* SCB General pointer */ - u32 scb_port; /* PORT register */ - u16 scb_flsh_cntrl; /* Flash Control register */ - u16 scb_eprm_cntrl; /* EEPROM control register */ - u32 scb_mdi_cntrl; /* MDI Control Register */ - /* Changed for 82558 enhancement */ - union { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - d101_scb_ext d101_scb; /* 82558/9 specific fields */ - d101m_scb_ext d101m_scb; /* 82559 specific fields */ - d102_scb_ext d102_scb; - } scb_ext; -} scb_t __attribute__ ((__packed__)); - -/* Self test - * This is used to dump results of the self test - */ -typedef struct _self_test_t { - u32 st_sign; /* Self Test Signature */ - u32 st_result; /* Self Test Results */ -} self_test_t __attribute__ ((__packed__)); - -/* - * Statistical Counters - */ -/* 82557 counters */ -typedef struct _basic_cntr_t { - u32 xmt_gd_frames; /* Good frames transmitted */ - u32 xmt_max_coll; /* Fatal frames -- had max collisions */ - u32 xmt_late_coll; /* Fatal frames -- had a late coll. */ - u32 xmt_uruns; /* Xmit underruns (fatal or re-transmit) */ - u32 xmt_lost_crs; /* Frames transmitted without CRS */ - u32 xmt_deferred; /* Deferred transmits */ - u32 xmt_sngl_coll; /* Transmits that had 1 and only 1 coll. */ - u32 xmt_mlt_coll; /* Transmits that had multiple coll. */ - u32 xmt_ttl_coll; /* Transmits that had 1+ collisions. */ - u32 rcv_gd_frames; /* Good frames received */ - u32 rcv_crc_errs; /* Aligned frames that had a CRC error */ - u32 rcv_algn_errs; /* Receives that had alignment errors */ - u32 rcv_rsrc_err; /* Good frame dropped cuz no resources */ - u32 rcv_oruns; /* Overrun errors - bus was busy */ - u32 rcv_err_coll; /* Received frms. that encountered coll. */ - u32 rcv_shrt_frames; /* Received frames that were to short */ -} basic_cntr_t; - -/* 82558 extended statistic counters */ -typedef struct _ext_cntr_t { - u32 xmt_fc_frames; - u32 rcv_fc_frames; - u32 rcv_fc_unsupported; -} ext_cntr_t; - -/* 82559 TCO statistic counters */ -typedef struct _tco_cntr_t { - u16 xmt_tco_frames; - u16 rcv_tco_frames; -} tco_cntr_t; - -/* Structures to access thet physical dump area */ -/* Use one of these types, according to the statisitcal counters mode, - to cast the pointer to the physical dump area and access the cmd_complete - DWORD. */ - -/* 557-mode : only basic counters + cmd_complete */ -typedef struct _err_cntr_557_t { - basic_cntr_t basic_stats; - u32 cmd_complete; -} err_cntr_557_t; - -/* 558-mode : basic + extended counters + cmd_complete */ -typedef struct _err_cntr_558_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - u32 cmd_complete; -} err_cntr_558_t; - -/* 559-mode : basic + extended + TCO counters + cmd_complete */ -typedef struct _err_cntr_559_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - tco_cntr_t tco_stats; - u32 cmd_complete; -} err_cntr_559_t; - -/* This typedef defines the struct needed to hold the largest number of counters */ -typedef err_cntr_559_t max_counters_t; - -/* Different statistical-counters mode the controller may be in */ -typedef enum _stat_mode_t { - E100_BASIC_STATS = 0, /* 82557 stats : 16 counters / 16 dw */ - E100_EXTENDED_STATS, /* 82558 stats : 19 counters / 19 dw */ - E100_TCO_STATS /* 82559 stats : 21 counters / 20 dw */ -} stat_mode_t; - -/* dump statistical counters complete codes */ -#define DUMP_STAT_COMPLETED 0xA005 -#define DUMP_RST_STAT_COMPLETED 0xA007 - -/* Command Block (CB) Generic Header Structure*/ -typedef struct _cb_header_t { - u16 cb_status; /* Command Block Status */ - u16 cb_cmd; /* Command Block Command */ - u32 cb_lnk_ptr; /* Link To Next CB */ -} cb_header_t __attribute__ ((__packed__)); - -//* Individual Address Command Block (IA_CB)*/ -typedef struct _ia_cb_t { - cb_header_t ia_cb_hdr; - u8 ia_addr[ETH_ALEN]; -} ia_cb_t __attribute__ ((__packed__)); - -/* Configure Command Block (CONFIG_CB)*/ -typedef struct _config_cb_t { - cb_header_t cfg_cbhdr; - u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; -} config_cb_t __attribute__ ((__packed__)); - -/* MultiCast Command Block (MULTICAST_CB)*/ -typedef struct _multicast_cb_t { - cb_header_t mc_cbhdr; - u16 mc_count; /* Number of multicast addresses */ - u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)]; -} mltcst_cb_t __attribute__ ((__packed__)); - -#define UCODE_MAX_DWORDS 134 -/* Load Microcode Command Block (LOAD_UCODE_CB)*/ -typedef struct _load_ucode_cb_t { - cb_header_t load_ucode_cbhdr; - u32 ucode_dword[UCODE_MAX_DWORDS]; -} load_ucode_cb_t __attribute__ ((__packed__)); - -/* Load Programmable Filter Data*/ -typedef struct _filter_cb_t { - cb_header_t filter_cb_hdr; - u32 filter_data[MAX_FILTER]; -} filter_cb_t __attribute__ ((__packed__)); - -/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block - */ -typedef struct _nxmit_cb_t { - union { - config_cb_t config; - ia_cb_t setup; - load_ucode_cb_t load_ucode; - mltcst_cb_t multicast; - filter_cb_t filter; - } ntcb; -} nxmit_cb_t __attribute__ ((__packed__)); - -/*Block for queuing for postponed execution of the non-transmit commands*/ -typedef struct _nxmit_cb_entry_t { - struct list_head list_elem; - nxmit_cb_t *non_tx_cmd; - dma_addr_t dma_addr; - unsigned long expiration_time; -} nxmit_cb_entry_t; - -/* States for postponed non tx commands execution */ -typedef enum _non_tx_cmd_state_t { - E100_NON_TX_IDLE = 0, /* No queued NON-TX commands */ - E100_WAIT_TX_FINISH, /* Wait for completion of the TX activities */ - E100_WAIT_NON_TX_FINISH /* Wait for completion of the non TX command */ -} non_tx_cmd_state_t; - -/* some defines for the ipcb */ -#define IPCB_IP_CHECKSUM_ENABLE BIT_4 -#define IPCB_TCPUDP_CHECKSUM_ENABLE BIT_5 -#define IPCB_TCP_PACKET BIT_6 -#define IPCB_LARGESEND_ENABLE BIT_7 -#define IPCB_HARDWAREPARSING_ENABLE BIT_0 -#define IPCB_INSERTVLAN_ENABLE BIT_1 -#define IPCB_IP_ACTIVATION_DEFAULT IPCB_HARDWAREPARSING_ENABLE - -/* Transmit Buffer Descriptor (TBD)*/ -typedef struct _tbd_t { - u32 tbd_buf_addr; /* Physical Transmit Buffer Address */ - u16 tbd_buf_cnt; /* Actual Count Of Bytes */ - u16 padd; -} tbd_t __attribute__ ((__packed__)); - -/* d102 specific fields */ -typedef struct _tcb_ipcb_t { - u16 schedule_low; - u8 ip_schedule; - u8 ip_activation_high; - u16 vlan; - u8 ip_header_offset; - u8 tcp_header_offset; - union { - u32 sec_rec_phys_addr; - u32 tbd_zero_address; - } tbd_sec_addr; - union { - u16 sec_rec_size; - u16 tbd_zero_size; - } tbd_sec_size; - u16 total_tcp_payload; -} tcb_ipcb_t __attribute__ ((__packed__)); - -#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS) - -/* Transmit Command Block (TCB)*/ -struct _tcb_t { - cb_header_t tcb_hdr; - u32 tcb_tbd_ptr; /* TBD address */ - u16 tcb_cnt; /* Data Bytes In TCB past header */ - u8 tcb_thrshld; /* TX Threshold for FIFO Extender */ - u8 tcb_tbd_num; - - union { - tcb_ipcb_t ipcb; /* d102 ipcb fields */ - tbd_t tbd_array[E100_TBD_ARRAY_SIZE]; - } tcbu; - - /* From here onward we can dump anything we want as long as the - * size of the total structure is a multiple of a paragraph - * boundary ( i.e. -16 bit aligned ). - */ - tbd_t *tbd_ptr; - - u32 tcb_tbd_dflt_ptr; /* TBD address for non-segmented packet */ - u32 tcb_tbd_expand_ptr; /* TBD address for segmented packet */ - - struct sk_buff *tcb_skb; /* the associated socket buffer */ - dma_addr_t tcb_phys; /* phys addr of the TCB */ -} __attribute__ ((__packed__)); - -#define _TCB_T_ -typedef struct _tcb_t tcb_t; - -/* Receive Frame Descriptor (RFD) - will be using the simple model*/ -struct _rfd_t { - /* 8255x */ - cb_header_t rfd_header; - u32 rfd_rbd_ptr; /* Receive Buffer Descriptor Addr */ - u16 rfd_act_cnt; /* Number Of Bytes Received */ - u16 rfd_sz; /* Number Of Bytes In RFD */ - /* D102 aka Gamla */ - u16 vlanid; - u8 rcvparserstatus; - u8 reserved; - u16 securitystatus; - u8 checksumstatus; - u8 zerocopystatus; - u8 pad[8]; /* data should be 16 byte aligned */ - u8 data[RFD_DATA_SIZE]; - -} __attribute__ ((__packed__)); - -#define _RFD_T_ -typedef struct _rfd_t rfd_t; - -/* Receive Buffer Descriptor (RBD)*/ -typedef struct _rbd_t { - u16 rbd_act_cnt; /* Number Of Bytes Received */ - u16 rbd_filler; - u32 rbd_lnk_addr; /* Link To Next RBD */ - u32 rbd_rcb_addr; /* Receive Buffer Address */ - u16 rbd_sz; /* Receive Buffer Size */ - u16 rbd_filler1; -} rbd_t __attribute__ ((__packed__)); - -/* - * This structure is used to maintain a FIFO access to a resource that is - * maintained as a circular queue. The resource to be maintained is pointed - * to by the "data" field in the structure below. In this driver the TCBs', - * TBDs' & RFDs' are maintained as a circular queue & are managed thru this - * structure. - */ -typedef struct _buf_pool_t { - unsigned int head; /* index to first used resource */ - unsigned int tail; /* index to last used resource */ - void *data; /* points to resource pool */ -} buf_pool_t; - -/*Rx skb holding structure*/ -struct rx_list_elem { - struct list_head list_elem; - dma_addr_t dma_addr; - struct sk_buff *skb; -}; - -enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT }; -enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING }; -enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP }; - -/* 64 bit aligned size */ -#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7) - -typedef struct _bd_dma_able_t { - char selftest[E100_SIZE_64A(self_test_t)]; - char stats_counters[E100_SIZE_64A(max_counters_t)]; -} bd_dma_able_t; - -/* bit masks for bool parameters */ -#define PRM_XSUMRX 0x00000001 -#define PRM_UCODE 0x00000002 -#define PRM_FC 0x00000004 -#define PRM_IFS 0x00000008 -#define PRM_BUNDLE_SMALL 0x00000010 - -struct cfg_params { - int e100_speed_duplex; - int RxDescriptors; - int TxDescriptors; - int IntDelay; - int BundleMax; - int ber; - u32 b_params; -}; -struct ethtool_lpbk_data{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - -}; - -struct e100_private { - struct vlan_group *vlgrp; - u32 flags; /* board management flags */ - u32 tx_per_underrun; /* number of good tx frames per underrun */ - unsigned int tx_count; /* count of tx frames, so we can request an interrupt */ - u8 tx_thld; /* stores transmit threshold */ - u16 eeprom_size; - u32 pwa_no; /* PWA: xxxxxx-0xx */ - u8 perm_node_address[ETH_ALEN]; - struct list_head active_rx_list; /* list of rx buffers */ - struct list_head rx_struct_pool; /* pool of rx buffer struct headers */ - u16 rfd_size; /* size of the adapter's RFD struct */ - int skb_req; /* number of skbs neede by the adapter */ - u8 intr_mask; /* mask for interrupt status */ - - void *dma_able; /* dma allocated structs */ - dma_addr_t dma_able_phys; - self_test_t *selftest; /* pointer to self test area */ - dma_addr_t selftest_phys; /* phys addr of selftest */ - max_counters_t *stats_counters; /* pointer to stats table */ - dma_addr_t stat_cnt_phys; /* phys addr of stat counter area */ - - stat_mode_t stat_mode; /* statistics mode: extended, TCO, basic */ - scb_t *scb; /* memory mapped ptr to 82557 scb */ - - tcb_t *last_tcb; /* pointer to last tcb sent */ - buf_pool_t tcb_pool; /* adapter's TCB array */ - dma_addr_t tcb_phys; /* phys addr of start of TCBs */ - - u16 cur_line_speed; - u16 cur_dplx_mode; - - struct net_device *device; - struct pci_dev *pdev; - struct driver_stats drv_stats; - - u8 rev_id; /* adapter PCI revision ID */ - - unsigned int phy_addr; /* address of PHY component */ - unsigned int PhyId; /* ID of PHY component */ - unsigned int PhyState; /* state for the fix squelch algorithm */ - unsigned int PhyDelay; /* delay for the fix squelch algorithm */ - - /* Lock defintions for the driver */ - spinlock_t bd_lock; /* board lock */ - spinlock_t bd_non_tx_lock; /* Non transmit command lock */ - spinlock_t config_lock; /* config block lock */ - spinlock_t mdi_access_lock; /* mdi lock */ - - struct timer_list watchdog_timer; /* watchdog timer id */ - - /* non-tx commands parameters */ - struct timer_list nontx_timer_id; /* non-tx timer id */ - struct list_head non_tx_cmd_list; - non_tx_cmd_state_t non_tx_command_state; - nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD]; - - enum next_cu_cmd_e next_cu_cmd; - - /* Zero Locking Algorithm data members */ - enum zlock_state_e zlock_state; - u8 zlock_read_data[16]; /* number of times each value 0-15 was read */ - u16 zlock_read_cnt; /* counts number of reads */ - ulong zlock_sleep_cnt; /* keeps track of "sleep" time */ - - u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; - - /* IFS params */ - u8 ifs_state; - u8 ifs_value; - - struct cfg_params params; /* adapter's command line parameters */ - - u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */ - - /* WOL params for ethtool */ - u32 wolsupported; - u32 wolopts; - u16 ip_lbytes; - struct ethtool_lpbk_data loopback; - struct timer_list blink_timer; /* led blink timer id */ - -#ifdef CONFIG_PM - u32 pci_state[16]; -#endif -#ifdef E100_CU_DEBUG - u8 last_cmd; - u8 last_sub_cmd; -#endif -}; - -#define E100_AUTONEG 0 -#define E100_SPEED_10_HALF 1 -#define E100_SPEED_10_FULL 2 -#define E100_SPEED_100_HALF 3 -#define E100_SPEED_100_FULL 4 - -/********* function prototypes *************/ -extern int e100_open(struct net_device *); -extern int e100_close(struct net_device *); -extern void e100_isolate_driver(struct e100_private *bdp); -extern unsigned char e100_hw_init(struct e100_private *); -extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); -extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb); -extern void e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd); -extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp); -extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *cmd); -extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout, - u32 *st_result); -extern unsigned char e100_get_link_state(struct e100_private *bdp); -extern unsigned char e100_wait_scb(struct e100_private *bdp); - -extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset); -extern unsigned char e100_configure_device(struct e100_private *bdp); -#ifdef E100_CU_DEBUG -extern unsigned char e100_cu_unknown_state(struct e100_private *bdp); -#endif - -#define ROM_TEST_FAIL 0x01 -#define REGISTER_TEST_FAIL 0x02 -#define SELF_TEST_FAIL 0x04 -#define TEST_TIMEOUT 0x08 - -enum test_offsets { - test_link, - test_eeprom, - test_self_test, - test_loopback_mac, - test_loopback_phy, - cable_diag, - max_test_res, /* must be last */ -}; - -#endif --- linux-2.6.1-rc1/drivers/net/e100/e100_main.c 2003-12-30 22:37:21.000000000 -0800 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,4343 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_main.c * -* * -* Abstract: Functions for the driver entry points like load, * -* unload, open and close. All board specific calls made * -* by the network interface section of the driver. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ - -/* Change Log - * - * 2.3.30 09/21/03 - * o Bug fix (Bugzilla 97908): Loading e100 was causing crash on Itanium2 - * with HP chipset - * o Bug fix (Bugzilla 101583): e100 can't pass traffic with ipv6 - * o Bug fix (Bugzilla 101360): PRO/10+ can't pass traffic - * - * 2.3.27 08/08/03 - * o Bug fix: read skb->len after freeing skb - * [Andrew Morton] akpm@zip.com.au - * o Bug fix: 82557 (with National PHY) timeout during init - * [Adam Kropelin] akropel1@rochester.rr.com - * o Feature add: allow to change Wake On LAN when EEPROM disabled - * - * 2.3.13 05/08/03 - */ - -#include -#include -#include -#include -#include "e100.h" -#include "e100_ucode.h" -#include "e100_config.h" -#include "e100_phy.h" - -extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp); - -static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", -}; -#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN - -static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *); -static void e100_get_speed_duplex_caps(struct e100_private *); -static int e100_ethtool_get_settings(struct net_device *, struct ifreq *); -static int e100_ethtool_set_settings(struct net_device *, struct ifreq *); - -static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *); -static int e100_ethtool_eeprom(struct net_device *, struct ifreq *); - -#define E100_EEPROM_MAGIC 0x1234 -static int e100_ethtool_glink(struct net_device *, struct ifreq *); -static int e100_ethtool_gregs(struct net_device *, struct ifreq *); -static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *); -static int e100_ethtool_wol(struct net_device *, struct ifreq *); -#ifdef CONFIG_PM -static unsigned char e100_setup_filter(struct e100_private *bdp); -static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp); -#endif -static u16 e100_get_ip_lbytes(struct net_device *dev); -extern void e100_config_wol(struct e100_private *bdp); -extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); -static int e100_ethtool_test(struct net_device *, struct ifreq *); -static int e100_ethtool_gstrings(struct net_device *, struct ifreq *); -static char test_strings[][ETH_GSTRING_LEN] = { - "Link test (on/offline)", - "Eeprom test (on/offline)", - "Self test (offline)", - "Mac loopback (offline)", - "Phy loopback (offline)", - "Cable diagnostic (offline)" -}; - -static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); - -static int e100_mii_ioctl(struct net_device *, struct ifreq *, int); - -static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *, - nxmit_cb_entry_t *); -static void e100_free_nontx_list(struct e100_private *); -static void e100_non_tx_background(unsigned long); -static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb); -/* Global Data structures and variables */ -char e100_copyright[] = "Copyright (c) 2003 Intel Corporation"; -char e100_driver_version[]="2.3.30-k1"; -const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; -char e100_short_driver_name[] = "e100"; -static int e100nics = 0; -static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group - *grp); -static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid); -static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); - -#ifdef CONFIG_PM -static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); -static int e100_suspend(struct pci_dev *pcid, u32 state); -static int e100_resume(struct pci_dev *pcid); -static unsigned char e100_asf_enabled(struct e100_private *bdp); -struct notifier_block e100_notifier_reboot = { - .notifier_call = e100_notify_reboot, - .next = NULL, - .priority = 0 -}; -#endif - -/*********************************************************************/ -/*! This is a GCC extension to ANSI C. - * See the item "Labeled Elements in Initializers" in the section - * "Extensions to the C Language Family" of the GCC documentation. - *********************************************************************/ -#define E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 } - -/* All parameters are treated the same, as an integer array of values. - * This macro just reduces the need to repeat the same declaration code - * over and over (plus this helps to avoid typo bugs). - */ -#define E100_PARAM(X, S) \ - static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \ - MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \ - MODULE_PARM_DESC(X, S); - -/* ====================================================================== */ -static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *); -static u8 e100_D102_check_checksum(rfd_t *); -static int e100_ioctl(struct net_device *, struct ifreq *, int); -static int e100_change_mtu(struct net_device *, int); -static int e100_xmit_frame(struct sk_buff *, struct net_device *); -static unsigned char e100_init(struct e100_private *); -static int e100_set_mac(struct net_device *, void *); -struct net_device_stats *e100_get_stats(struct net_device *); - -static irqreturn_t e100intr(int, void *, struct pt_regs *); -static void e100_print_brd_conf(struct e100_private *); -static void e100_set_multi(struct net_device *); - -static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); -static u8 e100_sw_init(struct e100_private *); -static void e100_tco_workaround(struct e100_private *); -static unsigned char e100_alloc_space(struct e100_private *); -static void e100_dealloc_space(struct e100_private *); -static int e100_alloc_tcb_pool(struct e100_private *); -static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *); -static void e100_free_tcb_pool(struct e100_private *); -static int e100_alloc_rfd_pool(struct e100_private *); -static void e100_free_rfd_pool(struct e100_private *); - -static void e100_rd_eaddr(struct e100_private *); -static void e100_rd_pwa_no(struct e100_private *); -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16); -extern u16 e100_eeprom_size(struct e100_private *); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); - -static unsigned char e100_clr_cntrs(struct e100_private *); -static unsigned char e100_load_microcode(struct e100_private *); -static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *); -static unsigned char e100_update_stats(struct e100_private *bdp); - -static void e100_start_ru(struct e100_private *); -static void e100_dump_stats_cntrs(struct e100_private *); - -static void e100_check_options(int board, struct e100_private *bdp); -static void e100_set_int_option(int *, int, int, int, int, char *); -static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, - char *); -unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); -void e100_exec_cmplx(struct e100_private *, u32, u8); - -/** - * e100_get_rx_struct - retrieve cell to hold skb buff from the pool - * @bdp: atapter's private data struct - * - * Returns the new cell to hold sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_get_rx_struct(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; - - if (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - } - - return rx_struct; -} - -/** - * e100_alloc_skb - allocate an skb for the adapter - * @bdp: atapter's private data struct - * - * Allocates skb with enough room for rfd, and data, and reserve non-data space. - * Returns the new cell with sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_alloc_skb(struct e100_private *bdp) -{ - struct sk_buff *new_skb; - u32 skb_size = sizeof (rfd_t); - struct rx_list_elem *rx_struct; - - new_skb = (struct sk_buff *) dev_alloc_skb(skb_size); - if (new_skb) { - /* The IP data should be - DWORD aligned. since the ethernet header is 14 bytes long, - we need to reserve 2 extra bytes so that the TCP/IP headers - will be DWORD aligned. */ - skb_reserve(new_skb, 2); - if ((rx_struct = e100_get_rx_struct(bdp)) == NULL) - goto err; - rx_struct->skb = new_skb; - rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data, - sizeof (rfd_t), - PCI_DMA_FROMDEVICE); - if (!rx_struct->dma_addr) - goto err; - skb_reserve(new_skb, bdp->rfd_size); - return rx_struct; - } else { - return NULL; - } - -err: - dev_kfree_skb_irq(new_skb); - return NULL; -} - -/** - * e100_add_skb_to_end - add an skb to the end of our rfd list - * @bdp: atapter's private data struct - * @rx_struct: rx_list_elem with the new skb - * - * Adds a newly allocated skb to the end of our rfd list. - */ -inline void -e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct) -{ - rfd_t *rfdn; /* The new rfd */ - rfd_t *rfd; /* The old rfd */ - struct rx_list_elem *rx_struct_last; - - (rx_struct->skb)->dev = bdp->device; - rfdn = RFD_POINTER(rx_struct->skb, bdp); - rfdn->rfd_header.cb_status = 0; - rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT); - rfdn->rfd_act_cnt = 0; - rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE); - - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size, - PCI_DMA_TODEVICE); - - if (!list_empty(&(bdp->active_rx_list))) { - rx_struct_last = list_entry(bdp->active_rx_list.prev, - struct rx_list_elem, list_elem); - rfd = RFD_POINTER(rx_struct_last->skb, bdp); - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_FROMDEVICE); - put_unaligned(cpu_to_le32(rx_struct->dma_addr), - ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr)))); - - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 8, PCI_DMA_TODEVICE); - rfd->rfd_header.cb_cmd &= - __constant_cpu_to_le16((u16) ~RFD_EL_BIT); - - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_TODEVICE); - } - - list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list)); -} - -static inline void -e100_alloc_skbs(struct e100_private *bdp) -{ - for (; bdp->skb_req > 0; bdp->skb_req--) { - struct rx_list_elem *rx_struct; - - if ((rx_struct = e100_alloc_skb(bdp)) == NULL) - return; - - e100_add_skb_to_end(bdp, rx_struct); - } -} - -void e100_tx_srv(struct e100_private *); -u32 e100_rx_srv(struct e100_private *); - -void e100_watchdog(struct net_device *); -void e100_refresh_txthld(struct e100_private *); -void e100_manage_adaptive_ifs(struct e100_private *); -void e100_clear_pools(struct e100_private *); -static void e100_clear_structs(struct net_device *); -static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *, - struct sk_buff *); -static void e100_set_multi_exec(struct net_device *dev); - -MODULE_AUTHOR("Intel Corporation, "); -MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver"); -MODULE_LICENSE("GPL"); - -E100_PARAM(TxDescriptors, "Number of transmit descriptors"); -E100_PARAM(RxDescriptors, "Number of receive descriptors"); -E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); -E100_PARAM(e100_speed_duplex, "Speed and Duplex settings"); -E100_PARAM(ucode, "Disable or enable microcode loading"); -E100_PARAM(ber, "Value for the BER correction algorithm"); -E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing"); -E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay"); -E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames"); -E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling"); -E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm"); - -/** - * e100_exec_cmd - issue a comand - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100. - */ -static inline void -e100_exec_cmd(struct e100_private *bdp, u8 cmd_low) -{ - writeb(cmd_low, &(bdp->scb->scb_cmd_low)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -/** - * e100_wait_scb - wait for SCB to clear - * @bdp: atapter's private data struct - * - * This routine checks to see if the e100 has accepted a command. - * It does so by checking the command field in the SCB, which will - * be zeroed by the e100 upon accepting a command. The loop waits - * for up to 1 millisecond for command acceptance. - * - * Returns: - * true if the SCB cleared within 1 millisecond. - * false if it didn't clear within 1 millisecond - */ -unsigned char -e100_wait_scb(struct e100_private *bdp) -{ - int i; - - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - } - - /* it didn't work. do it the slow way using udelay()s */ - for (i = 0; i < E100_MAX_SCB_WAIT; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - udelay(1); - } - - return false; -} - -/** - * e100_wait_exec_simple - issue a command - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100 after waiting for - * the previous command to finish. - * - * Returns: - * true if the command was issued to the chip successfully - * false if the command was not issued to the chip - */ -inline unsigned char -e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low) -{ - if (!e100_wait_scb(bdp)) { - printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n", - bdp->device->name); -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current simple command (%x) " - "can't be executed\n", - bdp->device->name, scb_cmd_low); -#endif - return false; - } - e100_exec_cmd(bdp, scb_cmd_low); -#ifdef E100_CU_DEBUG - bdp->last_cmd = scb_cmd_low; - bdp->last_sub_cmd = 0; -#endif - return true; -} - -void -e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd) -{ - writel(phys_addr, &(bdp->scb->scb_gen_ptr)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - e100_exec_cmd(bdp, cmd); -} - -unsigned char -e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd) -{ - if (!e100_wait_scb(bdp)) { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current complex command " - "(%x/%x) can't be executed\n", - bdp->device->name, cmd, sub_cmd); -#endif - return false; - } - e100_exec_cmplx(bdp, phys_addr, cmd); -#ifdef E100_CU_DEBUG - bdp->last_cmd = cmd; - bdp->last_sub_cmd = sub_cmd; -#endif - return true; -} - -inline u8 -e100_wait_cus_idle(struct e100_private *bdp) -{ - int i; - - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - } - - for (i = 0; i < E100_MAX_CU_IDLE_WAIT; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - udelay(1); - } - - return false; -} - -/** - * e100_disable_clear_intr - disable and clear/ack interrupts - * @bdp: atapter's private data struct - * - * This routine disables interrupts at the hardware, by setting - * the M (mask) bit in the adapter's CSR SCB command word. - * It also clear/ack interrupts. - */ -static inline void -e100_disable_clear_intr(struct e100_private *bdp) -{ - u16 intr_status; - /* Disable interrupts on our PCI board by setting the mask bit */ - writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi); - intr_status = readw(&bdp->scb->scb_status); - /* ack and clear intrs */ - writew(intr_status, &bdp->scb->scb_status); - readw(&bdp->scb->scb_status); -} - -/** - * e100_set_intr_mask - set interrupts - * @bdp: atapter's private data struct - * - * This routine sets interrupts at the hardware, by resetting - * the M (mask) bit in the adapter's CSR SCB command word - */ -static inline void -e100_set_intr_mask(struct e100_private *bdp) -{ - writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -static inline void -e100_trigger_SWI(struct e100_private *bdp) -{ - /* Trigger interrupt on our PCI board by asserting SWI bit */ - writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -static int -e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) -{ - static int first_time = true; - struct net_device *dev = NULL; - struct e100_private *bdp = NULL; - int rc = 0; - u16 cal_checksum, read_checksum; - - dev = alloc_etherdev(sizeof (struct e100_private)); - if (dev == NULL) { - printk(KERN_ERR "e100: Not able to alloc etherdev struct\n"); - rc = -ENODEV; - goto out; - } - - SET_MODULE_OWNER(dev); - - if (first_time) { - first_time = false; - printk(KERN_NOTICE "%s - version %s\n", - e100_full_driver_name, e100_driver_version); - printk(KERN_NOTICE "%s\n", e100_copyright); - printk(KERN_NOTICE "\n"); - } - - bdp = dev->priv; - bdp->pdev = pcid; - bdp->device = dev; - - pci_set_drvdata(pcid, dev); - SET_NETDEV_DEV(dev, &pcid->dev); - - bdp->flags = 0; - bdp->ifs_state = 0; - bdp->ifs_value = 0; - bdp->scb = 0; - - init_timer(&bdp->nontx_timer_id); - bdp->nontx_timer_id.data = (unsigned long) bdp; - bdp->nontx_timer_id.function = (void *) &e100_non_tx_background; - INIT_LIST_HEAD(&(bdp->non_tx_cmd_list)); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - - init_timer(&bdp->watchdog_timer); - bdp->watchdog_timer.data = (unsigned long) dev; - bdp->watchdog_timer.function = (void *) &e100_watchdog; - - if ((rc = e100_pci_setup(pcid, bdp)) != 0) { - goto err_dev; - } - - if ((rc = e100_alloc_space(bdp)) != 0) { - goto err_pci; - } - - if (((bdp->pdev->device > 0x1030) - && (bdp->pdev->device < 0x103F)) - || ((bdp->pdev->device >= 0x1050) - && (bdp->pdev->device <= 0x1057)) - || (bdp->pdev->device == 0x2449) - || (bdp->pdev->device == 0x2459) - || (bdp->pdev->device == 0x245D)) { - bdp->rev_id = D101MA_REV_ID; /* workaround for ICH3 */ - bdp->flags |= IS_ICH; - } - - if (bdp->rev_id == 0xff) - bdp->rev_id = 1; - - if ((u8) bdp->rev_id >= D101A4_REV_ID) - bdp->flags |= IS_BACHELOR; - - if ((u8) bdp->rev_id >= D102_REV_ID) { - bdp->flags |= USE_IPCB; - bdp->rfd_size = 32; - } else { - bdp->rfd_size = 16; - } - - dev->vlan_rx_register = e100_vlan_rx_register; - dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; - dev->irq = pcid->irq; - dev->open = &e100_open; - dev->hard_start_xmit = &e100_xmit_frame; - dev->stop = &e100_close; - dev->change_mtu = &e100_change_mtu; - dev->get_stats = &e100_get_stats; - dev->set_multicast_list = &e100_set_multi; - dev->set_mac_address = &e100_set_mac; - dev->do_ioctl = &e100_ioctl; - - if (bdp->flags & USE_IPCB) - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - - if ((rc = register_netdev(dev)) != 0) { - goto err_dealloc; - } - - e100_check_options(e100nics, bdp); - - if (!e100_init(bdp)) { - printk(KERN_ERR "e100: Failed to initialize, instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - /* Check if checksum is valid */ - cal_checksum = e100_eeprom_calculate_chksum(bdp); - read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1)); - if (cal_checksum != read_checksum) { - printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - e100nics++; - - e100_get_speed_duplex_caps(bdp); - - printk(KERN_NOTICE - "e100: %s: %s\n", - bdp->device->name, "Intel(R) PRO/100 Network Connection"); - e100_print_brd_conf(bdp); - - bdp->wolsupported = 0; - bdp->wolopts = 0; - if (bdp->rev_id >= D101A4_REV_ID) - bdp->wolsupported = WAKE_PHY | WAKE_MAGIC; - if (bdp->rev_id >= D101MA_REV_ID) - bdp->wolsupported |= WAKE_UCAST | WAKE_ARP; - - /* Check if WoL is enabled on EEPROM */ - if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) { - /* Magic Packet WoL is enabled on device by default */ - /* if EEPROM WoL bit is TRUE */ - bdp->wolopts = WAKE_MAGIC; - } - - printk(KERN_NOTICE "\n"); - - goto out; - -err_unregister_netdev: - unregister_netdev(dev); -err_dealloc: - e100_dealloc_space(bdp); -err_pci: - iounmap(bdp->scb); - pci_release_regions(pcid); - pci_disable_device(pcid); -err_dev: - pci_set_drvdata(pcid, NULL); - kfree(dev); -out: - return rc; -} - -/** - * e100_clear_structs - free resources - * @dev: adapter's net_device struct - * - * Free all device specific structs, unmap i/o address, etc. - */ -static void __devexit -e100_clear_structs(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - iounmap(bdp->scb); - pci_release_regions(bdp->pdev); - pci_disable_device(bdp->pdev); - - e100_dealloc_space(bdp); - pci_set_drvdata(bdp->pdev, NULL); - free_netdev(dev); -} - -static void __devexit -e100_remove1(struct pci_dev *pcid) -{ - struct net_device *dev; - struct e100_private *bdp; - - if (!(dev = (struct net_device *) pci_get_drvdata(pcid))) - return; - - bdp = dev->priv; - - unregister_netdev(dev); - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - del_timer_sync(&bdp->nontx_timer_id); - e100_free_nontx_list(bdp); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - } - - e100_clear_structs(dev); - - --e100nics; -} - -static struct pci_device_id e100_id_table[] = { - {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0,} /* This has to be the last entry*/ -}; -MODULE_DEVICE_TABLE(pci, e100_id_table); - -static struct pci_driver e100_driver = { - .name = "e100", - .id_table = e100_id_table, - .probe = e100_found1, - .remove = __devexit_p(e100_remove1), -#ifdef CONFIG_PM - .suspend = e100_suspend, - .resume = e100_resume, -#endif -}; - -static int __init -e100_init_module(void) -{ - int ret; - ret = pci_module_init(&e100_driver); - - if(ret >= 0) { -#ifdef CONFIG_PM - register_reboot_notifier(&e100_notifier_reboot); -#endif - } - - return ret; -} - -static void __exit -e100_cleanup_module(void) -{ -#ifdef CONFIG_PM - unregister_reboot_notifier(&e100_notifier_reboot); -#endif - - pci_unregister_driver(&e100_driver); -} - -module_init(e100_init_module); -module_exit(e100_cleanup_module); - -/** - * e100_check_options - check command line options - * @board: board number - * @bdp: atapter's private data struct - * - * This routine does range checking on command-line options - */ -void -e100_check_options(int board, struct e100_private *bdp) -{ - if (board >= E100_MAX_NIC) { - printk(KERN_NOTICE - "e100: No configuration available for board #%d\n", - board); - printk(KERN_NOTICE "e100: Using defaults for all values\n"); - board = E100_MAX_NIC; - } - - e100_set_int_option(&(bdp->params.TxDescriptors), TxDescriptors[board], - E100_MIN_TCB, E100_MAX_TCB, E100_DEFAULT_TCB, - "TxDescriptor count"); - - e100_set_int_option(&(bdp->params.RxDescriptors), RxDescriptors[board], - E100_MIN_RFD, E100_MAX_RFD, E100_DEFAULT_RFD, - "RxDescriptor count"); - - e100_set_int_option(&(bdp->params.e100_speed_duplex), - e100_speed_duplex[board], 0, 4, - E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode"); - - e100_set_int_option(&(bdp->params.ber), ber[board], 0, ZLOCK_MAX_ERRORS, - E100_DEFAULT_BER, "Bit Error Rate count"); - - e100_set_bool_option(bdp, XsumRX[board], PRM_XSUMRX, E100_DEFAULT_XSUM, - "XsumRX value"); - - /* Default ucode value depended on controller revision */ - if (bdp->rev_id >= D101MA_REV_ID) { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, - E100_DEFAULT_UCODE, "ucode value"); - } else { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, false, - "ucode value"); - } - - e100_set_bool_option(bdp, flow_control[board], PRM_FC, E100_DEFAULT_FC, - "flow control value"); - - e100_set_bool_option(bdp, IFS[board], PRM_IFS, E100_DEFAULT_IFS, - "IFS value"); - - e100_set_bool_option(bdp, BundleSmallFr[board], PRM_BUNDLE_SMALL, - E100_DEFAULT_BUNDLE_SMALL_FR, - "CPU saver bundle small frames value"); - - e100_set_int_option(&(bdp->params.IntDelay), IntDelay[board], 0x0, - 0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, - "CPU saver interrupt delay value"); - - e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1, - 0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX, - "CPU saver bundle max value"); - -} - -/** - * e100_set_int_option - check and set an integer option - * @option: a pointer to the relevant option field - * @val: the value specified - * @min: the minimum valid value - * @max: the maximum valid value - * @default_val: the default value - * @name: the name of the option - * - * This routine does range checking on a command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid, change it to the default. - */ -void -e100_set_int_option(int *option, int val, int min, int max, int default_val, - char *name) -{ - if (val == -1) { /* no value specified. use default */ - *option = default_val; - - } else if ((val < min) || (val > max)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid range is %i-%i\n", - name, val, min, max); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - *option = default_val; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - *option = val; - } -} - -/** - * e100_set_bool_option - check and set a boolean option - * @bdp: atapter's private data struct - * @val: the value specified - * @mask: the mask for the relevant option - * @default_val: the default value - * @name: the name of the option - * - * This routine checks a boolean command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid (not 0 or 1), - * change it to the default. - */ -void -e100_set_bool_option(struct e100_private *bdp, int val, u32 mask, - int default_val, char *name) -{ - if (val == -1) { - if (default_val) - bdp->params.b_params |= mask; - - } else if ((val != true) && (val != false)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid values are %i/%i\n", - name, val, false, true); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - - if (default_val) - bdp->params.b_params |= mask; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - if (val) - bdp->params.b_params |= mask; - } -} - -int -e100_open(struct net_device *dev) -{ - struct e100_private *bdp; - int rc = 0; - - bdp = dev->priv; - - /* setup the tcb pool */ - if (!e100_alloc_tcb_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - bdp->last_tcb = NULL; - - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - - e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data, - bdp->params.TxDescriptors, bdp); - - if (!e100_alloc_rfd_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } - - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (dev->flags & IFF_UP) - /* Otherwise process may sleep forever */ - netif_wake_queue(dev); - else - netif_start_queue(dev); - - e100_start_ru(bdp); - if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, - dev->name, dev)) != 0) { - del_timer_sync(&bdp->watchdog_timer); - goto err_exit; - } - bdp->intr_mask = 0; - e100_set_intr_mask(bdp); - - e100_force_config(bdp); - - goto exit; - -err_exit: - e100_clear_pools(bdp); -exit: - return rc; -} - -int -e100_close(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - e100_disable_clear_intr(bdp); - free_irq(dev->irq, dev); - bdp->intr_mask = SCB_INT_MASK; - e100_isolate_driver(bdp); - - netif_carrier_off(bdp->device); - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - e100_clear_pools(bdp); - - return 0; -} - -static int -e100_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) - return -EINVAL; - - dev->mtu = new_mtu; - return 0; -} - -static int -e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) -{ - int rc = 0; - int notify_stop = false; - struct e100_private *bdp = dev->priv; - - if (!spin_trylock(&bdp->bd_non_tx_lock)) { - notify_stop = true; - rc = 1; - goto exit2; - } - - /* tcb list may be empty temporarily during releasing resources */ - if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) || - (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { - notify_stop = true; - rc = 1; - goto exit1; - } - - bdp->drv_stats.net_stats.tx_bytes += skb->len; - - e100_prepare_xmit_buff(bdp, skb); - - dev->trans_start = jiffies; - -exit1: - spin_unlock(&bdp->bd_non_tx_lock); -exit2: - if (notify_stop) { - netif_stop_queue(dev); - } - - return rc; -} - -/** - * e100_get_stats - get driver statistics - * @dev: adapter's net_device struct - * - * This routine is called when the OS wants the adapter's stats returned. - * It returns the address of the net_device_stats stucture for the device. - * If the statistics are currently being updated, then they might be incorrect - * for a short while. However, since this cannot actually cause damage, no - * locking is used. - */ -struct net_device_stats * -e100_get_stats(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - bdp->drv_stats.net_stats.tx_errors = - bdp->drv_stats.net_stats.tx_carrier_errors + - bdp->drv_stats.net_stats.tx_aborted_errors; - - bdp->drv_stats.net_stats.rx_errors = - bdp->drv_stats.net_stats.rx_crc_errors + - bdp->drv_stats.net_stats.rx_frame_errors + - bdp->drv_stats.net_stats.rx_length_errors + - bdp->drv_stats.rcv_cdt_frames; - - return &(bdp->drv_stats.net_stats); -} - -/** - * e100_set_mac - set the MAC address - * @dev: adapter's net_device struct - * @addr: the new address - * - * This routine sets the ethernet address of the board - * Returns: - * 0 - if successful - * -1 - otherwise - */ -static int -e100_set_mac(struct net_device *dev, void *addr) -{ - struct e100_private *bdp; - int rc = -1; - struct sockaddr *p_sockaddr = (struct sockaddr *) addr; - - if (!is_valid_ether_addr(p_sockaddr->sa_data)) - return -EADDRNOTAVAIL; - bdp = dev->priv; - - if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) { - memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN); - rc = 0; - } - - return rc; -} - -static void -e100_set_multi_exec(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - mltcst_cb_t *mcast_buff; - cb_header_t *cb_hdr; - struct dev_mc_list *mc_list; - unsigned int i; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast); - cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr); - } else { - return; - } - - /* initialize the multi cast command */ - cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST); - - /* now fill in the rest of the multicast command */ - *(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6); - for (i = 0, mc_list = dev->mc_list; - (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS); - i++, mc_list = mc_list->next) { - /* copy into the command */ - memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]), - (u8 *) &(mc_list->dmi_addr), ETH_ALEN); - } - - if (!e100_exec_non_cu_cmd(bdp, cmd)) { - printk(KERN_WARNING "e100: %s: Multicast setup failed\n", - dev->name); - } -} - -/** - * e100_set_multi - set multicast status - * @dev: adapter's net_device struct - * - * This routine is called to add or remove multicast addresses, and/or to - * change the adapter's promiscuous state. - */ -static void -e100_set_multi(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - unsigned char promisc_enbl; - unsigned char mulcast_enbl; - - promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC); - mulcast_enbl = ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST_ADDRS)); - - e100_config_promisc(bdp, promisc_enbl); - e100_config_mulcast_enbl(bdp, mulcast_enbl); - - /* reconfigure the chip if something has changed in its config space */ - e100_config(bdp); - - if (promisc_enbl || mulcast_enbl) { - return; /* no need for Multicast Cmd */ - } - - /* get the multicast CB */ - e100_set_multi_exec(dev); -} - -static int -e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - - switch (cmd) { - - case SIOCETHTOOL: - return e100_do_ethtool_ioctl(dev, ifr); - break; - - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCSMIIREG: /* Write to MII PHY register. */ - return e100_mii_ioctl(dev, ifr, cmd); - break; - - default: - return -EOPNOTSUPP; - } - return 0; - -} - -/** - * e100init - initialize the adapter - * @bdp: atapter's private data struct - * - * This routine is called when this driver is loaded. This is the initialization - * routine which allocates memory, configures the adapter and determines the - * system resources. - * - * Returns: - * true: if successful - * false: otherwise - */ -static unsigned char -e100_init(struct e100_private *bdp) -{ - u32 st_timeout = 0; - u32 st_result = 0; - e100_sw_init(bdp); - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (st_timeout) { - printk(KERN_ERR "e100: selftest timeout\n"); - } else { - printk(KERN_ERR "e100: selftest failed. Results: %x\n", - st_result); - } - return false; - } - else - printk(KERN_DEBUG "e100: selftest OK.\n"); - - /* read the MAC address from the eprom */ - e100_rd_eaddr(bdp); - if (!is_valid_ether_addr(bdp->device->dev_addr)) { - printk(KERN_ERR "e100: Invalid Ethernet address\n"); - return false; - } - /* read NIC's part number */ - e100_rd_pwa_no(bdp); - - if (!e100_hw_init(bdp)) - return false; - /* Interrupts are enabled after device reset */ - e100_disable_clear_intr(bdp); - - return true; -} - -/** - * e100_sw_init - initialize software structs - * @bdp: atapter's private data struct - * - * This routine initializes all software structures. Sets up the - * circular structures for the RFD's & TCB's. Allocates the per board - * structure for storing adapter information. The CSR is also memory - * mapped in this routine. - * - * Returns : - * true: if S/W was successfully initialized - * false: otherwise - */ -static unsigned char -e100_sw_init(struct e100_private *bdp) -{ - bdp->next_cu_cmd = START_WAIT; // init the next cu state - - /* - * Set the value for # of good xmits per underrun. the value assigned - * here is an intelligent suggested default. Nothing magical about it. - */ - bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN; - - /* get the default transmit threshold value */ - bdp->tx_thld = TX_THRSHLD; - - /* get the EPROM size */ - bdp->eeprom_size = e100_eeprom_size(bdp); - - /* Initialize our spinlocks */ - spin_lock_init(&(bdp->bd_lock)); - spin_lock_init(&(bdp->bd_non_tx_lock)); - spin_lock_init(&(bdp->config_lock)); - spin_lock_init(&(bdp->mdi_access_lock)); - /* Initialize configuration data */ - e100_config_init(bdp); - - return 1; -} - -static void -e100_tco_workaround(struct e100_private *bdp) -{ - int i; - - /* Do software reset */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - - /* Do a dummy LOAD CU BASE command. */ - /* This gets us out of pre-driver to post-driver. */ - e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE); - - /* Wait 20 msec for reset to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 50 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset */ - e100_disable_clear_intr(bdp); - - /* Wait for command to be cleared up to 1 sec */ - for (i=0; i<100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } - - /* Wait for TCO request bit in PMDR register to be clear */ - for (i=0; i<50; i++) { - if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } -} - -/** - * e100_hw_init - initialized tthe hardware - * @bdp: atapter's private data struct - * - * This routine performs a reset on the adapter, and configures the adapter. - * This includes configuring the 82557 LAN controller, validating and setting - * the node address, detecting and configuring the Phy chip on the adapter, - * and initializing all of the on chip counters. - * - * Returns: - * true - If the adapter was initialized - * false - If the adapter failed initialization - */ -unsigned char -e100_hw_init(struct e100_private *bdp) -{ - if (!e100_phy_init(bdp)) - goto err; - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - /* Only 82559 or above needs TCO workaround */ - if (bdp->rev_id >= D101MA_REV_ID) - e100_tco_workaround(bdp); - - /* Load the CU BASE (set to 0, because we use linear mode) */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - goto err; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - goto err; - - /* Load interrupt microcode */ - if (e100_load_microcode(bdp)) { - bdp->flags |= DF_UCODE_LOADED; - } - - if ((u8) bdp->rev_id < D101A4_REV_ID) - e100_config_init_82557(bdp); - - if (!e100_config(bdp)) - goto err; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) - goto err; - - /* Clear the internal counters */ - if (!e100_clr_cntrs(bdp)) - goto err; - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up the - * Flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - return true; -err: - printk(KERN_ERR "e100: hw init failed\n"); - return false; -} - -/** - * e100_setup_tcb_pool - setup TCB circular list - * @head: Pointer to head of the allocated TCBs - * @qlen: Number of elements in the queue - * @bdp: atapter's private data struct - * - * This routine arranges the contigiously allocated TCB's in a circular list. - * Also does the one time initialization of the TCBs. - */ -static void -e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp) -{ - int ele_no; - tcb_t *pcurr_tcb; /* point to current tcb */ - u32 next_phys; /* the next phys addr */ - u16 txcommand = CB_S_BIT | CB_TX_SF_BIT; - - bdp->tx_count = 0; - if (bdp->flags & USE_IPCB) { - txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT; - } else if (bdp->flags & IS_BACHELOR) { - txcommand |= CB_TRANSMIT | CB_CID_DEFAULT; - } else { - txcommand |= CB_TRANSMIT; - } - - for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head; - ele_no < qlen; ele_no++, pcurr_tcb++) { - - /* set the phys addr for this TCB, next_phys has not incr. yet */ - pcurr_tcb->tcb_phys = next_phys; - next_phys += sizeof (tcb_t); - - /* set the link to next tcb */ - if (ele_no == (qlen - 1)) - pcurr_tcb->tcb_hdr.cb_lnk_ptr = - cpu_to_le32(bdp->tcb_phys); - else - pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys); - - pcurr_tcb->tcb_hdr.cb_status = 0; - pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand); - pcurr_tcb->tcb_cnt = 0; - pcurr_tcb->tcb_thrshld = bdp->tx_thld; - if (ele_no < 2) { - pcurr_tcb->tcb_hdr.cb_status = - cpu_to_le16(CB_STATUS_COMPLETE); - } - pcurr_tcb->tcb_tbd_num = 1; - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_ptr = - __constant_cpu_to_le32(0xFFFFFFFF); - } else { - pcurr_tcb->tcb_tbd_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x20); - } else { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr; - - if (bdp->flags & USE_IPCB) { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]); - pcurr_tcb->tcbu.ipcb.ip_activation_high = - IPCB_IP_ACTIVATION_DEFAULT; - pcurr_tcb->tcbu.ipcb.vlan = 0; - } else { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]); - } - - pcurr_tcb->tcb_skb = NULL; - } - - wmb(); -} - -/***************************************************************************/ -/***************************************************************************/ -/* Memory Management Routines */ -/***************************************************************************/ - -/** - * e100_alloc_space - allocate private driver data - * @bdp: atapter's private data struct - * - * This routine allocates memory for the driver. Memory allocated is for the - * selftest and statistics structures. - * - * Returns: - * 0: if the operation was successful - * %-ENOMEM: if memory allocation failed - */ -unsigned char -e100_alloc_space(struct e100_private *bdp) -{ - unsigned long off; - - /* allocate all the dma-able structures in one call: - * selftest results, adapter stats, and non-tx cb commands */ - if (!(bdp->dma_able = - pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t), - &(bdp->dma_able_phys)))) { - goto err; - } - - /* now assign the various pointers into the struct we've just allocated */ - off = offsetof(bd_dma_able_t, selftest); - - bdp->selftest = (self_test_t *) (bdp->dma_able + off); - bdp->selftest_phys = bdp->dma_able_phys + off; - - off = offsetof(bd_dma_able_t, stats_counters); - - bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off); - bdp->stat_cnt_phys = bdp->dma_able_phys + off; - - return 0; - -err: - printk(KERN_ERR - "e100: Failed to allocate memory\n"); - return -ENOMEM; -} - -/** - * e100_alloc_tcb_pool - allocate TCB circular list - * @bdp: atapter's private data struct - * - * This routine allocates memory for the circular list of transmit descriptors. - * - * Returns: - * 0: if allocation has failed. - * 1: Otherwise. - */ -int -e100_alloc_tcb_pool(struct e100_private *bdp) -{ - int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors; - - /* allocate space for the TCBs */ - if (!(bdp->tcb_pool.data = - pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys))) - return 0; - - memset(bdp->tcb_pool.data, 0x00, stcb); - - return 1; -} - -void -e100_free_tcb_pool(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - /* Return tx skbs */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - e100_tx_skb_free(bdp, tcb); - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) - break; - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) * bdp->params.TxDescriptors, - bdp->tcb_pool.data, bdp->tcb_phys); - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - bdp->tcb_phys = 0; -} - -static void -e100_dealloc_space(struct e100_private *bdp) -{ - if (bdp->dma_able) { - pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t), - bdp->dma_able, bdp->dma_able_phys); - } - - bdp->selftest_phys = 0; - bdp->stat_cnt_phys = 0; - bdp->dma_able_phys = 0; - bdp->dma_able = 0; -} - -static void -e100_free_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - - while (!list_empty(&(bdp->active_rx_list))) { - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_TODEVICE); - dev_kfree_skb(rx_struct->skb); - kfree(rx_struct); - } - - while (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - kfree(rx_struct); - } -} - -/** - * e100_alloc_rfd_pool - allocate RFDs - * @bdp: atapter's private data struct - * - * Allocates initial pool of skb which holds both rfd and data, - * and return a pointer to the head of the list - */ -static int -e100_alloc_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - int i; - - INIT_LIST_HEAD(&(bdp->active_rx_list)); - INIT_LIST_HEAD(&(bdp->rx_struct_pool)); - bdp->skb_req = bdp->params.RxDescriptors; - for (i = 0; i < bdp->skb_req; i++) { - rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC); - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - } - e100_alloc_skbs(bdp); - return !list_empty(&(bdp->active_rx_list)); - -} - -void -e100_clear_pools(struct e100_private *bdp) -{ - bdp->last_tcb = NULL; - e100_free_rfd_pool(bdp); - e100_free_tcb_pool(bdp); -} - -/*****************************************************************************/ -/*****************************************************************************/ -/* Run Time Functions */ -/*****************************************************************************/ - -/** - * e100_watchdog - * @dev: adapter's net_device struct - * - * This routine runs every 2 seconds and updates our statitics and link state, - * and refreshs txthld value. - */ -void -e100_watchdog(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - -#ifdef E100_CU_DEBUG - if (e100_cu_unknown_state(bdp)) { - printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n", - dev->name); - } -#endif - if (!netif_running(dev)) { - return; - } - - /* check if link state has changed */ - if (e100_phy_check(bdp)) { - if (netif_carrier_ok(dev)) { - printk(KERN_ERR - "e100: %s NIC Link is Up %d Mbps %s duplex\n", - bdp->device->name, bdp->cur_line_speed, - (bdp->cur_dplx_mode == HALF_DUPLEX) ? - "Half" : "Full"); - - e100_config_fc(bdp); - e100_config(bdp); - - } else { - printk(KERN_ERR "e100: %s NIC Link is Down\n", - bdp->device->name); - } - } - - // toggle the tx queue according to link status - // this also resolves a race condition between tx & non-cu cmd flows - if (netif_carrier_ok(dev)) { - if (netif_running(dev)) - netif_wake_queue(dev); - } else { - if (netif_running(dev)) - netif_stop_queue(dev); - /* When changing to non-autoneg, device may lose */ - /* link with some switches. e100 will try to */ - /* revover link by sending command to PHY layer */ - if (bdp->params.e100_speed_duplex != E100_AUTONEG) - e100_force_speed_duplex_to_phy(bdp); - } - - rmb(); - - if (e100_update_stats(bdp)) { - - /* Check if a change in the IFS parameter is needed, - and configure the device accordingly */ - if (bdp->params.b_params & PRM_IFS) - e100_manage_adaptive_ifs(bdp); - - /* Now adjust our dynamic tx threshold value */ - e100_refresh_txthld(bdp); - - /* Now if we are on a 557 and we havn't received any frames then we - * should issue a multicast command to reset the RU */ - if (bdp->rev_id < D101A4_REV_ID) { - if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) { - e100_set_multi(dev); - } - } - } - /* Issue command to dump statistics from device. */ - /* Check for command completion on next watchdog timer. */ - e100_dump_stats_cntrs(bdp); - - wmb(); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (list_empty(&bdp->active_rx_list)) - e100_trigger_SWI(bdp); -} - -/** - * e100_manage_adaptive_ifs - * @bdp: atapter's private data struct - * - * This routine manages the adaptive Inter-Frame Spacing algorithm - * using a state machine. - */ -void -e100_manage_adaptive_ifs(struct e100_private *bdp) -{ - static u16 state_table[9][4] = { // rows are states - {2, 0, 0, 0}, // state0 // column0: next state if increasing - {2, 0, 5, 30}, // state1 // column1: next state if decreasing - {5, 1, 5, 30}, // state2 // column2: IFS value for 100 mbit - {5, 3, 0, 0}, // state3 // column3: IFS value for 10 mbit - {5, 3, 10, 60}, // state4 - {8, 4, 10, 60}, // state5 - {8, 6, 0, 0}, // state6 - {8, 6, 20, 60}, // state7 - {8, 7, 20, 60} // state8 - }; - - u32 transmits = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames); - u32 collisions = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll); - u32 state = bdp->ifs_state; - u32 old_value = bdp->ifs_value; - int next_col; - u32 min_transmits; - - if (bdp->cur_dplx_mode == FULL_DUPLEX) { - bdp->ifs_state = 0; - bdp->ifs_value = 0; - - } else { /* Half Duplex */ - /* Set speed specific parameters */ - if (bdp->cur_line_speed == 100) { - next_col = 2; - min_transmits = MIN_NUMBER_OF_TRANSMITS_100; - - } else { /* 10 Mbps */ - next_col = 3; - min_transmits = MIN_NUMBER_OF_TRANSMITS_10; - } - - if ((transmits / 32 < collisions) - && (transmits > min_transmits)) { - state = state_table[state][0]; /* increment */ - - } else if (transmits < min_transmits) { - state = state_table[state][1]; /* decrement */ - } - - bdp->ifs_value = state_table[state][next_col]; - bdp->ifs_state = state; - } - - /* If the IFS value has changed, configure the device */ - if (bdp->ifs_value != old_value) { - e100_config_ifs(bdp); - e100_config(bdp); - } -} - -/** - * e100intr - interrupt handler - * @irq: the IRQ number - * @dev_inst: the net_device struct - * @regs: registers (unused) - * - * This routine is the ISR for the e100 board. It services - * the RX & TX queues & starts the RU if it has stopped due - * to no resources. - */ -irqreturn_t -e100intr(int irq, void *dev_inst, struct pt_regs *regs) -{ - struct net_device *dev; - struct e100_private *bdp; - u16 intr_status; - - dev = dev_inst; - bdp = dev->priv; - - intr_status = readw(&bdp->scb->scb_status); - /* If not my interrupt, just return */ - if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) { - return IRQ_NONE; - } - - /* disable and ack intr */ - e100_disable_clear_intr(bdp); - - /* the device is closed, don't continue or else bad things may happen. */ - if (!netif_running(dev)) { - e100_set_intr_mask(bdp); - return IRQ_NONE; - } - - /* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */ - if (intr_status & SCB_STATUS_ACK_SWI) { - e100_alloc_skbs(bdp); - } - - /* do recv work if any */ - if (intr_status & - (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) - bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp); - - /* clean up after tx'ed packets */ - if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) - e100_tx_srv(bdp); - - e100_set_intr_mask(bdp); - return IRQ_HANDLED; -} - -/** - * e100_tx_skb_free - free TX skbs resources - * @bdp: atapter's private data struct - * @tcb: associated tcb of the freed skb - * - * This routine frees resources of TX skbs. - */ -static inline void -e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb) -{ - if (tcb->tcb_skb) { - int i; - tbd_t *tbd_arr = tcb->tbd_ptr; - int frags = skb_shinfo(tcb->tcb_skb)->nr_frags; - - for (i = 0; i <= frags; i++, tbd_arr++) { - pci_unmap_single(bdp->pdev, - le32_to_cpu(tbd_arr->tbd_buf_addr), - le16_to_cpu(tbd_arr->tbd_buf_cnt), - PCI_DMA_TODEVICE); - } - dev_kfree_skb_irq(tcb->tcb_skb); - tcb->tcb_skb = NULL; - } -} - -/** - * e100_tx_srv - service TX queues - * @bdp: atapter's private data struct - * - * This routine services the TX queues. It reclaims the TCB's & TBD's & other - * resources used during the transmit of this buffer. It is called from the ISR. - * We don't need a tx_lock since we always access buffers which were already - * prepared. - */ -void -e100_tx_srv(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - - /* go over at most TxDescriptors buffers */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - - rmb(); - - /* if the buffer at 'head' is not complete, break */ - if (!(tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - break; - - /* service next buffer, clear the out of resource condition */ - e100_tx_skb_free(bdp, tcb); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - /* if we've caught up with 'tail', break */ - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) { - break; - } - - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } -} - -/** - * e100_rx_srv - service RX queue - * @bdp: atapter's private data struct - * @max_number_of_rfds: max number of RFDs to process - * @rx_congestion: flag pointer, to inform the calling function of congestion. - * - * This routine processes the RX interrupt & services the RX queues. - * For each successful RFD, it allocates a new msg block, links that - * into the RFD list, and sends the old msg upstream. - * The new RFD is then put at the end of the free list of RFD's. - * It returns the number of serviced RFDs. - */ -u32 -e100_rx_srv(struct e100_private *bdp) -{ - rfd_t *rfd; /* new rfd, received rfd */ - int i; - u16 rfd_status; - struct sk_buff *skb; - struct net_device *dev; - unsigned int data_sz; - struct rx_list_elem *rx_struct; - u32 rfd_cnt = 0; - - dev = bdp->device; - - /* current design of rx is as following: - * 1. socket buffer (skb) used to pass network packet to upper layer - * 2. all HW host memory structures (like RFDs, RBDs and data buffers) - * are placed in a skb's data room - * 3. when rx process is complete, we change skb internal pointers to exclude - * from data area all unrelated things (RFD, RDB) and to leave - * just rx'ed packet netto - * 4. for each skb passed to upper layer, new one is allocated instead. - * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made - * (watchdog trigger SWI intr and isr should allocate new skbs) - */ - for (i = 0; i < bdp->params.RxDescriptors; i++) { - if (list_empty(&(bdp->active_rx_list))) { - break; - } - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - skb = rx_struct->skb; - - rfd = RFD_POINTER(skb, bdp); /* locate RFD within skb */ - - // sync only the RFD header - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - rfd_status = le16_to_cpu(rfd->rfd_header.cb_status); /* get RFD's status */ - if (!(rfd_status & RFD_STATUS_COMPLETE)) /* does not contains data yet - exit */ - break; - - /* to allow manipulation with current skb we need to unlink it */ - list_del(&(rx_struct->list_elem)); - - /* do not free & unmap badly received packet. - * move it to the end of skb list for reuse */ - if (!(rfd_status & RFD_STATUS_OK)) { - e100_add_skb_to_end(bdp, rx_struct); - continue; - } - - data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff), - (sizeof (rfd_t) - bdp->rfd_size)); - - /* now sync all the data */ - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - (data_sz + bdp->rfd_size), - PCI_DMA_FROMDEVICE); - - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_FROMDEVICE); - - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - - /* end of dma access to rfd */ - bdp->skb_req++; /* incr number of requested skbs */ - e100_alloc_skbs(bdp); /* and get them */ - - /* set packet size, excluding checksum (2 last bytes) if it is present */ - if ((bdp->flags & DF_CSUM_OFFLOAD) - && (bdp->rev_id < D102_REV_ID)) - skb_put(skb, (int) data_sz - 2); - else - skb_put(skb, (int) data_sz); - - /* set the protocol */ - skb->protocol = eth_type_trans(skb, dev); - - /* set the checksum info */ - if (bdp->flags & DF_CSUM_OFFLOAD) { - if (bdp->rev_id >= D102_REV_ID) { - skb->ip_summed = e100_D102_check_checksum(rfd); - } else { - skb->ip_summed = e100_D101M_checksum(bdp, skb); - } - } else { - skb->ip_summed = CHECKSUM_NONE; - } - - bdp->drv_stats.net_stats.rx_bytes += skb->len; - - if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) { - vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid)); - } else { - netif_rx(skb); - } - dev->last_rx = jiffies; - - rfd_cnt++; - } /* end of rfd loop */ - - /* restart the RU if it has stopped */ - if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) { - e100_start_ru(bdp); - } - - return rfd_cnt; -} - -void -e100_refresh_txthld(struct e100_private *bdp) -{ - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - /* as long as tx_per_underrun is not 0, we can go about dynamically * - * adjusting the xmit threshold. we stop doing that & resort to defaults - * * once the adjustments become meaningless. the value is adjusted by * - * dumping the error counters & checking the # of xmit underrun errors * - * we've had. */ - if (bdp->tx_per_underrun) { - /* We are going to last values dumped from the dump statistics - * command */ - if (le32_to_cpu(pstat->xmt_gd_frames)) { - if (le32_to_cpu(pstat->xmt_uruns)) { - /* - * if we have had more than one underrun per "DEFAULT # - * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the - * THRESHOLD. - */ - if ((le32_to_cpu(pstat->xmt_gd_frames) / - le32_to_cpu(pstat->xmt_uruns)) < - bdp->tx_per_underrun) { - bdp->tx_thld += 3; - } - } - - /* - * if we've had less than one underrun per the DEFAULT number of - * of good xmits allowed, lower the THOLD but not less than 0 - */ - if (le32_to_cpu(pstat->xmt_gd_frames) > - bdp->tx_per_underrun) { - bdp->tx_thld--; - - if (bdp->tx_thld < 6) - bdp->tx_thld = 6; - - } - } - - /* end good xmits */ - /* - * * if our adjustments are becoming unresonable, stop adjusting & - * resort * to defaults & pray. A THOLD value > 190 means that the - * adapter will * wait for 190*8=1520 bytes in TX FIFO before it - * starts xmit. Since * MTU is 1514, it doesn't make any sense for - * further increase. */ - if (bdp->tx_thld >= 190) { - bdp->tx_per_underrun = 0; - bdp->tx_thld = 189; - } - } /* end underrun check */ -} - -/** - * e100_prepare_xmit_buff - prepare a buffer for transmission - * @bdp: atapter's private data struct - * @skb: skb to send - * - * This routine prepare a buffer for transmission. It checks - * the message length for the appropiate size. It picks up a - * free tcb from the TCB pool and sets up the corresponding - * TBD's. If the number of fragments are more than the number - * of TBD/TCB it copies all the fragments in a coalesce buffer. - * It returns a pointer to the prepared TCB. - */ -static inline tcb_t * -e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) -{ - tcb_t *tcb, *prev_tcb; - - tcb = bdp->tcb_pool.data; - tcb += TCB_TO_USE(bdp->tcb_pool); - - if (bdp->flags & USE_IPCB) { - tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; - } - - if(bdp->vlgrp && vlan_tx_tag_present(skb)) { - (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; - (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); - } - - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); - - /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */ - if (!(++bdp->tx_count % TX_FRAME_CNT)) - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT); - else - /* Clear I bit on other packets */ - tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT); - - tcb->tcb_skb = skb; - - if (skb->ip_summed == CHECKSUM_HW) { - const struct iphdr *ip = skb->nh.iph; - - if ((ip->protocol == IPPROTO_TCP) || - (ip->protocol == IPPROTO_UDP)) { - - tcb->tcbu.ipcb.ip_activation_high |= - IPCB_HARDWAREPARSING_ENABLE; - tcb->tcbu.ipcb.ip_schedule |= - IPCB_TCPUDP_CHECKSUM_ENABLE; - - if (ip->protocol == IPPROTO_TCP) - tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET; - } - } - - if (!skb_shinfo(skb)->nr_frags) { - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len); - tcb->tcb_tbd_num = 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr; - } else { - int i; - void *addr; - tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]); - skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; - - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb_headlen(skb), - PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = - cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; - i++, tbd_arr_ptr++, frag++) { - - addr = ((void *) page_address(frag->page) + - frag->page_offset); - - tbd_arr_ptr->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, - addr, frag->size, - PCI_DMA_TODEVICE)); - tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size); - } - tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr; - } - - /* clear the S-BIT on the previous tcb */ - prev_tcb = bdp->tcb_pool.data; - prev_tcb += PREV_TCB_USED(bdp->tcb_pool); - prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT); - - bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail); - - wmb(); - - e100_start_cu(bdp, tcb); - - return tcb; -} - -/* Changed for 82558 enhancement */ -/** - * e100_start_cu - start the adapter's CU - * @bdp: atapter's private data struct - * @tcb: TCB to be transmitted - * - * This routine issues a CU Start or CU Resume command to the 82558/9. - * This routine was added because the prepare_ext_xmit_buff takes advantage - * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as - * soon as the first TBD is ready. - * - * e100_start_cu must be called while holding the tx_lock ! - */ -u8 -e100_start_cu(struct e100_private *bdp, tcb_t *tcb) -{ - unsigned long lock_flag; - u8 ret = true; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag); - switch (bdp->next_cu_cmd) { - case RESUME_NO_WAIT: - /*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to - * wait for command word to clear, we reach here only if we are bachlor - */ - e100_exec_cmd(bdp, SCB_CUC_RESUME); - break; - - case RESUME_WAIT: - if ((bdp->flags & IS_ICH) && - (bdp->cur_line_speed == 10) && - (bdp->cur_dplx_mode == HALF_DUPLEX)) { - e100_wait_exec_simple(bdp, SCB_CUC_NOOP); - udelay(1); - } - if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) && - (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) { - bdp->next_cu_cmd = RESUME_NO_WAIT; - } - break; - - case START_WAIT: - // The last command was a non_tx CU command - if (!e100_wait_cus_idle(bdp)) - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for cu\n", - bdp->device->name); - if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START, CB_TRANSMIT)) { - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for scb\n", - bdp->device->name); - e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START); - ret = false; - } - - bdp->next_cu_cmd = RESUME_WAIT; - - break; - } - - /* save the last tcb */ - bdp->last_tcb = tcb; - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - return ret; -} - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/** - * e100_selftest - perform H/W self test - * @bdp: atapter's private data struct - * @st_timeout: address to return timeout value, if fails - * @st_result: address to return selftest result, if fails - * - * This routine will issue PORT Self-test command to test the e100. - * The self-test will fail if the adapter's master-enable bit is not - * set in the PCI Command Register, or if the adapter is not seated - * in a PCI master-enabled slot. we also disable interrupts when the - * command is completed. - * - * Returns: - * true: if adapter passes self_test - * false: otherwise - */ -unsigned char -e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result) -{ - u32 selftest_cmd; - - /* initialize the nic state before running test */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - /* Setup the address of the self_test area */ - selftest_cmd = bdp->selftest_phys; - - /* Setup SELF TEST Command Code in D3 - D0 */ - selftest_cmd |= PORT_SELFTEST; - - /* Initialize the self-test signature and results DWORDS */ - bdp->selftest->st_sign = 0; - bdp->selftest->st_result = 0xffffffff; - - /* Do the port command */ - writel(selftest_cmd, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* Wait at least 10 milliseconds for the self-test to complete */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset during selftest */ - e100_disable_clear_intr(bdp); - - /* if The First Self Test DWORD Still Zero, We've timed out. If the - * second DWORD is not zero then we have an error. */ - if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) { - - if (st_timeout) - *st_timeout = !(le32_to_cpu(bdp->selftest->st_sign)); - - if (st_result) - *st_result = le32_to_cpu(bdp->selftest->st_result); - - return false; - } - - return true; -} - -/** - * e100_setup_iaaddr - issue IA setup sommand - * @bdp: atapter's private data struct - * @eaddr: new ethernet address - * - * This routine will issue the IA setup command. This command - * will notify the 82557 (e100) of what its individual (node) - * address is. This command will be executed in polled mode. - * - * Returns: - * true: if the IA setup command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr) -{ - unsigned int i; - cb_header_t *ntcb_hdr; - unsigned char res; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS); - - for (i = 0; i < ETH_ALEN; i++) { - (cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i]; - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: IA setup failed\n", - bdp->device->name); - -exit: - return res; -} - -/** - * e100_start_ru - start the RU if needed - * @bdp: atapter's private data struct - * - * This routine checks the status of the 82557's receive unit(RU), - * and starts the RU if it was not already active. However, - * before restarting the RU, the driver gives the RU the buffers - * it freed up during the servicing of the ISR. If there are - * no free buffers to give to the RU, (i.e. we have reached a - * no resource condition) the RU will not be started till the - * next ISR. - */ -void -e100_start_ru(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; - int buffer_found = 0; - struct list_head *entry_ptr; - - list_for_each(entry_ptr, &(bdp->active_rx_list)) { - rx_struct = - list_entry(entry_ptr, struct rx_list_elem, list_elem); - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) & - __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) { - buffer_found = 1; - break; - } - } - - /* No available buffers */ - if (!buffer_found) { - return; - } - - spin_lock(&bdp->bd_lock); - - if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) { - printk(KERN_DEBUG - "e100: %s: start_ru: wait_scb failed\n", - bdp->device->name); - e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START); - } - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - spin_unlock(&bdp->bd_lock); -} - -/** - * e100_cmd_complete_location - * @bdp: atapter's private data struct - * - * This routine returns a pointer to the location of the command-complete - * DWord in the dump statistical counters area, according to the statistical - * counters mode (557 - basic, 558 - extended, or 559 - TCO mode). - * See e100_config_init() for the setting of the statistical counters mode. - */ -static u32 * -e100_cmd_complete_location(struct e100_private *bdp) -{ - u32 *cmd_complete; - max_counters_t *stats = bdp->stats_counters; - - switch (bdp->stat_mode) { - case E100_EXTENDED_STATS: - cmd_complete = - (u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete); - break; - - case E100_TCO_STATS: - cmd_complete = - (u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete); - break; - - case E100_BASIC_STATS: - default: - cmd_complete = - (u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete); - break; - } - - return cmd_complete; -} - -/** - * e100_clr_cntrs - clear statistics counters - * @bdp: atapter's private data struct - * - * This routine will clear the adapter error statistic counters. - * - * Returns: - * true: if successfully cleared stat counters - * false: otherwise - */ -static unsigned char -e100_clr_cntrs(struct e100_private *bdp) -{ - volatile u32 *pcmd_complete; - - /* clear the dump counter complete word */ - pcmd_complete = e100_cmd_complete_location(bdp); - *pcmd_complete = 0; - wmb(); - - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; - - /* wait 10 microseconds for the command to complete */ - udelay(10); - - if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) - return false; - - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - - return true; -} - -static unsigned char -e100_update_stats(struct e100_private *bdp) -{ - u32 *pcmd_complete; - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - // check if last dump command completed - pcmd_complete = e100_cmd_complete_location(bdp); - if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) && - *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) { - *pcmd_complete = 0; - return false; - } - - /* increment the statistics */ - bdp->drv_stats.net_stats.rx_packets += - le32_to_cpu(pstat->rcv_gd_frames); - bdp->drv_stats.net_stats.tx_packets += - le32_to_cpu(pstat->xmt_gd_frames); - bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll); - bdp->drv_stats.net_stats.rx_length_errors += - le32_to_cpu(pstat->rcv_shrt_frames); - bdp->drv_stats.net_stats.rx_over_errors += - le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.rx_crc_errors += - le32_to_cpu(pstat->rcv_crc_errs); - bdp->drv_stats.net_stats.rx_frame_errors += - le32_to_cpu(pstat->rcv_algn_errs); - bdp->drv_stats.net_stats.rx_fifo_errors += - le32_to_cpu(pstat->rcv_oruns); - bdp->drv_stats.net_stats.tx_aborted_errors += - le32_to_cpu(pstat->xmt_max_coll); - bdp->drv_stats.net_stats.tx_carrier_errors += - le32_to_cpu(pstat->xmt_lost_crs); - bdp->drv_stats.net_stats.tx_fifo_errors += - le32_to_cpu(pstat->xmt_uruns); - - bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll); - bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred); - bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll); - bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll); - bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll); - - if (bdp->stat_mode != E100_BASIC_STATS) { - ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats; - - bdp->drv_stats.xmt_fc_pkts += - le32_to_cpu(pex_stat->xmt_fc_frames); - bdp->drv_stats.rcv_fc_pkts += - le32_to_cpu(pex_stat->rcv_fc_frames); - bdp->drv_stats.rcv_fc_unsupported += - le32_to_cpu(pex_stat->rcv_fc_unsupported); - } - - if (bdp->stat_mode == E100_TCO_STATS) { - tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats; - - bdp->drv_stats.xmt_tco_pkts += - le16_to_cpu(ptco_stat->xmt_tco_frames); - bdp->drv_stats.rcv_tco_pkts += - le16_to_cpu(ptco_stat->rcv_tco_frames); - } - - *pcmd_complete = 0; - return true; -} - -/** - * e100_dump_stat_cntrs - * @bdp: atapter's private data struct - * - * This routine will dump the board statistical counters without waiting - * for stat_dump to complete. Any access to this stats should verify the completion - * of the command - */ -void -e100_dump_stats_cntrs(struct e100_private *bdp) -{ - unsigned long lock_flag_bd; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd); - - /* dump h/w stats counters */ - if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) { - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - } - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd); -} - -/** - * e100_exec_non_cu_cmd - * @bdp: atapter's private data struct - * @command: the non-cu command to execute - * - * This routine will submit a command block to be executed, - */ -unsigned char -e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) -{ - cb_header_t *ntcb_hdr; - unsigned long lock_flag; - unsigned long expiration_time; - unsigned char rc = true; - u8 sub_cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */ - sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd); - - /* Set the Command Block to be the last command block */ - ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT); - ntcb_hdr->cb_status = 0; - ntcb_hdr->cb_lnk_ptr = 0; - - wmb(); - if (in_interrupt()) - return e100_delayed_exec_non_cu_cmd(bdp, command); - - if (netif_running(bdp->device) && netif_carrier_ok(bdp->device)) - return e100_delayed_exec_non_cu_cmd(bdp, command); - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - goto delayed_exec; - } - - if (bdp->last_tcb) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto delayed_exec; - } - - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) { - goto delayed_exec; - } - - spin_lock_irqsave(&bdp->bd_lock, lock_flag); - - if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) { - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - rc = false; - goto exit; - } - - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - - /* now wait for completion of non-cu CB up to 20 msec */ - expiration_time = jiffies + HZ / 50 + 1; - rmb(); - while (!(ntcb_hdr->cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) { - - if (time_before(jiffies, expiration_time)) { - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - yield(); - spin_lock_bh(&(bdp->bd_non_tx_lock)); - } else { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: non-TX command (%x) " - "timeout\n", bdp->device->name, sub_cmd); -#endif - rc = false; - goto exit; - } - rmb(); - } - -exit: - e100_free_non_tx_cmd(bdp, command); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return rc; - -delayed_exec: - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return e100_delayed_exec_non_cu_cmd(bdp, command); -} - -/** - * e100_sw_reset - * @bdp: atapter's private data struct - * @reset_cmd: s/w reset or selective reset - * - * This routine will issue a software reset to the adapter. It - * will also disable interrupts, as the are enabled after reset. - */ -void -e100_sw_reset(struct e100_private *bdp, u32 reset_cmd) -{ - /* Do a selective reset first to avoid a potential PCI hang */ - writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* wait for the reset to take effect */ - udelay(20); - if (reset_cmd == PORT_SOFTWARE_RESET) { - writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port); - - /* wait 20 micro seconds for the reset to take effect */ - udelay(20); - } - - /* Mask off our interrupt line -- it is unmasked after reset */ - e100_disable_clear_intr(bdp); -#ifdef E100_CU_DEBUG - bdp->last_cmd = 0; - bdp->last_sub_cmd = 0; -#endif -} - -/** - * e100_load_microcode - Download microsocde to controller. - * @bdp: atapter's private data struct - * - * This routine downloads microcode on to the controller. This - * microcode is available for the 82558/9, 82550. Currently the - * microcode handles interrupt bundling and TCO workaround. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_load_microcode(struct e100_private *bdp) -{ - static struct { - u8 rev_id; - u32 ucode[UCODE_MAX_DWORDS + 1]; - int timer_dword; - int bundle_dword; - int min_size_dword; - } ucode_opts[] = { - { D101A4_REV_ID, - D101_A_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101B0_REV_ID, - D101_B0_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101MA_REV_ID, - D101M_B_RCVBUNDLE_UCODE, - D101M_CPUSAVER_TIMER_DWORD, - D101M_CPUSAVER_BUNDLE_DWORD, - D101M_CPUSAVER_MIN_SIZE_DWORD }, - { D101S_REV_ID, - D101S_RCVBUNDLE_UCODE, - D101S_CPUSAVER_TIMER_DWORD, - D101S_CPUSAVER_BUNDLE_DWORD, - D101S_CPUSAVER_MIN_SIZE_DWORD }, - { D102_REV_ID, - D102_B_RCVBUNDLE_UCODE, - D102_B_CPUSAVER_TIMER_DWORD, - D102_B_CPUSAVER_BUNDLE_DWORD, - D102_B_CPUSAVER_MIN_SIZE_DWORD }, - { D102C_REV_ID, - D102_C_RCVBUNDLE_UCODE, - D102_C_CPUSAVER_TIMER_DWORD, - D102_C_CPUSAVER_BUNDLE_DWORD, - D102_C_CPUSAVER_MIN_SIZE_DWORD }, - { D102E_REV_ID, - D102_E_RCVBUNDLE_UCODE, - D102_E_CPUSAVER_TIMER_DWORD, - D102_E_CPUSAVER_BUNDLE_DWORD, - D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { 0, {0}, 0, 0, 0} - }, *opts; - - opts = ucode_opts; - - /* User turned ucode loading off */ - if (!(bdp->params.b_params & PRM_UCODE)) - return false; - - /* These controllers do not need ucode */ - if (bdp->flags & IS_ICH) - return false; - - /* Search for ucode match against h/w rev_id */ - while (opts->rev_id) { - if (bdp->rev_id == opts->rev_id) { - int i; - u32 *ucode_dword; - load_ucode_cb_t *ucode_cmd_ptr; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - ucode_cmd_ptr = - (load_ucode_cb_t *) cmd->non_tx_cmd; - ucode_dword = ucode_cmd_ptr->ucode_dword; - } else { - return false; - } - - memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode)); - - /* Insert user-tunable settings */ - ucode_dword[opts->timer_dword] &= 0xFFFF0000; - ucode_dword[opts->timer_dword] |= - (u16) bdp->params.IntDelay; - ucode_dword[opts->bundle_dword] &= 0xFFFF0000; - ucode_dword[opts->bundle_dword] |= - (u16) bdp->params.BundleMax; - ucode_dword[opts->min_size_dword] &= 0xFFFF0000; - ucode_dword[opts->min_size_dword] |= - (bdp->params.b_params & PRM_BUNDLE_SMALL) ? - 0xFFFF : 0xFF80; - - for (i = 0; i < UCODE_MAX_DWORDS; i++) - cpu_to_le32s(&(ucode_dword[i])); - - ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd = - __constant_cpu_to_le16(CB_LOAD_MICROCODE); - - return e100_exec_non_cu_cmd(bdp, cmd); - } - opts++; - } - - return false; -} - -/***************************************************************************/ -/***************************************************************************/ -/* EEPROM Functions */ -/***************************************************************************/ - -/* Read PWA (printed wired assembly) number */ -void -e100_rd_pwa_no(struct e100_private *bdp) -{ - bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO); - bdp->pwa_no <<= 16; - bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1); -} - -/* Read the permanent ethernet address from the eprom. */ -void -e100_rd_eaddr(struct e100_private *bdp) -{ - int i; - u16 eeprom_word; - - for (i = 0; i < 6; i += 2) { - eeprom_word = - e100_eeprom_read(bdp, - EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); - - bdp->device->dev_addr[i] = - bdp->perm_node_address[i] = (u8) eeprom_word; - bdp->device->dev_addr[i + 1] = - bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8); - } -} - -/* Check the D102 RFD flags to see if the checksum passed */ -static unsigned char -e100_D102_check_checksum(rfd_t *rfd) -{ - if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT) - && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_TCP_PACKET) - || ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_UDP_PACKET)) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) { - return CHECKSUM_UNNECESSARY; - } - return CHECKSUM_NONE; -} - -/** - * e100_D101M_checksum - * @bdp: atapter's private data struct - * @skb: skb received - * - * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The - * D101M sums all words in frame excluding the ethernet II header (14 bytes) so - * in case the packet is ethernet II and the protocol is IP, all is need is to - * assign this value to skb->csum. - */ -static unsigned char -e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb) -{ - unsigned short proto = (skb->protocol); - - if (proto == __constant_htons(ETH_P_IP)) { - - skb->csum = get_unaligned((u16 *) (skb->tail)); - return CHECKSUM_HW; - } - return CHECKSUM_NONE; -} - -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/* Auxilary Functions */ -/***************************************************************************/ - -/* Print the board's configuration */ -void -e100_print_brd_conf(struct e100_private *bdp) -{ - /* Print the string if checksum Offloading was enabled */ - if (bdp->flags & DF_CSUM_OFFLOAD) - printk(KERN_NOTICE " Hardware receive checksums enabled\n"); - else { - if (bdp->rev_id >= D101MA_REV_ID) - printk(KERN_NOTICE " Hardware receive checksums disabled\n"); - } - - if ((bdp->flags & DF_UCODE_LOADED)) - printk(KERN_NOTICE " cpu cycle saver enabled\n"); -} - -/** - * e100_pci_setup - setup the adapter's PCI information - * @pcid: adapter's pci_dev struct - * @bdp: atapter's private data struct - * - * This routine sets up all PCI information for the adapter. It enables the bus - * master bit (some BIOS don't do this), requests memory ans I/O regions, and - * calls ioremap() on the adapter's memory region. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp) -{ - struct net_device *dev = bdp->device; - int rc = 0; - - if ((rc = pci_enable_device(pcid)) != 0) { - goto err; - } - - /* dev and ven ID have already been checked so it is our device */ - pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id)); - - /* address #0 is a memory region */ - dev->mem_start = pci_resource_start(pcid, 0); - dev->mem_end = dev->mem_start + sizeof (scb_t); - - /* address #1 is a IO region */ - dev->base_addr = pci_resource_start(pcid, 1); - - if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) { - goto err_disable; - } - - pci_enable_wake(pcid, 0, 0); - - /* if Bus Mastering is off, turn it on! */ - pci_set_master(pcid); - - /* address #0 is a memory mapping */ - bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t)); - - if (!bdp->scb) { - printk(KERN_ERR "e100: %s: Failed to map PCI address 0x%lX\n", - dev->name, pci_resource_start(pcid, 0)); - rc = -ENOMEM; - goto err_region; - } - - return 0; - -err_region: - pci_release_regions(pcid); -err_disable: - pci_disable_device(pcid); -err: - return rc; -} - -void -e100_isolate_driver(struct e100_private *bdp) -{ - - /* Check if interface is up */ - /* NOTE: Can't use netif_running(bdp->device) because */ - /* dev_close clears __LINK_STATE_START before calling */ - /* e100_close (aka dev->stop) */ - if (bdp->device->flags & IFF_UP) { - e100_disable_clear_intr(bdp); - del_timer_sync(&bdp->watchdog_timer); - netif_carrier_off(bdp->device); - netif_stop_queue(bdp->device); - bdp->last_tcb = NULL; - } - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); -} - -static void -e100_tcb_add_C_bit(struct e100_private *bdp) -{ - tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data; - int i; - - for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) { - tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE); - } -} - -/* - * Procedure: e100_configure_device - * - * Description: This routine will configure device - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * true upon success - * false upon failure - */ -unsigned char -e100_configure_device(struct e100_private *bdp) -{ - /*load CU & RU base */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - return false; - - if (e100_load_microcode(bdp)) - bdp->flags |= DF_UCODE_LOADED; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - return false; - - /* Issue the load dump counters address command */ - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) { - printk(KERN_ERR "e100: e100_configure_device: " - "setup iaaddr failed\n"); - return false; - } - - e100_set_multi_exec(bdp->device); - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up */ - /* flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, - &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - e100_force_config(bdp); - - return true; -} - -void -e100_deisolate_driver(struct e100_private *bdp, u8 full_reset) -{ - u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET; - e100_sw_reset(bdp, cmd); - if (cmd == PORT_SOFTWARE_RESET) { - if (!e100_configure_device(bdp)) - printk(KERN_ERR "e100: e100_deisolate_driver:" - " device configuration failed\n"); - } - - if (netif_running(bdp->device)) { - - bdp->next_cu_cmd = START_WAIT; - bdp->last_tcb = NULL; - - e100_start_ru(bdp); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - // we must clear tcbs since we may have lost Tx intrrupt - // or have unsent frames on the tcb chain - e100_tcb_add_C_bit(bdp); - e100_tx_srv(bdp); - netif_wake_queue(bdp->device); - e100_set_intr_mask(bdp); - } -} - -static int -e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_cmd ecmd; - int rc = -EOPNOTSUPP; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd))) - return -EFAULT; - - switch (ecmd.cmd) { - case ETHTOOL_GSET: - rc = e100_ethtool_get_settings(dev, ifr); - break; - case ETHTOOL_SSET: - rc = e100_ethtool_set_settings(dev, ifr); - break; - case ETHTOOL_GDRVINFO: - rc = e100_ethtool_get_drvinfo(dev, ifr); - break; - case ETHTOOL_GREGS: - rc = e100_ethtool_gregs(dev, ifr); - break; - case ETHTOOL_NWAY_RST: - rc = e100_ethtool_nway_rst(dev, ifr); - break; - case ETHTOOL_GLINK: - rc = e100_ethtool_glink(dev, ifr); - break; - case ETHTOOL_GEEPROM: - case ETHTOOL_SEEPROM: - rc = e100_ethtool_eeprom(dev, ifr); - break; - case ETHTOOL_GSTATS: { - struct { - struct ethtool_stats cmd; - uint64_t data[E100_STATS_LEN]; - } stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} }; - struct e100_private *bdp = dev->priv; - void *addr = ifr->ifr_data; - int i; - - for(i = 0; i < E100_STATS_LEN; i++) - stats.data[i] = - ((unsigned long *)&bdp->drv_stats.net_stats)[i]; - if(copy_to_user(addr, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case ETHTOOL_GWOL: - case ETHTOOL_SWOL: - rc = e100_ethtool_wol(dev, ifr); - break; - case ETHTOOL_TEST: - rc = e100_ethtool_test(dev, ifr); - break; - case ETHTOOL_GSTRINGS: - rc = e100_ethtool_gstrings(dev,ifr); - break; - case ETHTOOL_PHYS_ID: - rc = e100_ethtool_led_blink(dev,ifr); - break; -#ifdef ETHTOOL_GRINGPARAM - case ETHTOOL_GRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - memset((void *) &ering, 0, sizeof(ering)); - ering.rx_max_pending = E100_MAX_RFD; - ering.tx_max_pending = E100_MAX_TCB; - ering.rx_pending = bdp->params.RxDescriptors; - ering.tx_pending = bdp->params.TxDescriptors; - rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SRINGPARAM - case ETHTOOL_SRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering))) - return -EFAULT; - if (ering.rx_pending > E100_MAX_RFD - || ering.rx_pending < E100_MIN_RFD) - return -EINVAL; - if (ering.tx_pending > E100_MAX_TCB - || ering.tx_pending < E100_MIN_TCB) - return -EINVAL; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - /* Use new values to open interface */ - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - e100_hw_init(bdp); - e100_open(dev); - } - else { - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - } - return 0; - } -#endif -#ifdef ETHTOOL_GPAUSEPARAM - case ETHTOOL_GPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - memset((void *) &epause, 0, sizeof(epause)); - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - epause.autoneg = 1; - if (bdp->flags && DF_LINK_FC_CAP) { - epause.rx_pause = 1; - epause.tx_pause = 1; - } - if (bdp->flags && DF_LINK_FC_TX_ONLY) - epause.tx_pause = 1; - } - rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SPAUSEPARAM - case ETHTOOL_SPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - if (!(bdp->flags & IS_BACHELOR)) - return -EINVAL; - if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause))) - return -EFAULT; - if (epause.autoneg == 1) - bdp->params.b_params |= PRM_FC; - else - bdp->params.b_params &= ~PRM_FC; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; - } -#endif -#ifdef ETHTOOL_GRXCSUM - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - case ETHTOOL_GSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - memset((void *) &eval, 0, sizeof(eval)); - if ((ecmd.cmd == ETHTOOL_GRXCSUM) - && (bdp->params.b_params & PRM_XSUMRX)) - eval.data = 1; - else - eval.data = 0; - rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SRXCSUM - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - case ETHTOOL_SSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval))) - return -EFAULT; - if (ecmd.cmd == ETHTOOL_SRXCSUM) { - if (eval.data == 1) { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params |= PRM_XSUMRX; - else - return -EINVAL; - } else { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params &= ~PRM_XSUMRX; - else - return 0; - } - } else { - if (eval.data == 1) - return -EINVAL; - else - return 0; - } - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; - } -#endif - default: - break; - } //switch - return rc; -} - -static int -e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_cmd ecmd; - u16 advert = 0; - - memset((void *) &ecmd, 0, sizeof (ecmd)); - - bdp = dev->priv; - - ecmd.supported = bdp->speed_duplex_caps; - - ecmd.port = - (bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - ecmd.transceiver = XCVR_INTERNAL; - ecmd.phy_address = bdp->phy_addr; - - if (netif_carrier_ok(bdp->device)) { - ecmd.speed = bdp->cur_line_speed; - ecmd.duplex = - (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; - } - else { - ecmd.speed = -1; - ecmd.duplex = -1; - } - - ecmd.advertising = ADVERTISED_TP; - - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - ecmd.autoneg = AUTONEG_ENABLE; - ecmd.advertising |= ADVERTISED_Autoneg; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - } - - if (bdp->speed_duplex_caps & SUPPORTED_MII) { - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert); - - if (advert & ADVERTISE_10HALF) - ecmd.advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - ecmd.advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - ecmd.advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - ecmd.advertising |= ADVERTISED_100baseT_Full; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.advertising &= ~ADVERTISED_Autoneg; - } - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - int e100_new_speed_duplex; - int ethtool_new_speed_duplex; - struct ethtool_cmd ecmd; - - bdp = dev->priv; - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) { - return -EFAULT; - } - - if ((ecmd.autoneg == AUTONEG_ENABLE) - && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) { - bdp->params.e100_speed_duplex = E100_AUTONEG; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - if (ecmd.speed == SPEED_10) { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_10_HALF; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_10_FULL; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Full; - } - } else { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_100_HALF; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_100_FULL; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Full; - } - } - - if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) { - bdp->params.e100_speed_duplex = - e100_new_speed_duplex; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EOPNOTSUPP; - } - } - - return 0; -} - -static int -e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value info; - - memset((void *) &info, 0, sizeof (info)); - - bdp = dev->priv; - info.cmd = ETHTOOL_GLINK; - - /* Consider both PHY link and netif_running */ - info.data = e100_update_link_state(bdp); - - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_test(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_test *info; - int rc = -EFAULT; - - info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64), - GFP_ATOMIC); - - if (!info) - return -ENOMEM; - - memset((void *) info, 0, sizeof(*info) + - max_test_res * sizeof(u64)); - - if (copy_from_user(info, ifr->ifr_data, sizeof(*info))) - goto exit; - - info->flags = e100_run_diag(dev, info->data, info->flags); - - if (!copy_to_user(ifr->ifr_data, info, - sizeof(*info) + max_test_res * sizeof(u64))) - rc = 0; -exit: - kfree(info); - return rc; -} - -static int -e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - u32 regs_buff[E100_REGS_LEN]; - struct ethtool_regs regs = {ETHTOOL_GREGS}; - void *addr = ifr->ifr_data; - u16 mdi_reg; - - bdp = dev->priv; - - if(copy_from_user(®s, addr, sizeof(regs))) - return -EFAULT; - - regs.version = (1 << 24) | bdp->rev_id; - regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | - readb(&(bdp->scb->scb_cmd_low)) << 16 | - readw(&(bdp->scb->scb_status)); - e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg); - regs_buff[1] = mdi_reg; - - if(copy_to_user(addr, ®s, sizeof(regs))) - return -EFAULT; - - addr += offsetof(struct ethtool_regs, data); - if(copy_to_user(addr, regs_buff, regs.len)) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - - bdp = dev->priv; - - if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) && - (bdp->params.e100_speed_duplex == E100_AUTONEG)) { - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EFAULT; - } - return 0; -} - -static int -e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_drvinfo info; - - memset((void *) &info, 0, sizeof (info)); - - bdp = dev->priv; - - strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1); - strncpy(info.version, e100_driver_version, sizeof (info.version) - 1); - strncpy(info.fw_version, "N/A", - sizeof (info.fw_version) - 1); - strncpy(info.bus_info, pci_name(bdp->pdev), - sizeof (info.bus_info) - 1); - info.n_stats = E100_STATS_LEN; - info.regdump_len = E100_REGS_LEN * sizeof(u32); - info.eedump_len = (bdp->eeprom_size << 1); - info.testinfo_len = max_test_res; - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_eeprom ecmd; - u16 eeprom_data[256]; - u16 *usr_eeprom_ptr; - u16 first_word, last_word; - int i, max_len; - void *ptr; - u8 *eeprom_data_bytes = (u8 *)eeprom_data; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - usr_eeprom_ptr = - (u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data)); - - max_len = bdp->eeprom_size * 2; - - if (ecmd.offset > ecmd.offset + ecmd.len) - return -EINVAL; - - if ((ecmd.offset + ecmd.len) > max_len) - ecmd.len = (max_len - ecmd.offset); - - first_word = ecmd.offset >> 1; - last_word = (ecmd.offset + ecmd.len - 1) >> 1; - - if (first_word >= bdp->eeprom_size) - return -EFAULT; - - if (ecmd.cmd == ETHTOOL_GEEPROM) { - for(i = 0; i <= (last_word - first_word); i++) - eeprom_data[i] = e100_eeprom_read(bdp, first_word + i); - - ecmd.magic = E100_EEPROM_MAGIC; - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - if(ecmd.offset & 1) - eeprom_data_bytes++; - if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len)) - return -EFAULT; - } else { - if (ecmd.magic != E100_EEPROM_MAGIC) - return -EFAULT; - - ptr = (void *)eeprom_data; - if(ecmd.offset & 1) { - /* need modification of first changed EEPROM word */ - /* only the second byte of the word is being modified */ - eeprom_data[0] = e100_eeprom_read(bdp, first_word); - ptr++; - } - if((ecmd.offset + ecmd.len) & 1) { - /* need modification of last changed EEPROM word */ - /* only the first byte of the word is being modified */ - eeprom_data[last_word - first_word] = - e100_eeprom_read(bdp, last_word); - } - if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len)) - return -EFAULT; - - e100_eeprom_write_block(bdp, first_word, eeprom_data, - last_word - first_word + 1); - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - } - return 0; -} - -#define E100_BLINK_INTERVAL (HZ/4) -/** - * e100_led_control - * @bdp: atapter's private data struct - * @led_mdi_op: led operation - * - * Software control over adapter's led. The possible operations are: - * TURN LED OFF, TURN LED ON and RETURN LED CONTROL TO HARDWARE. - */ -static void -e100_led_control(struct e100_private *bdp, u16 led_mdi_op) -{ - e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL, - bdp->phy_addr, led_mdi_op); - -} -/** - * e100_led_blink_callback - * @data: pointer to atapter's private data struct - * - * Blink timer callback function. Toggles ON/OFF led status bit and calls - * led hardware access function. - */ -static void -e100_led_blink_callback(unsigned long data) -{ - struct e100_private *bdp = (struct e100_private *) data; - - if(bdp->flags & LED_IS_ON) { - bdp->flags &= ~LED_IS_ON; - e100_led_control(bdp, PHY_82555_LED_OFF); - } else { - bdp->flags |= LED_IS_ON; - if (bdp->rev_id >= D101MA_REV_ID) - e100_led_control(bdp, PHY_82555_LED_ON_559); - else - e100_led_control(bdp, PHY_82555_LED_ON_PRE_559); - } - - mod_timer(&bdp->blink_timer, jiffies + E100_BLINK_INTERVAL); -} -/** - * e100_ethtool_led_blink - * @dev: pointer to atapter's net_device struct - * @ifr: pointer to ioctl request structure - * - * Blink led ioctl handler. Initialtes blink timer and sleeps until - * blink period expires. Than it kills timer and returns. The led control - * is returned back to hardware when blink timer is killed. - */ -static int -e100_ethtool_led_blink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value ecmd; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - if(!bdp->blink_timer.function) { - init_timer(&bdp->blink_timer); - bdp->blink_timer.function = e100_led_blink_callback; - bdp->blink_timer.data = (unsigned long) bdp; - } - - mod_timer(&bdp->blink_timer, jiffies); - - set_current_state(TASK_INTERRUPTIBLE); - - if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) - ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); - - schedule_timeout(ecmd.data * HZ); - - del_timer_sync(&bdp->blink_timer); - - e100_led_control(bdp, PHY_82555_LED_NORMAL_CONTROL); - - return 0; -} - -static inline int -e100_10BaseT_adapter(struct e100_private *bdp) -{ - return ((bdp->pdev->device == 0x1229) && - (bdp->pdev->subsystem_vendor == 0x8086) && - (bdp->pdev->subsystem_device == 0x0003)); -} - -static void -e100_get_speed_duplex_caps(struct e100_private *bdp) -{ - u16 status; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - bdp->speed_duplex_caps = 0; - - bdp->speed_duplex_caps |= - (status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0; - - if (IS_NC3133(bdp)) - bdp->speed_duplex_caps = - (SUPPORTED_FIBRE | SUPPORTED_100baseT_Full); - else - bdp->speed_duplex_caps |= SUPPORTED_TP; - - if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) { - bdp->speed_duplex_caps = - (SUPPORTED_10baseT_Half | SUPPORTED_TP); - } else { - bdp->speed_duplex_caps |= SUPPORTED_MII; - } - -} - -#ifdef CONFIG_PM -static unsigned char -e100_setup_filter(struct e100_private *bdp) -{ - cb_header_t *ntcb_hdr; - unsigned char res = false; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER); - - /* Set EL and FIX bit */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] = - __constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX); - - if (bdp->wolopts & WAKE_UCAST) { - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - __constant_cpu_to_le32(CB_FILTER_IA_MATCH); - } - - if (bdp->wolopts & WAKE_ARP) { - /* Setup ARP bit and lower IP parts */ - /* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes); - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: Filter setup failed\n", - bdp->device->name); - -exit: - return res; - -} - -static void -e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp) -{ - e100_config_wol(bdp); - - if (e100_config(bdp)) { - if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) - if (!e100_setup_filter(bdp)) - printk(KERN_ERR - "e100: WOL options failed\n"); - } else { - printk(KERN_ERR "e100: config WOL failed\n"); - } -} -#endif - -static u16 -e100_get_ip_lbytes(struct net_device *dev) -{ - struct in_ifaddr *ifa; - struct in_device *in_dev; - u32 res = 0; - - in_dev = (struct in_device *) dev->ip_ptr; - /* Check if any in_device bound to interface */ - if (in_dev) { - /* Check if any IP address is bound to interface */ - if ((ifa = in_dev->ifa_list) != NULL) { - res = __constant_ntohl(ifa->ifa_address); - res = __constant_htons(res & 0x0000ffff); - } - } - return res; -} - -static int -e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_wolinfo wolinfo; - int res = 0; - - bdp = dev->priv; - - if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) { - return -EFAULT; - } - - switch (wolinfo.cmd) { - case ETHTOOL_GWOL: - wolinfo.supported = bdp->wolsupported; - wolinfo.wolopts = bdp->wolopts; - if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) - res = -EFAULT; - break; - case ETHTOOL_SWOL: - /* If ALL requests are supported or request is DISABLE wol */ - if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) - || (wolinfo.wolopts == 0)) { - bdp->wolopts = wolinfo.wolopts; - } else { - res = -EOPNOTSUPP; - } - if (wolinfo.wolopts & WAKE_ARP) - bdp->ip_lbytes = e100_get_ip_lbytes(dev); - break; - default: - break; - } - return res; -} - -static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_gstrings info; - char *strings = NULL; - char *usr_strings; - int i; - - memset((void *) &info, 0, sizeof(info)); - - usr_strings = (u8 *) (ifr->ifr_data + - offsetof(struct ethtool_gstrings, data)); - - if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) - return -EFAULT; - - switch (info.string_set) { - case ETH_SS_TEST: { - int ret = 0; - if (info.len > max_test_res) - info.len = max_test_res; - strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); - if (!strings) - return -ENOMEM; - memset(strings, 0, info.len * ETH_GSTRING_LEN); - - for (i = 0; i < info.len; i++) { - sprintf(strings + i * ETH_GSTRING_LEN, "%s", - test_strings[i]); - } - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - ret = -EFAULT; - if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) - ret = -EFAULT; - kfree(strings); - return ret; - } - case ETH_SS_STATS: { - char *strings = NULL; - void *addr = ifr->ifr_data; - info.len = E100_STATS_LEN; - strings = *e100_gstrings_stats; - if(copy_to_user(ifr->ifr_data, &info, sizeof(info))) - return -EFAULT; - addr += offsetof(struct ethtool_gstrings, data); - if(copy_to_user(addr, strings, - info.len * ETH_GSTRING_LEN)) - return -EFAULT; - return 0; - } - default: - return -EOPNOTSUPP; - } -} - -static int -e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct e100_private *bdp; - struct mii_ioctl_data *data_ptr = - (struct mii_ioctl_data *) &(ifr->ifr_data); - - bdp = dev->priv; - - switch (cmd) { - case SIOCGMIIPHY: - data_ptr->phy_id = bdp->phy_addr & 0x1f; - break; - - case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr, - &(data_ptr->val_out)); - break; - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* If reg = 0 && change speed/duplex */ - if (data_ptr->reg_num == 0 && - (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */ - || data_ptr->val_in == (BMCR_RESET) /* reset cmd */ - || data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) - || data_ptr->val_in == 0)) { - if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) - || data_ptr->val_in == (BMCR_RESET)) - bdp->params.e100_speed_duplex = E100_AUTONEG; - else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - else if (data_ptr->val_in == (BMCR_SPEED100)) - bdp->params.e100_speed_duplex = E100_SPEED_100_HALF; - else if (data_ptr->val_in == (BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; - else - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } - else - /* Only allows changing speed/duplex */ - return -EINVAL; - - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -nxmit_cb_entry_t * -e100_alloc_non_tx_cmd(struct e100_private *bdp) -{ - nxmit_cb_entry_t *non_tx_cmd_elem; - - if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *) - kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) { - return NULL; - } - non_tx_cmd_elem->non_tx_cmd = - pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t), - &(non_tx_cmd_elem->dma_addr)); - if (non_tx_cmd_elem->non_tx_cmd == NULL) { - kfree(non_tx_cmd_elem); - return NULL; - } - return non_tx_cmd_elem; -} - -void -e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd_elem) -{ - pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t), - non_tx_cmd_elem->non_tx_cmd, - non_tx_cmd_elem->dma_addr); - kfree(non_tx_cmd_elem); -} - -static void -e100_free_nontx_list(struct e100_private *bdp) -{ - nxmit_cb_entry_t *command; - int i; - - while (!list_empty(&bdp->non_tx_cmd_list)) { - command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - list_del(&(command->list_elem)); - e100_free_non_tx_cmd(bdp, command); - } - - for (i = 0; i < CB_MAX_NONTX_CMD; i++) { - bdp->same_cmd_entry[i] = NULL; - } -} - -static unsigned char -e100_delayed_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *command) -{ - nxmit_cb_entry_t *same_command; - cb_header_t *ntcb_hdr; - u16 cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; - - cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd); - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - same_command = bdp->same_cmd_entry[cmd]; - - if (same_command != NULL) { - memcpy((void *) (same_command->non_tx_cmd), - (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t)); - e100_free_non_tx_cmd(bdp, command); - } else { - list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list)); - bdp->same_cmd_entry[cmd] = command; - } - - if (bdp->non_tx_command_state == E100_NON_TX_IDLE) { - bdp->non_tx_command_state = E100_WAIT_TX_FINISH; - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } - - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return true; -} - -static void -e100_non_tx_background(unsigned long ptr) -{ - struct e100_private *bdp = (struct e100_private *) ptr; - nxmit_cb_entry_t *active_command; - int restart = true; - cb_header_t *non_tx_cmd; - u8 sub_cmd; - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - switch (bdp->non_tx_command_state) { - case E100_WAIT_TX_FINISH: - if (bdp->last_tcb != NULL) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto exit; - } - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == - SCB_CUS_ACTIVE) { - goto exit; - } - break; - - case E100_WAIT_NON_TX_FINISH: - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - rmb(); - - if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - && time_before(jiffies, active_command->expiration_time)) { - goto exit; - } else { - non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd; - sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd); -#ifdef E100_CU_DEBUG - if (!(non_tx_cmd->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - printk(KERN_ERR "e100: %s: Queued " - "command (%x) timeout\n", - bdp->device->name, sub_cmd); -#endif - list_del(&(active_command->list_elem)); - e100_free_non_tx_cmd(bdp, active_command); - } - break; - - default: - break; - } //switch - - if (list_empty(&bdp->non_tx_cmd_list)) { - bdp->non_tx_command_state = E100_NON_TX_IDLE; - spin_lock_irq(&(bdp->bd_lock)); - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irq(&(bdp->bd_lock)); - restart = false; - goto exit; - } else { - u16 cmd_type; - - bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH; - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd; - spin_lock_irq(&(bdp->bd_lock)); - e100_wait_exec_cmplx(bdp, active_command->dma_addr, - SCB_CUC_START, sub_cmd); - spin_unlock_irq(&(bdp->bd_lock)); - active_command->expiration_time = jiffies + HZ; - cmd_type = CB_CMD_MASK & - le16_to_cpu(((cb_header_t *) - (active_command->non_tx_cmd))->cb_cmd); - bdp->same_cmd_entry[cmd_type] = NULL; - } - -exit: - if (restart) { - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } else { - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - } - spin_unlock_bh(&(bdp->bd_non_tx_lock)); -} - -static void -e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) -{ - struct e100_private *bdp = netdev->priv; - - e100_disable_clear_intr(bdp); - bdp->vlgrp = grp; - - if(grp) { - /* enable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, true); - - } else { - /* disable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, false); - } - - e100_config(bdp); - e100_set_intr_mask(bdp); -} - -static void -e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid) -{ - /* We don't do Vlan filtering */ - return; -} - -static void -e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) -{ - struct e100_private *bdp = netdev->priv; - - if(bdp->vlgrp) - bdp->vlgrp->vlan_devices[vid] = NULL; - /* We don't do Vlan filtering */ - return; -} - -#ifdef CONFIG_PM -static int -e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) -{ - struct pci_dev *pdev = NULL; - - switch(event) { - case SYS_DOWN: - case SYS_HALT: - case SYS_POWER_OFF: - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - if(pci_dev_driver(pdev) == &e100_driver) { - /* If net_device struct is allocated? */ - if (pci_get_drvdata(pdev)) - e100_suspend(pdev, 3); - - } - } - } - return NOTIFY_DONE; -} - -static int -e100_suspend(struct pci_dev *pcid, u32 state) -{ - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - e100_isolate_driver(bdp); - pci_save_state(pcid, bdp->pci_state); - - /* Enable or disable WoL */ - e100_do_wol(pcid, bdp); - - /* If wol is enabled */ - if (bdp->wolopts || e100_asf_enabled(bdp)) { - pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ - pci_set_power_state(pcid, 3); /* Set power state to D3. */ - } else { - /* Disable bus mastering */ - pci_disable_device(pcid); - pci_set_power_state(pcid, state); - } - return 0; -} - -static int -e100_resume(struct pci_dev *pcid) -{ - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - pci_set_power_state(pcid, 0); - pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */ - pci_restore_state(pcid, bdp->pci_state); - - /* Also do device full reset because device was in D3 state */ - e100_deisolate_driver(bdp, true); - - return 0; -} - -/** - * e100_asf_enabled - checks if ASF is configured on the current adaper - * by reading registers 0xD and 0x90 in the EEPROM - * @bdp: atapter's private data struct - * - * Returns: true if ASF is enabled - */ -static unsigned char -e100_asf_enabled(struct e100_private *bdp) -{ - u16 asf_reg; - u16 smbus_addr_reg; - if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) { - asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF); - if ((asf_reg & EEPROM_FLAG_ASF) - && !(asf_reg & EEPROM_FLAG_GCL)) { - smbus_addr_reg = - e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR); - if ((smbus_addr_reg & 0xFF) != 0xFE) - return true; - } - } - return false; -} -#endif /* CONFIG_PM */ - -#ifdef E100_CU_DEBUG -unsigned char -e100_cu_unknown_state(struct e100_private *bdp) -{ - u8 scb_cmd_low; - u16 scb_status; - scb_cmd_low = bdp->scb->scb_cmd_low; - scb_status = le16_to_cpu(bdp->scb->scb_status); - /* If CU is active and executing unknown cmd */ - if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN) - return true; - else - return false; -} -#endif - --- linux-2.6.1-rc1/drivers/net/e100/e100_phy.c 2003-12-30 22:37:21.000000000 -0800 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,1163 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" - -void e100_handle_zlock(struct e100_private *bdp); - -/* - * Procedure: e100_mdi_write - * - * Description: This routine will write a value to the specified MII register - * of an external MDI compliant device (e.g. PHY 100). The - * command will execute in polled mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are writing to - * phy_addr - The MDI address of the Phy component. - * data - The value that we are writing to the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - temp_val = (((u32) data) | (reg_addr << 16) | - (phy_addr << 21) | (MDI_WRITE << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi write to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) - return 0; - else { - printk(KERN_ERR "e100: MDI write timeout\n"); - return 1; - } -} - -/* - * Procedure: e100_mdi_read - * - * Description: This routine will read a value from the specified MII register - * of an external MDI compliant device (e.g. PHY 100), and return - * it to the calling routine. The command will execute in polled - * mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are reading from - * phy_addr - The MDI address of the Phy component. - * - * Results: - * data - The value that we read from the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - /* Issue the read command to the MDI control register. */ - temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi read to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) { - /* return the lower word */ - *data = (u16) mdi_cntrl; - return 0; - } - else { - printk(KERN_ERR "e100: MDI read timeout\n"); - return 1; - } -} - -static unsigned char -e100_phy_valid(struct e100_private *bdp, unsigned int phy_address) -{ - u16 ctrl_reg, stat_reg; - - /* Read the MDI control register */ - e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg); - - /* Read the status register twice, bacause of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - - if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0))) - return false; - - return true; -} - -static void -e100_phy_address_detect(struct e100_private *bdp) -{ - unsigned int addr; - unsigned char valid_phy_found = false; - - if (IS_NC3133(bdp)) { - bdp->phy_addr = 0; - return; - } - - if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) { - bdp->phy_addr = PHY_DEFAULT_ADDRESS; - valid_phy_found = true; - - } else { - for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) { - if (e100_phy_valid(bdp, addr)) { - bdp->phy_addr = addr; - valid_phy_found = true; - break; - } - } - } - - if (!valid_phy_found) { - bdp->phy_addr = PHY_ADDRESS_503; - } -} - -static void -e100_phy_id_detect(struct e100_private *bdp) -{ - u16 low_id_reg, high_id_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - bdp->PhyId = PHY_503; - return; - } - if (!(bdp->flags & IS_ICH)) { - if (bdp->rev_id >= D102_REV_ID) { - bdp->PhyId = PHY_82562ET; - return; - } - } - - /* Read phy id from the MII register */ - e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg); - e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg); - - bdp->PhyId = ((unsigned int) low_id_reg | - ((unsigned int) high_id_reg << 16)); -} - -static void -e100_phy_isolate(struct e100_private *bdp) -{ - unsigned int phy_address; - u16 ctrl_reg; - - /* Go over all phy addresses. Deisolate the selected one, and isolate - * all the rest */ - for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) { - if (phy_address != bdp->phy_addr) { - e100_mdi_write(bdp, MII_BMCR, phy_address, - BMCR_ISOLATE); - - } else { - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg); - ctrl_reg &= ~BMCR_ISOLATE; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - } - - udelay(100); - } -} - -static unsigned char -e100_phy_specific_setup(struct e100_private *bdp) -{ - u16 misc_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - switch (bdp->params.e100_speed_duplex) { - case E100_AUTONEG: - /* The adapter can't autoneg. so set to 10/HALF */ - printk(KERN_INFO - "e100: 503 serial component detected which " - "cannot autonegotiate\n"); - printk(KERN_INFO - "e100: speed/duplex forced to " - "10Mbps / Half duplex\n"); - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - break; - - case E100_SPEED_100_HALF: - case E100_SPEED_100_FULL: - printk(KERN_ERR - "e100: 503 serial component detected " - "which does not support 100Mbps\n"); - printk(KERN_ERR - "e100: Change the forced speed/duplex " - "to a supported setting\n"); - return false; - } - - return true; - } - - if (IS_NC3133(bdp)) { - u16 int_reg; - - /* enable 100BASE fiber interface */ - e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr, - MDI_NC3133_100FX_ENABLE); - - if ((bdp->params.e100_speed_duplex != E100_AUTONEG) && - (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) { - /* just inform user about 100 full */ - printk(KERN_ERR "e100: NC3133 NIC can only run " - "at 100Mbps full duplex\n"); - } - - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - - /* enable interrupts */ - e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, &int_reg); - int_reg |= MDI_NC3133_INT_ENABLE; - e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, int_reg); - } - - /* Handle the National TX */ - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) { - e100_mdi_read(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, &misc_reg); - - misc_reg |= NSC_TX_CONG_TXREADY; - - /* disable the congestion control bit in the National Phy */ - misc_reg &= ~NSC_TX_CONG_ENABLE; - - e100_mdi_write(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, misc_reg); - } - - return true; -} - -/* - * Procedure: e100_phy_fix_squelch - * - * Description: - * Help find link on certain rare scenarios. - * NOTE: This routine must be called once per watchdog, - * and *after* setting the current link state. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_phy_fix_squelch(struct e100_private *bdp) -{ - if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED)) - return; - - if (netif_carrier_ok(bdp->device)) { - switch (bdp->PhyState) { - case 0: - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - break; - } - bdp->PhyState = 0; - bdp->PhyDelay = 0; - - } else if (!bdp->PhyDelay--) { - switch (bdp->PhyState) { - case 0: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, EXTENDED_SQUELCH_BIT); - bdp->PhyState = 1; - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x2010); - bdp->PhyState = 2; - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - bdp->PhyState = 0; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - bdp->PhyDelay = 3; - } -} - -/* - * Procedure: e100_fix_polarity - * - * Description: - * Fix for 82555 auto-polarity toggle problem. With a short cable - * connecting an 82555 with an 840A link partner, if the medium is noisy, - * the 82555 sometime thinks that the polarity might be wrong and so - * toggles polarity. This happens repeatedly and results in a high bit - * error rate. - * NOTE: This happens only at 10 Mbps - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_fix_polarity(struct e100_private *bdp) -{ - u16 status; - u16 errors; - u16 misc_reg; - int speed; - - if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) && - (bdp->PhyId != PHY_82562EM)) - return; - - /* If the user wants auto-polarity disabled, do only that and nothing * - * else. * e100_autopolarity == 0 means disable --- we do just the - * disabling * e100_autopolarity == 1 means enable --- we do nothing at - * all * e100_autopolarity >= 2 means we do the workaround code. */ - /* Change for 82558 enhancement */ - switch (E100_AUTOPOLARITY) { - case 0: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg | DISABLE_AUTO_POLARITY)); - break; - - case 1: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg & ~DISABLE_AUTO_POLARITY)); - break; - - case 2: - /* we do this only if link is up */ - if (!netif_carrier_ok(bdp->device)) { - break; - } - - e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status); - speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10; - - /* we need to do this only if speed is 10 */ - if (speed != 10) { - break; - } - - /* see if we have any end of frame errors */ - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero, wait for 100 ms before reading again */ - if (errors) { - udelay(200); - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero again, we disable polarity */ - if (errors) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - - if (!errors) { - /* it is safe to read the polarity now */ - e100_mdi_read(bdp, PHY_82555_CSR, - bdp->phy_addr, &status); - - /* if polarity is normal, disable polarity */ - if (!(status & PHY_82555_POLARITY_BIT)) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - break; - - default: - break; - } -} - -/* - * Procedure: e100_find_speed_duplex - * - * Description: This routine will figure out what line speed and duplex mode - * the PHY is currently using. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_find_speed_duplex(struct e100_private *bdp) -{ - unsigned int PhyId; - u16 stat_reg, misc_reg; - u16 ad_reg, lp_ad_reg; - - PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK; - - /* First we should check to see if we have link */ - /* If we don't have a link no reason to print a speed and duplex */ - if (!e100_update_link_state(bdp)) { - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - return; - } - - /* On the 82559 and later controllers, speed/duplex is part of the * - * SCB. So, we save an mdi_read and get these from the SCB. * */ - if (bdp->rev_id >= D101MA_REV_ID) { - /* Read speed */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Read duplex */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* If this is a Phy 100, then read bits 1 and 0 of extended register 0, - * to get the current speed and duplex settings. */ - if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || - (PhyId == PHY_82555_TX)) { - - /* Read Phy 100 extended register 0 */ - e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg); - - /* Get current speed setting */ - if (misc_reg & PHY_100_ER0_SPEED_INDIC) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get current duplex setting -- FDX enabled if bit is set */ - if (misc_reg & PHY_100_ER0_FDX_INDIC) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg); - - /* See if Auto-Negotiation was complete (bit 5, reg 1) */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* If a True NWAY connection was made, then we can detect speed/dplx - * by ANDing our adapter's advertised abilities with our link partner's - * advertised ablilities, and then assuming that the highest common - * denominator was chosed by NWAY. */ - if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) { - - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - /* AND the two advertisement registers together, and get rid - * of any extraneous bits. */ - ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY); - - /* Get speed setting */ - if (ad_reg & - (ADVERTISE_100HALF | ADVERTISE_100FULL | - ADVERTISE_100BASE4)) - - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get duplex setting -- use priority resolution algorithm */ - if (ad_reg & ADVERTISE_100BASE4) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_100FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else if (ad_reg & ADVERTISE_100HALF) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_10FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else { - bdp->cur_dplx_mode = HALF_DUPLEX; - } - - return; - } - - /* If we are connected to a dumb (non-NWAY) repeater or hub, and the - * line speed was determined automatically by parallel detection, then - * we have no way of knowing exactly what speed the PHY is set to - * unless that PHY has a propietary register which indicates speed in - * this situation. The NSC TX PHY does have such a register. Also, - * since NWAY didn't establish the connection, the duplex setting - * should HALF duplex. */ - bdp->cur_dplx_mode = HALF_DUPLEX; - - if (PhyId == PHY_NSC_TX) { - /* Read register 25 to get the SPEED_10 bit */ - e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg); - - /* If bit 6 was set then we're at 10Mbps */ - if (misc_reg & NSC_TX_SPD_INDC_SPEED) - bdp->cur_line_speed = 10; - else - bdp->cur_line_speed = 100; - - } else { - /* If we don't know the line speed, default to 10Mbps */ - bdp->cur_line_speed = 10; - } -} - -/* - * Procedure: e100_force_speed_duplex - * - * Description: This routine forces line speed and duplex mode of the - * adapter based on the values the user has set in e100.c. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -void -e100_force_speed_duplex(struct e100_private *bdp) -{ - u16 control; - unsigned long expires; - - bdp->flags |= DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); - - /* loop must run at least once */ - expires = jiffies + 2 * HZ; - do { - if (e100_update_link_state(bdp) || - time_after(jiffies, expires)) { - break; - } else { - yield(); - } - - } while (true); -} - -void -e100_force_speed_duplex_to_phy(struct e100_private *bdp) -{ - u16 control; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - } - - /* Send speed/duplex command to PHY layer. */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); -} - -/* - * Procedure: e100_set_fc - * - * Description: Checks the link's capability for flow control. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -static void -e100_set_fc(struct e100_private *bdp) -{ - u16 ad_reg; - u16 lp_ad_reg; - u16 exp_reg; - - /* no flow control for 82557, forced links or half duplex */ - if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) || - (bdp->cur_dplx_mode == HALF_DUPLEX) || - !(bdp->flags & IS_BACHELOR)) { - - bdp->flags &= ~DF_LINK_FC_CAP; - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg); - - if (exp_reg & EXPANSION_NWAY) { - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - ad_reg &= lp_ad_reg; /* AND the 2 ad registers */ - - if (ad_reg & NWAY_AD_FC_SUPPORTED) - bdp->flags |= DF_LINK_FC_CAP; - else - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused */ - /* by incoming PAUSE frames */ - bdp->flags |= DF_LINK_FC_TX_ONLY; - - } else { - bdp->flags &= ~DF_LINK_FC_CAP; - } -} - -/* - * Procedure: e100_phy_check - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: true if link state was changed - * false otherwise - * - */ -unsigned char -e100_phy_check(struct e100_private *bdp) -{ - unsigned char old_link; - unsigned char changed = false; - - old_link = netif_carrier_ok(bdp->device) ? 1 : 0; - e100_find_speed_duplex(bdp); - - if (!old_link && netif_carrier_ok(bdp->device)) { - e100_set_fc(bdp); - changed = true; - } - - if (old_link && !netif_carrier_ok(bdp->device)) { - /* reset the zero lock state */ - bdp->zlock_state = ZLOCK_INITIAL; - - // set auto lock for phy auto-negotiation on link up - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX) - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - changed = true; - } - - e100_phy_fix_squelch(bdp); - e100_handle_zlock(bdp); - - return changed; -} - -/* - * Procedure: e100_auto_neg - * - * Description: This routine will start autonegotiation and wait - * for it to complete - * - * Arguments: - * bdp - pointer to this card's e100_bdconfig structure - * force_restart - defines if autoneg should be restarted even if it - * has been completed before - * Returns: - * NOTHING - */ -static void -e100_auto_neg(struct e100_private *bdp, unsigned char force_restart) -{ - u16 stat_reg; - unsigned long expires; - - bdp->flags &= ~DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* if we are capable of performing autoneg then we restart if needed */ - if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) { - - if ((!force_restart) && - (stat_reg & BMSR_ANEGCOMPLETE)) { - goto exit; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - - /* wait for autoneg to complete (up to 3 seconds) */ - expires = jiffies + HZ * 3; - do { - /* now re-read the value. Sticky so read twice */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - if ((stat_reg & BMSR_ANEGCOMPLETE) || - time_after(jiffies, expires) ) { - goto exit; - } else { - yield(); - } - } while (true); - } - -exit: - e100_find_speed_duplex(bdp); -} - -void -e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart) -{ - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - if (bdp->rev_id >= D102_REV_ID) - /* Enable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_AUTO_SWITCH_ENABLE); - e100_auto_neg(bdp, force_restart); - - } else { - if (bdp->rev_id >= D102_REV_ID) - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - e100_force_speed_duplex(bdp); - } - - e100_set_fc(bdp); -} - -void -e100_phy_autoneg(struct e100_private *bdp) -{ - u16 ctrl_reg; - - ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET; - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - - udelay(100); -} - -void -e100_phy_set_loopback(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_LOOPBACK; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - udelay(100); -} - -void -e100_phy_reset(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_RESET; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - /* ieee 802.3 : The reset process shall be completed */ - /* within 0.5 seconds from the settting of PHY reset bit. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); -} - -unsigned char -e100_phy_init(struct e100_private *bdp) -{ - e100_phy_reset(bdp); - e100_phy_address_detect(bdp); - e100_phy_isolate(bdp); - e100_phy_id_detect(bdp); - - if (!e100_phy_specific_setup(bdp)) - return false; - - bdp->PhyState = 0; - bdp->PhyDelay = 0; - bdp->zlock_state = ZLOCK_INITIAL; - - e100_phy_set_speed_duplex(bdp, false); - e100_fix_polarity(bdp); - - return true; -} - -/* - * Procedure: e100_get_link_state - * - * Description: This routine checks the link status of the adapter - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_get_link_state(struct e100_private *bdp) -{ - unsigned char link = false; - u16 status; - - /* Check link status */ - /* If the controller is a 82559 or later one, link status is available - * from the CSR. This avoids the mdi_read. */ - if (bdp->rev_id >= D101MA_REV_ID) { - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) { - link = true; - } else { - link = false; - } - - } else { - /* Read the status register twice because of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - if (status & BMSR_LSTATUS) { - link = true; - } else { - link = false; - } - } - - return link; -} - -/* - * Procedure: e100_update_link_state - * - * Description: This routine updates the link status of the adapter, - * also considering netif_running - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_update_link_state(struct e100_private *bdp) -{ - unsigned char link; - - /* Logical AND PHY link & netif_running */ - link = e100_get_link_state(bdp) && netif_running(bdp->device); - - if (link) { - if (!netif_carrier_ok(bdp->device)) - netif_carrier_on(bdp->device); - } else { - if (netif_carrier_ok(bdp->device)) - netif_carrier_off(bdp->device); - } - - return link; -} - -/**************************************************************************\ - ** - ** PROC NAME: e100_handle_zlock - ** This function manages a state machine that controls - ** the driver's zero locking algorithm. - ** This function is called by e100_watchdog() every ~2 second. - ** States: - ** The current link handling state is stored in - ** bdp->zlock_state, and is one of: - ** ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING - ** Detailed description of the states and the transitions - ** between states is found below. - ** Note that any time the link is down / there is a reset - ** state will be changed outside this function to ZLOCK_INITIAL - ** Algorithm: - ** 1. If link is up & 100 Mbps continue else stay in #1: - ** 2. Set 'auto lock' - ** 3. Read & Store 100 times 'Zero' locked in 1 sec interval - ** 4. If max zero read >= 0xB continue else goto 1 - ** 5. Set most popular 'Zero' read in #3 - ** 6. Sleep 5 minutes - ** 7. Read number of errors, if it is > 300 goto 2 else goto 6 - ** Data Structures (in DRIVER_DATA): - ** zlock_state - current state of the algorithm - ** zlock_read_cnt - counts number of reads (up to 100) - ** zlock_read_data[i] - counts number of times 'Zero' read was i, 0 <= i <= 15 - ** zlock_sleep_cnt - keeps track of "sleep" time (up to 300 secs = 5 minutes) - ** - ** Parameters: DRIVER_DATA *bdp - ** - ** bdp - Pointer to HSM's adapter data space - ** - ** Return Value: NONE - ** - ** See Also: e100_watchdog() - ** - \**************************************************************************/ -void -e100_handle_zlock(struct e100_private *bdp) -{ - u16 pos; - u16 eq_reg; - u16 err_cnt; - u8 mpz; /* Most Popular Zero */ - - switch (bdp->zlock_state) { - case ZLOCK_INITIAL: - - if (((u8) bdp->rev_id <= D102_REV_ID) || - !(bdp->cur_line_speed == 100) || - !netif_carrier_ok(bdp->device)) { - break; - } - - /* initialize hw and sw and start reading */ - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - /* reset read counters: */ - bdp->zlock_read_cnt = 0; - for (pos = 0; pos < 16; pos++) - bdp->zlock_read_data[pos] = 0; - /* start reading in the next call back: */ - bdp->zlock_state = ZLOCK_READING; - - /* FALL THROUGH !! */ - - case ZLOCK_READING: - /* state: reading (100 times) zero locked in 1 sec interval - * prev states: ZLOCK_INITIAL - * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */ - - e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, &eq_reg); - pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4; - bdp->zlock_read_data[pos]++; - bdp->zlock_read_cnt++; - - if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) { - /* check if we read a 'Zero' value of 0xB or greater */ - if ((bdp->zlock_read_data[0xB]) || - (bdp->zlock_read_data[0xC]) || - (bdp->zlock_read_data[0xD]) || - (bdp->zlock_read_data[0xE]) || - (bdp->zlock_read_data[0xF])) { - - /* we've read 'Zero' value of 0xB or greater, - * find most popular 'Zero' value and lock it */ - mpz = 0; - /* this loop finds the most popular 'Zero': */ - for (pos = 1; pos < 16; pos++) { - if (bdp->zlock_read_data[pos] > - bdp->zlock_read_data[mpz]) - - mpz = pos; - } - /* now lock the most popular 'Zero': */ - eq_reg = (ZLOCK_SET_ZERO | mpz); - e100_mdi_write(bdp, - PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, eq_reg); - - /* sleep for 5 minutes: */ - bdp->zlock_sleep_cnt = jiffies; - bdp->zlock_state = ZLOCK_SLEEPING; - /* we will be reading the # of errors after 5 - * minutes, so we need to reset the error - * counters - these registers are self clearing - * on read, so read them */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - - } else { - /* we did not read a 'Zero' value of 0xB or - * above. go back to the start */ - bdp->zlock_state = ZLOCK_INITIAL; - } - - } - break; - - case ZLOCK_SLEEPING: - /* state: sleeping for 5 minutes - * prev states: ZLOCK_READING - * next states: ZLOCK_READING, ZLOCK_SLEEPING */ - - /* if 5 minutes have passed: */ - if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) { - /* read and sum up the number of errors: */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - /* if we've more than 300 errors (this number was - * calculated according to the spec max allowed errors - * (80 errors per 1 million frames) for 5 minutes in - * 100 Mbps (or the user specified max BER number) */ - if (err_cnt > bdp->params.ber) { - /* start again in the next callback: */ - bdp->zlock_state = ZLOCK_INITIAL; - } else { - /* we don't have more errors than allowed, - * sleep for 5 minutes */ - bdp->zlock_sleep_cnt = jiffies; - } - } - break; - - default: - break; - } -} --- linux-2.6.1-rc1/drivers/net/e100/e100_phy.h 2003-06-14 12:17:59.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,158 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_PHY_INC_ -#define _E100_PHY_INC_ - -#include "e100.h" - -/* - * Auto-polarity enable/disable - * e100_autopolarity = 0 => disable auto-polarity - * e100_autopolarity = 1 => enable auto-polarity - * e100_autopolarity = 2 => let software determine - */ -#define E100_AUTOPOLARITY 2 - -#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \ - ((bdp)->pdev->subsystem_device == 0xB0E1)) - -#define PHY_503 0 -#define PHY_100_A 0x000003E0 -#define PHY_100_C 0x035002A8 -#define PHY_NSC_TX 0x5c002000 -#define PHY_82562ET 0x033002A8 -#define PHY_82562EM 0x032002A8 -#define PHY_82562EH 0x017002A8 -#define PHY_82555_TX 0x015002a8 /* added this for 82555 */ -#define PHY_OTHER 0xFFFF -#define MAX_PHY_ADDR 31 -#define MIN_PHY_ADDR 0 - -#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF - -#define PHY_DEFAULT_ADDRESS 1 -#define PHY_ADDRESS_503 32 - -/* MDI Control register bit definitions */ -#define MDI_PHY_READY BIT_28 /* PHY is ready for next MDI cycle */ - -#define MDI_NC3133_CONFIG_REG 0x19 -#define MDI_NC3133_100FX_ENABLE BIT_2 -#define MDI_NC3133_INT_ENABLE_REG 0x17 -#define MDI_NC3133_INT_ENABLE BIT_1 - -/* MDI Control register opcode definitions */ -#define MDI_WRITE 1 /* Phy Write */ -#define MDI_READ 2 /* Phy read */ - -/* MDI register set*/ -#define AUTO_NEG_NEXT_PAGE_REG 0x07 /* Auto-negotiation next page xmit */ -#define EXTENDED_REG_0 0x10 /* Extended reg 0 (Phy 100 modes) */ -#define EXTENDED_REG_1 0x14 /* Extended reg 1 (Phy 100 error indications) */ -#define NSC_CONG_CONTROL_REG 0x17 /* National (TX) congestion control */ -#define NSC_SPEED_IND_REG 0x19 /* National (TX) speed indication */ - -#define HWI_CONTROL_REG 0x1D /* HWI Control register */ -/* MDI/MDI-X Control Register bit definitions */ -#define MDI_MDIX_RES_TIMER BIT_0_3 /* minimum slot time for resolution timer */ -#define MDI_MDIX_CONFIG_IS_OK BIT_4 /* 1 = resolution algorithm completes OK */ -#define MDI_MDIX_STATUS BIT_5 /* 1 = MDIX (croos over), 0 = MDI (straight through) */ -#define MDI_MDIX_SWITCH BIT_6 /* 1 = Forces to MDIX, 0 = Forces to MDI */ -#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7 /* 1 = MDI/MDI-X feature enabled */ -#define MDI_MDIX_CONCT_CONFIG BIT_8 /* Sets the MDI/MDI-X connectivity configuration (test prupose only) */ -#define MDI_MDIX_CONCT_TEST_ENABLE BIT_9 /* 1 = Enables connectivity testing */ -#define MDI_MDIX_RESET_ALL_MASK 0x0000 - -/* HWI Control Register bit definitions */ -#define HWI_TEST_DISTANCE BIT_0_8 /* distance to cable problem */ -#define HWI_TEST_HIGHZ_PROBLEM BIT_9 /* 1 = Open Circuit */ -#define HWI_TEST_LOWZ_PROBLEM BIT_10 /* 1 = Short Circuit */ -#define HWI_TEST_RESERVED (BIT_11 | BIT_12) /* reserved */ -#define HWI_TEST_EXECUTE BIT_13 /* 1 = Execute the HWI test on the PHY */ -#define HWI_TEST_ABILITY BIT_14 /* 1 = test passed */ -#define HWI_TEST_ENABLE BIT_15 /* 1 = Enables the HWI feature */ -#define HWI_RESET_ALL_MASK 0x0000 - -/* ############Start of 82555 specific defines################## */ - -/* Intel 82555 specific registers */ -#define PHY_82555_CSR 0x10 /* 82555 CSR */ -#define PHY_82555_SPECIAL_CONTROL 0x11 /* 82555 special control register */ - -#define PHY_82555_RCV_ERR 0x15 /* 82555 100BaseTx Receive Error - * Frame Counter */ -#define PHY_82555_SYMBOL_ERR 0x16 /* 82555 RCV Symbol Error Counter */ -#define PHY_82555_PREM_EOF_ERR 0x17 /* 82555 100BaseTx RCV Premature End - * of Frame Error Counter */ -#define PHY_82555_EOF_COUNTER 0x18 /* 82555 end of frame error counter */ -#define PHY_82555_MDI_EQUALIZER_CSR 0x1a /* 82555 specific equalizer reg. */ - -/* 82555 CSR bits */ -#define PHY_82555_SPEED_BIT BIT_1 -#define PHY_82555_POLARITY_BIT BIT_8 - -/* 82555 equalizer reg. opcodes */ -#define ENABLE_ZERO_FORCING 0x2010 /* write to ASD conf. reg. 0 */ -#define DISABLE_ZERO_FORCING 0x2000 /* write to ASD conf. reg. 0 */ - -/* 82555 special control reg. opcodes */ -#define DISABLE_AUTO_POLARITY 0x0010 -#define EXTENDED_SQUELCH_BIT BIT_2 - -/* ############End of 82555 specific defines##################### */ - -/* Auto-Negotiation advertisement register bit definitions*/ -#define NWAY_AD_FC_SUPPORTED 0x0400 /* Flow Control supported */ - -/* Auto-Negotiation link partner ability register bit definitions*/ -#define NWAY_LP_ABILITY 0x07e0 /* technologies supported */ - -/* PHY 100 Extended Register 0 bit definitions*/ -#define PHY_100_ER0_FDX_INDIC BIT_0 /* 1 = FDX, 0 = half duplex */ -#define PHY_100_ER0_SPEED_INDIC BIT_1 /* 1 = 100Mbps, 0= 10Mbps */ - -/* National Semiconductor TX phy congestion control register bit definitions*/ -#define NSC_TX_CONG_TXREADY BIT_10 /* Makes TxReady an input */ -#define NSC_TX_CONG_ENABLE BIT_8 /* Enables congestion control */ - -/* National Semiconductor TX phy speed indication register bit definitions*/ -#define NSC_TX_SPD_INDC_SPEED BIT_6 /* 0 = 100Mbps, 1=10Mbps */ - -/************* function prototypes ************/ -extern unsigned char e100_phy_init(struct e100_private *bdp); -extern unsigned char e100_update_link_state(struct e100_private *bdp); -extern unsigned char e100_phy_check(struct e100_private *bdp); -extern void e100_phy_set_speed_duplex(struct e100_private *bdp, - unsigned char force_restart); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern int e100_mdi_write(struct e100_private *, u32, u32, u16); -extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *); - -#endif --- linux-2.6.1-rc1/drivers/net/e100/e100_test.c 2003-06-14 12:18:08.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,500 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" -#include "e100_config.h" - -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8, u8); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern void e100_force_speed_duplex(struct e100_private *bdp); - -static u8 e100_diag_selftest(struct net_device *); -static u8 e100_diag_eeprom(struct net_device *); -static u8 e100_diag_loopback(struct net_device *); - -static u8 e100_diag_one_loopback (struct net_device *, u8); -static u8 e100_diag_rcv_loopback_pkt(struct e100_private *); -static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *); -static u8 e100_diag_loopback_alloc(struct e100_private *); -static void e100_diag_loopback_cu_ru_exec(struct e100_private *); -static u8 e100_diag_check_pkt(u8 *); -static void e100_diag_loopback_free(struct e100_private *); -static int e100_cable_diag(struct e100_private *bdp); - -#define LB_PACKET_SIZE 1500 - -/** - * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines - * @dev: atapter's net device data struct - * @test_info: array with test request mask also used to store test results - * - * RETURNS: updated flags field of struct ethtool_test - */ -u32 -e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) -{ - struct e100_private* bdp = dev->priv; - u8 test_result = 0; - - if (!e100_get_link_state(bdp)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_link] = true; - } - if (!e100_diag_eeprom(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_eeprom] = true; - } - if (flags & ETH_TEST_FL_OFFLINE) { - u8 fail_mask; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - } - if (e100_diag_selftest(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_self_test] = true; - } - - fail_mask = e100_diag_loopback(dev); - if (fail_mask) { - test_result = ETH_TEST_FL_FAILED; - if (fail_mask & PHY_LOOPBACK) - test_info[test_loopback_phy] = true; - if (fail_mask & MAC_LOOPBACK) - test_info[test_loopback_mac] = true; - } - - test_info[cable_diag] = e100_cable_diag(bdp); - /* Need hw init regardless of netif_running */ - e100_hw_init(bdp); - if (netif_running(dev)) { - e100_open(dev); - } - } - else { - test_info[test_self_test] = false; - test_info[test_loopback_phy] = false; - test_info[test_loopback_mac] = false; - test_info[cable_diag] = false; - } - - return flags | test_result; -} - -/** - * e100_diag_selftest - run hardware selftest - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_selftest(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u32 st_timeout, st_result; - u8 retval = 0; - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (!st_timeout) { - if (st_result & CB_SELFTEST_REGISTER_BIT) - retval |= REGISTER_TEST_FAIL; - if (st_result & CB_SELFTEST_DIAG_BIT) - retval |= SELF_TEST_FAIL; - if (st_result & CB_SELFTEST_ROM_BIT) - retval |= ROM_TEST_FAIL; - } else { - retval = TEST_TIMEOUT; - } - } - - return retval; -} - -/** - * e100_diag_eeprom - validate eeprom checksum correctness - * @dev: atapter's net device data struct - * - */ -static u8 -e100_diag_eeprom (struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u16 i, eeprom_sum, eeprom_actual_csm; - - for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) { - eeprom_sum += e100_eeprom_read(bdp, i); - } - - eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1); - - if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) { - return true; - } - - return false; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_loopback (struct net_device *dev) -{ - u8 rc = 0; - - printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) { - rc |= PHY_LOOPBACK; - } - printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name); - - printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) { - rc |= MAC_LOOPBACK; - } - printk(KERN_DEBUG "%s: MAC loopback test ends\n", dev->name); - - return rc; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - * @mode: lopback test type - */ -static u8 -e100_diag_one_loopback (struct net_device *dev, u8 mode) -{ - struct e100_private *bdp = dev->priv; - u8 res = false; - u8 saved_dynamic_tbd = false; - u8 saved_extended_tcb = false; - - if (!e100_diag_loopback_alloc(bdp)) - return false; - - /* change the config block to standard tcb and the correct loopback */ - e100_diag_config_loopback(bdp, true, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - - e100_diag_loopback_cu_ru_exec(bdp); - - if (e100_diag_rcv_loopback_pkt(bdp)) { - res = true; - } - - e100_diag_loopback_free(bdp); - - /* change the config block to previous tcb mode and the no loopback */ - e100_diag_config_loopback(bdp, false, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - return res; -} - -/** - * e100_diag_config_loopback - setup/clear loopback before/after lpbk test - * @bdp: atapter's private data struct - * @set_loopback: true if the function is called to set lb - * @loopback_mode: the loopback mode(MAC or PHY) - * @tcb_extended: true if need to set extended tcb mode after clean loopback - * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback - * - */ -void -e100_diag_config_loopback(struct e100_private* bdp, - u8 set_loopback, - u8 loopback_mode, - u8* tcb_extended, - u8* dynamic_tbd) -{ - /* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd. - * the previous values are saved in the params tcb_extended/dynamic_tbd - * if set_loopback == false - we want to restore previous value. - */ - if (set_loopback || (*tcb_extended)) - *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended); - - if (set_loopback || (*dynamic_tbd)) - *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); - - if (set_loopback) { - /* ICH PHY loopback is broken */ - if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK) - loopback_mode = MAC_LOOPBACK; - /* Configure loopback on MAC */ - e100_config_loopback_mode(bdp,loopback_mode); - } else { - e100_config_loopback_mode(bdp,NO_LOOPBACK); - } - - e100_config(bdp); - - if (loopback_mode == PHY_LOOPBACK) { - if (set_loopback) - /* Set PHY loopback mode */ - e100_phy_set_loopback(bdp); - else - /* Reset PHY loopback mode */ - e100_phy_reset(bdp); - /* Wait for PHY state change */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } else { /* For MAC loopback wait 500 msec to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); - } -} - -/** - * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback - * @bdp: atapter's private data struct - * - */ -static u8 -e100_diag_loopback_alloc(struct e100_private *bdp) -{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - tbd_t *tbd; - - /* tcb, tbd and transmit buffer are allocated */ - tcb = pci_alloc_consistent(bdp->pdev, - (sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE), - &dma_handle); - if (tcb == NULL) - return false; - - memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE); - tcb->tcb_phys = dma_handle; - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_hdr.cb_cmd = - cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); - /* Next command is null */ - tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff); - tcb->tcb_cnt = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_tbd_num = 1; - /* Set up tcb tbd pointer */ - tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); - tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); - /* Set up tbd transmit buffer */ - tbd->tbd_buf_addr = - cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); - tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); - /* The value of first 512 bytes is FF */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512); - /* The value of second 512 bytes is BA */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512); - wmb(); - rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); - - if (rfd == NULL) { - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE, tcb, tcb->tcb_phys); - return false; - } - - memset(rfd, 0x00, sizeof (rfd_t)); - - /* init all fields in rfd */ - rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); - rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE); - /* dma_handle is physical address of rfd */ - bdp->loopback.dma_handle = dma_handle; - bdp->loopback.tcb = tcb; - bdp->loopback.rfd = rfd; - wmb(); - return true; -} - -/** - * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) -{ - /*load CU & RU base */ - if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0)) - printk(KERN_ERR "e100: SCB_RUC_START failed!\n"); - - bdp->next_cu_cmd = START_WAIT; - e100_start_cu(bdp, bdp->loopback.tcb); - bdp->last_tcb = NULL; - rmb(); -} -/** - * e100_diag_check_pkt - checks if a given packet is a loopback packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_check_pkt(u8 *datap) -{ - int i; - for (i = 0; i<512; i++) { - if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) { - printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i); - return false; - } - } - printk (KERN_DEBUG "e100: Check received loopback packet OK\n"); - return true; -} - -/** - * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_rcv_loopback_pkt(struct e100_private* bdp) -{ - rfd_t *rfdp; - u16 rfd_status; - unsigned long expires = jiffies + HZ * 2; - - rfdp =bdp->loopback.rfd; - - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - - while (!(rfd_status & RFD_STATUS_COMPLETE)) { - if (time_before(jiffies, expires)) { - yield(); - rmb(); - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - } else { - break; - } - } - - if (rfd_status & RFD_STATUS_COMPLETE) { - printk(KERN_DEBUG "e100: Loopback packet received\n"); - return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size)); - } - else { - printk(KERN_ERR "e100: Loopback packet not received\n"); - return false; - } -} - -/** - * e100_diag_loopback_free - free data allocated for loopback pkt send/receive - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_free (struct e100_private *bdp) -{ - pci_free_consistent(bdp->pdev, - sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE, - bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys); - - pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd, - bdp->loopback.dma_handle); -} - -static int -e100_cable_diag(struct e100_private *bdp) -{ - int saved_open_circut = 0xffff; - int saved_short_circut = 0xffff; - int saved_distance = 0xffff; - int saved_same = 0; - int cable_status = E100_CABLE_UNKNOWN; - int i; - - /* If we have link, */ - if (e100_get_link_state(bdp)) - return E100_CABLE_OK; - - if (bdp->rev_id < D102_REV_ID) - return E100_CABLE_UNKNOWN; - - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - /* Set to 100 Full as required by cable test */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_SPEED100 | BMCR_FULLDPLX); - - /* Test up to 100 times */ - for (i = 0; i < 100; i++) { - u16 ctrl_reg; - int distance, open_circut, short_circut, near_end; - - /* Enable and execute cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, - (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); - /* Wait for cable test finished */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100 + 1); - /* Read results */ - e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); - distance = ctrl_reg & HWI_TEST_DISTANCE; - open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; - short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; - - if ((distance == saved_distance) && - (open_circut == saved_open_circut) && - (short_circut == saved_short_circut)) - saved_same++; - else { - saved_same = 0; - saved_distance = distance; - saved_open_circut = open_circut; - saved_short_circut = short_circut; - } - /* If results are the same 3 times */ - if (saved_same == 3) { - near_end = ((distance * HWI_REGISTER_GRANULARITY) < - HWI_NEAR_END_BOUNDARY); - if (open_circut) - cable_status = (near_end) ? - E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; - if (short_circut) - cable_status = (near_end) ? - E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; - break; - } - } - /* Reset cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); - return cable_status; -} - --- linux-2.6.1-rc1/drivers/net/e100/e100_ucode.h 2003-06-14 12:18:34.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,365 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - 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. - - 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. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_UCODE_H_ -#define _E100_UCODE_H_ - -/* -e100_ucode.h - -This file contains the loadable micro code arrays to implement receive -bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, -D102 B-step, D102 B-step with TCO work around and D102 C-step. - -Each controller has its own specific micro code array. The array for one -controller is totally incompatible with any other controller, and if used -will most likely cause the controller to lock up and stop responding to -the driver. Each micro code array has its own parameter offsets (described -below), and they each have their own version number. -*/ - -/************************************************************************* -* CPUSaver parameters -* -* All CPUSaver parameters are 16-bit literals that are part of a -* "move immediate value" instruction. By changing the value of -* the literal in the instruction before the code is loaded, the -* driver can change algorithm. -* -* CPUSAVER_DWORD - This is the location of the instruction that loads -* the dead-man timer with its inital value. By writing a 16-bit -* value to the low word of this instruction, the driver can change -* the timer value. The current default is either x600 or x800; -* experiments show that the value probably should stay within the -* range of x200 - x1000. -* -* CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction -* that sets the maximum number of frames that will be bundled. In -* some situations, such as the TCP windowing algorithm, it may be -* better to limit the growth of the bundle size than let it go as -* high as it can, because that could cause too much added latency. -* The default is six, because this is the number of packets in the -* default TCP window size. A value of 1 would make CPUSaver indicate -* an interrupt for every frame received. If you do not want to put -* a limit on the bundle size, set this value to xFFFF. -* -* CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction -* that contains a bit-mask describing the minimum size frame that -* will be bundled. The default masks the lower 7 bits, which means -* that any frame less than 128 bytes in length will not be bundled, -* but will instead immediately generate an interrupt. This does -* not affect the current bundle in any way. Any frame that is 128 -* bytes or large will be bundled normally. This feature is meant -* to provide immediate indication of ACK frames in a TCP environment. -* Customers were seeing poor performance when a machine with CPUSaver -* enabled was sending but not receiving. The delay introduced when -* the ACKs were received was enough to reduce total throughput, because -* the sender would sit idle until the ACK was finally seen. -* -* The current default is 0xFF80, which masks out the lower 7 bits. -* This means that any frame which is x7F (127) bytes or smaller -* will cause an immediate interrupt. Because this value must be a -* bit mask, there are only a few valid values that can be used. To -* turn this feature off, the driver can write the value xFFFF to the -* lower word of this instruction (in the same way that the other -* parameters are used). Likewise, a value of 0xF800 (2047) would -* cause an interrupt to be generated for every frame, because all -* standard Ethernet frames are <= 2047 bytes in length. -*************************************************************************/ - -#ifndef UCODE_MAX_DWORDS -#define UCODE_MAX_DWORDS 134 -#endif - -/********************************************************/ -/* CPUSaver micro code for the D101A */ -/********************************************************/ - -/* Version 2.0 */ - -/* This value is the same for both A and B step of 558. */ - -#define D101_CPUSAVER_TIMER_DWORD 72 -#define D101_CPUSAVER_BUNDLE_DWORD UCODE_MAX_DWORDS -#define D101_CPUSAVER_MIN_SIZE_DWORD UCODE_MAX_DWORDS - -#define D101_A_RCVBUNDLE_UCODE \ -{\ -0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \ -0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \ -0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \ -0x00101213, 0x00041000, 0x0038051E, 0x00101313, \ -0x00010400, 0x00380521, 0x00050600, 0x00100824, \ -0x00101310, 0x00041000, 0x00080600, 0x00101B10, \ -0x0038051E, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101B */ -/********************************************************/ - -/* Version 2.0 */ - -#define D101_B0_RCVBUNDLE_UCODE \ -{\ -0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \ -0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \ -0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \ -0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \ -0x00010400, 0x00380522, 0x00050600, 0x00100837, \ -0x00101310, 0x00041000, 0x00080600, 0x00101790, \ -0x0038051F, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101M (B-step only) */ -/********************************************************/ - -/* Version 2.10.1 */ - -/* Parameter values for the D101M B-step */ -#define D101M_CPUSAVER_TIMER_DWORD 78 -#define D101M_CPUSAVER_BUNDLE_DWORD 65 -#define D101M_CPUSAVER_MIN_SIZE_DWORD 126 - -#define D101M_B_RCVBUNDLE_UCODE \ -{\ -0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \ -0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \ -0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \ -0x00380438, 0x00000000, 0x00140000, 0x00380555, \ -0x00308000, 0x00100662, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \ -0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \ -0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \ -0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \ -0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \ -0x00041000, 0x00010004, 0x00130826, 0x000C0006, \ -0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380C34, 0x00000000, 0x00000000, \ -0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \ -0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \ -0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \ -0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \ -0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \ -0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \ -0x00130826, 0x000C0001, 0x00220559, 0x00101313, \ -0x00380559, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00130831, 0x0010090B, 0x00124813, \ -0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \ -0x003806A8, 0x00000000, 0x00000000, 0x00000000, \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101S */ -/********************************************************/ - -/* Version 1.20.1 */ - -/* Parameter values for the D101S */ -#define D101S_CPUSAVER_TIMER_DWORD 78 -#define D101S_CPUSAVER_BUNDLE_DWORD 67 -#define D101S_CPUSAVER_MIN_SIZE_DWORD 128 - -#define D101S_RCVBUNDLE_UCODE \ -{\ -0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \ -0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \ -0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \ -0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \ -0x00308000, 0x00100610, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \ -0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \ -0x003A047E, 0x00044010, 0x00380819, 0x00000000, \ -0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \ -0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \ -0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \ -0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \ -0x00101313, 0x00380700, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \ -0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \ -0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \ -0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \ -0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \ -0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \ -0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \ -0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \ -0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00130831, \ -0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \ -0x00041000, 0x00010004, 0x00380700 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D102 B-step */ -/********************************************************/ - -/* Version 2.0 */ -/* Parameter values for the D102 B-step */ -#define D102_B_CPUSAVER_TIMER_DWORD 82 -#define D102_B_CPUSAVER_BUNDLE_DWORD 106 -#define D102_B_CPUSAVER_MIN_SIZE_DWORD 70 - -#define D102_B_RCVBUNDLE_UCODE \ -{\ -0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \ -0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \ -0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \ -0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \ -0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \ -0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \ -0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \ -0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \ -0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \ -0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \ -0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \ -0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \ -0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \ -0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \ -0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \ -0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \ -0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \ -0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \ -0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \ -0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \ -0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \ -0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \ -0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \ -} - -/********************************************************/ -/* Micro code for the D102 C-step */ -/********************************************************/ - -/* Parameter values for the D102 C-step */ -#define D102_C_CPUSAVER_TIMER_DWORD 46 -#define D102_C_CPUSAVER_BUNDLE_DWORD 74 -#define D102_C_CPUSAVER_MIN_SIZE_DWORD 54 - -#define D102_C_RCVBUNDLE_UCODE \ -{ \ -0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \ -0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \ -0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \ -0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \ -0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \ -0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \ -0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \ -0x00E00E85, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* Micro code for the D102 E-step */ -/********************************************************/ - -/* Parameter values for the D102 E-step */ -#define D102_E_CPUSAVER_TIMER_DWORD 42 -#define D102_E_CPUSAVER_BUNDLE_DWORD 54 -#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46 - -#define D102_E_RCVBUNDLE_UCODE \ -{\ -0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \ -0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \ -0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \ -0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \ -0x00300006, 0x00E014FB, 0x00000000, 0x00000000 \ -} - -#endif /* _E100_UCODE_H_ */ --- linux-2.6.1-rc1/drivers/net/e100/LICENSE 2003-06-14 12:18:24.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,339 +0,0 @@ - -"This software program is licensed subject to the GNU General Public License -(GPL). Version 2, June 1991, available at -" - -GNU General Public License - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is intended -to guarantee your freedom to share and change free software--to make sure -the software is free for all its users. This General Public License applies -to most of the Free Software Foundation's software and to any other program -whose authors commit to using it. (Some other Free Software Foundation -software is covered by the GNU Library General Public License instead.) You -can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom -to distribute copies of free software (and charge for this service if you -wish), that you receive source code or can get it if you want it, that you -can change the software or use pieces of it in new free programs; and that -you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to -deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you distribute -copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or -for a fee, you must give the recipients all the rights that you have. You -must make sure that they, too, receive or can get the source code. And you -must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If -the software is modified by someone else and passed on, we want its -recipients to know that what they have is not the original, so that any -problems introduced by others will not reflect on the original authors' -reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must be -licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice - placed by the copyright holder saying it may be distributed under the - terms of this General Public License. The "Program", below, refers to any - such program or work, and a "work based on the Program" means either the - Program or any derivative work under copyright law: that is to say, a - work containing the Program or a portion of it, either verbatim or with - modifications and/or translated into another language. (Hereinafter, - translation is included without limitation in the term "modification".) - Each licensee is addressed as "you". - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of running - the Program is not restricted, and the output from the Program is covered - only if its contents constitute a work based on the Program (independent - of having been made by running the Program). Whether that is true depends - on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source code - as you receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice and - disclaimer of warranty; keep intact all the notices that refer to this - License and to the absence of any warranty; and give any other recipients - of the Program a copy of this License along with the Program. - - You may charge a fee for the physical act of transferring a copy, and you - may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, - thus forming a work based on the Program, and copy and distribute such - modifications or work under the terms of Section 1 above, provided that - you also meet all of these conditions: - - * a) You must cause the modified files to carry prominent notices stating - that you changed the files and the date of any change. - - * b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - * c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive - use in the most ordinary way, to print or display an announcement - including an appropriate copyright notice and a notice that there is - no warranty (or else, saying that you provide a warranty) and that - users may redistribute the program under these conditions, and - telling the user how to view a copy of this License. (Exception: if - the Program itself is interactive but does not normally print such - an announcement, your work based on the Program is not required to - print an announcement.) - - These requirements apply to the modified work as a whole. If identifiable - sections of that work are not derived from the Program, and can be - reasonably considered independent and separate works in themselves, then - this License, and its terms, do not apply to those sections when you - distribute them as separate works. But when you distribute the same - sections as part of a whole which is a work based on the Program, the - distribution of the whole must be on the terms of this License, whose - permissions for other licensees extend to the entire whole, and thus to - each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Program. - - In addition, mere aggregation of another work not based on the Program - with the Program (or with a work based on the Program) on a volume of a - storage or distribution medium does not bring the other work under the - scope of this License. - -3. You may copy and distribute the Program (or a work based on it, under - Section 2) in object code or executable form under the terms of Sections - 1 and 2 above provided that you also do one of the following: - - * a) Accompany it with the complete corresponding machine-readable source - code, which must be distributed under the terms of Sections 1 and 2 - above on a medium customarily used for software interchange; or, - - * b) Accompany it with a written offer, valid for at least three years, - to give any third party, for a charge no more than your cost of - physically performing source distribution, a complete machine- - readable copy of the corresponding source code, to be distributed - under the terms of Sections 1 and 2 above on a medium customarily - used for software interchange; or, - - * c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - - The source code for a work means the preferred form of the work for - making modifications to it. For an executable work, complete source code - means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to control - compilation and installation of the executable. However, as a special - exception, the source code distributed need not include anything that is - normally distributed (in either source or binary form) with the major - components (compiler, kernel, and so on) of the operating system on which - the executable runs, unless that component itself accompanies the - executable. - - If distribution of executable or object code is made by offering access - to copy from a designated place, then offering equivalent access to copy - the source code from the same place counts as distribution of the source - code, even though third parties are not compelled to copy the source - along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as - expressly provided under this License. Any attempt otherwise to copy, - modify, sublicense or distribute the Program is void, and will - automatically terminate your rights under this License. However, parties - who have received copies, or rights, from you under this License will not - have their licenses terminated so long as such parties remain in full - compliance. - -5. You are not required to accept this License, since you have not signed - it. However, nothing else grants you permission to modify or distribute - the Program or its derivative works. These actions are prohibited by law - if you do not accept this License. Therefore, by modifying or - distributing the Program (or any work based on the Program), you - indicate your acceptance of this License to do so, and all its terms and - conditions for copying, distributing or modifying the Program or works - based on it. - -6. Each time you redistribute the Program (or any work based on the - Program), the recipient automatically receives a license from the - original licensor to copy, distribute or modify the Program subject to - these terms and conditions. You may not impose any further restrictions - on the recipients' exercise of the rights granted herein. You are not - responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot distribute - so as to satisfy simultaneously your obligations under this License and - any other pertinent obligations, then as a consequence you may not - distribute the Program at all. For example, if a patent license would - not permit royalty-free redistribution of the Program by all those who - receive copies directly or indirectly through you, then the only way you - could satisfy both it and this License would be to refrain entirely from - distribution of the Program. - - If any portion of this section is held invalid or unenforceable under any - particular circumstance, the balance of the section is intended to apply - and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system, which is implemented - by public license practices. Many people have made generous contributions - to the wide range of software distributed through that system in - reliance on consistent application of that system; it is up to the - author/donor to decide if he or she is willing to distribute software - through any other system and a licensee cannot impose that choice. - - This section is intended to make thoroughly clear what is believed to be - a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain - countries either by patents or by copyrighted interfaces, the original - copyright holder who places the Program under this License may add an - explicit geographical distribution limitation excluding those countries, - so that distribution is permitted only in or among countries not thus - excluded. In such case, this License incorporates the limitation as if - written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new versions of - the General Public License from time to time. Such new versions will be - similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the Program - specifies a version number of this License which applies to it and "any - later version", you have the option of following the terms and - conditions either of that version or of any later version published by - the Free Software Foundation. If the Program does not specify a version - number of this License, you may choose any version ever published by the - Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs - whose distribution conditions are different, write to the author to ask - for permission. For software which is copyrighted by the Free Software - Foundation, write to the Free Software Foundation; we sometimes make - exceptions for this. Our decision will be guided by the two goals of - preserving the free status of all derivatives of our free software and - of promoting the sharing and reuse of software generally. - - NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER - EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE - ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH - YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL - NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR - DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL - DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM - (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED - INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF - THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR - OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it free -software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey the -exclusion of warranty; and each file should have at least the "copyright" -line and a pointer to where the full notice is found. - -one line to give the program's name and an idea of what it does. -Copyright (C) yyyy name of author - -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. - -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. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when -it starts in an interactive mode: - -Gnomovision version 69, Copyright (C) year name of author Gnomovision comes -with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free -software, and you are welcome to redistribute it under certain conditions; -type 'show c' for details. - -The hypothetical commands 'show w' and 'show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may be -called something other than 'show w' and 'show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in the program -'Gnomovision' (which makes passes at compilers) written by James Hacker. - -signature of Ty Coon, 1 April 1989 -Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General Public -License instead of this License. --- linux-2.6.1-rc1/drivers/net/e100/Makefile 2003-06-14 12:18:34.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,8 +0,0 @@ -# -# Makefile for the Intel's E100 ethernet driver -# - -obj-$(CONFIG_E100) += e100.o - -e100-objs := e100_main.o e100_config.o e100_phy.o \ - e100_eeprom.o e100_test.o --- linux-2.6.1-rc1/drivers/net/e2100.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/e2100.c 2003-12-30 22:49:19.000000000 -0800 @@ -95,7 +95,6 @@ static inline void mem_off(short port) #define E21_BIG_RX_STOP_PG 0xF0 /* Last page +1 of RX ring */ #define E21_TX_START_PG E21_RX_STOP_PG /* First page of TX buffer */ -int e2100_probe(struct net_device *dev); static int e21_probe1(struct net_device *dev, int ioaddr); static int e21_open(struct net_device *dev); @@ -117,10 +116,11 @@ static int e21_close(struct net_device * station address). */ -int __init e2100_probe(struct net_device *dev) +static int __init do_e2100_probe(struct net_device *dev) { int *port; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -129,13 +129,46 @@ int __init e2100_probe(struct net_devic else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (port = e21_probe_list; *port; port++) + for (port = e21_probe_list; *port; port++) { + dev->irq = irq; if (e21_probe1(dev, *port) == 0) return 0; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: e21_close() handles free_irq */ + release_region(dev->base_addr, E21_IO_EXTENT); +} + +struct net_device * __init e2100_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_e2100_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init e21_probe1(struct net_device *dev, int ioaddr) { int i, status, retval; @@ -175,13 +208,6 @@ static int __init e21_probe1(struct net_ for (i = 0; i < 6; i++) printk(" %02X", station_addr[i]); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - if (dev->irq < 2) { int irqlist[] = {15,11,10,12,5,9,3,4}, i; for (i = 0; i < 8; i++) @@ -191,8 +217,6 @@ static int __init e21_probe1(struct net_ } if (i >= 8) { printk(" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -376,7 +400,7 @@ e21_close(struct net_device *dev) #ifdef MODULE #define MAX_E21_CARDS 4 /* Max number of E21 cards per module */ -static struct net_device dev_e21[MAX_E21_CARDS]; +static struct net_device *dev_e21[MAX_E21_CARDS]; static int io[MAX_E21_CARDS]; static int irq[MAX_E21_CARDS]; static int mem[MAX_E21_CARDS]; @@ -398,29 +422,35 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { - struct net_device *dev = &dev_e21[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ - dev->init = e2100_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ + if (do_e2100_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_e21[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -429,13 +459,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { - struct net_device *dev = &dev_e21[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - /* NB: e21_close() handles free_irq */ - release_region(dev->base_addr, E21_IO_EXTENT); + struct net_device *dev = dev_e21[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/eepro100.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/eepro100.c 2003-12-30 22:49:19.000000000 -0800 @@ -542,6 +542,7 @@ static int speedo_start_xmit(struct sk_b static void speedo_refill_rx_buffers(struct net_device *dev, int force); static int speedo_rx(struct net_device *dev); static void speedo_tx_buffer_gc(struct net_device *dev); +static void poll_speedo (struct net_device *dev); static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int speedo_close(struct net_device *dev); static struct net_device_stats *speedo_get_stats(struct net_device *dev); @@ -885,6 +886,9 @@ static int __devinit speedo_found1(struc dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_speedo; +#endif if (register_netdevice(dev)) goto err_free_unlock; @@ -1675,6 +1679,23 @@ static irqreturn_t speedo_interrupt(int return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_speedo (struct net_device *dev) +{ + /* disable_irq is not very nice, but with the funny lockless design + we have no other choice. */ + disable_irq(dev->irq); + speedo_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) { struct speedo_private *sp = (struct speedo_private *)dev->priv; --- linux-2.6.1-rc1/drivers/net/eepro.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/eepro.c 2003-12-30 22:49:19.000000000 -0800 @@ -302,9 +302,7 @@ struct eepro_local { /* Index to functions, as function prototypes. */ -extern int eepro_probe(struct net_device *dev); - -static int eepro_probe1(struct net_device *dev, short ioaddr); +static int eepro_probe1(struct net_device *dev, int autoprobe); static int eepro_open(struct net_device *dev); static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -527,10 +525,11 @@ buffer (transmit-buffer = 32K - receive- If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ -int __init eepro_probe(struct net_device *dev) +static int __init do_eepro_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -563,24 +562,48 @@ int __init eepro_probe(struct net_device #endif if (base_addr > 0x1ff) /* Check a single specified location. */ - return eepro_probe1(dev, base_addr); + return eepro_probe1(dev, 0); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; eepro_portlist[i]; i++) { - int ioaddr = eepro_portlist[i]; - - if (check_region(ioaddr, EEPRO_IO_EXTENT)) - continue; - if (eepro_probe1(dev, ioaddr) == 0) + dev->base_addr = eepro_portlist[i]; + dev->irq = irq; + if (eepro_probe1(dev, 1) == 0) return 0; } return -ENODEV; } +struct net_device * __init eepro_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + SET_MODULE_OWNER(dev); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_eepro_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, EEPRO_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static void __init printEEPROMInfo(short ioaddr, struct net_device *dev) { unsigned short Word; @@ -713,83 +736,75 @@ static void eepro_print_info (struct net probes on the ISA bus. A good device probe avoids doing writes, and verifies that the correct device exists and functions. */ -static int __init eepro_probe1(struct net_device *dev, short ioaddr) +static int __init eepro_probe1(struct net_device *dev, int autoprobe) { unsigned short station_addr[6], id, counter; - int i, j, irqMask, retval = 0; + int i; struct eepro_local *lp; enum iftype { AUI=0, BNC=1, TPE=2 }; + int ioaddr = dev->base_addr; + + /* Grab the region so we can find another board if autoIRQ fails. */ + if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { + if (!autoprobe) + printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", + ioaddr); + return -EBUSY; + } /* Now, we are going to check for the signature of the ID_REG (register 2 of bank 0) */ - id=inb(ioaddr + ID_REG); + id = inb(ioaddr + ID_REG); - if (((id) & ID_REG_MASK) != ID_REG_SIG) { - retval = -ENODEV; + if ((id & ID_REG_MASK) != ID_REG_SIG) goto exit; - } - /* We seem to have the 82595 signature, let's - play with its counter (last 2 bits of - register 2 of bank 0) to be sure. */ + /* We seem to have the 82595 signature, let's + play with its counter (last 2 bits of + register 2 of bank 0) to be sure. */ - counter = (id & R_ROBIN_BITS); - - if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS)!=(counter + 0x40)) { - retval = -ENODEV; - goto exit; - } + counter = id & R_ROBIN_BITS; - /* Initialize the device structure */ - dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); - if (!dev->priv) { - retval = -ENOMEM; + if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40)) goto exit; - } - - memset(dev->priv, 0, sizeof(struct eepro_local)); - - lp = (struct eepro_local *)dev->priv; - /* default values */ - lp->eepro = 0; + lp = (struct eepro_local *)dev->priv; + memset(lp, 0, sizeof(struct eepro_local)); lp->xmt_bar = XMT_BAR_PRO; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; lp->eeprom_reg = EEPROM_REG_PRO; + spin_lock_init(&lp->lock); - /* Now, get the ethernet hardware address from - the EEPROM */ - station_addr[0] = read_eeprom(ioaddr, 2, dev); - - /* FIXME - find another way to know that we've found - * an Etherexpress 10 - */ - if (station_addr[0] == 0x0000 || - station_addr[0] == 0xffff) { - lp->eepro = LAN595FX_10ISA; + /* Now, get the ethernet hardware address from + the EEPROM */ + station_addr[0] = read_eeprom(ioaddr, 2, dev); + + /* FIXME - find another way to know that we've found + * an Etherexpress 10 + */ + if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) { + lp->eepro = LAN595FX_10ISA; lp->eeprom_reg = EEPROM_REG_10; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; lp->xmt_bar = XMT_BAR_10; - station_addr[0] = read_eeprom(ioaddr, 2, dev); - } - station_addr[1] = read_eeprom(ioaddr, 3, dev); - station_addr[2] = read_eeprom(ioaddr, 4, dev); + station_addr[0] = read_eeprom(ioaddr, 2, dev); + } + station_addr[1] = read_eeprom(ioaddr, 3, dev); + station_addr[2] = read_eeprom(ioaddr, 4, dev); if (!lp->eepro) { if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) lp->eepro = 2; else if (station_addr[2] == SA_ADDR1) lp->eepro = 1; - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; + } + /* Fill in the 'dev' fields. */ for (i=0; i < 6; i++) - dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; + dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; /* RX buffer must be more than 3K and less than 29K */ if (dev->mem_end < 3072 || dev->mem_end > 29696) @@ -798,65 +813,49 @@ static int __init eepro_probe1(struct ne /* calculate {xmt,rcv}_{lower,upper}_limit */ eepro_recalc(dev); - - if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) - dev->if_port = BNC; + if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) + dev->if_port = BNC; else dev->if_port = TPE; - if ((dev->irq < 2) && (lp->eepro!=0)) { - i = read_eeprom(ioaddr, 1, dev); - irqMask = read_eeprom(ioaddr, 7, dev); - i &= 0x07; /* Mask off INT number */ - - for (j=0; ((j<16) && (i>=0)); j++) { - if ((irqMask & (1<irq = j; - break; /* found bit corresponding to irq */ - } - i--; /* count bits set in irqMask */ - } - } - if (dev->irq < 2) { - printk(KERN_ERR " Duh! invalid interrupt vector stored in EEPROM.\n"); - retval = -ENODEV; - goto freeall; - } else - if (dev->irq==2) dev->irq = 9; - } - - /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { - printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); - goto freeall; - } - ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; - - dev->open = eepro_open; - dev->stop = eepro_close; - dev->hard_start_xmit = eepro_send_packet; - dev->get_stats = eepro_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->tx_timeout = eepro_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Fill in the fields of the device structure with - ethernet generic values */ - ether_setup(dev); - + if (dev->irq < 2 && lp->eepro != 0) { + /* Mask off INT number */ + int count = read_eeprom(ioaddr, 1, dev) & 7; + unsigned irqMask = read_eeprom(ioaddr, 7, dev); + + while (count--) + irqMask &= irqMask - 1; + + count = ffs(irqMask); + + if (count) + dev->irq = count - 1; + + if (dev->irq < 2) { + printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n"); + goto exit; + } else if (dev->irq == 2) { + dev->irq = 9; + } + } + + dev->open = eepro_open; + dev->stop = eepro_close; + dev->hard_start_xmit = eepro_send_packet; + dev->get_stats = eepro_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = eepro_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + /* print boot time info */ eepro_print_info(dev); /* reset 82595 */ - eepro_reset(ioaddr); - + eepro_reset(ioaddr); + return 0; exit: - return retval; -freeall: - kfree(dev->priv); - goto exit; - + release_region(dev->base_addr, EEPRO_IO_EXTENT); + return -ENODEV; } /* Open/initialize the board. This is called (in the current kernel) @@ -1701,7 +1700,7 @@ eepro_transmit_interrupt(struct net_devi #ifdef MODULE #define MAX_EEPRO 8 -static struct net_device dev_eepro[MAX_EEPRO]; +static struct net_device *dev_eepro[MAX_EEPRO]; static int io[MAX_EEPRO]; static int irq[MAX_EEPRO]; @@ -1729,6 +1728,7 @@ MODULE_PARM_DESC(autodetect, "EtherExpre int init_module(void) { + struct net_device *dev; int i; if (io[0] == 0 && autodetect == 0) { printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n"); @@ -1743,17 +1743,24 @@ init_module(void) } for (i = 0; i < MAX_EEPRO; i++) { - struct net_device *d = &dev_eepro[n_eepro]; - d->mem_end = mem[i]; - d->base_addr = io[i]; - d->irq = irq[i]; - d->init = eepro_probe; - - if (register_netdev(d) == 0) - n_eepro++; - else - break; + dev = alloc_etherdev(sizeof(struct eepro_local)); + if (!dev) + break; + + dev->mem_end = mem[i]; + dev->base_addr = io[i]; + dev->irq = irq[i]; + + if (do_eepro_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_eepro[n_eepro++] = dev; + continue; + } + release_region(dev->base_addr, EEPRO_IO_EXTENT); } + free_netdev(dev); + break; + } if (n_eepro) printk(KERN_INFO "%s", version); @@ -1767,15 +1774,10 @@ cleanup_module(void) int i; for (i=0; ipriv); - d->priv=NULL; - - /* If we don't do this, we can't re-insmod it later. */ - release_region(d->base_addr, EEPRO_IO_EXTENT); - + struct net_device *dev = dev_eepro[i]; + unregister_netdev(dev); + release_region(dev->base_addr, EEPRO_IO_EXTENT); + free_netdev(dev); } } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/eexpress.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/eexpress.c 2003-12-30 22:49:19.000000000 -0800 @@ -244,7 +244,6 @@ static char mca_irqmap[] = { 12, 9, 3, 4 * Prototypes for Linux interface */ -extern int express_probe(struct net_device *dev); static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); @@ -334,11 +333,13 @@ static inline unsigned short int SHADOW( * checks for presence of EtherExpress card */ -int __init express_probe(struct net_device *dev) +static int __init do_express_probe(struct net_device *dev) { unsigned short *port; static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; + int dev_irq = dev->irq; + int err; SET_MODULE_OWNER(dev); @@ -391,27 +392,58 @@ int __init express_probe(struct net_devi } } #endif - if (ioaddr&0xfe00) - return eexp_hw_probe(dev,ioaddr); - else if (ioaddr) + if (ioaddr&0xfe00) { + if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) + return -EBUSY; + err = eexp_hw_probe(dev,ioaddr); + release_region(ioaddr, EEXP_IO_EXTENT); + return err; + } else if (ioaddr) return -ENXIO; for (port=&ports[0] ; *port ; port++ ) { unsigned short sum = 0; int i; + if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress")) + continue; for ( i=0 ; i<4 ; i++ ) { unsigned short t; t = inb(*port + ID_PORT); sum |= (t>>4) << ((t & 0x03)<<2); } - if (sum==0xbaba && !eexp_hw_probe(dev,*port)) + if (sum==0xbaba && !eexp_hw_probe(dev,*port)) { + release_region(*port, EEXP_IO_EXTENT); return 0; + } + release_region(*port, EEXP_IO_EXTENT); + dev->irq = dev_irq; } return -ENODEV; } +struct net_device * __init express_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_express_probe(dev); + if (!err) { + err = register_netdev(dev); + if (!err) + return dev; + } + free_netdev(dev); + return ERR_PTR(err); +} + /* * open and initialize the adapter, ready for use */ @@ -1058,7 +1090,7 @@ static int __init eexp_hw_probe(struct n unsigned int memory_size; int i; unsigned short xsum = 0; - struct net_local *lp; + struct net_local *lp = dev->priv; printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr); @@ -1108,17 +1140,18 @@ static int __init eexp_hw_probe(struct n buswidth = !((setupval & 0x400) >> 10); } - dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - - memset(dev->priv, 0, sizeof(struct net_local)); + memset(lp, 0, sizeof(struct net_local)); spin_lock_init(&lp->lock); printk("(IRQ %d, %s connector, %d-bit bus", dev->irq, eexp_ifmap[dev->if_port], buswidth?8:16); + if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress")) + return -EBUSY; + eexp_hw_set_interface(dev); + + release_region(dev->base_addr + 0x300e, 1); /* Find out how much RAM we have on the card */ outw(0, dev->base_addr + WRITE_PTR); @@ -1156,7 +1189,6 @@ static int __init eexp_hw_probe(struct n break; default: printk(") bad memory size (%dk).\n", memory_size); - kfree(dev->priv); return -ENODEV; break; } @@ -1171,7 +1203,6 @@ static int __init eexp_hw_probe(struct n dev->set_multicast_list = &eexp_set_multicast; dev->tx_timeout = eexp_timeout; dev->watchdog_timeo = 2*HZ; - ether_setup(dev); return 0; } @@ -1654,7 +1685,7 @@ eexp_set_multicast(struct net_device *de #define EEXP_MAX_CARDS 4 /* max number of cards to support */ -static struct net_device dev_eexp[EEXP_MAX_CARDS]; +static struct net_device *dev_eexp[EEXP_MAX_CARDS]; static int irq[EEXP_MAX_CARDS]; static int io[EEXP_MAX_CARDS]; @@ -1671,25 +1702,30 @@ MODULE_LICENSE("GPL"); */ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_eexp[this_dev]; + dev = alloc_etherdev(sizeof(struct net_local)); dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->init = express_probe; if (io[this_dev] == 0) { - if (this_dev) break; + if (this_dev) + break; printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); - if (found != 0) return 0; - return -ENXIO; + if (do_express_probe(dev) == 0 && register_netdev(dev) == 0) { + dev_eexp[this_dev] = dev; + found++; + continue; } - found++; + printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -1697,11 +1733,10 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_eexp[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_eexp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/eql.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/eql.c 2003-12-30 22:49:19.000000000 -0800 @@ -600,7 +600,7 @@ static int __init eql_init_module(void) err = register_netdev(dev_eql); if (err) - kfree(dev_eql); + free_netdev(dev_eql); return err; } --- linux-2.6.1-rc1/drivers/net/es3210.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/es3210.c 2003-12-30 22:49:19.000000000 -0800 @@ -62,7 +62,6 @@ static const char version[] = #include "8390.h" -int es_probe(struct net_device *dev); static int es_probe1(struct net_device *dev, int ioaddr); static int es_open(struct net_device *dev); @@ -125,9 +124,11 @@ static unsigned char hi_irq_map[] __init * PROM for a match against the Racal-Interlan assigned value. */ -int __init es_probe(struct net_device *dev) +static int __init do_es_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; SET_MODULE_OWNER(dev); @@ -144,13 +145,47 @@ int __init es_probe(struct net_device *d } /* EISA spec allows for up to 16 slots, but 8 is typical. */ - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (es_probe1(dev, ioaddr) == 0) return 0; + dev->irq = irq; + dev->mem_start = mem_start; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, ES_IO_EXTENT); +} + +struct net_device * __init es_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_es_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -240,13 +275,6 @@ static int __init es_probe1(struct net_d printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out1; - } - #if ES_DEBUG & ES_D_PROBE if (inb(ioaddr + ES_CFG5)) printk("es3210: Warning - DMA channel enabled, but not used here.\n"); @@ -376,7 +404,7 @@ static int es_close(struct net_device *d #ifdef MODULE #define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */ #define NAMELEN 8 /* # of chars for storing dev->name */ -static struct net_device dev_es3210[MAX_ES_CARDS]; +static struct net_device *dev_es3210[MAX_ES_CARDS]; static int io[MAX_ES_CARDS]; static int irq[MAX_ES_CARDS]; static int mem[MAX_ES_CARDS]; @@ -393,26 +421,32 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { - struct net_device *dev = &dev_es3210[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ - dev->init = es_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev->mem_start = mem[this_dev]; + if (do_es_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_es3210[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -421,13 +455,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { - struct net_device *dev = &dev_es3210[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(dev->base_addr, ES_IO_EXTENT); + struct net_device *dev = dev_es3210[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/eth16i.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/eth16i.c 2003-12-30 22:49:19.000000000 -0800 @@ -369,7 +369,6 @@ static unsigned int eth32i_irqmap[] __in #define NUM_OF_EISA_IRQS 8 static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 }; -static unsigned int boot = 1; /* Use 0 for production, 1 for verification, >2 for debug */ #ifndef ETH16I_DEBUG @@ -395,8 +394,6 @@ struct eth16i_local { /* Function prototypes */ -extern int eth16i_probe(struct net_device *dev); - static int eth16i_probe1(struct net_device *dev, int ioaddr); static int eth16i_check_signature(int ioaddr); static int eth16i_probe_port(int ioaddr); @@ -418,7 +415,7 @@ static void eth16i_timeout(struct net static void eth16i_skip_packet(struct net_device *dev); static void eth16i_multicast(struct net_device *dev); static void eth16i_select_regbank(unsigned char regbank, int ioaddr); -static void eth16i_initialize(struct net_device *dev); +static void eth16i_initialize(struct net_device *dev, int boot); #if 0 static int eth16i_set_irq(struct net_device *dev); @@ -432,7 +429,7 @@ static struct net_device_stats *eth16i_g static char cardname[] __initdata = "ICL EtherTeam 16i/32"; -int __init eth16i_probe(struct net_device *dev) +static int __init do_eth16i_probe(struct net_device *dev) { int i; int ioaddr; @@ -461,14 +458,38 @@ int __init eth16i_probe(struct net_devic return -ENODEV; } +struct net_device * __init eth16i_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_eth16i_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, ETH16I_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init eth16i_probe1(struct net_device *dev, int ioaddr) { - struct eth16i_local *lp; + struct eth16i_local *lp = dev->priv; static unsigned version_printed; int retval; - boot = 1; /* To inform initilization that we are in boot probe */ - /* Let's grab the region */ if (!request_region(ioaddr, ETH16I_IO_EXTENT, dev->name)) return -EBUSY; @@ -531,22 +552,13 @@ static int __init eth16i_probe1(struct n eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); - eth16i_initialize(dev); /* Initialize rest of the chip's registers */ + eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */ /* Now let's same some energy by shutting down the chip ;) */ BITCLR(ioaddr + CONFIG_REG_1, POWERUP); /* Initialize the device structure */ - if(dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL); - if(dev->priv == NULL) { - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto out; - } - } - - memset(dev->priv, 0, sizeof(struct eth16i_local)); + memset(lp, 0, sizeof(struct eth16i_local)); dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; @@ -554,15 +566,7 @@ static int __init eth16i_probe1(struct n dev->set_multicast_list = eth16i_multicast; dev->tx_timeout = eth16i_timeout; dev->watchdog_timeo = TX_TIMEOUT; - - lp = (struct eth16i_local *)dev->priv; spin_lock_init(&lp->lock); - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - boot = 0; - return 0; out: release_region(ioaddr, ETH16I_IO_EXTENT); @@ -570,7 +574,7 @@ out: } -static void eth16i_initialize(struct net_device *dev) +static void eth16i_initialize(struct net_device *dev, int boot) { int ioaddr = dev->base_addr; int i, node_w = 0; @@ -953,7 +957,7 @@ static int eth16i_open(struct net_device outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); /* Initialize the chip */ - eth16i_initialize(dev); + eth16i_initialize(dev, 0); /* Set the transmit buffer size */ lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03]; @@ -1401,7 +1405,7 @@ static ushort eth16i_parse_mediatype(con #define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */ -static struct net_device dev_eth16i[MAX_ETH16I_CARDS]; +static struct net_device *dev_eth16i[MAX_ETH16I_CARDS]; static int io[MAX_ETH16I_CARDS]; #if 0 static int irq[MAX_ETH16I_CARDS]; @@ -1431,14 +1435,14 @@ MODULE_PARM_DESC(debug, "eth16i debug le int init_module(void) { int this_dev, found = 0; + struct net_device *dev; + + for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { + dev = alloc_etherdev(sizeof(struct eth16i_local)); + if (!dev) + break; - for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) - { - struct net_device *dev = &dev_eth16i[this_dev]; - - dev->irq = 0; /* irq[this_dev]; */ dev->base_addr = io[this_dev]; - dev->init = eth16i_probe; if(debug != -1) eth16i_debug = debug; @@ -1448,44 +1452,43 @@ int init_module(void) dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]); - if(io[this_dev] == 0) - { - if(this_dev != 0) break; /* Only autoprobe 1st one */ + if(io[this_dev] == 0) { + if(this_dev != 0) /* Only autoprobe 1st one */ + break; printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n"); } - if(register_netdev(dev) != 0) - { - printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", - io[this_dev]); - - if(found != 0) return 0; - return -ENXIO; + if (do_eth16i_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_eth16i[found++] = dev; + continue; + } + free_irq(dev->irq, dev); + release_region(dev->base_addr, ETH16I_IO_EXTENT); } - - found++; + printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", + io[this_dev]); + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) { int this_dev; - for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) - { - struct net_device* dev = &dev_eth16i[this_dev]; + for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { + struct net_device *dev = dev_eth16i[this_dev]; - if(dev->priv != NULL) - { + if(dev->priv) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - free_irq(dev->irq, dev); release_region(dev->base_addr, ETH16I_IO_EXTENT); - + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/ethertap.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/ethertap.c 2003-12-30 22:49:19.000000000 -0800 @@ -72,8 +72,7 @@ static int __init ethertap_probe(int un struct net_device *dev; int err = -ENOMEM; - dev = alloc_netdev(sizeof(struct net_local), "tap%d", - ether_setup); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) goto out; --- linux-2.6.1-rc1/drivers/net/ewrk3.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ewrk3.c 2003-12-30 22:49:19.000000000 -0800 @@ -324,25 +324,14 @@ static int Read_EEPROM(u_long iobase, u_ static int Write_EEPROM(short data, u_long iobase, u_char eaddr); static u_char get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType); -static void isa_probe(struct net_device *dev, u_long iobase); -static void eisa_probe(struct net_device *dev, u_long iobase); -static struct net_device *alloc_device(struct net_device *dev, u_long iobase); -static int ewrk3_dev_index(char *s); -static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)); +static int ewrk3_probe1(struct net_device *dev, u_long iobase, int irq); +static int isa_probe(struct net_device *dev, u_long iobase); +static int eisa_probe(struct net_device *dev, u_long iobase); - -#ifdef MODULE -static int autoprobed = 1, loading_module = 1; - -#else -static u_char irq[] = -{5, 0, 10, 3, 11, 9, 15, 12}; -static int autoprobed, loading_module; - -#endif /* MODULE */ +static u_char irq[MAX_NUM_EWRK3S+1] = {5, 0, 10, 3, 11, 9, 15, 12}; static char name[EWRK3_STRLEN + 1]; -static int num_ewrk3s, num_eth; +static int num_ewrks3s; /* ** Miscellaneous defines... @@ -352,38 +341,50 @@ static int num_ewrk3s, num_eth; mdelay(1);\ } -int __init ewrk3_probe(struct net_device *dev) +struct net_device * __init ewrk3_probe(int unit) { - int tmp = num_ewrk3s, status = -ENODEV; - u_long iobase = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - if ((iobase == 0) && loading_module) { - printk("Autoprobing is not supported when loading a module based driver.\n"); - status = -EIO; - } else { /* First probe for the Ethernet */ - /* Address PROM pattern */ - isa_probe(dev, iobase); - eisa_probe(dev, iobase); - - if ((tmp == num_ewrk3s) && (iobase != 0) && loading_module) { - printk("%s: ewrk3_probe() cannot find device at 0x%04lx.\n", dev->name, - iobase); - } - /* - ** Walk the device list to check that at least one device - ** initialised OK - */ - for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); + err = ewrk3_probe1(dev, dev->base_addr, dev->irq); + if (err) + goto out; + return dev; +out: + free_netdev(dev); + return ERR_PTR(err); + +} - if (dev->priv) - status = 0; - if (iobase == 0) - autoprobed = 1; - } +static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq) +{ + int err; - return status; + dev->base_addr = iobase; + dev->irq = irq; + + /* Address PROM pattern */ + err = isa_probe(dev, iobase); + if (err != 0) + err = eisa_probe(dev, iobase); + + if (err) + return err; + + err = register_netdev(dev); + if (err) + release_region(dev->base_addr, EWRK3_TOTAL_SIZE); + + return err; } static int __init @@ -396,8 +397,8 @@ ewrk3_hw_init(struct net_device *dev, u_ u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; /* - ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. - ** This also disables the EISA_ENABLE bit in the EISA Control Register. + ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. + ** This also disables the EISA_ENABLE bit in the EISA Control Register. */ if (iobase > 0x400) eisa_cr = inb(EISA_CR); @@ -409,232 +410,210 @@ ewrk3_hw_init(struct net_device *dev, u_ icr &= 0x70; outb(icr, EWRK3_ICR); /* Disable all the IRQs */ - if (nicsr == (CSR_TXD | CSR_RXD)) { + if (nicsr == (CSR_TXD | CSR_RXD)) + return -ENXIO; - /* Check that the EEPROM is alive and well and not living on Pluto... */ - for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { - union { - short val; - char c[2]; - } tmp; - - tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); - eeprom_image[i] = tmp.c[0]; - eeprom_image[i + 1] = tmp.c[1]; - chksum += eeprom_image[i] + eeprom_image[i + 1]; - } - - if (chksum != 0) { /* Bad EEPROM Data! */ - printk("%s: Device has a bad on-board EEPROM.\n", dev->name); - status = -ENXIO; - } else { - EthwrkSignature(name, eeprom_image); - if (*name != '\0') { /* found a EWRK3 device */ - dev->base_addr = iobase; - - if (iobase > 0x400) { - outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ - } - lemac = eeprom_image[EEPROM_CHIPVER]; - cmr = inb(EWRK3_CMR); - - if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || - ((lemac == LeMAC2) && !(cmr & CMR_HS))) { - printk("%s: %s at %#4lx", dev->name, name, iobase); - hard_strapped = 1; - } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { - /* EISA slot address */ - printk("%s: %s at %#4lx (EISA slot %ld)", - dev->name, name, iobase, ((iobase >> 12) & 0x0f)); - } else { /* ISA port address */ - printk("%s: %s at %#4lx", dev->name, name, iobase); - } - - if (!status) { - printk(", h/w address "); - if (lemac != LeMAC2) - DevicePresent(iobase); /* need after EWRK3_INIT */ - status = get_hw_addr(dev, eeprom_image, lemac); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); - if (status) { - printk(" which has an EEPROM CRC error.\n"); - status = -ENXIO; - } else { - if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ - cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); - if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) - cmr |= CMR_RA; - if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) - cmr |= CMR_WB; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) - cmr |= CMR_POLARITY; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) - cmr |= CMR_LINK; - if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) - cmr |= CMR_0WS; - } - if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) - cmr |= CMR_DRAM; - outb(cmr, EWRK3_CMR); - - cr = inb(EWRK3_CR); /* Set up the Control Register */ - cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; - if (cr & SETUP_APD) - cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; - cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; - cr |= eeprom_image[EEPROM_MISC0] & ENA_16; - outb(cr, EWRK3_CR); + /* Check that the EEPROM is alive and well and not living on Pluto... */ + for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { + union { + short val; + char c[2]; + } tmp; + + tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); + eeprom_image[i] = tmp.c[0]; + eeprom_image[i + 1] = tmp.c[1]; + chksum += eeprom_image[i] + eeprom_image[i + 1]; + } + + if (chksum != 0) { /* Bad EEPROM Data! */ + printk("%s: Device has a bad on-board EEPROM.\n", dev->name); + return -ENXIO; + } + + EthwrkSignature(name, eeprom_image); + if (*name == '\0') + return -ENXIO; + + dev->base_addr = iobase; + + if (iobase > 0x400) { + outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ + } + lemac = eeprom_image[EEPROM_CHIPVER]; + cmr = inb(EWRK3_CMR); + + if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || + ((lemac == LeMAC2) && !(cmr & CMR_HS))) { + printk("%s: %s at %#4lx", dev->name, name, iobase); + hard_strapped = 1; + } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { + /* EISA slot address */ + printk("%s: %s at %#4lx (EISA slot %ld)", + dev->name, name, iobase, ((iobase >> 12) & 0x0f)); + } else { /* ISA port address */ + printk("%s: %s at %#4lx", dev->name, name, iobase); + } + + printk(", h/w address "); + if (lemac != LeMAC2) + DevicePresent(iobase); /* need after EWRK3_INIT */ + status = get_hw_addr(dev, eeprom_image, lemac); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ + printk("%2.2x:", dev->dev_addr[i]); + } + printk("%2.2x,\n", dev->dev_addr[i]); + + if (status) { + printk(" which has an EEPROM CRC error.\n"); + return -ENXIO; + } + + if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ + cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); + if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) + cmr |= CMR_RA; + if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) + cmr |= CMR_WB; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) + cmr |= CMR_POLARITY; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) + cmr |= CMR_LINK; + if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) + cmr |= CMR_0WS; + } + if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) + cmr |= CMR_DRAM; + outb(cmr, EWRK3_CMR); + + cr = inb(EWRK3_CR); /* Set up the Control Register */ + cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; + if (cr & SETUP_APD) + cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; + cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; + cr |= eeprom_image[EEPROM_MISC0] & ENA_16; + outb(cr, EWRK3_CR); - /* - ** Determine the base address and window length for the EWRK3 - ** RAM from the memory base register. - */ - mem_start = inb(EWRK3_MBR); - shmem_length = 0; - if (mem_start != 0) { - if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { - mem_start *= SHMEM_64K; - shmem_length = SHMEM_64K; - } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { - mem_start *= SHMEM_32K; - shmem_length = SHMEM_32K; - } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { - mem_start = mem_start * SHMEM_2K + 0x80000; - shmem_length = SHMEM_2K; - } else { - status = -ENXIO; - } - } - /* - ** See the top of this source code for comments about - ** uncommenting this line. - */ + /* + ** Determine the base address and window length for the EWRK3 + ** RAM from the memory base register. + */ + mem_start = inb(EWRK3_MBR); + shmem_length = 0; + if (mem_start != 0) { + if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { + mem_start *= SHMEM_64K; + shmem_length = SHMEM_64K; + } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { + mem_start *= SHMEM_32K; + shmem_length = SHMEM_32K; + } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { + mem_start = mem_start * SHMEM_2K + 0x80000; + shmem_length = SHMEM_2K; + } else { + return -ENXIO; + } + } + /* + ** See the top of this source code for comments about + ** uncommenting this line. + */ /* FORCE_2K_MODE; */ + + if (hard_strapped) { + printk(" is hard strapped.\n"); + } else if (mem_start) { + printk(" has a %dk RAM window", (int) (shmem_length >> 10)); + printk(" at 0x%.5lx", mem_start); + } else { + printk(" is in I/O only mode"); + } - if (!status) { - if (hard_strapped) { - printk(" is hard strapped.\n"); - } else if (mem_start) { - printk(" has a %dk RAM window", (int) (shmem_length >> 10)); - printk(" at 0x%.5lx", mem_start); - } else { - printk(" is in I/O only mode"); - } - - /* private area & initialise */ - dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), - GFP_KERNEL); - if (dev->priv == NULL) { - return -ENOMEM; - } - lp = (struct ewrk3_private *) dev->priv; - memset(dev->priv, 0, sizeof(struct ewrk3_private)); - lp->shmem_base = mem_start; - lp->shmem_length = shmem_length; - lp->lemac = lemac; - lp->hard_strapped = hard_strapped; - lp->led_mask = CR_LED; - spin_lock_init(&lp->hw_lock); - - lp->mPage = 64; - if (cmr & CMR_DRAM) - lp->mPage <<= 1; /* 2 DRAMS on module */ - - sprintf(lp->adapter_name, "%s (%s)", name, dev->name); - request_region(iobase, EWRK3_TOTAL_SIZE, lp->adapter_name); - - lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; - - if (!hard_strapped) { - /* - ** Enable EWRK3 board interrupts for autoprobing - */ - icr |= ICR_IE; /* Enable interrupts */ - outb(icr, EWRK3_ICR); - - /* The DMA channel may be passed in on this parameter. */ - dev->dma = 0; - - /* To auto-IRQ we enable the initialization-done and DMA err, - interrupts. For now we will always get a DMA error. */ - if (dev->irq < 2) { + lp = (struct ewrk3_private *) dev->priv; + lp->shmem_base = mem_start; + lp->shmem_length = shmem_length; + lp->lemac = lemac; + lp->hard_strapped = hard_strapped; + lp->led_mask = CR_LED; + spin_lock_init(&lp->hw_lock); + + lp->mPage = 64; + if (cmr & CMR_DRAM) + lp->mPage <<= 1; /* 2 DRAMS on module */ + + sprintf(lp->adapter_name, "%s (%s)", name, dev->name); + + lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; + + if (!hard_strapped) { + /* + ** Enable EWRK3 board interrupts for autoprobing + */ + icr |= ICR_IE; /* Enable interrupts */ + outb(icr, EWRK3_ICR); + + /* The DMA channel may be passed in on this parameter. */ + dev->dma = 0; + + /* To auto-IRQ we enable the initialization-done and DMA err, + interrupts. For now we will always get a DMA error. */ + if (dev->irq < 2) { #ifndef MODULE - u_char irqnum; - unsigned long irq_mask; + u_char irqnum; + unsigned long irq_mask; - irq_mask = probe_irq_on(); - - /* - ** Trigger a TNE interrupt. - */ - icr |= ICR_TNEM; - outb(1, EWRK3_TDQ); /* Write to the TX done queue */ - outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ - - irqnum = irq[((icr & IRQ_SEL) >> 4)]; - - mdelay(20); - dev->irq = probe_irq_off(irq_mask); - if ((dev->irq) && (irqnum == dev->irq)) { - printk(" and uses IRQ%d.\n", dev->irq); - } else { - if (!dev->irq) { - printk(" and failed to detect IRQ line.\n"); - } else if ((irqnum == 1) && (lemac == LeMAC2)) { - printk(" and an illegal IRQ line detected.\n"); - } else { - printk(", but incorrect IRQ line detected.\n"); - } - status = -ENXIO; - } - - DISABLE_IRQs; /* Mask all interrupts */ - -#endif /* MODULE */ - } else { - printk(" and requires IRQ%d.\n", dev->irq); - } - } - if (status) - release_region(iobase, EWRK3_TOTAL_SIZE); - } else { - status = -ENXIO; - } - } - } + irq_mask = probe_irq_on(); + + /* + ** Trigger a TNE interrupt. + */ + icr |= ICR_TNEM; + outb(1, EWRK3_TDQ); /* Write to the TX done queue */ + outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ + + irqnum = irq[((icr & IRQ_SEL) >> 4)]; + + mdelay(20); + dev->irq = probe_irq_off(irq_mask); + if ((dev->irq) && (irqnum == dev->irq)) { + printk(" and uses IRQ%d.\n", dev->irq); } else { - status = -ENXIO; - } - } - - if (!status) { - if (ewrk3_debug > 1) { - printk(version); + if (!dev->irq) { + printk(" and failed to detect IRQ line.\n"); + } else if ((irqnum == 1) && (lemac == LeMAC2)) { + printk(" and an illegal IRQ line detected.\n"); + } else { + printk(", but incorrect IRQ line detected.\n"); + } + return -ENXIO; } - /* The EWRK3-specific entries in the device structure. */ - dev->open = ewrk3_open; - dev->hard_start_xmit = ewrk3_queue_pkt; - dev->stop = ewrk3_close; - dev->get_stats = ewrk3_get_stats; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = ewrk3_ioctl; - dev->tx_timeout = ewrk3_timeout; - dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; - dev->mem_start = 0; + DISABLE_IRQs; /* Mask all interrupts */ - /* Fill in the generic field of the device structure. */ - ether_setup(dev); +#endif /* MODULE */ + } else { + printk(" and requires IRQ%d.\n", dev->irq); } - } else { - status = -ENXIO; } - return status; + + if (ewrk3_debug > 1) { + printk(version); + } + /* The EWRK3-specific entries in the device structure. */ + dev->open = ewrk3_open; + dev->hard_start_xmit = ewrk3_queue_pkt; + dev->stop = ewrk3_close; + dev->get_stats = ewrk3_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->do_ioctl = ewrk3_ioctl; + dev->tx_timeout = ewrk3_timeout; + dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; + + dev->mem_start = 0; + + return 0; } @@ -1269,15 +1248,15 @@ static void SetMulticastFilter(struct ne /* ** ISA bus I/O device probe */ -static void __init isa_probe(struct net_device *dev, u_long ioaddr) +static int __init isa_probe(struct net_device *dev, u_long ioaddr) { - int i = num_ewrk3s, maxSlots; + int i = num_ewrks3s, maxSlots; + int ret = -ENODEV; + u_long iobase; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ if (ioaddr >= 0x400) - return; /* Not ISA */ + goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EWRK3_IO_BASE; /* Get the first slot address */ @@ -1287,38 +1266,37 @@ static void __init isa_probe(struct net_ maxSlots = i + 1; } - for (; (i < maxSlots) && (dev != NULL); iobase += EWRK3_IOP_INC, i++) { - if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { + for (; (i < maxSlots) && (dev != NULL); + iobase += EWRK3_IOP_INC, i++) + { + if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name)) { if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (ewrk3_hw_init(dev, iobase) == 0) { - num_ewrk3s++; - } - num_eth++; - } + int irq = dev->irq; + ret = ewrk3_hw_init(dev, iobase); + if (!ret) + break; + dev->irq = irq; } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + release_region(iobase, EWRK3_TOTAL_SIZE); } } + out: - return; + return ret; } /* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. */ -static void __init eisa_probe(struct net_device *dev, u_long ioaddr) +static int __init eisa_probe(struct net_device *dev, u_long ioaddr) { int i, maxSlots; u_long iobase; - char name[EWRK3_STRLEN]; + int ret = -ENODEV; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ if (ioaddr < 0x1000) - return; /* Not EISA */ + goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EISA_SLOT_INC; /* Get the first slot address */ @@ -1332,114 +1310,22 @@ static void __init eisa_probe(struct net for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { if (EISA_signature(name, EISA_ID) == 0) { - if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { - if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (ewrk3_hw_init(dev, iobase) == 0) { - num_ewrk3s++; - } - num_eth++; - } - } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name) && + DevicePresent(iobase) == 0) { + int irq = dev->irq; + ret = ewrk3_hw_init(dev, iobase); + if (!ret) + break; + dev->irq = irq; } + release_region(iobase, EWRK3_TOTAL_SIZE); } } - return; + out: + return ret; } -/* - ** Search the entire 'eth' device list for a fixed probe. If a match isn't - ** found then check for an autoprobe or unused device location. If they - ** are not available then insert a new device structure at the end of - ** the current list. - */ -static struct net_device * __init alloc_device(struct net_device *dev, u_long iobase) -{ - struct net_device *adev = NULL; - int fixed = 0, new_dev = 0; - - num_eth = ewrk3_dev_index(dev->name); - if (loading_module) - return dev; - - while (1) { - if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0)) && !adev) { - adev = dev; - } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "eth", 3) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) - break; - dev = dev->next; - num_eth++; - } - if (adev && !fixed) { - dev = adev; - num_eth = ewrk3_dev_index(dev->name); - new_dev = 0; - } - if (((dev->next == NULL) && - ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_eth++; /* New device */ - dev = insert_device(dev, iobase, ewrk3_probe); - } - return dev; -} - -/* - ** If at end of eth device list and can't use current entry, malloc - ** one up. If memory could not be allocated, print an error message. - */ -static struct net_device * __init -insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)) -{ - struct net_device *new; - - new = (struct net_device *) kmalloc(sizeof(struct net_device) + 8, GFP_KERNEL); - if (new == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", num_eth); - return NULL; - } else { - new->next = dev->next; - dev->next = new; - dev = dev->next; /* point to the new device */ - if (num_eth > 9999) { - sprintf(dev->name, "eth????"); /* New device name */ - } else { - sprintf(dev->name, "eth%d", num_eth); /* New device name */ - } - dev->base_addr = iobase; /* assign the io address */ - dev->init = init; /* initialisation routine */ - } - - return dev; -} - -static int __init -ewrk3_dev_index(char *s) -{ - int i = 0, j = 0; - - for (; *s; s++) { - if (isdigit(*s)) { - j = 1; - i = (i * 10) + (*s - '0'); - } else if (j) - break; - } - - return i; -} /* ** Read the EWRK3 EEPROM using this routine @@ -2074,8 +1960,7 @@ static int ewrk3_ioctl(struct net_device #ifdef MODULE static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S]; static int ndevs; -static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, }; /* or use the insmod io= irq= options */ +static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* '21' below should really be 'MAX_NUM_EWRK3S' */ MODULE_PARM(io, "0-21i"); @@ -2083,50 +1968,39 @@ MODULE_PARM(irq, "0-21i"); MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)"); MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)"); -static void ewrk3_exit_module(void) +static __exit void ewrk3_exit_module(void) { int i; for( i=0; ipriv) { - kfree(ewrk3_devs[i]->priv); - ewrk3_devs[i]->priv = NULL; - } - ewrk3_devs[i]->irq = 0; - release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE); free_netdev(ewrk3_devs[i]); ewrk3_devs[i] = NULL; } } -static int ewrk3_init_module(void) +static __init int ewrk3_init_module(void) { int i=0; while( io[i] && irq[i] ) { - ewrk3_devs[ndevs] = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!ewrk3_devs[ndevs]) - goto error; - memset(ewrk3_devs[ndevs], 0, sizeof(struct net_device)); - ewrk3_devs[ndevs]->base_addr = io[i]; - ewrk3_devs[ndevs]->irq = irq[i]; - ewrk3_devs[ndevs]->init = ewrk3_probe; - - if (register_netdev(ewrk3_devs[ndevs]) == 0) - ndevs++; - else - kfree(ewrk3_devs[ndevs]); + struct net_device *dev + = alloc_etherdev(sizeof(struct ewrk3_private)); + + if (!dev) + break; + if (ewrk3_probe1(dev, io[i], irq[i]) != 0) { + free_netdev(dev); + break; + } + + ewrk3_devs[ndevs++] = dev; i++; } return ndevs ? 0 : -EIO; - -error: - ewrk3_exit_module(); - return -ENOMEM; } --- linux-2.6.1-rc1/drivers/net/fc/iph5526.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/fc/iph5526.c 2003-12-30 22:49:19.000000000 -0800 @@ -259,6 +259,7 @@ static int __init iph5526_probe_pci(stru static int __init fcdev_init(struct net_device *dev) { + SET_MODULE_OWNER(dev); dev->open = iph5526_open; dev->stop = iph5526_close; dev->hard_start_xmit = iph5526_send_packet; @@ -2896,14 +2897,12 @@ static void update_EDB_indx(struct fc_in static int iph5526_open(struct net_device *dev) { netif_start_queue(dev); - MOD_INC_USE_COUNT; return 0; } static int iph5526_close(struct net_device *dev) { netif_stop_queue(dev); - MOD_DEC_USE_COUNT; return 0; } --- linux-2.6.1-rc1/drivers/net/fc/iph5526_scsi.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/net/fc/iph5526_scsi.h 2003-12-30 22:49:19.000000000 -0800 @@ -25,7 +25,7 @@ int iph5526_queuecommand(Scsi_Cmnd *Cmnd int iph5526_release(struct Scsi_Host *host); int iph5526_abort(Scsi_Cmnd *Cmnd); const char *iph5526_info(struct Scsi_Host *host); -int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[]); +int iph5526_biosparam(struct Scsi_Disk * disk, struct block_device *n, int ip[]); #endif --- linux-2.6.1-rc1/drivers/net/fmv18x.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/fmv18x.c 2003-12-30 22:49:19.000000000 -0800 @@ -57,7 +57,7 @@ static const char version[] = #include #include -static int fmv18x_probe_list[] __initdata = { +static unsigned fmv18x_probe_list[] __initdata = { 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0 }; @@ -109,8 +109,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int fmv18x_probe(struct net_device *dev); - static int fmv18x_probe1(struct net_device *dev, short ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -129,23 +127,50 @@ static void set_multicast_list(struct ne (detachable devices only). */ -int __init fmv18x_probe(struct net_device *dev) +static int io = 0x220; +static int irq; + +struct net_device * __init fmv18x_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return fmv18x_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; fmv18x_probe_list[i]; i++) - if (fmv18x_probe1(dev, fmv18x_probe_list[i]) == 0) - return 0; - - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = fmv18x_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = fmv18x_probe_list; *port; port++) + if (fmv18x_probe1(dev, *port) == 0) + break; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, FMV18X_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -160,7 +185,7 @@ static int __init fmv18x_probe1(struct n { char irqmap[4] = {3, 7, 10, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; - unsigned int i, irq, retval; + unsigned int i, retval; struct net_local *lp; /* Resetting the chip doesn't reset the ISA interface, so don't bother. @@ -170,6 +195,9 @@ static int __init fmv18x_probe1(struct n if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name)) return -EBUSY; + dev->irq = irq; + dev->base_addr = ioaddr; + /* Check I/O address configuration and Fujitsu vendor code */ if (inb(ioaddr+FJ_MACADDR ) != 0x00 || inb(ioaddr+FJ_MACADDR+1) != 0x00 @@ -181,9 +209,8 @@ static int __init fmv18x_probe1(struct n /* Check PnP mode for FMV-183/184/183A/184A. */ /* This PnP routine is very poor. IO and IRQ should be known. */ if (inb(ioaddr + FJ_STATUS1) & 0x20) { - irq = dev->irq; for (i = 0; i < 8; i++) { - if (irq == irqmap_pnp[i]) + if (dev->irq == irqmap_pnp[i]) break; } if (i == 8) { @@ -193,22 +220,19 @@ static int __init fmv18x_probe1(struct n } else { if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr) return -ENODEV; - irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; + dev->irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; } /* Snarf the interrupt vector now. */ - retval = request_irq(irq, &net_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); if (retval) { printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on" - "IRQ %d.\n", ioaddr, irq); + "IRQ %d.\n", ioaddr, dev->irq); goto out; } printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name, - ioaddr, irq); - - dev->base_addr = ioaddr; - dev->irq = irq; + ioaddr, dev->irq); for(i = 0; i < 6; i++) { unsigned char val = inb(ioaddr + FJ_MACADDR + i); @@ -279,14 +303,10 @@ static int __init fmv18x_probe1(struct n dev->watchdog_timeo = HZ/10; dev->get_stats = net_get_stats; dev->set_multicast_list = set_multicast_list; - - /* Fill in the fields of 'dev' with ethernet-generic values. */ - - ether_setup(dev); return 0; out_irq: - free_irq(irq, dev); + free_irq(dev->irq, dev); out: release_region(ioaddr, FMV18X_IO_EXTENT); return retval; @@ -413,9 +433,7 @@ static int net_send_packet(struct sk_buf lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; - } else if (lp->tx_queue_len < 4096 - 1502) - /* Yes, there is room for one more packet. */ - else + } else if (lp->tx_queue_len >= 4096 - 1502) /* No room for a packet */ netif_stop_queue(dev); dev_kfree_skb(skb); @@ -628,9 +646,7 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_fmv18x; -static int io = 0x220; -static int irq; +static struct net_device *dev_fmv18x; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -644,26 +660,19 @@ int init_module(void) { if (io == 0) printk("fmv18x: You should not use auto-probing with insmod!\n"); - dev_fmv18x.base_addr = io; - dev_fmv18x.irq = irq; - dev_fmv18x.init = fmv18x_probe; - if (register_netdev(&dev_fmv18x) != 0) { - printk("fmv18x: register_netdev() returned non-zero.\n"); - return -EIO; - } + dev_fmv18x = fmv18x_probe(-1); + if (IS_ERR(dev_fmv18x)) + return PTR_ERR(dev_fmv18x); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_fmv18x); - kfree(dev_fmv18x.priv); - dev_fmv18x.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_fmv18x.irq, &dev_fmv18x); - release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT); + unregister_netdev(dev_fmv18x); + free_irq(dev_fmv18x->irq, dev_fmv18x); + release_region(dev_fmv18x->base_addr, FMV18X_IO_EXTENT); + free_netdev(dev_fmv18x); } #endif /* MODULE */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/net/forcedeth.c 2003-12-30 22:49:19.000000000 -0800 @@ -0,0 +1,1495 @@ +/* + * forcedeth: Ethernet driver for NVIDIA nForce media access controllers. + * + * Note: This driver is a cleanroom reimplementation based on reverse + * engineered documentation written by Carl-Daniel Hailfinger + * and Andrew de Quincey. It's neither supported nor endorsed + * by NVIDIA Corp. Use at your own risk. + * + * NVIDIA, nForce and other NVIDIA marks are trademarks or registered + * trademarks of NVIDIA Corporation in the United States and other + * countries. + * + * Copyright (C) 2003 Manfred Spraul + * + * 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. + * + * 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 + * + * Changelog: + * 0.01: 05 Oct 2003: First release that compiles without warnings. + * 0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs. + * Check all PCI BARs for the register window. + * udelay added to mii_rw. + * 0.03: 06 Oct 2003: Initialize dev->irq. + * 0.04: 07 Oct 2003: Initialize np->lock, reduce handled irqs, add printks. + * 0.05: 09 Oct 2003: printk removed again, irq status print tx_timeout. + * 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated, + * irq mask updated + * 0.07: 14 Oct 2003: Further irq mask updates. + * 0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill + * added into irq handler, NULL check for drain_ring. + * 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the + * requested interrupt sources. + * 0.10: 20 Oct 2003: First cleanup for release. + * 0.11: 21 Oct 2003: hexdump for tx added, rx buffer sizes increased. + * MAC Address init fix, set_multicast cleanup. + * 0.12: 23 Oct 2003: Cleanups for release. + * 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10. + * Set link speed correctly. start rx before starting + * tx (start_rx sets the link speed). + * 0.14: 25 Oct 2003: Nic dependant irq mask. + * 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during + * open. + * 0.16: 15 Nov 2003: include file cleanup for ppc64, rx buffer size + * increased to 1628 bytes. + * 0.17: 16 Nov 2003: undo rx buffer size increase. Substract 1 from + * the tx length. + * 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats + * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac + * addresses, really stop rx if already running + * in start_rx, clean up a bit. + * (C) Carl-Daniel Hailfinger + * + * Known bugs: + * The irq handling is wrong - no tx done interrupts are generated. + * This means recovery from netif_stop_queue only happens in the hw timer + * interrupt (1/2 second on nForce2, 1/100 second on nForce3), or if an + * rx packet arrives by chance. + */ +#define FORCEDETH_VERSION "0.19" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +#define dprintk printk +#else +#define dprintk(x...) do { } while (0) +#endif + + +/* + * Hardware access: + */ + +#define DEV_NEED_LASTPACKET1 0x0001 +#define DEV_IRQMASK_1 0x0002 +#define DEV_IRQMASK_2 0x0004 + +enum { + NvRegIrqStatus = 0x000, +#define NVREG_IRQSTAT_MIIEVENT 0x040 +#define NVREG_IRQSTAT_MASK 0x1ff + NvRegIrqMask = 0x004, +#define NVREG_IRQ_RX 0x0002 +#define NVREG_IRQ_RX_NOBUF 0x0004 +#define NVREG_IRQ_TX_ERR 0x0008 +#define NVREG_IRQ_TX2 0x0010 +#define NVREG_IRQ_TIMER 0x0020 +#define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_TX1 0x0100 +#define NVREG_IRQMASK_WANTED_1 0x005f +#define NVREG_IRQMASK_WANTED_2 0x0147 +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) + + NvRegUnknownSetupReg6 = 0x008, +#define NVREG_UNKSETUP6_VAL 3 + + NvRegPollingInterval = 0x00c, + NvRegMisc1 = 0x080, +#define NVREG_MISC1_HD 0x02 +#define NVREG_MISC1_FORCE 0x3b0f3c + + NvRegTransmitterControl = 0x084, +#define NVREG_XMITCTL_START 0x01 + NvRegTransmitterStatus = 0x088, +#define NVREG_XMITSTAT_BUSY 0x01 + + NvRegPacketFilterFlags = 0x8c, +#define NVREG_PFF_ALWAYS 0x7F0008 +#define NVREG_PFF_PROMISC 0x80 +#define NVREG_PFF_MYADDR 0x20 + + NvRegOffloadConfig = 0x90, +#define NVREG_OFFLOAD_HOMEPHY 0x601 +#define NVREG_OFFLOAD_NORMAL 0x5ee + NvRegReceiverControl = 0x094, +#define NVREG_RCVCTL_START 0x01 + NvRegReceiverStatus = 0x98, +#define NVREG_RCVSTAT_BUSY 0x01 + + NvRegRandomSeed = 0x9c, +#define NVREG_RNDSEED_MASK 0x00ff +#define NVREG_RNDSEED_FORCE 0x7f00 + + NvRegUnknownSetupReg1 = 0xA0, +#define NVREG_UNKSETUP1_VAL 0x16070f + NvRegUnknownSetupReg2 = 0xA4, +#define NVREG_UNKSETUP2_VAL 0x16 + NvRegMacAddrA = 0xA8, + NvRegMacAddrB = 0xAC, + NvRegMulticastAddrA = 0xB0, +#define NVREG_MCASTADDRA_FORCE 0x01 + NvRegMulticastAddrB = 0xB4, + NvRegMulticastMaskA = 0xB8, + NvRegMulticastMaskB = 0xBC, + + NvRegTxRingPhysAddr = 0x100, + NvRegRxRingPhysAddr = 0x104, + NvRegRingSizes = 0x108, +#define NVREG_RINGSZ_TXSHIFT 0 +#define NVREG_RINGSZ_RXSHIFT 16 + NvRegUnknownTransmitterReg = 0x10c, + NvRegLinkSpeed = 0x110, +#define NVREG_LINKSPEED_FORCE 0x10000 +#define NVREG_LINKSPEED_10 10 +#define NVREG_LINKSPEED_100 100 +#define NVREG_LINKSPEED_1000 1000 + NvRegUnknownSetupReg5 = 0x130, +#define NVREG_UNKSETUP5_BIT31 (1<<31) + NvRegUnknownSetupReg3 = 0x134, +#define NVREG_UNKSETUP3_VAL1 0x200010 + NvRegTxRxControl = 0x144, +#define NVREG_TXRXCTL_KICK 0x0001 +#define NVREG_TXRXCTL_BIT1 0x0002 +#define NVREG_TXRXCTL_BIT2 0x0004 +#define NVREG_TXRXCTL_IDLE 0x0008 +#define NVREG_TXRXCTL_RESET 0x0010 + NvRegMIIStatus = 0x180, +#define NVREG_MIISTAT_ERROR 0x0001 +#define NVREG_MIISTAT_LINKCHANGE 0x0008 +#define NVREG_MIISTAT_MASK 0x000f +#define NVREG_MIISTAT_MASK2 0x000f + NvRegUnknownSetupReg4 = 0x184, +#define NVREG_UNKSETUP4_VAL 8 + + NvRegAdapterControl = 0x188, +#define NVREG_ADAPTCTL_START 0x02 +#define NVREG_ADAPTCTL_LINKUP 0x04 +#define NVREG_ADAPTCTL_PHYVALID 0x4000 +#define NVREG_ADAPTCTL_RUNNING 0x100000 +#define NVREG_ADAPTCTL_PHYSHIFT 24 + NvRegMIISpeed = 0x18c, +#define NVREG_MIISPEED_BIT8 (1<<8) +#define NVREG_MIIDELAY 5 + NvRegMIIControl = 0x190, +#define NVREG_MIICTL_INUSE 0x10000 +#define NVREG_MIICTL_WRITE 0x08000 +#define NVREG_MIICTL_ADDRSHIFT 5 + NvRegMIIData = 0x194, + NvRegWakeUpFlags = 0x200, +#define NVREG_WAKEUPFLAGS_VAL 0x7770 +#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24 +#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16 +#define NVREG_WAKEUPFLAGS_D3SHIFT 12 +#define NVREG_WAKEUPFLAGS_D2SHIFT 8 +#define NVREG_WAKEUPFLAGS_D1SHIFT 4 +#define NVREG_WAKEUPFLAGS_D0SHIFT 0 +#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 +#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 +#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 + + NvRegPatternCRC = 0x204, + NvRegPatternMask = 0x208, + NvRegPowerCap = 0x268, +#define NVREG_POWERCAP_D3SUPP (1<<30) +#define NVREG_POWERCAP_D2SUPP (1<<26) +#define NVREG_POWERCAP_D1SUPP (1<<25) + NvRegPowerState = 0x26c, +#define NVREG_POWERSTATE_POWEREDUP 0x8000 +#define NVREG_POWERSTATE_VALID 0x0100 +#define NVREG_POWERSTATE_MASK 0x0003 +#define NVREG_POWERSTATE_D0 0x0000 +#define NVREG_POWERSTATE_D1 0x0001 +#define NVREG_POWERSTATE_D2 0x0002 +#define NVREG_POWERSTATE_D3 0x0003 +}; + +struct ring_desc { + u32 PacketBuffer; + u16 Length; + u16 Flags; +}; + +#define NV_TX_LASTPACKET (1<<0) +#define NV_TX_RETRYERROR (1<<3) +#define NV_TX_LASTPACKET1 (1<<8) +#define NV_TX_DEFERRED (1<<10) +#define NV_TX_CARRIERLOST (1<<11) +#define NV_TX_LATECOLLISION (1<<12) +#define NV_TX_UNDERFLOW (1<<13) +#define NV_TX_ERROR (1<<14) +#define NV_TX_VALID (1<<15) + +#define NV_RX_DESCRIPTORVALID (1<<0) +#define NV_RX_MISSEDFRAME (1<<1) +#define NV_RX_SUBSTRACT1 (1<<3) +#define NV_RX_ERROR1 (1<<7) +#define NV_RX_ERROR2 (1<<8) +#define NV_RX_ERROR3 (1<<9) +#define NV_RX_ERROR4 (1<<10) +#define NV_RX_CRCERR (1<<11) +#define NV_RX_OVERFLOW (1<<12) +#define NV_RX_FRAMINGERR (1<<13) +#define NV_RX_ERROR (1<<14) +#define NV_RX_AVAIL (1<<15) + +/* Miscelaneous hardware related defines: */ +#define NV_PCI_REGSZ 0x270 + +/* various timeout delays: all in usec */ +#define NV_TXRX_RESET_DELAY 4 +#define NV_TXSTOP_DELAY1 10 +#define NV_TXSTOP_DELAY1MAX 500000 +#define NV_TXSTOP_DELAY2 100 +#define NV_RXSTOP_DELAY1 10 +#define NV_RXSTOP_DELAY1MAX 500000 +#define NV_RXSTOP_DELAY2 100 +#define NV_SETUP5_DELAY 5 +#define NV_SETUP5_DELAYMAX 50000 +#define NV_POWERUP_DELAY 5 +#define NV_POWERUP_DELAYMAX 5000 +#define NV_MIIBUSY_DELAY 50 +#define NV_MIIPHY_DELAY 10 +#define NV_MIIPHY_DELAYMAX 10000 + +#define NV_WAKEUPPATTERNS 5 +#define NV_WAKEUPMASKENTRIES 4 + +/* General driver defaults */ +#define NV_WATCHDOG_TIMEO (2*HZ) +#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */ + +#define RX_RING 128 +#define TX_RING 16 +/* limited to 1 packet until we understand NV_TX_LASTPACKET */ +#define TX_LIMIT_STOP 10 +#define TX_LIMIT_START 5 + +/* rx/tx mac addr + type + vlan + align + slack*/ +#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64) +/* even more slack */ +#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128) + +#define OOM_REFILL (1+HZ/20) +#define POLL_WAIT (1+HZ/100) + +/* + * SMP locking: + * All hardware access under dev->priv->lock, except the performance + * critical parts: + * - rx is (pseudo-) lockless: it relies on the single-threading provided + * by the arch code for interrupts. + * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission + * needs dev->priv->lock :-( + * - set_multicast_list: preparation lockless, relies on dev->xmit_lock. + */ + +/* in dev: base, irq */ +struct fe_priv { + spinlock_t lock; + + /* General data: + * Locking: spin_lock(&np->lock); */ + struct net_device_stats stats; + int in_shutdown; + u32 linkspeed; + int duplex; + int phyaddr; + + /* General data: RO fields */ + dma_addr_t ring_addr; + struct pci_dev *pci_dev; + u32 orig_mac[2]; + u32 irqmask; + + /* rx specific fields. + * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); + */ + struct ring_desc *rx_ring; + unsigned int cur_rx, refill_rx; + struct sk_buff *rx_skbuff[RX_RING]; + dma_addr_t rx_dma[RX_RING]; + unsigned int rx_buf_sz; + struct timer_list oom_kick; + struct timer_list nic_poll; + + /* + * tx specific fields. + */ + struct ring_desc *tx_ring; + unsigned int next_tx, nic_tx; + struct sk_buff *tx_skbuff[TX_RING]; + dma_addr_t tx_dma[TX_RING]; + u16 tx_flags; +}; + +/* + * Maximum number of loops until we assume that a bit in the irq mask + * is stuck. Overridable with module param. + */ +static int max_interrupt_work = 5; + +static inline struct fe_priv *get_nvpriv(struct net_device *dev) +{ + return (struct fe_priv *) dev->priv; +} + +static inline u8 *get_hwbase(struct net_device *dev) +{ + return (u8 *) dev->base_addr; +} + +static inline void pci_push(u8 * base) +{ + /* force out pending posted writes */ + readl(base); +} + +static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, + int delay, int delaymax, const char *msg) +{ + u8 *base = get_hwbase(dev); + + pci_push(base); + do { + udelay(delay); + delaymax -= delay; + if (delaymax < 0) { + if (msg) + printk(msg); + return 1; + } + } while ((readl(base + offset) & mask) != target); + return 0; +} + +#define MII_READ (-1) +/* mii_rw: read/write a register on the PHY. + * + * Caller must guarantee serialization + */ +static int mii_rw(struct net_device *dev, int addr, int miireg, int value) +{ + u8 *base = get_hwbase(dev); + int was_running; + u32 reg; + int retval; + + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + was_running = 0; + reg = readl(base + NvRegAdapterControl); + if (reg & NVREG_ADAPTCTL_RUNNING) { + was_running = 1; + writel(reg & ~NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + } + reg = readl(base + NvRegMIIControl); + if (reg & NVREG_MIICTL_INUSE) { + writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl); + udelay(NV_MIIBUSY_DELAY); + } + + reg = NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg; + if (value != MII_READ) { + writel(value, base + NvRegMIIData); + reg |= NVREG_MIICTL_WRITE; + } + writel(reg, base + NvRegMIIControl); + + if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0, + NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) { + dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n", + dev->name, miireg, addr); + retval = -1; + } else if (value != MII_READ) { + /* it was a write operation - fewer failures are detectable */ + dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n", + dev->name, value, miireg, addr); + retval = 0; + } else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) { + dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n", + dev->name, miireg, addr); + retval = -1; + } else { + /* FIXME: why is that required? */ + udelay(50); + retval = readl(base + NvRegMIIData); + dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n", + dev->name, miireg, addr, retval); + } + if (was_running) { + reg = readl(base + NvRegAdapterControl); + writel(reg | NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + } + return retval; +} + +static void start_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: start_rx\n", dev->name); + /* Already running? Stop it. */ + if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { + writel(0, base + NvRegReceiverControl); + pci_push(base); + } + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); + pci_push(base); +} + +static void stop_rx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name); + writel(0, base + NvRegReceiverControl); + reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, + NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, + KERN_INFO "stop_rx: ReceiverStatus remained busy"); + + udelay(NV_RXSTOP_DELAY2); + writel(0, base + NvRegLinkSpeed); +} + +static void start_tx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: start_tx\n", dev->name); + writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); + pci_push(base); +} + +static void stop_tx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name); + writel(0, base + NvRegTransmitterControl); + reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, + NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, + KERN_INFO "stop_tx: TransmitterStatus remained busy"); + + udelay(NV_TXSTOP_DELAY2); + writel(0, base + NvRegUnknownTransmitterReg); +} + +static void txrx_reset(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); + pci_push(base); + udelay(NV_TXRX_RESET_DELAY); + writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl); + pci_push(base); +} + +/* + * get_stats: dev->get_stats function + * Get latest stats value from the nic. + * Called with read_lock(&dev_base_lock) held for read - + * only synchronized against unregister_netdevice. + */ +static struct net_device_stats *get_stats(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + /* It seems that the nic always generates interrupts and doesn't + * accumulate errors internally. Thus the current values in np->stats + * are already up to date. + */ + return &np->stats; +} + + +/* + * nic_ioctl: dev->do_ioctl function + * Called with rtnl_lock held. + */ +static int nic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + return -EOPNOTSUPP; +} + +/* + * alloc_rx: fill rx ring entries. + * Return 1 if the allocations for the skbs failed and the + * rx engine is without Available descriptors + */ +static int alloc_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + unsigned int refill_rx = np->refill_rx; + + while (np->cur_rx != refill_rx) { + int nr = refill_rx % RX_RING; + struct sk_buff *skb; + + if (np->rx_skbuff[nr] == NULL) { + + skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); + if (!skb) + break; + + skb->dev = dev; + np->rx_skbuff[nr] = skb; + } else { + skb = np->rx_skbuff[nr]; + } + np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, + PCI_DMA_FROMDEVICE); + np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); + wmb(); + np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); + dprintk(KERN_DEBUG "%s: alloc_rx: Packet %d marked as Available\n", + dev->name, refill_rx); + refill_rx++; + } + np->refill_rx = refill_rx; + if (np->cur_rx - refill_rx == RX_RING) + return 1; + return 0; +} + +static void do_rx_refill(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + + disable_irq(dev->irq); + if (alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + enable_irq(dev->irq); +} + +static int init_ring(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + + np->next_tx = np->nic_tx = 0; + for (i = 0; i < TX_RING; i++) { + np->tx_ring[i].Flags = 0; + } + + np->cur_rx = RX_RING; + np->refill_rx = 0; + for (i = 0; i < RX_RING; i++) { + np->rx_ring[i].Flags = 0; + } + return alloc_rx(dev); +} + +static void drain_tx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + for (i = 0; i < TX_RING; i++) { + np->tx_ring[i].Flags = 0; + if (np->tx_skbuff[i]) { + pci_unmap_single(np->pci_dev, np->tx_dma[i], + np->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = NULL; + np->stats.tx_dropped++; + } + } +} + +static void drain_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + for (i = 0; i < RX_RING; i++) { + np->rx_ring[i].Flags = 0; + wmb(); + if (np->rx_skbuff[i]) { + pci_unmap_single(np->pci_dev, np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_skbuff[i]); + np->rx_skbuff[i] = NULL; + } + } +} + +static void drain_ring(struct net_device *dev) +{ + drain_tx(dev); + drain_rx(dev); +} + +/* + * start_xmit: dev->hard_start_xmit function + * Called with dev->xmit_lock held. + */ +static int start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int nr = np->next_tx % TX_RING; + + np->tx_skbuff[nr] = skb; + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, + PCI_DMA_TODEVICE); + + np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring[nr].Length = cpu_to_le16(skb->len-1); + + spin_lock_irq(&np->lock); + wmb(); + np->tx_ring[nr].Flags = np->tx_flags; + dprintk(KERN_DEBUG "%s: start_xmit: packet packet %d queued for transmission.\n", + dev->name, np->next_tx); + { + int j; + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } + + np->next_tx++; + + dev->trans_start = jiffies; + if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) + netif_stop_queue(dev); + spin_unlock_irq(&np->lock); + writel(NVREG_TXRXCTL_KICK, get_hwbase(dev) + NvRegTxRxControl); + return 0; +} + +/* + * tx_done: check for completed packets, release the skbs. + * + * Caller must own np->lock. + */ +static void tx_done(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + while (np->nic_tx < np->next_tx) { + struct ring_desc *prd; + int i = np->nic_tx % TX_RING; + + prd = &np->tx_ring[i]; + + dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n", + dev->name, np->nic_tx, prd->Flags); + if (prd->Flags & cpu_to_le16(NV_TX_VALID)) + break; + if (prd->Flags & cpu_to_le16(NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (prd->Flags & cpu_to_le16(NV_TX_UNDERFLOW)) + np->stats.tx_fifo_errors++; + if (prd->Flags & cpu_to_le16(NV_TX_CARRIERLOST)) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += np->tx_skbuff[i]->len; + } + pci_unmap_single(np->pci_dev, np->tx_dma[i], + np->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(np->tx_skbuff[i]); + np->tx_skbuff[i] = NULL; + np->nic_tx++; + } + if (np->next_tx - np->nic_tx < TX_LIMIT_START) + netif_wake_queue(dev); +} + +/* + * tx_timeout: dev->tx_timeout function + * Called with dev->xmit_lock held. + */ +static void tx_timeout(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name, + readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + + spin_lock_irq(&np->lock); + + /* 1) stop tx engine */ + stop_tx(dev); + + /* 2) check that the packets were not sent already: */ + tx_done(dev); + + /* 3) if there are dead entries: clear everything */ + if (np->next_tx != np->nic_tx) { + printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); + drain_tx(dev); + np->next_tx = np->nic_tx = 0; + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + netif_wake_queue(dev); + } + + /* 4) restart tx engine */ + start_tx(dev); + spin_unlock_irq(&np->lock); +} + +static void rx_process(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + for (;;) { + struct ring_desc *prd; + struct sk_buff *skb; + int len; + int i; + if (np->cur_rx - np->refill_rx >= RX_RING) + break; /* we scanned the whole ring - do not continue */ + + i = np->cur_rx % RX_RING; + prd = &np->rx_ring[i]; + dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n", + dev->name, np->cur_rx, prd->Flags); + + if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) + break; /* still owned by hardware, */ + + /* + * the packet is for us - immediately tear down the pci mapping, and + * prefetch the first cacheline of the packet. + */ + pci_unmap_single(np->pci_dev, np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_FROMDEVICE); + prefetch(np->rx_skbuff[i]->data); + + { + int j; + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",prd->Flags); + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]); + } + dprintk("\n"); + } + /* look at what we actually got: */ + if (!(prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID))) + goto next_pkt; + + + len = le16_to_cpu(prd->Length); + + if (prd->Flags & cpu_to_le16(NV_RX_MISSEDFRAME)) { + np->stats.rx_missed_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_CRCERR)) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_OVERFLOW)) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_ERROR)) { + /* framing errors are soft errors, the rest is fatal. */ + if (prd->Flags & cpu_to_le16(NV_RX_FRAMINGERR)) { + if (prd->Flags & cpu_to_le16(NV_RX_SUBSTRACT1)) { + len--; + } + } else { + np->stats.rx_errors++; + goto next_pkt; + } + } + /* got a valid packet - forward it to the network core */ + skb = np->rx_skbuff[i]; + np->rx_skbuff[i] = NULL; + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n", + dev->name, np->cur_rx, len, skb->protocol); + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; +next_pkt: + np->cur_rx++; + } +} + +/* + * change_mtu: dev->change_mtu function + * Called with dev_base_lock held for read. + */ +static int change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu > DEFAULT_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +/* + * change_mtu: dev->change_mtu function + * Called with dev->xmit_lock held. + */ +static void set_multicast(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 addr[2]; + u32 mask[2]; + u32 pff; + + memset(addr, 0, sizeof(addr)); + memset(mask, 0, sizeof(mask)); + + if (dev->flags & IFF_PROMISC) { + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + pff = NVREG_PFF_PROMISC; + } else { + pff = NVREG_PFF_MYADDR; + + if (dev->flags & IFF_ALLMULTI || dev->mc_list) { + u32 alwaysOff[2]; + u32 alwaysOn[2]; + + alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0xffffffff; + if (dev->flags & IFF_ALLMULTI) { + alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; + } else { + struct dev_mc_list *walk; + + walk = dev->mc_list; + while (walk != NULL) { + u32 a, b; + a = le32_to_cpu(*(u32 *) walk->dmi_addr); + b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4])); + alwaysOn[0] &= a; + alwaysOff[0] &= ~a; + alwaysOn[1] &= b; + alwaysOff[1] &= ~b; + walk = walk->next; + } + } + addr[0] = alwaysOn[0]; + addr[1] = alwaysOn[1]; + mask[0] = alwaysOn[0] | alwaysOff[0]; + mask[1] = alwaysOn[1] | alwaysOff[1]; + } + } + addr[0] |= NVREG_MCASTADDRA_FORCE; + pff |= NVREG_PFF_ALWAYS; + spin_lock_irq(&np->lock); + stop_rx(dev); + writel(addr[0], base + NvRegMulticastAddrA); + writel(addr[1], base + NvRegMulticastAddrB); + writel(mask[0], base + NvRegMulticastMaskA); + writel(mask[1], base + NvRegMulticastMaskB); + writel(pff, base + NvRegPacketFilterFlags); + start_rx(dev); + spin_unlock_irq(&np->lock); +} + +static int update_linkspeed(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int adv, lpa, newls, newdup; + + adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); + dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", + dev->name, adv, lpa); + + /* FIXME: handle parallel detection properly, handle gigabit ethernet */ + lpa = lpa & adv; + if (lpa & LPA_100FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 1; + } else if (lpa & LPA_100HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 0; + } else if (lpa & LPA_10FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 1; + } else if (lpa & LPA_10HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } else { + dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, lpa); + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } + if (np->duplex != newdup || np->linkspeed != newls) { + np->duplex = newdup; + np->linkspeed = newls; + return 1; + } + return 0; +} + +static void link_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 miistat; + int miival; + + miistat = readl(base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + printk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); + + miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + if (miival & BMSR_ANEGCOMPLETE) { + update_linkspeed(dev); + + if (netif_carrier_ok(dev)) { + stop_rx(dev); + } else { + netif_carrier_on(dev); + printk(KERN_INFO "%s: link up.\n", dev->name); + } + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + start_rx(dev); + } else { + if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down.\n", dev->name); + stop_rx(dev); + } + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + } +} + +static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name); + + for (i=0; ; i++) { + events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { + spin_lock(&np->lock); + tx_done(dev); + spin_unlock(&np->lock); + } + + if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { + rx_process(dev); + if (alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } + + if (events & NVREG_IRQ_LINK) { + spin_lock(&np->lock); + link_irq(dev); + spin_unlock(&np->lock); + } + if (events & (NVREG_IRQ_TX_ERR)) { + dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", + dev->name, events); + } + if (events & (NVREG_IRQ_UNKNOWN)) { + printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", + dev->name, events); + } + if (i > max_interrupt_work) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + writel(0, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name); + + return IRQ_RETVAL(i); +} + +static void do_nic_poll(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + disable_irq(dev->irq); + /* + * reenable interrupts on the nic, we have to do this before calling + * nic_irq because that may decide to do otherwise + */ + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(dev->irq); +} + +static int open(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + int ret, oom, i; + + dprintk(KERN_DEBUG "forcedeth: open\n"); + + /* 1) erase previous misconfiguration */ + /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ + writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); + writel(0, base + NvRegMulticastAddrB); + writel(0, base + NvRegMulticastMaskA); + writel(0, base + NvRegMulticastMaskB); + writel(0, base + NvRegPacketFilterFlags); + writel(0, base + NvRegAdapterControl); + writel(0, base + NvRegLinkSpeed); + writel(0, base + NvRegUnknownTransmitterReg); + txrx_reset(dev); + writel(0, base + NvRegUnknownSetupReg6); + + /* 2) initialize descriptor rings */ + np->in_shutdown = 0; + oom = init_ring(dev); + + /* 3) set mac address */ + { + u32 mac[2]; + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + + writel(mac[0], base + NvRegMacAddrA); + writel(mac[1], base + NvRegMacAddrB); + } + + /* 4) continue setup */ + np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + np->duplex = 0; + writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); + writel(0, base + NvRegTxRxControl); + pci_push(base); + writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl); + reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, + NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, + KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); + writel(0, base + NvRegUnknownSetupReg4); + + /* 5) Find a suitable PHY */ + writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed); + for (i = 1; i < 32; i++) { + int id1, id2; + + id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); + if (id1 < 0) + continue; + id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); + if (id2 < 0) + continue; + dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", + dev->name, id1, id2, i); + np->phyaddr = i; + + update_linkspeed(dev); + + break; + } + if (i == 32) { + printk(KERN_INFO "%s: open: failing due to lack of suitable PHY.\n", + dev->name); + ret = -EINVAL; + goto out_drain; + } + + /* 6) continue setup */ + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); + writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); + writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); + + writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); + get_random_bytes(&i, sizeof(i)); + writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); + writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); + writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); + writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); + writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID, + base + NvRegAdapterControl); + writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4); + writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags); + + /* 7) start packet processing */ + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + + i = readl(base + NvRegPowerState); + if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0) { + writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState); + } + pci_push(base); + udelay(10); + writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); + writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + + + writel(0, base + NvRegIrqMask); + pci_push(base); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + + ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev); + if (ret) + goto out_drain; + + writel(np->irqmask, base + NvRegIrqMask); + + spin_lock_irq(&np->lock); + writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); + writel(0, base + NvRegMulticastAddrB); + writel(0, base + NvRegMulticastMaskA); + writel(0, base + NvRegMulticastMaskB); + writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); + start_rx(dev); + start_tx(dev); + netif_start_queue(dev); + if (oom) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + if (!(mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ) & BMSR_ANEGCOMPLETE)) { + printk("%s: no link during initialization.\n", dev->name); + netif_carrier_off(dev); + } + + spin_unlock_irq(&np->lock); + + return 0; +out_drain: + drain_ring(dev); + return ret; +} + +static int close(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + spin_lock_irq(&np->lock); + np->in_shutdown = 1; + spin_unlock_irq(&np->lock); + synchronize_irq(dev->irq); + + del_timer_sync(&np->oom_kick); + del_timer_sync(&np->nic_poll); + + netif_stop_queue(dev); + spin_lock_irq(&np->lock); + stop_tx(dev); + stop_rx(dev); + spin_unlock_irq(&np->lock); + + free_irq(dev->irq, dev); + + drain_ring(dev); + + /* FIXME: power down nic */ + + return 0; +} + +static int __devinit probe_nic(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + struct net_device *dev; + struct fe_priv *np; + unsigned long addr; + u8 *base; + int err, i; + + dev = alloc_etherdev(sizeof(struct fe_priv)); + np = get_nvpriv(dev); + err = -ENOMEM; + if (!dev) + goto out; + + np->pci_dev = pci_dev; + spin_lock_init(&np->lock); + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pci_dev->dev); + + init_timer(&np->oom_kick); + np->oom_kick.data = (unsigned long) dev; + np->oom_kick.function = &do_rx_refill; /* timer handler */ + init_timer(&np->nic_poll); + np->nic_poll.data = (unsigned long) dev; + np->nic_poll.function = &do_nic_poll; /* timer handler */ + + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_INFO "forcedeth: pci_enable_dev failed: %d\n", err); + goto out_free; + } + + pci_set_master(pci_dev); + + err = pci_request_regions(pci_dev, dev->name); + if (err < 0) + goto out_disable; + + err = -EINVAL; + addr = 0; + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dprintk(KERN_DEBUG "forcedeth: resource %d start %p len %ld flags 0x%08lx.\n", + i, (void*)pci_resource_start(pci_dev, i), + pci_resource_len(pci_dev, i), + pci_resource_flags(pci_dev, i)); + if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && + pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) { + addr = pci_resource_start(pci_dev, i); + break; + } + } + if (i == DEVICE_COUNT_RESOURCE) { + printk(KERN_INFO "forcedeth: Couldn't find register window.\n"); + goto out_relreg; + } + + err = -ENOMEM; + dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ); + if (!dev->base_addr) + goto out_disable; + dev->irq = pci_dev->irq; + np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring) + goto out_unmap; + np->tx_ring = &np->rx_ring[RX_RING]; + + dev->open = open; + dev->stop = close; + dev->hard_start_xmit = start_xmit; + dev->get_stats = get_stats; + dev->change_mtu = change_mtu; + dev->set_multicast_list = set_multicast; + dev->do_ioctl = nic_ioctl; + dev->tx_timeout = tx_timeout; + dev->watchdog_timeo = NV_WATCHDOG_TIMEO; + + pci_set_drvdata(pci_dev, dev); + + err = register_netdev(dev); + if (err) { + printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err); + goto out_freering; + } + + printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x\n", + dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device); + + + /* read the mac address */ + base = get_hwbase(dev); + np->orig_mac[0] = readl(base + NvRegMacAddrA); + np->orig_mac[1] = readl(base + NvRegMacAddrB); + + dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff; + dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff; + dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff; + dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; + dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; + dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + + if (!is_valid_ether_addr(dev->dev_addr)) { + /* + * Bad mac address. At least one bios sets the mac address + * to 01:23:45:67:89:ab + */ + printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n"); + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x6c; + get_random_bytes(&dev->dev_addr[3], 3); + } + + dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); + if (id->driver_data & DEV_NEED_LASTPACKET1) + np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); + if (id->driver_data & DEV_IRQMASK_1) + np->irqmask = NVREG_IRQMASK_WANTED_1; + if (id->driver_data & DEV_IRQMASK_2) + np->irqmask = NVREG_IRQMASK_WANTED_2; + + return 0; + +out_freering: + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + np->rx_ring, np->ring_addr); +out_unmap: + iounmap(get_hwbase(dev)); +out_relreg: + pci_release_regions(pci_dev); +out_disable: + pci_disable_device(pci_dev); +out_free: + kfree(dev); + pci_set_drvdata(pci_dev, NULL); +out: + return err; +} + +static void __devexit remove_nic(struct pci_dev *pci_dev) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + unregister_netdev(dev); + + /* special op: write back the misordered MAC address - otherwise + * the next probe_nic would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + + /* free all structures */ + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); + iounmap(get_hwbase(dev)); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + kfree(dev); + pci_set_drvdata(pci_dev, NULL); +} + +static struct pci_device_id pci_tbl[] = { + { /* nForce Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x1C3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_IRQMASK_1, + }, + { /* nForce2 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x0066, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x00D6, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2, + }, + {0,}, +}; + +static struct pci_driver driver = { + .name = "forcedeth", + .id_table = pci_tbl, + .probe = probe_nic, + .remove = __devexit_p(remove_nic), +}; + + +static int __init init_nic(void) +{ + printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION); + return pci_module_init(&driver); +} + +static void __exit exit_nic(void) +{ + pci_unregister_driver(&driver); +} + +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); + +MODULE_AUTHOR("Manfred Spraul "); +MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +module_init(init_nic); +module_exit(exit_nic); --- linux-2.6.1-rc1/drivers/net/gt96100eth.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/gt96100eth.c 2003-12-30 22:49:19.000000000 -0800 @@ -729,10 +729,12 @@ gt96100_probe1(int port_num) return -EBUSY; } - dev = init_etherdev(0, sizeof(struct gt96100_private)); + dev = alloc_etherdev(sizeof(struct gt96100_private)); + if (!dev) + goto out; gtif->dev = dev; - /* private struct aligned and zeroed by init_etherdev */ + /* private struct aligned and zeroed by alloc_etherdev */ /* Fill in the 'dev' fields. */ dev->base_addr = gtif->iobase; dev->irq = gtif->irq; @@ -740,7 +742,7 @@ gt96100_probe1(int port_num) if ((retval = parse_mac_addr(dev, gtif->mac_str))) { err("%s: MAC address parse failed\n", __FUNCTION__); retval = -EINVAL; - goto free_region; + goto out1; } gp = dev->priv; @@ -768,7 +770,7 @@ gt96100_probe1(int port_num) &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; - goto free_region; + goto out1; } gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE); @@ -781,11 +783,8 @@ gt96100_probe1(int port_num) gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE, &gp->rx_buff_dma); if (gp->rx_buff == NULL) { - dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE - + sizeof(gt96100_td_t) * TX_RING_SIZE, - gp->rx_ring); retval = -ENOMEM; - goto free_region; + goto out2; } } @@ -797,12 +796,8 @@ gt96100_probe1(int port_num) gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE, &gp->hash_table_dma); if (gp->hash_table == NULL) { - dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE - + sizeof(gt96100_td_t) * TX_RING_SIZE, - gp->rx_ring); - dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); retval = -ENOMEM; - goto free_region; + goto out3; } } @@ -819,14 +814,23 @@ gt96100_probe1(int port_num) dev->tx_timeout = gt96100_tx_timeout; dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); + retval = register_netdev(dev); + if (retval) + goto out4; return 0; - free_region: - release_region(gtif->iobase, GT96100_ETH_IO_SIZE); - unregister_netdev(dev); +out4: + dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); +out3: + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); +out2: + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); +out1: free_netdev (dev); +out: + release_region(gtif->iobase, GT96100_ETH_IO_SIZE); err("%s failed. Returns %d\n", __FUNCTION__, retval); return retval; } @@ -1573,9 +1577,14 @@ static void gt96100_cleanup_module(void) if (gtif->dev != NULL) { struct gt96100_private *gp = (struct gt96100_private *)gtif->dev->priv; - release_region(gtif->iobase, gp->io_size); unregister_netdev(gtif->dev); - free_netdev (gtif->dev); + dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + free_netdev(gtif->dev); + release_region(gtif->iobase, gp->io_size); } } } --- linux-2.6.1-rc1/drivers/net/hamradio/baycom_epp.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/hamradio/baycom_epp.c 2003-12-30 22:49:19.000000000 -0800 @@ -1275,7 +1275,7 @@ static int baycom_ioctl(struct net_devic * If dev->base_addr == 2, allocate space for the device and return success * (detachable devices only). */ -static int baycom_probe(struct net_device *dev) +static void baycom_probe(struct net_device *dev) { static char ax25_bcast[AX25_ADDR_LEN] = { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1 @@ -1288,9 +1288,6 @@ static int baycom_probe(struct net_devic }; struct baycom_state *bc; - if (!dev) - return -ENXIO; - baycom_paranoia_check(dev, "baycom_probe", -ENXIO); /* * not a real probe! only initialize data structures */ @@ -1332,8 +1329,6 @@ static int baycom_probe(struct net_devic /* New style flags */ dev->flags = 0; - - return 0; } /* --------------------------------------------------------------------- */ @@ -1368,7 +1363,7 @@ static void __init baycom_epp_dev_setup( /* * initialize part of the device struct */ - dev->init = baycom_probe; + baycom_probe(dev); } static int __init init_baycomepp(void) @@ -1401,7 +1396,7 @@ static int __init init_baycomepp(void) if (register_netdev(dev)) { printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name); - kfree(dev); + free_netdev(dev); break; } if (set_hw && baycom_setmode(dev->priv, mode[i])) --- linux-2.6.1-rc1/drivers/net/hamradio/bpqether.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/hamradio/bpqether.c 2003-12-30 22:49:19.000000000 -0800 @@ -547,7 +547,7 @@ static int bpq_new_device(struct net_dev error: dev_put(edev); - kfree(ndev); + free_netdev(ndev); return err; } --- linux-2.6.1-rc1/drivers/net/hamradio/dmascc.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/drivers/net/hamradio/dmascc.c 2003-12-30 22:49:19.000000000 -0800 @@ -242,7 +242,7 @@ struct scc_priv { struct scc_info { int irq_used; int twin_serial_cfg; - struct net_device dev[2]; + struct net_device *dev[2]; struct scc_priv priv[2]; struct scc_info *next; spinlock_t register_lock; /* Per device register lock */ @@ -310,18 +310,19 @@ static void __exit dmascc_exit(void) { info = first; /* Unregister devices */ - for (i = 0; i < 2; i++) { - if (info->dev[i].name) - unregister_netdev(&info->dev[i]); - } + for (i = 0; i < 2; i++) + unregister_netdev(info->dev[i]); /* Reset board */ if (info->priv[0].type == TYPE_TWIN) - outb(0, info->dev[0].base_addr + TWIN_SERIAL_CFG); + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); write_scc(&info->priv[0], R9, FHWRES); - release_region(info->dev[0].base_addr, + release_region(info->dev[0]->base_addr, hw[info->priv[0].type].io_size); + for (i = 0; i < 2; i++) + free_netdev(info->dev[i]); + /* Free memory */ first = info->next; kfree(info); @@ -443,156 +444,193 @@ static int __init dmascc_init(void) { module_init(dmascc_init); module_exit(dmascc_exit); +static void dev_setup(struct net_device *dev) +{ + dev->type = ARPHRD_AX25; + dev->hard_header_len = 73; + dev->mtu = 1500; + dev->addr_len = 7; + dev->tx_queue_len = 64; + memcpy(dev->broadcast, ax25_broadcast, 7); + memcpy(dev->dev_addr, ax25_test, 7); +} + +static int __init setup_adapter(int card_base, int type, int n) +{ + int i, irq, chip; + struct scc_info *info; + struct net_device *dev; + struct scc_priv *priv; + unsigned long time; + unsigned int irqs; + int tmr_base = card_base + hw[type].tmr_offset; + int scc_base = card_base + hw[type].scc_offset; + char *chipnames[] = CHIPNAMES; + + /* Allocate memory */ + info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); + if (!info) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out; + } -int __init setup_adapter(int card_base, int type, int n) { - int i, irq, chip; - struct scc_info *info; - struct net_device *dev; - struct scc_priv *priv; - unsigned long time; - unsigned int irqs; - int tmr_base = card_base + hw[type].tmr_offset; - int scc_base = card_base + hw[type].scc_offset; - char *chipnames[] = CHIPNAMES; - - /* Allocate memory */ - info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); - if (!info) { - printk(KERN_ERR "dmascc: could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); - return -1; - } - - /* Initialize what is necessary for write_scc and write_scc_data */ - memset(info, 0, sizeof(struct scc_info)); - spin_lock_init(&info->register_lock); - - priv = &info->priv[0]; - priv->type = type; - priv->card_base = card_base; - priv->scc_cmd = scc_base + SCCA_CMD; - priv->scc_data = scc_base + SCCA_DATA; - priv->register_lock = &info->register_lock; - - /* Reset SCC */ - write_scc(priv, R9, FHWRES | MIE | NV); - - /* Determine type of chip by enabling SDLC/HDLC enhancements */ - write_scc(priv, R15, SHDLCE); - if (!read_scc(priv, R15)) { - /* WR7' not present. This is an ordinary Z8530 SCC. */ - chip = Z8530; - } else { - /* Put one character in TX FIFO */ - write_scc_data(priv, 0, 0); - if (read_scc(priv, R0) & Tx_BUF_EMP) { - /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ - chip = Z85230; - } else { - /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ - chip = Z85C30; - } - } - write_scc(priv, R15, 0); + /* Initialize what is necessary for write_scc and write_scc_data */ + memset(info, 0, sizeof(struct scc_info)); - /* Start IRQ auto-detection */ - irqs = probe_irq_on(); + info->dev[0] = alloc_netdev(0, "", dev_setup); + if (!info->dev[0]) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out1; + } - /* Enable interrupts */ - if (type == TYPE_TWIN) { - outb(0, card_base + TWIN_DMA_CFG); - inb(card_base + TWIN_CLR_TMR1); - inb(card_base + TWIN_CLR_TMR2); - outb((info->twin_serial_cfg = TWIN_EI), card_base + TWIN_SERIAL_CFG); - } else { - write_scc(priv, R15, CTSIE); - write_scc(priv, R0, RES_EXT_INT); - write_scc(priv, R1, EXT_INT_ENAB); - } - - /* Start timer */ - outb(1, tmr_base + TMR_CNT1); - outb(0, tmr_base + TMR_CNT1); - - /* Wait and detect IRQ */ - time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); - irq = probe_irq_off(irqs); - - /* Clear pending interrupt, disable interrupts */ - if (type == TYPE_TWIN) { - inb(card_base + TWIN_CLR_TMR1); - } else { - write_scc(priv, R1, 0); - write_scc(priv, R15, 0); - write_scc(priv, R0, RES_EXT_INT); - } + info->dev[1] = alloc_netdev(0, "", dev_setup); + if (!info->dev[1]) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out2; + } + spin_lock_init(&info->register_lock); - if (irq <= 0) { - printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", - hw[type].name, card_base, irq); - kfree(info); - return -1; - } + priv = &info->priv[0]; + priv->type = type; + priv->card_base = card_base; + priv->scc_cmd = scc_base + SCCA_CMD; + priv->scc_data = scc_base + SCCA_DATA; + priv->register_lock = &info->register_lock; + + /* Reset SCC */ + write_scc(priv, R9, FHWRES | MIE | NV); + + /* Determine type of chip by enabling SDLC/HDLC enhancements */ + write_scc(priv, R15, SHDLCE); + if (!read_scc(priv, R15)) { + /* WR7' not present. This is an ordinary Z8530 SCC. */ + chip = Z8530; + } else { + /* Put one character in TX FIFO */ + write_scc_data(priv, 0, 0); + if (read_scc(priv, R0) & Tx_BUF_EMP) { + /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ + chip = Z85230; + } else { + /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ + chip = Z85C30; + } + } + write_scc(priv, R15, 0); - /* Set up data structures */ - for (i = 0; i < 2; i++) { - dev = &info->dev[i]; - priv = &info->priv[i]; - priv->type = type; - priv->chip = chip; - priv->dev = dev; - priv->info = info; - priv->channel = i; - spin_lock_init(&priv->ring_lock); - priv->register_lock = &info->register_lock; - priv->card_base = card_base; - priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); - priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); - priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); - priv->tmr_ctrl = tmr_base + TMR_CTRL; - priv->tmr_mode = i ? 0xb0 : 0x70; - priv->param.pclk_hz = hw[type].pclk_hz; - priv->param.brg_tc = -1; - priv->param.clocks = TCTRxCP | RCRTxCP; - priv->param.persist = 256; - priv->param.dma = -1; - INIT_WORK(&priv->rx_work, rx_bh, priv); - dev->priv = priv; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - if (sizeof(dev->name) == sizeof(char *)) dev->name = priv->name; -#endif - sprintf(dev->name, "dmascc%i", 2*n+i); - SET_MODULE_OWNER(dev); - dev->base_addr = card_base; - dev->irq = irq; - dev->open = scc_open; - dev->stop = scc_close; - dev->do_ioctl = scc_ioctl; - dev->hard_start_xmit = scc_send_packet; - dev->get_stats = scc_get_stats; - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; - dev->set_mac_address = scc_set_mac_address; - dev->type = ARPHRD_AX25; - dev->hard_header_len = 73; - dev->mtu = 1500; - dev->addr_len = 7; - dev->tx_queue_len = 64; - memcpy(dev->broadcast, ax25_broadcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); - rtnl_lock(); - if (register_netdevice(dev)) { - printk(KERN_ERR "dmascc: could not register %s\n", dev->name); - } - rtnl_unlock(); - } + /* Start IRQ auto-detection */ + irqs = probe_irq_on(); + /* Enable interrupts */ + if (type == TYPE_TWIN) { + outb(0, card_base + TWIN_DMA_CFG); + inb(card_base + TWIN_CLR_TMR1); + inb(card_base + TWIN_CLR_TMR2); + info->twin_serial_cfg = TWIN_EI; + outb(info->twin_serial_cfg, card_base + TWIN_SERIAL_CFG); + } else { + write_scc(priv, R15, CTSIE); + write_scc(priv, R0, RES_EXT_INT); + write_scc(priv, R1, EXT_INT_ENAB); + } - info->next = first; - first = info; - printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, - chipnames[chip], card_base, irq); - return 0; + /* Start timer */ + outb(1, tmr_base + TMR_CNT1); + outb(0, tmr_base + TMR_CNT1); + + /* Wait and detect IRQ */ + time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); + irq = probe_irq_off(irqs); + + /* Clear pending interrupt, disable interrupts */ + if (type == TYPE_TWIN) { + inb(card_base + TWIN_CLR_TMR1); + } else { + write_scc(priv, R1, 0); + write_scc(priv, R15, 0); + write_scc(priv, R0, RES_EXT_INT); + } + + if (irq <= 0) { + printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", + hw[type].name, card_base, irq); + goto out3; + } + + /* Set up data structures */ + for (i = 0; i < 2; i++) { + dev = info->dev[i]; + priv = &info->priv[i]; + priv->type = type; + priv->chip = chip; + priv->dev = dev; + priv->info = info; + priv->channel = i; + spin_lock_init(&priv->ring_lock); + priv->register_lock = &info->register_lock; + priv->card_base = card_base; + priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); + priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); + priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); + priv->tmr_ctrl = tmr_base + TMR_CTRL; + priv->tmr_mode = i ? 0xb0 : 0x70; + priv->param.pclk_hz = hw[type].pclk_hz; + priv->param.brg_tc = -1; + priv->param.clocks = TCTRxCP | RCRTxCP; + priv->param.persist = 256; + priv->param.dma = -1; + INIT_WORK(&priv->rx_work, rx_bh, priv); + dev->priv = priv; + sprintf(dev->name, "dmascc%i", 2*n+i); + SET_MODULE_OWNER(dev); + dev->base_addr = card_base; + dev->irq = irq; + dev->open = scc_open; + dev->stop = scc_close; + dev->do_ioctl = scc_ioctl; + dev->hard_start_xmit = scc_send_packet; + dev->get_stats = scc_get_stats; + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; + dev->set_mac_address = scc_set_mac_address; + } + if (register_netdev(info->dev[0])) { + printk(KERN_ERR "dmascc: could not register %s\n", + info->dev[0]->name); + goto out3; + } + if (register_netdev(info->dev[1])) { + printk(KERN_ERR "dmascc: could not register %s\n", + info->dev[1]->name); + goto out4; + } + + + info->next = first; + first = info; + printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, + chipnames[chip], card_base, irq); + return 0; + +out4: + unregister_netdev(info->dev[0]); +out3: + if (info->priv[0].type == TYPE_TWIN) + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); + write_scc(&info->priv[0], R9, FHWRES); + free_netdev(info->dev[1]); +out2: + free_netdev(info->dev[0]); +out1: + kfree(info); +out: + return -1; } --- linux-2.6.1-rc1/drivers/net/hamradio/hdlcdrv.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/hamradio/hdlcdrv.c 2003-12-30 22:49:19.000000000 -0800 @@ -832,7 +832,7 @@ struct net_device *hdlcdrv_register(cons if (err < 0) { printk(KERN_WARNING "hdlcdrv: cannot register net " "device %s\n", dev->name); - kfree(dev); + free_netdev(dev); dev = ERR_PTR(err); } return dev; --- linux-2.6.1-rc1/drivers/net/hamradio/yam.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/hamradio/yam.c 2003-12-30 22:49:19.000000000 -0800 @@ -1192,7 +1192,7 @@ static void __exit yam_cleanup_driver(vo struct net_device *dev = yam_devs[i]; if (dev) { unregister_netdev(dev); - kfree(dev); + free_netdev(dev); } } --- linux-2.6.1-rc1/drivers/net/hp100.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/hp100.c 2003-12-30 22:49:19.000000000 -0800 @@ -118,8 +118,6 @@ #include #include -typedef struct net_device_stats hp100_stats_t; - #include "hp100.h" /* @@ -130,23 +128,8 @@ typedef struct net_device_stats hp100_st #define HP100_BUS_EISA 1 #define HP100_BUS_PCI 2 -#ifndef PCI_DEVICE_ID_HP_J2585B -#define PCI_DEVICE_ID_HP_J2585B 0x1031 -#endif -#ifndef PCI_VENDOR_ID_COMPEX -#define PCI_VENDOR_ID_COMPEX 0x11f6 -#endif -#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4 -#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 -#endif -#ifndef PCI_VENDOR_ID_COMPEX2 -#define PCI_VENDOR_ID_COMPEX2 0x101a -#endif -#ifndef PCI_DEVICE_ID_COMPEX2_100VG -#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 -#endif - #define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_SIG_LEN 8 /* same as EISA_SIG_LEN */ #define HP100_MAX_PACKET_SIZE (1536+4) #define HP100_MIN_PACKET_SIZE 60 @@ -165,20 +148,9 @@ typedef struct net_device_stats hp100_st * structures */ -struct hp100_eisa_id { - u_int id; - const char *name; - u_char bus; -}; - -struct hp100_pci_id { - u_short vendor; - u_short device; -}; - struct hp100_private { - struct hp100_eisa_id *id; spinlock_t lock; + char id[HP100_SIG_LEN]; u_short chip; u_short soft_model; u_int memory_size; @@ -196,7 +168,7 @@ struct hp100_private { u_char mac1_mode; u_char mac2_mode; u_char hash_bytes[8]; - hp100_stats_t stats; + struct net_device_stats stats; /* Rings for busmaster mode: */ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ @@ -216,83 +188,36 @@ struct hp100_private { /* * variables */ - -static struct hp100_eisa_id hp100_eisa_ids[] = { - - /* 10/100 EISA card with revision A Cascade chip */ - {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, - - /* 10/100 ISA card with revision A Cascade chip */ - {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, - - /* 10 only EISA card with Cascade chip */ - {0x2019F022, "HP 27248B", HP100_BUS_EISA}, - - /* 10/100 EISA card with Cascade chip */ - {0x4019F022, "HP J2577", HP100_BUS_EISA}, - - /* 10/100 ISA card with Cascade chip */ - {0x5019F022, "HP J2573", HP100_BUS_ISA}, - - /* 10/100 EISA card with AT&T chip */ - {0x9019f022, "HP J2577", HP100_BUS_EISA }, - - /* 10/100 PCI card - old J2585A */ - {0x1030103c, "HP J2585A", HP100_BUS_PCI}, - - /* 10/100 PCI card - new J2585B - master capable */ - {0x1041103c, "HP J2585B", HP100_BUS_PCI}, - - /* 10 Mbit Combo Adapter */ - {0x1042103c, "HP J2970", HP100_BUS_PCI}, - - /* 10 Mbit 10baseT Adapter */ - {0x1040103c, "HP J2973", HP100_BUS_PCI}, - - /* 10/100 EISA card from Compex */ - {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, - - /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */ - /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */ - /* version of adapter, too... */ - {0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA}, - - /* 10/100 PCI card from Compex - FreedomLine - * - * I think this card doesn't like aic7178 scsi controller, but - * I haven't tested this much. It works fine on diskless machines. - * Jacek Lipkowski - */ - {0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI}, - - /* 10/100 PCI card from Compex (J2585A compatible) */ - {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI}, - - /* 10/100 PCI card from KTI */ - {0x40008e2e, "KTI DP-200", HP100_BUS_PCI } +static const char *hp100_isa_tbl[] = { + "HWPF150", /* HP J2573 rev A */ + "HWP1950", /* HP J2573 */ }; -#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) - -#ifdef CONFIG_PCI -static struct hp100_pci_id hp100_pci_ids[] = { - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B}, - {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4}, - {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG} +#ifdef CONFIG_EISA +static struct eisa_device_id hp100_eisa_tbl[] = { + { "HWPF180" }, /* HP J2577 rev A */ + { "HWP1920" }, /* HP 27248B */ + { "HWP1940" }, /* HP J2577 */ + { "HWP1990" }, /* HP J2577 */ + { "CPX0301" }, /* ReadyLink ENET100-VG4 */ + { "CPX0401" }, /* FreedomLine 100/VG */ }; +MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); #endif -#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) - +#ifdef CONFIG_PCI static struct pci_device_id hp100_pci_tbl[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2973A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,}, +/* {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_DP200, PCI_ANY_ID, PCI_ANY_ID }, */ {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hp100_pci_tbl); +#endif static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; @@ -316,7 +241,7 @@ static int hp100_start_xmit(struct sk_bu static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev); static void hp100_rx(struct net_device *dev); -static hp100_stats_t *hp100_get_stats(struct net_device *dev); +static struct net_device_stats *hp100_get_stats(struct net_device *dev); static void hp100_misc_interrupt(struct net_device *dev); static void hp100_update_stats(struct net_device *dev); static void hp100_clear_stats(struct hp100_private *lp, int ioaddr); @@ -370,196 +295,180 @@ static void wait(void) * since this could cause problems when the card is not installed. */ -int __init hp100_probe(struct net_device *dev) +/* + * Read board id and convert to string. + * Effectively same code as decode_eisa_sig + */ +static __init const char *hp100_read_id(int ioaddr) { - int base_addr = dev ? dev->base_addr : 0; - int ioaddr = 0; - int pci_start_index = 0; + int i; + static char str[HP100_SIG_LEN]; + unsigned char sig[4], sum; + unsigned short rev; -#ifdef HP100_DEBUG_B - hp100_outw(0x4200, TRACE); - printk("hp100: %s: probe\n", dev->name); -#endif + hp100_page(ID_MAC_ADDR); + sum = 0; + for (i = 0; i < 4; i++) { + sig[i] = hp100_inb(BOARD_ID + i); + sum += sig[i]; + } - if (base_addr > 0xff) { /* Check a single specified location. */ - if (check_region(base_addr, HP100_REGION_SIZE)) - return -EINVAL; - if (base_addr < 0x400) - return hp100_probe1(dev, base_addr, HP100_BUS_ISA, - NULL); - if (EISA_bus && base_addr >= 0x1c38 && ((base_addr - 0x1c38) & 0x3ff) == 0) - return hp100_probe1(dev, base_addr, HP100_BUS_EISA, NULL); -#ifdef CONFIG_PCI - printk("hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name); -#else - return -ENODEV; -#endif - } else -#ifdef CONFIG_PCI - if (base_addr > 0 && base_addr < 8 + 1) - pci_start_index = 0x100 | (base_addr - 1); - else -#endif - if (base_addr != 0) - return -ENXIO; + sum += hp100_inb(BOARD_ID + i); + if (sum != 0xff) + return NULL; /* bad checksum */ - /* First: scan PCI bus(es) */ + str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); + str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); + str[2] = (sig[1] & 0x1f) + ('A' - 1); + rev = (sig[2] << 8) | sig[3]; + sprintf(str + 3, "%04X", rev); -#ifdef CONFIG_PCI - { - int pci_index; - struct pci_dev *pci_dev = NULL; - int pci_id_index; - u_short pci_command; - -#ifdef HP100_DEBUG_PCI - printk("hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name); -#endif - pci_index = 0; - for (pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; - pci_id_index++) { - while ((pci_dev = pci_find_device(hp100_pci_ids[pci_id_index].vendor, - hp100_pci_ids[pci_id_index].device, - pci_dev)) != NULL) { - if (pci_index < (pci_start_index & 7)) { - pci_index++; - continue; - } - if (pci_enable_device(pci_dev)) - continue; - /* found... */ - ioaddr = pci_resource_start(pci_dev, 0); - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - pci_read_config_word(pci_dev, PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_IO)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_IO; - pci_write_config_word(pci_dev, PCI_COMMAND, pci_command); - } - if (!(pci_command & PCI_COMMAND_MASTER)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_MASTER; - pci_write_config_word(pci_dev, PCI_COMMAND, pci_command); - } -#ifdef HP100_DEBUG - printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); -#endif - if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_dev) == 0) - return 0; - } - } - } - if (pci_start_index > 0) - return -ENODEV; -#endif /* CONFIG_PCI */ + return str; +} - /* Second: Probe all EISA possible port regions (if EISA bus present) */ - for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, NULL) == 0) - return 0; - } +static __init int hp100_isa_probe1(struct net_device *dev, int addr) +{ + const char *sig; + int i; + + if (!request_region(addr, HP100_REGION_SIZE, "hp100")) + goto err; + + sig = hp100_read_id(addr); + release_region(addr, HP100_REGION_SIZE); + + if (sig == NULL) + goto err; + + for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) { + if (!strcmp(hp100_isa_tbl[i], sig)) + break; - /* Third: Probe all ISA possible port regions */ - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, NULL) == 0) - return 0; } + if (i < ARRAY_SIZE(hp100_isa_tbl)) + return hp100_probe1(dev, addr, HP100_BUS_ISA, NULL); + err: return -ENODEV; + +} +/* + * Probe for ISA board. + * EISA and PCI are handled by device infrastructure. + */ + +static int __init hp100_isa_probe(struct net_device *dev, int addr) +{ + int err = -ENODEV; + + /* Probe for a specific ISA address */ + if (addr > 0xff && addr < 0x400) + err = hp100_isa_probe1(dev, addr); + + else if (addr != 0) + err = -ENXIO; + + else { + /* Probe all ISA possible port regions */ + for (addr = 0x100; addr < 0x400; addr += 0x20) { + err = hp100_isa_probe1(dev, addr); + if (!err) + break; + } + } + return err; +} + + +struct net_device * __init hp100_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + SET_MODULE_OWNER(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4200, TRACE); + printk("hp100: %s: probe\n", dev->name); +#endif + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + err = hp100_isa_probe(dev, dev->base_addr); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: + release_region(dev->base_addr, HP100_REGION_SIZE); + out: + free_netdev(dev); + return ERR_PTR(err); } static int __init hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev) { int i; - - u_char uc, uc_1; - u_int eisa_id; + int err = -ENODEV; + const char *eid; u_int chip; + u_char uc; u_int memory_size = 0, virt_memory_size = 0; u_short local_mode, lsw; short mem_mapped; unsigned long mem_ptr_phys; void **mem_ptr_virt; struct hp100_private *lp; - struct hp100_eisa_id *eid; #ifdef HP100_DEBUG_B hp100_outw(0x4201, TRACE); printk("hp100: %s: probe1\n", dev->name); #endif - if (dev == NULL) { -#ifdef HP100_DEBUG - printk("hp100_probe1: %s: dev == NULL ?\n", dev->name); -#endif - return -EIO; - } + /* memory region for programmed i/o */ + if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) + goto out1; - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { - return -ENODEV; - } else { - chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; + if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) + goto out2; + + chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; #ifdef HP100_DEBUG - if (chip == HP100_CHIPID_SHASTA) - printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_RAINIER) - printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_LASSEN) - printk("hp100: %s: Lassen Chip detected.\n", dev->name); - else - printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); + if (chip == HP100_CHIPID_SHASTA) + printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_RAINIER) + printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_LASSEN) + printk("hp100: %s: Lassen Chip detected.\n", dev->name); + else + printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); #endif - } dev->base_addr = ioaddr; - hp100_page(ID_MAC_ADDR); - for (i = uc = eisa_id = 0; i < 4; i++) { - eisa_id >>= 8; - uc_1 = hp100_inb(BOARD_ID + i); - eisa_id |= uc_1 << 24; - uc += uc_1; - } - uc += hp100_inb(BOARD_ID + 4); - - if (uc != 0xff) { /* bad checksum? */ - printk("hp100_probe: %s: bad EISA ID checksum at base port 0x%x\n", dev->name, ioaddr); - return -ENODEV; - } - - for (i = 0; i < HP100_EISA_IDS_SIZE; i++) - if (hp100_eisa_ids[i].id == eisa_id) - break; - if (i >= HP100_EISA_IDS_SIZE) { - for (i = 0; i < HP100_EISA_IDS_SIZE; i++) - if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff)) - break; - if (i >= HP100_EISA_IDS_SIZE) { - printk ("hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev->name, ioaddr, eisa_id); - return -ENODEV; - } - } - eid = &hp100_eisa_ids[i]; - if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) { - printk("hp100_probe: %s: newer version of card %s at port 0x%x - unsupported\n", dev->name, eid->name, ioaddr); - return -ENODEV; + eid = hp100_read_id(ioaddr); + if (eid == NULL) { /* bad checksum? */ + printk(KERN_WARNING "hp100_probe: bad ID checksum at base port 0x%x\n", ioaddr); + goto out2; } + hp100_page(ID_MAC_ADDR); for (i = uc = 0; i < 7; i++) uc += hp100_inb(LAN_ADDR + i); if (uc != 0xff) { - printk("hp100_probe: %s: bad lan address checksum (card %s at port 0x%x)\n", dev->name, eid->name, ioaddr); - return -EIO; + printk(KERN_WARNING "hp100_probe: bad lan address checksum at port 0x%x)\n", ioaddr); + err = -EIO; + goto out2; } /* Make sure, that all registers are correctly updated... */ @@ -607,17 +516,17 @@ static int __init hp100_probe1(struct ne hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: %s: IO mapped mode forced.\n", dev->name); + printk("hp100: IO mapped mode forced.\n"); } else if (local_mode == 2) { hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: %s: Shared memory mode requested.\n", dev->name); + printk("hp100: Shared memory mode requested.\n"); } else if (local_mode == 4) { if (chip == HP100_CHIPID_LASSEN) { hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_SET_HB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: %s: Busmaster mode requested.\n", dev->name); + printk("hp100: Busmaster mode requested.\n"); } local_mode = 1; } @@ -643,7 +552,7 @@ static int __init hp100_probe1(struct ne /* Gracefully fallback to shared memory */ goto busmasterfail; } - printk("hp100: %s: Busmaster mode enabled.\n", dev->name); + printk("hp100: Busmaster mode enabled.\n"); hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); } else { busmasterfail: @@ -675,7 +584,7 @@ static int __init hp100_probe1(struct ne mem_ptr_phys &= ~0x1fff; /* 8k alignment */ if (bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff) != 0) { - printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name); + printk("hp100: Can only use programmed i/o mode.\n"); mem_ptr_phys = 0; mem_mapped = 0; local_mode = 3; /* Use programmed i/o */ @@ -699,7 +608,7 @@ static int __init hp100_probe1(struct ne } if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ - printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name); + printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); local_mode = 3; virt_memory_size = 0; } @@ -710,17 +619,14 @@ static int __init hp100_probe1(struct ne mem_mapped = 0; mem_ptr_phys = 0; mem_ptr_virt = NULL; - printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name); + printk("hp100: Using (slow) programmed i/o mode.\n"); } /* Initialise the "private" data structure for this card. */ - if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) - return -ENOMEM; - lp = (struct hp100_private *) dev->priv; - memset(lp, 0, sizeof(struct hp100_private)); + spin_lock_init(&lp->lock); - lp->id = eid; + strlcpy(lp->id, eid, HP100_SIG_LEN); lp->chip = chip; lp->mode = local_mode; lp->bus = bus; @@ -741,9 +647,6 @@ static int __init hp100_probe1(struct ne lp->virt_memory_size = virt_memory_size; lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - /* memory region for programmed i/o */ - request_region(dev->base_addr, HP100_REGION_SIZE, eid->name); - dev->open = hp100_open; dev->stop = hp100_close; @@ -776,10 +679,6 @@ static int __init hp100_probe1(struct ne /* Reset statistics (counters) */ hp100_clear_stats(lp, ioaddr); - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pci_dev->dev); - ether_setup(dev); - /* If busmaster mode is wanted, a dma-capable memory area is needed for * the rx and tx PDLs * PCI cards can access the whole PC memory. Therefore GFP_DMA is not @@ -795,8 +694,10 @@ static int __init hp100_probe1(struct ne /* Conversion to new PCI API : * Pages are always aligned and zeroed, no need to it ourself. * Doc says should be OK for EISA bus as well - Jean II */ - if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) - return -ENOMEM; + if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) { + err = -ENOMEM; + goto out2; + } lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn); #ifdef HP100_DEBUG_BM @@ -818,7 +719,7 @@ static int __init hp100_probe1(struct ne lp->lan_type = hp100_sense_lan(dev); /* Print out a message what about what we think we have probed. */ - printk("hp100: %s: %s at 0x%x, IRQ %d, ", dev->name, lp->id->name, ioaddr, dev->irq); + printk("hp100: at 0x%x, IRQ %d, ", ioaddr, dev->irq); switch (bus) { case HP100_BUS_EISA: printk("EISA"); @@ -833,7 +734,7 @@ static int __init hp100_probe1(struct ne printk(" bus, %dk SRAM (rx/tx %d%%).\n", lp->memory_size >> 10, lp->rx_ratio); if (lp->mode == 2) { /* memory mapped */ - printk("hp100: %s: Memory area at 0x%lx-0x%lx", dev->name, mem_ptr_phys, + printk("hp100: Memory area at 0x%lx-0x%lx", mem_ptr_phys, (mem_ptr_phys + (mem_ptr_phys > 0x100000 ? (u_long) lp->memory_size : 16 * 1024)) - 1); if (mem_ptr_virt) printk(" (virtual base %p)", mem_ptr_virt); @@ -843,7 +744,8 @@ static int __init hp100_probe1(struct ne dev->mem_start = mem_ptr_phys; dev->mem_end = mem_ptr_phys + lp->memory_size; } - printk("hp100: %s: ", dev->name); + + printk("hp100: "); if (lp->lan_type != HP100_LAN_ERR) printk("Adapter is attached to "); switch (lp->lan_type) { @@ -861,6 +763,10 @@ static int __init hp100_probe1(struct ne } return 0; +out2: + release_region(ioaddr, HP100_REGION_SIZE); +out1: + return -ENODEV; } /* This procedure puts the card into a stable init state */ @@ -950,6 +856,7 @@ static void hp100_hwinit(struct net_devi /* Finally try to log in the Hub if there may be a VG connection. */ if ((lp->lan_type == HP100_LAN_100) || (lp->lan_type == HP100_LAN_ERR)) hp100_login_to_vg_hub(dev, 0); /* relogin */ + } @@ -1152,7 +1059,7 @@ static int hp100_open(struct net_device if (request_irq(dev->irq, hp100_interrupt, lp->bus == HP100_BUS_PCI || lp->bus == HP100_BUS_EISA ? SA_SHIRQ : SA_INTERRUPT, - lp->id->name, dev)) { + "hp100", dev)) { printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq); return -EAGAIN; } @@ -2054,7 +1961,7 @@ static void hp100_rx_bm(struct net_devic /* * statistics */ -static hp100_stats_t *hp100_get_stats(struct net_device *dev) +static struct net_device_stats *hp100_get_stats(struct net_device *dev) { unsigned long flags; int ioaddr = dev->base_addr; @@ -2558,10 +2465,14 @@ static int hp100_sense_lan(struct net_de return HP100_LAN_COAX; } - if ((lp->id->id == 0x02019F022) || - (lp->id->id == 0x01042103c) || (lp->id->id == 0x01040103c)) - return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ - + /* Those cards don't have a 100 Mbit connector */ + if ( !strcmp(lp->id, "HWP1920") || + (lp->pci_dev && + lp->pci_dev->vendor == PCI_VENDOR_ID && + (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A || + lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A))) + return HP100_LAN_ERR; + if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ return HP100_LAN_100; return HP100_LAN_ERR; @@ -2915,122 +2826,248 @@ void hp100_RegisterDump(struct net_devic #endif +static void cleanup_dev(struct net_device *d) +{ + struct hp100_private *p = (struct hp100_private *) d->priv; + + unregister_netdev(d); + release_region(d->base_addr, HP100_REGION_SIZE); + + if (p->mode == 1) /* busmaster */ + pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, + p->page_vaddr_algn, + virt_to_whatever(d, p->page_vaddr_algn)); + if (p->mem_ptr_virt) + iounmap(p->mem_ptr_virt); + + free_netdev(d); +} + +#ifdef CONFIG_EISA +static int __init hp100_eisa_probe (struct device *gendev) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + struct eisa_device *edev = to_eisa_device(gendev); + int err; + + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &edev->dev); + + err = hp100_probe1(dev, edev->base_addr, HP100_BUS_EISA, NULL); + if (err) + goto out1; + + err = register_netdev(dev); + if (err) + goto out2; + +#ifdef HP100_DEBUG + printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, + dev->base_addr); +#endif + gendev->driver_data = dev; + return 0; + out2: + release_region(dev->base_addr, HP100_REGION_SIZE); + out1: + free_netdev(dev); + return err; +} + +static int __devexit hp100_eisa_remove (struct device *gendev) +{ + struct net_device *dev = gendev->driver_data; + cleanup_dev(dev); + return 0; +} + +static struct eisa_driver hp100_eisa_driver = { + .id_table = hp100_eisa_tbl, + .driver = { + .name = "hp100", + .probe = hp100_eisa_probe, + .remove = __devexit_p (hp100_eisa_remove), + } +}; +#endif + +#ifdef CONFIG_PCI +static int __devinit hp100_pci_probe (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int ioaddr = pci_resource_start(pdev, 0); + u_short pci_command; + int err; + + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (!(pci_command & PCI_COMMAND_IO)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_IO; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + if (!(pci_command & PCI_COMMAND_MASTER)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + + err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); + if (err) + goto out1; + err = register_netdev(dev); + if (err) + goto out2; + +#ifdef HP100_DEBUG + printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); +#endif + pci_set_drvdata(pdev, dev); + return 0; + out2: + release_region(dev->base_addr, HP100_REGION_SIZE); + out1: + free_netdev(dev); + return err; +} + +static void __devexit hp100_pci_remove (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + cleanup_dev(dev); +} + + +static struct pci_driver hp100_pci_driver = { + .name = "hp100", + .id_table = hp100_pci_tbl, + .probe = hp100_pci_probe, + .remove = __devexit_p(hp100_pci_remove), +}; +#endif + /* * module section */ -#ifdef MODULE - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jaroslav Kysela , " "Siegfried \"Frieder\" Loeffler (dg1sek) "); MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters"); /* - * Note: if you have more than five 100vg cards in your pc, feel free to - * increase this value - */ - -#define HP100_DEVICES 5 - -/* - * Note: to register three eisa or pci devices, use: + * Note: to register three isa devices, use: * option hp100 hp100_port=0,0,0 * to register one card at io 0x280 as eth239, use: - * option hp100 hp100_port=0x280 hp100_name=eth239 + * option hp100 hp100_port=0x280 */ - +#if defined(MODULE) && defined(CONFIG_ISA) +#define HP100_DEVICES 5 /* Parameters set by insmod */ static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 }; MODULE_PARM(hp100_port, "1-" __MODULE_STRING(HP100_DEVICES) "i"); -/* Allocate HP100_DEVICES strings of length IFNAMSIZ, one string for each device */ -static char hp100_name[HP100_DEVICES][IFNAMSIZ] = { "", "", "", "", "" }; -/* Allow insmod to write those HP100_DEVICES strings individually */ -MODULE_PARM(hp100_name, "1-" __MODULE_STRING(HP100_DEVICES) "c" __MODULE_STRING(IFNAMSIZ)); - /* List of devices */ static struct net_device *hp100_devlist[HP100_DEVICES]; -static void release_dev(int i) +static int __init hp100_isa_init(void) { - struct net_device *d = hp100_devlist[i]; - struct hp100_private *p = (struct hp100_private *) d->priv; + struct net_device *dev; + int i, err, cards = 0; - unregister_netdev(d); - release_region(d->base_addr, HP100_REGION_SIZE); + /* Don't autoprobe ISA bus */ + if (hp100_port[0] == 0) + return -ENODEV; - if (p->mode == 1) /* busmaster */ - pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, p->page_vaddr_algn, virt_to_whatever(d, p->page_vaddr_algn)); - if (p->mem_ptr_virt) - iounmap(p->mem_ptr_virt); - kfree(d->priv); - d->priv = NULL; - free_netdev(d); - hp100_devlist[i] = NULL; + /* Loop on all possible base addresses */ + for (i = 0; i < HP100_DEVICES && hp100_port[i] != -1; ++i) { + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + printk(KERN_WARNING "hp100: no memory for network device\n"); + while (cards > 0) + cleanup_dev(hp100_devlist[--cards]); + + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + err = hp100_isa_probe(dev, hp100_port[i]); + if (!err) { + err = register_netdev(dev); + if (!err) + hp100_devlist[cards++] = dev; + else + release_region(dev->base_addr, HP100_REGION_SIZE); + } + + if (err) + free_netdev(dev); + } + + return cards > 0 ? 0 : -ENODEV; } -static int __init hp100_module_init(void) +static void __exit hp100_isa_cleanup(void) { - int i, cards; + int i; -#ifndef CONFIG_PCI - if (hp100_port == 0 && !EISA_bus) - printk("hp100: You should not use auto-probing with insmod!\n"); + for (i = 0; i < HP100_DEVICES; i++) { + struct net_device *dev = hp100_devlist[i]; + if (dev) + cleanup_dev(dev); + } +} +#else +#define hp100_isa_init() (0) +#define hp100_isa_cleanup() do { } while(0) #endif - /* Loop on all possible base addresses */ - i = -1; - cards = 0; - while ((hp100_port[++i] != -1) && (i < HP100_DEVICES)) { - /* Create device and set basics args */ - hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!hp100_devlist[i]) - goto fail; - memset(hp100_devlist[i], 0x00, sizeof(struct net_device)); -#if LINUX_VERSION_CODE >= 0x020362 /* 2.3.99-pre7 */ - memcpy(hp100_devlist[i]->name, hp100_name[i], IFNAMSIZ); /* Copy name */ -#else - hp100_devlist[i]->name = hp100_name[i]; -#endif /* LINUX_VERSION_CODE >= 0x020362 */ - hp100_devlist[i]->base_addr = hp100_port[i]; - hp100_devlist[i]->init = &hp100_probe; - - /* Try to create the device */ - if (register_netdev(hp100_devlist[i]) != 0) { - /* DeAllocate everything */ - /* Note: if dev->priv is mallocated, there is no way to fail */ - kfree(hp100_devlist[i]); - hp100_devlist[i] = (struct net_device *) NULL; - } else - cards++; - } /* Loop over all devices */ +static int __init hp100_module_init(void) +{ + int err; - return cards > 0 ? 0 : -ENODEV; - fail: - while (cards && --i) - if (hp100_devlist[i]) { - release_dev(i); - --cards; - } - return -ENOMEM; + err = hp100_isa_init(); + +#ifdef CONFIG_EISA + err |= eisa_driver_register(&hp100_eisa_driver); +#endif +#ifdef CONFIG_PCI + err |= pci_module_init(&hp100_pci_driver); +#endif + return err; } + static void __exit hp100_module_exit(void) { - int i; - - /* TODO: Check if all skb's are released/freed. */ - for (i = 0; i < HP100_DEVICES; i++) - if (hp100_devlist[i] != (struct net_device *) NULL) - release_dev(i); + hp100_isa_cleanup(); +#ifdef CONFIG_EISA + eisa_driver_unregister (&hp100_eisa_driver); +#endif +#ifdef CONFIG_PCI + pci_unregister_driver (&hp100_pci_driver); +#endif } module_init(hp100_module_init) module_exit(hp100_module_exit) -#endif /* MODULE */ - /* * Local variables: --- linux-2.6.1-rc1/drivers/net/hp.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/hp.c 2003-12-30 22:49:19.000000000 -0800 @@ -55,7 +55,6 @@ static unsigned int hppclan_portlist[] _ #define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */ #define HP_16BSTOP_PG 0xFF /* Same, for 16 bit cards. */ -int hp_probe(struct net_device *dev); static int hp_probe1(struct net_device *dev, int ioaddr); static int hp_open(struct net_device *dev); @@ -79,10 +78,11 @@ static char irqmap[16] __initdata= { 0, Also initialize the card and fill in STATION_ADDR with the station address. */ -int __init hp_probe(struct net_device *dev) +static int __init do_hp_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -91,13 +91,46 @@ int __init hp_probe(struct net_device *d else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; hppclan_portlist[i]; i++) + for (i = 0; hppclan_portlist[i]; i++) { if (hp_probe1(dev, hppclan_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + +struct net_device * __init hp_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_hp_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init hp_probe1(struct net_device *dev, int ioaddr) { int i, retval, board_id, wordmode; @@ -131,13 +164,6 @@ static int __init hp_probe1(struct net_d if (ei_debug && version_printed++ == 0) printk(version); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); for(i = 0; i < ETHER_ADDR_LEN; i++) @@ -166,14 +192,14 @@ static int __init hp_probe1(struct net_d if (*irqp == 0) { printk(" no free IRQ lines.\n"); retval = -EBUSY; - goto out1; + goto out; } } else { if (dev->irq == 2) dev->irq = 9; if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); - goto out1; + goto out; } } @@ -195,9 +221,6 @@ static int __init hp_probe1(struct net_d hp_init_card(dev); return 0; -out1: - kfree(dev->priv); - dev->priv = NULL; out: release_region(ioaddr, HP_IO_EXTENT); return retval; @@ -372,7 +395,7 @@ hp_init_card(struct net_device *dev) #ifdef MODULE #define MAX_HP_CARDS 4 /* Max number of HP cards per module */ -static struct net_device dev_hp[MAX_HP_CARDS]; +static struct net_device *dev_hp[MAX_HP_CARDS]; static int io[MAX_HP_CARDS]; static int irq[MAX_HP_CARDS]; @@ -388,27 +411,33 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { - struct net_device *dev = &dev_hp[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = hp_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_hp_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_hp[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -417,14 +446,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { - struct net_device *dev = &dev_hp[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - NIC_OFFSET; - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(ioaddr, HP_IO_EXTENT); + struct net_device *dev = dev_hp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/hplance.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/hplance.c 2003-12-30 22:49:19.000000000 -0800 @@ -50,8 +50,7 @@ struct hplance_private { * plus board-specific init, open and close actions. * Oh, and we need to tell the generic code how to read and write LANCE registers... */ -int hplance_probe(struct net_device *dev); -static int hplance_init(struct net_device *dev, int scode); +static void hplance_init(struct net_device *dev, int scode); static int hplance_open(struct net_device *dev); static int hplance_close(struct net_device *dev); static void hplance_writerap(void *priv, unsigned short value); @@ -62,57 +61,61 @@ static unsigned short hplance_readrdp(vo static struct hplance_private *root_hplance_dev; #endif +static void cleanup_card(struct net_device *dev) +{ + struct hplance_private *lp = dev->priv; + dio_unconfig_board(lp->scode); +} + /* Find all the HP Lance boards and initialise them... */ -int __init hplance_probe(struct net_device *dev) +struct net_device * __init hplance_probe(int unit) { - int cards = 0, called = 0; + struct net_device *dev; + + if (!MACH_IS_HP300) + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct hplance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } - if (!MACH_IS_HP300 || called) - return(ENODEV); - called++; + SET_MODULE_OWNER(dev); /* Isn't DIO nice? */ for(;;) { - int v, scode = dio_find(DIO_ID_LAN); + int scode = dio_find(DIO_ID_LAN); if (!scode) break; - if(cards) - dev = NULL; /* don't trash previous device, make a new one */ - cards++; - - v = hplance_init(dev, scode); - if (v) /* error, abort immediately */ - return v; + dio_config_board(scode); + hplance_init(dev, scode); + if (!register_netdev(dev)) { + struct hplance_private *lp = dev->priv; + lp->next_module = root_hplance_dev; + root_hplance_dev = lp; + return dev; + } + cleanup_card(dev); } - /* OK, return success, or ENODEV if we didn't find any cards */ - if (!cards) - return -ENODEV; - return 0; + free_netdev(dev); + return ERR_PTR(-ENODEV); } /* Initialise a single lance board at the given select code */ -static int __init hplance_init(struct net_device *dev, int scode) +static void __init hplance_init(struct net_device *dev, int scode) { const char *name = dio_scodetoname(scode); void *va = dio_scodetoviraddr(scode); struct hplance_private *lp; int i; -#ifdef MODULE - dev = init_etherdev(0, sizeof(struct hplance_private)); - if (!dev) - return -ENOMEM; -#else - dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct hplance_private)); -#endif - SET_MODULE_OWNER(dev); - printk("%s: %s; select code %d, addr", dev->name, name, scode); /* reset the board */ @@ -154,17 +157,7 @@ static int __init hplance_init(struct ne lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; lp->scode = scode; lp->base = va; - ether_setup(dev); printk(", irq %d\n", lp->lance.irq); - -#ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_hplance_dev; - root_hplance_dev = lp; -#endif /* MODULE */ - - dio_config_board(scode); /* tell bus scanning code this one's taken */ - return 0; } /* This is disgusting. We have to check the DIO status register for ack every @@ -227,8 +220,10 @@ static int hplance_close(struct net_devi MODULE_LICENSE("GPL"); int init_module(void) { - root_lance_dev = NULL; - return hplance_probe(NULL); + int found = 0; + while (!IS_ERR(hplance_probe(-1))) + found++; + return found ? 0 : -ENODEV; } void cleanup_module(void) @@ -237,8 +232,8 @@ void cleanup_module(void) struct hplance_private *lp; while (root_hplance_dev) { lp = root_hplance_dev->next_module; - dio_unconfig_board(lp->scode); unregister_netdev(root_lance_dev->dev); + cleanup_card(root_lance_dev->dev); free_netdev(root_lance_dev->dev); root_lance_dev = lp; } --- linux-2.6.1-rc1/drivers/net/hp-plus.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/hp-plus.c 2003-12-30 22:49:19.000000000 -0800 @@ -92,7 +92,6 @@ enum HP_Option { EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20, MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, }; -int hp_plus_probe(struct net_device *dev); static int hpp_probe1(struct net_device *dev, int ioaddr); static void hpp_reset_8390(struct net_device *dev); @@ -115,10 +114,11 @@ static void hpp_io_get_8390_hdr(struct n /* Probe a list of addresses for an HP LAN+ adaptor. This routine is almost boilerplate. */ -int __init hp_plus_probe(struct net_device *dev) +static int __init do_hpp_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -127,13 +127,46 @@ int __init hp_plus_probe(struct net_devi else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; hpplus_portlist[i]; i++) + for (i = 0; hpplus_portlist[i]; i++) { if (hpp_probe1(dev, hpplus_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: hpp_close() handles free_irq */ + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + +struct net_device * __init hp_plus_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_hpp_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + /* Do the interesting part of the probe at a single address. */ static int __init hpp_probe1(struct net_device *dev, int ioaddr) { @@ -179,13 +212,6 @@ static int __init hpp_probe1(struct net_ printk(" ID %4.4x", inw(ioaddr + 12)); } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("hp-plus.c: unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* Read the IRQ line. */ outw(HW_Page, ioaddr + HP_PAGING); { @@ -400,7 +426,7 @@ hpp_mem_block_output(struct net_device * #ifdef MODULE #define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */ -static struct net_device dev_hpp[MAX_HPP_CARDS]; +static struct net_device *dev_hpp[MAX_HPP_CARDS]; static int io[MAX_HPP_CARDS]; static int irq[MAX_HPP_CARDS]; @@ -416,27 +442,33 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { - struct net_device *dev = &dev_hpp[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = hp_plus_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_hpp_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_hpp[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -445,14 +477,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { - struct net_device *dev = &dev_hpp[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - NIC_OFFSET; - void *priv = dev->priv; - /* NB: hpp_close() handles free_irq */ - release_region(ioaddr, HP_IO_EXTENT); + struct net_device *dev = dev_hpp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/hydra.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/hydra.c 2003-12-30 22:49:19.000000000 -0800 @@ -89,13 +89,14 @@ static int __init hydra_init(unsigned lo const char name[] = "NE2000"; int start_page, stop_page; int j; + int err; static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = init_etherdev(NULL, 0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); @@ -113,13 +114,9 @@ static int __init hydra_init(unsigned lo /* Install the Interrupt handler */ if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, "Hydra Ethernet", - dev)) + dev)) { + free_netdev(dev); return -EAGAIN; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; } printk("%s: hydra at 0x%08lx, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", dev->name, ZTWO_PADDR(board), @@ -146,7 +143,13 @@ static int __init hydra_init(unsigned lo root_hydra_dev = dev; #endif NS8390_init(dev, 0); - return 0; + err = register_netdev(dev); + if (!err) + return 0; + + free_irq(IRQ_AMIGA_PORTS, dev); + free_netdev(dev); + return err; } static int hydra_open(struct net_device *dev) --- linux-2.6.1-rc1/drivers/net/ibmlana.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/ibmlana.c 2003-12-30 22:49:19.000000000 -0800 @@ -906,7 +906,7 @@ static void ibmlana_set_multicast_list(s static int startslot; /* counts through slots when probing multiple devices */ -int ibmlana_probe(struct net_device *dev) +static int ibmlana_probe(struct net_device *dev) { int force_detect = 0; int slot, z; @@ -924,34 +924,21 @@ int ibmlana_probe(struct net_device *dev if (dev->mem_start == 1) force_detect = 1; - /* search through slots */ - if (dev != NULL) { - base = dev->mem_start; - irq = dev->irq; - } - slot = mca_find_adapter(IBM_LANA_ID, startslot); + base = dev->mem_start; + irq = dev->irq; - while (slot != -1) { + for (slot = startslot; (slot = mca_find_adapter(IBM_LANA_ID, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, &base, &memlen, &iobase, &irq, &medium); /* slot already in use ? */ - if (mca_is_adapter_used(slot)) { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); + if (mca_is_adapter_used(slot)) continue; - } /* were we looking for something different ? */ - if (dev->irq != 0 || dev->mem_start != 0) { - if (dev->irq != 0 && dev->irq != irq) { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); - continue; - } - if (dev->mem_start != 0 && dev->mem_start != base) - { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); - continue; - } - } + if (dev->irq && dev->irq != irq) + continue; + if (dev->mem_start && dev->mem_start != base) + continue; /* found something that matches */ break; } @@ -977,16 +964,11 @@ int ibmlana_probe(struct net_device *dev mca_mark_as_used(slot); /* allocate structure */ - priv = dev->priv = (ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL); - if (!priv) { - release_region(iobase, IBM_LANA_IORANGE); - return -ENOMEM; - } + priv = dev->priv; priv->slot = slot; priv->realirq = irq; priv->medium = medium; spin_lock_init(&priv->lock); - memset(&priv->stat, 0, sizeof(struct net_device_stats)); /* set base + irq for this device (irq not allocated so far) */ @@ -1006,10 +988,6 @@ int ibmlana_probe(struct net_device *dev dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; - /* generic setup */ - - ether_setup(dev); - /* copy out MAC address */ for (z = 0; z < sizeof(dev->dev_addr); z++) @@ -1044,7 +1022,7 @@ int ibmlana_probe(struct net_device *dev #define DEVMAX 5 -static struct net_device moddevs[DEVMAX]; +static struct net_device *moddevs[DEVMAX]; static int irq; static int io; @@ -1056,41 +1034,47 @@ MODULE_LICENSE("GPL"); int init_module(void) { - int z, res; + int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { - moddevs[z].init = ibmlana_probe; - moddevs[z].irq = irq; - moddevs[z].base_addr = io; - res = register_netdev(moddevs + z); - if (res != 0) - return (z > 0) ? 0 : -EIO; + struct net_device *dev = alloc_etherdev(sizeof(ibmlana_priv)); + if (!dev) + break; + dev->irq = irq; + dev->base_addr = io; + if (ibmlana_probe(dev)) { + free_netdev(dev); + break; + } + if (register_netdev(dev)) { + ibmlana_priv *priv = dev->priv; + release_region(dev->base_addr, IBM_LANA_IORANGE); + mca_mark_as_unused(priv->slot); + mca_set_adapter_name(priv->slot, ""); + mca_set_adapter_procfn(priv->slot, NULL, NULL); + free_netdev(dev); + break; + } + moddevs[z] = dev; } - return 0; + return (z > 0) ? 0 : -EIO; } void cleanup_module(void) { - struct net_device *dev; - ibmlana_priv *priv; int z; - for (z = 0; z < DEVMAX; z++) { - dev = moddevs + z; - if (dev->priv != NULL) { - priv = (ibmlana_priv *) dev->priv; + struct net_device *dev = moddevs[z]; + if (dev) { + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + unregister_netdev(dev); /*DeinitBoard(dev); */ - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; release_region(dev->base_addr, IBM_LANA_IORANGE); - unregister_netdev(dev); mca_mark_as_unused(priv->slot); mca_set_adapter_name(priv->slot, ""); mca_set_adapter_procfn(priv->slot, NULL, NULL); - kfree(dev->priv); - dev->priv = NULL; + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/ibmlana.h 2003-06-14 12:18:31.000000000 -0700 +++ 25/drivers/net/ibmlana.h 2003-12-30 22:49:19.000000000 -0800 @@ -275,7 +275,4 @@ typedef struct { #endif /* _IBM_LANA_DRIVER_ */ -extern int ibmlana_probe(struct net_device *); - - #endif /* _IBM_LANA_INCLUDE_ */ --- linux-2.6.1-rc1/drivers/net/irda/sa1100_ir.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/irda/sa1100_ir.c 2003-12-30 22:49:19.000000000 -0800 @@ -20,6 +20,7 @@ */ #include #include +#include #include #include #include @@ -358,9 +359,13 @@ static void sa1100_irda_shutdown(struct static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level) { struct net_device *dev = dev_get_drvdata(_dev); - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si; + + if (!dev || level != SUSPEND_DISABLE) + return 0; - if (si && si->open && level == SUSPEND_DISABLE) { + si = dev->priv; + if (si->open) { /* * Stop the transmit queue */ @@ -379,9 +384,13 @@ static int sa1100_irda_suspend(struct de static int sa1100_irda_resume(struct device *_dev, u32 level) { struct net_device *dev = dev_get_drvdata(_dev); - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si; - if (si && si->open && level == RESUME_ENABLE) { + if (!dev || level != RESUME_ENABLE) + return 0; + + si = dev->priv; + if (si->open) { /* * If we missed a speed change, initialise at the new speed * directly. It is debatable whether this is actually @@ -833,8 +842,6 @@ static int sa1100_irda_start(struct net_ struct sa1100_irda *si = dev->priv; int err; - MOD_INC_USE_COUNT; - si->speed = 9600; err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); @@ -890,7 +897,6 @@ err_tx_dma: err_rx_dma: free_irq(dev->irq, dev); err_irq: - MOD_DEC_USE_COUNT; return err; } @@ -930,8 +936,6 @@ static int sa1100_irda_stop(struct net_d sa1100_set_power(si, 0); - MOD_DEC_USE_COUNT; - return 0; } @@ -947,56 +951,48 @@ static int sa1100_irda_init_iobuf(iobuff return io->head ? 0 : -ENOMEM; } -static struct device_driver sa1100ir_driver = { - .name = "sa1100ir", - .bus = &system_bus_type, - .suspend = sa1100_irda_suspend, - .resume = sa1100_irda_resume, -}; - -static struct sys_device sa1100ir_device = { - .name = "sa1100ir", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA11x0 [IrDA]", - .bus_id = "0", - .driver = &sa1100ir_driver, - }, -}; - -static int sa1100_irda_net_init(struct net_device *dev) +static int sa1100_irda_probe(struct device *_dev) { - struct sa1100_irda *si = dev->priv; + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct sa1100_irda *si; unsigned int baudrate_mask; - int err = -ENOMEM; + int err; - si = kmalloc(sizeof(struct sa1100_irda), GFP_KERNEL); - if (!si) - goto out; + err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_3; - memset(si, 0, sizeof(*si)); + dev = alloc_irdadev(sizeof(struct sa1100_irda)); + if (!dev) + goto err_mem_4; - si->dev = &sa1100ir_device.dev; + si = dev->priv; + si->dev = &pdev->dev; /* * Initialise the HP-SIR buffers */ err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); if (err) - goto out; + goto err_mem_5; err = sa1100_irda_init_iobuf(&si->tx_buff, 4000); if (err) - goto out_free_rx; + goto err_mem_5; - dev->priv = si; dev->hard_start_xmit = sa1100_irda_hard_xmit; dev->open = sa1100_irda_start; dev->stop = sa1100_irda_stop; dev->do_ioctl = sa1100_irda_ioctl; dev->get_stats = sa1100_irda_stats; + dev->irq = IRQ_Ser2ICP; - irda_device_setup(dev); irda_init_max_qos_capabilies(&si->qos); /* @@ -1030,42 +1026,62 @@ static int sa1100_irda_net_init(struct n Ser2UTCR4 = si->utcr4; Ser2HSCR0 = HSCR0_UART; - return 0; - - kfree(si->tx_buff.head); -out_free_rx: - kfree(si->rx_buff.head); -out: - kfree(si); + err = register_netdev(dev); + if (err == 0) + dev_set_drvdata(&pdev->dev, si); + if (err) { + err_mem_5: + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + err_mem_4: + release_mem_region(__PREG(Ser2HSCR2), 0x04); + err_mem_3: + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + err_mem_2: + release_mem_region(__PREG(Ser2UTCR0), 0x24); + } + err_mem_1: return err; } -/* - * Remove all traces of this driver module from the kernel, so we can't be - * called. Note that the device has already been stopped, so we don't have - * to worry about interrupts or dma. - */ -static void sa1100_irda_net_uninit(struct net_device *dev) +static int sa1100_irda_remove(struct device *_dev) { - struct sa1100_irda *si = dev->priv; + struct net_device *dev = dev_get_drvdata(_dev); - dev->hard_start_xmit = NULL; - dev->open = NULL; - dev->stop = NULL; - dev->do_ioctl = NULL; - dev->get_stats = NULL; - dev->priv = NULL; - - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - kfree(si); + if (dev) { + struct sa1100_irda *si = dev->priv; + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(Ser2HSCR2), 0x04); + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + release_mem_region(__PREG(Ser2UTCR0), 0x24); + + return 0; } +static struct device_driver sa1100ir_driver = { + .name = "sa11x0-ir", + .bus = &platform_bus_type, + .probe = sa1100_irda_probe, + .remove = sa1100_irda_remove, + .suspend = sa1100_irda_suspend, + .resume = sa1100_irda_resume, +}; + +static struct platform_device sa1100ir_device = { + .name = "sa11x0-ir", + .id = 0, +}; + static int __init sa1100_irda_init(void) { - struct net_device *dev; - int err; + int ret; /* * Limit power level a sensible range. @@ -1075,103 +1091,30 @@ static int __init sa1100_irda_init(void) if (power_level > 3) power_level = 3; - err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_1; - err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_2; - err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_3; - - driver_register(&sa1100ir_driver); - sys_device_register(&sa1100ir_device); - - rtnl_lock(); - dev = dev_alloc("irda%d", &err); - if (dev) { - dev->irq = IRQ_Ser2ICP; - dev->init = sa1100_irda_net_init; - dev->uninit = sa1100_irda_net_uninit; - - err = register_netdevice(dev); - - if (err) - kfree(dev); - else - dev_set_drvdata(&sa1100ir_device.dev, dev); + ret = driver_register(&sa1100ir_driver); + if (ret == 0) { + ret = platform_device_register(&sa1100ir_device); + if (ret) + driver_unregister(&sa1100ir_driver); } - rtnl_unlock(); - - if (err) { - sys_device_unregister(&sa1100ir_device); - driver_unregister(&sa1100ir_driver); - - release_mem_region(__PREG(Ser2HSCR2), 0x04); -err_mem_3: - release_mem_region(__PREG(Ser2HSCR0), 0x1c); -err_mem_2: - release_mem_region(__PREG(Ser2UTCR0), 0x24); - } -err_mem_1: - return err; + return ret; } static void __exit sa1100_irda_exit(void) { - struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev); - - if (dev) - unregister_netdev(dev); - - sys_device_unregister(&sa1100ir_device); driver_unregister(&sa1100ir_driver); - - release_mem_region(__PREG(Ser2HSCR2), 0x04); - release_mem_region(__PREG(Ser2HSCR0), 0x1c); - release_mem_region(__PREG(Ser2UTCR0), 0x24); - - if(dev) - free_netdev(dev); + platform_device_unregister(&sa1100ir_device); } -static int __init sa1100ir_setup(char *line) -{ - char *opt; - - if (!line) - return 0; - - while ((opt = strsep(&line, ",")) != NULL) { - if (!strncmp(opt, "max_rate:", 9)) { - max_rate = simple_strtoul(opt + 9, NULL, 0); - continue; - } - if (!strncmp(opt, "power_level:", 12)) { - power_level = simple_strtoul(opt + 12, NULL, 0); - continue; - } - if (!strncmp(opt, "tx_lpm:", 7)) { - tx_lpm = simple_strtoul(opt + 7, NULL, 0); - continue; - } - } - - return 1; -} - -__setup("sa1100ir=", sa1100ir_setup); - module_init(sa1100_irda_init); module_exit(sa1100_irda_exit); +module_param(power_level, int, 0); +module_param(tx_lpm, int, 0); +module_param(max_rate, int, 0); MODULE_AUTHOR("Russell King "); MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(power_level, "i"); MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); -MODULE_PARM(tx_lpm, "i"); MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); -MODULE_PARM(max_rate, "i"); MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); --- linux-2.6.1-rc1/drivers/net/ixgb/ixgb_main.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/ixgb/ixgb_main.c 2003-12-30 22:49:19.000000000 -0800 @@ -446,7 +446,7 @@ ixgb_probe(struct pci_dev *pdev, const s iounmap(adapter->hw.hw_addr); err_ioremap: pci_release_regions(pdev); - kfree(netdev); + free_netdev(netdev); err_alloc_etherdev: return -ENOMEM; } --- linux-2.6.1-rc1/drivers/net/jazzsonic.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/drivers/net/jazzsonic.c 2003-12-30 22:49:19.000000000 -0800 @@ -80,7 +80,6 @@ static unsigned short known_revisions[] /* Index to functions, as function prototypes. */ -extern int sonic_probe(struct net_device *dev); static int sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq); @@ -89,29 +88,57 @@ static int sonic_probe1(struct net_devic * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -int __init sonic_probe(struct net_device *dev) +struct net_device * __init sonic_probe(int unit) { - unsigned int base_addr = dev ? dev->base_addr : 0; + struct net_device *dev; + struct sonic_local *lp; + unsigned int base_addr; + int err = 0; int i; /* * Don't probe if we're not running on a Jazz board. */ if (mips_machgroup != MACH_GROUP_JAZZ) - return -ENODEV; - if (base_addr >= KSEG0) /* Check a single specified location. */ - return sonic_probe1(dev, base_addr, dev->irq); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; sonic_portlist[i].port; i++) { - int base_addr = sonic_portlist[i].port; - if (check_region(base_addr, 0x100)) - continue; - if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0) - return 0; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(0); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + base_addr = dev->base_addr; + + if (base_addr >= KSEG0) { /* Check a single specified location. */ + err = sonic_probe1(dev, base_addr, dev->irq); + } else if (base_addr != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (i = 0; sonic_portlist[i].port; i++) { + int io = sonic_portlist[i].port; + if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) + break; + } + if (!sonic_portlist[i].port) + err = -ENODEV; } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + lp = dev->priv; + vdma_free(lp->rba_laddr); + kfree(lp->rba); + vdma_free(lp->cda_laddr); + kfree(lp); + release_region(dev->base_addr, 0x100); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr, @@ -121,8 +148,11 @@ static int __init sonic_probe1(struct ne unsigned int silicon_revision; unsigned int val; struct sonic_local *lp; + int err = -ENODEV; int i; + if (!request_region(base_addr, 0x100, dev->name)) + return -EBUSY; /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at @@ -140,12 +170,9 @@ static int __init sonic_probe1(struct ne if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); - return -ENODEV; + goto out; } - if (!request_region(base_addr, 0x100, dev->name)) - return -EBUSY; - if (sonic_debug && version_printed++ == 0) printk(version); @@ -175,6 +202,8 @@ static int __init sonic_probe1(struct ne } printk(" IRQ %d\n", irq); + + err = -ENOMEM; /* Initialize the device structure. */ if (dev->priv == NULL) { @@ -196,7 +225,7 @@ static int __init sonic_probe1(struct ne if (lp == NULL) { printk("%s: couldn't allocate memory for descriptors\n", dev->name); - return -ENOMEM; + goto out; } memset(lp, 0, sizeof(struct sonic_local)); @@ -206,7 +235,7 @@ static int __init sonic_probe1(struct ne if (lp->cda_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for " "descriptors\n", dev->name); - return -ENOMEM; + goto out1; } lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); @@ -219,7 +248,7 @@ static int __init sonic_probe1(struct ne if (!lp->rba) { printk("%s: couldn't allocate receive buffers\n", dev->name); - return -ENOMEM; + goto out2; } /* get virtual dma address */ @@ -228,7 +257,7 @@ static int __init sonic_probe1(struct ne if (lp->rba_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for receive " "buffers\n",dev->name); - return -ENOMEM; + goto out3; } /* now convert pointer to KSEG1 pointer */ @@ -252,9 +281,16 @@ static int __init sonic_probe1(struct ne SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); return 0; +out3: + kfree(lp->rba); +out2: + vdma_free(lp->cda_laddr); +out1: + kfree(lp); +out: + release_region(base_addr, 0x100); + return err; } /* --- linux-2.6.1-rc1/drivers/net/Kconfig 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/Kconfig 2003-12-30 22:49:20.000000000 -0800 @@ -657,7 +657,7 @@ config ELMC config ELMC_II tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)" - depends on NET_VENDOR_3COM && MCA && EXPERIMENTAL && BROKEN_ON_SMP + depends on NET_VENDOR_3COM && MCA && MCA_LEGACY help If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1283,6 +1283,19 @@ config B44 . The module will be called b44. +config FORCEDETH + tristate "Reverse Engineered nForce Ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + help + If you have a network (Ethernet) controller of this type, say Y and + read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here and read + . The module will be + called forcedeth. + + config CS89x0 tristate "CS89x0 support" depends on NET_PCI && ISA @@ -1341,8 +1354,9 @@ config EEPRO100_PIO say N. config E100 - tristate "EtherExpressPro/100 support (e100, Alternate Intel driver)" + tristate "Intel(R) PRO/100+ support" depends on NET_PCI && PCI + select MII ---help--- This driver supports Intel(R) PRO/100 family of adapters, which includes: @@ -1415,6 +1429,10 @@ config E100 . The module will be called e100. +config E100_NAPI + bool "Use Rx Polling (NAPI)" + depends on E100 + config LNE390 tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" depends on NET_PCI && EISA && EXPERIMENTAL @@ -1564,6 +1582,24 @@ config 8139_OLD_RX_RESET experience problems, you can enable this option to restore the old RX-reset behavior. If unsure, say N. +config 8139_RXBUF_IDX + int "Receive ring size (0 => 8K, 1 => 16K, 2 => 32K, 3 => 64K)" + depends on 8139TOO + range 0 3 + default 1 if EMBEDDED || SH_DREAMCAST + default 2 + help + The 8139too driver has a fixed area of memory for receiving data. + The default value is adequate for most systems. The 64KB + ring size has hardware issues that may cause problems. + Values: + 0 => 8 KB + 1 => 16 KB embedded systems + 2 => 32 KB default for most systems + 3 => 64 KB + If unsure, use the default 2. + + config SIS900 tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" depends on NET_PCI && PCI @@ -1957,9 +1993,11 @@ config SK98LIN - EG1032 v2 Instant Gigabit Network Adapter - EG1064 v2 Instant Gigabit Network Adapter - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte) - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill) - Marvell RDK-8001 Adapter @@ -2005,8 +2043,10 @@ config SK98LIN Questions concerning this driver may be addressed to: linux@syskonnect.de - To compile this driver as a module, choose M here: the module - will be called sk98lin. This is recommended. + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called sk98lin. This is recommended. config TIGON3 tristate "Broadcom Tigon3 support" @@ -2441,6 +2481,13 @@ config SHAPER To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. +config NETCONSOLE + tristate "Network console logging support (EXPERIMENTAL)" + depends on NETDEVICES && EXPERIMENTAL + ---help--- + If you want to log kernel messages over the network, enable this. + See Documentation/networking/netconsole.txt for details. + source "drivers/net/wan/Kconfig" source "drivers/net/pcmcia/Kconfig" --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/net/kgdb_eth.c 2003-12-30 22:49:27.000000000 -0800 @@ -0,0 +1,131 @@ +/* + * Network interface GDB stub + * + * Written by San Mehat (nettwerk@biodome.org) + * Based upon 'gdbserial' by David Grothe (dave@gcom.com) + * and Scott Foehner (sfoehner@engr.sgi.com) + * + * Twiddled for 2.6 by Robert Walsh + * and wangdi . + * + * Refactored for netpoll API by Matt Mackall + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define IN_BUF_SIZE 512 /* power of 2, please */ +#define OUT_BUF_SIZE 256 + +static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE]; +static int in_head, in_tail, out_count; +static atomic_t in_count; +int kgdboe = 0; /* Default to tty mode */ + +extern void set_debug_traps(void); +extern void breakpoint(void); +static void rx_hook(struct netpoll *np, int port, char *msg, int len); + +static struct netpoll np = { + .name = "kgdboe", + .dev_name = "eth0", + .rx_hook = rx_hook, + .local_port = 6443, + .remote_port = 6442, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; + +int eth_getDebugChar(void) +{ + int chr; + + while (atomic_read(&in_count) == 0) + netpoll_poll(&np); + + chr = in_buf[in_tail++]; + in_tail &= (IN_BUF_SIZE - 1); + atomic_dec(&in_count); + return chr; +} + +void eth_flushDebugChar(void) +{ + if(out_count && np.dev) { + netpoll_send_udp(&np, out_buf, out_count); + out_count = 0; + } +} + +void eth_putDebugChar(int chr) +{ + out_buf[out_count++] = chr; + if(out_count == OUT_BUF_SIZE) + eth_flushDebugChar(); +} + +static void rx_hook(struct netpoll *np, int port, char *msg, int len) +{ + int i; + + np->remote_port = port; + + /* Is this gdb trying to attach? */ + if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8)) + kgdb_schedule_breakpoint(); + + for (i = 0; i < len; i++) { + if (msg[i] == 3) + kgdb_schedule_breakpoint(); + + if (atomic_read(&in_count) >= IN_BUF_SIZE) { + /* buffer overflow, clear it */ + in_head = in_tail = 0; + atomic_set(&in_count, 0); + break; + } + in_buf[in_head++] = msg[i]; + in_head &= (IN_BUF_SIZE - 1); + atomic_inc(&in_count); + } +} + +static int option_setup(char *opt) +{ + return netpoll_parse_options(&np, opt); +} + +__setup("kgdboe=", option_setup); + +static int init_kgdboe(void) +{ +#ifdef CONFIG_SMP + if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) { + printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS); + return -1; + } +#endif + + set_debug_traps(); + + if(!np.remote_ip || netpoll_setup(&np)) + return 1; + + kgdboe = 1; + printk(KERN_INFO "kgdb: debugging over ethernet enabled\n"); + + return 0; +} + +module_init(init_kgdboe); --- linux-2.6.1-rc1/drivers/net/lance.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/lance.c 2003-12-30 22:49:20.000000000 -0800 @@ -59,8 +59,8 @@ static const char version[] = "lance.c:v #include static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0}; -int lance_probe(struct net_device *dev); static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); +static int __init do_lance_probe(struct net_device *dev); #ifdef LANCE_DEBUG static int lance_debug = LANCE_DEBUG; @@ -274,7 +274,6 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); -static int lance_open_fail(struct net_device *dev); static void lance_init_ring(struct net_device *dev, int mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); @@ -286,10 +285,21 @@ static void lance_tx_timeout (struct net +static void cleanup_card(struct net_device *dev) +{ + struct lance_private *lp = dev->priv; + if (dev->dma != 4) + free_dma(dev->dma); + release_region(dev->base_addr, LANCE_TOTAL_SIZE); + kfree(lp->tx_bounce_buffs); + kfree((void*)lp->rx_buffs); + kfree(lp); +} + #ifdef MODULE #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ -static struct net_device dev_lance[MAX_CARDS]; +static struct net_device *dev_lance[MAX_CARDS]; static int io[MAX_CARDS]; static int dma[MAX_CARDS]; static int irq[MAX_CARDS]; @@ -305,28 +315,35 @@ MODULE_PARM_DESC(lance_debug, "LANCE/PCn int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_lance[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->dma = dma[this_dev]; - dev->init = lance_probe; if (io[this_dev] == 0) { - if (this_dev != 0) break; /* only complain once */ + if (this_dev != 0) /* only complain once */ + break; printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n"); return -EPERM; } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; + dev = alloc_etherdev(0); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->dma = dma[this_dev]; + if (do_lance_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_lance[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + break; } - - return 0; + if (found != 0) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -334,13 +351,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_lance[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_lance[this_dev]; + if (dev) { unregister_netdev(dev); - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } @@ -352,7 +367,7 @@ MODULE_LICENSE("GPL"); board probes now that kmalloc() can allocate ISA DMA-able regions. This also allows the LANCE driver to be used as a module. */ -int __init lance_probe(struct net_device *dev) +static int __init do_lance_probe(struct net_device *dev) { int *port, result; @@ -387,6 +402,31 @@ int __init lance_probe(struct net_device return -ENODEV; } +struct net_device * __init lance_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(0); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_lance_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options) { struct lance_private *lp; @@ -398,6 +438,7 @@ static int __init lance_probe1(struct ne int hp_builtin = 0; /* HP on-board ethernet. */ static int did_version; /* Already printed version info. */ unsigned long flags; + int err = -ENOMEM; /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -432,7 +473,7 @@ static int __init lance_probe1(struct ne outw(88, ioaddr+LANCE_ADDR); if (inw(ioaddr+LANCE_ADDR) != 88) { lance_version = 0; - } else { /* Good, it's a newer chip. */ + } else { /* Good, it's a newer chip. */ int chip_version = inw(ioaddr+LANCE_DATA); outw(89, ioaddr+LANCE_ADDR); chip_version |= inw(ioaddr+LANCE_DATA) << 16; @@ -447,13 +488,9 @@ static int __init lance_probe1(struct ne } } - /* We can't use init_etherdev() to allocate dev->priv because it must + /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ - dev = init_etherdev(dev, 0); - if (!dev) - return -ENOMEM; SET_MODULE_OWNER(dev); - dev->open = lance_open_fail; chipname = chip_table[lance_version].name; printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); @@ -465,8 +502,7 @@ static int __init lance_probe1(struct ne dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ - lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, - GFP_DMA | GFP_KERNEL)+7) & ~7); + lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL); if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); @@ -486,7 +522,7 @@ static int __init lance_probe1(struct ne lp->tx_bounce_buffs = NULL; lp->chip_version = lance_version; - lp->devlock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&lp->devlock); lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */ for (i = 0; i < 6; i++) @@ -540,6 +576,7 @@ static int __init lance_probe1(struct ne dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0); } + err = -ENODEV; if (dev->irq >= 2) printk(" assigned IRQ %d", dev->irq); else if (lance_version != 0) { /* 7990 boards need DMA detection first. */ @@ -559,7 +596,7 @@ static int __init lance_probe1(struct ne printk(", probed IRQ %d", dev->irq); else { printk(", failed to detect IRQ line.\n"); - return -ENODEV; + goto out_tx; } /* Check for the initialization done bit, 0x0100, which means @@ -573,7 +610,7 @@ static int __init lance_probe1(struct ne } else if (dev->dma) { if (request_dma(dev->dma, chipname)) { printk("DMA %d allocation failed.\n", dev->dma); - return -ENODEV; + goto out_tx; } else printk(", assigned DMA %d.\n", dev->dma); } else { /* OK, we have to auto-DMA. */ @@ -613,7 +650,7 @@ static int __init lance_probe1(struct ne } if (i == 4) { /* Failure: bail. */ printk("DMA detection failed.\n"); - return -ENODEV; + goto out_tx; } } @@ -629,7 +666,7 @@ static int __init lance_probe1(struct ne dev->irq = probe_irq_off(irq_mask); if (dev->irq == 0) { printk(" Failed to detect the 7990 IRQ line.\n"); - return -ENODEV; + goto out_dma; } printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); } @@ -655,18 +692,18 @@ static int __init lance_probe1(struct ne dev->watchdog_timeo = TX_TIMEOUT; return 0; -out_rx: kfree((void*)lp->rx_buffs); -out_lp: kfree(lp); - return -ENOMEM; -} - -static int -lance_open_fail(struct net_device *dev) -{ - return -ENODEV; +out_dma: + if (dev->dma != 4) + free_dma(dev->dma); +out_tx: + kfree(lp->tx_bounce_buffs); +out_rx: + kfree((void*)lp->rx_buffs); +out_lp: + kfree(lp); + return err; } - static int lance_open(struct net_device *dev) --- linux-2.6.1-rc1/drivers/net/lasi_82596.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/lasi_82596.c 2003-12-30 22:49:20.000000000 -0800 @@ -1149,12 +1149,11 @@ static void print_eth(unsigned char *add #define LAN_PROM_ADDR 0xF0810000 -static int __devinit i82596_probe(struct net_device *dev) +static int __devinit i82596_probe(struct net_device *dev, + struct device *gen_dev) { int i; struct i596_private *lp; - /* we're going to overwrite dev->priv, so pull the device out */ - struct device *gen_dev = dev->priv; char eth_addr[6]; dma_addr_t dma_addr; @@ -1204,7 +1203,6 @@ static int __devinit i82596_probe(struct return -ENOMEM; } - ether_setup(dev); DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) @@ -1537,12 +1535,19 @@ lan_init_chip(struct parisc_device *dev) netdevice->base_addr = dev->hpa; netdevice->irq = dev->irq; - netdevice->init = i82596_probe; - netdevice->priv = &dev->dev; + + retval = i82596_probe(netdevice, &dev->dev); + if (retval) { + free_netdev(netdevice); + return -ENODEV; + } retval = register_netdev(netdevice); if (retval) { + struct i596_private *lp = netdevice->priv; printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); + dma_free_noncoherent(lp->dev, sizeof(struct i596_private), + (void *)netdevice->mem_start, lp->dma_addr); free_netdev(netdevice); return -ENODEV; }; --- linux-2.6.1-rc1/drivers/net/lne390.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/lne390.c 2003-12-30 22:49:20.000000000 -0800 @@ -49,7 +49,6 @@ static const char *version = #include "8390.h" -int lne390_probe(struct net_device *dev); static int lne390_probe1(struct net_device *dev, int ioaddr); static int lne390_open(struct net_device *dev); @@ -103,9 +102,11 @@ static unsigned int shmem_mapB[] __initd * PROM for a match against the value assigned to Mylex. */ -int __init lne390_probe(struct net_device *dev) +static int __init do_lne390_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; int ret; SET_MODULE_OWNER(dev); @@ -135,11 +136,46 @@ int __init lne390_probe(struct net_devic if (lne390_probe1(dev, ioaddr) == 0) return 0; release_region(ioaddr, LNE390_IO_EXTENT); + dev->irq = irq; + dev->mem_start = mem_start; } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, LNE390_IO_EXTENT); + if (ei_status.reg0) + iounmap((void *)dev->mem_start); +} + +struct net_device * __init lne390_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_lne390_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; @@ -174,11 +210,6 @@ static int __init lne390_probe1(struct n return -ENODEV; } #endif - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("lne390.c: unable to allocate memory for dev->priv!\n"); - return -ENOMEM; - } printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000); for(i = 0; i < ETHER_ADDR_LEN; i++) @@ -199,8 +230,6 @@ static int __init lne390_probe1(struct n if ((ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -274,8 +303,6 @@ static int __init lne390_probe1(struct n return 0; cleanup: free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -373,7 +400,7 @@ static int lne390_close(struct net_devic #ifdef MODULE #define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */ -static struct net_device dev_lne[MAX_LNE_CARDS]; +static struct net_device *dev_lne[MAX_LNE_CARDS]; static int io[MAX_LNE_CARDS]; static int irq[MAX_LNE_CARDS]; static int mem[MAX_LNE_CARDS]; @@ -389,26 +416,32 @@ MODULE_LICENSE("GPL"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { - struct net_device *dev = &dev_lne[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; - dev->init = lne390_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + if (do_lne390_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_lne[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; - } - return 0; + free_netdev(dev); + printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); + break; + } + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -416,15 +449,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { - struct net_device *dev = &dev_lne[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(dev->base_addr, LNE390_IO_EXTENT); - if (ei_status.reg0) - iounmap((void *)dev->mem_start); + struct net_device *dev = dev_lne[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/lp486e.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/lp486e.c 2003-12-30 22:49:20.000000000 -0800 @@ -1314,18 +1314,23 @@ static int io = IOADDR; static int irq = IRQ; static int __init lp486e_init_module(void) { - struct net_device *dev; - - dev = alloc_etherdev(sizeof(struct i596_private)); + int err; + struct net_device *dev = alloc_etherdev(sizeof(struct i596_private)); if (!dev) return -ENOMEM; dev->irq = irq; dev->base_addr = io; - dev->init = lp486e_probe; - if (register_netdev(dev) != 0) { + err = lp486e_probe(dev); + if (err) { + free_netdev(dev); + return err; + } + err = register_netdev(dev); + if (err) { + release_region(dev->base_addr, LP486E_TOTAL_SIZE); free_netdev(dev); - return -EIO; + return err; } dev_lp486e = dev; full_duplex = 0; --- linux-2.6.1-rc1/drivers/net/mac8390.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/mac8390.c 2003-12-30 22:49:20.000000000 -0800 @@ -124,11 +124,10 @@ static int useresources[] = { static char version[] __initdata = "mac8390.c: v0.4 2001-05-15 David Huggins-Daines and others\n"; -extern int mac8390_probe(struct net_device * dev); extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); extern int mac8390_memsize(unsigned long membase); extern int mac8390_memtest(struct net_device * dev); -extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, +static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type); static int mac8390_open(struct net_device * dev); @@ -223,43 +222,43 @@ int __init mac8390_memsize(unsigned long return i * 0x1000; } -static int probed __initdata = 0; - -int __init mac8390_probe(struct net_device * dev) +struct net_device * __init mac8390_probe(int unit) { + struct net_device *dev; volatile unsigned short *i; - int boards_found = 0; int version_disp = 0; struct nubus_dev * ndev = NULL; + int err = -ENODEV; struct nubus_dir dir; struct nubus_dirent ent; int offset; + static unsigned int slots; enum mac8390_type cardtype; - if (probed) - return -ENODEV; - probed++; - /* probably should check for Nubus instead */ if (!MACH_IS_MAC) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_ei_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { - - dev = NULL; - - if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + /* Have we seen it already? */ + if (slots & (1<board->slot)) continue; + slots |= 1<board->slot; - dev = init_etherdev(dev, 0); - if (dev == NULL) { - printk(KERN_ERR "Unable to allocate etherdev" - "structure!\n"); - return -ENOMEM; - } + if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + continue; if (version_disp == 0) { version_disp = 1; @@ -358,21 +357,25 @@ int __init mac8390_probe(struct net_devi printk(KERN_ERR "Card type %s is" " unsupported, sorry\n", cardname[cardtype]); - return -ENODEV; + continue; } } /* Do the nasty 8390 stuff */ - if (mac8390_initdev(dev, ndev, cardtype)) - continue; - boards_found++; + if (!mac8390_initdev(dev, ndev, cardtype)) + break; } - /* We're outta here */ - if (boards_found > 0) - return 0; - else - return -ENODEV; + if (!ndev) + goto out; + err = register_netdev(dev); + if (err) + goto out; + return dev; + +out: + free_netdev(dev); + return ERR_PTR(err); } #ifdef MODULE @@ -380,26 +383,39 @@ MODULE_AUTHOR("David Huggins-Daines priv */ - if (ethdev_init(dev)) { - printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name); - return -ENOMEM; - } - /* Now fill in our stuff */ dev->open = &mac8390_open; dev->stop = &mac8390_close; @@ -529,7 +539,6 @@ static int mac8390_open(struct net_devic printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - MOD_INC_USE_COUNT; return 0; } @@ -537,7 +546,6 @@ static int mac8390_close(struct net_devi { free_irq(dev->irq, dev); ei_close(dev); - MOD_DEC_USE_COUNT; return 0; } --- linux-2.6.1-rc1/drivers/net/mac89x0.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/drivers/net/mac89x0.c 2003-12-30 22:49:20.000000000 -0800 @@ -123,7 +123,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int mac89x0_probe(struct net_device *dev); #if 0 extern void reset_chip(struct net_device *dev); #endif @@ -170,8 +169,9 @@ writereg(struct net_device *dev, int por /* Probe for the CS8900 card in slot E. We won't bother looking anywhere else until we have a really good reason to do so. */ -int __init mac89x0_probe(struct net_device *dev) +struct net_device * __init mac89x0_probe(int unit) { + struct net_device *dev; static int once_is_enough; struct net_local *lp; static unsigned version_printed; @@ -179,18 +179,28 @@ int __init mac89x0_probe(struct net_devi unsigned rev_type = 0; unsigned long ioaddr; unsigned short sig; + int err = -ENODEV; + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); if (once_is_enough) - return -ENODEV; + goto out; once_is_enough = 1; /* We might have to parameterize this later */ slot = 0xE; /* Get out now if there's a real NuBus card in slot E */ if (nubus_find_slot(slot, NULL) != NULL) - return -ENODEV; + goto out; /* The pseudo-ISA bits always live at offset 0x300 (gee, wonder why...) */ @@ -206,21 +216,15 @@ int __init mac89x0_probe(struct net_devi local_irq_restore(flags); if (!card_present) - return -ENODEV; + goto out; } nubus_writew(0, ioaddr + ADD_PORT); sig = nubus_readw(ioaddr + DATA_PORT); if (sig != swab16(CHIP_EISA_ID_SIG)) - return -ENODEV; + goto out; /* Initialize the net_device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - } lp = (struct net_local *)dev->priv; /* Fill in the 'dev' fields. */ @@ -258,9 +262,7 @@ int __init mac89x0_probe(struct net_devi /* Try to read the MAC address */ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { printk("\nmac89x0: No EEPROM, giving up now.\n"); - kfree(dev->priv); - dev->priv = NULL; - return -ENODEV; + goto out1; } else { for (i = 0; i < ETH_ALEN; i += 2) { /* Big-endian (why??!) */ @@ -277,6 +279,7 @@ int __init mac89x0_probe(struct net_devi for (i = 0; i < ETH_ALEN; i++) printk("%2.2x%s", dev->dev_addr[i], ((i < ETH_ALEN-1) ? ":" : "")); + printk("\n"); dev->open = net_open; dev->stop = net_close; @@ -285,11 +288,15 @@ int __init mac89x0_probe(struct net_devi dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &set_mac_address; - /* Fill in the fields of the net_device structure with ethernet values. */ - ether_setup(dev); - - printk("\n"); + err = register_netdev(dev); + if (err) + goto out1; return 0; +out1: + nubus_writew(0, dev->base_addr + ADD_PORT); +out: + free_netdev(dev); + return ERR_PTR(err); } #if 0 @@ -619,7 +626,7 @@ static int set_mac_address(struct net_de #ifdef MODULE -static struct net_device dev_cs89x0; +static struct net_device *dev_cs89x0; static int debug; MODULE_PARM(debug, "i"); @@ -630,36 +637,20 @@ int init_module(void) { net_debug = debug; - dev_cs89x0.init = mac89x0_probe; - dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev_cs89x0.priv) - return -ENOMEM; - memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - - if (register_netdev(&dev_cs89x0) != 0) { + dev_cs89x0 = mac89x0_probe(-1); + if (IS_ERR(dev_cs89x0)) { printk(KERN_WARNING "mac89x0.c: No card found\n"); - kfree(dev_cs89x0.priv); - return -ENXIO; - } + return PTR_ERR(dev_cs89x0); + } return 0; } void cleanup_module(void) { - -#endif -#ifdef MODULE - nubus_writew(0, dev_cs89x0.base_addr + ADD_PORT); -#endif -#ifdef MODULE - - if (dev_cs89x0.priv != NULL) { - /* Free up the private structure, or leak memory :-) */ - unregister_netdev(&dev_cs89x0); - kfree(dev_cs89x0.priv); - dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ - } + unregister_netdev(dev_cs89x0); + nubus_writew(0, dev_cs89x0->base_addr + ADD_PORT); + free_netdev(dev_cs89x0); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/mace.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/mace.c 2003-12-30 22:49:20.000000000 -0800 @@ -142,6 +142,10 @@ static void __init mace_probe1(struct de } } + /* + * lazy allocation - it's a driver-wide thing and it will live until + * the unload, but we don't allocate it until it's needed + */ if (dummy_buf == NULL) { dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); if (dummy_buf == NULL) { @@ -150,7 +154,7 @@ static void __init mace_probe1(struct de } } - dev = init_etherdev(0, PRIV_BYTES); + dev = alloc_etherdev(PRIV_BYTES); if (!dev) return; SET_MODULE_OWNER(dev); @@ -160,16 +164,16 @@ static void __init mace_probe1(struct de if (!request_OF_resource(mace, 0, " (mace)")) { printk(KERN_ERR "MACE: can't request IO resource !\n"); - goto err_out; + goto out1; } if (!request_OF_resource(mace, 1, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't request TX DMA resource !\n"); - goto err_out; + goto out2; } if (!request_OF_resource(mace, 2, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't request RX DMA resource !\n"); - goto err_out; + goto out3; } dev->base_addr = mace->addrs[0].address; @@ -229,30 +233,42 @@ static void __init mace_probe1(struct de dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - ether_setup(dev); - mace_reset(dev); - if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) + if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); + goto out4; + } if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", - dev)) + dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); + goto out5; + } if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", - dev)) + dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); + goto out6; + } + if (register_netdev(dev) != 0) + goto out7; mp->next_mace = mace_devs; mace_devs = dev; return; -err_out: - unregister_netdev(dev); - if (mp->of_node) { - release_OF_resource(mp->of_node, 0); - release_OF_resource(mp->of_node, 1); - release_OF_resource(mp->of_node, 2); - } +out7: + free_irq(mp->rx_dma_intr, dev); +out6: + free_irq(mp->tx_dma_intr, dev); +out5: + free_irq(dev->irq, dev); +out4: + release_OF_resource(mp->of_node, 2); +out3: + release_OF_resource(mp->of_node, 1); +out2: + release_OF_resource(mp->of_node, 0); +out1: free_netdev(dev); } @@ -975,7 +991,7 @@ static void __exit mace_cleanup (void) release_OF_resource(mp->of_node, 1); release_OF_resource(mp->of_node, 2); - kfree(dev); + free_netdev(dev); } if (dummy_buf != NULL) { kfree(dummy_buf); --- linux-2.6.1-rc1/drivers/net/macmace.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/drivers/net/macmace.c 2003-12-30 22:49:20.000000000 -0800 @@ -180,7 +180,7 @@ static void mace_dma_off(struct net_devi * model of Macintrash has a MACE (AV macintoshes) */ -int mace_probe(struct net_device *unused) +struct net_device *mace_probe(int unit) { int j; struct mace_data *mp; @@ -188,13 +188,19 @@ int mace_probe(struct net_device *unused struct net_device *dev; unsigned char checksum = 0; static int found = 0; + int err; - if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + if (found || macintosh_config->ether_type != MAC_ETHER_MACE) + return ERR_PTR(-ENODEV); found = 1; /* prevent 'finding' one on every device probe */ - dev = init_etherdev(0, PRIV_BYTES); - if (!dev) return -ENOMEM; + dev = alloc_etherdev(PRIV_BYTES); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); mp = (struct mace_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; @@ -221,7 +227,10 @@ int mace_probe(struct net_device *unused checksum ^= bitrev(addr[j<<4]); } - if (checksum != 0xFF) return -ENODEV; + if (checksum != 0xFF) { + free_netdev(dev); + return ERR_PTR(-ENODEV); + } memset(&mp->stats, 0, sizeof(mp->stats)); @@ -234,13 +243,16 @@ int mace_probe(struct net_device *unused dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - ether_setup(dev); - printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); printk("\n"); - return 0; + err = register_netdev(dev); + if (!err) + return dev; + + free_netdev(dev); + return ERR_PTR(err); } /* --- linux-2.6.1-rc1/drivers/net/macsonic.c 2003-07-27 12:14:39.000000000 -0700 +++ 25/drivers/net/macsonic.c 2003-12-30 22:49:20.000000000 -0800 @@ -74,7 +74,6 @@ static int sonic_version_printed; static int reg_offset; -extern int macsonic_probe(struct net_device* dev); extern int mac_onboard_sonic_probe(struct net_device* dev); extern int mac_nubus_sonic_probe(struct net_device* dev); @@ -110,14 +109,38 @@ enum macsonic_type { #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr) -int __init macsonic_probe(struct net_device* dev) +struct net_device * __init macsonic_probe(int unit) { - int rv; + struct net_device *dev = alloc_etherdev(0); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ - if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV) - return rv; - return mac_nubus_sonic_probe(dev); + err = mac_onboard_sonic_probe(dev); + if (err == 0) + goto found; + if (err != -ENODEV) + goto out; + err = mac_nubus_sonic_probe(dev); + if (err) + goto out; +found: + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + kfree(dev->priv); +out: + free_netdev(dev); + return ERR_PTR(err); } /* @@ -195,6 +218,7 @@ int __init macsonic_init(struct net_devi if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); + dev->priv = NULL; kfree(lp); return -ENOMEM; } @@ -229,8 +253,6 @@ int __init macsonic_init(struct net_devi sonic_write(dev, SONIC_FAET, 0xffff); sonic_write(dev, SONIC_MPT, 0xffff); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); return 0; } @@ -344,30 +366,6 @@ int __init mac_onboard_sonic_probe(struc printk("yes\n"); - if (dev) { - dev = init_etherdev(dev, sizeof(struct sonic_local)); - if (!dev) - return -ENOMEM; - /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - } - } else { - dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } - - if (dev == NULL) - return -ENOMEM; - - if(dev->priv) { - printk("%s: warning! sonic entering with priv already allocated!\n", - dev->name); - printk("%s: discarding, will attempt to reallocate\n", dev->name); - dev->priv = NULL; - } - /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ @@ -497,7 +495,6 @@ int __init mac_nubus_sonic_probe(struct { static int slots; struct nubus_dev* ndev = NULL; - struct sonic_local* lp; unsigned long base_addr, prom_addr; u16 sonic_dcr; int id; @@ -567,25 +564,6 @@ int __init mac_nubus_sonic_probe(struct return -ENODEV; } - if (dev) { - dev = init_etherdev(dev, sizeof(struct sonic_local)); - if (!dev) - return -ENOMEM; - /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) /* FIXME: kfree dev if necessary */ - return -ENOMEM; - } - } else { - dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } - - if (dev == NULL) - return -ENOMEM; - - lp = (struct sonic_local*) dev->priv; - memset(lp, 0, sizeof(struct sonic_local)); /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ dev->base_addr = base_addr; @@ -631,8 +609,7 @@ int __init mac_nubus_sonic_probe(struct } #ifdef MODULE -static char namespace[16] = ""; -static struct net_device dev_macsonic; +static struct net_device *dev_macsonic; MODULE_PARM(sonic_debug, "i"); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); @@ -641,24 +618,20 @@ MODULE_LICENSE("GPL"); int init_module(void) { - dev_macsonic.name = namespace; - dev_macsonic.init = macsonic_probe; - - if (register_netdev(&dev_macsonic) != 0) { + dev_macsonic = macsonic_probe(-1); + if (IS_ERR(dev_macsonic)) { printk(KERN_WARNING "macsonic.c: No card found\n"); - return -ENXIO; - } + return PTR_ERR(dev_macsonic); + } return 0; } void cleanup_module(void) { - if (dev_macsonic.priv != NULL) { - unregister_netdev(&dev_macsonic); - kfree(dev_macsonic.priv); - dev_macsonic.priv = NULL; - } + unregister_netdev(dev_macsonic); + kfree(dev_macsonic->priv); + free_netdev(dev_macsonic); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/Makefile 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/Makefile 2003-12-30 22:49:27.000000000 -0800 @@ -8,7 +8,6 @@ ifeq ($(CONFIG_ISDN_PPP),y) obj-$(CONFIG_ISDN) += slhc.o endif -obj-$(CONFIG_E100) += e100/ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_BONDING) += bonding/ @@ -39,6 +38,7 @@ obj-$(CONFIG_TYPHOON) += typhoon.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_EEPRO100) += eepro100.o +obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS190) += sis190.o @@ -95,6 +95,7 @@ obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o +obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o @@ -111,7 +112,6 @@ endif obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_DE600) += de600.o obj-$(CONFIG_DE620) += de620.o -obj-$(CONFIG_AT1500) += lance.o obj-$(CONFIG_LANCE) += lance.o obj-$(CONFIG_SUN3_82586) += sun3_82586.o obj-$(CONFIG_SUN3LANCE) += sun3lance.o @@ -188,3 +188,6 @@ obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ +# Must come after all NICs that might use them +obj-$(CONFIG_NETCONSOLE) += netconsole.o +obj-$(CONFIG_KGDB) += kgdb_eth.o --- linux-2.6.1-rc1/drivers/net/meth.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/meth.c 2003-12-30 22:49:20.000000000 -0800 @@ -95,7 +95,6 @@ typedef struct meth_private { spinlock_t meth_lock; } meth_private; -extern struct net_device meth_devs[]; void meth_tx_timeout (struct net_device *dev); void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); @@ -762,17 +761,16 @@ struct net_device_stats *meth_stats(stru /* * The init function (sometimes called probe). - * It is invoked by register_netdev() */ -int meth_init(struct net_device *dev) +static struct net_device *meth_init(struct net_device *dev) { + struct net_device *dev; meth_private *priv; int ret; - /* - * Then, assign other fields in dev, using ether_setup() and some - * hand assignments - */ - ether_setup(dev); /* assign some of the fields */ + + dev = alloc_etherdev(sizeof(struct meth_private)); + if (!dev) + return ERR_PTR(-ENOMEM); dev->open = meth_open; dev->stop = meth_release; @@ -787,16 +785,8 @@ int meth_init(struct net_device *dev) dev->irq = MACE_ETHERNET_IRQ; SET_MODULE_OWNER(dev); - /* - * Then, allocate the priv field. This encloses the statistics - * and a few private fields. - */ - priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - dev->priv=priv; - memset(priv, 0, sizeof(struct meth_private)); - spin_lock_init(&((struct meth_private *) dev->priv)->meth_lock); + priv = dev->priv; + spin_lock_init(&priv->meth_lock); /* * Make the usual checks: check_region(), probe irq, ... -ENODEV * should be returned if no device found. No resource should be @@ -807,28 +797,41 @@ int meth_init(struct net_device *dev) priv->phy_addr = -1; /* No phy is known yet... */ /* Initialize the hardware */ - if((ret=meth_reset(dev)) < 0) - return ret; + ret = meth_reset(dev); + if (ret < 0) + goto out; /* Allocate the ring buffers */ - if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){ - meth_free_tx_ring(priv); - meth_free_rx_ring(priv); - return ret; - } + ret = meth_init_tx_ring(priv); + if (ret < 0) + goto out; + + ret = meth_init_rx_ring(priv); + if (ret < 0) + goto out1; + + ret = register_netdev(dev); + if (ret) + goto out2; printk("SGI O2 Fast Ethernet rev. %ld\n", priv->regs->mac_ctrl >> 29); - return 0; + return ret; + +out2: + meth_free_rx_ring(priv); +out1: + meth_free_tx_ring(priv); +out: + free_netdev(dev); + return ERR_PTR(ret); } /* * The devices */ -struct net_device meth_devs[1] = { - { init: meth_init, } /* init, nothing more */ -}; +struct net_device *meth_dev; /* * Finally, the module stuff @@ -836,23 +839,19 @@ struct net_device meth_devs[1] = { int meth_init_module(void) { - int result, device_present = 0; - - strcpy(meth_devs[0].name, "eth%d"); - - if ( (result = register_netdev(meth_devs)) ) - printk("meth: error %i registering device \"%s\"\n", - result, meth_devs->name); - else device_present++; - - return device_present ? 0 : -ENODEV; + meth_dev = meth_init(); + if (IS_ERR(meth_dev)) + return PTR_ERR(meth_dev); + return 0; } void meth_cleanup(void) { - kfree(meth_devs->priv); - unregister_netdev(meth_devs); - return; + meth_private *priv = meth_dev->priv; + unregister_netdev(meth_dev); + meth_free_rx_ring(priv); + meth_free_tx_ring(priv); + free_netdev(meth_dev); } module_init(meth_init_module); --- linux-2.6.1-rc1/drivers/net/mvme147.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/mvme147.c 2003-12-30 22:49:20.000000000 -0800 @@ -41,7 +41,7 @@ struct m147lance_private { struct lance_private lance; void *base; - void *ram; + unsigned long ram; }; /* function prototypes... This is easy because all the grot is in the @@ -49,7 +49,6 @@ struct m147lance_private { * plus board-specific init, open and close actions. * Oh, and we need to tell the generic code how to read and write LANCE registers... */ -int mvme147lance_probe(struct net_device *dev); static int m147lance_open(struct net_device *dev); static int m147lance_close(struct net_device *dev); static void m147lance_writerap(struct m147lance_private *lp, unsigned short value); @@ -60,29 +59,29 @@ typedef void (*writerap_t)(void *, unsig typedef void (*writerdp_t)(void *, unsigned short); typedef unsigned short (*readrdp_t)(void *); -#ifdef MODULE -static struct m147lance_private *root_m147lance_dev; -#endif - /* Initialise the one and only on-board 7990 */ -int __init mvme147lance_probe(struct net_device *dev) +struct net_device * __init mvme147lance_probe(int unit) { + struct net_device *dev; static int called; static const char name[] = "MVME147 LANCE"; struct m147lance_private *lp; u_long *addr; u_long address; + int err; if (!MACH_IS_MVME147 || called) - return -ENODEV; + return ERR_PTR(-ENODEV); called++; - SET_MODULE_OWNER(dev); + dev = alloc_etherdev(sizeof(struct m147lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); - dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct m147lance_private)); + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; @@ -114,11 +113,12 @@ int __init mvme147lance_probe(struct net dev->dev_addr[5]); lp = (struct m147lance_private *)dev->priv; - lp->ram = (void *)__get_dma_pages(GFP_ATOMIC, 3); /* 16K */ + lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ if (!lp->ram) { printk("%s: No memory for LANCE buffers\n", dev->name); - return -ENODEV; + free_netdev(dev); + return ERR_PTR(-ENOMEM); } lp->lance.name = (char*)name; /* discards const, shut up gcc */ @@ -134,15 +134,15 @@ int __init mvme147lance_probe(struct net lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK; lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; - ether_setup(dev); -#ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_m147lance_dev; - root_m147lance_dev = lp; -#endif /* MODULE */ + err = register_netdev(dev); + if (err) { + free_pages(lp->ram, 3); + free_netdev(dev); + return ERR_PTR(err); + } - return 0; + return dev; } static void m147lance_writerap(struct m147lance_private *lp, unsigned short value) @@ -185,23 +185,21 @@ static int m147lance_close(struct net_de #ifdef MODULE MODULE_LICENSE("GPL"); +static struct net_device *dev_mvme147_lance; int init_module(void) { - root_lance_dev = NULL; - return mvme147lance_probe(NULL); + dev_mvme147_lance = mvme147lance_probe(-1); + if (IS_ERR(dev_mvme147_lance)) + return PTR_ERR(dev_mvme147_lance); + return 0; } void cleanup_module(void) { - /* Walk the chain of devices, unregistering them */ - struct m147lance_private *lp; - while (root_m147lance_dev) { - lp = root_m147lance_dev->next_module; - unregister_netdev(root_lance_dev->dev); - free_pages(lp->ram, 3); - free_netdev(root_lance_dev->dev); - root_lance_dev = lp; - } + struct m147lance_private *lp = dev_mvme147_lance->priv; + unregister_netdev(dev_mvme147_lance); + free_pages(lp->ram, 3); + free_netdev(dev_mvme147_lance); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/natsemi.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/natsemi.c 2003-12-30 22:49:20.000000000 -0800 @@ -765,19 +765,13 @@ static int __devinit natsemi_probe1 (str SET_NETDEV_DEV(dev, &pdev->dev); i = pci_request_regions(pdev, dev->name); - if (i) { - free_netdev(dev); - return i; - } + if (i) + goto err_pci_request_regions; - { - void *mmio = ioremap (ioaddr, iosize); - if (!mmio) { - pci_release_regions(pdev); - free_netdev(dev); - return -ENOMEM; - } - ioaddr = (unsigned long) mmio; + ioaddr = (unsigned long) ioremap (ioaddr, iosize); + if (!ioaddr) { + i = -ENOMEM; + goto err_ioremap; } /* Work around the dropped serial bit. */ @@ -835,13 +829,9 @@ static int __devinit natsemi_probe1 (str dev->mtu = mtu; i = register_netdev(dev); - if (i) { - pci_release_regions(pdev); - unregister_netdev(dev); - free_netdev(dev); - pci_set_drvdata(pdev, NULL); - return i; - } + if (i) + goto err_register_netdev; + netif_carrier_off(dev); if (netif_msg_drv(np)) { @@ -878,6 +868,17 @@ static int __devinit natsemi_probe1 (str return 0; + + err_register_netdev: + iounmap ((void *) dev->base_addr); + + err_ioremap: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + + err_pci_request_regions: + free_netdev(dev); + return i; } --- linux-2.6.1-rc1/drivers/net/ne2.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/ne2.c 2003-12-30 22:49:20.000000000 -0800 @@ -242,7 +242,7 @@ static unsigned int __init dlink_get_eep * Note that at boot, this probe only picks up one card at a time. */ -int __init ne2_probe(struct net_device *dev) +static int __init do_ne2_probe(struct net_device *dev) { static int current_mca_slot = -1; int i; @@ -262,16 +262,52 @@ int __init ne2_probe(struct net_device * mca_find_unused_adapter(ne2_adapters[i].id, 0); if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { + int res; mca_set_adapter_name(current_mca_slot, ne2_adapters[i].name); mca_mark_as_used(current_mca_slot); - return ne2_probe1(dev, current_mca_slot); + res = ne2_probe1(dev, current_mca_slot); + if (res) + mca_mark_as_unused(current_mca_slot); + return res; } } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + mca_mark_as_unused(ei_status.priv); + mca_set_adapter_procfn( ei_status.priv, NULL, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne2_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne2_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { @@ -443,14 +479,6 @@ static int __init ne2_probe1(struct net_ dev->base_addr = base_addr; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto out; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; @@ -735,7 +763,7 @@ retry: #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -754,23 +782,30 @@ MODULE_PARM_DESC(bad, "(ignored)"); int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; - dev->init = ne2_probe; - if (register_netdev(dev) != 0) { - if (found != 0) return 0; /* Got at least one. */ - - printk(KERN_WARNING "ne2.c: No NE/2 card found.\n"); - return -ENXIO; + if (do_ne2_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + printk(KERN_WARNING "ne2.c: No NE/2 card found\n"); + return -ENXIO; } void cleanup_module(void) @@ -778,14 +813,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - mca_mark_as_unused(ei_status.priv); - mca_set_adapter_procfn( ei_status.priv, NULL, NULL); - kfree(dev->priv); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/ne2k_cbus.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ne2k_cbus.c 2003-12-30 22:49:20.000000000 -0800 @@ -78,7 +78,6 @@ bad_clone_list[] __initdata = { #include "ne2k_cbus.h" -int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_open(struct net_device *dev); static int ne_close(struct net_device *dev); @@ -113,9 +112,10 @@ static void ne_block_output(struct net_d E2010 starts at 0x100 and ends at 0x4000. E2010-x starts at 0x100 and ends at 0xffff. */ -int __init ne_probe(struct net_device *dev) +static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -135,7 +135,7 @@ int __init ne_probe(struct net_device *d if (ei_debug > 2) printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr); - result = ne_probe_cbus(dev, hw, base_addr); + result = ne_probe_cbus(dev, hw, base_addr, irq); if (result != 0) ne2k_cbus_destroy(dev); @@ -156,13 +156,13 @@ int __init ne_probe(struct net_device *d if (hw && hw->hwtype) { const unsigned short *plist; for (plist = hw->portlist; *plist; plist++) - if (ne_probe_cbus(dev, hw, *plist) == 0) + if (ne_probe_cbus(dev, hw, *plist, irq) == 0) return 0; } else { for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { const unsigned short *plist; for (plist = hw->portlist; *plist; plist++) - if (ne_probe_cbus(dev, hw, *plist) == 0) + if (ne_probe_cbus(dev, hw, *plist, irq) == 0) return 0; } } @@ -174,7 +174,45 @@ int __init ne_probe(struct net_device *d return -ENODEV; } -static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr) +static void cleanup_card(struct net_device *dev) +{ + const struct ne2k_cbus_region *rlist; + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + + free_irq(dev->irq, dev); + for (rlist = hw->regionlist; rlist->range; rlist++) { + release_region(dev->base_addr + rlist->start, + rlist->range); + } + ne2k_cbus_destroy(dev); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + +static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq) { if (ei_debug > 2) printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n", @@ -182,6 +220,7 @@ static int __init ne_probe_cbus(struct n if (hw && hw->hwtype) { ne2k_cbus_set_hwtype(dev, hw, ioaddr); + dev->irq = irq; return ne_probe1(dev, ioaddr); } else { /* auto detect */ @@ -189,6 +228,7 @@ static int __init ne_probe_cbus(struct n printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n"); for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { ne2k_cbus_set_hwtype(dev, hw, ioaddr); + dev->irq = irq; if (ne_probe1(dev, ioaddr) == 0) return 0; } @@ -301,11 +341,12 @@ static int __init ne_probe1(struct net_d if (ei_debug > 2) printk(" [CNET98EL-specific initialize..."); outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); /* 0x20|0x1 */ + ret = -ENODEV; i = inb(ioaddr); if ((i & ~0x2) != (0x20 | 0x01)) - return -ENODEV; + goto err_out; if ((inb(ioaddr + 0x7) & 0x80) != 0x80) - return -ENODEV; + goto err_out; outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* out(ioaddr+0xc, 0x20) */ /* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */ outb_p(ENDCFG_WTS | 0x48, ioaddr + EN0_DCFG); /* 0x49 */ @@ -330,7 +371,7 @@ static int __init ne_probe1(struct net_d if (ei_debug > 2) printk("] "); printk("memory failure at %x\n", i); - return -ENODEV; + goto err_out; } if (ei_debug > 2) printk(" good..."); @@ -338,7 +379,7 @@ static int __init ne_probe1(struct net_d if (ei_debug > 2) printk("] "); printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n"); - return -ENODEV; + goto err_out; } outb((dev->irq > 5) ? (dev->irq & 4):(dev->irq >> 1), ioaddr + (0x2 | 0x400)); outb(0x7e, ioaddr + (0x4 | 0x400)); @@ -457,14 +498,6 @@ static int __init ne_probe1(struct net_d goto err_out; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk (" unable to get memory for dev->priv.\n"); - ret = -ENOMEM; - goto err_out; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); @@ -779,7 +812,7 @@ retry: #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -806,26 +839,32 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = hwtype[this_dev]; - dev->init = ne_probe; - if (register_netdev(dev) == 0) { - found++; - continue; - } - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } + free_netdev(dev); + if (found) + break; if (io[this_dev] != 0) printk(KERN_WARNING "ne2k_cbus: No NE*000 card found at i/o = %#x\n", io[this_dev]); else - printk(KERN_NOTICE "ne2k_cbus: You must supply \"io=0xNNN\" value(s) for C-Bus cards.\n"); + printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - return 0; + if (found) + return 0; + return -ENODEV; } void cleanup_module(void) @@ -833,18 +872,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - const struct ne2k_cbus_region *rlist; - const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); - - free_irq(dev->irq, dev); - for (rlist = hw->regionlist; rlist->range; rlist++) { - release_region(dev->base_addr + rlist->start, - rlist->range); - } + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); - ne2k_cbus_destroy(dev); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/ne2k_cbus.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/drivers/net/ne2k_cbus.h 2003-12-30 22:49:20.000000000 -0800 @@ -477,5 +477,5 @@ static void __init ne2k_cbus_writemem(st } #endif -static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr); +static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq); /* End of ne2k_cbus.h */ --- linux-2.6.1-rc1/drivers/net/ne2k-pci.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ne2k-pci.c 2003-12-30 22:49:20.000000000 -0800 @@ -115,6 +115,7 @@ enum ne2k_pci_chipsets { CH_Winbond_W89C940F, CH_Holtek_HT80232, CH_Holtek_HT80229, + CH_Winbond_89C940_8c4a, }; @@ -132,6 +133,7 @@ static struct { {"Winbond W89C940F", 0}, {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, + {"Winbond W89C940(misprogrammed)", 0}, {0,} }; @@ -147,6 +149,7 @@ static struct pci_device_id ne2k_pci_tbl { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F }, { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 }, { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 }, + { 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a }, { 0, } }; MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl); --- linux-2.6.1-rc1/drivers/net/ne3210.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/ne3210.c 2003-12-30 22:49:20.000000000 -0800 @@ -111,12 +111,6 @@ static int __init ne3210_eisa_probe (str device->driver_data = dev; ioaddr = edev->base_addr; - if (ethdev_init (dev)) { - printk ("ne3210.c: unable to allocate memory for dev->priv!\n"); - retval = -ENOMEM; - goto out; - } - if (!request_region(ioaddr, NE3210_IO_EXTENT, dev->name)) { retval = -EBUSY; goto out; @@ -357,24 +351,6 @@ static struct eisa_driver ne3210_eisa_dr }, }; -#ifdef MODULE -#if 0 -#define MAX_NE3210_CARDS 4 /* Max number of NE3210 cards per module */ -static struct net_device dev_ne3210[MAX_NE3210_CARDS]; -static int io[MAX_NE3210_CARDS]; -static int irq[MAX_NE3210_CARDS]; -static int mem[MAX_NE3210_CARDS]; - -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s)"); -MODULE_PARM_DESC(mem, "memory base address(es)"); -#endif -#endif /* MODULE */ - - MODULE_DESCRIPTION("NE3210 EISA Ethernet driver"); MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/ne.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ne.c 2003-12-30 22:49:20.000000000 -0800 @@ -126,7 +126,6 @@ bad_clone_list[] __initdata = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_probe_isapnp(struct net_device *dev); @@ -163,9 +162,10 @@ static void ne_block_output(struct net_d E2010 starts at 0x100 and ends at 0x4000. E2010-x starts at 0x100 and ends at 0xffff. */ -int __init ne_probe(struct net_device *dev) +static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -183,6 +183,7 @@ int __init ne_probe(struct net_device *d /* Last resort. The semi-risky ISA auto-probe. */ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { int ioaddr = netcard_portlist[base_addr]; + dev->irq = irq; if (ne_probe1(dev, ioaddr) == 0) return 0; } @@ -191,6 +192,40 @@ int __init ne_probe(struct net_device *d return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ne_probe_isapnp(struct net_device *dev) { int i; @@ -425,20 +460,12 @@ static int __init ne_probe1(struct net_d goto err_out; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk (" unable to get memory for dev->priv.\n"); - ret = -ENOMEM; - goto err_out; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); if (ret) { printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); - goto err_out_kfree; + goto err_out; } dev->base_addr = ioaddr; @@ -472,9 +499,6 @@ static int __init ne_probe1(struct net_d NS8390_init(dev, 0); return 0; -err_out_kfree: - kfree(dev->priv); - dev->priv = NULL; err_out: release_region(ioaddr, NE_IO_EXTENT); return ret; @@ -734,7 +758,7 @@ retry: #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -758,25 +782,31 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; - dev->init = ne_probe; - if (register_netdev(dev) == 0) { - found++; - continue; - } - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } + free_netdev(dev); + if (found) + break; if (io[this_dev] != 0) printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); else printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - return 0; + if (found) + return 0; + return -ENODEV; } void cleanup_module(void) @@ -784,16 +814,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/net/netconsole.c 2003-12-30 22:49:20.000000000 -0800 @@ -0,0 +1,120 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * This file contains the implementation of an IRQ-safe, crash-safe + * kernel console implementation that outputs kernel messages to the + * network. + * + * Modification history: + * + * 2001-09-17 started by Ingo Molnar. + * 2003-08-11 2.6 port by Matt Mackall + * simplified options + * generic card hooks + * works non-modular + * 2003-09-07 rewritten with netpoll api + */ + +/**************************************************************** + * 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, or (at your option) + * any 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Maintainer: Matt Mackall "); +MODULE_DESCRIPTION("Console driver for network interfaces"); +MODULE_LICENSE("GPL"); + +static char config[256]; +module_param_string(netconsole, config, 256, 0); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; + +#define MAX_PRINT_CHUNK 1000 + +static void write_msg(struct console *con, const char *msg, unsigned int len) +{ + int frag, left; + unsigned long flags; + + if (!np.dev) + return; + + local_irq_save(flags); + + for(left = len; left; ) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + + local_irq_restore(flags); +} + +static struct console netconsole = { + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg +}; + +static int option_setup(char *opt) +{ + return netpoll_parse_options(&np, opt); +} + +__setup("netconsole=", option_setup); + +static int init_netconsole(void) +{ + if(strlen(config) && option_setup(config)) + return 1; + + if(!np.remote_ip || netpoll_setup(&np)) + return 1; + + register_console(&netconsole); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void cleanup_netconsole(void) +{ + unregister_console(&netconsole); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); --- linux-2.6.1-rc1/drivers/net/net_init.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/net_init.c 2003-12-30 22:49:20.000000000 -0800 @@ -73,23 +73,28 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) { + void *p; struct net_device *dev; int alloc_size; - /* ensure 32-byte alignment of the private area */ - alloc_size = sizeof (*dev) + sizeof_priv + 31; + /* ensure 32-byte alignment of both the device and private area */ - dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); - if (dev == NULL) - { - printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); + alloc_size = (sizeof(struct net_device) + 31) & ~31; + alloc_size += sizeof_priv + 31; + + p = kmalloc (alloc_size, GFP_KERNEL); + if (!p) { + printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); return NULL; } - memset(dev, 0, alloc_size); + memset(p, 0, alloc_size); + + dev = (struct net_device *)(((long)p + 31) & ~31); + dev->padded = (char *)dev - (char *)p; if (sizeof_priv) - dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); + dev->priv = netdev_priv(dev); setup(dev); strcpy(dev->name, mask); --- linux-2.6.1-rc1/drivers/net/ni5010.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ni5010.c 2003-12-30 22:49:20.000000000 -0800 @@ -82,7 +82,7 @@ static unsigned int bufsize_rcv; #ifndef FULL_IODETECT /* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int ni5010_portlist[] __initdata = +static unsigned int ports[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; #endif @@ -95,13 +95,11 @@ static unsigned int ni5010_portlist[] __ struct ni5010_local { struct net_device_stats stats; int o_pkt_size; - int i_pkt_size; spinlock_t lock; }; /* Index to functions, as function prototypes. */ -extern int ni5010_probe(struct net_device *dev); static int ni5010_probe1(struct net_device *dev, int ioaddr); static int ni5010_open(struct net_device *dev); static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -120,38 +118,58 @@ static void chipset_init(struct net_dev static void dump_packet(void *buf, int len); static void ni5010_show_registers(struct net_device *dev); +static int io; +static int irq; -int __init ni5010_probe(struct net_device *dev) +struct net_device * __init ni5010_probe(int unit) { + struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local)); int *port; - int base_addr = dev->base_addr; + int err = 0; - PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + if (!dev) + return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni5010_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; + PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + SET_MODULE_OWNER(dev); + + if (io > 0x1ff) { /* Check a single specified location. */ + err = ni5010_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { #ifdef FULL_IODETECT - for (int ioaddr=0x200; ioaddr<0x400; ioaddr+=0x20) { - if (check_region(ioaddr, NI5010_IO_EXTENT)) - continue; - if (ni5010_probe1(dev, ioaddr) == 0) - return 0; - } + for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20) + ; + if (io == 0x400) + err = -ENODEV; + #else - for (port = ni5010_portlist; *port; port++) { - int ioaddr = *port; - if (check_region(ioaddr, NI5010_IO_EXTENT)) - continue; - if (ni5010_probe1(dev, ioaddr) == 0) - return 0; - } + for (port = ports; *port && ni5010_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; #endif /* FULL_IODETECT */ - return -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, NI5010_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } static inline int rd_port(int ioaddr) @@ -188,9 +206,17 @@ static void __init trigger_irq(int ioadd static int __init ni5010_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; + struct ni5010_local *lp; int i; unsigned int data = 0; int boguscount = 40; + int err = -ENODEV; + + dev->base_addr = ioaddr; + dev->irq = irq; + + if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname)) + return -EBUSY; /* * This is no "official" probe method, I've rather tested which @@ -205,36 +231,40 @@ static int __init ni5010_probe1(struct n * * - Andreas */ - + PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n", dev->name, ioaddr)); - if (inb(ioaddr+0) == 0xff) return -ENODEV; + if (inb(ioaddr+0) == 0xff) + goto out; while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff) { - if (boguscount-- == 0) return -ENODEV; + if (boguscount-- == 0) + goto out; } PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name)); for (i=0; i<32; i++) if ( (data = rd_port(ioaddr)) != 0xff) break; - if (data==0xff) return -ENODEV; + if (data==0xff) + goto out; PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name)); - if ( (data == SA_ADDR0) && - (rd_port(ioaddr) == SA_ADDR1) && - (rd_port(ioaddr) == SA_ADDR2) ) { - for (i=0; i<4; i++) rd_port(ioaddr); - if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || - (rd_port(ioaddr) != NI5010_MAGICVAL2) ) { - return -ENODEV; - } - } else return -ENODEV; - + if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) || + (rd_port(ioaddr) != SA_ADDR2)) + goto out; + + for (i=0; i<4; i++) + rd_port(ioaddr); + + if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || + (rd_port(ioaddr) != NI5010_MAGICVAL2) ) + goto out; + PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name)); if (NI5010_DEBUG && version_printed++ == 0) @@ -267,8 +297,9 @@ static int __init ni5010_probe1(struct n PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name)); if (dev->irq == 0) { + err = -EAGAIN; printk(KERN_WARNING "%s: no IRQ found!\n", dev->name); - return -EAGAIN; + goto out; } PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name)); } else if (dev->irq == 2) { @@ -278,19 +309,9 @@ static int __init ni5010_probe1(struct n PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); /* DMA is not supported (yet?), so no use detecting it */ + lp = (struct ni5010_local*)dev->priv; - if (dev->priv == NULL) { - struct ni5010_local* lp; - - dev->priv = kmalloc(sizeof(struct ni5010_local), GFP_KERNEL|GFP_DMA); - if (dev->priv == NULL) { - printk(KERN_WARNING "%s: Failed to allocate private memory\n", dev->name); - return -ENOMEM; - } - - lp = (struct ni5010_local*)dev->priv; - spin_lock_init(&lp->lock); - } + spin_lock_init(&lp->lock); PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name)); @@ -315,9 +336,6 @@ static int __init ni5010_probe1(struct n } printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); memset(dev->priv, 0, sizeof(struct ni5010_local)); - - /* Grab the region so we can find another board if autoIRQ fails. */ - request_region(ioaddr, NI5010_IO_EXTENT, boardname); dev->open = ni5010_open; dev->stop = ni5010_close; @@ -327,9 +345,6 @@ static int __init ni5010_probe1(struct n dev->tx_timeout = ni5010_timeout; dev->watchdog_timeo = HZ/20; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ /* Shut up the ni5010 */ @@ -345,6 +360,9 @@ static int __init ni5010_probe1(struct n printk(KERN_INFO "Join the NI5010 driver development team!\n"); printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n"); return 0; +out: + release_region(dev->base_addr, NI5010_IO_EXTENT); + return err; } /* @@ -513,6 +531,7 @@ static void ni5010_rx(struct net_device int ioaddr = dev->base_addr; unsigned char rcv_stat; struct sk_buff *skb; + int i_pkt_size; PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name)); @@ -532,17 +551,17 @@ static void ni5010_rx(struct net_device outb(0xff, EDLC_RCLR); /* Clear the interrupt */ - lp->i_pkt_size = inw(IE_RCNT); - if (lp->i_pkt_size > ETH_FRAME_LEN || lp->i_pkt_size < 10 ) { + i_pkt_size = inw(IE_RCNT); + if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) { PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", - dev->name, lp->i_pkt_size)); + dev->name, i_pkt_size)); lp->stats.rx_errors++; lp->stats.rx_length_errors++; return; } /* Malloc up new buffer. */ - skb = dev_alloc_skb(lp->i_pkt_size + 3); + skb = dev_alloc_skb(i_pkt_size + 3); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; @@ -555,7 +574,7 @@ static void ni5010_rx(struct net_device /* Read packet into buffer */ outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ outw(0, IE_GP); /* Seek to beginning of packet */ - insb(IE_RBUF, skb_put(skb, lp->i_pkt_size), lp->i_pkt_size); + insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size); if (NI5010_DEBUG >= 4) dump_packet(skb->data, skb->len); @@ -564,10 +583,10 @@ static void ni5010_rx(struct net_device netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += lp->i_pkt_size; + lp->stats.rx_bytes += i_pkt_size; PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", - dev->name, lp->i_pkt_size)); + dev->name, i_pkt_size)); } @@ -697,10 +716,10 @@ static void hardware_send_packet(struct if (NI5010_DEBUG > 3) dump_packet(buf, length); - buf_offs = NI5010_BUFSIZE - length - pad; - lp->o_pkt_size = length + pad; + buf_offs = NI5010_BUFSIZE - length - pad; spin_lock_irqsave(&lp->lock, flags); + lp->o_pkt_size = length + pad; outb(0, EDLC_RMASK); /* Mask all receive interrupts */ outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ @@ -745,9 +764,7 @@ static void ni5010_show_registers(struct } #ifdef MODULE -static struct net_device dev_ni5010; -static int io; -static int irq; +static struct net_device *dev_ni5010; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -756,8 +773,6 @@ MODULE_PARM_DESC(irq, "ni5010 IRQ number int init_module(void) { - int result; - PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname)); /* if(io <= 0 || irq == 0){ @@ -771,29 +786,18 @@ int init_module(void) } PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io)); - dev_ni5010.irq=irq; - dev_ni5010.base_addr=io; - dev_ni5010.init=ni5010_probe; - if ((result = register_netdev(&dev_ni5010)) != 0) { - PRINTK((KERN_WARNING "%s: register_netdev returned %d.\n", - boardname, result)); - return -EIO; - } + dev_ni5010 = ni5010_probe(-1); + if (IS_ERR(dev_ni5010)) + return PTR_ERR(dev_ni5010); return 0; } -void -cleanup_module(void) +void cleanup_module(void) { PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname)); - - unregister_netdev(&dev_ni5010); - - release_region(dev_ni5010.base_addr, NI5010_IO_EXTENT); - if (dev_ni5010.priv != NULL){ - kfree(dev_ni5010.priv); - dev_ni5010.priv = NULL; - } + unregister_netdev(dev_ni5010); + release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT); + free_netdev(dev_ni5010); } #endif /* MODULE */ MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/ni52.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ni52.c 2003-12-30 22:49:20.000000000 -0800 @@ -354,50 +354,76 @@ static void alloc586(struct net_device * memset((char *)p->scb,0,sizeof(struct scb_struct)); } +/* set: io,irq,memstart,memend or set it when calling insmod */ +static int irq=9; +static int io=0x300; +static long memstart; /* e.g 0xd0000 */ +static long memend; /* e.g 0xd4000 */ + /********************************************** * probe the ni5210-card */ -int __init ni52_probe(struct net_device *dev) +struct net_device * __init ni52_probe(int unit) { -#ifndef MODULE - int *port; + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0}; -#endif - int base_addr = dev->base_addr; - - SET_MODULE_OWNER(dev); + int *port; + int err = 0; - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni52_probe1(dev, base_addr); - else if (base_addr > 0) /* Don't probe at all. */ - return -ENXIO; + if (!dev) + return ERR_PTR(-ENOMEM); -#ifdef MODULE - printk("%s: no autoprobing allowed for modules.\n",dev->name); -#else - for (port = ports; *port; port++) { - int ioaddr = *port; - dev->base_addr = ioaddr; - if (ni52_probe1(dev, ioaddr) == 0) - return 0; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + memstart = dev->mem_start; + memend = dev->mem_end; } -#ifdef FULL_IO_PROBE - for(dev->base_addr=0x200; dev->base_addr<0x400; dev->base_addr+=8) - if (ni52_probe1(dev, dev->base_addr) == 0) - return 0; -#endif + SET_MODULE_OWNER(dev); + if (io > 0x1ff) { /* Check a single specified location. */ + err = ni52_probe1(dev, io); + } else if (io > 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = ports; *port && ni52_probe1(dev, *port) ; port++) + ; + if (*port) + goto got_it; +#ifdef FULL_IO_PROBE + for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8) + ; + if (io < 0x400) + goto got_it; #endif - - dev->base_addr = base_addr; - return -ENODEV; + err = -ENODEV; + } + if (err) + goto out; +got_it: + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, NI52_TOTAL_SIZE); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init ni52_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; + dev->base_addr = ioaddr; + dev->irq = irq; + dev->mem_start = memstart; + dev->mem_end = memend; + if (!request_region(ioaddr, NI52_TOTAL_SIZE, dev->name)) return -EBUSY; @@ -416,7 +442,7 @@ static int __init ni52_probe1(struct net goto out; } - printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); + printk(KERN_INFO "%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); /* * check (or search) IO-Memory, 8K and 16K @@ -469,13 +495,6 @@ static int __init ni52_probe1(struct net dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ #endif - dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); - if(dev->priv == NULL) { - printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); - retval = -ENOMEM; - goto out; - } - /* warning: we don't free it on errors */ memset((char *) dev->priv,0,sizeof(struct priv)); ((struct priv *) (dev->priv))->memtop = isa_bus_to_virt(dev->mem_start) + size; @@ -503,8 +522,6 @@ static int __init ni52_probe1(struct net if(!dev->irq) { printk("?autoirq, Failed to detect IRQ line!\n"); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -526,8 +543,6 @@ static int __init ni52_probe1(struct net dev->if_port = 0; - ether_setup(dev); - return 0; out: release_region(ioaddr, NI52_TOTAL_SIZE); @@ -1295,13 +1310,7 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_ni52; - -/* set: io,irq,memstart,memend or set it when calling insmod */ -static int irq=9; -static int io=0x300; -static long memstart; /* e.g 0xd0000 */ -static long memend; /* e.g 0xd4000 */ +static struct net_device *dev_ni52; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -1318,22 +1327,17 @@ int init_module(void) printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); return -ENODEV; } - dev_ni52.init = ni52_probe; - dev_ni52.irq = irq; - dev_ni52.base_addr = io; - dev_ni52.mem_end = memend; - dev_ni52.mem_start = memstart; - if (register_netdev(&dev_ni52) != 0) - return -EIO; + dev_ni52 = ni52_probe(-1); + if (IS_ERR(dev_ni52)) + return PTR_ERR(dev_ni52); return 0; } void cleanup_module(void) { - release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); - unregister_netdev(&dev_ni52); - kfree(dev_ni52.priv); - dev_ni52.priv = NULL; + unregister_netdev(dev_ni52); + release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE); + free_netdev(dev_ni52); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/ni65.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ni65.c 2003-12-30 22:49:20.000000000 -0800 @@ -343,29 +343,64 @@ static int ni65_close(struct net_device return 0; } +static void cleanup_card(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + disable_dma(dev->dma); + free_dma(dev->dma); + release_region(dev->base_addr, cards[p->cardno].total_size); + ni65_free_buffer(p); +} + +/* set: io,irq,dma or set it when calling insmod */ +static int irq; +static int io; +static int dma; + /* * Probe The Card (not the lance-chip) */ -#ifdef MODULE -static -#endif -int __init ni65_probe(struct net_device *dev) +struct net_device * __init ni65_probe(int unit) { - int *port; + struct net_device *dev = alloc_etherdev(0); static int ports[] = {0x360,0x300,0x320,0x340, 0}; + int *port; + int err = 0; - if (dev->base_addr > 0x1ff) /* Check a single specified location. */ - return ni65_probe1(dev, dev->base_addr); - else if (dev->base_addr > 0) /* Don't probe at all. */ - return -ENXIO; + if (!dev) + return ERR_PTR(-ENOMEM); - for (port = ports; *port; port++) - { - if (ni65_probe1(dev, *port) == 0) - return 0; - } - - return -ENODEV; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + irq = dev->irq; + dma = dev->dma; + } else { + dev->base_addr = io; + } + + if (dev->base_addr > 0x1ff) { /* Check a single specified location. */ + err = ni65_probe1(dev, dev->base_addr); + } else if (dev->base_addr > 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = ports; *port && ni65_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } /* @@ -377,6 +412,9 @@ static int __init ni65_probe1(struct net struct priv *p; unsigned long flags; + dev->irq = irq; + dev->dma = dma; + for(i=0;iwatchdog_timeo = HZ/2; dev->get_stats = ni65_get_stats; dev->set_multicast_list = set_multicast_list; - - ether_setup(dev); - return 0; /* everything is OK */ } @@ -1213,12 +1248,7 @@ static void set_multicast_list(struct ne } #ifdef MODULE -static struct net_device dev_ni65 = { .base_addr = 0x360, .irq = 9, .init = ni65_probe }; - -/* set: io,irq,dma or set it when calling insmod */ -static int irq; -static int io; -static int dma; +static struct net_device *dev_ni65; MODULE_PARM(irq, "i"); MODULE_PARM(io, "i"); @@ -1229,26 +1259,15 @@ MODULE_PARM_DESC(dma, "ni6510 ISA DMA ch int init_module(void) { - dev_ni65.irq = irq; - dev_ni65.dma = dma; - dev_ni65.base_addr = io; - if (register_netdev(&dev_ni65) != 0) - return -EIO; - return 0; + dev_ni65 = ni65_probe(-1); + return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; } void cleanup_module(void) { - struct priv *p; - p = (struct priv *) dev_ni65.priv; - if(!p) - BUG(); - disable_dma(dev_ni65.dma); - free_dma(dev_ni65.dma); - unregister_netdev(&dev_ni65); - release_region(dev_ni65.base_addr,cards[p->cardno].total_size); - ni65_free_buffer(p); - dev_ni65.priv = NULL; + unregister_netdev(dev_ni65); + cleanup_card(dev_ni65); + free_netdev(dev_ni65); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/ns83820.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ns83820.c 2003-12-30 22:49:20.000000000 -0800 @@ -374,19 +374,6 @@ static int lnksts = 0; /* CFG_LNKSTS bi #define LINK_DOWN 0x02 #define LINK_UP 0x04 -#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) - -#define kick_rx(dev) do { \ - dprintk("kick_rx: maybe kicking\n"); \ - if (test_and_clear_bit(0, &dev->rx_info.idle)) { \ - dprintk("actually kicking\n"); \ - writel(dev->rx_info.phy_descs + (4 * DESC_SIZE * dev->rx_info.next_rx), dev->base + RXDP); \ - if (dev->rx_info.next_rx == dev->rx_info.next_empty) \ - printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", dev->net_dev.name);\ - __kick_rx(dev); \ - } \ -} while(0) - #ifdef USE_64BIT_ADDR #define HW_ADDR_LEN 8 #define desc_addr_set(desc, addr) \ @@ -438,7 +425,6 @@ struct rx_info { struct ns83820 { - struct net_device net_dev; /* must be first */ struct net_device_stats stats; u8 *base; @@ -478,6 +464,29 @@ struct ns83820 { struct timer_list tx_watchdog; }; +static inline struct ns83820 *PRIV(struct net_device *dev) +{ + return netdev_priv(dev); +} + +#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) + +static inline void kick_rx(struct net_device *ndev) +{ + struct ns83820 *dev = PRIV(ndev); + dprintk("kick_rx: maybe kicking\n"); + if (test_and_clear_bit(0, &dev->rx_info.idle)) { + dprintk("actually kicking\n"); + writel(dev->rx_info.phy_descs + + (4 * DESC_SIZE * dev->rx_info.next_rx), + dev->base + RXDP); + if (dev->rx_info.next_rx == dev->rx_info.next_empty) + printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", + ndev->name); + __kick_rx(dev); + } +} + //free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC #define start_tx_okay(dev) \ (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE) @@ -546,15 +555,16 @@ static inline int ns83820_add_rx_skb(str return 0; } -static inline int rx_refill(struct ns83820 *dev, int gfp) +static inline int rx_refill(struct net_device *ndev, int gfp) { + struct ns83820 *dev = PRIV(ndev); unsigned i; unsigned long flags = 0; if (unlikely(nr_rx_empty(dev) <= 2)) return 0; - dprintk("rx_refill(%p)\n", dev); + dprintk("rx_refill(%p)\n", ndev); if (gfp == GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); for (i=0; idev = &dev->net_dev; + skb->dev = ndev; if (gfp != GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); res = ns83820_add_rx_skb(dev, skb); @@ -587,20 +597,21 @@ static inline int rx_refill(struct ns838 return i ? 0 : -ENOMEM; } -static void FASTCALL(rx_refill_atomic(struct ns83820 *dev)); -static void rx_refill_atomic(struct ns83820 *dev) +static void FASTCALL(rx_refill_atomic(struct net_device *ndev)); +static void rx_refill_atomic(struct net_device *ndev) { - rx_refill(dev, GFP_ATOMIC); + rx_refill(ndev, GFP_ATOMIC); } /* REFILL */ static inline void queue_refill(void *_dev) { - struct ns83820 *dev = _dev; + struct net_device *ndev = _dev; + struct ns83820 *dev = PRIV(ndev); - rx_refill(dev, GFP_KERNEL); + rx_refill(ndev, GFP_KERNEL); if (dev->rx_info.up) - kick_rx(dev); + kick_rx(ndev); } static inline void clear_rx_desc(struct ns83820 *dev, unsigned i) @@ -608,9 +619,10 @@ static inline void clear_rx_desc(struct build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0); } -static void FASTCALL(phy_intr(struct ns83820 *dev)); -static void phy_intr(struct ns83820 *dev) +static void FASTCALL(phy_intr(struct net_device *ndev)); +static void phy_intr(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; u32 tbisr, tanar, tanlpar; @@ -688,27 +700,28 @@ static void phy_intr(struct ns83820 *dev if (newlinkstate & LINK_UP && dev->linkstate != newlinkstate) { - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); + netif_start_queue(ndev); + netif_wake_queue(ndev); printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n", - dev->net_dev.name, + ndev->name, speeds[speed], fullduplex ? "full" : "half"); } else if (newlinkstate & LINK_DOWN && dev->linkstate != newlinkstate) { - netif_stop_queue(&dev->net_dev); - printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name); + netif_stop_queue(ndev); + printk(KERN_INFO "%s: link now down.\n", ndev->name); } dev->linkstate = newlinkstate; } -static int ns83820_setup_rx(struct ns83820 *dev) +static int ns83820_setup_rx(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); unsigned i; int ret; - dprintk("ns83820_setup_rx(%p)\n", dev); + dprintk("ns83820_setup_rx(%p)\n", ndev); dev->rx_info.idle = 1; dev->rx_info.next_rx = 0; @@ -721,7 +734,7 @@ static int ns83820_setup_rx(struct ns838 writel(0, dev->base + RXDP_HI); writel(dev->rx_info.phy_descs, dev->base + RXDP); - ret = rx_refill(dev, GFP_KERNEL); + ret = rx_refill(ndev, GFP_KERNEL); if (!ret) { dprintk("starting receiver\n"); /* prevent the interrupt handler from stomping on us */ @@ -734,7 +747,7 @@ static int ns83820_setup_rx(struct ns838 dev->rx_info.up = 1; - phy_intr(dev); + phy_intr(ndev); /* Okay, let it rip */ spin_lock_irq(&dev->misc_lock); @@ -753,7 +766,7 @@ static int ns83820_setup_rx(struct ns838 writel(1, dev->base + IER); spin_unlock_irq(&dev->misc_lock); - kick_rx(dev); + kick_rx(ndev); spin_unlock_irq(&dev->rx_info.lock); } @@ -793,37 +806,39 @@ static void ns83820_cleanup_rx(struct ns } } -static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev)); -static void ns83820_rx_kick(struct ns83820 *dev) +static void FASTCALL(ns83820_rx_kick(struct net_device *ndev)); +static void ns83820_rx_kick(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { if (dev->rx_info.up) { - rx_refill_atomic(dev); - kick_rx(dev); + rx_refill_atomic(ndev); + kick_rx(ndev); } } if (dev->rx_info.up && nr_rx_empty(dev) > NR_RX_DESC*3/4) schedule_work(&dev->tq_refill); else - kick_rx(dev); + kick_rx(ndev); if (dev->rx_info.idle) - printk(KERN_DEBUG "%s: BAD\n", dev->net_dev.name); + printk(KERN_DEBUG "%s: BAD\n", ndev->name); } /* rx_irq * */ -static void FASTCALL(rx_irq(struct ns83820 *dev)); -static void rx_irq(struct ns83820 *dev) +static void FASTCALL(rx_irq(struct net_device *ndev)); +static void rx_irq(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); struct rx_info *info = &dev->rx_info; unsigned next_rx; u32 cmdsts, *desc; unsigned long flags; int nr = 0; - dprintk("rx_irq(%p)\n", dev); + dprintk("rx_irq(%p)\n", ndev); dprintk("rxdp: %08x, descs: %08lx next_rx[%d]: %p next_empty[%d]: %p\n", readl(dev->base + RXDP), (long)(dev->rx_info.phy_descs), @@ -873,7 +888,7 @@ static void rx_irq(struct ns83820 *dev) } else { skb->ip_summed = CHECKSUM_NONE; } - skb->protocol = eth_type_trans(skb, &dev->net_dev); + skb->protocol = eth_type_trans(skb, ndev); if (NET_RX_DROP == netif_rx(skb)) { netdev_mangle_me_harder_failed: dev->stats.rx_dropped ++; @@ -899,8 +914,9 @@ out: static void rx_action(unsigned long _dev) { - struct ns83820 *dev = (void *)_dev; - rx_irq(dev); + struct net_device *ndev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); + rx_irq(ndev); writel(ihr, dev->base + IHR); spin_lock_irq(&dev->misc_lock); @@ -908,8 +924,8 @@ static void rx_action(unsigned long _dev writel(dev->IMR_cache, dev->base + IMR); spin_unlock_irq(&dev->misc_lock); - rx_irq(dev); - ns83820_rx_kick(dev); + rx_irq(ndev); + ns83820_rx_kick(ndev); } /* Packet Transmit code @@ -924,13 +940,14 @@ static inline void kick_tx(struct ns8382 /* No spinlock needed on the transmit irq path as the interrupt handler is * serialized. */ -static void do_tx_done(struct ns83820 *dev) +static void do_tx_done(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); u32 cmdsts, tx_done_idx, *desc; spin_lock_irq(&dev->tx_lock); - dprintk("do_tx_done(%p)\n", dev); + dprintk("do_tx_done(%p)\n", ndev); tx_done_idx = dev->tx_done_idx; desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); @@ -980,10 +997,10 @@ static void do_tx_done(struct ns83820 *d /* Allow network stack to resume queueing packets after we've * finished transmitting at least 1/4 of the packets in the queue. */ - if (netif_queue_stopped(&dev->net_dev) && start_tx_okay(dev)) { - dprintk("start_queue(%p)\n", dev); - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); + if (netif_queue_stopped(ndev) && start_tx_okay(dev)) { + dprintk("start_queue(%p)\n", ndev); + netif_start_queue(ndev); + netif_wake_queue(ndev); } spin_unlock_irq(&dev->tx_lock); } @@ -1015,9 +1032,9 @@ static void ns83820_cleanup_tx(struct ns * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN). */ -static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) +static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); u32 free_idx, cmdsts, extsts; int nr_free, nr_frags; unsigned tx_done_idx, last_idx; @@ -1033,10 +1050,10 @@ static int ns83820_hard_start_xmit(struc nr_frags = skb_shinfo(skb)->nr_frags; again: if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { - netif_stop_queue(&dev->net_dev); + netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) return 1; - netif_start_queue(&dev->net_dev); + netif_start_queue(ndev); } last_idx = free_idx = dev->tx_free_idx; @@ -1044,13 +1061,13 @@ again: nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC; nr_free -= 1; if (nr_free <= nr_frags) { - dprintk("stop_queue - not enough(%p)\n", dev); - netif_stop_queue(&dev->net_dev); + dprintk("stop_queue - not enough(%p)\n", ndev); + netif_stop_queue(ndev); /* Check again: we may have raced with a tx done irq */ if (dev->tx_done_idx != tx_done_idx) { - dprintk("restart queue(%p)\n", dev); - netif_start_queue(&dev->net_dev); + dprintk("restart queue(%p)\n", ndev); + netif_start_queue(ndev); goto again; } return 1; @@ -1063,8 +1080,8 @@ again: nr_free -= nr_frags; if (nr_free < MIN_TX_DESC_FREE) { - dprintk("stop_queue - last entry(%p)\n", dev); - netif_stop_queue(&dev->net_dev); + dprintk("stop_queue - last entry(%p)\n", ndev); + netif_stop_queue(ndev); stopped = 1; } @@ -1136,10 +1153,10 @@ again: /* Check again: we may have raced with a tx done irq */ if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev)) - netif_start_queue(&dev->net_dev); + netif_start_queue(ndev); /* set the transmit start time to catch transmit timeouts */ - dev->net_dev.trans_start = jiffies; + ndev->trans_start = jiffies; return 0; } @@ -1161,9 +1178,9 @@ static void ns83820_update_stats(struct dev->stats.tx_carrier_errors += readl(base + 0x88) & 0xff; } -static struct net_device_stats *ns83820_get_stats(struct net_device *_dev) +static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) { - struct ns83820 *dev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); /* somewhat overkill */ spin_lock_irq(&dev->misc_lock); @@ -1213,9 +1230,9 @@ static int ns83820_ethtool_ioctl (struct return -EOPNOTSUPP; } -static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd) +static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); switch(cmd) { case SIOCETHTOOL: @@ -1233,23 +1250,25 @@ static void ns83820_mib_isr(struct ns838 spin_unlock(&dev->misc_lock); } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr); +static void ns83820_do_isr(struct net_device *ndev, u32 isr); static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs) { - struct ns83820 *dev = data; + struct net_device *ndev = data; + struct ns83820 *dev = PRIV(ndev); u32 isr; - dprintk("ns83820_irq(%p)\n", dev); + dprintk("ns83820_irq(%p)\n", ndev); dev->ihr = 0; isr = readl(dev->base + ISR); dprintk("irq: %08x\n", isr); - ns83820_do_isr(dev, isr); + ns83820_do_isr(ndev, isr); return IRQ_HANDLED; } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr) +static void ns83820_do_isr(struct net_device *ndev, u32 isr) { + struct ns83820 *dev = PRIV(ndev); #ifdef DEBUG if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC)) Dprintk("odd isr? 0x%08x\n", isr); @@ -1258,7 +1277,7 @@ static void ns83820_do_isr(struct ns8382 if (ISR_RXIDLE & isr) { dev->rx_info.idle = 1; Dprintk("oh dear, we are idle\n"); - ns83820_rx_kick(dev); + ns83820_rx_kick(ndev); } if ((ISR_RXDESC | ISR_RXOK) & isr) { @@ -1270,12 +1289,12 @@ static void ns83820_do_isr(struct ns8382 spin_unlock_irq(&dev->misc_lock); tasklet_schedule(&dev->rx_tasklet); - //rx_irq(dev); + //rx_irq(ndev); //writel(4, dev->base + IHR); } if ((ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr) - ns83820_rx_kick(dev); + ns83820_rx_kick(ndev); if (unlikely(ISR_RXSOVR & isr)) { //printk("overrun: rxsovr\n"); @@ -1297,7 +1316,7 @@ static void ns83820_do_isr(struct ns8382 txdp -= dev->tx_phy_descs; dev->tx_idx = txdp / (DESC_SIZE * 4); if (dev->tx_idx >= NR_TX_DESC) { - printk(KERN_ALERT "%s: BUG -- txdp out of range\n", dev->net_dev.name); + printk(KERN_ALERT "%s: BUG -- txdp out of range\n", ndev->name); dev->tx_idx = 0; } /* The may have been a race between a pci originated read @@ -1313,7 +1332,7 @@ static void ns83820_do_isr(struct ns8382 * work has accumulated */ if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) { - do_tx_done(dev); + do_tx_done(ndev); /* Disable TxOk if there are no outstanding tx packets. */ @@ -1345,7 +1364,7 @@ static void ns83820_do_isr(struct ns8382 /* PHY: Link up/down/negotiation state change */ if (unlikely(ISR_PHY & isr)) - phy_intr(dev); + phy_intr(ndev); #if 0 /* Still working on the interrupt mitigation strategy */ if (dev->ihr) @@ -1363,9 +1382,9 @@ static void ns83820_do_reset(struct ns83 Dprintk("okay!\n"); } -static int ns83820_stop(struct net_device *_dev) +static int ns83820_stop(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); /* FIXME: protect against interrupt handler? */ del_timer_sync(&dev->tx_watchdog); @@ -1392,10 +1411,9 @@ static int ns83820_stop(struct net_devic return 0; } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr); -static void ns83820_tx_timeout(struct net_device *_dev) +static void ns83820_tx_timeout(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); u32 tx_done_idx, *desc; unsigned long flags; @@ -1405,7 +1423,7 @@ static void ns83820_tx_timeout(struct ne desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); printk(KERN_INFO "%s: tx_timeout: tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - dev->net_dev.name, + ndev->name, tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS])); #if defined(DEBUG) @@ -1413,17 +1431,17 @@ static void ns83820_tx_timeout(struct ne u32 isr; isr = readl(dev->base + ISR); printk("irq: %08x imr: %08x\n", isr, dev->IMR_cache); - ns83820_do_isr(dev, isr); + ns83820_do_isr(ndev, isr); } #endif - do_tx_done(dev); + do_tx_done(ndev); tx_done_idx = dev->tx_done_idx; desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); printk(KERN_INFO "%s: after: tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - dev->net_dev.name, + ndev->name, tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS])); local_irq_restore(flags); @@ -1431,7 +1449,8 @@ static void ns83820_tx_timeout(struct ne static void ns83820_tx_watch(unsigned long data) { - struct ns83820 *dev = (void *)data; + struct net_device *ndev = (void *)data; + struct ns83820 *dev = PRIV(ndev); #if defined(DEBUG) printk("ns83820_tx_watch: %u %u %d\n", @@ -1439,21 +1458,21 @@ static void ns83820_tx_watch(unsigned lo ); #endif - if (time_after(jiffies, dev->net_dev.trans_start + 1*HZ) && + if (time_after(jiffies, ndev->trans_start + 1*HZ) && dev->tx_done_idx != dev->tx_free_idx) { printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n", - dev->net_dev.name, + ndev->name, dev->tx_done_idx, dev->tx_free_idx, atomic_read(&dev->nr_tx_skbs)); - ns83820_tx_timeout(&dev->net_dev); + ns83820_tx_timeout(ndev); } mod_timer(&dev->tx_watchdog, jiffies + 2*HZ); } -static int ns83820_open(struct net_device *_dev) +static int ns83820_open(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); unsigned i; u32 desc; int ret; @@ -1462,7 +1481,7 @@ static int ns83820_open(struct net_devic writel(0, dev->base + PQCR); - ret = ns83820_setup_rx(dev); + ret = ns83820_setup_rx(ndev); if (ret) goto failed; @@ -1481,16 +1500,16 @@ static int ns83820_open(struct net_devic writel(desc, dev->base + TXDP); init_timer(&dev->tx_watchdog); - dev->tx_watchdog.data = (unsigned long)dev; + dev->tx_watchdog.data = (unsigned long)ndev; dev->tx_watchdog.function = ns83820_tx_watch; mod_timer(&dev->tx_watchdog, jiffies + 2*HZ); - netif_start_queue(&dev->net_dev); /* FIXME: wait for phy to come up */ + netif_start_queue(ndev); /* FIXME: wait for phy to come up */ return 0; failed: - ns83820_stop(_dev); + ns83820_stop(ndev); return ret; } @@ -1513,28 +1532,28 @@ static void ns83820_getmac(struct ns8382 } } -static int ns83820_change_mtu(struct net_device *_dev, int new_mtu) +static int ns83820_change_mtu(struct net_device *ndev, int new_mtu) { if (new_mtu > RX_BUF_SIZE) return -EINVAL; - _dev->mtu = new_mtu; + ndev->mtu = new_mtu; return 0; } -static void ns83820_set_multicast(struct net_device *_dev) +static void ns83820_set_multicast(struct net_device *ndev) { - struct ns83820 *dev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); u8 *rfcr = dev->base + RFCR; u32 and_mask = 0xffffffff; u32 or_mask = 0; u32 val; - if (dev->net_dev.flags & IFF_PROMISC) + if (ndev->flags & IFF_PROMISC) or_mask |= RFCR_AAU | RFCR_AAM; else and_mask &= ~(RFCR_AAU | RFCR_AAM); - if (dev->net_dev.flags & IFF_ALLMULTI) + if (ndev->flags & IFF_ALLMULTI) or_mask |= RFCR_AAM; else and_mask &= ~RFCR_AAM; @@ -1547,14 +1566,15 @@ static void ns83820_set_multicast(struct spin_unlock_irq(&dev->misc_lock); } -static void ns83820_run_bist(struct ns83820 *dev, const char *name, u32 enable, u32 done, u32 fail) +static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enable, u32 done, u32 fail) { + struct ns83820 *dev = PRIV(ndev); int timed_out = 0; long start; u32 status; int loops = 0; - dprintk("%s: start %s\n", dev->net_dev.name, name); + dprintk("%s: start %s\n", ndev->name, name); start = jiffies; @@ -1578,12 +1598,12 @@ static void ns83820_run_bist(struct ns83 if (status & fail) printk(KERN_INFO "%s: %s failed! (0x%08x & 0x%08x)\n", - dev->net_dev.name, name, status, fail); + ndev->name, name, status, fail); else if (timed_out) printk(KERN_INFO "%s: run_bist %s timed out! (%08x)\n", - dev->net_dev.name, name, status); + ndev->name, name, status); - dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops); + dprintk("%s: done %s in %d loops\n", ndev->name, name, loops); } #ifdef PHY_CODE_IS_FINISHED @@ -1706,8 +1726,9 @@ static unsigned ns83820_mii_write_reg(st return data; } -static void ns83820_probe_phy(struct ns83820 *dev) +static void ns83820_probe_phy(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); static int first; int i; #define MII_PHYIDR1 0x02 @@ -1734,11 +1755,11 @@ static void ns83820_probe_phy(struct ns8 b = ns83820_mii_read_reg(dev, i, MII_PHYIDR2); //printk("%s: phy %d: 0x%04x 0x%04x\n", - // dev->net_dev.name, i, a, b); + // ndev->name, i, a, b); for (j=0; j<0x16; j+=4) { dprintk("%s: [0x%02x] %04x %04x %04x %04x\n", - dev->net_dev.name, j, + ndev->name, j, ns83820_mii_read_reg(dev, i, 0 + j), ns83820_mii_read_reg(dev, i, 1 + j), ns83820_mii_read_reg(dev, i, 2 + j), @@ -1763,6 +1784,7 @@ static void ns83820_probe_phy(struct ns8 static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id) { + struct net_device *ndev; struct ns83820 *dev; long addr; int err; @@ -1778,7 +1800,8 @@ static int __devinit ns83820_init_one(st return -ENODEV; } - dev = (struct ns83820 *)alloc_etherdev((sizeof *dev) - (sizeof dev->net_dev)); + ndev = alloc_etherdev(sizeof(struct ns83820)); + dev = PRIV(ndev); err = -ENOMEM; if (!dev) goto out; @@ -1790,12 +1813,11 @@ static int __devinit ns83820_init_one(st dev->ee.cache = &dev->MEAR_cache; dev->ee.lock = &dev->misc_lock; - SET_MODULE_OWNER(dev->net_dev); - SET_NETDEV_DEV(&dev->net_dev, &pci_dev->dev); - dev->net_dev.priv = dev; + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &pci_dev->dev); - INIT_WORK(&dev->tq_refill, queue_refill, dev); - tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev); + INIT_WORK(&dev->tq_refill, queue_refill, ndev); + tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); if (err) { @@ -1829,55 +1851,63 @@ static int __devinit ns83820_init_one(st 0); err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ, - dev->net_dev.name, dev); + ndev->name, ndev); if (err) { printk(KERN_INFO "ns83820: unable to register irq %d\n", pci_dev->irq); goto out_disable; } - err = register_netdev(&dev->net_dev); - if (err) { - printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); + /* + * FIXME: we are holding rtnl_lock() over obscenely long area only + * because some of the setup code uses dev->name. It's Wrong(tm) - + * we should be using driver-specific names for all that stuff. + * For now that will do, but we really need to come back and kill + * most of the dev_alloc_name() users later. + */ + rtnl_lock(); + err = dev_alloc_name(ndev, ndev->name); + if (err < 0) { + printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err); goto out_free_irq; } printk("%s: ns83820.c: 0x22c: %08x, subsystem: %04x:%04x\n", - dev->net_dev.name, le32_to_cpu(readl(dev->base + 0x22c)), + ndev->name, le32_to_cpu(readl(dev->base + 0x22c)), pci_dev->subsystem_vendor, pci_dev->subsystem_device); - dev->net_dev.open = ns83820_open; - dev->net_dev.stop = ns83820_stop; - dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit; - dev->net_dev.get_stats = ns83820_get_stats; - dev->net_dev.change_mtu = ns83820_change_mtu; - dev->net_dev.set_multicast_list = ns83820_set_multicast; - dev->net_dev.do_ioctl = ns83820_ioctl; - dev->net_dev.tx_timeout = ns83820_tx_timeout; - dev->net_dev.watchdog_timeo = 5 * HZ; + ndev->open = ns83820_open; + ndev->stop = ns83820_stop; + ndev->hard_start_xmit = ns83820_hard_start_xmit; + ndev->get_stats = ns83820_get_stats; + ndev->change_mtu = ns83820_change_mtu; + ndev->set_multicast_list = ns83820_set_multicast; + ndev->do_ioctl = ns83820_ioctl; + ndev->tx_timeout = ns83820_tx_timeout; + ndev->watchdog_timeo = 5 * HZ; - pci_set_drvdata(pci_dev, dev); + pci_set_drvdata(pci_dev, ndev); ns83820_do_reset(dev, CR_RST); /* Must reset the ram bist before running it */ writel(PTSCR_RBIST_RST, dev->base + PTSCR); - ns83820_run_bist(dev, "sram bist", PTSCR_RBIST_EN, + ns83820_run_bist(ndev, "sram bist", PTSCR_RBIST_EN, PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL); - ns83820_run_bist(dev, "eeprom bist", PTSCR_EEBIST_EN, 0, + ns83820_run_bist(ndev, "eeprom bist", PTSCR_EEBIST_EN, 0, PTSCR_EEBIST_FAIL); - ns83820_run_bist(dev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); + ns83820_run_bist(ndev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); /* I love config registers */ dev->CFG_cache = readl(dev->base + CFG); if ((dev->CFG_cache & CFG_PCI64_DET)) { printk(KERN_INFO "%s: detected 64 bit PCI data bus.\n", - dev->net_dev.name); + ndev->name); /*dev->CFG_cache |= CFG_DATA64_EN;*/ if (!(dev->CFG_cache & CFG_DATA64_EN)) printk(KERN_INFO "%s: EEPROM did not enable 64 bit bus. Disabled.\n", - dev->net_dev.name); + ndev->name); } else dev->CFG_cache &= ~(CFG_DATA64_EN); @@ -1905,7 +1935,7 @@ static int __devinit ns83820_init_one(st /* setup optical transceiver if we have one */ if (dev->CFG_cache & CFG_TBI_EN) { printk(KERN_INFO "%s: enabling optical transceiver\n", - dev->net_dev.name); + ndev->name); writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR); /* setup auto negotiation feature advertisement */ @@ -1926,7 +1956,7 @@ static int __devinit ns83820_init_one(st dprintk("CFG: %08x\n", dev->CFG_cache); if (reset_phy) { - printk(KERN_INFO "%s: resetting phy\n", dev->net_dev.name); + printk(KERN_INFO "%s: resetting phy\n", ndev->name); writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ+99)/100); @@ -1996,37 +2026,49 @@ static int __devinit ns83820_init_one(st /* Disable Wake On Lan */ writel(0, dev->base + WCSR); - ns83820_getmac(dev, dev->net_dev.dev_addr); + ns83820_getmac(dev, ndev->dev_addr); /* Yes, we support dumb IP checksum on transmit */ - dev->net_dev.features |= NETIF_F_SG; - dev->net_dev.features |= NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_SG; + ndev->features |= NETIF_F_IP_CSUM; if (using_dac) { printk(KERN_INFO "%s: using 64 bit addressing.\n", - dev->net_dev.name); - dev->net_dev.features |= NETIF_F_HIGHDMA; + ndev->name); + ndev->features |= NETIF_F_HIGHDMA; } printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", - dev->net_dev.name, + ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1], - dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3], - dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5], + ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], + ndev->dev_addr[4], ndev->dev_addr[5], addr, pci_dev->irq, - (dev->net_dev.features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" + (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); #ifdef PHY_CODE_IS_FINISHED - ns83820_probe_phy(dev); + ns83820_probe_phy(ndev); #endif + err = register_netdevice(ndev); + if (err) { + printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); + goto out_cleanup; + } + rtnl_unlock(); + return 0; +out_cleanup: + writel(0, dev->base + IMR); /* paranoia */ + writel(0, dev->base + IER); + readl(dev->base + IER); out_free_irq: - free_irq(pci_dev->irq, dev); + rtnl_unlock(); + free_irq(pci_dev->irq, ndev); out_disable: if (dev->base) iounmap(dev->base); @@ -2034,7 +2076,7 @@ out_disable: pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(pci_dev); out_free: - kfree(dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); out: return err; @@ -2042,24 +2084,25 @@ out: static void __devexit ns83820_remove_one(struct pci_dev *pci_dev) { - struct ns83820 *dev = pci_get_drvdata(pci_dev); + struct net_device *ndev = pci_get_drvdata(pci_dev); + struct ns83820 *dev = PRIV(ndev); /* ok even if NULL */ - if (!dev) /* paranoia */ + if (!ndev) /* paranoia */ return; writel(0, dev->base + IMR); /* paranoia */ writel(0, dev->base + IER); readl(dev->base + IER); - unregister_netdev(&dev->net_dev); - free_irq(dev->pci_dev->irq, dev); + unregister_netdev(ndev); + free_irq(dev->pci_dev->irq, ndev); iounmap(dev->base); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC, dev->tx_descs, dev->tx_phy_descs); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(dev->pci_dev); - free_netdev(&dev->net_dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); } --- linux-2.6.1-rc1/drivers/net/oaknet.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/oaknet.c 2003-12-30 22:49:20.000000000 -0800 @@ -94,8 +94,8 @@ static int __init oaknet_init(void) { register int i; int reg0, regd; - int ret; - struct net_device tmp, *dev = NULL; + int ret = -ENOMEM; + struct net_device *dev; #if 0 unsigned long ioaddr = OAKNET_IO_BASE; #else @@ -105,17 +105,14 @@ static int __init oaknet_init(void) if (!ioaddr) return -ENOMEM; - /* - * This MUST happen here because of the nic_* macros - * which have an implicit dependency on dev->base_addr. - */ - tmp.base_addr = ioaddr; - dev = &tmp; + dev = alloc_ei_netdev(); + if (!dev) + goto out_unmap; ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - goto out_unmap; + goto out_dev; /* Quick register check to see if the device is really there. */ @@ -144,17 +141,7 @@ static int __init oaknet_init(void) goto out_region; } - /* - * We're not using the old-style probing API, so we have to allocate - * our own device structure. - */ - - dev = init_etherdev(NULL, 0); - ret = -ENOMEM; - if (!dev) - goto out_region; SET_MODULE_OWNER(dev); - oaknet_devs = dev; /* * This controller is on an embedded board, so the base address @@ -164,14 +151,6 @@ static int __init oaknet_init(void) dev->base_addr = ioaddr; dev->irq = OAKNET_INT; - /* Allocate 8390-specific device-private area and fields. */ - - ret = -ENOMEM; - if (ethdev_init(dev)) { - printk(" unable to get memory for dev->priv.\n"); - goto out_dev; - } - /* * Disable all chip interrupts for now and ACK all pending * interrupts. @@ -186,7 +165,7 @@ static int __init oaknet_init(void) if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { printk("%s: unable to request interrupt %d.\n", dev->name, dev->irq); - goto out_priv; + goto out_region; } /* Tell the world about what and where we've found. */ @@ -215,15 +194,19 @@ static int __init oaknet_init(void) dev->stop = oaknet_close; NS8390_init(dev, FALSE); + ret = register_netdev(dev); + if (ret) + goto out_irq; + + oaknet_devs = dev; + return 0; - return (0); -out_priv: - kfree(dev->priv); -out_dev: - unregister_netdev(dev); - kfree(dev); +out_irq; + free_irq(dev->irq, dev); out_region: release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); +out_dev: + free_netdev(dev); out_unmap: iounmap(ioaddr); return ret; @@ -662,38 +645,18 @@ oaknet_dma_error(struct net_device *dev, } /* - * Oak Ethernet module load interface. - */ -static int __init oaknet_init_module (void) -{ - if (oaknet_devs != NULL) - return (-EBUSY); - - return (oaknet_init()); -} - -/* * Oak Ethernet module unload interface. */ static void __exit oaknet_cleanup_module (void) { - if (oaknet_devs == NULL) - return; - - if (oaknet_devs->priv != NULL) { - int ioaddr = oaknet_devs->base_addr; - void *priv = oaknet_devs->priv; - free_irq(oaknet_devs->irq, oaknet_devs); - release_region(ioaddr, OAKNET_IO_SIZE); - iounmap(ioaddr); - unregister_netdev(oaknet_dev); - free_netdev(priv); - } - /* Convert to loop once driver supports multiple devices. */ - kfree(oaknet_devs); + unregister_netdev(oaknet_dev); + free_irq(oaknet_devs->irq, oaknet_devs); + release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE); + iounmap(ioaddr); + free_netdev(oaknet_devs); } -module_init(oaknet_init_module); +module_init(oaknet_init); module_exit(oaknet_cleanup_module); MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/pci-skeleton.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/net/pci-skeleton.c 2003-12-30 22:49:20.000000000 -0800 @@ -730,7 +730,7 @@ err_out_free_res: #endif pci_release_regions (pdev); err_out: - kfree (dev); + free_netdev (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; } --- linux-2.6.1-rc1/drivers/net/pcmcia/3c574_cs.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/pcmcia/3c574_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -330,7 +330,7 @@ static dev_link_t *tc574_attach(void) client_reg.event_handler = &tc574_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); tc574_detach(link); @@ -362,23 +362,17 @@ static void tc574_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) tc574_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* tc574_detach */ /* @@ -387,8 +381,8 @@ static void tc574_detach(dev_link_t *lin ethernet device available to the system. */ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ + do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void tc574_config(dev_link_t *link) { @@ -409,12 +403,12 @@ static void tc574_config(dev_link_t *lin tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -424,15 +418,15 @@ static void tc574_config(dev_link_t *lin link->io.IOAddrLines = 16; for (i = j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); goto failed; } - CS_CHECK(RequestIRQ, link->handle, &link->irq); - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -451,8 +445,8 @@ static void tc574_config(dev_link_t *lin the hardware address. The future products may include a modem chip and put the address in the CIS. */ tuple.DesiredTuple = 0x88; - if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) { - CardServices(GetTupleData, handle, &tuple); + if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) { + pcmcia_get_tuple_data(handle, &tuple); for (i = 0; i < 3; i++) phys_addr[i] = htons(buf[i]); } else { @@ -466,9 +460,9 @@ static void tc574_config(dev_link_t *lin } } tuple.DesiredTuple = CISTPL_VERS_1; - if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS && - CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS && - CardServices(ParseTuple, handle, &tuple, &parse) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS && + pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS && + pcmcia_parse_tuple(handle, &tuple, &parse) == CS_SUCCESS) { cardname = parse.version_1.str + parse.version_1.ofs[1]; } else cardname = "3Com 3c574"; @@ -557,21 +551,11 @@ static void tc574_release(dev_link_t *li { DEBUG(0, "3c574_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "3c574_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - tc574_detach(link); } /* @@ -608,7 +592,7 @@ static int tc574_event(event_t event, in if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -616,7 +600,7 @@ static int tc574_event(event_t event, in /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { tc574_reset(dev); netif_device_attach(dev); @@ -1300,8 +1284,7 @@ static int el3_close(struct net_device * link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc574_release(link); + return 0; } --- linux-2.6.1-rc1/drivers/net/pcmcia/3c589_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/pcmcia/3c589_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -244,7 +244,7 @@ static dev_link_t *tc589_attach(void) client_reg.event_handler = &tc589_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); tc589_detach(link); @@ -276,23 +276,17 @@ static void tc589_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) tc589_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* tc589_detach */ /*====================================================================== @@ -303,8 +297,8 @@ static void tc589_detach(dev_link_t *lin ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void tc589_config(dev_link_t *link) { @@ -323,20 +317,20 @@ static void tc589_config(dev_link_t *lin phys_addr = (u16 *)dev->dev_addr; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Is this a 3c562? */ tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; - if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && - (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) { + if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) { if (le16_to_cpu(buf[0]) != MANFID_3COM) printk(KERN_INFO "3c589_cs: hmmm, is this really a " "3Com card??\n"); @@ -351,15 +345,15 @@ static void tc589_config(dev_link_t *lin for (i = j = 0; j < 0x400; j += 0x10) { if (multi && (j & 0x80)) continue; link->io.BasePort1 = j ^ 0x300; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); goto failed; } - CS_CHECK(RequestIRQ, link->handle, &link->irq); - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -374,8 +368,8 @@ static void tc589_config(dev_link_t *lin /* The 3c589 has an extra EEPROM for configuration info, including the hardware address. The 3c562 puts the address in the CIS. */ tuple.DesiredTuple = 0x88; - if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) { - CardServices(GetTupleData, handle, &tuple); + if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) { + pcmcia_get_tuple_data(handle, &tuple); for (i = 0; i < 3; i++) phys_addr[i] = htons(buf[i]); } else { @@ -433,21 +427,11 @@ static void tc589_release(dev_link_t *li { DEBUG(0, "3c589_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "3c589_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - tc589_detach(link); } /*====================================================================== @@ -486,7 +470,7 @@ static int tc589_event(event_t event, in if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -494,7 +478,7 @@ static int tc589_event(event_t event, in /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { tc589_reset(dev); netif_device_attach(dev); @@ -1076,8 +1060,6 @@ static int el3_close(struct net_device * link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc589_release(link); return 0; } --- linux-2.6.1-rc1/drivers/net/pcmcia/axnet_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/pcmcia/axnet_cs.c 2003-12-30 22:50:03.000000000 -0800 @@ -119,7 +119,7 @@ static void axnet_detach(dev_link_t *); static dev_info_t dev_info = "axnet_cs"; static dev_link_t *dev_list; -static int axdev_init(struct net_device *dev); +static void axdev_setup(struct net_device *dev); static void AX88190_init(struct net_device *dev, int startp); static int ax_open(struct net_device *dev); static int ax_close(struct net_device *dev); @@ -128,7 +128,6 @@ static irqreturn_t ax_interrupt(int irq, /*====================================================================*/ typedef struct axnet_dev_t { - struct net_device dev; /* so &dev == &axnet_dev_t */ dev_link_t link; dev_node_t node; caddr_t base; @@ -140,16 +139,10 @@ typedef struct axnet_dev_t { int flags; } axnet_dev_t; -/*====================================================================== - - We never need to do anything when a axnet device is "initialized" - by the net software, because we only register already-found cards. - -======================================================================*/ - -static int axnet_init(struct net_device *dev) +static inline axnet_dev_t *PRIV(struct net_device *dev) { - return 0; + void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device); + return p; } /*====================================================================== @@ -170,12 +163,15 @@ static dev_link_t *axnet_attach(void) DEBUG(0, "axnet_attach()\n"); - /* Create new ethernet device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; dev = &info->dev; - link->priv = info; + dev = alloc_netdev(sizeof(struct ei_device) + sizeof(axnet_dev_t), + "eth%d", axdev_setup); + + if (!dev) + return NULL; + + info = PRIV(dev); + link = &info->link; + link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] == -1) @@ -186,8 +182,6 @@ static dev_link_t *axnet_attach(void) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - axdev_init(dev); - dev->init = &axnet_init; dev->open = &axnet_open; dev->stop = &axnet_close; dev->do_ioctl = &axnet_ioctl; @@ -205,7 +199,7 @@ static dev_link_t *axnet_attach(void) client_reg.event_handler = &axnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); axnet_detach(link); @@ -226,7 +220,7 @@ static dev_link_t *axnet_attach(void) static void axnet_detach(dev_link_t *link) { - axnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "axnet_detach(0x%p)\n", link); @@ -237,23 +231,17 @@ static void axnet_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) axnet_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { - unregister_netdev(&info->dev); - free_netdev(&info->dev); - } else - kfree(info); - + if (link->dev) + unregister_netdev(dev); + free_netdev(dev); } /* axnet_detach */ /*====================================================================== @@ -313,11 +301,8 @@ static int get_prom(dev_link_t *link) ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int try_io_port(dev_link_t *link) { @@ -340,20 +325,20 @@ static int try_io_port(dev_link_t *link) for (j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; - ret = CardServices(RequestIO, link->handle, &link->io); + ret = pcmcia_request_io(link->handle, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } else { - return CardServices(RequestIO, link->handle, &link->io); + return pcmcia_request_io(link->handle, &link->io); } } static void axnet_config(dev_link_t *link) { client_handle_t handle = link->handle; - axnet_dev_t *info = link->priv; - struct net_device *dev = &info->dev; + struct net_device *dev = link->priv; + axnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, j, last_ret, last_fn; @@ -367,9 +352,9 @@ static void axnet_config(dev_link_t *lin tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* don't trust the CIS on this; Linksys got it wrong */ link->conf.Present = 0x63; @@ -378,19 +363,19 @@ static void axnet_config(dev_link_t *lin link->state |= DEV_CONFIG; /* Look up current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (last_ret == CS_SUCCESS) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_io_t *io = &(parse.cftable_entry.io); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); - if ((cfg->index == 0) || (cfg->io.nwin == 0)) + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0 || + cfg->index == 0 || cfg->io.nwin == 0) goto next_entry; link->conf.ConfigIndex = 0x05; @@ -411,32 +396,27 @@ static void axnet_config(dev_link_t *lin if (last_ret == CS_SUCCESS) break; } next_entry: - last_ret = CardServices(GetNextTuple, handle, &tuple); + last_ret = pcmcia_get_next_tuple(handle, &tuple); } if (last_ret != CS_SUCCESS) { cs_error(handle, RequestIO, last_ret); goto failed; } - CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (register_netdev(dev) != 0) { - printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); - goto failed; - } if (!get_prom(link)) { printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n"); printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n"); - unregister_netdev(dev); goto failed; } @@ -451,7 +431,6 @@ static void axnet_config(dev_link_t *lin ei_status.block_output = &block_output; strcpy(info->node.dev_name, dev->name); - link->dev = &info->node; if (inb(dev->base_addr + AXNET_TEST) != 0) info->flags |= IS_AX88790; @@ -476,7 +455,7 @@ static void axnet_config(dev_link_t *lin Bit 2 of CCSR is active low. */ if (i == 32) { conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 }; - CardServices(AccessConfigurationRegister, link->handle, ®); + pcmcia_access_configuration_register(link->handle, ®); for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); if ((j != 0) && (j != 0xffff)) break; @@ -490,6 +469,12 @@ static void axnet_config(dev_link_t *lin printk(KERN_NOTICE " No MII transceivers found!\n"); } + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); + goto failed; + } + + link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; return; @@ -513,21 +498,11 @@ static void axnet_release(dev_link_t *li { DEBUG(0, "axnet_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", - ((axnet_dev_t *)(link->priv))->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - axnet_detach(link); } /*====================================================================== @@ -543,7 +518,7 @@ static int axnet_event(event_t event, in event_callback_args_t *args) { dev_link_t *link = args->client_data; - axnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; DEBUG(2, "axnet_event(0x%06x)\n", event); @@ -551,7 +526,7 @@ static int axnet_event(event_t event, in case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_device_detach(&info->dev); + netif_device_detach(dev); axnet_release(link); } break; @@ -565,8 +540,8 @@ static int axnet_event(event_t event, in case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) - netif_device_detach(&info->dev); - CardServices(ReleaseConfiguration, link->handle); + netif_device_detach(dev); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -574,11 +549,11 @@ static int axnet_event(event_t event, in /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { - axnet_reset_8390(&info->dev); - AX88190_init(&info->dev, 1); - netif_device_attach(&info->dev); + axnet_reset_8390(dev); + AX88190_init(dev, 1); + netif_device_attach(dev); } } break; @@ -648,7 +623,7 @@ static void mdio_write(ioaddr_t addr, in static int axnet_open(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "axnet_open('%s')\n", dev->name); @@ -663,7 +638,7 @@ static int axnet_open(struct net_device info->link_status = 0x00; init_timer(&info->watchdog); info->watchdog.function = &ei_watchdog; - info->watchdog.data = (u_long)info; + info->watchdog.data = (u_long)dev; info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); @@ -674,7 +649,7 @@ static int axnet_open(struct net_device static int axnet_close(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "axnet_close('%s')\n", dev->name); @@ -685,8 +660,6 @@ static int axnet_close(struct net_device link->open--; netif_stop_queue(dev); del_timer_sync(&info->watchdog); - if (link->state & DEV_STALE_CONFIG) - axnet_release(link); return 0; } /* axnet_close */ @@ -726,15 +699,15 @@ static void axnet_reset_8390(struct net_ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) { - axnet_dev_t *info = dev_id; - info->stale = 0; + struct net_device *dev = dev_id; + PRIV(dev)->stale = 0; return ax_interrupt(irq, dev_id, regs); } static void ei_watchdog(u_long arg) { - axnet_dev_t *info = (axnet_dev_t *)(arg); - struct net_device *dev = &info->dev; + struct net_device *dev = (struct net_device *)(arg); + axnet_dev_t *info = PRIV(dev); ioaddr_t nic_base = dev->base_addr; ioaddr_t mii_addr = nic_base + AXNET_MII_EEP; u_short link; @@ -804,7 +777,7 @@ static struct ethtool_ops netdev_ethtool static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { @@ -1053,14 +1026,7 @@ static void do_set_multicast_list(struct static int ax_open(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device *) dev->priv; - - /* This can't happen unless somebody forgot to call axdev_init(). */ - if (ei_local == NULL) - { - printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name); - return -ENXIO; - } + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); #ifdef HAVE_TX_TIMEOUT /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout @@ -1086,7 +1052,7 @@ static int ax_open(struct net_device *de return 0; } -#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock) +#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock) /** * ax_close - shut down network device @@ -1120,7 +1086,7 @@ int ax_close(struct net_device *dev) void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; @@ -1166,7 +1132,7 @@ void ei_tx_timeout(struct net_device *de static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int length, send_length, output_page; unsigned long flags; u8 packet[ETH_ZLEN]; @@ -1312,7 +1278,7 @@ static irqreturn_t ax_interrupt(int irq, } e8390_base = dev->base_addr; - ei_local = (struct ei_device *) dev->priv; + ei_local = (struct ei_device *) netdev_priv(dev); /* * Protect the irq test too. @@ -1424,7 +1390,7 @@ static irqreturn_t ax_interrupt(int irq, static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -1465,7 +1431,7 @@ static void ei_tx_err(struct net_device static void ei_tx_intr(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int status = inb(e8390_base + EN0_TSR); /* @@ -1546,7 +1512,7 @@ static void ei_tx_intr(struct net_device static void ei_receive(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; int rx_pkt_count = 0; @@ -1666,7 +1632,7 @@ static void ei_rx_overrun(struct net_dev axnet_dev_t *info = (axnet_dev_t *)dev; long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -1733,7 +1699,7 @@ static void ei_rx_overrun(struct net_dev static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* If the card is stopped, just return the present stats. */ @@ -1786,39 +1752,30 @@ static void set_multicast_list(struct ne } /** - * axdev_init - init rest of 8390 device struct + * axdev_setup - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -static int axdev_init(struct net_device *dev) +static void axdev_setup(struct net_device *dev) { + struct ei_device *ei_local; if (ei_debug > 1) printk(version_8390); SET_MODULE_OWNER(dev); - if (dev->priv == NULL) - { - struct ei_device *ei_local; - dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ei_device)); - ei_local = (struct ei_device *)dev->priv; - spin_lock_init(&ei_local->page_lock); - } + ei_local = (struct ei_device *)netdev_priv(dev); + spin_lock_init(&ei_local->page_lock); dev->hard_start_xmit = &ei_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - - return 0; } /* This page of functions should be 8390 generic */ @@ -1834,9 +1791,9 @@ static int axdev_init(struct net_device static void AX88190_init(struct net_device *dev, int startp) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; @@ -1905,7 +1862,7 @@ static void NS8390_trigger_send(struct n int start_page) { long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev); if (inb_p(e8390_base) & E8390_TRANS) { --- linux-2.6.1-rc1/drivers/net/pcmcia/com20020_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/pcmcia/com20020_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -145,20 +145,6 @@ typedef struct com20020_dev_t { dev_node_t node; } com20020_dev_t; -static void com20020_setup(struct net_device *dev) -{ - struct arcnet_local *lp = dev->priv; - - lp->timeout = timeout; - lp->backplane = backplane; - lp->clockp = clockp; - lp->clockm = clockm & 3; - lp->hw.owner = THIS_MODULE; - - /* fill in our module parameters as defaults */ - dev->dev_addr[0] = node; -} - /*====================================================================== com20020_attach() creates an "instance" of the driver, allocating @@ -187,14 +173,21 @@ static dev_link_t *com20020_attach(void) if (!info) goto fail_alloc_info; - dev = alloc_netdev(sizeof(struct arcnet_local), "arc%d", - com20020_setup); + dev = alloc_arcdev(""); if (!dev) goto fail_alloc_dev; memset(info, 0, sizeof(struct com20020_dev_t)); memset(link, 0, sizeof(struct dev_link_t)); lp = dev->priv; + lp->timeout = timeout; + lp->backplane = backplane; + lp->clockp = clockp; + lp->clockm = clockm & 3; + lp->hw.owner = THIS_MODULE; + + /* fill in our module parameters as defaults */ + dev->dev_addr[0] = node; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 16; @@ -227,7 +220,7 @@ static dev_link_t *com20020_attach(void) client_reg.event_handler = &com20020_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); com20020_detach(link); @@ -270,14 +263,11 @@ static void com20020_detach(dev_link_t * dev = info->dev; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) com20020_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ DEBUG(1,"unlinking...\n"); @@ -293,6 +283,8 @@ static void com20020_detach(dev_link_t * if (netif_running(dev)) dev->stop(dev); + + unregister_netdev(dev); /* * this is necessary because we register our IRQ separately @@ -300,10 +292,7 @@ static void com20020_detach(dev_link_t * */ if (dev->irq) free_irq(dev->irq, dev); - /* ...but I/O ports are done automatically by card services */ - - unregister_netdev(dev); } DEBUG(1,"kfree...\n"); @@ -325,8 +314,8 @@ static void com20020_detach(dev_link_t * ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void com20020_config(dev_link_t *link) { @@ -353,9 +342,9 @@ static void com20020_config(dev_link_t * tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* Configure card */ @@ -368,13 +357,13 @@ static void com20020_config(dev_link_t * for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) { link->io.BasePort1 = ioaddr; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } } else - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i != CS_SUCCESS) { @@ -388,7 +377,7 @@ static void com20020_config(dev_link_t * DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n", link->irq.AssignedIRQ, link->irq.IRQInfo1, link->irq.IRQInfo2); - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { DEBUG(1,"arcnet: requestIRQ failed totally!\n"); @@ -397,7 +386,7 @@ static void com20020_config(dev_link_t * dev->irq = link->irq.AssignedIRQ; - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); if (com20020_check(dev)) { @@ -447,21 +436,11 @@ static void com20020_release(dev_link_t DEBUG(0, "com20020_release(0x%p)\n", link); - if (link->open) { - DEBUG(1,"postpone...\n"); - DEBUG(1, "com20020_cs: release postponed, device stll open\n"); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); - - if (link->state & DEV_STALE_CONFIG) - com20020_detach(link); } /*====================================================================== @@ -502,7 +481,7 @@ static int com20020_event(event_t event, if (link->open) { netif_device_detach(dev); } - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -510,7 +489,7 @@ static int com20020_event(event_t event, /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { int ioaddr = dev->base_addr; struct arcnet_local *lp = (struct arcnet_local *)dev->priv; --- linux-2.6.1-rc1/drivers/net/pcmcia/fmvj18x_cs.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/pcmcia/fmvj18x_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -307,7 +307,7 @@ static dev_link_t *fmvj18x_attach(void) client_reg.event_handler = &fmvj18x_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); fmvj18x_detach(link); @@ -332,30 +332,24 @@ static void fmvj18x_detach(dev_link_t *l if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) fmvj18x_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* fmvj18x_detach */ /*====================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int mfc_try_io_port(dev_link_t *link) { @@ -369,7 +363,7 @@ static int mfc_try_io_port(dev_link_t *l link->io.NumPorts2 = 0; printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n"); } - ret = CardServices(RequestIO, link->handle, &link->io); + ret = pcmcia_request_io(link->handle, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; @@ -385,7 +379,7 @@ static int ungermann_try_io_port(dev_lin */ for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) { link->io.BasePort1 = ioaddr; - ret = CardServices(RequestIO, link->handle, &link->io); + ret = pcmcia_request_io(link->handle, &link->io); if (ret == CS_SUCCESS) { /* calculate ConfigIndex value */ link->conf.ConfigIndex = @@ -417,12 +411,12 @@ static void fmvj18x_config(dev_link_t *l registers. */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleData = (u_char *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); /* Configure card */ link->state |= DEV_CONFIG; @@ -432,16 +426,16 @@ static void fmvj18x_config(dev_link_t *l tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; - if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) { /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigIndex = parse.cftable_entry.index; tuple.DesiredTuple = CISTPL_MANFID; - if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) - CS_CHECK(GetTupleData, handle, &tuple); + if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); else buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { @@ -449,7 +443,7 @@ static void fmvj18x_config(dev_link_t *l cardtype = TDK; if (le16_to_cpu(buf[1]) == PRODID_TDK_CF010) { cs_status_t status; - CardServices(GetStatus, handle, &status); + pcmcia_get_status(handle, &status); if (status.CardState & CS_EVENT_3VCARD) link->conf.Vcc = 33; /* inserted in 3.3V slot */ } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) { @@ -478,8 +472,8 @@ static void fmvj18x_config(dev_link_t *l } else { /* old type card */ tuple.DesiredTuple = CISTPL_MANFID; - if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) - CS_CHECK(GetTupleData, handle, &tuple); + if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); else buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { @@ -510,10 +504,10 @@ static void fmvj18x_config(dev_link_t *l ret = ungermann_try_io_port(link); if (ret != CS_SUCCESS) goto cs_failed; } else { - CS_CHECK(RequestIO, link->handle, &link->io); + CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); } - CS_CHECK(RequestIRQ, link->handle, &link->irq); - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; if (register_netdev(dev) != 0) { @@ -546,17 +540,17 @@ static void fmvj18x_config(dev_link_t *l case CONTEC: tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); if (cardtype == MBH10304) { /* MBH10304's CIS_FUNCE is corrupted */ node_id = &(tuple.TupleData[5]); card_name = "FMV-J182"; } else { while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) { - CS_CHECK(GetNextTuple, handle, &tuple) ; - CS_CHECK(GetTupleData, handle, &tuple) ; + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); } node_id = &(tuple.TupleData[2]); if( cardtype == TDK ) { @@ -633,8 +627,7 @@ static int fmvj18x_get_hwinfo(dev_link_t req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - i = CardServices(RequestWindow, &link->win, &req); + i = pcmcia_request_window(&link->handle, &req, &link->win); if (i != CS_SUCCESS) { cs_error(link->handle, RequestWindow, i); return -1; @@ -643,7 +636,7 @@ static int fmvj18x_get_hwinfo(dev_link_t base = ioremap(req.Base, req.Size); mem.Page = 0; mem.CardOffset = 0; - CardServices(MapMemPage, link->win, &mem); + pcmcia_map_mem_page(link->win, &mem); /* * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format @@ -668,7 +661,7 @@ static int fmvj18x_get_hwinfo(dev_link_t } iounmap(base); - j = CardServices(ReleaseWindow, link->win); + j = pcmcia_release_window(link->win); if (j != CS_SUCCESS) cs_error(link->handle, ReleaseWindow, j); return (i != 0x200) ? 0 : -1; @@ -689,8 +682,7 @@ static int fmvj18x_setup_mfc(dev_link_t req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - i = CardServices(RequestWindow, &link->win, &req); + i = pcmcia_request_window(&link->handle, &req, &link->win); if (i != CS_SUCCESS) { cs_error(link->handle, RequestWindow, i); return -1; @@ -699,7 +691,7 @@ static int fmvj18x_setup_mfc(dev_link_t base = ioremap(req.Base, req.Size); mem.Page = 0; mem.CardOffset = 0; - CardServices(MapMemPage, link->win, &mem); + pcmcia_map_mem_page(link->win, &mem); ioaddr = dev->base_addr; writeb(0x47, base+0x800); /* Config Option Register of LAN */ @@ -712,7 +704,7 @@ static int fmvj18x_setup_mfc(dev_link_t writeb(0x8, base+0x822); /* Config and Status Register */ iounmap(base); - j = CardServices(ReleaseWindow, link->win); + j = pcmcia_release_window(link->win); if (j != CS_SUCCESS) cs_error(link->handle, ReleaseWindow, j); return 0; @@ -725,27 +717,13 @@ static void fmvj18x_release(dev_link_t * DEBUG(0, "fmvj18x_release(0x%p)\n", link); - /* - If the device is currently in use, we won't release until it - is actually closed. - */ - if (link->open) { - DEBUG(1, "fmvj18x_cs: release postponed, '%s' " - "still open\n", link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseWindow, link->win); - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - fmvj18x_detach(link); } /*====================================================================*/ @@ -777,7 +755,7 @@ static int fmvj18x_event(event_t event, if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -785,7 +763,7 @@ static int fmvj18x_event(event_t event, /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { fjn_reset(dev); netif_device_attach(dev); @@ -1253,8 +1231,6 @@ static int fjn_close(struct net_device * outb(INTR_OFF, ioaddr + LAN_CTRL); link->open--; - if (link->state & DEV_STALE_CONFIG) - fmvj18x_release(link); return 0; } /* fjn_close */ --- linux-2.6.1-rc1/drivers/net/pcmcia/ibmtr_cs.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/pcmcia/ibmtr_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -125,8 +125,7 @@ static void ibmtr_detach(dev_link_t *); static dev_link_t *dev_list; -extern int ibmtr_probe(struct net_device *dev); -extern int trdev_init(struct net_device *dev); +extern int ibmtr_probe_card(struct net_device *dev); extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ @@ -199,7 +198,6 @@ static dev_link_t *ibmtr_attach(void) link->irq.Instance = info->dev = dev; - dev->init = &ibmtr_probe; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); /* Register with Card Services */ @@ -214,7 +212,7 @@ static dev_link_t *ibmtr_attach(void) client_reg.event_handler = &ibmtr_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); goto out_detach; @@ -253,22 +251,22 @@ static void ibmtr_detach(dev_link_t *lin return; dev = info->dev; + + if (link->dev) + unregister_netdev(dev); + { struct tok_info *ti = (struct tok_info *)dev->priv; del_timer_sync(&(ti->tr_timer)); } - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) ibmtr_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - unregister_netdev(dev); free_netdev(dev); kfree(info); } /* ibmtr_detach */ @@ -281,8 +279,8 @@ static void ibmtr_detach(dev_link_t *lin ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void ibmtr_config(dev_link_t *link) { @@ -304,9 +302,9 @@ static void ibmtr_config(dev_link_t *lin tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* Configure card */ @@ -318,18 +316,18 @@ static void ibmtr_config(dev_link_t *lin /* Try PRIMARY card at 0xA20-0xA23 */ link->io.BasePort1 = 0xA20; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) { memcpy(info->node.dev_name, "tr0\0", 4); } else { /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ link->io.BasePort1 = 0xA24; - CS_CHECK(RequestIO, link->handle, &link->io); + CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); memcpy(info->node.dev_name, "tr1\0", 4); } dev->base_addr = link->io.BasePort1; - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); dev->irq = link->irq.AssignedIRQ; ti->irq = link->irq.AssignedIRQ; ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); @@ -340,12 +338,11 @@ static void ibmtr_config(dev_link_t *lin req.Base = 0; req.Size = 0x2000; req.AccessSpeed = 250; - link->win = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &link->win, &req); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); mem.CardOffset = mmiobase; mem.Page = 0; - CS_CHECK(MapMemPage, link->win, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); ti->mmio = ioremap(req.Base, req.Size); /* Allocate the SRAM memory window */ @@ -354,24 +351,23 @@ static void ibmtr_config(dev_link_t *lin req.Base = 0; req.Size = sramsize * 1024; req.AccessSpeed = 250; - info->sram_win_handle = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &info->sram_win_handle, &req); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &info->sram_win_handle)); mem.CardOffset = srambase; mem.Page = 0; - CS_CHECK(MapMemPage, info->sram_win_handle, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(info->sram_win_handle, &mem)); ti->sram_base = mem.CardOffset >> 12; ti->sram_virt = (u_long)ioremap(req.Base, req.Size); - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); /* Set up the Token-Ring Controller Configuration Register and turn on the card. Check the "Local Area Network Credit Card Adapters Technical Reference" SC30-3585 for this info. */ ibmtr_hw_setup(dev, mmiobase); - i = register_netdev(dev); + i = ibmtr_probe_card(dev); if (i != 0) { printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); @@ -412,27 +408,17 @@ static void ibmtr_release(dev_link_t *li DEBUG(0, "ibmtr_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "ibmtr_cs: release postponed, '%s' " - "still open\n", info->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); if (link->win) { struct tok_info *ti = dev->priv; iounmap((void *)ti->mmio); - CardServices(ReleaseWindow, link->win); - CardServices(ReleaseWindow, info->sram_win_handle); + pcmcia_release_window(link->win); + pcmcia_release_window(info->sram_win_handle); } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - ibmtr_detach(link); } /*====================================================================== @@ -474,7 +460,7 @@ static int ibmtr_event(event_t event, in if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -482,9 +468,9 @@ static int ibmtr_event(event_t event, in /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { - (dev->init)(dev); + ibmtr_probe(dev); /* really? */ netif_device_attach(dev); } } --- linux-2.6.1-rc1/drivers/net/pcmcia/nmclan_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/pcmcia/nmclan_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -520,7 +520,7 @@ static dev_link_t *nmclan_attach(void) client_reg.event_handler = &nmclan_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); nmclan_detach(link); @@ -551,23 +551,17 @@ static void nmclan_detach(dev_link_t *li if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) nmclan_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* nmclan_detach */ /* ---------------------------------------------------------------------------- @@ -706,8 +700,8 @@ nmclan_config ethernet device available to the system. ---------------------------------------------------------------------------- */ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ + do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void nmclan_config(dev_link_t *link) { @@ -727,17 +721,17 @@ static void nmclan_config(dev_link_t *li tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* Configure card */ link->state |= DEV_CONFIG; - CS_CHECK(RequestIO, handle, &link->io); - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; i = register_netdev(dev); @@ -753,8 +747,8 @@ static void nmclan_config(dev_link_t *li tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN); /* Verify configuration by reading the MACE ID. */ @@ -812,21 +806,11 @@ static void nmclan_release(dev_link_t *l DEBUG(0, "nmclan_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "nmclan_cs: release postponed, '%s' " - "still open\n", link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - nmclan_detach(link); } /* ---------------------------------------------------------------------------- @@ -863,7 +847,7 @@ static int nmclan_event(event_t event, i if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -871,7 +855,7 @@ static int nmclan_event(event_t event, i /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { nmclan_reset(dev); netif_device_attach(dev); @@ -903,7 +887,7 @@ static void nmclan_reset(struct net_devi reg.Action = CS_READ; reg.Offset = CISREG_COR; reg.Value = 0; - CardServices(AccessConfigurationRegister, link->handle, ®); + pcmcia_access_configuration_register(link->handle, ®); OrigCorValue = reg.Value; /* Reset Xilinx */ @@ -912,12 +896,12 @@ static void nmclan_reset(struct net_devi DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n", OrigCorValue); reg.Value = COR_SOFT_RESET; - CardServices(AccessConfigurationRegister, link->handle, ®); + pcmcia_access_configuration_register(link->handle, ®); /* Need to wait for 20 ms for PCMCIA to finish reset. */ /* Restore original COR configuration index */ reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK); - CardServices(AccessConfigurationRegister, link->handle, ®); + pcmcia_access_configuration_register(link->handle, ®); /* Xilinx is now completely reset along with the MACE chip. */ lp->tx_free_frames=AM2150_MAX_TX_FRAMES; @@ -993,8 +977,6 @@ static int mace_close(struct net_device link->open--; netif_stop_queue(dev); - if (link->state & DEV_STALE_CONFIG) - nmclan_release(link); return 0; } /* mace_close */ @@ -1046,7 +1028,7 @@ static void mace_tx_timeout(struct net_d printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name); #if RESET_ON_TIMEOUT printk("resetting card\n"); - CardServices(ResetCard, link->handle); + pcmcia_reset_card(link->handle, NULL); #else /* #if RESET_ON_TIMEOUT */ printk("NOT resetting card\n"); #endif /* #if RESET_ON_TIMEOUT */ --- linux-2.6.1-rc1/drivers/net/pcmcia/pcnet_cs.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/pcmcia/pcnet_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -224,7 +224,6 @@ static hw_info_t dl10019_info = { 0, 0, static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII }; typedef struct pcnet_dev_t { - struct net_device dev; /* so &dev == &pcnet_dev_t */ dev_link_t link; dev_node_t node; u_int flags; @@ -237,16 +236,10 @@ typedef struct pcnet_dev_t { u_long mii_reset; } pcnet_dev_t; -/*====================================================================== - - We never need to do anything when a pcnet device is "initialized" - by the net software, because we only register already-found cards. - -======================================================================*/ - -static int pcnet_init(struct net_device *dev) +static inline pcnet_dev_t *PRIV(struct net_device *dev) { - return 0; + char *p = netdev_priv(dev); + return (pcnet_dev_t *)(p + sizeof(struct ei_device)); } /*====================================================================== @@ -268,11 +261,11 @@ static dev_link_t *pcnet_attach(void) DEBUG(0, "pcnet_attach()\n"); /* Create new ethernet device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; dev = &info->dev; - link->priv = info; + dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); + if (!dev) return NULL; + info = PRIV(dev); + link = &info->link; + link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; @@ -284,9 +277,7 @@ static dev_link_t *pcnet_attach(void) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - ethdev_init(dev); SET_MODULE_OWNER(dev); - dev->init = &pcnet_init; dev->open = &pcnet_open; dev->stop = &pcnet_close; dev->set_config = &set_config; @@ -303,7 +294,7 @@ static dev_link_t *pcnet_attach(void) client_reg.event_handler = &pcnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); pcnet_detach(link); @@ -324,7 +315,7 @@ static dev_link_t *pcnet_attach(void) static void pcnet_detach(dev_link_t *link) { - pcnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "pcnet_detach(0x%p)\n", link); @@ -335,23 +326,17 @@ static void pcnet_detach(dev_link_t *lin if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) pcnet_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { - unregister_netdev(&info->dev); - free_netdev(&info->dev); - } else - kfree(info); - + if (link->dev) + unregister_netdev(dev); + free_netdev(dev); } /* pcnet_detach */ /*====================================================================== @@ -373,8 +358,7 @@ static hw_info_t *get_hwinfo(dev_link_t req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - i = CardServices(RequestWindow, &link->win, &req); + i = pcmcia_request_window(&link->handle, &req, &link->win); if (i != CS_SUCCESS) { cs_error(link->handle, RequestWindow, i); return NULL; @@ -384,7 +368,7 @@ static hw_info_t *get_hwinfo(dev_link_t mem.Page = 0; for (i = 0; i < NR_INFO; i++) { mem.CardOffset = hw_info[i].offset & ~(req.Size-1); - CardServices(MapMemPage, link->win, &mem); + pcmcia_map_mem_page(link->win, &mem); base = &virt[hw_info[i].offset & (req.Size-1)]; if ((readb(base+0) == hw_info[i].a0) && (readb(base+2) == hw_info[i].a1) && @@ -397,7 +381,7 @@ static hw_info_t *get_hwinfo(dev_link_t } iounmap(virt); - j = CardServices(ReleaseWindow, link->win); + j = pcmcia_release_window(link->win); if (j != CS_SUCCESS) cs_error(link->handle, ReleaseWindow, j); return (i < NR_INFO) ? hw_info+i : NULL; @@ -544,11 +528,8 @@ static hw_info_t *get_hwired(dev_link_t ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int try_io_port(dev_link_t *link) { @@ -571,20 +552,20 @@ static int try_io_port(dev_link_t *link) for (j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; - ret = CardServices(RequestIO, link->handle, &link->io); + ret = pcmcia_request_io(link->handle, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } else { - return CardServices(RequestIO, link->handle, &link->io); + return pcmcia_request_io(link->handle, &link->io); } } static void pcnet_config(dev_link_t *link) { client_handle_t handle = link->handle; - pcnet_dev_t *info = link->priv; - struct net_device *dev = &info->dev; + struct net_device *dev = link->priv; + pcnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; @@ -600,9 +581,9 @@ static void pcnet_config(dev_link_t *lin tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -610,28 +591,28 @@ static void pcnet_config(dev_link_t *lin link->state |= DEV_CONFIG; /* Look up current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; - if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && - (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) { + if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) { manfid = le16_to_cpu(buf[0]); prodid = le16_to_cpu(buf[1]); } tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (last_ret == CS_SUCCESS) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_io_t *io = &(parse.cftable_entry.io); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); - if ((cfg->index == 0) || (cfg->io.nwin == 0)) - goto next_entry; + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0 || + cfg->index == 0 || cfg->io.nwin == 0) + goto next_entry; link->conf.ConfigIndex = cfg->index; /* For multifunction cards, by convention, we configure the @@ -653,14 +634,14 @@ static void pcnet_config(dev_link_t *lin if (last_ret == CS_SUCCESS) break; } next_entry: - last_ret = CardServices(GetNextTuple, handle, &tuple); + last_ret = pcmcia_get_next_tuple(handle, &tuple); } if (last_ret != CS_SUCCESS) { cs_error(handle, RequestIO, last_ret); goto failed; } - CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; @@ -670,7 +651,7 @@ static void pcnet_config(dev_link_t *lin (prodid == PRODID_IBM_HOME_AND_AWAY)) link->conf.ConfigIndex |= 0x10; - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; if (info->flags & HAS_MISC_REG) { @@ -786,29 +767,19 @@ failed: static void pcnet_release(dev_link_t *link) { - pcnet_dev_t *info = link->priv; + pcnet_dev_t *info = PRIV(link->priv); DEBUG(0, "pcnet_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n", - info->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - if (info->flags & USE_SHMEM) { iounmap(info->base); - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); } - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - pcnet_detach(link); } /*====================================================================== @@ -824,7 +795,7 @@ static int pcnet_event(event_t event, in event_callback_args_t *args) { dev_link_t *link = args->client_data; - pcnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; DEBUG(2, "pcnet_event(0x%06x)\n", event); @@ -832,7 +803,7 @@ static int pcnet_event(event_t event, in case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_device_detach(&info->dev); + netif_device_detach(dev); pcnet_release(link); } break; @@ -846,8 +817,8 @@ static int pcnet_event(event_t event, in case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) - netif_device_detach(&info->dev); - CardServices(ReleaseConfiguration, link->handle); + netif_device_detach(dev); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -855,11 +826,11 @@ static int pcnet_event(event_t event, in /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { - pcnet_reset_8390(&info->dev); - NS8390_init(&info->dev, 1); - netif_device_attach(&info->dev); + pcnet_reset_8390(dev); + NS8390_init(dev, 1); + netif_device_attach(dev); } } break; @@ -1039,7 +1010,7 @@ static void write_asic(ioaddr_t ioaddr, static void set_misc_reg(struct net_device *dev) { ioaddr_t nic_base = dev->base_addr; - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); u_char tmp; if (info->flags & HAS_MISC_REG) { @@ -1069,7 +1040,7 @@ static void set_misc_reg(struct net_devi static void mii_phy_probe(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; int i; u_int tmp, phyid; @@ -1093,7 +1064,7 @@ static void mii_phy_probe(struct net_dev static int pcnet_open(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "pcnet_open('%s')\n", dev->name); @@ -1110,7 +1081,7 @@ static int pcnet_open(struct net_device info->link_status = 0x00; init_timer(&info->watchdog); info->watchdog.function = &ei_watchdog; - info->watchdog.data = (u_long)info; + info->watchdog.data = (u_long)dev; info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); @@ -1121,7 +1092,7 @@ static int pcnet_open(struct net_device static int pcnet_close(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "pcnet_close('%s')\n", dev->name); @@ -1132,8 +1103,6 @@ static int pcnet_close(struct net_device link->open--; netif_stop_queue(dev); del_timer_sync(&info->watchdog); - if (link->state & DEV_STALE_CONFIG) - pcnet_release(link); return 0; } /* pcnet_close */ @@ -1174,7 +1143,7 @@ static void pcnet_reset_8390(struct net_ static int set_config(struct net_device *dev, struct ifmap *map) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (!(info->flags & HAS_MISC_REG)) return -EOPNOTSUPP; @@ -1192,7 +1161,8 @@ static int set_config(struct net_device static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) { - pcnet_dev_t *info = dev_id; + struct net_device *dev = dev_id; + pcnet_dev_t *info = PRIV(dev); info->stale = 0; ei_interrupt(irq, dev_id, regs); /* FIXME! Was it really ours? */ @@ -1201,8 +1171,8 @@ static irqreturn_t ei_irq_wrapper(int ir static void ei_watchdog(u_long arg) { - pcnet_dev_t *info = (pcnet_dev_t *)(arg); - struct net_device *dev = &info->dev; + struct net_device *dev = (struct net_device *)arg; + pcnet_dev_t *info = PRIV(dev); ioaddr_t nic_base = dev->base_addr; ioaddr_t mii_addr = nic_base + DLINK_GPIO; u_short link; @@ -1305,7 +1275,7 @@ static struct ethtool_ops netdev_ethtool static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; switch (cmd) { @@ -1416,7 +1386,7 @@ static void dma_block_output(struct net_ const u_char *buf, const int start_page) { ioaddr_t nic_base = dev->base_addr; - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); #ifdef PCMCIA_DEBUG int retries = 0; #endif @@ -1602,7 +1572,7 @@ static int setup_shmem_window(dev_link_t int stop_pg, int cm_offset) { struct net_device *dev = link->priv; - pcnet_dev_t *info = link->priv; + pcnet_dev_t *info = PRIV(dev); win_req_t req; memreq_t mem; int i, window_size, offset, last_ret, last_fn; @@ -1620,14 +1590,13 @@ static int setup_shmem_window(dev_link_t req.Attributes |= WIN_USE_WAIT; req.Base = 0; req.Size = window_size; req.AccessSpeed = mem_speed; - link->win = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &link->win, &req); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); mem.CardOffset = (start_pg << 8) + cm_offset; offset = mem.CardOffset % window_size; mem.CardOffset -= offset; mem.Page = 0; - CS_CHECK(MapMemPage, link->win, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); /* Try scribbling on the buffer */ info->base = ioremap(req.Base, window_size); @@ -1639,7 +1608,7 @@ static int setup_shmem_window(dev_link_t pcnet_reset_8390(dev); if (i != (TX_PAGES<<8)) { iounmap(info->base); - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); info->base = NULL; link->win = NULL; goto failed; } --- linux-2.6.1-rc1/drivers/net/pcmcia/smc91c92_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/pcmcia/smc91c92_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -379,7 +379,7 @@ static dev_link_t *smc91c92_attach(void) client_reg.event_handler = &smc91c92_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); smc91c92_detach(link); @@ -411,23 +411,17 @@ static void smc91c92_detach(dev_link_t * if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) smc91c92_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* smc91c92_detach */ /*====================================================================*/ @@ -453,19 +447,27 @@ static int cvt_ascii_address(struct net_ /*====================================================================*/ -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, - cisparse_t *parse) +static int first_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) { - int i; - i = CardServices(fn, handle, tuple); - if (i != CS_SUCCESS) return i; - i = CardServices(GetTupleData, handle, tuple); - if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + int i; + + if ((i = pcmcia_get_first_tuple(handle, tuple)) != CS_SUCCESS || + (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS) + return i; + return pcmcia_parse_tuple(handle, tuple, parse); } -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int next_tuple(client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + + if ((i = pcmcia_get_next_tuple(handle, tuple)) != CS_SUCCESS || + (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS) + return i; + return pcmcia_parse_tuple(handle, tuple, parse); +} /*====================================================================== @@ -534,7 +536,7 @@ static int mhz_mfc_config(dev_link_t *li for (k = 0; k < 0x400; k += 0x10) { if (k & 0x80) continue; link->io.BasePort1 = k ^ 0x300; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i == CS_SUCCESS) break; @@ -548,15 +550,14 @@ static int mhz_mfc_config(dev_link_t *li req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - i = CardServices(RequestWindow, &link->win, &req); + i = pcmcia_request_window(&link->handle, &req, &link->win); if (i != CS_SUCCESS) return i; smc->base = ioremap(req.Base, req.Size); mem.CardOffset = mem.Page = 0; if (smc->manfid == MANFID_MOTOROLA) mem.CardOffset = link->conf.ConfigBase; - i = CardServices(MapMemPage, link->win, &mem); + i = pcmcia_map_mem_page(link->win, &mem); if ((i == CS_SUCCESS) && (smc->manfid == MANFID_MEGAHERTZ) @@ -594,9 +595,9 @@ static int mhz_setup(dev_link_t *link) /* Another possibility: for the EM3288, in a special tuple */ tuple.DesiredTuple = 0x81; - if (CardServices(GetFirstTuple, handle, &tuple) != CS_SUCCESS) + if (pcmcia_get_first_tuple(handle, &tuple) != CS_SUCCESS) return -1; - if (CardServices(GetTupleData, handle, &tuple) != CS_SUCCESS) + if (pcmcia_get_tuple_data(handle, &tuple) != CS_SUCCESS) return -1; buf[12] = '\0'; if (cvt_ascii_address(dev, buf) == 0) @@ -690,7 +691,7 @@ static int smc_config(dev_link_t *link) link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } i = next_tuple(link->handle, &tuple, &parse); @@ -763,14 +764,14 @@ static int osi_config(dev_link_t *link) for (i = j = 0; j < 4; j++) { link->io.BasePort2 = com[j]; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { /* Fallback: turn off hard decode */ link->conf.ConfigIndex = 0x03; link->io.NumPorts2 = 0; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); } dev->base_addr = link->io.BasePort1 + 0x10; return i; @@ -791,12 +792,12 @@ static int osi_setup(dev_link_t *link, u /* Read the station address from tuple 0x90, subtuple 0x04 */ tuple.DesiredTuple = 0x90; - i = CardServices(GetFirstTuple, handle, &tuple); + i = pcmcia_get_first_tuple(handle, &tuple); while (i == CS_SUCCESS) { - i = CardServices(GetTupleData, handle, &tuple); + i = pcmcia_get_tuple_data(handle, &tuple); if ((i != CS_SUCCESS) || (buf[0] == 0x04)) break; - i = CardServices(GetNextTuple, handle, &tuple); + i = pcmcia_get_next_tuple(handle, &tuple); } if (i != CS_SUCCESS) return -1; @@ -869,9 +870,9 @@ static int check_sig(dev_link_t *link) printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); args.client_data = link; smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args); - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - CardServices(RequestIO, link->handle, &link->io); + pcmcia_request_io(link->handle, &link->io); smc91c92_event(CS_EVENT_CARD_RESET, 0, &args); return check_sig(link); } @@ -936,9 +937,9 @@ static void smc91c92_config(dev_link_t * } CS_EXIT_TEST(i, RequestIO, config_failed); - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); CS_EXIT_TEST(i, RequestIRQ, config_failed); - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); CS_EXIT_TEST(i, RequestConfiguration, config_failed); if (smc->manfid == MANFID_MOTOROLA) @@ -1063,27 +1064,17 @@ static void smc91c92_release(dev_link_t DEBUG(0, "smc91c92_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); if (link->win) { struct net_device *dev = link->priv; struct smc_private *smc = dev->priv; iounmap(smc->base); - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - smc91c92_detach(link); } /*====================================================================== @@ -1124,7 +1115,7 @@ static int smc91c92_event(event_t event, if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -1135,7 +1126,7 @@ static int smc91c92_event(event_t event, if ((smc->manfid == MANFID_MEGAHERTZ) && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (smc->manfid == MANFID_MOTOROLA) mot_config(link); if ((smc->manfid == MANFID_OSITECH) && @@ -1309,8 +1300,6 @@ static int smc_close(struct net_device * link->open--; del_timer_sync(&smc->media); - if (link->state & DEV_STALE_CONFIG) - smc91c92_release(link); return 0; } /* smc_close */ --- linux-2.6.1-rc1/drivers/net/pcmcia/xirc2ps_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/pcmcia/xirc2ps_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -391,28 +391,27 @@ static int do_stop(struct net_device *de /*=============== Helper functions =========================*/ static int -get_tuple_data(int fn, client_handle_t handle, tuple_t *tuple) +first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { - int err; + int err; - if ((err=CardServices(fn, handle, tuple))) + if ((err = pcmcia_get_first_tuple(handle, tuple)) == 0 && + (err = pcmcia_get_tuple_data(handle, tuple)) == 0) + err = pcmcia_parse_tuple(handle, tuple, parse); return err; - return CardServices(GetTupleData, handle, tuple); } static int -get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { - int err; + int err; - if ((err=get_tuple_data(fn, handle, tuple))) + if ((err = pcmcia_get_next_tuple(handle, tuple)) == 0 && + (err = pcmcia_get_tuple_data(handle, tuple)) == 0) + err = pcmcia_parse_tuple(handle, tuple, parse); return err; - return CardServices(ParseTuple, handle, tuple, parse); } -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) - #define SelectPage(pgnr) outb((pgnr), ioaddr + XIRCREG_PR) #define GetByte(reg) ((unsigned)inb(ioaddr + (reg))) #define GetWord(reg) ((unsigned)inw(ioaddr + (reg))) @@ -636,7 +635,7 @@ xirc2ps_attach(void) client_reg.event_handler = &xirc2ps_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - if ((err = CardServices(RegisterClient, &link->handle, &client_reg))) { + if ((err = pcmcia_register_client(&link->handle, &client_reg))) { cs_error(link->handle, RegisterClient, err); xirc2ps_detach(link); return NULL; @@ -680,16 +679,13 @@ xirc2ps_detach(dev_link_t * link) /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free it */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* xirc2ps_detach */ /**************** @@ -887,7 +883,8 @@ xirc2ps_config(dev_link_t * link) } if (err) { /* not found: try to get the node-id from tuple 0x89 */ tuple.DesiredTuple = 0x89; /* data layout looks like tuple 0x22 */ - if (!(err = get_tuple_data(GetFirstTuple, handle, &tuple))) { + if ((err = pcmcia_get_first_tuple(handle, &tuple)) == 0 && + (err = pcmcia_get_tuple_data(handle, &tuple)) == 0) { if (tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID) memcpy(&parse, buf, 8); else @@ -953,8 +950,7 @@ xirc2ps_config(dev_link_t * link) link->conf.ConfigIndex = cf->index ; link->io.BasePort2 = cf->io.win[0].base; link->io.BasePort1 = ioaddr; - if (!(err=CardServices(RequestIO, link->handle, - &link->io))) + if (!(err=pcmcia_request_io(link->handle, &link->io))) goto port_found; } } @@ -976,8 +972,7 @@ xirc2ps_config(dev_link_t * link) link->io.BasePort1 = link->io.BasePort2 + (pass ? (cf->index & 0x20 ? -24:8) : (cf->index & 0x20 ? 8:-24)); - if (!(err=CardServices(RequestIO, link->handle, - &link->io))) + if (!(err=pcmcia_request_io(link->handle, &link->io))) goto port_found; } } @@ -992,11 +987,11 @@ xirc2ps_config(dev_link_t * link) link->io.NumPorts1 = 16; for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { link->io.BasePort1 = ioaddr; - if (!(err=CardServices(RequestIO, link->handle, &link->io))) + if (!(err=pcmcia_request_io(link->handle, &link->io))) goto port_found; } link->io.BasePort1 = 0; /* let CS decide */ - if ((err=CardServices(RequestIO, link->handle, &link->io))) { + if ((err=pcmcia_request_io(link->handle, &link->io))) { cs_error(link->handle, RequestIO, err); goto config_error; } @@ -1009,7 +1004,7 @@ xirc2ps_config(dev_link_t * link) * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - if ((err=CardServices(RequestIRQ, link->handle, &link->irq))) { + if ((err=pcmcia_request_irq(link->handle, &link->irq))) { cs_error(link->handle, RequestIRQ, err); goto config_error; } @@ -1018,8 +1013,7 @@ xirc2ps_config(dev_link_t * link) * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ - if ((err=CardServices(RequestConfiguration, - link->handle, &link->conf))) { + if ((err=pcmcia_request_configuration(link->handle, &link->conf))) { cs_error(link->handle, RequestConfiguration, err); goto config_error; } @@ -1037,16 +1031,14 @@ xirc2ps_config(dev_link_t * link) reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_0; reg.Value = link->io.BasePort2 & 0xff; - if ((err = CardServices(AccessConfigurationRegister, link->handle, - ®))) { + if ((err = pcmcia_access_configuration_register(link->handle, ®))) { cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_1; reg.Value = (link->io.BasePort2 >> 8) & 0xff; - if ((err = CardServices(AccessConfigurationRegister, link->handle, - ®))) { + if ((err = pcmcia_access_configuration_register(link->handle, ®))) { cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } @@ -1058,15 +1050,14 @@ xirc2ps_config(dev_link_t * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - if ((err = CardServices(RequestWindow, &link->win, &req))) { + if ((err = pcmcia_request_window(&link->handle, &req, &link->win))) { cs_error(link->handle, RequestWindow, err); goto config_error; } local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; mem.CardOffset = 0x0; mem.Page = 0; - if ((err = CardServices(MapMemPage, link->win, &mem))) { + if ((err = pcmcia_map_mem_page(link->win, &mem))) { cs_error(link->handle, MapMemPage, err); goto config_error; } @@ -1171,11 +1162,11 @@ xirc2ps_release(dev_link_t *link) local_info_t *local = dev->priv; if (local->dingo) iounmap(local->dingo_ccr - 0x0800); - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); } - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } /* xirc2ps_release */ @@ -1227,7 +1218,7 @@ xirc2ps_event(event_t event, int priorit netif_device_detach(dev); do_powerdown(dev); } - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -1235,7 +1226,7 @@ xirc2ps_event(event_t event, int priorit /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { do_reset(dev,1); netif_device_attach(dev); --- linux-2.6.1-rc1/drivers/net/pcnet32.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/net/pcnet32.c 2003-12-30 22:49:20.000000000 -0800 @@ -456,6 +456,14 @@ static struct pcnet32_access pcnet32_dwi .reset = pcnet32_dwio_reset }; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void pcnet32_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); +} +#endif /* only probes for non-PCI devices, the rest are handled by @@ -805,12 +813,16 @@ pcnet32_probe1(unsigned long ioaddr, uns dev->do_ioctl = &pcnet32_ioctl; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = pcnet32_poll_controller; +#endif + + /* Fill in the generic fields of the device structure. */ + if (register_netdev(dev)) + goto err_free_consistent; lp->next = pcnet32_dev; pcnet32_dev = dev; - - /* Fill in the generic fields of the device structure. */ - register_netdev(dev); printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name); cards_found++; return 0; --- linux-2.6.1-rc1/drivers/net/plip.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/plip.c 2003-12-30 22:49:20.000000000 -0800 @@ -277,19 +277,11 @@ inline static unsigned char read_status then calls us here. */ -static int +static void plip_init_netdev(struct net_device *dev) { struct net_local *nl = dev->priv; - printk(KERN_INFO "%s", version); - if (dev->irq != -1) - printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n", - dev->name, dev->base_addr, dev->irq); - else - printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n", - dev->name, dev->base_addr); - /* Then, override parts of it */ dev->hard_start_xmit = plip_tx_packet; dev->open = plip_open; @@ -323,8 +315,6 @@ plip_init_netdev(struct net_device *dev) INIT_WORK(&nl->timer, (void (*)(void *))plip_timer_bh, dev); spin_lock_init(&nl->lock); - - return 0; } /* Bottom half handler for the delayed request. @@ -1282,14 +1272,13 @@ static void plip_attach (struct parport } sprintf(name, "plip%d", unit); - dev = alloc_netdev(sizeof(struct net_local), name, - ether_setup); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) { printk(KERN_ERR "plip: memory squeeze\n"); return; } - dev->init = plip_init_netdev; + strcpy(dev->name, name); SET_MODULE_OWNER(dev); dev->irq = port->irq; @@ -1306,17 +1295,35 @@ static void plip_attach (struct parport if (!nl->pardev) { printk(KERN_ERR "%s: parport_register failed\n", name); - kfree(dev); + goto err_free_dev; return; } + plip_init_netdev(dev); + if (register_netdev(dev)) { printk(KERN_ERR "%s: network register failed\n", name); - kfree(dev); - } else { - dev_plip[unit++] = dev; + goto err_parport_unregister; } + + printk(KERN_INFO "%s", version); + if (dev->irq != -1) + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "using IRQ %d.\n", + dev->name, dev->base_addr, dev->irq); + else + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "not using IRQ.\n", + dev->name, dev->base_addr); + dev_plip[unit++] = dev; } + return; + +err_parport_unregister: + parport_unregister_device(nl->pardev); +err_free_dev: + free_netdev(dev); + return; } /* plip_detach() is called (by the parport code) when a port is --- linux-2.6.1-rc1/drivers/net/ppp_async.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/ppp_async.c 2003-12-30 22:50:01.000000000 -0800 @@ -16,8 +16,6 @@ * Part of the code in this driver was inspired by the old async-only * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. - * - * ==FILEVERSION 20020125== */ #include @@ -61,6 +59,9 @@ struct asyncppp { struct sk_buff *rpkt; int lcp_fcs; + struct sk_buff_head rqueue; + + struct tasklet_struct tsk; atomic_t refcnt; struct semaphore dead_sem; @@ -74,8 +75,9 @@ struct asyncppp { #define XMIT_BUSY 2 /* State bits */ -#define SC_TOSS 0x20000000 -#define SC_ESCAPE 0x40000000 +#define SC_TOSS 1 +#define SC_ESCAPE 2 +#define SC_PREV_ERROR 4 /* Bits in rbits */ #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) @@ -97,6 +99,8 @@ static void ppp_async_input(struct async char *flags, int count); static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg); +static void ppp_async_process(unsigned long arg); + static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, int len, int inbound); @@ -165,6 +169,9 @@ ppp_asynctty_open(struct tty_struct *tty ap->olim = ap->obuf; ap->lcp_fcs = -1; + skb_queue_head_init(&ap->rqueue); + tasklet_init(&ap->tsk, ppp_async_process, (unsigned long) ap); + atomic_set(&ap->refcnt, 1); init_MUTEX_LOCKED(&ap->dead_sem); @@ -214,10 +221,12 @@ ppp_asynctty_close(struct tty_struct *tt */ if (!atomic_dec_and_test(&ap->refcnt)) down(&ap->dead_sem); + tasklet_kill(&ap->tsk); ppp_unregister_channel(&ap->chan); if (ap->rpkt != 0) kfree_skb(ap->rpkt); + skb_queue_purge(&ap->rqueue); if (ap->tpkt != 0) kfree_skb(ap->tpkt); kfree(ap); @@ -316,17 +325,24 @@ ppp_asynctty_room(struct tty_struct *tty return 65535; } +/* + * This can now be called from hard interrupt level as well + * as soft interrupt level or mainline. + */ static void ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, - char *flags, int count) + char *cflags, int count) { struct asyncppp *ap = ap_get(tty); + unsigned long flags; if (ap == 0) return; - spin_lock_bh(&ap->recv_lock); - ppp_async_input(ap, buf, flags, count); - spin_unlock_bh(&ap->recv_lock); + spin_lock_irqsave(&ap->recv_lock, flags); + ppp_async_input(ap, buf, cflags, count); + spin_unlock_irqrestore(&ap->recv_lock, flags); + if (skb_queue_len(&ap->rqueue)) + tasklet_schedule(&ap->tsk); ap_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver->unthrottle) @@ -341,8 +357,8 @@ ppp_asynctty_wakeup(struct tty_struct *t clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (ap == 0) return; - if (ppp_async_push(ap)) - ppp_output_wakeup(&ap->chan); + set_bit(XMIT_WAKEUP, &ap->xmit_flags); + tasklet_schedule(&ap->tsk); ap_put(ap); } @@ -396,9 +412,9 @@ ppp_async_ioctl(struct ppp_channel *chan if (get_user(val, (int *) arg)) break; ap->flags = val & ~SC_RCV_BITS; - spin_lock_bh(&ap->recv_lock); + spin_lock_irq(&ap->recv_lock); ap->rbits = val & SC_RCV_BITS; - spin_unlock_bh(&ap->recv_lock); + spin_unlock_irq(&ap->recv_lock); err = 0; break; @@ -460,6 +476,28 @@ ppp_async_ioctl(struct ppp_channel *chan } /* + * This is called at softirq level to deliver received packets + * to the ppp_generic code, and to tell the ppp_generic code + * if we can accept more output now. + */ +static void ppp_async_process(unsigned long arg) +{ + struct asyncppp *ap = (struct asyncppp *) arg; + struct sk_buff *skb; + + /* process received packets */ + while ((skb = skb_dequeue(&ap->rqueue)) != NULL) { + if (skb->cb[0]) + ppp_input_error(&ap->chan, 0); + ppp_input(&ap->chan, skb); + } + + /* try to push more stuff out */ + if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_async_push(ap)) + ppp_output_wakeup(&ap->chan); +} + +/* * Procedures for encapsulation and framing. */ @@ -641,7 +679,6 @@ ppp_async_push(struct asyncppp *ap) struct tty_struct *tty = ap->tty; int tty_stuffed = 0; - set_bit(XMIT_WAKEUP, &ap->xmit_flags); /* * We can get called recursively here if the tty write * function calls our wakeup function. This can happen @@ -752,22 +789,19 @@ scan_ordinary(struct asyncppp *ap, const } /* called when a flag is seen - do end-of-packet processing */ -static inline void +static void process_input_packet(struct asyncppp *ap) { struct sk_buff *skb; unsigned char *p; unsigned int len, fcs, proto; - int code = 0; skb = ap->rpkt; - ap->rpkt = 0; - if ((ap->state & (SC_TOSS | SC_ESCAPE)) || skb == 0) { - ap->state &= ~(SC_TOSS | SC_ESCAPE); - if (skb != 0) - kfree_skb(skb); - return; - } + if (ap->state & (SC_TOSS | SC_ESCAPE)) + goto err; + + if (skb == NULL) + return; /* 0-length packet */ /* check the FCS */ p = skb->data; @@ -801,20 +835,18 @@ process_input_packet(struct asyncppp *ap async_lcp_peek(ap, p, skb->len, 1); } - /* all OK, give it to the generic layer */ - ppp_input(&ap->chan, skb); + /* queue the frame to be processed */ + skb->cb[0] = ap->state; + skb_queue_tail(&ap->rqueue, skb); + ap->rpkt = 0; + ap->state = 0; return; err: - kfree_skb(skb); - ppp_input_error(&ap->chan, code); -} - -static inline void -input_error(struct asyncppp *ap, int code) -{ - ap->state |= SC_TOSS; - ppp_input_error(&ap->chan, code); + /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */ + ap->state = SC_PREV_ERROR; + if (skb) + skb_trim(skb, 0); } /* called when the tty driver has data for us. */ @@ -856,7 +888,7 @@ ppp_async_input(struct asyncppp *ap, con } if (f != 0) { /* start tossing */ - input_error(ap, f); + ap->state |= SC_TOSS; } else if (n > 0 && (ap->state & SC_TOSS) == 0) { /* stuff the chars in the skb */ @@ -872,7 +904,7 @@ ppp_async_input(struct asyncppp *ap, con } if (n > skb_tailroom(skb)) { /* packet overflowed MRU */ - input_error(ap, 1); + ap->state |= SC_TOSS; } else { sp = skb_put(skb, n); memcpy(sp, buf, n); @@ -909,7 +941,7 @@ ppp_async_input(struct asyncppp *ap, con nomem: printk(KERN_ERR "PPPasync: no memory (input pkt)\n"); - input_error(ap, 0); + ap->state |= SC_TOSS; } /* --- linux-2.6.1-rc1/drivers/net/ppp_generic.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/ppp_generic.c 2003-12-30 22:49:20.000000000 -0800 @@ -917,19 +917,14 @@ ppp_net_ioctl(struct net_device *dev, st return err; } -static int -ppp_net_init(struct net_device *dev) +static void ppp_setup(struct net_device *dev) { dev->hard_header_len = PPP_HDRLEN; dev->mtu = PPP_MTU; - dev->hard_start_xmit = ppp_start_xmit; - dev->get_stats = ppp_net_stats; - dev->do_ioctl = ppp_net_ioctl; dev->addr_len = 0; dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - return 0; } /* @@ -2272,23 +2267,13 @@ ppp_create_interface(int unit, int *retp int i; ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); - if (ppp == 0) - goto err; - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == 0) - goto err; + if (!ppp) + goto out; + dev = alloc_netdev(0, "", ppp_setup); + if (!dev) + goto out1; memset(ppp, 0, sizeof(struct ppp)); - memset(dev, 0, sizeof(struct net_device)); - ret = -EEXIST; - down(&all_ppp_sem); - if (unit < 0) - unit = cardmap_find_first_free(all_ppp_units); - else if (cardmap_get(all_ppp_units, unit) != NULL) - goto err_unlock; /* unit already exists */ - - /* Initialize the new ppp unit */ - ppp->file.index = unit; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ @@ -2301,20 +2286,29 @@ ppp_create_interface(int unit, int *retp ppp->minseq = -1; skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ - ppp->dev = dev; - dev->init = ppp_net_init; - sprintf(dev->name, "ppp%d", unit); dev->priv = ppp; - dev->destructor = free_netdev; - rtnl_lock(); - ret = register_netdevice(dev); - rtnl_unlock(); + dev->hard_start_xmit = ppp_start_xmit; + dev->get_stats = ppp_net_stats; + dev->do_ioctl = ppp_net_ioctl; + + ret = -EEXIST; + down(&all_ppp_sem); + if (unit < 0) + unit = cardmap_find_first_free(all_ppp_units); + else if (cardmap_get(all_ppp_units, unit) != NULL) + goto out2; /* unit already exists */ + + /* Initialize the new ppp unit */ + ppp->file.index = unit; + sprintf(dev->name, "ppp%d", unit); + + ret = register_netdev(dev); if (ret != 0) { printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); - goto err_unlock; + goto out2; } atomic_inc(&ppp_unit_count); @@ -2323,14 +2317,13 @@ ppp_create_interface(int unit, int *retp *retp = 0; return ppp; - err_unlock: +out2: up(&all_ppp_sem); - err: + free_netdev(dev); +out1: + kfree(ppp); +out: *retp = ret; - if (ppp) - kfree(ppp); - if (dev) - kfree(dev); return NULL; } @@ -2361,8 +2354,10 @@ static void ppp_shutdown_interface(struc ppp->dev = 0; ppp_unlock(ppp); /* This will call dev_close() for us. */ - if (dev) + if (dev) { unregister_netdev(dev); + free_netdev(dev); + } cardmap_set(&all_ppp_units, ppp->file.index, NULL); ppp->file.dead = 1; ppp->owner = NULL; --- linux-2.6.1-rc1/drivers/net/r8169.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/net/r8169.c 2003-12-30 22:49:20.000000000 -0800 @@ -56,9 +56,11 @@ VERSION 1.2 <2002/11/30> printk( "Assertion failed! %s,%s,%s,line=%d\n", \ #expr,__FILE__,__FUNCTION__,__LINE__); \ } +#define dprintk(fmt, args...) do { printk(PFX fmt, ## args) } while (0) #else #define assert(expr) do {} while (0) -#endif +#define dprintk(fmt, args...) do {} while (0) +#endif /* RTL8169_DEBUG */ /* media options */ #define MAX_UNITS 8 @@ -89,9 +91,12 @@ static int multicast_filter_limit = 32; #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ #define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 -#define TX_TIMEOUT (6*HZ) +#define RTL8169_TX_TIMEOUT (6*HZ) +#define RTL8169_PHY_TIMEOUT (HZ) /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) @@ -101,11 +106,35 @@ static int multicast_filter_limit = 32; #define RTL_R16(reg) readw (ioaddr + (reg)) #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) -static struct { +enum mac_version { + RTL_GIGA_MAC_VER_B = 0x00, + /* RTL_GIGA_MAC_VER_C = 0x03, */ + RTL_GIGA_MAC_VER_D = 0x01, + RTL_GIGA_MAC_VER_E = 0x02 +}; + +enum phy_version { + RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */ + RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */ +}; + + +#define _R(NAME,MAC,MASK) \ + { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } + +const static struct { const char *name; -} board_info[] __devinitdata = { - { -"RealTek RTL8169 Gigabit Ethernet"},}; + u8 mac_version; + u32 RxConfigMask; /* Clears the bits supported by this chip */ +} rtl_chip_info[] __devinitdata = { + _R("RTL8169", RTL_GIGA_MAC_VER_B, 0xff7e1880), + _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_D, 0xff7e1880), + _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_E, 0xff7e1880) +}; +#undef _R static struct pci_device_id rtl8169_pci_tbl[] = { {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -114,6 +143,8 @@ static struct pci_device_id rtl8169_pci_ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); +static int rx_copybreak = 200; + enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ @@ -242,14 +273,6 @@ enum RTL8169_register_content { TBILinkOK = 0x02000000, }; -const static struct { - const char *name; - u8 version; /* depend on RTL8169 docs */ - u32 RxConfigMask; /* should clear the bits supported by this chip */ -} rtl_chip_info[] = { - { -"RTL-8169", 0x00, 0xff7e1880,},}; - enum _DescStatusBit { OWNbit = 0x80000000, EORbit = 0x40000000, @@ -257,6 +280,8 @@ enum _DescStatusBit { LSbit = 0x10000000, }; +#define RsvdMask 0x3fffc000 + struct TxDesc { u32 status; u32 vlan_tag; @@ -277,28 +302,33 @@ struct rtl8169_private { struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ int chipset; - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ - unsigned long dirty_tx; - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ + int mac_version; + int phy_version; + u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ + u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ + u32 dirty_rx; + u32 dirty_tx; struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ - unsigned char *RxBufferRings; /* Index of Rx Buffer */ - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ + dma_addr_t TxPhyAddr; + dma_addr_t RxPhyAddr; + struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ + struct timer_list timer; + unsigned long phy_link_down_cnt; }; MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_copybreak, "i"); MODULE_LICENSE("GPL"); static int rtl8169_open(struct net_device *dev); static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static void rtl8169_init_ring(struct net_device *dev); +static int rtl8169_init_ring(struct net_device *dev); static void rtl8169_hw_start(struct net_device *dev); static int rtl8169_close(struct net_device *dev); static void rtl8169_set_rx_mode(struct net_device *dev); @@ -306,11 +336,15 @@ static void rtl8169_tx_timeout(struct ne static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); static const u16 rtl8169_intr_mask = - SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | - RxErr | RxOK; + RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); +#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half +#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less +#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less +#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less + void mdio_write(void *ioaddr, int RegAddr, int value) { @@ -342,13 +376,258 @@ mdio_read(void *ioaddr, int RegAddr) if (RTL_R32(PHYAR) & 0x80000000) { value = (int) (RTL_R32(PHYAR) & 0xFFFF); break; - } else { - udelay(100); } + udelay(100); } return value; } +static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, + int bitval) +{ + int val; + + val = mdio_read(ioaddr, reg); + val = (bitval == 1) ? + val | (bitval << bitnum) : val & ~(0x0001 << bitnum); + mdio_write(ioaddr, reg, val & 0xffff); +} + +static void rtl8169_get_mac_version(struct rtl8169_private *tp, void *ioaddr) +{ + const struct { + u32 mask; + int mac_version; + } mac_info[] = { + { 0x1 << 26, RTL_GIGA_MAC_VER_E }, + { 0x1 << 23, RTL_GIGA_MAC_VER_D }, + { 0x00000000, RTL_GIGA_MAC_VER_B } /* Catch-all */ + }, *p = mac_info; + u32 reg; + + reg = RTL_R32(TxConfig) & 0x7c800000; + while ((reg & p->mask) != p->mask) + p++; + tp->mac_version = p->mac_version; +} + +static void rtl8169_print_mac_version(struct rtl8169_private *tp) +{ + struct { + int version; + char *msg; + } mac_print[] = { + { RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" }, + { RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" }, + { RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" }, + { 0, NULL } + }, *p; + + for (p = mac_print; p->msg; p++) { + if (tp->mac_version == p->version) { + dprintk("mac_version == %s (%04d)\n", p->msg, + p->version); + return; + } + } + dprintk("mac_version == Unknown\n"); +} + +static void rtl8169_get_phy_version(struct rtl8169_private *tp, void *ioaddr) +{ + const struct { + u16 mask; + u16 set; + int phy_version; + } phy_info[] = { + { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G }, + { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F }, + { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E }, + { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */ + }, *p = phy_info; + u16 reg; + + reg = mdio_read(ioaddr, 3) & 0xffff; + while ((reg & p->mask) != p->set) + p++; + tp->phy_version = p->phy_version; +} + +static void rtl8169_print_phy_version(struct rtl8169_private *tp) +{ + struct { + int version; + char *msg; + u32 reg; + } phy_print[] = { + { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 }, + { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 }, + { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 }, + { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 }, + { 0, NULL, 0x0000 } + }, *p; + + for (p = phy_print; p->msg; p++) { + if (tp->phy_version == p->version) { + dprintk("phy_version == %s (%04x)\n", p->msg, p->reg); + return; + } + } + dprintk("phy_version == Unknown\n"); +} + +static void rtl8169_hw_phy_config(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + struct { + u16 regs[5]; /* Beware of bit-sign propagation */ + } phy_magic[5] = { { + { 0x0000, //w 4 15 12 0 + 0x00a1, //w 3 15 0 00a1 + 0x0008, //w 2 15 0 0008 + 0x1020, //w 1 15 0 1020 + 0x1000 } },{ //w 0 15 0 1000 + { 0x7000, //w 4 15 12 7 + 0xff41, //w 3 15 0 ff41 + 0xde60, //w 2 15 0 de60 + 0x0140, //w 1 15 0 0140 + 0x0077 } },{ //w 0 15 0 0077 + { 0xa000, //w 4 15 12 a + 0xdf01, //w 3 15 0 df01 + 0xdf20, //w 2 15 0 df20 + 0xff95, //w 1 15 0 ff95 + 0xfa00 } },{ //w 0 15 0 fa00 + { 0xb000, //w 4 15 12 b + 0xff41, //w 3 15 0 ff41 + 0xde20, //w 2 15 0 de20 + 0x0140, //w 1 15 0 0140 + 0x00bb } },{ //w 0 15 0 00bb + { 0xf000, //w 4 15 12 f + 0xdf01, //w 3 15 0 df01 + 0xdf20, //w 2 15 0 df20 + 0xff95, //w 1 15 0 ff95 + 0xbf00 } //w 0 15 0 bf00 + } + }, *p = phy_magic; + int i; + + rtl8169_print_mac_version(tp); + rtl8169_print_phy_version(tp); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_B) + return; + if (tp->phy_version >= RTL_GIGA_PHY_VER_F) + return; + + dprintk("MAC version != 0 && PHY version == 0 or 1\n"); + dprintk("Do final_reg2.cfg\n"); + + /* Shazam ! */ + + // phy config for RTL8169s mac_version C chip + mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1 + mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000 + mdio_write(ioaddr, 24, 0x65c7); //w 24 15 0 65c7 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + + for (i = ARRAY_SIZE(phy_magic); i > 0; i++, p++) { + int val, pos = 4; + + val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); + mdio_write(ioaddr, pos, val); + while (--pos >= 0) + mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + } + mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0 +} + +static void rtl8169_hw_phy_reset(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + int i, val; + + printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name); + + val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff; + mdio_write(ioaddr, 0, val); + + for (i = 50; i >= 0; i--) { + if (!(mdio_read(ioaddr, 0) & 0x8000)) + break; + udelay(100); /* Gross */ + } + + if (i < 0) { + printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n", + dev->name); + } +} + +static void rtl8169_phy_timer(unsigned long __opaque) +{ + struct net_device *dev = (struct net_device *)__opaque; + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + void *ioaddr = tp->mmio_addr; + + assert(tp->mac_version > RTL_GIGA_MAC_VER_B); + assert(tp->phy_version < RTL_GIGA_PHY_VER_G); + + if (RTL_R8(PHYstatus) & LinkStatus) + tp->phy_link_down_cnt = 0; + else { + tp->phy_link_down_cnt++; + if (tp->phy_link_down_cnt >= 12) { + int reg; + + // If link on 1000, perform phy reset. + reg = mdio_read(ioaddr, PHY_1000_CTRL_REG); + if (reg & PHY_Cap_1000_Full) + rtl8169_hw_phy_reset(dev); + + tp->phy_link_down_cnt = 0; + } + } + + mod_timer(timer, RTL8169_PHY_TIMEOUT); +} + +static inline void rtl8169_delete_timer(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || + (tp->phy_version >= RTL_GIGA_PHY_VER_G)) + return; + + del_timer_sync(timer); + + tp->phy_link_down_cnt = 0; +} + +static inline void rtl8169_request_timer(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || + (tp->phy_version >= RTL_GIGA_PHY_VER_G)) + return; + + tp->phy_link_down_cnt = 0; + + init_timer(timer); + timer->expires = jiffies + RTL8169_PHY_TIMEOUT; + timer->data = (unsigned long)(dev); + timer->function = rtl8169_phy_timer; + add_timer(timer); +} + static int __devinit rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, void **ioaddr_out) @@ -356,9 +635,9 @@ rtl8169_init_board(struct pci_dev *pdev, void *ioaddr = NULL; struct net_device *dev; struct rtl8169_private *tp; - int rc, i; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - u32 tmp; + int rc, i, acpi_idle_state = 0, pm_cap; + assert(pdev != NULL); assert(ioaddr_out != NULL); @@ -379,8 +658,22 @@ rtl8169_init_board(struct pci_dev *pdev, // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); - if (rc) + if (rc) { + printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name); goto err_out; + } + + /* save power state before pci_enable_device overwrites it */ + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap) { + u16 pwr_command; + + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); + acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + } else { + printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); + goto err_out_free_res; + } mmio_start = pci_resource_start(pdev, 1); mmio_end = pci_resource_end(pdev, 1); @@ -402,8 +695,10 @@ rtl8169_init_board(struct pci_dev *pdev, } rc = pci_request_regions(pdev, dev->name); - if (rc) + if (rc) { + printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name); goto err_out_disable; + } // enable PCI bus-mastering pci_set_master(pdev); @@ -420,30 +715,32 @@ rtl8169_init_board(struct pci_dev *pdev, RTL_W8(ChipCmd, CmdReset); // Check that the chip has finished the reset. - for (i = 1000; i > 0; i--) + for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; - else - udelay(10); + udelay(10); + } - // identify chip attached to board - tmp = RTL_R32(TxConfig); - tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24; - - for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) - if (tmp == rtl_chip_info[i].version) { - tp->chipset = i; - goto match; - } - //if unknown chip, assume array element #0, original RTL-8169 in this case - printk(KERN_DEBUG PFX - "PCI device %s: unknown chip version, assuming RTL-8169\n", - pci_name(pdev)); - printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", - pci_name(pdev), (unsigned long) RTL_R32(TxConfig)); - tp->chipset = 0; + // Identify chip attached to board + rtl8169_get_mac_version(tp, ioaddr); + rtl8169_get_phy_version(tp, ioaddr); + + rtl8169_print_mac_version(tp); + rtl8169_print_phy_version(tp); + + for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) { + if (tp->mac_version == rtl_chip_info[i].mac_version) + break; + } + if (i < 0) { + /* Unknown chip: assume array element #0, original RTL-8169 */ + printk(KERN_DEBUG PFX + "PCI device %s: unknown chip version, assuming %s\n", + pci_name(pdev), rtl_chip_info[0].name); + i++; + } + tp->chipset = i; -match: *ioaddr_out = ioaddr; *dev_out = dev; return 0; @@ -499,7 +796,7 @@ rtl8169_init_one(struct pci_dev *pdev, c dev->stop = rtl8169_close; dev->tx_timeout = rtl8169_tx_timeout; dev->set_multicast_list = rtl8169_set_rx_mode; - dev->watchdog_timeo = TX_TIMEOUT; + dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; // dev->do_ioctl = mii_ioctl; @@ -528,12 +825,29 @@ rtl8169_init_one(struct pci_dev *pdev, c "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, - board_info[ent->driver_data].name, + rtl_chip_info[ent->driver_data].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); + rtl8169_hw_phy_config(dev); + + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + + if (tp->mac_version < RTL_GIGA_MAC_VER_E) { + dprintk("Set PCI Latency=0x40\n"); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + } + + if (tp->mac_version == RTL_GIGA_MAC_VER_D) { + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + dprintk("Set PHY Reg 0x0bh = 0x00h\n"); + mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 + } + // if TBI is not endbled if (!(RTL_R8(PHYstatus) & TBI_Enable)) { int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); @@ -546,23 +860,23 @@ rtl8169_init_one(struct pci_dev *pdev, c Cap10_100 = 0, Cap1000 = 0; switch (option) { case _10_Half: - Cap10_100 = PHY_Cap_10_Half; + Cap10_100 = PHY_Cap_10_Half_Or_Less; Cap1000 = PHY_Cap_Null; break; case _10_Full: - Cap10_100 = PHY_Cap_10_Full; + Cap10_100 = PHY_Cap_10_Full_Or_Less; Cap1000 = PHY_Cap_Null; break; case _100_Half: - Cap10_100 = PHY_Cap_100_Half; + Cap10_100 = PHY_Cap_100_Half_Or_Less; Cap1000 = PHY_Cap_Null; break; case _100_Full: - Cap10_100 = PHY_Cap_100_Full; + Cap10_100 = PHY_Cap_100_Full_Or_Less; Cap1000 = PHY_Cap_Null; break; case _1000_Full: - Cap10_100 = PHY_Cap_Null; + Cap10_100 = PHY_Cap_100_Full_Or_Less; Cap1000 = PHY_Cap_1000_Full; break; default: @@ -576,9 +890,7 @@ rtl8169_init_one(struct pci_dev *pdev, c // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged mdio_write(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_10_Half | PHY_Cap_10_Full | - PHY_Cap_100_Half | PHY_Cap_100_Full | (val & - 0x1F)); + PHY_Cap_100_Full_Or_Less | (val & 0x1f)); // enable 1000 Full Mode mdio_write(ioaddr, PHY_1000_CTRL_REG, @@ -647,56 +959,96 @@ rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +#ifdef CONFIG_PM + +static int rtl8169_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + unsigned long flags; + + if (!netif_running(dev)) + return 0; + + netif_device_detach(dev); + netif_stop_queue(dev); + spin_lock_irqsave(&tp->lock, flags); + + /* Disable interrupts, stop Rx and Tx */ + RTL_W16(IntrMask, 0); + RTL_W8(ChipCmd, 0); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + +static int rtl8169_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (!netif_running(dev)) + return 0; + + netif_device_attach(dev); + rtl8169_hw_start(dev); + + return 0; +} + +#endif /* CONFIG_PM */ + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; int retval; - u8 diff; - u32 TxPhyAddr, RxPhyAddr; retval = request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) { - return retval; - } + if (retval < 0) + goto out; - tp->TxDescArrays = - kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL); - // Tx Desscriptor needs 256 bytes alignment; - TxPhyAddr = virt_to_bus(tp->TxDescArrays); - diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8)); - TxPhyAddr += diff; - tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff); - - tp->RxDescArrays = - kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL); - // Rx Desscriptor needs 256 bytes alignment; - RxPhyAddr = virt_to_bus(tp->RxDescArrays); - diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8)); - RxPhyAddr += diff; - tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff); + retval = -ENOMEM; - if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) { - printk(KERN_INFO - "Allocate RxDescArray or TxDescArray failed\n"); - free_irq(dev->irq, dev); - if (tp->TxDescArrays) - kfree(tp->TxDescArrays); - if (tp->RxDescArrays) - kfree(tp->RxDescArrays); - return -ENOMEM; - } - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); - if (tp->RxBufferRings == NULL) { - printk(KERN_INFO "Allocate RxBufferRing failed\n"); - } + /* + * Rx and Tx desscriptors needs 256 bytes alignment. + * pci_alloc_consistent provides more. + */ + tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, + &tp->TxPhyAddr); + if (!tp->TxDescArray) + goto err_free_irq; + + tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, + &tp->RxPhyAddr); + if (!tp->RxDescArray) + goto err_free_tx; + + retval = rtl8169_init_ring(dev); + if (retval < 0) + goto err_free_rx; - rtl8169_init_ring(dev); rtl8169_hw_start(dev); - return 0; - + rtl8169_request_timer(dev); +out: + return retval; + +err_free_rx: + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); +err_free_tx: + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); +err_free_irq: + free_irq(dev->irq, dev); + goto out; } static void @@ -733,11 +1085,17 @@ rtl8169_hw_start(struct net_device *dev) RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift)); + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd)); + + if (tp->mac_version == RTL_GIGA_MAC_VER_D) { + dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n"); + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3)); + } tp->cur_rx = 0; - RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray)); - RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray)); + RTL_W32(TxDescStartAddr, tp->TxPhyAddr); + RTL_W32(RxDescStartAddr, tp->RxPhyAddr); RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); @@ -755,31 +1113,131 @@ rtl8169_hw_start(struct net_device *dev) } -static void -rtl8169_init_ring(struct net_device *dev) +static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) +{ + desc->buf_addr = 0xdeadbeef; + desc->status &= ~cpu_to_le32(OWNbit | RsvdMask); +} + +static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct RxDesc *desc) +{ + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(*sk_buff); + *sk_buff = NULL; + rtl8169_make_unusable_by_asic(desc); +} + +static inline void rtl8169_return_to_asic(struct RxDesc *desc) +{ + desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE); +} + +static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) +{ + desc->buf_addr = cpu_to_le32(mapping); + desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE); +} + +static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, + struct sk_buff **sk_buff, struct RxDesc *desc) +{ + struct sk_buff *skb; + dma_addr_t mapping; + int ret = 0; + + skb = dev_alloc_skb(RX_BUF_SIZE); + if (!skb) + goto err_out; + + skb->dev = dev; + skb_reserve(skb, 2); + *sk_buff = skb; + + mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + rtl8169_give_to_asic(desc, mapping); + +out: + return ret; + +err_out: + ret = -ENOMEM; + rtl8169_make_unusable_by_asic(desc); + goto out; +} + +static void rtl8169_rx_clear(struct rtl8169_private *tp) { - struct rtl8169_private *tp = dev->priv; int i; - tp->cur_rx = 0; - tp->cur_tx = 0; - tp->dirty_tx = 0; + for (i = 0; i < NUM_RX_DESC; i++) { + if (tp->Rx_skbuff[i]) { + rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + } + } +} + +static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, + u32 start, u32 end) +{ + u32 cur; + + for (cur = start; end - start > 0; cur++) { + int ret, i = cur % NUM_RX_DESC; + + if (tp->Rx_skbuff[i]) + continue; + + ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + if (ret < 0) + break; + } + return cur - start; +} + +static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) +{ + desc->status |= cpu_to_le32(EORbit); +} + +static int rtl8169_init_ring(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + + tp->cur_rx = tp->dirty_rx = 0; + tp->cur_tx = tp->dirty_tx = 0; memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc)); memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc)); - for (i = 0; i < NUM_TX_DESC; i++) { - tp->Tx_skbuff[i] = NULL; - } - for (i = 0; i < NUM_RX_DESC; i++) { - if (i == (NUM_RX_DESC - 1)) - tp->RxDescArray[i].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE; + memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); + memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); - tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); - tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); - } + if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) + goto err_out; + + rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); + + return 0; + +err_out: + rtl8169_rx_clear(tp); + return -ENOMEM; +} + +static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct TxDesc *desc) +{ + u32 len = sk_buff[0]->len; + + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), + len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE); + desc->buf_addr = 0x00; + *sk_buff = NULL; } static void @@ -789,9 +1247,12 @@ rtl8169_tx_clear(struct rtl8169_private tp->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { - if (tp->Tx_skbuff[i] != NULL) { - dev_kfree_skb(tp->Tx_skbuff[i]); - tp->Tx_skbuff[i] = NULL; + struct sk_buff *skb = tp->Tx_skbuff[i]; + + if (skb) { + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i, + tp->TxDescArray + i); + dev_kfree_skb(skb); tp->stats.tx_dropped++; } } @@ -829,41 +1290,51 @@ rtl8169_start_xmit(struct sk_buff *skb, struct rtl8169_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry = tp->cur_tx % NUM_TX_DESC; + u32 len = skb->len; - if (skb->len < ETH_ZLEN) { + if (unlikely(skb->len < ETH_ZLEN)) { skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; + if (!skb) + goto err_update_stats; + len = ETH_ZLEN; } spin_lock_irq(&tp->lock); - if ((tp->TxDescArray[entry].status & OWNbit) == 0) { + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { + dma_addr_t mapping; + + mapping = pci_map_single(tp->pci_dev, skb->data, len, + PCI_DMA_TODEVICE); + tp->Tx_skbuff[entry] = skb; - tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data); - if (entry != (NUM_TX_DESC - 1)) - tp->TxDescArray[entry].status = - (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ? - skb->len : ETH_ZLEN); - else - tp->TxDescArray[entry].status = - (OWNbit | EORbit | FSbit | LSbit) | - ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); + tp->TxDescArray[entry].buf_addr = cpu_to_le32(mapping); + tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit | + LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC))); + RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; - } + } else + goto err_drop; - spin_unlock_irq(&tp->lock); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { netif_stop_queue(dev); } +out: + spin_unlock_irq(&tp->lock); return 0; + +err_drop: + dev_kfree_skb(skb); +err_update_stats: + tp->stats.tx_dropped++; + goto out; } static void @@ -881,11 +1352,17 @@ rtl8169_tx_interrupt(struct net_device * tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { - if ((tp->TxDescArray[entry].status & OWNbit) == 0) { - dev_kfree_skb_irq(tp-> - Tx_skbuff[dirty_tx % NUM_TX_DESC]); - tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL; + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { + int cur = dirty_tx % NUM_TX_DESC; + struct sk_buff *skb = tp->Tx_skbuff[cur]; + + /* FIXME: is it really accurate for TxErr ? */ + tp->stats.tx_bytes += skb->len >= ETH_ZLEN ? + skb->len : ETH_ZLEN; tp->stats.tx_packets++; + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + cur, + tp->TxDescArray + cur); + dev_kfree_skb_irq(skb); dirty_tx++; tx_left--; entry++; @@ -899,70 +1376,95 @@ rtl8169_tx_interrupt(struct net_device * } } +static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, + struct RxDesc *desc, + struct net_device *dev) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_size + 2); + if (skb) { + skb->dev = dev; + skb_reserve(skb, 2); + eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + *sk_buff = skb; + rtl8169_return_to_asic(desc); + ret = 0; + } + } + return ret; +} + static void rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - int cur_rx; - struct sk_buff *skb; - int pkt_size = 0; + int cur_rx, delta; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); - cur_rx = tp->cur_rx; + cur_rx = tp->cur_rx % RX_BUF_SIZE; - while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { + while (!(le32_to_cpu(tp->RxDescArray[cur_rx].status) & OWNbit)) { + u32 status = le32_to_cpu(tp->RxDescArray[cur_rx].status); - if (tp->RxDescArray[cur_rx].status & RxRES) { + if (status & RxRES) { printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); tp->stats.rx_errors++; - if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT)) + if (status & (RxRWT | RxRUNT)) tp->stats.rx_length_errors++; - if (tp->RxDescArray[cur_rx].status & RxCRC) + if (status & RxCRC) tp->stats.rx_crc_errors++; } else { - pkt_size = - (int) (tp->RxDescArray[cur_rx]. - status & 0x00001FFF) - 4; - skb = dev_alloc_skb(pkt_size + 2); - if (skb != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); // 16 byte align the IP fields. // - eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], - pkt_size, 0); - skb_put(skb, pkt_size); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - if (cur_rx == (NUM_RX_DESC - 1)) - tp->RxDescArray[cur_rx].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[cur_rx].status = - OWNbit + RX_BUF_SIZE; - - tp->RxDescArray[cur_rx].buf_addr = - virt_to_bus(tp->RxBufferRing[cur_rx]); - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - } else { - printk(KERN_WARNING - "%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; + struct RxDesc *desc = tp->RxDescArray + cur_rx; + struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; + int pkt_size = (status & 0x00001FFF) - 4; + + pci_dma_sync_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + + if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) { + pci_unmap_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + tp->Rx_skbuff[cur_rx] = NULL; } - } - - cur_rx = (cur_rx + 1) % NUM_RX_DESC; - - } - tp->cur_rx = cur_rx; + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + dev->last_rx = jiffies; + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; + } + + tp->cur_rx++; + cur_rx = tp->cur_rx % NUM_RX_DESC; + } + + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + if (delta > 0) + tp->dirty_rx += delta; + else if (delta < 0) + printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + + /* + * FIXME: until there is periodic timer to try and refill the ring, + * a temporary shortage may definitely kill the Rx process. + * - disable the asic to try and avoid an overflow and kick it again + * after refill ? + * - how do others driver handle this condition (Uh oh...). + */ + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) + printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -991,9 +1493,7 @@ rtl8169_interrupt(int irq, void *dev_ins RTL_W16(IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); - if ((status & - (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK)) == 0) + if (!(status & rtl8169_intr_mask)) break; // Rx interrupt @@ -1023,11 +1523,13 @@ static int rtl8169_close(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; - int i; netif_stop_queue(dev); + rtl8169_delete_timer(dev); + spin_lock_irq(&tp->lock); /* Stop the chip's Tx and Rx DMA processes. */ @@ -1046,16 +1548,15 @@ rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); rtl8169_tx_clear(tp); - kfree(tp->TxDescArrays); - kfree(tp->RxDescArrays); - tp->TxDescArrays = NULL; - tp->RxDescArrays = NULL; + + rtl8169_rx_clear(tp); + + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); tp->TxDescArray = NULL; tp->RxDescArray = NULL; - kfree(tp->RxBufferRings); - for (i = 0; i < NUM_RX_DESC; i++) { - tp->RxBufferRing[i] = NULL; - } return 0; } @@ -1109,11 +1610,26 @@ rtl8169_set_rx_mode(struct net_device *d spin_unlock_irqrestore(&tp->lock, flags); } +/** + * rtl8169_get_stats - Get rtl8169 read/write statistics + * @dev: The Ethernet Device to get statistics for + * + * Get TX/RX statistics for rtl8169 + */ struct net_device_stats * rtl8169_get_stats(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + unsigned long flags; + if (netif_running(dev)) { + spin_lock_irqsave(&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + spin_unlock_irqrestore(&tp->lock, flags); + } + return &tp->stats; } @@ -1122,8 +1638,10 @@ static struct pci_driver rtl8169_pci_dri .id_table = rtl8169_pci_tbl, .probe = rtl8169_init_one, .remove = __devexit_p(rtl8169_remove_one), - .suspend = NULL, - .resume = NULL, +#ifdef CONFIG_PM + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, +#endif }; static int __init --- linux-2.6.1-rc1/drivers/net/saa9730.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/saa9730.c 2003-12-30 22:49:20.000000000 -0800 @@ -996,11 +996,11 @@ static void __devexit saa9730_remove_one struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - + unregister_netdev(dev); + if (dev->priv) kfree(dev->priv); - unregister_netdev(dev); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -1015,17 +1015,10 @@ static int lan_saa9730_init(struct net_d unsigned char ethernet_addr[6]; int ret = 0; - dev = init_etherdev(dev, 0); - - if (!dev) - return -ENOMEM; - dev->open = lan_saa9730_open_fail; - if (get_ethernet_addr(ethernet_addr)) { - ret = -ENODEV; - goto out; - } + if (get_ethernet_addr(ethernet_addr)) + return -ENODEV; memcpy(dev->dev_addr, ethernet_addr, 6); dev->base_addr = ioaddr; @@ -1040,10 +1033,8 @@ static int lan_saa9730_init(struct net_d GFP_DMA | GFP_KERNEL) + 7) & ~7); - if (!lp) { - ret = -ENOMEM; - goto out; - } + if (!lp) + return -ENOMEM; dev->priv = lp; memset(lp, 0, sizeof(*lp)); @@ -1057,6 +1048,7 @@ static int lan_saa9730_init(struct net_d SAA9730_EVM_REGS_ADDR); /* Allocate LAN RX/TX frame buffer space. */ + /* FIXME: a leak */ if ((ret = lan_saa9730_allocate_buffers(lp))) goto out; @@ -1095,63 +1087,70 @@ static int lan_saa9730_init(struct net_d dev->watchdog_timeo = (HZ >> 1); dev->dma = 0; + ret = register_netdev(dev); + if (ret) + goto out; return 0; out: - if (dev) { - if (dev->priv) - kfree(dev->priv); - unregister_netdevice(dev); - free_netdev(dev); - } - + if (dev->priv) + kfree(dev->priv); + free_netdev(dev); return ret; } static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev = NULL; + struct net_device *dev; unsigned int pci_ioaddr; int err; if (lan_saa9730_debug > 1) printk("saa9730.c: PCI bios is present, checking for devices...\n"); + err = -ENOMEM; + dev = alloc_etherdev(0); + if (!dev) + goto out; + + SET_MODULE_OWNER(dev); + err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); - goto out; + goto out1; } err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); - goto out_disable_pdev; + goto out2; } pci_irq_line = pdev->irq; /* LAN base address in located at BAR 1. */ - + pci_ioaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); - + printk("Found SAA9730 (PCI) at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); err = lan_saa9730_init(dev, pci_ioaddr, pci_irq_line); if (err) { printk("Lan init failed"); - goto out_disable_pdev; + goto out2; } - + pci_set_drvdata(pdev, dev); return 0; - out_disable_pdev: +out2: pci_disable_device(pdev); - out: - pci_set_drvdata(pdev, NULL); +out1: + free_netdev(dev); +out: return err; } --- linux-2.6.1-rc1/drivers/net/sb1250-mac.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/sb1250-mac.c 2003-12-30 22:49:20.000000000 -0800 @@ -2372,6 +2372,7 @@ static int sbmac_init(struct net_device unsigned char *eaddr; uint64_t ea_reg; int i; + int err; sc = (struct sbmac_softc *)dev->priv; @@ -2430,7 +2431,6 @@ static int sbmac_init(struct net_device spin_lock_init(&(sc->sbm_lock)); - ether_setup(dev); dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; @@ -2444,8 +2444,11 @@ static int sbmac_init(struct net_device /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); - - return 0; + + err = register_netdev(dev); + if (err) + sbmac_uninitctx(sc); + return err; } @@ -2811,13 +2814,12 @@ sbmac_setup_hwaddr(int chan,char *addr) } #endif -static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0}; +static struct net_device *dev_sbmac[MAX_UNITS]; static int __init sbmac_init_module(void) { int idx; - int macidx = 0; struct net_device *dev; sbmac_port_t port; int chip_max_units; @@ -2884,26 +2886,24 @@ sbmac_init_module(void) * Okay, cool. Initialize this MAC. */ - dev = init_etherdev(NULL,sizeof(struct sbmac_softc)); + dev = alloc_etherdev(sizeof(struct sbmac_softc)); if (!dev) - return -ENOMEM; /* return ENOMEM */ + return -ENOMEM; /* return ENOMEM */ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); dev->irq = K_INT_MAC_0 + idx; dev->base_addr = port; dev->mem_end = 0; - /*dev->init = sbmac_init;*/ - sbmac_init(dev, macidx); - - dev_sbmac[macidx] = dev; - macidx++; + if (sbmac_init(dev, idx)) { + port = A_MAC_CHANNEL_BASE(idx); + SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), + sbmac_orig_hwaddr[idx] ); + free_netdev(dev); + continue; + } + dev_sbmac[idx++] = dev; } - - /* - * Should we care, 'macidx' is the total number of enabled MACs. - */ - return 0; } @@ -2916,21 +2916,12 @@ sbmac_cleanup_module(void) sbmac_port_t port; for (idx = 0; idx < MAX_UNITS; idx++) { dev = dev_sbmac[idx]; - if (dev == NULL) - continue; - if (dev->priv != NULL) { - struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; - + if (!dev) { + struct sbmac_softc *sc = dev->priv; unregister_netdev(dev); - sbmac_uninitctx(sc); - + free_netdev(dev); } - - port = A_MAC_CHANNEL_BASE(idx); - SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), sbmac_orig_hwaddr[idx] ); - free_netdev(dev); - dev_sbmac[idx] = NULL; } } --- linux-2.6.1-rc1/drivers/net/seeq8005.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/net/seeq8005.c 2003-12-30 22:49:20.000000000 -0800 @@ -78,8 +78,6 @@ struct net_local { /* Index to functions, as function prototypes. */ -extern int seeq8005_probe(struct net_device *dev); - static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); @@ -102,22 +100,48 @@ static inline void wait_for_buffer(struc If dev->base_addr == 1, always return failure. */ -int __init -seeq8005_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; - - if (base_addr > 0x1ff) /* Check a single specified location. */ - return seeq8005_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; seeq8005_portlist[i]; i++) - if (seeq8005_probe1(dev, seeq8005_portlist[i]) == 0) - return 0; +static int io = 0x320; +static int irq = 10; - return -ENODEV; +struct net_device * __init seeq8005_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } + + if (io > 0x1ff) { /* Check a single specified location. */ + err = seeq8005_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = seeq8005_portlist; *port; port++) { + if (seeq8005_probe1(dev, *port) == 0) + break; + } + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, SEEQ8005_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /* This is the real probe routine. Linux has a history of friendly device @@ -274,6 +298,7 @@ static int __init seeq8005_probe1(struct /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; + dev->irq = irq; /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) @@ -307,13 +332,6 @@ static int __init seeq8005_probe1(struct } } #endif - - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = seeq8005_open; dev->stop = seeq8005_close; dev->hard_start_xmit = seeq8005_send_packet; @@ -321,10 +339,6 @@ static int __init seeq8005_probe1(struct dev->watchdog_timeo = HZ/20; dev->get_stats = seeq8005_get_stats; dev->set_multicast_list = set_multicast_list; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; return 0; @@ -721,9 +735,7 @@ inline void wait_for_buffer(struct net_d #ifdef MODULE -static struct net_device dev_seeq = { .init = seeq8005_probe }; -static int io = 0x320; -static int irq = 10; +static struct net_device *dev_seeq; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -732,28 +744,17 @@ MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ num int init_module(void) { - dev_seeq.irq=irq; - dev_seeq.base_addr=io; - if (register_netdev(&dev_seeq) != 0) - return -EIO; + dev_seeq = seeq8005_probe(-1); + if (IS_ERR(dev_seeq)) + return PTR_ERR(dev_seeq); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_seeq); - - /* - * Free up the private structure, or leak memory :-) - */ - - kfree(dev_seeq.priv); - dev_seeq.priv = NULL; /* gets re-allocated by el1_probe1 */ - - /* - * If we don't do this, we can't re-insmod it later. - */ - release_region(dev_seeq.base_addr, SEEQ8005_IO_EXTENT); + unregister_netdev(dev_seeq); + release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT); + free_netdev(dev_seeq); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/sgiseeq.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/sgiseeq.c 2003-12-30 22:49:20.000000000 -0800 @@ -600,6 +600,7 @@ int sgiseeq_init(struct hpc3_regs* regs, { struct net_device *dev; struct sgiseeq_private *sp; + int err = -ENOMEM; int i; sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL); @@ -609,19 +610,17 @@ int sgiseeq_init(struct hpc3_regs* regs, return -ENOMEM; } - dev = init_etherdev(NULL, 0); + dev = alloc_etherdev(0); if (!dev) { printk (KERN_ERR "Seeq8003: Could not allocate memory for device.\n"); - free_page((unsigned long) sp); - return -ENOMEM; + goto out; } if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { - printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq); - free_page((unsigned long) sp); - unregister_netdev(dev); - return -EAGAIN; + printk(KERN_ERR "Seeq8003: Can't get irq %d\n", irq); + err = -EAGAIN; + goto out1; } printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); @@ -637,6 +636,8 @@ int sgiseeq_init(struct hpc3_regs* regs, } printk("\n"); + SET_MODULE_OWNER(dev); + dev->priv = sp; #ifdef DEBUG gpriv = sp; @@ -677,12 +678,22 @@ int sgiseeq_init(struct hpc3_regs* regs, dev->set_multicast_list = sgiseeq_set_multicast; dev->irq = irq; dev->dma = 0; - ether_setup(dev); + + err = register_netdev(dev); + if (err) + goto out2; sp->next_module = root_sgiseeq_dev; root_sgiseeq_dev = dev; return 0; +out2: + free_irq(dev->irq, dev); +out1: + free_netdev(dev); +out: + free_page((unsigned long) sp); + return err; } static int __init sgiseeq_probe(void) @@ -701,9 +712,9 @@ static void __exit sgiseeq_exit(void) while (dev) { sp = (struct sgiseeq_private *) dev->priv; next = sp->next_module; + unregister_netdev(dev); free_irq(dev->irq, dev); free_page((unsigned long) sp); - unregister_netdev(dev); free_netdev(dev); dev = next; } --- linux-2.6.1-rc1/drivers/net/shaper.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/shaper.c 2003-12-30 22:49:20.000000000 -0800 @@ -718,8 +718,10 @@ static int __init shaper_init(void) if (!dev) break; - if (register_netdev(dev)) + if (register_netdev(dev)) { + free_netdev(dev); break; + } devs[i] = dev; shapers_registered++; @@ -737,9 +739,12 @@ static void __exit shaper_exit (void) { int i; - for (i = 0; i < shapers_registered; i++) - if (devs[i]) + for (i = 0; i < shapers_registered; i++) { + if (devs[i]) { unregister_netdev(devs[i]); + free_netdev(devs[i]); + } + } kfree(devs); devs = NULL; --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skcsum.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skcsum.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skcsum.h * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) - * Version: $Revision: 1.9 $ - * Date: $Date: 2001/02/06 11:21:39 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/08/20 13:59:57 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -26,6 +26,10 @@ * History: * * $Log: skcsum.h,v $ + * Revision 1.10 2003/08/20 13:59:57 mschmid + * Changed notation of #ifndef SkCsCalculateChecksum to + * #ifndef SK_CS_CALCULATE_CHECKSUM + * * Revision 1.9 2001/02/06 11:21:39 rassmann * Editorial changes. * @@ -226,11 +230,11 @@ typedef struct s_CsPacketInfo { /* function prototypes ********************************************************/ -#ifndef SkCsCalculateChecksum +#ifndef SK_CS_CALCULATE_CHECKSUM extern unsigned SkCsCalculateChecksum( void *pData, unsigned Length); -#endif +#endif /* SK_CS_CALCULATE_CHECKSUM */ extern int SkCsEvent( SK_AC *pAc, --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skdrv1st.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skdrv1st.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,15 +2,16 @@ * * Name: skdrv1st.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.1 $ - * Date: $Date: 2003/07/21 07:22:43 $ + * Version: $Revision: 1.4 $ + * Date: $Date: 2003/11/12 14:28:14 $ * Purpose: First header file for driver and all other modules * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,15 @@ * History: * * $Log: skdrv1st.h,v $ + * Revision 1.4 2003/11/12 14:28:14 rroesler + * Fix: use dedicated ip_fast_csum() on X86_64 systems + * + * Revision 1.3 2003/10/07 08:16:52 mlindner + * Fix: Copyright changes + * + * Revision 1.2 2003/09/29 12:05:59 mlindner + * Fix: Added define SK_CS_CALCULSTE_CHECKSUM + * * Revision 1.1 2003/07/21 07:22:43 rroesler * Fix: Re-Enter after CVS crash * @@ -110,6 +120,9 @@ #ifndef __INC_SKDRV1ST_H #define __INC_SKDRV1ST_H +/* Check kernel version */ +#include + typedef struct s_AC SK_AC; /* Set card versions */ @@ -124,17 +137,15 @@ typedef struct s_AC SK_AC; #define SK_PNMI_READ_U32(p,v) memcpy((char*)&(v),(char*)(p),4) #define SK_PNMI_READ_U64(p,v) memcpy((char*)&(v),(char*)(p),8) -#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff) - #define SK_ADDR_EQUAL(a1,a2) (!memcmp(a1,a2,6)) - #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif +#include #include #include #include @@ -154,6 +165,13 @@ typedef struct s_AC SK_AC; #include #include +#define SK_CS_CALCULATE_CHECKSUM +#ifndef CONFIG_X86_64 +#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff) +#else +#define SkCsCalculateChecksum(p,l) ((~ip_fast_csum(p, l)) & 0xffff) +#endif + #include "h/sktypes.h" #include "h/skerror.h" #include "h/skdebug.h" --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skdrv2nd.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skdrv2nd.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,15 +2,16 @@ * * Name: skdrv2nd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 2003/08/12 16:51:18 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/12/11 16:04:45 $ * Purpose: Second header file for driver and all other modules * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,27 @@ * History: * * $Log: skdrv2nd.h,v $ + * Revision 1.10 2003/12/11 16:04:45 mlindner + * Add: New pnmi data backup structure + * + * Revision 1.9 2003/11/10 09:31:37 rroesler + * Add: pnmiBackup structure for DIAG backup restore + * + * Revision 1.8 2003/10/22 14:18:32 rroesler + * Fix: DIAG handling for DualNet cards + * + * Revision 1.7 2003/10/07 09:34:59 mlindner + * Add: New defines for lower and upper range values (interrupt moderation) + * + * Revision 1.6 2003/10/07 08:16:51 mlindner + * Fix: Copyright changes + * + * Revision 1.5 2003/09/01 13:10:39 rroesler + * Add: Prototypes for DIAG Attach/Detach functions + * + * Revision 1.4 2003/09/01 12:33:38 rroesler + * Add: Defines for optimized DIAG interaction + * * Revision 1.3 2003/08/12 16:51:18 mlindner * Fix: UDP and TCP Proto checks * Fix: UDP header offset @@ -206,6 +228,11 @@ extern int SkPciWriteCfgWord(SK_AC*, in extern int SkPciWriteCfgByte(SK_AC*, int, SK_U8); extern int SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA); +#ifdef SK_DIAG_SUPPORT +extern int SkDrvEnterDiagMode(SK_AC *pAc); +extern int SkDrvLeaveDiagMode(SK_AC *pAc); +#endif + struct s_DrvRlmtMbuf { SK_MBUF *pNext; /* Pointer to next RLMT Mbuf. */ SK_U8 *pData; /* Data buffer (virtually contig.). */ @@ -247,6 +274,7 @@ struct s_DrvRlmtMbuf { #define SK_IOCTL_SETMIB (SK_IOCTL_BASE + 1) #define SK_IOCTL_PRESETMIB (SK_IOCTL_BASE + 2) #define SK_IOCTL_GEN (SK_IOCTL_BASE + 3) +#define SK_IOCTL_DIAG (SK_IOCTL_BASE + 4) typedef struct s_IOCTL SK_GE_IOCTL; @@ -462,6 +490,9 @@ struct s_RxPort { #define C_INTS_PER_SEC_DEFAULT 2000 #define C_INT_MOD_ENABLE_PERCENTAGE 50 /* if higher 50% enable */ #define C_INT_MOD_DISABLE_PERCENTAGE 50 /* if lower 50% disable */ +#define C_INT_MOD_IPS_LOWER_RANGE 30 +#define C_INT_MOD_IPS_UPPER_RANGE 40000 + typedef struct s_DynIrqModInfo DIM_INFO; struct s_DynIrqModInfo { @@ -493,6 +524,11 @@ typedef struct s_PerStrm PER_STRM; #define SK_ALLOC_IRQ 0x00000001 +#ifdef SK_DIAG_SUPPORT +#define DIAG_ACTIVE 1 +#define DIAG_NOTACTIVE 0 +#endif + /**************************************************************************** * Per board structure / Adapter Context structure: * Allocated within attach(9e) and freed within detach(9e). @@ -563,9 +599,18 @@ struct s_AC { int PortUp; int PortDown; int ChipsetType; /* Chipset family type - * 0 == Genesis family support - * 1 == Yukon family support - */ + * 0 == Genesis family support + * 1 == Yukon family support + */ +#ifdef SK_DIAG_SUPPORT + SK_U32 DiagModeActive; /* is diag active? */ + SK_BOOL DiagFlowCtrl; /* for control purposes */ + SK_PNMI_STRUCT_DATA PnmiBackup; /* backup structure for all Pnmi-Data */ + SK_BOOL WasIfUp[SK_MAX_MACS]; /* for OpenClose while + * DIAG is busy with NIC + */ +#endif + }; --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skgehw.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skgehw.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgehw.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.53 $ - * Date: $Date: 2003/07/04 12:39:01 $ + * Version: $Revision: 1.56 $ + * Date: $Date: 2003/09/23 09:01:00 $ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product Family * ******************************************************************************/ @@ -26,6 +26,17 @@ * * History: * $Log: skgehw.h,v $ + * Revision 1.56 2003/09/23 09:01:00 malthoff + * Minor change: Define I2C device size constants as long. + * + * Revision 1.55 2003/09/16 14:03:34 rschmidt + * Added define for YUKON-Lite Rev. A1,A2 Chip Revision + * Moved defines for PHY power down modes to skgeinit.h + * Editorial changes + * + * Revision 1.54 2003/09/16 07:37:58 mschmid + * Added defines for Marvell PHY low power modes + * * Revision 1.53 2003/07/04 12:39:01 rschmidt * Added SK_FAR to pointers in XM_IN32() and GM_IN32() macros (for PXE) * Editorial changes @@ -84,7 +95,7 @@ * Editorial changes * * Revision 1.39 2002/06/10 09:37:07 rschmidt - * Added macros for the ADDR-Modul + * Added macros for the ADDR-Module * * Revision 1.38 2002/06/05 08:15:19 rschmidt * Added defines for WOL Registers @@ -628,12 +639,12 @@ extern "C" { #define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */ #define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */ /* 0x0125 - 0x0127: reserved */ -#define B2_LD_CRTL 0x0128 /* 8 bit EPROM loader control register */ +#define B2_LD_CTRL 0x0128 /* 8 bit EPROM loader control register */ #define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */ /* 0x012a - 0x012f: reserved */ #define B2_TI_INI 0x0130 /* 32 bit Timer Init Value */ #define B2_TI_VAL 0x0134 /* 32 bit Timer Value */ -#define B2_TI_CRTL 0x0138 /* 8 bit Timer Control */ +#define B2_TI_CTRL 0x0138 /* 8 bit Timer Control */ #define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */ /* 0x013a - 0x013f: reserved */ #define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/ @@ -1021,7 +1032,7 @@ extern "C" { /* Bit 7: reserved */ #define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0,..,6f = block 6f */ -/* B0_CTST 16 bit Control/Status register */ +/* B0_CTST 16 bit Control/Status register */ /* Bit 15..14: reserved */ #define CS_CLK_RUN_HOT BIT_13S /* CLK_RUN hot m. (YUKON-Lite only) */ #define CS_CLK_RUN_RST BIT_12S /* CLK_RUN reset (YUKON-Lite only) */ @@ -1038,7 +1049,7 @@ extern "C" { #define CS_RST_CLR BIT_1S /* Clear Software reset */ #define CS_RST_SET BIT_0S /* Set Software reset */ -/* B0_LED 8 Bit LED register */ +/* B0_LED 8 Bit LED register */ /* Bit 7.. 2: reserved */ #define LED_STAT_ON BIT_1S /* Status LED on */ #define LED_STAT_OFF BIT_0S /* Status LED off */ @@ -1053,9 +1064,9 @@ extern "C" { #define PC_VCC_ON BIT_1 /* Switch VCC On */ #define PC_VCC_OFF BIT_0 /* Switch VCC Off */ -/* B0_ISRC 32 bit Interrupt Source Register */ -/* B0_IMSK 32 bit Interrupt Mask Register */ -/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ +/* B0_ISRC 32 bit Interrupt Source Register */ +/* B0_IMSK 32 bit Interrupt Mask Register */ +/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ /* B2_IRQM_MSK 32 bit IRQ Moderation Mask */ #define IS_ALL_MSK 0xbfffffffUL /* All Interrupt bits */ #define IS_HW_ERR BIT_31 /* Interrupt HW Error */ @@ -1099,9 +1110,9 @@ extern "C" { #define IS_XA2_C BIT_0 /* Q_XA2 Encoding Error */ -/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ -/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ -/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ +/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ +/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ +/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ #define IS_ERR_MSK 0x00000fffL /* All Error bits */ /* Bit 31..14: reserved */ #define IS_IRQ_TIST_OV BIT_13 /* Time Stamp Timer Overflow (YUKON only) */ @@ -1119,29 +1130,32 @@ extern "C" { #define IS_R1_PAR_ERR BIT_1 /* Queue R1 Parity Error */ #define IS_R2_PAR_ERR BIT_0 /* Queue R2 Parity Error */ -/* B2_CONN_TYP 8 bit Connector type */ -/* B2_PMD_TYP 8 bit PMD type */ +/* B2_CONN_TYP 8 bit Connector type */ +/* B2_PMD_TYP 8 bit PMD type */ /* Values of connector and PMD type comply to SysKonnect internal std */ -/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */ +/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */ #define CFG_CHIP_R_MSK (0xf<<4) /* Bit 7.. 4: Chip Revision */ /* Bit 3.. 2: reserved */ #define CFG_DIS_M2_CLK BIT_1S /* Disable Clock for 2nd MAC */ #define CFG_SNG_MAC BIT_0S /* MAC Config: 0=2 MACs / 1=1 MAC*/ -/* B2_CHIP_ID 8 bit Chip Identification Number */ +/* B2_CHIP_ID 8 bit Chip Identification Number */ #define CHIP_ID_GENESIS 0x0a /* Chip ID for GENESIS */ #define CHIP_ID_YUKON 0xb0 /* Chip ID for YUKON */ -#define CHIP_ID_YUKON_LITE 0xb1 /* Chip ID for YUKON-Lite (Rev. A1) */ +#define CHIP_ID_YUKON_LITE 0xb1 /* Chip ID for YUKON-Lite (Rev. A1-A3) */ #define CHIP_ID_YUKON_LP 0xb2 /* Chip ID for YUKON-LP */ -/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ +#define CHIP_REV_YU_LITE_A1 3 /* Chip Rev. for YUKON-Lite A1,A2 */ +#define CHIP_REV_YU_LITE_A3 7 /* Chip Rev. for YUKON-Lite A3 */ + +/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ #define FAR_ADDR 0x1ffffL /* Bit 16.. 0: FPROM Address mask */ -/* B2_LD_CRTL 8 bit EPROM loader control register */ +/* B2_LD_CTRL 8 bit EPROM loader control register */ /* Bits are currently reserved */ -/* B2_LD_TEST 8 bit EPROM loader test register */ +/* B2_LD_TEST 8 bit EPROM loader test register */ /* Bit 7.. 4: reserved */ #define LD_T_ON BIT_3S /* Loader Test mode on */ #define LD_T_OFF BIT_2S /* Loader Test mode off */ @@ -1151,16 +1165,16 @@ extern "C" { /* * Timer Section */ -/* B2_TI_CRTL 8 bit Timer control */ +/* B2_TI_CTRL 8 bit Timer control */ /* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ /* Bit 7.. 3: reserved */ #define TIM_START BIT_2S /* Start Timer */ #define TIM_STOP BIT_1S /* Stop Timer */ #define TIM_CLR_IRQ BIT_0S /* Clear Timer IRQ (!IRQM) */ -/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_TI_TEST 8 Bit Timer Test */ /* B2_IRQM_TEST 8 bit IRQ Moderation Timer Test */ -/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ +/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ /* Bit 7.. 3: reserved */ #define TIM_T_ON BIT_2S /* Test mode on */ #define TIM_T_OFF BIT_1S /* Test mode off */ @@ -1197,7 +1211,7 @@ extern "C" { #define TST_FRC_APERR_1M64 BIT_1S /* AddrPERR on 1. phase */ #define TST_FRC_APERR_2M64 BIT_0S /* AddrPERR on 2. phase */ -/* B2_GP_IO 32 bit General Purpose I/O Register */ +/* B2_GP_IO 32 bit General Purpose I/O Register */ /* Bit 31..26: reserved */ #define GP_DIR_9 BIT_25 /* IO_9 direct, 0=In/1=Out */ #define GP_DIR_8 BIT_24 /* IO_8 direct, 0=In/1=Out */ @@ -1221,28 +1235,28 @@ extern "C" { #define GP_IO_1 BIT_1 /* IO_1 pin */ #define GP_IO_0 BIT_0 /* IO_0 pin */ -/* B2_I2C_CTRL 32 bit I2C HW Control Register */ +/* B2_I2C_CTRL 32 bit I2C HW Control Register */ #define I2C_FLAG BIT_31 /* Start read/write if WR */ #define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be RD/WR */ #define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */ /* Bit 8.. 5: reserved */ #define I2C_BURST_LEN BIT_4 /* Burst Len, 1/4 bytes */ -#define I2C_DEV_SIZE (7L<<1) /* Bit 3.. 1: I2C Device Size */ -#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smal. */ -#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ -#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ -#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ -#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ -#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ -#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ -#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ +#define I2C_DEV_SIZE (7<<1) /* Bit 3.. 1: I2C Device Size */ +#define I2C_025K_DEV (0<<1) /* 0: 256 Bytes or smal. */ +#define I2C_05K_DEV (1<<1) /* 1: 512 Bytes */ +#define I2C_1K_DEV (2<<1) /* 2: 1024 Bytes */ +#define I2C_2K_DEV (3<<1) /* 3: 2048 Bytes */ +#define I2C_4K_DEV (4<<1) /* 4: 4096 Bytes */ +#define I2C_8K_DEV (5<<1) /* 5: 8192 Bytes */ +#define I2C_16K_DEV (6<<1) /* 6: 16384 Bytes */ +#define I2C_32K_DEV (7<<1) /* 7: 32768 Bytes */ #define I2C_STOP BIT_0 /* Interrupt I2C transfer */ -/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ +/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ /* Bit 31.. 1 reserved */ #define I2C_CLR_IRQ BIT_0 /* Clear I2C IRQ */ -/* B2_I2C_SW 32 bit (8 bit access) I2C HW SW Port Register */ +/* B2_I2C_SW 32 bit (8 bit access) I2C HW SW Port Register */ /* Bit 7.. 3: reserved */ #define I2C_DATA_DIR BIT_2S /* direction of I2C_DATA */ #define I2C_DATA BIT_1S /* I2C Data Port */ @@ -1254,27 +1268,27 @@ extern "C" { #define I2C_SENS_ADDR LM80_ADDR /* I2C Sensor Address, (Volt and Temp)*/ -/* B2_BSC_CTRL 8 bit Blink Source Counter Control */ +/* B2_BSC_CTRL 8 bit Blink Source Counter Control */ /* Bit 7.. 2: reserved */ #define BSC_START BIT_1S /* Start Blink Source Counter */ #define BSC_STOP BIT_0S /* Stop Blink Source Counter */ -/* B2_BSC_STAT 8 bit Blink Source Counter Status */ +/* B2_BSC_STAT 8 bit Blink Source Counter Status */ /* Bit 7.. 1: reserved */ #define BSC_SRC BIT_0S /* Blink Source, 0=Off / 1=On */ -/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ +/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ #define BSC_T_ON BIT_2S /* Test mode on */ #define BSC_T_OFF BIT_1S /* Test mode off */ #define BSC_T_STEP BIT_0S /* Test step */ -/* B3_RAM_ADDR 32 bit RAM Address, to read or write */ +/* B3_RAM_ADDR 32 bit RAM Address, to read or write */ /* Bit 31..19: reserved */ #define RAM_ADR_RAN 0x0007ffffL /* Bit 18.. 0: RAM Address Range */ /* RAM Interface Registers */ -/* B3_RI_CTRL 16 bit RAM Iface Control Register */ +/* B3_RI_CTRL 16 bit RAM Iface Control Register */ /* Bit 15..10: reserved */ #define RI_CLR_RD_PERR BIT_9S /* Clear IRQ RAM Read Parity Err */ #define RI_CLR_WR_PERR BIT_8S /* Clear IRQ RAM Write Parity Err*/ @@ -1282,7 +1296,7 @@ extern "C" { #define RI_RST_CLR BIT_1S /* Clear RAM Interface Reset */ #define RI_RST_SET BIT_0S /* Set RAM Interface Reset */ -/* B3_RI_TEST 8 bit RAM Iface Test Register */ +/* B3_RI_TEST 8 bit RAM Iface Test Register */ /* Bit 15.. 4: reserved */ #define RI_T_EV BIT_3S /* Timeout Event occured */ #define RI_T_ON BIT_2S /* Timeout Timer Test On */ @@ -1309,7 +1323,7 @@ extern "C" { #define MA_DIS_REC_RX1 BIT_0S /* Disable Recovery Timer RX1 */ /* Packet Arbiter Registers */ -/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ +/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ /* Bit 15..14: reserved */ #define PA_CLR_TO_TX2 BIT_13S /* Clear IRQ Packet Timeout TX2 */ #define PA_CLR_TO_TX1 BIT_12S /* Clear IRQ Packet Timeout TX1 */ @@ -1332,7 +1346,7 @@ extern "C" { /* Rx/Tx Path related Arbiter Test Registers */ /* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ /* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ -/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ +/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ /* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ #define TX2_T_EV BIT_15S /* TX2 Timeout/Recv Event occured */ #define TX2_T_ON BIT_14S /* TX2 Timeout/Recv Timer Test On */ @@ -1353,14 +1367,14 @@ extern "C" { /* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ -/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ -/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ -/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ -/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ +/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ +/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ +/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ +/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ /* Bit 31..24: reserved */ #define TXA_MAX_VAL 0x00ffffffUL/* Bit 23.. 0: Max TXA Timer/Cnt Val */ -/* TXA_CTRL 8 bit Tx Arbiter Control Register */ +/* TXA_CTRL 8 bit Tx Arbiter Control Register */ #define TXA_ENA_FSYNC BIT_7S /* Enable force of sync Tx queue */ #define TXA_DIS_FSYNC BIT_6S /* Disable force of sync Tx queue */ #define TXA_ENA_ALLOC BIT_5S /* Enable alloc of free bandwidth */ @@ -1370,7 +1384,7 @@ extern "C" { #define TXA_ENA_ARB BIT_1S /* Enable Tx Arbiter */ #define TXA_DIS_ARB BIT_0S /* Disable Tx Arbiter */ -/* TXA_TEST 8 bit Tx Arbiter Test Register */ +/* TXA_TEST 8 bit Tx Arbiter Test Register */ /* Bit 7.. 6: reserved */ #define TXA_INT_T_ON BIT_5S /* Tx Arb Interval Timer Test On */ #define TXA_INT_T_OFF BIT_4S /* Tx Arb Interval Timer Test Off */ @@ -1379,22 +1393,22 @@ extern "C" { #define TXA_LIM_T_OFF BIT_1S /* Tx Arb Limit Timer Test Off */ #define TXA_LIM_T_STEP BIT_0S /* Tx Arb Limit Timer Step */ -/* TXA_STAT 8 bit Tx Arbiter Status Register */ +/* TXA_STAT 8 bit Tx Arbiter Status Register */ /* Bit 7.. 1: reserved */ #define TXA_PRIO_XS BIT_0S /* sync queue has prio to send */ -/* Q_BC 32 bit Current Byte Counter */ +/* Q_BC 32 bit Current Byte Counter */ /* Bit 31..16: reserved */ #define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */ /* BMU Control Status Registers */ -/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ -/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */ -/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ -/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */ -/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ -/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ -/* Q_CSR 32 bit BMU Control/Status Register */ +/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ +/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */ +/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */ +/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ +/* Q_CSR 32 bit BMU Control/Status Register */ /* Bit 31..25: reserved */ #define CSR_SV_IDLE BIT_24 /* BMU SM Idle */ /* Bit 23..22: reserved */ @@ -1428,7 +1442,7 @@ extern "C" { CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\ CSR_TRANS_RUN) -/* Q_F 32 bit Flag Register */ +/* Q_F 32 bit Flag Register */ /* Bit 31..28: reserved */ #define F_ALM_FULL BIT_27 /* Rx FIFO: almost full */ #define F_EMPTY BIT_27 /* Tx FIFO: empty flag */ @@ -1439,17 +1453,17 @@ extern "C" { /* Bit 15..11: reserved */ #define F_WATER_MARK 0x0007ffL /* Bit 10.. 0: Watermark */ -/* Q_T1 32 bit Test Register 1 */ +/* Q_T1 32 bit Test Register 1 */ /* Holds four State Machine control Bytes */ -#define SM_CRTL_SV_MSK (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ -#define SM_CRTL_RD_MSK (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ -#define SM_CRTL_WR_MSK (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */ -#define SM_CRTL_TR_MSK 0xffL /* Bit 7.. 0: Control Transfer SM */ - -/* Q_T1_TR 8 bit Test Register 1 Transfer SM */ -/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */ -/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */ -/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */ +#define SM_CTRL_SV_MSK (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ +#define SM_CTRL_RD_MSK (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ +#define SM_CTRL_WR_MSK (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */ +#define SM_CTRL_TR_MSK 0xffL /* Bit 7.. 0: Control Transfer SM */ + +/* Q_T1_TR 8 bit Test Register 1 Transfer SM */ +/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */ +/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */ +/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */ /* The control status byte of each machine looks like ... */ #define SM_STATE 0xf0 /* Bit 7.. 4: State which shall be loaded */ @@ -1459,7 +1473,7 @@ extern "C" { #define SM_STEP BIT_0S /* Step the State Machine */ /* The encoding of the states is not supported by the Diagnostics Tool */ -/* Q_T2 32 bit Test Register 2 */ +/* Q_T2 32 bit Test Register 2 */ /* Bit 31.. 8: reserved */ #define T2_AC_T_ON BIT_7 /* Address Counter Test Mode on */ #define T2_AC_T_OFF BIT_6 /* Address Counter Test Mode off */ @@ -1470,23 +1484,23 @@ extern "C" { #define T2_STEP02 BIT_1 /* Inc AC/Dec BC by 2 */ #define T2_STEP01 BIT_0 /* Inc AC/Dec BC by 1 */ -/* Q_T3 32 bit Test Register 3 */ +/* Q_T3 32 bit Test Register 3 */ /* Bit 31.. 7: reserved */ #define T3_MUX_MSK (7<<4) /* Bit 6.. 4: Mux Position */ /* Bit 3: reserved */ #define T3_VRAM_MSK 7 /* Bit 2.. 0: Virtual RAM Buffer Address */ /* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */ -/* RB_START 32 bit RAM Buffer Start Address */ -/* RB_END 32 bit RAM Buffer End Address */ -/* RB_WP 32 bit RAM Buffer Write Pointer */ -/* RB_RP 32 bit RAM Buffer Read Pointer */ -/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */ -/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pause Pack */ -/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */ -/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */ -/* RB_PC 32 bit RAM Buffer Packet Counter */ -/* RB_LEV 32 bit RAM Buffer Level Register */ +/* RB_START 32 bit RAM Buffer Start Address */ +/* RB_END 32 bit RAM Buffer End Address */ +/* RB_WP 32 bit RAM Buffer Write Pointer */ +/* RB_RP 32 bit RAM Buffer Read Pointer */ +/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */ +/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pause Pack */ +/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */ +/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */ +/* RB_PC 32 bit RAM Buffer Packet Counter */ +/* RB_LEV 32 bit RAM Buffer Level Register */ /* Bit 31..19: reserved */ #define RB_MSK 0x0007ffff /* Bit 18.. 0: RAM Buffer Pointer Bits */ @@ -1519,17 +1533,17 @@ extern "C" { /* Receive and Transmit MAC FIFO Registers (GENESIS only) */ -/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */ -/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */ -/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */ -/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter */ -/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */ -/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */ -/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer */ -/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pointer */ -/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ -/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ -/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ +/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */ +/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */ +/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */ +/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter */ +/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */ +/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */ +/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer */ +/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pointer */ +/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ +/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ +/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ /* Bit 31.. 6: reserved */ #define MFF_MSK 0x007fL /* Bit 5.. 0: MAC FIFO Address/Ptr Bits */ @@ -1682,7 +1696,7 @@ extern "C" { #define RX_GMF_FL_THR_DEF 0x0a /* Rx GMAC FIFO Flush Threshold default */ -/* GMAC_TI_ST_CTRL 8 bit Time Stamp Timer Ctrl Reg (YUKON only) */ +/* GMAC_TI_ST_CTRL 8 bit Time Stamp Timer Ctrl Reg (YUKON only) */ /* Bit 7.. 3: reserved */ #define GMT_ST_START BIT_2S /* Start Time Stamp Timer */ #define GMT_ST_STOP BIT_1S /* Stop Time Stamp Timer */ @@ -1766,13 +1780,13 @@ extern "C" { #define GMAC_DEF_MSK (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \ GM_IS_TX_FF_UR) -/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ +/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ /* Bits 15.. 2: reserved */ #define GMLC_RST_CLR BIT_1S /* Clear GMAC Link Reset */ #define GMLC_RST_SET BIT_0S /* Set GMAC Link Reset */ -/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ +/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ #define WOL_CTL_LINK_CHG_OCC BIT_15S #define WOL_CTL_MAGIC_PKT_OCC BIT_14S #define WOL_CTL_PATTERN_OCC BIT_13S @@ -1801,7 +1815,7 @@ extern "C" { WOL_CTL_DIS_PATTERN_UNIT | \ WOL_CTL_DIS_MAGIC_PKT_UNIT) -/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ +/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ #define WOL_CTL_PATT_ENA(x) (BIT_0 << (x)) #define SK_NUM_WOL_PATTERN 7 --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skgehwt.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skgehwt.h 2003-12-30 22:49:20.000000000 -0800 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skhwt.h - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.6 $ - * Date: $Date: 2003/05/13 17:57:48 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.7 $ + * Date: $Date: 2003/09/16 12:55:08 $ * Purpose: Defines for the hardware timer functions * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skgehwt.h,v $ + * Revision 1.7 2003/09/16 12:55:08 rschmidt + * Editorial changes + * * Revision 1.6 2003/05/13 17:57:48 mkarl * Editorial changes. * @@ -34,7 +37,7 @@ * Changed license header to GPL. * * Revision 1.4 1998/08/19 09:50:58 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs + * fix: remove struct keyword from C-code (see CCC) add typedefs * * Revision 1.3 1998/08/14 07:09:29 gklug * fix: chg pAc -> pAC @@ -44,10 +47,6 @@ * * Revision 1.1 1998/08/07 09:32:58 gklug * first version - * - * - * - * * ******************************************************************************/ @@ -64,14 +63,14 @@ * - use in Adapters context name pAC->Hwt */ typedef struct s_Hwt { - SK_U32 TStart ; /* HWT start */ - SK_U32 TStop ; /* HWT stop */ - int TActive ; /* HWT: flag : active/inactive */ + SK_U32 TStart; /* HWT start */ + SK_U32 TStop; /* HWT stop */ + int TActive; /* HWT: flag : active/inactive */ } SK_HWT; extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc); extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time); extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc); -extern SK_U32 SkHwtRead(SK_AC *pAC,SK_IOC Ioc); +extern SK_U32 SkHwtRead(SK_AC *pAC, SK_IOC Ioc); extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc); #endif /* _SKGEHWT_H_ */ --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skgei2c.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skgei2c.h 2003-12-30 22:49:20.000000000 -0800 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: skgei2c.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.23 $ - * Date: $Date: 2002/12/19 14:34:27 $ - * Purpose: Special GEnesis defines for TWSI + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.25 $ + * Date: $Date: 2003/10/20 09:06:05 $ + * Purpose: Special defines for TWSI * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,12 @@ * History: * * $Log: skgei2c.h,v $ + * Revision 1.25 2003/10/20 09:06:05 rschmidt + * Editorial changes. + * + * Revision 1.24 2003/09/23 09:31:15 malthoff + * Parameter dev_size added to macro definition of SK_I2C_CTL. + * * Revision 1.23 2002/12/19 14:34:27 rschmidt * Added cast in macros SK_I2C_SET_BIT() and SK_I2C_CLR_BIT() * Editorial changes (TWSI) @@ -107,8 +114,6 @@ * Revision 1.1 1998/07/17 11:27:56 gklug * Created. * - * - * ******************************************************************************/ /* @@ -121,12 +126,13 @@ /* * Macros to access the B2_I2C_CTRL */ -#define SK_I2C_CTL(IoC, flag, dev, reg, burst) \ +#define SK_I2C_CTL(IoC, flag, dev, dev_size, reg, burst) \ SK_OUT32(IoC, B2_I2C_CTRL,\ (flag ? 0x80000000UL : 0x0L) | \ - (((SK_U32) reg << 16) & I2C_ADDR) | \ - (((SK_U32) dev << 9) & I2C_DEV_SEL) | \ - (( burst << 4) & I2C_BURST_LEN)) + (((SK_U32)reg << 16) & I2C_ADDR) | \ + (((SK_U32)dev << 9) & I2C_DEV_SEL) | \ + (dev_size & I2C_DEV_SIZE) | \ + ((burst << 4) & I2C_BURST_LEN)) #define SK_I2C_STOP(IoC) { \ SK_U32 I2cCtrl; \ @@ -166,42 +172,42 @@ */ #define SK_LM80_VT_LSB 22 /* 22mV LSB resolution */ #define SK_LM80_TEMP_LSB 10 /* 1 degree LSB resolution */ -#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for the - * extension value - */ -#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2)) -/* formula: counter = (22500*60)/(rpm * divisor * pulses/2) +#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for ext. val. */ + +/* + * formula: counter = (22500*60)/(rpm * divisor * pulses/2) * assuming: 6500rpm, 4 pulses, divisor 1 */ +#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2)) /* * Define sensor management data - * Maximum is reached on copperfield with dual Broadcom. + * Maximum is reached on Genesis copper dual port and Yukon-64 * Board specific maximum is in pAC->I2c.MaxSens */ #define SK_MAX_SENSORS 8 /* maximal no. of installed sensors */ #define SK_MIN_SENSORS 5 /* minimal no. of installed sensors */ /* - * To watch the statemachine (JS) use the timer in two ways instead of one as hitherto + * To watch the state machine (SM) use the timer in two ways + * instead of one as hitherto */ -#define SK_TIMER_WATCH_STATEMACHINE 0 /* Watch the statemachine to finish in a specific time */ -#define SK_TIMER_NEW_GAUGING 1 /* Start a new gauging when timer expires */ - +#define SK_TIMER_WATCH_SM 0 /* Watch the SM to finish in a spec. time */ +#define SK_TIMER_NEW_GAUGING 1 /* Start a new gauging when timer expires */ /* - * Defines for the individual Thresholds + * Defines for the individual thresholds */ /* Temperature sensor */ -#define SK_SEN_TEMP_HIGH_ERR 800 /* Temperature High Err Threshold */ +#define SK_SEN_TEMP_HIGH_ERR 800 /* Temperature High Err Threshold */ #define SK_SEN_TEMP_HIGH_WARN 700 /* Temperature High Warn Threshold */ #define SK_SEN_TEMP_LOW_WARN 100 /* Temperature Low Warn Threshold */ -#define SK_SEN_TEMP_LOW_ERR 0 /* Temperature Low Err Threshold */ +#define SK_SEN_TEMP_LOW_ERR 0 /* Temperature Low Err Threshold */ /* VCC which should be 5 V */ -#define SK_SEN_PCI_5V_HIGH_ERR 5588 /* Voltage PCI High Err Threshold */ -#define SK_SEN_PCI_5V_HIGH_WARN 5346 /* Voltage PCI High Warn Threshold */ +#define SK_SEN_PCI_5V_HIGH_ERR 5588 /* Voltage PCI High Err Threshold */ +#define SK_SEN_PCI_5V_HIGH_WARN 5346 /* Voltage PCI High Warn Threshold */ #define SK_SEN_PCI_5V_LOW_WARN 4664 /* Voltage PCI Low Warn Threshold */ #define SK_SEN_PCI_5V_LOW_ERR 4422 /* Voltage PCI Low Err Threshold */ @@ -229,17 +235,16 @@ #define SK_SEN_PCI_IO_3V3_HIGH_ERR 3850 /* + 15% V PCI-IO High Err Threshold */ #define SK_SEN_PCI_IO_3V3_HIGH_WARN 3674 /* + 10% V PCI-IO High Warn Threshold */ /* 3300 mVolt */ -#define SK_SEN_PCI_IO_3V3_LOW_WARN 2926 /* - 10% V PCI-IO Low Warn Threshold */ -#define SK_SEN_PCI_IO_3V3_LOW_ERR 2772 /* - 15% V PCI-IO Low Err Threshold */ - +#define SK_SEN_PCI_IO_3V3_LOW_WARN 2926 /* - 10% V PCI-IO Low Warn Threshold */ +#define SK_SEN_PCI_IO_3V3_LOW_ERR 2772 /* - 15% V PCI-IO Low Err Threshold */ /* * VDD voltage */ -#define SK_SEN_VDD_HIGH_ERR 3630 /* Voltage ASIC High Err Threshold */ -#define SK_SEN_VDD_HIGH_WARN 3476 /* Voltage ASIC High Warn Threshold */ -#define SK_SEN_VDD_LOW_WARN 3146 /* Voltage ASIC Low Warn Threshold */ -#define SK_SEN_VDD_LOW_ERR 2970 /* Voltage ASIC Low Err Threshold */ +#define SK_SEN_VDD_HIGH_ERR 3630 /* Voltage ASIC High Err Threshold */ +#define SK_SEN_VDD_HIGH_WARN 3476 /* Voltage ASIC High Warn Threshold */ +#define SK_SEN_VDD_LOW_WARN 3146 /* Voltage ASIC Low Warn Threshold */ +#define SK_SEN_VDD_LOW_ERR 2970 /* Voltage ASIC Low Err Threshold */ /* * PHY PLL 3V3 voltage @@ -255,8 +260,8 @@ #define SK_SEN_VAUX_3V3_HIGH_ERR 3630 /* Voltage VAUX High Err Threshold */ #define SK_SEN_VAUX_3V3_HIGH_WARN 3476 /* Voltage VAUX High Warn Threshold */ #define SK_SEN_VAUX_3V3_LOW_WARN 3146 /* Voltage VAUX Low Warn Threshold */ -#define SK_SEN_VAUX_3V3_LOW_ERR 2970 /* Voltage VAUX Low Err Threshold */ -#define SK_SEN_VAUX_0V_WARN_ERR 0 /* if VAUX not present */ +#define SK_SEN_VAUX_3V3_LOW_ERR 2970 /* Voltage VAUX Low Err Threshold */ +#define SK_SEN_VAUX_0V_WARN_ERR 0 /* if VAUX not present */ #define SK_SEN_VAUX_RANGE_LIMITER 1000 /* 1000 mV range delimiter */ /* @@ -270,7 +275,7 @@ /* * ASIC Core 1V5 voltage (YUKON only) */ -#define SK_SEN_CORE_1V5_HIGH_ERR 1650 /* Voltage ASIC Core High Err Threshold */ +#define SK_SEN_CORE_1V5_HIGH_ERR 1650 /* Voltage ASIC Core High Err Threshold */ #define SK_SEN_CORE_1V5_HIGH_WARN 1575 /* Voltage ASIC Core High Warn Threshold */ #define SK_SEN_CORE_1V5_LOW_WARN 1425 /* Voltage ASIC Core Low Warn Threshold */ #define SK_SEN_CORE_1V5_LOW_ERR 1350 /* Voltage ASIC Core Low Err Threshold */ @@ -285,8 +290,8 @@ */ #define SK_SEN_FAN_HIGH_ERR 20000 /* FAN Speed High Err Threshold */ #define SK_SEN_FAN_HIGH_WARN 20000 /* FAN Speed High Warn Threshold */ -#define SK_SEN_FAN_LOW_WARN 5200 /* FAN Speed Low Warn Threshold */ -#define SK_SEN_FAN_LOW_ERR 4550 /* FAN Speed Low Err Threshold */ +#define SK_SEN_FAN_LOW_WARN 5200 /* FAN Speed Low Warn Threshold */ +#define SK_SEN_FAN_LOW_ERR 4550 /* FAN Speed Low Err Threshold */ /* * Some Voltages need dynamic thresholds --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skgeinit.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skgeinit.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgeinit.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.81 $ - * Date: $Date: 2003/07/04 12:30:38 $ + * Version: $Revision: 1.83 $ + * Date: $Date: 2003/09/16 14:07:37 $ * Purpose: Structures and prototypes for the GE Init Module * ******************************************************************************/ @@ -27,6 +27,23 @@ * History: * * $Log: skgeinit.h,v $ + * Revision 1.83 2003/09/16 14:07:37 rschmidt + * Moved defines for PHY power down modes from skgehw.h + * Added prototypes for SkMacClearRst() + * Editorial changes + * + * Revision 1.82 2003/09/16 07:18:36 mschmid + * Added members to port structure for MAC control + * - PMacColThres + * - PMacJamLen + * - PMacJamIpgVal + * - PMacJamIpgData + * - PMacIpgData + * - PMacLimit4 + * Added PHY power state to port structure + * - PPhyPowerState + * Added function prototypes to enter and leave low power modes + * * Revision 1.81 2003/07/04 12:30:38 rschmidt * Added SK_FAR to pointers in MAC statistic functions (for PXE) * Editorial changes @@ -594,6 +611,13 @@ extern "C" { #define SK_PRT_INIT 2 /* the port is initialized */ #define SK_PRT_RUN 3 /* the port has an active link */ +/* PHY power down modes */ +#define PHY_PM_OPERATIONAL_MODE 0 /* PHY operational mode */ +#define PHY_PM_DEEP_SLEEP 1 /* coma mode --> minimal power */ +#define PHY_PM_IEEE_POWER_DOWN 2 /* IEEE 22.2.4.1.5 compl. power down */ +#define PHY_PM_ENERGY_DETECT 3 /* energy detect */ +#define PHY_PM_ENERGY_DETECT_PLUS 4 /* energy detect plus */ + /* Default receive frame limit for Workaround of XMAC Errata */ #define SK_DEF_RX_WA_LIM SK_CONSTU64(100) @@ -685,6 +709,13 @@ typedef struct s_GePort { SK_U8 PCableLen; /* Cable Length */ SK_U8 PMdiPairLen[4]; /* MDI[0..3] Pair Length */ SK_U8 PMdiPairSts[4]; /* MDI[0..3] Pair Diagnostic Status */ + SK_U8 PPhyPowerState; /* PHY current power state */ + int PMacColThres; /* MAC Collision Threshold */ + int PMacJamLen; /* MAC Jam length */ + int PMacJamIpgVal; /* MAC Jam IPG */ + int PMacJamIpgData; /* MAC IPG Jam to Data */ + int PMacIpgData; /* MAC Data IPG */ + SK_BOOL PMacLimit4; /* reset collision counter and backoff algorithm */ } SK_GEPORT; /* @@ -865,6 +896,11 @@ extern void SkMacHardRst( SK_IOC IoC, int Port); +extern void SkMacClearRst( + SK_AC *pAC, + SK_IOC IoC, + int Port); + extern void SkXmInitMac( SK_AC *pAC, SK_IOC IoC, @@ -1040,6 +1076,17 @@ extern int SkGmCableDiagStatus( int Port, SK_BOOL StartTest); +extern int SkGmEnterLowPowerMode( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_U8 Mode); + +extern int SkGmLeaveLowPowerMode( + SK_AC *pAC, + SK_IOC IoC, + int Port); + #ifdef SK_DIAG extern void SkGePhyRead( SK_AC *pAC, @@ -1101,6 +1148,7 @@ extern int SkGeInitAssignRamToQueues(); extern void SkMacRxTxDisable(); extern void SkMacSoftRst(); extern void SkMacHardRst(); +extern void SkMacClearRst(); extern void SkMacInitPhy(); extern int SkMacRxTxEnable(); extern void SkMacPromiscMode(); @@ -1131,6 +1179,8 @@ extern int SkGmResetCounter(); extern int SkXmOverflowStatus(); extern int SkGmOverflowStatus(); extern int SkGmCableDiagStatus(); +extern int SkGmEnterLowPowerMode(); +extern int SkGmLeaveLowPowerMode(); #ifdef SK_DIAG extern void SkGePhyRead(); --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skgepnmi.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skgepnmi.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgepnmi.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.61 $ - * Date: $Date: 2003/05/23 12:53:52 $ + * Version: $Revision: 1.62 $ + * Date: $Date: 2003/08/15 12:31:52 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ @@ -27,6 +27,18 @@ * History: * * $Log: skgepnmi.h,v $ + * Revision 1.62 2003/08/15 12:31:52 tschilli + * Added new OIDs: + * OID_SKGE_DRIVER_RELDATE + * OID_SKGE_DRIVER_FILENAME + * OID_SKGE_CHIPID + * OID_SKGE_RAMSIZE + * OID_SKGE_VAUXAVAIL + * OID_SKGE_PHY_TYPE + * OID_SKGE_PHY_LP_MODE + * + * Added new define SK_DIAG_ATTACHED for OID_SKGE_DIAG_MODE handling. + * * Revision 1.61 2003/05/23 12:53:52 tschilli * Generic PNMI IOCTL subcommands added. * Function prototype SkPnmiGenIoctl() added. @@ -568,15 +580,23 @@ #define OID_SKGE_ALL_DATA 0xFF020190 /* Defines for VCT. */ -#define OID_SKGE_VCT_GET 0xFF020200 -#define OID_SKGE_VCT_SET 0xFF020201 -#define OID_SKGE_VCT_STATUS 0xFF020202 +#define OID_SKGE_VCT_GET 0xFF020200 +#define OID_SKGE_VCT_SET 0xFF020201 +#define OID_SKGE_VCT_STATUS 0xFF020202 #ifdef SK_DIAG_SUPPORT /* Defines for driver DIAG mode. */ -#define OID_SKGE_DIAG_MODE 0xFF020204 +#define OID_SKGE_DIAG_MODE 0xFF020204 #endif /* SK_DIAG_SUPPORT */ +/* New OIDs */ +#define OID_SKGE_DRIVER_RELDATE 0xFF020210 +#define OID_SKGE_DRIVER_FILENAME 0xFF020211 +#define OID_SKGE_CHIPID 0xFF020212 +#define OID_SKGE_RAMSIZE 0xFF020213 +#define OID_SKGE_VAUXAVAIL 0xFF020214 +#define OID_SKGE_PHY_TYPE 0xFF020215 +#define OID_SKGE_PHY_LP_MODE 0xFF020216 /* VCT struct to store a backup copy of VCT data after a port reset. */ typedef struct s_PnmiVct { @@ -613,6 +633,12 @@ typedef struct s_PnmiVct { #define OID_SKGE_TRAP_RLMT_PORT_UP 523 #define OID_SKGE_TRAP_RLMT_SEGMENTATION 524 +#ifdef SK_DIAG_SUPPORT +/* Defines for driver DIAG mode. */ +#define SK_DIAG_ATTACHED 2 +#define SK_DIAG_RUNNING 1 +#define SK_DIAG_IDLE 0 +#endif /* SK_DIAG_SUPPORT */ /* * Generic PNMI IOCTL subcommand definitions. @@ -730,6 +756,14 @@ typedef struct s_PnmiVct { #define SK_PNMI_ERR051MSG "SkPnmiEvent: Port switch suspicious" #define SK_PNMI_ERR052 (SK_ERRBASE_PNMI + 52) #define SK_PNMI_ERR052MSG "" +#define SK_PNMI_ERR053 (SK_ERRBASE_PNMI + 53) +#define SK_PNMI_ERR053MSG "General: Driver release date not initialized" +#define SK_PNMI_ERR054 (SK_ERRBASE_PNMI + 54) +#define SK_PNMI_ERR054MSG "General: Driver release date string too long" +#define SK_PNMI_ERR055 (SK_ERRBASE_PNMI + 55) +#define SK_PNMI_ERR055MSG "General: Driver file name not initialized" +#define SK_PNMI_ERR056 (SK_ERRBASE_PNMI + 56) +#define SK_PNMI_ERR056MSG "General: Driver file name string too long" /* * Management counter macros called by the driver @@ -740,6 +774,11 @@ typedef struct s_PnmiVct { #define SK_PNMI_SET_DRIVER_VER(pAC,v) ((pAC)->Pnmi.pDriverVersion = \ (char *)(v)) +#define SK_PNMI_SET_DRIVER_RELDATE(pAC,v) ((pAC)->Pnmi.pDriverReleaseDate = \ + (char *)(v)) + +#define SK_PNMI_SET_DRIVER_FILENAME(pAC,v) ((pAC)->Pnmi.pDriverFileName = \ + (char *)(v)) #define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \ { \ @@ -916,6 +955,8 @@ typedef struct s_PnmiConf { char ConfMacFactoryAddr[6]; SK_U8 ConfPMD; SK_U8 ConfConnector; + SK_U32 ConfPhyType; + SK_U32 ConfPhyMode; SK_U8 ConfLinkCapability; SK_U8 ConfLinkMode; SK_U8 ConfLinkModeStatus; @@ -964,9 +1005,14 @@ typedef struct s_PnmiStrucData { SK_U32 DeviceType; char DriverDescr[SK_PNMI_STRINGLEN1]; char DriverVersion[SK_PNMI_STRINGLEN2]; + char DriverReleaseDate[SK_PNMI_STRINGLEN1]; + char DriverFileName[SK_PNMI_STRINGLEN1]; char HwDescr[SK_PNMI_STRINGLEN1]; char HwVersion[SK_PNMI_STRINGLEN2]; SK_U16 Chipset; + SK_U32 ChipId; + SK_U8 VauxAvail; + SK_U32 RamSize; SK_U32 MtuSize; SK_U32 Action; SK_U32 TestResult; @@ -1090,6 +1136,8 @@ typedef struct s_PnmiData { char *pDriverDescription; char *pDriverVersion; + char *pDriverReleaseDate; + char *pDriverFileName; int MacUpdatedFlag; int RlmtUpdatedFlag; @@ -1119,6 +1167,9 @@ typedef struct s_PnmiData { SK_U8 VctStatus[SK_MAX_MACS]; SK_PNMI_VCT VctBackup[SK_MAX_MACS]; SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS]; +#ifdef SK_DIAG_SUPPORT + SK_U32 DiagAttached; +#endif /* SK_DIAG_SUPPORT */ } SK_PNMI; --- linux-2.6.1-rc1/drivers/net/sk98lin/h/ski2c.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/ski2c.h 2003-12-30 22:49:20.000000000 -0800 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: ski2c.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.34 $ - * Date: $Date: 2003/01/28 09:11:21 $ + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.35 $ + * Date: $Date: 2003/10/20 09:06:30 $ * Purpose: Defines to access Voltage and Temperature Sensor * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,10 @@ * History: * * $Log: ski2c.h,v $ + * Revision 1.35 2003/10/20 09:06:30 rschmidt + * Added prototypes for SkI2cRead() and SkI2cWrite(). + * Editorial changes. + * * Revision 1.34 2003/01/28 09:11:21 rschmidt * Editorial changes * @@ -137,7 +142,6 @@ * Revision 1.1 1998/06/19 14:30:10 malthoff * Created. Sources taken from ML Project. * - * ******************************************************************************/ /* @@ -252,7 +256,7 @@ struct s_Sensor { SK_I32 SenThreWarnLow; /* Lower warning Threshold of the sensor */ int SenErrFlag; /* Sensor indicated an error */ SK_BOOL SenInit; /* Is sensor initialized ? */ - SK_U64 SenErrCts; /* Error trap counter */ + SK_U64 SenErrCts; /* Error trap counter */ SK_U64 SenWarnCts; /* Warning trap counter */ SK_U64 SenBegErrTS; /* Begin error timestamp */ SK_U64 SenBegWarnTS; /* Begin warning timestamp */ @@ -279,13 +283,17 @@ typedef struct s_I2c { #endif /* !SK_DIAG */ } SK_I2C; +extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); +extern int SkI2cWrite(SK_AC *pAC, SK_IOC IoC, SK_U32 Data, int Dev, int Size, + int Reg, int Burst); extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen); -#ifndef SK_DIAG +#ifdef SK_DIAG +extern SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg, + int Burst); +#else /* !SK_DIAG */ extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para); -extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC); extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC); - -#endif +#endif /* !SK_DIAG */ #endif /* n_SKI2C_H */ --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skqueue.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skqueue.h 2003-12-30 22:49:20.000000000 -0800 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skqueue.h - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.15 $ - * Date: $Date: 2003/05/13 17:54:57 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.16 $ + * Date: $Date: 2003/09/16 12:50:32 $ * Purpose: Defines for the Event queue * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skqueue.h,v $ + * Revision 1.16 2003/09/16 12:50:32 rschmidt + * Editorial changes + * * Revision 1.15 2003/05/13 17:54:57 mkarl * Editorial changes. * @@ -47,7 +50,7 @@ * add: typedef SK_QUEUE * * Revision 1.9 1998/08/19 09:50:59 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs + * fix: remove struct keyword from C-code (see CCC) add typedefs * * Revision 1.8 1998/08/18 07:00:01 gklug * fix: SK_PTR not defined use void * instead. @@ -74,8 +77,6 @@ * Revision 1.1 1998/07/30 14:52:12 gklug * Initial version. * Defines Event Classes, Event structs and queue management variables. - * - * * ******************************************************************************/ @@ -92,7 +93,7 @@ */ #define SKGE_DRV 1 /* Driver Event Class */ #define SKGE_RLMT 2 /* RLMT Event Class */ -#define SKGE_I2C 3 /* i2C Event Class */ +#define SKGE_I2C 3 /* I2C Event Class */ #define SKGE_PNMI 4 /* PNMI Event Class */ #define SKGE_CSUM 5 /* Checksum Event Class */ #define SKGE_HWAC 6 /* Hardware Access Event Class */ @@ -121,25 +122,25 @@ typedef union u_EvPara { * Event Queue * skqueue.c * events are class/value pairs - * class is addressee, e.g. RMT, PCM etc. + * class is addressee, e.g. RLMT, PNMI etc. * value is command, e.g. line state change, ring op change etc. */ typedef struct s_EventElem { - SK_U32 Class ; /* Event class */ - SK_U32 Event ; /* Event value */ - SK_EVPARA Para ; /* Event parameter */ + SK_U32 Class; /* Event class */ + SK_U32 Event; /* Event value */ + SK_EVPARA Para; /* Event parameter */ } SK_EVENTELEM; typedef struct s_Queue { SK_EVENTELEM EvQueue[SK_MAX_EVENT]; - SK_EVENTELEM *EvPut ; - SK_EVENTELEM *EvGet ; + SK_EVENTELEM *EvPut; + SK_EVENTELEM *EvGet; } SK_QUEUE; extern void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level); extern void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event, SK_EVPARA Para); -extern int SkEventDispatcher(SK_AC *pAC,SK_IOC Ioc); +extern int SkEventDispatcher(SK_AC *pAC, SK_IOC Ioc); /* Define Error Numbers and messages */ --- linux-2.6.1-rc1/drivers/net/sk98lin/h/sktimer.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/sktimer.h 2003-12-30 22:49:20.000000000 -0800 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: sktimer.h - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.10 $ - * Date: $Date: 2003/05/13 17:56:44 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/09/16 12:58:18 $ * Purpose: Defines for the timer functions * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: sktimer.h,v $ + * Revision 1.11 2003/09/16 12:58:18 rschmidt + * Editorial changes + * * Revision 1.10 2003/05/13 17:56:44 mkarl * Editorial changes. * @@ -40,7 +43,7 @@ * fix: SK_TIMCTRL needs to be defined * * Revision 1.6 1998/08/19 09:51:00 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs + * fix: remove struct keyword from C-code (see CCC) add typedefs * * Revision 1.5 1998/08/17 13:43:21 gklug * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR @@ -78,25 +81,25 @@ typedef struct s_Timer SK_TIMER; struct s_Timer { - SK_TIMER *TmNext ; /* linked list */ - SK_U32 TmClass ; /* Timer Event class */ - SK_U32 TmEvent ; /* Timer Event value */ - SK_EVPARA TmPara ; /* Timer Event parameter */ - SK_U32 TmDelta ; /* delta time */ - int TmActive ; /* flag : active/inactive */ -} ; + SK_TIMER *TmNext; /* linked list */ + SK_U32 TmClass; /* Timer Event class */ + SK_U32 TmEvent; /* Timer Event value */ + SK_EVPARA TmPara; /* Timer Event parameter */ + SK_U32 TmDelta; /* delta time */ + int TmActive; /* flag: active/inactive */ +}; /* * Timer control struct. * - use in Adapters context name pAC->Tim */ typedef struct s_TimCtrl { - SK_TIMER *StQueue ; /* Head of Timer queue */ -} SK_TIMCTRL ; + SK_TIMER *StQueue; /* Head of Timer queue */ +} SK_TIMCTRL; -extern void SkTimerInit(SK_AC *pAC,SK_IOC Ioc, int Level); -extern void SkTimerStop(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer); -extern void SkTimerStart(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer, - SK_U32 Time,SK_U32 Class,SK_U32 Event,SK_EVPARA Para); -extern void SkTimerDone(SK_AC *pAC,SK_IOC Ioc); +extern void SkTimerInit(SK_AC *pAC, SK_IOC Ioc, int Level); +extern void SkTimerStop(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer); +extern void SkTimerStart(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer, + SK_U32 Time, SK_U32 Class, SK_U32 Event, SK_EVPARA Para); +extern void SkTimerDone(SK_AC *pAC, SK_IOC Ioc); #endif /* _SKTIMER_H_ */ --- linux-2.6.1-rc1/drivers/net/sk98lin/h/sktypes.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk98lin/h/sktypes.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,15 +2,16 @@ * * Name: sktypes.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.1 $ - * Date: $Date: 2003/07/21 07:26:01 $ + * Version: $Revision: 1.2 $ + * Date: $Date: 2003/10/07 08:16:51 $ * Purpose: Define data types for Linux * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,9 @@ * History: * * $Log: sktypes.h,v $ + * Revision 1.2 2003/10/07 08:16:51 mlindner + * Fix: Copyright changes + * * Revision 1.1 2003/07/21 07:26:01 rroesler * Fix: Re-Enter after CVS crash * --- linux-2.6.1-rc1/drivers/net/sk98lin/h/skversion.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skversion.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,15 +2,16 @@ * * Name: version.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 2003/08/25 13:34:48 $ + * Version: $Revision: 1.5 $ + * Date: $Date: 2003/10/07 08:16:51 $ * Purpose: SK specific Error log support * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -25,6 +26,12 @@ * * History: * $Log: skversion.h,v $ + * Revision 1.5 2003/10/07 08:16:51 mlindner + * Fix: Copyright changes + * + * Revision 1.4 2003/09/22 08:40:10 mlindner + * Add: Added DRIVER_FILE_NAME and DRIVER_REL_DATE + * * Revision 1.3 2003/08/25 13:34:48 mlindner * Fix: Lint changes * @@ -54,12 +61,14 @@ #ifdef lint static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH."; static const char SysKonnectBuildNumber[] = - "@(#)SK-BUILD: 6.18 PL: 01"; + "@(#)SK-BUILD: 6.21 PL: 01"; #endif /* !defined(lint) */ -#define BOOT_STRING "sk98lin: Network Device Driver v6.18\n" \ +#define BOOT_STRING "sk98lin: Network Device Driver v6.21\n" \ "(C)Copyright 1999-2003 Marvell(R)." -#define VER_STRING "6.18" +#define VER_STRING "6.21" +#define DRIVER_FILE_NAME "sk98lin" +#define DRIVER_REL_DATE "Dec-15-2003" --- linux-2.6.1-rc1/drivers/net/sk98lin/h/xmac_ii.h 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/h/xmac_ii.h 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: xmac_ii.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.48 $ - * Date: $Date: 2003/05/13 17:17:55 $ + * Version: $Revision: 1.52 $ + * Date: $Date: 2003/10/02 16:35:50 $ * Purpose: Defines and Macros for Gigabit Ethernet Controller * ******************************************************************************/ @@ -27,6 +27,22 @@ * History: * * $Log: xmac_ii.h,v $ + * Revision 1.52 2003/10/02 16:35:50 rschmidt + * Added defines for default values of GMAC parameters + * Changed defines for setting GMAC parameters + * Editorial changes + * + * Revision 1.51 2003/09/23 09:04:27 malthoff + * Add bit definitions for PHY_MARV_EXT_P_STAT. + * + * Revision 1.50 2003/09/16 14:15:07 rschmidt + * Added defines for Extended PHY Specific Control + * Editorial changes + * + * Revision 1.49 2003/09/16 07:22:46 mschmid + * Added defines for Marvell PHY energy detect modes + * Added macros for MAC parameter setting in port structure + * * Revision 1.48 2003/05/13 17:17:55 mkarl * Editorial changes. * @@ -676,7 +692,7 @@ extern "C" { #define PHY_XMAC_AUNE_LP 0x05 /* 16 bit r/o Link Partner Abi Reg */ #define PHY_XMAC_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_XMAC_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_XMAC_NEPG_LP 0x08 /* 16 bit r/o Next Page Link P Reg */ +#define PHY_XMAC_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* 0x09 - 0x0e: reserved */ #define PHY_XMAC_EXT_STAT 0x0f /* 16 bit r/o Ext Status Register */ #define PHY_XMAC_RES_ABI 0x10 /* 16 bit r/o PHY Resolved Ability */ @@ -693,7 +709,7 @@ extern "C" { #define PHY_BCOM_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ #define PHY_BCOM_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_BCOM_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_BCOM_NEPG_LP 0x08 /* 16 bit r/o Next Page Link P Reg */ +#define PHY_BCOM_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* Broadcom-specific registers */ #define PHY_BCOM_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */ #define PHY_BCOM_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ @@ -702,7 +718,7 @@ extern "C" { #define PHY_BCOM_P_EXT_CTRL 0x10 /* 16 bit r/w PHY Extended Ctrl Reg */ #define PHY_BCOM_P_EXT_STAT 0x11 /* 16 bit r/o PHY Extended Stat Reg */ #define PHY_BCOM_RE_CTR 0x12 /* 16 bit r/w Receive Error Counter */ -#define PHY_BCOM_FC_CTR 0x13 /* 16 bit r/w False Carr Sense Cnt */ +#define PHY_BCOM_FC_CTR 0x13 /* 16 bit r/w False Carrier Sense Cnt */ #define PHY_BCOM_RNO_CTR 0x14 /* 16 bit r/w Receiver NOT_OK Cnt */ /* 0x15 - 0x17: reserved */ #define PHY_BCOM_AUX_CTRL 0x18 /* 16 bit r/w Auxiliary Control Reg */ @@ -724,7 +740,7 @@ extern "C" { #define PHY_MARV_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ #define PHY_MARV_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_MARV_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_MARV_NEPG_LP 0x08 /* 16 bit r/o Next Page Link P Reg */ +#define PHY_MARV_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* Marvel-specific registers */ #define PHY_MARV_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */ #define PHY_MARV_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ @@ -757,7 +773,7 @@ extern "C" { #define PHY_LONE_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ #define PHY_LONE_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ #define PHY_LONE_NEPG 0x07 /* 16 bit r/w Next Page Register */ -#define PHY_LONE_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner*/ +#define PHY_LONE_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ /* Level One-specific registers */ #define PHY_LONE_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Control Reg*/ #define PHY_LONE_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ @@ -804,12 +820,13 @@ extern "C" { /* * PHY bit definitions * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are - * Xmac/Broadcom/LevelOne/National-specific. + * XMAC/Broadcom/LevelOne/National/Marvell-specific. * All other are general. */ /***** PHY_XMAC_CTRL 16 bit r/w PHY Control Register *****/ /***** PHY_BCOM_CTRL 16 bit r/w PHY Control Register *****/ +/***** PHY_MARV_CTRL 16 bit r/w PHY Status Register *****/ /***** PHY_LONE_CTRL 16 bit r/w PHY Control Register *****/ #define PHY_CT_RESET (1<<15) /* Bit 15: (sc) clear all PHY related regs */ #define PHY_CT_LOOP (1<<14) /* Bit 14: enable Loopback over PHY */ @@ -909,27 +926,20 @@ extern "C" { /***** PHY_XMAC_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ /* Bit 15..4: reserved */ -#define PHY_AN_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */ -#define PHY_AN_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */ -#define PHY_AN_RX_PG (1<<1) /* Bit 1: Page Received */ +#define PHY_ANE_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */ +#define PHY_ANE_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */ +#define PHY_ANE_RX_PG (1<<1) /* Bit 1: Page Received */ /* Bit 0: reserved */ /***** PHY_BCOM_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ - /* Bit 15..5: reserved */ -#define PHY_B_AN_PDF (1<<4) /* Bit 4: Parallel Detection Fault */ -/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ -/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ -/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ -#define PHY_B_AN_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ - /***** PHY_LONE_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ -#define PHY_L_AN_BP (1<<5) /* Bit 5: Base Page Indication */ -#define PHY_L_AN_PDF (1<<4) /* Bit 4: Parallel Detection Fault */ -/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ -/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ -/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ -#define PHY_B_AN_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ - +/***** PHY_MARV_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ + /* Bit 15..5: reserved */ +#define PHY_ANE_PAR_DF (1<<4) /* Bit 4: Parallel Detection Fault */ +/* PHY_ANE_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ +/* PHY_ANE_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ +/* PHY_ANE_RX_PG (see XMAC) Bit 1: Page Received */ +#define PHY_ANE_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ /***** PHY_XMAC_NEPG 16 bit r/w Next Page Register *****/ /***** PHY_BCOM_NEPG 16 bit r/w Next Page Register *****/ @@ -958,7 +968,7 @@ extern "C" { #define PHY_X_RS_HD (1<<6) /* Bit 6: Half Duplex Mode selected */ #define PHY_X_RS_FD (1<<5) /* Bit 5: Full Duplex Mode selected */ #define PHY_X_RS_ABLMIS (1<<4) /* Bit 4: duplex or pause cap mismatch */ -#define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability missmatch */ +#define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability mismatch */ /* Bit 2..0: reserved */ /* * Remote Fault Bits (PHY_X_AN_RFB) encoding @@ -990,6 +1000,7 @@ extern "C" { /* Bit 7..0: reserved */ /***** PHY_BCOM_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +/***** PHY_MARV_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ #define PHY_B_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ #define PHY_B_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */ #define PHY_B_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */ @@ -1309,7 +1320,6 @@ extern "C" { /* Bit 7..0: reserved */ /***** PHY_MARV_PHY_CTRL 16 bit r/w PHY Specific Ctrl Reg *****/ - #define PHY_M_PC_TX_FFD_MSK (3<<14) /* Bit 15..14: Tx FIFO Depth Mask */ #define PHY_M_PC_RX_FFD_MSK (3<<12) /* Bit 13..12: Rx FIFO Depth Mask */ #define PHY_M_PC_ASS_CRS_TX (1<<11) /* Bit 11: Assert CRS on Transmit */ @@ -1323,6 +1333,9 @@ extern "C" { #define PHY_M_PC_POL_R_DIS (1<<1) /* Bit 1: Polarity Reversal Disabled */ #define PHY_M_PC_DIS_JABBER (1<<0) /* Bit 0: Disable Jabber */ +#define PHY_M_PC_EN_DET SHIFT8(2) /* Energy Detect (Mode 1) */ +#define PHY_M_PC_EN_DET_PLUS SHIFT8(3) /* Energy Detect Plus (Mode 2) */ + #define PHY_M_PC_MDI_XMODE(x) SHIFT5(x) #define PHY_M_PC_MAN_MDI 0 /* 00 = Manual MDI configuration */ #define PHY_M_PC_MAN_MDIX 1 /* 01 = Manual MDIX configuration */ @@ -1373,6 +1386,7 @@ extern "C" { #define PHY_M_EC_M_DSC_MSK (3<<10) /* Bit 11..10: Master downshift counter */ #define PHY_M_EC_S_DSC_MSK (3<<8) /* Bit 9.. 8: Slave downshift counter */ #define PHY_M_EC_MAC_S_MSK (7<<4) /* Bit 6.. 4: Def. MAC interface speed */ +#define PHY_M_EC_FIB_AN_ENA (1<<3) /* Bit 3: Fiber Auto-Neg. Enable */ #define PHY_M_EC_M_DSC(x) SHIFT10(x) /* 00=1x; 01=2x; 10=3x; 11=4x */ #define PHY_M_EC_S_DSC(x) SHIFT8(x) /* 00=dis; 01=1x; 10=2x; 11=3x */ @@ -1434,6 +1448,18 @@ extern "C" { #define PHY_M_EC2_FO_BOOST (1<<3) /* Bit 3: Fiber Output Boost */ #define PHY_M_EC2_FO_AM_MSK 7 /* Bit 2.. 0: Fiber Output Amplitude */ +/***** PHY_MARV_EXT_P_STAT 16 bit r/w Ext. PHY Specific Status *****/ +#define PHY_M_FC_AUTO_SEL (1<<15) /* Bit 15: Fiber/Copper Auto Sel. dis. */ +#define PHY_M_FC_AN_REG_ACC (1<<14) /* Bit 14: Fiber/Copper Autoneg. reg acc */ +#define PHY_M_FC_RESULUTION (1<<13) /* Bit 13: Fiber/Copper Resulution */ +#define PHY_M_SER_IF_AN_BP (1<<12) /* Bit 12: Ser IF autoneg. bypass enable */ +#define PHY_M_SER_IF_BP_ST (1<<11) /* Bit 11: Ser IF autoneg. bypass status */ +#define PHY_M_IRQ_POLARITY (1<<10) /* Bit 10: IRQ polarity */ + /* Bit 9..4: reserved */ +#define PHY_M_UNDOC1 (1<< 7) /* undocumented bit !! */ +#define PHY_M_MODE_MASK (0xf<<0)/* Bit 3..0: copy of HWCFG MODE[3:0] */ + + /***** PHY_MARV_CABLE_DIAG 16 bit r/o Cable Diagnostic Reg *****/ #define PHY_M_CABD_ENA_TEST (1<<15) /* Bit 15: Enable Test */ #define PHY_M_CABD_STAT_MSK (3<<13) /* Bit 14..13: Status */ @@ -1531,7 +1557,7 @@ extern "C" { #define GM_RXF_SHT \ (GM_MIB_CNT_BASE + 80) /* Frames <64 Byte Received OK */ #define GM_RXE_FRAG \ - (GM_MIB_CNT_BASE + 88) /* Frames <64 Byte Receeived with FCS Err */ + (GM_MIB_CNT_BASE + 88) /* Frames <64 Byte Received with FCS Err */ #define GM_RXF_64B \ (GM_MIB_CNT_BASE + 96) /* 64 Byte Rx Frame */ #define GM_RXF_127B \ @@ -1606,7 +1632,6 @@ extern "C" { */ /* GM_GP_STAT 16 bit r/o General Purpose Status Register */ - #define GM_GPSR_SPEED (1<<15) /* Bit 15: Port Speed (1 = 100 Mbps) */ #define GM_GPSR_DUPLEX (1<<14) /* Bit 14: Duplex Mode (1 = Full) */ #define GM_GPSR_FC_TX_DIS (1<<13) /* Bit 13: Tx Flow-Control Mode Disabled */ @@ -1646,11 +1671,14 @@ extern "C" { GM_GPCR_AU_SPD_DIS) /* GM_TX_CTRL 16 bit r/w Transmit Control Register */ - #define GM_TXCR_FORCE_JAM (1<<15) /* Bit 15: Force Jam / Flow-Control */ #define GM_TXCR_CRC_DIS (1<<14) /* Bit 14: Disable insertion of CRC */ #define GM_TXCR_PAD_DIS (1<<13) /* Bit 13: Disable padding of packets */ -#define GM_TXCR_COL_THR (4<<10) /* Bit 12..10: Collision Threshold */ +#define GM_TXCR_COL_THR_MSK (1<<10) /* Bit 12..10: Collision Threshold */ + +#define TX_COL_THR(x) (SHIFT10(x) & GM_TXCR_COL_THR_MSK) + +#define TX_COL_DEF 0x04 /* GM_RX_CTRL 16 bit r/w Receive Control Register */ #define GM_RXCR_UCF_ENA (1<<15) /* Bit 15: Enable Unicast filtering */ @@ -1663,35 +1691,41 @@ extern "C" { #define GM_TXPA_JAMIPG_MSK (0x1f<<9) /* Bit 13..9: Jam IPG */ #define GM_TXPA_JAMDAT_MSK (0x1f<<4) /* Bit 8..4: IPG Jam to Data */ /* Bit 3..0: reserved */ -#define JAM_LEN_VAL(x) SHIFT14(x) -#define JAM_IPG_VAL(x) SHIFT9(x) -#define IPG_JAM_DATA(x) SHIFT4(x) + +#define TX_JAM_LEN_VAL(x) (SHIFT14(x) & GM_TXPA_JAMLEN_MSK) +#define TX_JAM_IPG_VAL(x) (SHIFT9(x) & GM_TXPA_JAMIPG_MSK) +#define TX_IPG_JAM_DATA(x) (SHIFT4(x) & GM_TXPA_JAMDAT_MSK) + +#define TX_JAM_LEN_DEF 0x03 +#define TX_JAM_IPG_DEF 0x0b +#define TX_IPG_JAM_DEF 0x1c /* GM_SERIAL_MODE 16 bit r/w Serial Mode Register */ -#define GM_SMOD_DATABL_MSK (0x1f<<11) /* Bit 15..11: Data Blinder */ +#define GM_SMOD_DATABL_MSK (0x1f<<11) /* Bit 15..11: Data Blinder (r/o) */ #define GM_SMOD_LIMIT_4 (1<<10) /* Bit 10: 4 consecutive Tx trials */ #define GM_SMOD_VLAN_ENA (1<<9) /* Bit 9: Enable VLAN (Max. Frame Len) */ #define GM_SMOD_JUMBO_ENA (1<<8) /* Bit 8: Enable Jumbo (Max. Frame Len) */ /* Bit 7..5: reserved */ #define GM_SMOD_IPG_MSK 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */ -#define DATA_BLIND_VAL(x) SHIFT11(x) -#define DATA_BLIND_FAST_ETH 0x1c -#define DATA_BLIND_GIGABIT 4 +#define DATA_BLIND_VAL(x) (SHIFT11(x) & GM_SMOD_DATABL_MSK) +#define DATA_BLIND_DEF 0x04 -#define IPG_VAL_FAST_ETH 0x1e -#define IPG_VAL_GIGABIT 6 +#define IPG_DATA_VAL(x) (x & GM_SMOD_IPG_MSK) +#define IPG_DATA_DEF 0x1e /* GM_SMI_CTRL 16 bit r/w SMI Control Register */ - -#define GM_SMI_CT_PHY_AD(x) SHIFT11(x) -#define GM_SMI_CT_REG_AD(x) SHIFT6(x) +#define GM_SMI_CT_PHY_A_MSK (0x1f<<11) /* Bit 15..11: PHY Device Address */ +#define GM_SMI_CT_REG_A_MSK (0x1f<<6) /* Bit 10.. 6: PHY Register Address */ #define GM_SMI_CT_OP_RD (1<<5) /* Bit 5: OpCode Read (0=Write)*/ #define GM_SMI_CT_RD_VAL (1<<4) /* Bit 4: Read Valid (Read completed) */ #define GM_SMI_CT_BUSY (1<<3) /* Bit 3: Busy (Operation in progress) */ /* Bit 2..0: reserved */ -/* GM_PHY_ADDR 16 bit r/w GPHY Address Register */ +#define GM_SMI_CT_PHY_AD(x) (SHIFT11(x) & GM_SMI_CT_PHY_A_MSK) +#define GM_SMI_CT_REG_AD(x) (SHIFT6(x) & GM_SMI_CT_REG_A_MSK) + + /* GM_PHY_ADDR 16 bit r/w GPHY Address Register */ /* Bit 15..6: reserved */ #define GM_PAR_MIB_CLR (1<<5) /* Bit 5: Set MIB Clear Counter Mode */ #define GM_PAR_MIB_TST (1<<4) /* Bit 4: MIB Load Counter (Test Mode) */ --- linux-2.6.1-rc1/drivers/net/sk98lin/Makefile 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/Makefile 2003-12-30 22:49:20.000000000 -0800 @@ -76,7 +76,7 @@ endif # SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources # SK_DBGCAT_DRV_EVENT 0x08000000 driver events -EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) +EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) clean: rm -f core *.o *.a *.s --- linux-2.6.1-rc1/drivers/net/sk98lin/skcsum.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skcsum.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skcsum.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/03/11 14:05:55 $ + * Version: $Revision: 1.12 $ + * Date: $Date: 2003/08/20 13:55:53 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -26,6 +26,10 @@ * History: * * $Log: skcsum.c,v $ + * Revision 1.12 2003/08/20 13:55:53 mschmid + * Changed notation of #ifndef SkCsCalculateChecksum to + * #ifndef SK_CS_CALCULATE_CHECKSUM + * * Revision 1.11 2003/03/11 14:05:55 rschmidt * Replaced memset() by macro SK_MEMSET() * Editorial changes @@ -78,7 +82,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skcsum.c,v 1.11 2003/03/11 14:05:55 rschmidt Exp $ (C) SysKonnect."; + "@(#) $Id: skcsum.c,v 1.12 2003/08/20 13:55:53 mschmid Exp $ (C) SysKonnect."; #endif /* !lint */ /****************************************************************************** @@ -791,7 +795,7 @@ int NetNumber) *pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE; } /* SkCsSetReceiveFlags */ -#ifndef SkCsCalculateChecksum +#ifndef SK_CS_CALCULATE_CHECKSUM /****************************************************************************** * @@ -856,7 +860,7 @@ unsigned Length) /* Length of data. */ return ((unsigned) Checksum); } /* SkCsCalculateChecksum */ -#endif /* SkCsCalculateChecksum */ +#endif /* SK_CS_CALCULATE_CHECKSUM */ /****************************************************************************** * --- linux-2.6.1-rc1/drivers/net/sk98lin/skdim.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/sk98lin/skdim.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skdim.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 2003/08/21 12:35:05 $ + * Version: $Revision: 1.5 $ + * Date: $Date: 2003/11/28 12:55:40 $ * Purpose: All functions to maintain interrupt moderation * ******************************************************************************/ @@ -11,6 +11,7 @@ /****************************************************************************** * * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,15 @@ * History: * * $Log: skdim.c,v $ + * Revision 1.5 2003/11/28 12:55:40 rroesler + * Fix: support for new process timing interface added + * + * Revision 1.4 2003/10/10 10:58:56 mlindner + * Fix: CPU detection under the kernel 2.6 + * + * Revision 1.3 2003/10/07 08:17:08 mlindner + * Fix: Copyright changes + * * Revision 1.2 2003/08/21 12:35:05 mlindner * Fix: Corrected CPU detection and compile errors on single CPU machines * @@ -62,7 +72,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skdim.c,v 1.2 2003/08/21 12:35:05 mlindner Exp $ (C) SysKonnect."; + "@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect."; #endif #define __SKADDR_C @@ -327,7 +337,9 @@ GetCurrentSystemLoad(SK_AC *pAC) { ** ** struct kernel_stat kstat ** - ** is not marked as an exported symbol + ** is not marked as an exported symbol in the file + ** + ** kernel/ksyms.c ** ** As a consequence, using this driver as KLM is not possible ** and any access of the structure kernel_stat via the --- linux-2.6.1-rc1/drivers/net/sk98lin/skge.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/sk98lin/skge.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,35 +1,20 @@ /****************************************************************************** * - * Name: skge.c + * Name: skge.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/08/26 16:05:19 $ + * Version: $Revision: 1.42 $ + * Date: $Date: 2003/12/12 10:05:43 $ * Purpose: The main driver source module * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * - * Driver for SysKonnect Gigabit Ethernet Server Adapters: - * - * SK-9871 (single link 1000Base-ZX) - * SK-9872 (dual link 1000Base-ZX) - * SK-9861 (single link 1000Base-SX, VF45 Volition Plug) - * SK-9862 (dual link 1000Base-SX, VF45 Volition Plug) - * SK-9841 (single link 1000Base-LX) - * SK-9842 (dual link 1000Base-LX) - * SK-9843 (single link 1000Base-SX) - * SK-9844 (dual link 1000Base-SX) - * SK-9821 (single link 1000Base-T) - * SK-9822 (dual link 1000Base-T) - * SK-9881 (single link 1000Base-SX V2 LC) - * SK-9871 (single link 1000Base-ZX V2) - * SK-9861 (single link 1000Base-SX V2, VF45 Volition Plug) - * SK-9841 (single link 1000Base-LX V2) - * SK-9843 (single link 1000Base-SX V2) - * SK-9821 (single link 1000Base-T V2) + * Driver for Marvell Yukon chipset and SysKonnect Gigabit Ethernet + * Server Adapters. * * Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and * SysKonnects GEnesis Solaris driver @@ -56,6 +41,87 @@ * History: * * $Log: skge.c,v $ + * Revision 1.42 2003/12/12 10:05:43 mlindner + * Fix: Format of error message corrected + * + * Revision 1.41 2003/12/11 16:03:57 mlindner + * Fix: Create backup from pnmi data structure + * + * Revision 1.40 2003/12/11 12:14:48 mlindner + * Fix: Initalize Board before network configuration + * Fix: Change device names to driver name + * + * Revision 1.39 2003/12/10 08:57:38 rroesler + * Fix: Modifications regarding try_module_get() and capable() + * + * Revision 1.38 2003/12/01 17:16:50 mlindner + * Fix: Remove useless register_netdev + * + * Revision 1.37 2003/12/01 17:11:30 mlindner + * Fix: Register net device before SkGeBoardInit + * + * Revision 1.36 2003/11/28 13:04:27 rroesler + * Fix: do not print interface status in case DIAG is used + * + * Revision 1.35 2003/11/17 14:41:06 mlindner + * Fix: Endif command + * + * Revision 1.34 2003/11/17 13:29:05 mlindner + * Fix: Editorial changes + * + * Revision 1.33 2003/11/14 14:56:54 rroesler + * Fix: corrected compilation warnings kernel 2.2 + * + * Revision 1.32 2003/11/13 14:18:47 rroesler + * Fix: added latest changes regarding the use of the proc system + * + * Revision 1.31 2003/11/13 09:28:35 rroesler + * Fix: removed kernel warning 'driver changed get_stats after register' + * + * Revision 1.30 2003/11/11 13:15:27 rroesler + * Fix: use suitables kernel usage count macros when using the diag + * + * Revision 1.29 2003/11/10 09:38:26 rroesler + * Fix: restore PNMI structure backup for DIAG actions + * + * Revision 1.28 2003/11/07 17:28:45 rroesler + * Fix: Additions for the LeaveDiagMode + * + * Revision 1.27 2003/11/03 13:21:14 mlindner + * Add: SkGeBuffPad function for padding to ensure the trailing bytes exist + * + * Revision 1.26 2003/10/30 09:20:40 mlindner + * Fix: Control bit check + * + * Revision 1.25 2003/10/29 07:43:37 rroesler + * Fix: Implemented full None values handling for parameter Moderation + * + * Revision 1.24 2003/10/22 14:18:12 rroesler + * Fix: DIAG handling for DualNet cards + * + * Revision 1.23 2003/10/17 10:05:13 mlindner + * Add: New blinkmode for Morvell cards + * + * Revision 1.22 2003/10/15 12:31:25 rroesler + * Fix: Corrected bugreport #10954 (Linux System crash when using vlans) + * + * Revision 1.21 2003/10/07 12:32:28 mlindner + * Fix: Editorial changes + * + * Revision 1.20 2003/10/07 12:22:40 mlindner + * Fix: Compiler warnings + * + * Revision 1.19 2003/10/07 09:33:40 mlindner + * Fix: No warnings for illegal values of Mod and IntsPerSec + * Fix: Speed 100 in Half Duplex not allowed for Yukon + * Fix: PrefPort=B not allowed on single NICs + * + * Revision 1.18 2003/10/07 08:17:08 mlindner + * Fix: Copyright changes + * + * Revision 1.17 2003/09/29 12:06:59 mlindner + * *** empty log message *** + * * Revision 1.16 2003/09/23 11:07:35 mlindner * Fix: IO-control return race condition * Fix: Interrupt moderation value check @@ -68,6 +134,12 @@ * Add: Yukon Plus changes (ChipID, PCI...) * Fix: TCP and UDP Checksum calculation * + * Revision 1.13 2003/09/01 13:30:08 rroesler + * Fix: Corrected missing defines + * + * Revision 1.12 2003/09/01 13:12:02 rroesler + * Add: Code for improved DIAG Attach/Detach interface + * * Revision 1.11 2003/08/26 16:05:19 mlindner * Fix: Compiler warnings (void *) * @@ -406,7 +478,6 @@ * * * "h/skdrv1st.h" - * * * * @@ -568,6 +639,12 @@ static void StartDrvCleanupTimer(SK_AC * static void StopDrvCleanupTimer(SK_AC *pAC); static int XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*); +#ifdef SK_DIAG_SUPPORT +static SK_U32 ParseDeviceNbrFromSlotName(const char *SlotName); +static int SkDrvInitAdapter(SK_AC *pAC, int devNbr); +static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr); +#endif + /******************************************************************************* * * Extern Function Prototypes @@ -576,8 +653,8 @@ static int XmitFrameSG(SK_AC*, TX_PORT*, #ifdef CONFIG_PROC_FS static const char SK_Root_Dir_entry[] = "sk98lin"; -static struct proc_dir_entry *pSkRootDir; -extern struct file_operations sk_proc_fops; +static struct proc_dir_entry *pSkRootDir = NULL; +extern struct file_operations sk_proc_fops; #endif extern void SkDimEnableModerationIfNeeded(SK_AC *pAC); @@ -595,12 +672,19 @@ static void DumpLong(char*, int); static const char *BootString = BOOT_STRING; struct SK_NET_DEVICE *SkGeRootDev = NULL; static int probed __initdata = 0; +static SK_BOOL DoPrintInterfaceChange = SK_TRUE; /* local variables **********************************************************/ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *pSkRootDir; +#endif + + + /***************************************************************************** * * skge_probe - find all SK-98xx adapters @@ -626,6 +710,7 @@ static int __init skge_probe (void) SK_BOOL BootStringCount = SK_FALSE; int retval; #ifdef CONFIG_PROC_FS + int proc_root_initialized = 0; struct proc_dir_entry *pProcFile; #endif @@ -700,6 +785,7 @@ static int __init skge_probe (void) dev->stop = &SkGeClose; dev->hard_start_xmit = &SkGeXmit; dev->get_stats = &SkGeStats; + dev->last_stats = &SkGeStats; dev->set_multicast_list = &SkGeSetRxMode; dev->set_mac_address = &SkGeSetMacAddr; dev->do_ioctl = &SkGeIoctl; @@ -718,15 +804,13 @@ static int __init skge_probe (void) #endif pAC->Index = boards_found; + if (SkGeBoardInit(dev, pAC)) { - FreeResources(dev); free_netdev(dev); continue; } - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); - + /* Register net device */ if (register_netdev(dev)) { printk(KERN_ERR "SKGE: Could not register device.\n"); FreeResources(dev); @@ -734,6 +818,25 @@ static int __init skge_probe (void) continue; } + /* Print adapter specific string from vpd */ + ProductStr(pAC); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + + SkGeYellowLED(pAC, pAC->IoBase, 1); + + + memcpy((caddr_t) &dev->dev_addr, + (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); + /* First adapter... Create proc and print message */ #ifdef CONFIG_PROC_FS if (!DeviceFound) { @@ -744,25 +847,27 @@ static int __init skge_probe (void) /*Create proc (directory)*/ if(!pSkRootDir) { pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); - if (!pSkRootDir) + if (!pSkRootDir) { printk(KERN_WARNING "%s: Unable to create /proc/net/%s", - dev->name, SK_Root_Dir_entry); - else + dev->name, SK_Root_Dir_entry); + } else { pSkRootDir->owner = THIS_MODULE; + } } } - + /* Create proc file */ - if (pSkRootDir - && (pProcFile = create_proc_entry(dev->name, S_IRUGO, - pSkRootDir))) { + if (pSkRootDir && + (pProcFile = create_proc_entry(dev->name, S_IRUGO, + pSkRootDir))) { pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; + pProcFile->data = dev; } + #endif pNet->PortNr = 0; - pNet->NetNr = 0; + pNet->NetNr = 0; boards_found++; @@ -774,23 +879,24 @@ static int __init skge_probe (void) break; } - pAC->dev[1] = dev; - pNet = dev->priv; - pNet->PortNr = 1; - pNet->NetNr = 1; - pNet->pAC = pAC; - pNet->Mtu = 1500; - pNet->Up = 0; - - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; + pAC->dev[1] = dev; + pNet = dev->priv; + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + pNet->Mtu = 1500; + pNet->Up = 0; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->last_stats = &SkGeStats; dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; #ifdef SK_ZEROCOPY #ifdef USE_SK_TX_CHECKSUM @@ -802,34 +908,39 @@ static int __init skge_probe (void) #endif if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register " - "second port.\n"); + printk(KERN_ERR "SKGE: Could not register device.\n"); free_netdev(dev); pAC->dev[1] = pAC->dev[0]; } else { #ifdef CONFIG_PROC_FS if (pSkRootDir && (pProcFile = create_proc_entry(dev->name, - S_IRUGO, - pSkRootDir))) { + S_IRUGO, pSkRootDir))) { pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; + pProcFile->data = dev; } #endif - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); + memcpy((caddr_t) &dev->dev_addr, + (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); } } - /* Save the hardware revision */ pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + (pAC->GIni.GIPciHwRev & 0x0F); + /* Set driver globals */ + pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; + pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; + + SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); + SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + /* * This is bollocks, but we need to tell the net-init * code that it shall go for the next device. @@ -849,7 +960,6 @@ static int __init skge_probe (void) } /* skge_probe */ - /***************************************************************************** * * SkGeInitPCI - Init the PCI resources @@ -1143,7 +1253,7 @@ SK_EVPARA EvPara; if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ unregister_netdev(pAC->dev[1]); - kfree(pAC->dev[1]); + free_netdev(pAC->dev[1]); } FreeResources(SkGeRootDev); @@ -1161,8 +1271,7 @@ SK_EVPARA EvPara; #ifdef CONFIG_PROC_FS /* clear proc-dir */ - if (pSkRootDir) - remove_proc_entry(pSkRootDir->name, proc_net); + remove_proc_entry(pSkRootDir->name, proc_net); #endif } /* skge_cleanup_module */ @@ -1224,7 +1333,7 @@ SK_BOOL DualNet; SkAddrInit( pAC, pAC->IoBase, SK_INIT_DATA); SkRlmtInit( pAC, pAC->IoBase, SK_INIT_DATA); SkTimerInit(pAC, pAC->IoBase, SK_INIT_DATA); - + pAC->BoardLevel = SK_INIT_DATA; pAC->RxBufSize = ETH_BUF_SIZE; @@ -1236,7 +1345,7 @@ SK_BOOL DualNet; /* level 1 init common modules here (HW init) */ spin_lock_irqsave(&pAC->SlowPathLock, Flags); if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { - printk("HWInit (1) failed.\n"); + printk("sk98lin: HWInit (1) failed.\n"); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); return(-EAGAIN); } @@ -1268,14 +1377,14 @@ SK_BOOL DualNet; Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ, pAC->Name, dev); } else { - printk(KERN_WARNING "%s: Illegal number of ports: %d\n", - dev->name, pAC->GIni.GIMacsFound); + printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n", + pAC->GIni.GIMacsFound); return -EAGAIN; } if (Ret) { - printk(KERN_WARNING "%s: Requested IRQ %d is busy.\n", - dev->name, dev->irq); + printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n", + dev->irq); return -EAGAIN; } pAC->AllocFlag |= SK_ALLOC_IRQ; @@ -1303,25 +1412,10 @@ SK_BOOL DualNet; pAC->ActivePort, DualNet)) { BoardFreeMem(pAC); - printk("SkGeInitAssignRamToQueues failed.\n"); + printk("sk98lin: SkGeInitAssignRamToQueues failed.\n"); return(-EAGAIN); } - /* Print adapter specific string from vpd */ - ProductStr(pAC); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - - /* Print configuration settings */ - printk(" PrefPort:%c RlmtMode:%s\n", - 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, - (pAC->RlmtMode==0) ? "Check Link State" : - ((pAC->RlmtMode==1) ? "Check Link State" : - ((pAC->RlmtMode==3) ? "Check Local Port" : - ((pAC->RlmtMode==7) ? "Check Segmentation" : - ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); - - SkGeYellowLED(pAC, pAC->IoBase, 1); - /* * Register the device here */ @@ -1879,14 +1973,26 @@ struct SK_NET_DEVICE *dev) SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC)); +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + return (-1); /* still in use by diag; deny actions */ + } + } +#endif + + if (!try_module_get(THIS_MODULE)) { + return (-1); /* increase of usage count not possible */ + } /* Set blink mode */ - if (pAC->PciDev->vendor == 0x1186) + if ((pAC->PciDev->vendor == 0x1186) || (pAC->PciDev->vendor == 0x11ab )) pAC->GIni.GILedBlinkCtrl = OEM_CONFIG_VALUE; if (pAC->BoardLevel == SK_INIT_DATA) { /* level 1 init common modules here */ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { + module_put(THIS_MODULE); /* decrease usage count */ printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name); return (-1); } @@ -1902,6 +2008,7 @@ struct SK_NET_DEVICE *dev) if (pAC->BoardLevel != SK_INIT_RUN) { /* tschilling: Level 2 init modules here, check return value. */ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_RUN) != 0) { + module_put(THIS_MODULE); /* decrease usage count */ printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name); return (-1); } @@ -1953,7 +2060,6 @@ struct SK_NET_DEVICE *dev) pAC->MaxPorts++; pNet->Up = 1; - try_module_get(THIS_MODULE); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeOpen suceeded\n")); @@ -1976,26 +2082,50 @@ struct SK_NET_DEVICE *dev) static int SkGeClose( struct SK_NET_DEVICE *dev) { - DEV_NET *pNet; - SK_AC *pAC; + DEV_NET *pNet; + DEV_NET *newPtrNet; + SK_AC *pAC; unsigned long Flags; /* for spin lock */ - int i; - int PortIdx; - SK_EVPARA EvPara; + int i; + int PortIdx; + SK_EVPARA EvPara; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); - netif_stop_queue(dev); pNet = (DEV_NET*) dev->priv; pAC = pNet->pAC; +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->DiagFlowCtrl == SK_FALSE) { + module_put(THIS_MODULE); + /* + ** notify that the interface which has been closed + ** by operator interaction must not be started up + ** again when the DIAG has finished. + */ + newPtrNet = (DEV_NET *) pAC->dev[0]->priv; + if (newPtrNet == pNet) { + pAC->WasIfUp[0] = SK_FALSE; + } else { + pAC->WasIfUp[1] = SK_FALSE; + } + return 0; /* return to system everything is fine... */ + } else { + pAC->DiagFlowCtrl = SK_FALSE; + } + } +#endif + + netif_stop_queue(dev); + if (pAC->RlmtNets == 1) PortIdx = pAC->ActivePort; else PortIdx = pNet->NetNr; - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, - ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); - StopDrvCleanupTimer(pAC); /* @@ -2053,6 +2183,10 @@ struct SK_NET_DEVICE *dev) SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeClose: done ")); + SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); + SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + pAC->MaxPorts--; pNet->Up = 0; @@ -2199,9 +2333,10 @@ struct sk_buff *pMessage) /* pointer to ** This is to resolve faulty padding by the HW with 0xaa bytes. */ if (BytesSend < C_LEN_ETHERNET_MINSIZE) { - skb_put(pMessage, (C_LEN_ETHERNET_MINSIZE-BytesSend)); - SK_MEMSET( ((char *)(pMessage->data))+BytesSend, - 0, C_LEN_ETHERNET_MINSIZE-BytesSend); + if ((pMessage = skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) == NULL) { + return 0; + } + pMessage->len = C_LEN_ETHERNET_MINSIZE; } /* @@ -3318,6 +3453,16 @@ SK_EVPARA EvPara; return -EINVAL; } +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->DiagFlowCtrl == SK_FALSE) { + return -1; /* still in use, deny any actions of MTU */ + } else { + pAC->DiagFlowCtrl = SK_FALSE; + } + } +#endif + pNet->Mtu = NewMtu; pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv; if ((pOtherNet->Mtu>1500) && (NewMtu<=1500) && (pOtherNet->Up==1)) { @@ -3537,11 +3682,20 @@ unsigned long Flags; /* for spin lock SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeStats starts now...\n")); pPnmiStruct = &pAC->PnmiStruct; - memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); + +#ifdef SK_DIAG_SUPPORT + if ((pAC->DiagModeActive == DIAG_NOTACTIVE) && + (pAC->BoardLevel == SK_INIT_RUN)) { +#endif + SK_MEMSET(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); spin_lock_irqsave(&pAC->SlowPathLock, Flags); Size = SK_PNMI_STRUCT_SIZE; SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); +#ifdef SK_DIAG_SUPPORT + } +#endif + pPnmiStat = &pPnmiStruct->Stat[0]; pPnmiConf = &pPnmiStruct->Conf[0]; @@ -3604,7 +3758,7 @@ static int SkGeIoctl(struct SK_NET_DEVIC DEV_NET *pNet; SK_AC *pAC; void *pMemBuf; - +struct pci_dev *pdev = NULL; SK_GE_IOCTL Ioctl; unsigned int Err = 0; int Size = 0; @@ -3671,6 +3825,45 @@ int HeaderLength = sizeof(SK_U32) + siz fault_gen: kfree(pMemBuf); /* cleanup everything */ break; +#ifdef SK_DIAG_SUPPORT + case SK_IOCTL_DIAG: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) { + Length = Ioctl.Len; + } else { + Length = sizeof(pAC->PnmiStruct) + HeaderLength; + } + if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) { + return -ENOMEM; + } + if(copy_from_user(pMemBuf, Ioctl.pData, Length)) { + Err = -EFAULT; + goto fault_diag; + } + pdev = pAC->PciDev; + Length = 3 * sizeof(SK_U32); /* Error, Bus and Device */ + /* + ** While coding this new IOCTL interface, only a few lines of code + ** are to to be added. Therefore no dedicated function has been + ** added. If more functionality is added, a separate function + ** should be used... + */ + * ((SK_U32 *)pMemBuf) = 0; + * ((SK_U32 *)pMemBuf + 1) = pdev->bus->number; + * ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pdev->slot_name); + if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) { + Err = -EFAULT; + goto fault_diag; + } + Ioctl.Len = Length; + if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) { + Err = -EFAULT; + goto fault_diag; + } +fault_diag: + kfree(pMemBuf); /* cleanup everything */ + break; +#endif default: Err = -EOPNOTSUPP; } @@ -3826,10 +4019,9 @@ int Capabilities[3][3] = (strcmp(ConType[pAC->Index],"Auto")!=0) && (strcmp(ConType[pAC->Index],"")!=0)) { /* Set the speed parameter back */ - printk("%s: Illegal value \"%s\" " + printk("sk98lin: Illegal value \"%s\" " "for ConType." " Using Auto.\n", - pAC->dev[0]->name, ConType[pAC->Index]); sprintf(ConType[pAC->Index], "Auto"); @@ -3873,8 +4065,8 @@ int Capabilities[3][3] = M_CurrPort.PLinkSpeed = SK_LSPEED_10MBPS; } } else { - printk("%s: Illegal value \"%s\" for ConType\n", - pAC->dev[0]->name, ConType[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for ConType\n", + ConType[pAC->Index]); IsConTypeDefined = SK_FALSE; /* Wrong ConType defined */ } } else { @@ -3898,8 +4090,8 @@ int Capabilities[3][3] = } else if (strcmp(Speed_A[pAC->Index],"1000")==0) { LinkSpeed = SK_LSPEED_1000MBPS; } else { - printk("%s: Illegal value \"%s\" for Speed_A\n", - pAC->dev[0]->name, Speed_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Speed_A\n", + Speed_A[pAC->Index]); IsLinkSpeedDefined = SK_FALSE; } } else { @@ -3913,9 +4105,9 @@ int Capabilities[3][3] = if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) && ((LinkSpeed != SK_LSPEED_AUTO) && (LinkSpeed != SK_LSPEED_1000MBPS))) { - printk("%s: Illegal value for Speed_A. " + printk("sk98lin: Illegal value for Speed_A. " "Not a copper card or GE V2 card\n Using " - "speed 1000\n", pAC->dev[0]->name); + "speed 1000\n"); LinkSpeed = SK_LSPEED_1000MBPS; } @@ -3945,8 +4137,8 @@ int Capabilities[3][3] = } else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) { AutoNeg = AN_SENS; } else { - printk("%s: Illegal value \"%s\" for AutoNeg_A\n", - pAC->dev[0]->name, AutoNeg_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for AutoNeg_A\n", + AutoNeg_A[pAC->Index]); } } @@ -3964,33 +4156,32 @@ int Capabilities[3][3] = } else if (strcmp(DupCap_A[pAC->Index],"Half")==0) { DuplexCap = DC_HALF; } else { - printk("%s: Illegal value \"%s\" for DupCap_A\n", - pAC->dev[0]->name, DupCap_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for DupCap_A\n", + DupCap_A[pAC->Index]); } } - + /* ** Check for illegal combinations */ - if ((LinkSpeed = SK_LSPEED_1000MBPS) && + if ((LinkSpeed == SK_LSPEED_1000MBPS) && ((DuplexCap == SK_LMODE_STAT_AUTOHALF) || (DuplexCap == SK_LMODE_STAT_HALF)) && (pAC->ChipsetType)) { - printk("%s: Half Duplex not possible with Gigabit speed!\n" - " Using Full Duplex.\n", - pAC->dev[0]->name); + printk("sk98lin: Half Duplex not possible with Gigabit speed!\n" + " Using Full Duplex.\n"); DuplexCap = DC_FULL; } if ( AutoSet && AutoNeg==AN_SENS && DupSet) { - printk("%s, Port A: DuplexCapabilities" - " ignored using Sense mode\n", pAC->dev[0]->name); + printk("sk98lin, Port A: DuplexCapabilities" + " ignored using Sense mode\n"); } if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ - printk("%s, Port A: Illegal combination" + printk("sk98lin: Port A: Illegal combination" " of values AutoNeg. and DuplexCap.\n Using " - "Full Duplex\n", pAC->dev[0]->name); + "Full Duplex\n"); DuplexCap = DC_FULL; } @@ -3999,10 +4190,9 @@ int Capabilities[3][3] = } if (!AutoSet && DupSet) { - printk("%s, Port A: Duplex setting not" + printk("sk98lin: Port A: Duplex setting not" " possible in\n default AutoNegotiation mode" - " (Sense).\n Using AutoNegotiation On\n", - pAC->dev[0]->name); + " (Sense).\n Using AutoNegotiation On\n"); AutoNeg = AN_ON; } @@ -4029,8 +4219,8 @@ int Capabilities[3][3] = } else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) { FlowCtrl = SK_FLOW_MODE_NONE; } else { - printk("%s: Illegal value \"%s\" for FlowCtrl_A\n", - pAC->dev[0]->name, FlowCtrl_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for FlowCtrl_A\n", + FlowCtrl_A[pAC->Index]); IsFlowCtrlDefined = SK_FALSE; } } else { @@ -4039,9 +4229,9 @@ int Capabilities[3][3] = if (IsFlowCtrlDefined) { if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) { - printk("%s, Port A: FlowControl" + printk("sk98lin: Port A: FlowControl" " impossible without AutoNegotiation," - " disabled\n", pAC->dev[0]->name); + " disabled\n"); FlowCtrl = SK_FLOW_MODE_NONE; } pAC->GIni.GP[0].PFlowCtrlMode = FlowCtrl; @@ -4061,8 +4251,8 @@ int Capabilities[3][3] = } else if (strcmp(Role_A[pAC->Index],"Slave")==0) { MSMode = SK_MS_MODE_SLAVE; } else { - printk("%s: Illegal value \"%s\" for Role_A\n", - pAC->dev[0]->name, Role_A[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Role_A\n", + Role_A[pAC->Index]); IsRoleDefined = SK_FALSE; } } else { @@ -4097,8 +4287,8 @@ int Capabilities[3][3] = } else if (strcmp(Speed_B[pAC->Index],"1000")==0) { LinkSpeed = SK_LSPEED_1000MBPS; } else { - printk("%s: Illegal value \"%s\" for Speed_B\n", - pAC->dev[1]->name, Speed_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Speed_B\n", + Speed_B[pAC->Index]); IsLinkSpeedDefined = SK_FALSE; } } else { @@ -4112,9 +4302,9 @@ int Capabilities[3][3] = if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) && ((LinkSpeed != SK_LSPEED_AUTO) && (LinkSpeed != SK_LSPEED_1000MBPS))) { - printk("%s: Illegal value for Speed_B. " + printk("sk98lin: Illegal value for Speed_B. " "Not a copper card or GE V2 card\n Using " - "speed 1000\n", pAC->dev[1]->name); + "speed 1000\n"); LinkSpeed = SK_LSPEED_1000MBPS; } @@ -4144,8 +4334,8 @@ int Capabilities[3][3] = } else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) { AutoNeg = AN_SENS; } else { - printk("%s: Illegal value \"%s\" for AutoNeg_B\n", - pAC->dev[0]->name, AutoNeg_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for AutoNeg_B\n", + AutoNeg_B[pAC->Index]); } } @@ -4163,8 +4353,8 @@ int Capabilities[3][3] = } else if (strcmp(DupCap_B[pAC->Index],"Half")==0) { DuplexCap = DC_HALF; } else { - printk("%s: Illegal value \"%s\" for DupCap_B\n", - pAC->dev[0]->name, DupCap_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for DupCap_B\n", + DupCap_B[pAC->Index]); } } @@ -4172,25 +4362,24 @@ int Capabilities[3][3] = /* ** Check for illegal combinations */ - if ((LinkSpeed = SK_LSPEED_1000MBPS) && + if ((LinkSpeed == SK_LSPEED_1000MBPS) && ((DuplexCap == SK_LMODE_STAT_AUTOHALF) || (DuplexCap == SK_LMODE_STAT_HALF)) && (pAC->ChipsetType)) { - printk("%s: Half Duplex not possible with Gigabit speed!\n" - " Using Full Duplex.\n", - pAC->dev[1]->name); + printk("sk98lin: Half Duplex not possible with Gigabit speed!\n" + " Using Full Duplex.\n"); DuplexCap = DC_FULL; } if (AutoSet && AutoNeg==AN_SENS && DupSet) { - printk("%s, Port B: DuplexCapabilities" - " ignored using Sense mode\n", pAC->dev[1]->name); + printk("sk98lin, Port B: DuplexCapabilities" + " ignored using Sense mode\n"); } if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ - printk("%s, Port B: Illegal combination" + printk("sk98lin: Port B: Illegal combination" " of values AutoNeg. and DuplexCap.\n Using " - "Full Duplex\n", pAC->dev[1]->name); + "Full Duplex\n"); DuplexCap = DC_FULL; } @@ -4199,10 +4388,9 @@ int Capabilities[3][3] = } if (!AutoSet && DupSet) { - printk("%s, Port B: Duplex setting not" + printk("sk98lin: Port B: Duplex setting not" " possible in\n default AutoNegotiation mode" - " (Sense).\n Using AutoNegotiation On\n", - pAC->dev[1]->name); + " (Sense).\n Using AutoNegotiation On\n"); AutoNeg = AN_ON; } @@ -4229,8 +4417,8 @@ int Capabilities[3][3] = } else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) { FlowCtrl = SK_FLOW_MODE_NONE; } else { - printk("%s: Illegal value \"%s\" for FlowCtrl_B\n", - pAC->dev[0]->name, FlowCtrl_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for FlowCtrl_B\n", + FlowCtrl_B[pAC->Index]); IsFlowCtrlDefined = SK_FALSE; } } else { @@ -4239,9 +4427,9 @@ int Capabilities[3][3] = if (IsFlowCtrlDefined) { if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) { - printk("%s, Port B: FlowControl" + printk("sk98lin: Port B: FlowControl" " impossible without AutoNegotiation," - " disabled\n", pAC->dev[1]->name); + " disabled\n"); FlowCtrl = SK_FLOW_MODE_NONE; } pAC->GIni.GP[1].PFlowCtrlMode = FlowCtrl; @@ -4261,8 +4449,8 @@ int Capabilities[3][3] = } else if (strcmp(Role_B[pAC->Index],"Slave")==0) { MSMode = SK_MS_MODE_SLAVE; } else { - printk("%s: Illegal value \"%s\" for Role_B\n", - pAC->dev[1]->name, Role_B[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for Role_B\n", + Role_B[pAC->Index]); IsRoleDefined = SK_FALSE; } } else { @@ -4280,28 +4468,37 @@ int Capabilities[3][3] = if (PrefPort != NULL && pAC->IndexIndex] != NULL) { if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */ - pAC->ActivePort = 0; - pAC->Rlmt.Net[0].Preference = -1; /* auto */ - pAC->Rlmt.Net[0].PrefPort = 0; + pAC->ActivePort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; } else if (strcmp(PrefPort[pAC->Index],"A") == 0) { - /* - ** do not set ActivePort here, thus a port - ** switch is issued after net up. - */ - Port = 0; - pAC->Rlmt.Net[0].Preference = Port; - pAC->Rlmt.Net[0].PrefPort = Port; + /* + ** do not set ActivePort here, thus a port + ** switch is issued after net up. + */ + Port = 0; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; } else if (strcmp(PrefPort[pAC->Index],"B") == 0) { - /* - ** do not set ActivePort here, thus a port - ** switch is issued after net up. - */ - Port = 1; - pAC->Rlmt.Net[0].Preference = Port; - pAC->Rlmt.Net[0].PrefPort = Port; + /* + ** do not set ActivePort here, thus a port + ** switch is issued after net up. + */ + if (pAC->GIni.GIMacsFound == 1) { + printk("sk98lin: Illegal value \"B\" for PrefPort.\n" + " Port B not available on single port adapters.\n"); + + pAC->ActivePort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; + } else { + Port = 1; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; + } } else { - printk("%s: Illegal value \"%s\" for PrefPort\n", - pAC->dev[0]->name, PrefPort[pAC->Index]); + printk("sk98lin: Illegal value \"%s\" for PrefPort\n", + PrefPort[pAC->Index]); } } @@ -4325,9 +4522,9 @@ int Capabilities[3][3] = pAC->RlmtMode = SK_RLMT_CHECK_LINK; pAC->RlmtNets = 2; } else { - printk("%s: Illegal value \"%s\" for" + printk("sk98lin: Illegal value \"%s\" for" " RlmtMode, using default\n", - pAC->dev[0]->name, RlmtMode[pAC->Index]); + RlmtMode[pAC->Index]); pAC->RlmtMode = 0; } } else { @@ -4338,97 +4535,111 @@ int Capabilities[3][3] = ** Check the interrupt moderation parameters */ if (Moderation[pAC->Index] != NULL) { - if (strcmp(Moderation[pAC->Index], "Static") == 0) { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC; - } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC; - } else { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; - } + if (strcmp(Moderation[pAC->Index], "") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } else if (strcmp(Moderation[pAC->Index], "Static") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC; + } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC; + } else if (strcmp(Moderation[pAC->Index], "None") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } else { + printk("sk98lin: Illegal value \"%s\" for Moderation.\n" + " Disable interrupt moderation.\n", + Moderation[pAC->Index]); + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } } else { - pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; } if (Stats[pAC->Index] != NULL) { - if (strcmp(Stats[pAC->Index], "Yes") == 0) { - pAC->DynIrqModInfo.DisplayStats = SK_TRUE; - } else { - pAC->DynIrqModInfo.DisplayStats = SK_FALSE; - } + if (strcmp(Stats[pAC->Index], "Yes") == 0) { + pAC->DynIrqModInfo.DisplayStats = SK_TRUE; + } else { + pAC->DynIrqModInfo.DisplayStats = SK_FALSE; + } } else { - pAC->DynIrqModInfo.DisplayStats = SK_FALSE; + pAC->DynIrqModInfo.DisplayStats = SK_FALSE; } - if (ModerationMask[pAC->Index] != NULL) { - if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; - } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY; - } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY; - } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; - } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; - } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; - } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; - } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; - } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; - } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) { - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; - } else { /* some rubbish */ - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; - } - } else { /* operator has stated nothing */ - pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; - } - - if (AutoSizing[pAC->Index] != NULL) { - if (strcmp(AutoSizing[pAC->Index], "On") == 0) { - pAC->DynIrqModInfo.AutoSizing = SK_FALSE; - } else { - pAC->DynIrqModInfo.AutoSizing = SK_FALSE; - } - } else { /* operator has stated nothing */ - pAC->DynIrqModInfo.AutoSizing = SK_FALSE; - } + if (ModerationMask[pAC->Index] != NULL) { + if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; + } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; + } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; + } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; + } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else { /* some rubbish */ + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; + } + } else { /* operator has stated nothing */ + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } + + if (AutoSizing[pAC->Index] != NULL) { + if (strcmp(AutoSizing[pAC->Index], "On") == 0) { + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } else { + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } + } else { /* operator has stated nothing */ + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } - if (IntsPerSec[pAC->Index] != 0) { - if ((IntsPerSec[pAC->Index]< 30) || (IntsPerSec[pAC->Index]> 40000)) { - pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; - } else { - pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index]; - } - } else { - pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; - } + if (IntsPerSec[pAC->Index] != 0) { + if ((IntsPerSec[pAC->Index]< C_INT_MOD_IPS_LOWER_RANGE) || + (IntsPerSec[pAC->Index] > C_INT_MOD_IPS_UPPER_RANGE)) { + printk("sk98lin: Illegal value \"%d\" for IntsPerSec. (Range: %d - %d)\n" + " Using default value of %i.\n", + IntsPerSec[pAC->Index], + C_INT_MOD_IPS_LOWER_RANGE, + C_INT_MOD_IPS_UPPER_RANGE, + C_INTS_PER_SEC_DEFAULT); + pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; + } else { + pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index]; + } + } else { + pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; + } - /* + /* ** Evaluate upper and lower moderation threshold */ - pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit = - pAC->DynIrqModInfo.MaxModIntsPerSec + - (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); - - pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit = - pAC->DynIrqModInfo.MaxModIntsPerSec - - (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); + pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit = + pAC->DynIrqModInfo.MaxModIntsPerSec + + (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); + + pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit = + pAC->DynIrqModInfo.MaxModIntsPerSec - + (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); - pAC->DynIrqModInfo.PrevTimeVal = jiffies; /* initial value */ + pAC->DynIrqModInfo.PrevTimeVal = jiffies; /* initial value */ } /* GetConfiguration */ @@ -4826,6 +5037,10 @@ SK_BOOL DualNet; FromPort = Param.Para32[0]; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("NET UP EVENT, Port: %d ", Param.Para32[0])); + /* Mac update */ + SkAddrMcUpdate(pAC,IoC, FromPort); + + if (DoPrintInterfaceChange) { printk("%s: network connection up using" " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]); @@ -4841,8 +5056,6 @@ SK_BOOL DualNet; printk(" speed: unknown\n"); } - /* Mac update */ - SkAddrMcUpdate(pAC,IoC, FromPort); Stat = pAC->GIni.GP[FromPort].PLinkModeStatus; if (Stat == SK_LMODE_STAT_AUTOHALF || @@ -4920,6 +5133,9 @@ SK_BOOL DualNet; printk(" rx-checksum: disabled\n"); #endif + } else { + DoPrintInterfaceChange = SK_TRUE; + } if ((Param.Para32[0] != pAC->ActivePort) && (pAC->RlmtNets == 1)) { @@ -4937,7 +5153,12 @@ SK_BOOL DualNet; /* action list 7 */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("NET DOWN EVENT ")); - printk("%s: network connection down\n", pAC->dev[Param.Para32[1]]->name); + if (DoPrintInterfaceChange) { + printk("%s: network connection down\n", + pAC->dev[Param.Para32[1]]->name); + } else { + DoPrintInterfaceChange = SK_TRUE; + } pAC->dev[Param.Para32[1]]->flags &= ~IFF_RUNNING; break; case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ @@ -5122,6 +5343,231 @@ char ClassStr[80]; } /* SkErrorLog */ +#ifdef SK_DIAG_SUPPORT + +/***************************************************************************** + * + * SkDrvEnterDiagMode - handles DIAG attach request + * + * Description: + * Notify the kernel to NOT access the card any longer due to DIAG + * Deinitialize the Card + * + * Returns: + * int + */ +int SkDrvEnterDiagMode( +SK_AC *pAc) /* pointer to adapter context */ +{ + SK_AC *pAC = NULL; + DEV_NET *pNet = NULL; + + pNet = (DEV_NET *) pAc->dev[0]->priv; + pAC = pNet->pAC; + + SK_MEMCPY(&(pAc->PnmiBackup), &(pAc->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + + pAC->DiagModeActive = DIAG_ACTIVE; + if (pAC->BoardLevel > SK_INIT_DATA) { + if (pNet->Up) { + pAC->WasIfUp[0] = SK_TRUE; + pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */ + } else { + pAC->WasIfUp[0] = SK_FALSE; + } + if (pNet != (DEV_NET *) pAc->dev[1]->priv) { + pNet = (DEV_NET *) pAc->dev[1]->priv; + if (pNet->Up) { + pAC->WasIfUp[1] = SK_TRUE; + pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 1); /* do SkGeClose */ + } else { + pAC->WasIfUp[1] = SK_FALSE; + } + } + pAC->BoardLevel = SK_INIT_DATA; + } + return(0); +} + +/***************************************************************************** + * + * SkDrvLeaveDiagMode - handles DIAG detach request + * + * Description: + * Notify the kernel to may access the card again after use by DIAG + * Initialize the Card + * + * Returns: + * int + */ +int SkDrvLeaveDiagMode( +SK_AC *pAc) /* pointer to adapter control context */ +{ + SK_MEMCPY(&(pAc->PnmiStruct), &(pAc->PnmiBackup), + sizeof(SK_PNMI_STRUCT_DATA)); + pAc->DiagModeActive = DIAG_NOTACTIVE; + pAc->Pnmi.DiagAttached = SK_DIAG_IDLE; + if (pAc->WasIfUp[0] == SK_TRUE) { + pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAc, 0); /* first device */ + } + if (pAc->WasIfUp[1] == SK_TRUE) { + pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAc, 1); /* second device */ + } + return(0); +} + +/***************************************************************************** + * + * ParseDeviceNbrFromSlotName - Evaluate PCI device number + * + * Description: + * This function parses the PCI slot name information string and will + * retrieve the devcie number out of it. The slot_name maintianed by + * linux is in the form of '02:0a.0', whereas the first two characters + * represent the bus number in hex (in the sample above this is + * pci bus 0x02) and the next two characters the device number (0x0a). + * + * Returns: + * SK_U32: The device number from the PCI slot name + */ + +static SK_U32 ParseDeviceNbrFromSlotName( +const char *SlotName) /* pointer to pci slot name eg. '02:0a.0' */ +{ + char *CurrCharPos = (char *) SlotName; + int FirstNibble = -1; + int SecondNibble = -1; + SK_U32 Result = 0; + + while (*CurrCharPos != '\0') { + if (*CurrCharPos == ':') { + while (*CurrCharPos != '.') { + CurrCharPos++; + if ( (*CurrCharPos >= '0') && + (*CurrCharPos <= '9')) { + if (FirstNibble == -1) { + /* dec. value for '0' */ + FirstNibble = *CurrCharPos - 48; + } else { + SecondNibble = *CurrCharPos - 48; + } + } else if ( (*CurrCharPos >= 'a') && + (*CurrCharPos <= 'f') ) { + if (FirstNibble == -1) { + FirstNibble = *CurrCharPos - 87; + } else { + SecondNibble = *CurrCharPos - 87; + } + } else { + Result = 0; + } + } + + Result = FirstNibble; + Result = Result << 4; /* first nibble is higher one */ + Result = Result | SecondNibble; + } + CurrCharPos++; /* next character */ + } + return (Result); +} + +/**************************************************************************** + * + * SkDrvDeInitAdapter - deinitialize adapter (this function is only + * called if Diag attaches to that card) + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkDrvDeInitAdapter( +SK_AC *pAC, /* pointer to adapter context */ +int devNbr) /* what device is to be handled */ +{ + struct SK_NET_DEVICE *dev; + + dev = pAC->dev[devNbr]; + + /* + ** Function SkGeClose() uses MOD_DEC_USE_COUNT (2.2/2.4) + ** or module_put() (2.6) to decrease the number of users for + ** a device, but if a device is to be put under control of + ** the DIAG, that count is OK already and does not need to + ** be adapted! Hence the opposite MOD_INC_USE_COUNT or + ** try_module_get() needs to be used again to correct that. + */ + if (!try_module_get(THIS_MODULE)) { + return (-1); + } + + if (SkGeClose(dev) != 0) { + module_put(THIS_MODULE); + return (-1); + } + return (0); + +} /* SkDrvDeInitAdapter() */ + +/**************************************************************************** + * + * SkDrvInitAdapter - Initialize adapter (this function is only + * called if Diag deattaches from that card) + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkDrvInitAdapter( +SK_AC *pAC, /* pointer to adapter context */ +int devNbr) /* what device is to be handled */ +{ + struct SK_NET_DEVICE *dev; + + dev = pAC->dev[devNbr]; + + if (SkGeOpen(dev) != 0) { + return (-1); + } else { + /* + ** Function SkGeOpen() uses MOD_INC_USE_COUNT (2.2/2.4) + ** or try_module_get() (2.6) to increase the number of + ** users for a device, but if a device was just under + ** control of the DIAG, that count is OK already and + ** does not need to be adapted! Hence the opposite + ** MOD_DEC_USE_COUNT or module_put() needs to be used + ** again to correct that. + */ + module_put(THIS_MODULE); + } + + /* + ** Use correct MTU size and indicate to kernel TX queue can be started + */ + if (SkGeChangeMtu(dev, dev->mtu) != 0) { + return (-1); + } + return (0); + +} /* SkDrvInitAdapter */ + +#endif + #ifdef DEBUG /****************************************************************************/ /* "debug only" section *****************************************************/ --- linux-2.6.1-rc1/drivers/net/sk98lin/skgehwt.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skgehwt.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,10 +1,10 @@ /****************************************************************************** * * Name: skgehwt.c - * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.14 $ - * Date: $Date: 2003/05/13 18:01:58 $ - * Purpose: Hardware Timer. + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.15 $ + * Date: $Date: 2003/09/16 13:41:23 $ + * Purpose: Hardware Timer * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: skgehwt.c,v $ + * Revision 1.15 2003/09/16 13:41:23 rschmidt + * Added (C) Marvell to SysKonnectFileId + * Editorial changes + * * Revision 1.14 2003/05/13 18:01:58 mkarl * Editorial changes. * @@ -69,19 +73,15 @@ * * Revision 1.1 1998/08/05 11:28:36 gklug * first version: adapted from SMT/FDDI - * - * - * * ******************************************************************************/ - /* - Event queue and dispatcher -*/ + * Event queue and dispatcher + */ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.14 2003/05/13 18:01:58 mkarl Exp $" ; + "@(#) $Id: skgehwt.c,v 1.15 2003/09/16 13:41:23 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -89,10 +89,7 @@ static const char SysKonnectFileId[] = #ifdef __C2MAN__ /* - Hardware Timer function queue management. - - General Description: - + * Hardware Timer function queue management. */ intro() {} @@ -117,9 +114,9 @@ SK_IOC Ioc) /* IoContext */ { pAC->Hwt.TStart = 0 ; pAC->Hwt.TStop = 0 ; - pAC->Hwt.TActive = SK_FALSE ; + pAC->Hwt.TActive = SK_FALSE; - SkHwtStop(pAC,Ioc) ; + SkHwtStop(pAC, Ioc); } /* @@ -132,28 +129,29 @@ SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ SK_U32 Time) /* Time in units of 16us to load the timer with. */ { - SK_U32 Cnt ; + SK_U32 Cnt; if (Time > SK_HWT_MAX) - Time = SK_HWT_MAX ; + Time = SK_HWT_MAX; - pAC->Hwt.TStart = Time ; - pAC->Hwt.TStop = 0L ; + pAC->Hwt.TStart = Time; + pAC->Hwt.TStop = 0L; - Cnt = Time ; + Cnt = Time; /* * if time < 16 us * time = 16 us */ if (!Cnt) { - Cnt++ ; + Cnt++; } - SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC) ; - SK_OUT16(Ioc, B2_TI_CRTL, TIM_START) ; /* Start timer. */ + SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC); + + SK_OUT16(Ioc, B2_TI_CTRL, TIM_START); /* Start timer. */ - pAC->Hwt.TActive = SK_TRUE ; + pAC->Hwt.TActive = SK_TRUE; } /* @@ -164,10 +162,11 @@ void SkHwtStop( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - SK_OUT16(Ioc, B2_TI_CRTL, TIM_STOP) ; - SK_OUT16(Ioc, B2_TI_CRTL, TIM_CLR_IRQ) ; + SK_OUT16(Ioc, B2_TI_CTRL, TIM_STOP); + + SK_OUT16(Ioc, B2_TI_CTRL, TIM_CLR_IRQ); - pAC->Hwt.TActive = SK_FALSE ; + pAC->Hwt.TActive = SK_FALSE; } @@ -182,26 +181,31 @@ SK_U32 SkHwtRead( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - SK_U32 TRead ; - SK_U32 IStatus ; + SK_U32 TRead; + SK_U32 IStatus; if (pAC->Hwt.TActive) { - SkHwtStop(pAC,Ioc) ; + + SkHwtStop(pAC, Ioc); SK_IN32(Ioc, B2_TI_VAL, &TRead); TRead /= SK_HWT_FAC; SK_IN32(Ioc, B0_ISRC, &IStatus); - /* Check if timer expired (or wraparound). */ + /* Check if timer expired (or wraped around) */ if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) { - SkHwtStop(pAC,Ioc) ; - pAC->Hwt.TStop = pAC->Hwt.TStart ; - } else { - pAC->Hwt.TStop = pAC->Hwt.TStart - TRead ; + + SkHwtStop(pAC, Ioc); + + pAC->Hwt.TStop = pAC->Hwt.TStart; + } + else { + + pAC->Hwt.TStop = pAC->Hwt.TStart - TRead; } } - return (pAC->Hwt.TStop) ; + return(pAC->Hwt.TStop); } /* @@ -211,9 +215,11 @@ void SkHwtIsr( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - SkHwtStop(pAC,Ioc); + SkHwtStop(pAC, Ioc); + pAC->Hwt.TStop = pAC->Hwt.TStart; - SkTimerDone(pAC,Ioc) ; + + SkTimerDone(pAC, Ioc); } /* End of file */ --- linux-2.6.1-rc1/drivers/net/sk98lin/skgeinit.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skgeinit.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgeinit.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.93 $ - * Date: $Date: 2003/05/28 15:44:43 $ + * Version: $Revision: 1.97 $ + * Date: $Date: 2003/10/02 16:45:31 $ * Purpose: Contains functions to initialize the adapter * ******************************************************************************/ @@ -27,6 +27,32 @@ * History: * * $Log: skgeinit.c,v $ + * Revision 1.97 2003/10/02 16:45:31 rschmidt + * Replaced default values of GMAC parameters with defines. + * Removed hard reset of MACs in SkGeDeInit(). + * Added define SK_PHY_LP_MODE around power saving mode in SkGeDeInit(). + * Added check for VAUX available before switch power to VAUX. + * + * Revision 1.96 2003/09/18 14:02:41 rroesler + * Add: Perform a hardreset of MACs in GeDeInit() + * + * Revision 1.95 2003/09/16 14:26:59 rschmidt + * Added switch power to VCC (WA for VAUX problem) in SkGeInit1(). + * Fixed setting PHY to coma mode and D3 power state in SkGeDeInit(). + * Editorial changes. + * + * Revision 1.94 2003/09/16 07:17:10 mschmid + * Added init for new members in port structure for MAC control + * - PMacColThres + * - PMacJamLen + * - PMacJamIpgVal + * - PMacJamIpgData + * - PMacIpgData + * - PMacLimit4 + * Added init for PHY power state in port structure + * - PPhyPowerState + * Added shutdown handling for Yukon Plus in SkGeDeInit() + * * Revision 1.93 2003/05/28 15:44:43 rschmidt * Added check for chip Id on WOL WA for chip Rev. A. * Added setting of GILevel in SkGeDeInit(). @@ -446,7 +472,7 @@ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "@(#) $Id: skgeinit.c,v 1.93 2003/05/28 15:44:43 rschmidt Exp $ (C) Marvell."; + "@(#) $Id: skgeinit.c,v 1.97 2003/10/02 16:45:31 rschmidt Exp $ (C) Marvell."; #endif struct s_QOffTab { @@ -1013,8 +1039,6 @@ int Port) /* Port Index (MAC_1 + n) */ * - enable the FIFO */ - Word = (SK_U16)GMF_RX_CTRL_DEF; - #ifdef GENESIS if (pAC->GIni.GIGenesis) { /* Configure Rx MAC FIFO */ @@ -1039,6 +1063,8 @@ int Port) /* Port Index (MAC_1 + n) */ /* set Rx GMAC FIFO Flush Mask */ SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK); + Word = (SK_U16)GMF_RX_CTRL_DEF; + /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */ if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) { @@ -1809,6 +1835,13 @@ SK_IOC IoC) /* IO context */ pPrt->PAutoNegFail = SK_FALSE; pPrt->PHWLinkUp = SK_FALSE; pPrt->PLinkBroken = SK_TRUE; /* See WA code */ + pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE; + pPrt->PMacColThres = TX_COL_DEF; + pPrt->PMacJamLen = TX_JAM_LEN_DEF; + pPrt->PMacJamIpgVal = TX_JAM_IPG_DEF; + pPrt->PMacJamIpgData = TX_IPG_JAM_DEF; + pPrt->PMacIpgData = IPG_DATA_DEF; + pPrt->PMacLimit4 = SK_FALSE; } pAC->GIni.GIPortUsage = SK_RED_LINK; @@ -1963,7 +1996,7 @@ SK_IOC IoC) /* IO context */ /* restore CLK_RUN bits */ SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat & (CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA))); - + /* read Chip Identification Number */ SK_IN8(IoC, B2_CHIP_ID, &Byte); pAC->GIni.GIChipId = Byte; @@ -2053,6 +2086,10 @@ SK_IOC IoC) /* IO context */ } } + /* switch power to VCC (WA for VAUX problem) */ + SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA | + PC_VAUX_OFF | PC_VCC_ON)); + /* read the Interrupt source */ SK_IN32(IoC, B0_ISRC, &DWord); @@ -2395,6 +2432,11 @@ SK_IOC IoC) /* IO context */ int i; SK_U16 Word; +#ifdef SK_PHY_LP_MODE + SK_U8 Byte; + SK_U16 PmCtlSts; +#endif /* SK_PHY_LP_MODE */ + #if (!defined(SK_SLIM) && !defined(VCPU)) /* ensure I2C is ready */ SkI2cWaitIrq(pAC, IoC); @@ -2409,6 +2451,38 @@ SK_IOC IoC) /* IO context */ } } +#ifdef SK_PHY_LP_MODE + /* + * for power saving purposes within mobile environments + * we set the PHY to coma mode and switch to D3 power state. + */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + /* for all ports switch PHY to coma mode */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + + SkGmEnterLowPowerMode(pAC, IoC, i, PHY_PM_DEEP_SLEEP); + } + + if (pAC->GIni.GIVauxAvail) { + /* switch power to VAUX */ + Byte = PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF; + + SK_OUT8(IoC, B0_POWER_CTRL, Byte); + } + + /* switch to D3 state */ + SK_IN16(IoC, PCI_C(PCI_PM_CTL_STS), &PmCtlSts); + + PmCtlSts |= PCI_PM_STATE_D3; + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + SK_OUT16(IoC, PCI_C(PCI_PM_CTL_STS), PmCtlSts); + } +#endif /* SK_PHY_LP_MODE */ + /* Reset all bits in the PCI STATUS register */ /* * Note: PCI Cfg cycles cannot be used, because they are not --- linux-2.6.1-rc1/drivers/net/sk98lin/skgemib.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skgemib.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgemib.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.9 $ - * Date: $Date: 2003/05/23 12:55:20 $ + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/09/15 13:38:12 $ * Purpose: Private Network Management Interface Management Database * ****************************************************************************/ @@ -27,6 +27,19 @@ * History: * * $Log: skgemib.c,v $ + * Revision 1.11 2003/09/15 13:38:12 tschilli + * OID_SKGE_PHY_LP_MODE included only after using #define SK_PHY_LP_MODE. + * + * Revision 1.10 2003/08/15 12:28:59 tschilli + * Added new OIDs: + * OID_SKGE_DRIVER_RELDATE + * OID_SKGE_DRIVER_FILENAME + * OID_SKGE_CHIPID + * OID_SKGE_RAMSIZE + * OID_SKGE_VAUXAVAIL + * OID_SKGE_PHY_TYPE + * OID_SKGE_PHY_LP_MODE + * * Revision 1.9 2003/05/23 12:55:20 tschilli * OID_SKGE_BOARDLEVEL added. * @@ -356,6 +369,16 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTa 0, SK_PNMI_MAI_OFF(DriverVersion), SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_RELDATE, + 1, + 0, + SK_PNMI_MAI_OFF(DriverReleaseDate), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_FILENAME, + 1, + 0, + SK_PNMI_MAI_OFF(DriverFileName), + SK_PNMI_RO, General, 0}, {OID_SKGE_HW_DESCR, 1, 0, @@ -371,6 +394,21 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTa 0, SK_PNMI_MAI_OFF(Chipset), SK_PNMI_RO, General, 0}, + {OID_SKGE_CHIPID, + 1, + 0, + SK_PNMI_MAI_OFF(ChipId), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RAMSIZE, + 1, + 0, + SK_PNMI_MAI_OFF(RamSize), + SK_PNMI_RO, General, 0}, + {OID_SKGE_VAUXAVAIL, + 1, + 0, + SK_PNMI_MAI_OFF(VauxAvail), + SK_PNMI_RO, General, 0}, {OID_SKGE_ACTION, 1, 0, @@ -876,6 +914,18 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTa sizeof(SK_PNMI_CONF), SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector), SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_PHY_TYPE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType), + SK_PNMI_RO, MacPrivateConf, 0}, +#ifdef SK_PHY_LP_MODE + {OID_SKGE_PHY_LP_MODE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyMode), + SK_PNMI_RW, MacPrivateConf, 0}, +#endif {OID_SKGE_LINK_CAP, SK_PNMI_MAC_ENTRIES, sizeof(SK_PNMI_CONF), --- linux-2.6.1-rc1/drivers/net/sk98lin/skgepnmi.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skgepnmi.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgepnmi.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.109 $ - * Date: $Date: 2003/07/17 14:15:24 $ + * Version: $Revision: 1.111 $ + * Date: $Date: 2003/09/15 13:35:35 $ * Purpose: Private Network Management Interface * ****************************************************************************/ @@ -27,6 +27,22 @@ * History: * * $Log: skgepnmi.c,v $ + * Revision 1.111 2003/09/15 13:35:35 tschilli + * Code for OID_SKGE_PHY_LP_MODE completed (using #define SK_PHY_LP_MODE). + * SK_DIAG_ATTACHED handling for OID_SKGE_DIAG_MODE in DiagActions() changed. + * + * Revision 1.110 2003/08/15 12:28:04 tschilli + * Added new OIDs: + * OID_SKGE_DRIVER_RELDATE + * OID_SKGE_DRIVER_FILENAME + * OID_SKGE_CHIPID + * OID_SKGE_RAMSIZE + * OID_SKGE_VAUXAVAIL + * OID_SKGE_PHY_TYPE + * OID_SKGE_PHY_LP_MODE + * + * Added SK_DIAG_ATTACHED handling for OID_SKGE_DIAG_MODE in DiagActions(). + * * Revision 1.109 2003/07/17 14:15:24 tschilli * Bug in SkPnmiGenIoctl() fixed. * @@ -471,7 +487,7 @@ #ifndef _lint static const char SysKonnectFileId[] = - "@(#) $Id: skgepnmi.c,v 1.109 2003/07/17 14:15:24 tschilli Exp $ (C) Marvell."; + "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell."; #endif /* !_lint */ #include "h/skdrv1st.h" @@ -4008,14 +4024,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in #endif /* SK_NDIS_64BIT_CTR */ break; - case OID_SKGE_BOARDLEVEL: - if (*pLen < sizeof(SK_U32)) { - - *pLen = sizeof(SK_U32); - return (SK_PNMI_ERR_TOO_SHORT); - } - break; - case OID_SKGE_PORT_NUMBER: case OID_SKGE_DEVICE_TYPE: case OID_SKGE_RESULT: @@ -4023,6 +4031,9 @@ SK_U32 NetIndex) /* NetIndex (0..n), in case OID_GEN_TRANSMIT_QUEUE_LENGTH: case OID_SKGE_TRAP_NUMBER: case OID_SKGE_MDB_VERSION: + case OID_SKGE_BOARDLEVEL: + case OID_SKGE_CHIPID: + case OID_SKGE_RAMSIZE: if (*pLen < sizeof(SK_U32)) { *pLen = sizeof(SK_U32); @@ -4043,6 +4054,7 @@ SK_U32 NetIndex) /* NetIndex (0..n), in case OID_SKGE_BUS_WIDTH: case OID_SKGE_SENSOR_NUMBER: case OID_SKGE_CHKSM_NUMBER: + case OID_SKGE_VAUXAVAIL: if (*pLen < sizeof(SK_U8)) { *pLen = sizeof(SK_U8); @@ -4234,6 +4246,66 @@ SK_U32 NetIndex) /* NetIndex (0..n), in *pLen = Len; break; + case OID_SKGE_DRIVER_RELDATE: + if (pAC->Pnmi.pDriverReleaseDate == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR053MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR054MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_DRIVER_FILENAME: + if (pAC->Pnmi.pDriverFileName == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR055MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR056MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1); + *pLen = Len; + break; + case OID_SKGE_HW_DESCR: /* * The hardware description is located in the VPD. This @@ -4291,8 +4363,25 @@ SK_U32 NetIndex) /* NetIndex (0..n), in *pLen = sizeof(SK_U16); break; + case OID_SKGE_CHIPID: + Val32 = pAC->GIni.GIChipId; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_RAMSIZE: + Val32 = pAC->GIni.GIRamSize; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_VAUXAVAIL: + *pBuf = (char) pAC->GIni.GIVauxAvail; + *pLen = sizeof(char); + break; + case OID_SKGE_BUS_TYPE: - *pBuf = (char)SK_PNMI_BUS_PCI; + *pBuf = (char) SK_PNMI_BUS_PCI; *pLen = sizeof(char); break; @@ -5435,6 +5524,9 @@ SK_U32 NetIndex) /* NetIndex (0..n), in case OID_SKGE_SPEED_CAP: case OID_SKGE_SPEED_MODE: case OID_SKGE_SPEED_STATUS: +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: +#endif if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) { *pLen = (Limit - LogPortIndex) * sizeof(SK_U8); @@ -5443,6 +5535,7 @@ SK_U32 NetIndex) /* NetIndex (0..n), in break; case OID_SKGE_MTU: + case OID_SKGE_PHY_TYPE: if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) { *pLen = (Limit - LogPortIndex) * sizeof(SK_U32); @@ -5488,6 +5581,49 @@ SK_U32 NetIndex) /* NetIndex (0..n), in Offset += sizeof(char); break; + case OID_SKGE_PHY_TYPE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + continue; + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + Val32 = pAC->GIni.GP[PhysPortIndex].PhyType; + SK_PNMI_STORE_U32(pBufPtr, Val32); + } + } + else { /* DualNetMode */ + + Val32 = pAC->GIni.GP[NetIndex].PhyType; + SK_PNMI_STORE_U32(pBufPtr, Val32); + } + Offset += sizeof(SK_U32); + break; + +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + continue; + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState; + *pBufPtr = Val8; + } + } + else { /* DualNetMode */ + + Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState; + *pBufPtr = Val8; + } + Offset += sizeof(SK_U8); + break; +#endif + case OID_SKGE_LINK_CAP: if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ if (LogPortIndex == 0) { @@ -5804,6 +5940,16 @@ SK_U32 NetIndex) /* NetIndex (0..n), in } break; +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: + if (*pLen < Limit - LogPortIndex) { + + *pLen = Limit - LogPortIndex; + return (SK_PNMI_ERR_TOO_SHORT); + } + break; +#endif + case OID_SKGE_MTU: if (*pLen < sizeof(SK_U32)) { @@ -6160,6 +6306,116 @@ SK_U32 NetIndex) /* NetIndex (0..n), in Offset += sizeof(SK_U32); break; + +#ifdef SK_PHY_LP_MODE + case OID_SKGE_PHY_LP_MODE: + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + Offset = 0; + continue; + } + else { + /* Set value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + + switch (*(pBuf + Offset)) { + case 0: + /* If LowPowerMode is active, we can leave it. */ + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex); + + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3) { + + SkDrvInitAdapter(pAC); + } + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + case 1: + case 2: + case 3: + case 4: + /* If no LowPowerMode is active, we can enter it. */ + if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + if ((*(pBuf + Offset)) < 3) { + + SkDrvDeInitAdapter(pAC); + } + + Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf); + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + default: + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + } + } + else { /* DualNetMode */ + + switch (*(pBuf + Offset)) { + case 0: + /* If we are in a LowPowerMode, we can leave it. */ + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex); + + if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3) { + + SkDrvInitAdapter(pAC); + } + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + case 1: + case 2: + case 3: + case 4: + /* If we are not already in LowPowerMode, we can enter it. */ + if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { + + if ((*(pBuf + Offset)) < 3) { + + SkDrvDeInitAdapter(pAC); + } + else { + + Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf); + } + break; + } + else { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + default: + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + } + Offset += sizeof(SK_U8); + break; +#endif default: SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, @@ -6318,6 +6574,7 @@ char *pBuf) /* Buffer used for the mana unsigned int PhysPortMax; unsigned int PhysPortIndex; SK_U8 Val8; + SK_U32 Val32; SK_BOOL PortActiveFlag; SK_GEPORT *pPrt; @@ -6340,6 +6597,14 @@ char *pBuf) /* Buffer used for the mana switch (Id) { + case OID_SKGE_PHY_TYPE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + Val32 = pPrt->PhyType; + SK_PNMI_STORE_U32(pBuf, Val32); + continue; + } + case OID_SKGE_LINK_CAP: /* @@ -7974,6 +8239,7 @@ unsigned int TableIndex, /* Index to the SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ { + SK_U32 DiagStatus; SK_U32 RetCode = SK_PNMI_ERR_GENERAL; /* @@ -8012,7 +8278,8 @@ SK_U32 NetIndex) /* NetIndex (0..n), in switch (Id) { case OID_SKGE_DIAG_MODE: - SK_PNMI_STORE_U32(pBuf, pAC->DiagModeActive); + DiagStatus = pAC->Pnmi.DiagAttached; + SK_PNMI_STORE_U32(pBuf, DiagStatus); *pLen = sizeof(SK_U32); RetCode = SK_PNMI_ERR_OK; break; @@ -8022,7 +8289,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in RetCode = SK_PNMI_ERR_GENERAL; break; } - return (RetCode); } @@ -8039,23 +8305,84 @@ SK_U32 NetIndex) /* NetIndex (0..n), in /* Handle the SET. */ switch (*pBuf) { - + + /* Attach the DIAG to this adapter. */ + case SK_DIAG_ATTACHED: + /* Check if we come from running */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + + RetCode = SkDrvLeaveDiagMode(pAC); + + } + else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) { + + RetCode = SK_PNMI_ERR_OK; + } + + else { + + RetCode = SK_PNMI_ERR_GENERAL; + + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED; + } + break; + /* Enter the DIAG mode in the driver. */ - case 1: - /* If DiagMode is not active, we can enter it. */ - if (!pAC->DiagModeActive) { + case SK_DIAG_RUNNING: + RetCode = SK_PNMI_ERR_OK; + + /* + * If DiagAttached is set, we can tell the driver + * to enter the DIAG mode. + */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) { + /* If DiagMode is not active, we can enter it. */ + if (!pAC->DiagModeActive) { - RetCode = SkDrvEnterDiagMode(pAC); + RetCode = SkDrvEnterDiagMode(pAC); + } + else { + + RetCode = SK_PNMI_ERR_GENERAL; + } } else { RetCode = SK_PNMI_ERR_GENERAL; } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING; + } break; - /* Leave the DIAG mode in the driver. */ - case 0: - RetCode = SkDrvLeaveDiagMode(pAC); + case SK_DIAG_IDLE: + /* Check if we come from running */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + + RetCode = SkDrvLeaveDiagMode(pAC); + + } + else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) { + + RetCode = SK_PNMI_ERR_OK; + } + + else { + + RetCode = SK_PNMI_ERR_GENERAL; + + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_IDLE; + } break; default: --- linux-2.6.1-rc1/drivers/net/sk98lin/skgesirq.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skgesirq.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skgesirq.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.91 $ - * Date: $Date: 2003/07/04 12:46:22 $ + * Version: $Revision: 1.92 $ + * Date: $Date: 2003/09/16 14:37:07 $ * Purpose: Special IRQ module * ******************************************************************************/ @@ -27,6 +27,12 @@ * History: * * $Log: skgesirq.c,v $ + * Revision 1.92 2003/09/16 14:37:07 rschmidt + * Added debug messages in some SkGePortCheckUp...() routines. + * Fixed compiler warnings for different types. + * Avoided port check up in reset state (eg. coma mode). + * Editorial changes. + * * Revision 1.91 2003/07/04 12:46:22 rschmidt * Added debug messages in SkGePortCheckUpGmac(). * Added error log message and new driver event SK_DRV_DOWNSHIFT_DET @@ -410,7 +416,7 @@ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "@(#) $Id: skgesirq.c,v 1.91 2003/07/04 12:46:22 rschmidt Exp $ (C) Marvell."; + "@(#) $Id: skgesirq.c,v 1.92 2003/09/16 14:37:07 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -490,7 +496,7 @@ int Port) /* Port Index (MAC_1 + n) */ ("AutoSensing: First mode %d on Port %d\n", (int)SK_LMODE_AUTOFULL, Port)); - pPrt->PLinkMode = SK_LMODE_AUTOFULL; + pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL; return; } /* SkHWInitDefSense */ @@ -606,7 +612,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* Reset Port stati */ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE; - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_INDETERMINATED; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED; /* Re-init Phy especially when the AutoSense default is set now */ SkMacInitPhy(pAC, IoC, Port, SK_FALSE); @@ -655,19 +661,19 @@ int Port) /* Port Index (MAC_1 + n) */ case SK_LSPEED_AUTO: /* default is 1000 Mbps */ case SK_LSPEED_1000MBPS: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; break; case SK_LSPEED_100MBPS: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; break; case SK_LSPEED_10MBPS: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; break; } /* Set Link Mode Status */ if (pPrt->PLinkMode == SK_LMODE_FULL) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_FULL; } else { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF; @@ -1598,8 +1604,7 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation * (clear Page Received bit if set) */ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat); - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); + return(SK_HW_PS_LINK); } @@ -1870,7 +1875,7 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg: %d, PhyStat: 0x%04X\n", AutoNeg, PhyStat)); + ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat)); SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); @@ -1897,8 +1902,11 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation if (AutoNeg) { if ((PhyStat & PHY_ST_AN_OVER) != 0) { + SkHWLinkUp(pAC, IoC, Port); + Done = SkMacAutoNegDone(pAC, IoC, Port); + if (Done != SK_AND_OK) { #ifdef DEBUG /* Get PHY parameters, for debugging only */ @@ -1924,9 +1932,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation (void *)NULL); } #endif /* DEBUG */ - - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); return(SK_HW_PS_LINK); } } @@ -1989,9 +1994,22 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation SK_U16 PhySpecStat;/* PHY Specific Status */ SK_U16 ResAb; /* Master/Slave resolution */ SK_EVPARA Para; +#ifdef DEBUG + SK_U16 Word; /* I/O helper */ +#endif /* DEBUG */ pPrt = &pAC->GIni.GP[Port]; + if (pPrt->PHWLinkUp) { + return(SK_HW_PS_NONE); + } + + /* Read PHY Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat)); + /* Read PHY Interrupt Status */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc); @@ -2005,16 +2023,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation ("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc)); } - if (pPrt->PHWLinkUp) { - return(SK_HW_PS_NONE); - } - - /* Read PHY Status */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); - - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg: %d, PhyStat: 0x%04X\n", AutoNeg, PhyStat)); - SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb); @@ -2034,7 +2042,20 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg: %d, PhySpecStat: 0x%04X\n", AutoNeg, PhySpecStat)); + ("Phy1000BT: 0x%04X, PhySpecStat: 0x%04X\n", ResAb, PhySpecStat)); + +#ifdef DEBUG + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &Word); + + if ((PhyIsrc & PHY_M_IS_AN_PR) != 0 || (Word & PHY_ANE_RX_PG) != 0 || + (PhySpecStat & PHY_M_PS_PAGE_REC) != 0) { + /* Read PHY Next Page Link Partner */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_NEPG_LP, &Word); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Page Received, NextPage: 0x%04X\n", Word)); + } +#endif /* DEBUG */ if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) { return(SK_HW_PS_NONE); @@ -2069,8 +2090,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation return(SK_HW_PS_RESTART); } - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); return(SK_HW_PS_LINK); } } @@ -2179,8 +2198,6 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation * extra link down/ups */ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat); - SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("AutoNeg done Port %d\n", Port)); return(SK_HW_PS_LINK); } } @@ -2278,8 +2295,14 @@ SK_EVPARA Para) /* Event specific Param switch (Event) { case SK_HWEV_WATIM: - /* Check whether port came up */ - PortStat = SkGePortCheckUp(pAC, IoC, (int)Port); + if (pPrt->PState == SK_PRT_RESET) { + + PortStat = SK_HW_PS_NONE; + } + else { + /* Check whether port came up */ + PortStat = SkGePortCheckUp(pAC, IoC, (int)Port); + } switch (PortStat) { case SK_HW_PS_RESTART: --- linux-2.6.1-rc1/drivers/net/sk98lin/ski2c.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/ski2c.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: ski2c.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.57 $ - * Date: $Date: 2003/01/28 09:17:38 $ + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.59 $ + * Date: $Date: 2003/10/20 09:07:25 $ * Purpose: Functions to access Voltage and Temperature Sensor * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,6 +27,14 @@ * History: * * $Log: ski2c.c,v $ + * Revision 1.59 2003/10/20 09:07:25 rschmidt + * Added cast SK_U32 in SkI2cWrite() to avoid compiler warning. + * Editorial changes. + * + * Revision 1.58 2003/09/23 09:22:53 malthoff + * Parameter I2cDevSize added in SkI2cRead and SkI2cWrite to + * support larger devices on the TWSI bus. + * * Revision 1.57 2003/01/28 09:17:38 rschmidt * Fixed handling for sensors on YUKON Fiber. * Editorial changes. @@ -224,15 +233,15 @@ * Created. Sources taken from ML Projekt. * Sources have to be reworked for GE. * - * ******************************************************************************/ - /* * I2C Protocol */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Id: ski2c.c,v 1.57 2003/01/28 09:17:38 rschmidt Exp $"; + "@(#) $Id: ski2c.c,v 1.59 2003/10/20 09:07:25 rschmidt Exp $ (C) Marvell. "; +#endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" @@ -312,7 +321,7 @@ intro() {} #endif -#ifdef SK_DIAG +#ifdef SK_DIAG /* * I2C Fast Mode timing values used by the LM80. * If new devices are added to the I2C bus the timing values have to be checked. @@ -516,7 +525,6 @@ SK_IOC IoC) /* I/O Context */ { /* * Received bit must be zero. - * */ SkI2cSndBit(IoC, 0); } /* SkI2cSndAck */ @@ -590,7 +598,7 @@ int Rw) /* Read / Write Flag */ return(SkI2cSndByte(IoC, (Addr<<1) | Rw)); } /* SkI2cSndDev */ -#endif /* SK_DIAG */ +#endif /* SK_DIAG */ /*----------------- I2C CTRL Register Functions ----------*/ @@ -620,7 +628,7 @@ int Event) /* complete event to wait fo SK_I2C_STOP(IoC); #ifndef SK_DIAG SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ return(1); } @@ -661,15 +669,19 @@ SK_IOC IoC) /* I/O Context */ } StartTime = SkOsGetTime(pAC); + do { if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { + SK_I2C_STOP(IoC); #ifndef SK_DIAG SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG); -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ return; } + SK_IN32(IoC, B0_ISRC, &IrqSrc); + } while ((IrqSrc & IS_I2C_READY) == 0); pSen->SenState = SK_SEN_IDLE; @@ -687,18 +699,19 @@ SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 I2cData, /* I2C Data to write */ int I2cDev, /* I2C Device Address */ +int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */ int I2cReg, /* I2C Device Register Address */ int I2cBurst) /* I2C Burst Flag */ { SK_OUT32(IoC, B2_I2C_DATA, I2cData); - SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cReg, I2cBurst); + + SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cDevSize, I2cReg, I2cBurst); return(SkI2cWait(pAC, IoC, I2C_WRITE)); } /* SkI2cWrite*/ #ifdef SK_DIAG - /* * reads a single byte or 4 bytes from the I2C device * @@ -708,23 +721,24 @@ SK_U32 SkI2cRead( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int I2cDev, /* I2C Device Address */ +int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */ int I2cReg, /* I2C Device Register Address */ int I2cBurst) /* I2C Burst Flag */ { SK_U32 Data; SK_OUT32(IoC, B2_I2C_DATA, 0); - SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cReg, I2cBurst); + SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cDevSize, I2cReg, I2cBurst); if (SkI2cWait(pAC, IoC, I2C_READ) != 0) { w_print("%s\n", SKERR_I2C_E002MSG); } SK_IN32(IoC, B2_I2C_DATA, &Data); + return(Data); } /* SkI2cRead */ - -#endif /* SK_DIAG */ +#endif /* SK_DIAG */ /* @@ -745,9 +759,10 @@ SK_SENSOR *pSen) /* Sensor to be read */ if (pSen->SenRead != NULL) { return((*pSen->SenRead)(pAC, IoC, pSen)); } - else + else { return(0); /* no success */ -} /* SkI2cReadSensor*/ + } +} /* SkI2cReadSensor */ /* * Do the Init state 0 initialization @@ -761,12 +776,12 @@ SK_AC *pAC) /* Adapter Context */ pAC->I2c.CurrSens = 0; /* Begin with timeout control for state machine */ - pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE; + pAC->I2c.TimerMode = SK_TIMER_WATCH_SM; /* Set sensor number to zero */ pAC->I2c.MaxSens = 0; -#ifndef SK_DIAG +#ifndef SK_DIAG /* Initialize Number of Dummy Reads */ pAC->I2c.DummyReads = SK_MAX_SENSORS; #endif @@ -840,19 +855,20 @@ SK_IOC IoC) /* I/O Context */ } /* Check for 64 Bit Yukon without sensors */ - if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_CFG, 0) != 0) { + if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_CFG, 0) != 0) { return(0); } - (void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_1, 0); + (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_1, 0); - (void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_2, 0); + (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_2, 0); - (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_FAN_CTRL, 0); + (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_FAN_CTRL, 0); - (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_TEMP_CTRL, 0); + (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_TEMP_CTRL, 0); - (void)SkI2cWrite(pAC, IoC, LM80_CFG_START, LM80_ADDR, LM80_CFG, 0); + (void)SkI2cWrite(pAC, IoC, (SK_U32)LM80_CFG_START, LM80_ADDR, I2C_025K_DEV, + LM80_CFG, 0); /* * MaxSens has to be updated here, because PhyType is not @@ -957,7 +973,7 @@ SK_IOC IoC) /* I/O Context */ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR; } else { - pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC-Co 1V5"; + pAC->I2c.SenTable[i].SenDesc = "Voltage Core 1V5"; pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR; pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN; pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN; @@ -1015,9 +1031,9 @@ SK_IOC IoC) /* I/O Context */ pAC->I2c.SenTable[i].SenDev = LM80_ADDR; } -#ifndef SK_DIAG +#ifndef SK_DIAG pAC->I2c.DummyReads = pAC->I2c.MaxSens; -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ /* Clear I2C IRQ */ SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); @@ -1208,15 +1224,13 @@ SK_SENSOR *pSen) pSen->SenLastErrLogTS = CurrTime; if (pSen->SenType == SK_SEN_TEMP) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, - SKERR_I2C_E011MSG); - } else if (pSen->SenType == SK_SEN_VOLT) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, - SKERR_I2C_E012MSG); - } else - { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, - SKERR_I2C_E015MSG); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, SKERR_I2C_E011MSG); + } + else if (pSen->SenType == SK_SEN_VOLT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, SKERR_I2C_E012MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, SKERR_I2C_E015MSG); } } } @@ -1235,8 +1249,7 @@ SK_SENSOR *pSen) /* This state is the former one */ /* So check first whether we have to send a trap */ - if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > - CurrTime) { + if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > CurrTime) { /* * Do NOT send the Trap. The hold back time * has to run out first. @@ -1245,8 +1258,7 @@ SK_SENSOR *pSen) } /* Check now whether we have to log an Error */ - if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > - CurrTime) { + if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > CurrTime) { /* * Do NOT log the error. The hold back time * has to run out first. @@ -1277,15 +1289,13 @@ SK_SENSOR *pSen) pSen->SenLastWarnLogTS = CurrTime; if (pSen->SenType == SK_SEN_TEMP) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, - SKERR_I2C_E009MSG); - } else if (pSen->SenType == SK_SEN_VOLT) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, - SKERR_I2C_E010MSG); - } else - { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, - SKERR_I2C_E014MSG); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG); + } + else if (pSen->SenType == SK_SEN_VOLT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, SKERR_I2C_E010MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, SKERR_I2C_E014MSG); } } } @@ -1317,7 +1327,7 @@ SK_SENSOR *pSen) } } -#if 0 +#ifdef TEST_ONLY /* Dynamic thresholds also for VAUX of LM80 sensor */ if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) { @@ -1359,7 +1369,7 @@ SK_SENSOR *pSen) if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG); } -} /* SkI2cCheckSensor*/ +} /* SkI2cCheckSensor */ /* @@ -1390,7 +1400,7 @@ SK_EVPARA Para) /* Event specific Parame if (ReadComplete) { /* Check sensor against defined thresholds */ - SkI2cCheckSensor (pAC, pSen); + SkI2cCheckSensor(pAC, pSen); /* Increment Current sensor and set appropriate Timeout */ pAC->I2c.CurrSens++; @@ -1414,7 +1424,7 @@ SK_EVPARA Para) /* Event specific Parame /* Start Timer */ ParaLocal.Para64 = (SK_U64)0; - pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE; + pAC->I2c.TimerMode = SK_TIMER_WATCH_SM; SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH, SKGE_I2C, SK_I2CEV_TIM, ParaLocal); @@ -1431,7 +1441,7 @@ SK_EVPARA Para) /* Event specific Parame if (ReadComplete) { /* Check sensor against defined thresholds */ - SkI2cCheckSensor (pAC, pSen); + SkI2cCheckSensor(pAC, pSen); /* Increment Current sensor and set appropriate Timeout */ pAC->I2c.CurrSens++; @@ -1496,4 +1506,4 @@ SK_EVPARA Para) /* Event specific Parame return(0); } /* SkI2cEvent*/ -#endif /* !SK_DIAG */ +#endif /* !SK_DIAG */ --- linux-2.6.1-rc1/drivers/net/sk98lin/sklm80.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/sklm80.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,16 +1,17 @@ /****************************************************************************** * * Name: sklm80.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.20 $ - * Date: $Date: 2002/08/13 09:16:27 $ - * Purpose: Funktions to access Voltage and Temperature Sensor (LM80) + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.22 $ + * Date: $Date: 2003/10/20 09:08:21 $ + * Purpose: Functions to access Voltage and Temperature Sensor (LM80) * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -26,15 +27,21 @@ * History: * * $Log: sklm80.c,v $ + * Revision 1.22 2003/10/20 09:08:21 rschmidt + * Editorial changes. + * + * Revision 1.21 2003/09/23 09:29:04 malthoff + * Parameter Dev_Size added to macro SK_I2C_CTL. + * * Revision 1.20 2002/08/13 09:16:27 rschmidt * Changed return value for SkLm80ReadSensor() back to 'int' - * Editorial changes + * Editorial changes. * * Revision 1.19 2002/08/06 09:43:31 jschmalz - * Extensions and changes for Yukon + * Extensions and changes for Yukon. * * Revision 1.18 2002/08/02 12:26:57 rschmidt - * Editorial changes + * Editorial changes. * * Revision 1.17 1999/11/22 13:35:51 cgoos * Changed license header to GPL. @@ -93,16 +100,15 @@ * Revision 1.1 1998/07/17 09:57:12 gklug * initial version * - * - * ******************************************************************************/ - /* LM80 functions */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Id: sklm80.c,v 1.20 2002/08/13 09:16:27 rschmidt Exp $" ; + "@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. "; +#endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" @@ -202,7 +208,7 @@ SK_SENSOR *pSen) /* Sensor to be read */ switch (pSen->SenState) { case SK_SEN_IDLE: /* Send address to ADDR register */ - SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, pSen->SenReg, 0); + SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0); pSen->SenState = SK_SEN_VALUE ; BREAK_OR_WAIT(pAC, IoC, I2C_READ); @@ -250,7 +256,7 @@ SK_SENSOR *pSen) /* Sensor to be read */ (pSen->SenValue % SK_LM80_TEMP_LSB); /* Send address to ADDR register */ - SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, LM80_TEMP_CTRL, 0); + SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0); pSen->SenState = SK_SEN_VALEXT ; BREAK_OR_WAIT(pAC, IoC, I2C_READ); @@ -284,3 +290,4 @@ SK_SENSOR *pSen) /* Sensor to be read */ /* Not completed */ return(0); } + --- linux-2.6.1-rc1/drivers/net/sk98lin/skproc.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk98lin/skproc.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,16 +1,17 @@ /****************************************************************************** * - * Name: skproc.c + * Name: skproc.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 2003/08/12 16:45:29 $ + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/12/11 16:03:57 $ * Purpose: Funktions to display statictic data * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2003 SysKonnect GmbH. + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. * * 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 @@ -28,6 +29,33 @@ * History: * * $Log: skproc.c,v $ + * Revision 1.11 2003/12/11 16:03:57 mlindner + * Fix: Create backup from pnmi data structure + * + * Revision 1.10 2003/11/19 16:25:36 mlindner + * Fix: Print output as 64-bit digit + * + * Revision 1.9 2003/11/17 13:29:05 mlindner + * Fix: Editorial changes + * + * Revision 1.8 2003/11/13 14:18:48 rroesler + * Fix: added latest changes regarding the use of the proc system + * + * Revision 1.7 2003/11/10 09:35:07 rroesler + * Fix: diag backup restore of PNMI structure + * + * Revision 1.6 2003/11/07 17:31:39 rroesler + * Add: security counter for the proc file system + * + * Revision 1.5 2003/10/07 08:17:08 mlindner + * Fix: Copyright changes + * + * Revision 1.4 2003/09/01 15:29:24 mlindner + * Fix: Editorial changes + * + * Revision 1.3 2003/08/29 12:30:58 mlindner + * Add: Version entry in the proc file system + * * Revision 1.2 2003/08/12 16:45:29 mlindner * Add: Removed SkNumber and SkDoDiv * Add: Counter output as (unsigned long long) @@ -94,223 +122,350 @@ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" +#include "h/skversion.h" -#ifdef CONFIG_PROC_FS +extern struct SK_NET_DEVICE *SkGeRootDev; +static int sk_proc_print(void *writePtr, char *format, ...); +static void sk_gen_browse(void *buffer); +int len; -extern struct net_device *SkGeRootDev; +static int sk_seq_show(struct seq_file *seq, void *v); +static int sk_proc_open(struct inode *inode, struct file *file); +struct file_operations sk_proc_fops = { + .owner = THIS_MODULE, + .open = sk_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +struct net_device *currDev = NULL; -static int sk_seq_show(struct seq_file *seq, void *v) +/***************************************************************************** + * + * sk_gen_browse -generic print "summaries" entry + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. + * + * Returns: - + * + */ +static void sk_gen_browse(void *buffer) { - struct net_device *dev = seq->private; - DEV_NET *pNet = dev->priv; - SK_AC *pAC = pNet->pAC; - SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct; - SK_PNMI_STAT *pPnmiStat = &pPnmiStruct->Stat[0]; - int unit = !(pAC->dev[0] == dev); - int i; - char sens_msg[50]; - - seq_printf(seq, - "\nDetailed statistic for device %s\n", - dev->name); - seq_printf(seq, - "=======================================\n"); - - /* Board statistics */ - seq_printf(seq, - "\nBoard statistics\n\n"); - seq_printf(seq, - "Active Port %c\n", - 'A' + pAC->Rlmt.Net[unit].Port[pAC->Rlmt. - Net[unit].PrefPort]->PortNumber); - seq_printf(seq, - "Preferred Port %c\n", - 'A' + pAC->Rlmt.Net[unit].Port[pAC->Rlmt. - Net[unit].PrefPort]->PortNumber); - - seq_printf(seq, - "Bus speed (MHz) %d\n", - pPnmiStruct->BusSpeed); - - seq_printf(seq, - "Bus width (Bit) %d\n", - pPnmiStruct->BusWidth); - seq_printf(seq, - "Hardware revision v%d.%d\n", - (pAC->GIni.GIPciHwRev >> 4) & 0x0F, - pAC->GIni.GIPciHwRev & 0x0F); - - /* Print sensor informations */ - for (i=0; i < pAC->I2c.MaxSens; i ++) { - /* Check type */ - switch (pAC->I2c.SenTable[i].SenType) { - case 1: - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (C)"); - seq_printf(seq, - "%-25s %d.%02d\n", - sens_msg, - pAC->I2c.SenTable[i].SenValue / 10, - pAC->I2c.SenTable[i].SenValue % 10); - - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (F)"); - seq_printf(seq, - "%-25s %d.%02d\n", - sens_msg, - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200)/100, - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200) % 10); - break; - case 2: - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (V)"); - seq_printf(seq, - "%-25s %d.%03d\n", - sens_msg, - pAC->I2c.SenTable[i].SenValue / 1000, - pAC->I2c.SenTable[i].SenValue % 1000); - break; - case 3: - strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); - strcat(sens_msg, " (rpm)"); - seq_printf(seq, - "%-25s %d\n", - sens_msg, - pAC->I2c.SenTable[i].SenValue); - break; - default: - break; + struct SK_NET_DEVICE *SkgeProcDev = SkGeRootDev; + struct SK_NET_DEVICE *next; + SK_PNMI_STRUCT_DATA *pPnmiStruct; + SK_PNMI_STAT *pPnmiStat; + unsigned long Flags; + unsigned int Size; + DEV_NET *pNet; + SK_AC *pAC; + char sens_msg[50]; + int MaxSecurityCount = 0; + int t; + int i; + + while (SkgeProcDev) { + MaxSecurityCount++; + if (MaxSecurityCount > 100) { + printk("Max limit for sk_proc_read security counter!\n"); + return; } - } + pNet = (DEV_NET*) SkgeProcDev->priv; + pAC = pNet->pAC; + next = pAC->Next; + pPnmiStruct = &pAC->PnmiStruct; + /* NetIndex in GetStruct is now required, zero is only dummy */ + + for (t=pAC->GIni.GIMacsFound; t > 0; t--) { + if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1) + t--; + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + Size = SK_PNMI_STRUCT_SIZE; +#ifdef SK_DIAG_SUPPORT + if (pAC->BoardLevel == SK_INIT_DATA) { + SK_MEMCPY(&(pAC->PnmiStruct), &(pAC->PnmiBackup), sizeof(SK_PNMI_STRUCT_DATA)); + if (pAC->DiagModeActive == DIAG_NOTACTIVE) { + pAC->Pnmi.DiagAttached = SK_DIAG_IDLE; + } + } else { + SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, t-1); + } +#else + SkPnmiGetStruct(pAC, pAC->IoBase, + pPnmiStruct, &Size, t-1); +#endif + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + if (strcmp(pAC->dev[t-1]->name, currDev->name) == 0) { + pPnmiStat = &pPnmiStruct->Stat[0]; + len = sk_proc_print(buffer, + "\nDetailed statistic for device %s\n", + pAC->dev[t-1]->name); + len += sk_proc_print(buffer, + "=======================================\n"); + + /* Board statistics */ + len += sk_proc_print(buffer, + "\nBoard statistics\n\n"); + len += sk_proc_print(buffer, + "Active Port %c\n", + 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. + Net[t-1].PrefPort]->PortNumber); + len += sk_proc_print(buffer, + "Preferred Port %c\n", + 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. + Net[t-1].PrefPort]->PortNumber); + + len += sk_proc_print(buffer, + "Bus speed (MHz) %d\n", + pPnmiStruct->BusSpeed); + + len += sk_proc_print(buffer, + "Bus width (Bit) %d\n", + pPnmiStruct->BusWidth); + len += sk_proc_print(buffer, + "Driver version %s\n", + VER_STRING); + len += sk_proc_print(buffer, + "Hardware revision v%d.%d\n", + (pAC->GIni.GIPciHwRev >> 4) & 0x0F, + pAC->GIni.GIPciHwRev & 0x0F); + + /* Print sensor informations */ + for (i=0; i < pAC->I2c.MaxSens; i ++) { + /* Check type */ + switch (pAC->I2c.SenTable[i].SenType) { + case 1: + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (C)"); + len += sk_proc_print(buffer, + "%-25s %d.%02d\n", + sens_msg, + pAC->I2c.SenTable[i].SenValue / 10, + pAC->I2c.SenTable[i].SenValue % 10); + + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (F)"); + len += sk_proc_print(buffer, + "%-25s %d.%02d\n", + sens_msg, + ((((pAC->I2c.SenTable[i].SenValue) + *10)*9)/5 + 3200)/100, + ((((pAC->I2c.SenTable[i].SenValue) + *10)*9)/5 + 3200) % 10); + break; + case 2: + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (V)"); + len += sk_proc_print(buffer, + "%-25s %d.%03d\n", + sens_msg, + pAC->I2c.SenTable[i].SenValue / 1000, + pAC->I2c.SenTable[i].SenValue % 1000); + break; + case 3: + strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc); + strcat(sens_msg, " (rpm)"); + len += sk_proc_print(buffer, + "%-25s %d\n", + sens_msg, + pAC->I2c.SenTable[i].SenValue); + break; + default: + break; + } + } - /*Receive statistics */ - seq_printf(seq, - "\nReceive statistics\n\n"); - - seq_printf(seq, - "Received bytes %Ld\n", - (unsigned long long) pPnmiStat->StatRxOctetsOkCts); - seq_printf(seq, - "Received packets %Ld\n", - (unsigned long long) pPnmiStat->StatRxOkCts); + /*Receive statistics */ + len += sk_proc_print(buffer, + "\nReceive statistics\n\n"); + + len += sk_proc_print(buffer, + "Received bytes %Lu\n", + (unsigned long long) pPnmiStat->StatRxOctetsOkCts); + len += sk_proc_print(buffer, + "Received packets %Lu\n", + (unsigned long long) pPnmiStat->StatRxOkCts); #if 0 - if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && - pAC->HWRevision < 12) { - pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - - pPnmiStat->StatRxShortsCts; - pPnmiStat->StatRxShortsCts = 0; - } + if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && + pAC->HWRevision < 12) { + pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - + pPnmiStat->StatRxShortsCts; + pPnmiStat->StatRxShortsCts = 0; + } #endif - if (pNet->Mtu > 1500) - pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - - pPnmiStat->StatRxTooLongCts; - - seq_printf(seq, - "Receive errors %Ld\n", - (unsigned long long) pPnmiStruct->InErrorsCts); - seq_printf(seq, - "Receive dropped %Ld\n", - (unsigned long long) pPnmiStruct->RxNoBufCts); - seq_printf(seq, - "Received multicast %Ld\n", - (unsigned long long) pPnmiStat->StatRxMulticastOkCts); - seq_printf(seq, - "Receive error types\n"); - seq_printf(seq, - " length %Ld\n", - (unsigned long long) pPnmiStat->StatRxRuntCts); - seq_printf(seq, - " buffer overflow %Ld\n", - (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); - seq_printf(seq, - " bad crc %Ld\n", - (unsigned long long) pPnmiStat->StatRxFcsCts); - seq_printf(seq, - " framing %Ld\n", - (unsigned long long) pPnmiStat->StatRxFramingCts); - seq_printf(seq, - " missed frames %Ld\n", - (unsigned long long) pPnmiStat->StatRxMissedCts); - - if (pNet->Mtu > 1500) - pPnmiStat->StatRxTooLongCts = 0; - - seq_printf(seq, - " too long %Ld\n", - (unsigned long long) pPnmiStat->StatRxTooLongCts); - seq_printf(seq, - " carrier extension %Ld\n", - (unsigned long long) pPnmiStat->StatRxCextCts); - seq_printf(seq, - " too short %Ld\n", - (unsigned long long) pPnmiStat->StatRxShortsCts); - seq_printf(seq, - " symbol %Ld\n", - (unsigned long long) pPnmiStat->StatRxSymbolCts); - seq_printf(seq, - " LLC MAC size %Ld\n", - (unsigned long long) pPnmiStat->StatRxIRLengthCts); - seq_printf(seq, - " carrier event %Ld\n", - (unsigned long long) pPnmiStat->StatRxCarrierCts); - seq_printf(seq, - " jabber %Ld\n", - (unsigned long long) pPnmiStat->StatRxJabberCts); - - - /*Transmit statistics */ - seq_printf(seq, - "\nTransmit statistics\n\n"); + if (pNet->Mtu > 1500) + pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - + pPnmiStat->StatRxTooLongCts; + + len += sk_proc_print(buffer, + "Receive errors %Lu\n", + (unsigned long long) pPnmiStruct->InErrorsCts); + len += sk_proc_print(buffer, + "Receive dropped %Lu\n", + (unsigned long long) pPnmiStruct->RxNoBufCts); + len += sk_proc_print(buffer, + "Received multicast %Lu\n", + (unsigned long long) pPnmiStat->StatRxMulticastOkCts); + len += sk_proc_print(buffer, + "Receive error types\n"); + len += sk_proc_print(buffer, + " length %Lu\n", + (unsigned long long) pPnmiStat->StatRxRuntCts); + len += sk_proc_print(buffer, + " buffer overflow %Lu\n", + (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); + len += sk_proc_print(buffer, + " bad crc %Lu\n", + (unsigned long long) pPnmiStat->StatRxFcsCts); + len += sk_proc_print(buffer, + " framing %Lu\n", + (unsigned long long) pPnmiStat->StatRxFramingCts); + len += sk_proc_print(buffer, + " missed frames %Lu\n", + (unsigned long long) pPnmiStat->StatRxMissedCts); + + if (pNet->Mtu > 1500) + pPnmiStat->StatRxTooLongCts = 0; + + len += sk_proc_print(buffer, + " too long %Lu\n", + (unsigned long long) pPnmiStat->StatRxTooLongCts); + len += sk_proc_print(buffer, + " carrier extension %Lu\n", + (unsigned long long) pPnmiStat->StatRxCextCts); + len += sk_proc_print(buffer, + " too short %Lu\n", + (unsigned long long) pPnmiStat->StatRxShortsCts); + len += sk_proc_print(buffer, + " symbol %Lu\n", + (unsigned long long) pPnmiStat->StatRxSymbolCts); + len += sk_proc_print(buffer, + " LLC MAC size %Lu\n", + (unsigned long long) pPnmiStat->StatRxIRLengthCts); + len += sk_proc_print(buffer, + " carrier event %Lu\n", + (unsigned long long) pPnmiStat->StatRxCarrierCts); + len += sk_proc_print(buffer, + " jabber %Lu\n", + (unsigned long long) pPnmiStat->StatRxJabberCts); + + + /*Transmit statistics */ + len += sk_proc_print(buffer, + "\nTransmit statistics\n\n"); - seq_printf(seq, - "Transmited bytes %Ld\n", - (unsigned long long) pPnmiStat->StatTxOctetsOkCts); - seq_printf(seq, - "Transmited packets %Ld\n", - (unsigned long long) pPnmiStat->StatTxOkCts); - seq_printf(seq, - "Transmit errors %Ld\n", - (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); - seq_printf(seq, - "Transmit dropped %Ld\n", - (unsigned long long) pPnmiStruct->TxNoBufCts); - seq_printf(seq, - "Transmit collisions %Ld\n", - (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); - seq_printf(seq, - "Transmit error types\n"); - seq_printf(seq, - " excessive collision %ld\n", - pAC->stats.tx_aborted_errors); - seq_printf(seq, - " carrier %Ld\n", - (unsigned long long) pPnmiStat->StatTxCarrierCts); - seq_printf(seq, - " fifo underrun %Ld\n", - (unsigned long long) pPnmiStat->StatTxFifoUnderrunCts); - seq_printf(seq, - " heartbeat %Ld\n", - (unsigned long long) pPnmiStat->StatTxCarrierCts); - seq_printf(seq, - " window %ld\n", - pAC->stats.tx_window_errors); + len += sk_proc_print(buffer, + "Transmited bytes %Lu\n", + (unsigned long long) pPnmiStat->StatTxOctetsOkCts); + len += sk_proc_print(buffer, + "Transmited packets %Lu\n", + (unsigned long long) pPnmiStat->StatTxOkCts); + len += sk_proc_print(buffer, + "Transmit errors %Lu\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sk_proc_print(buffer, + "Transmit dropped %Lu\n", + (unsigned long long) pPnmiStruct->TxNoBufCts); + len += sk_proc_print(buffer, + "Transmit collisions %Lu\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sk_proc_print(buffer, + "Transmit error types\n"); + len += sk_proc_print(buffer, + " excessive collision %ld\n", + pAC->stats.tx_aborted_errors); + len += sk_proc_print(buffer, + " carrier %Lu\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sk_proc_print(buffer, + " fifo underrun %Lu\n", + (unsigned long long) pPnmiStat->StatTxFifoUnderrunCts); + len += sk_proc_print(buffer, + " heartbeat %Lu\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sk_proc_print(buffer, + " window %ld\n", + pAC->stats.tx_window_errors); - return 0; + } /* if (strcmp(pACname, currDeviceName) == 0) */ + } + SkgeProcDev = next; + } } +/***************************************************************************** + * + * sk_proc_print -generic line print + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. + * + * Returns: number of bytes written + * + */ +static int sk_proc_print(void *writePtr, char *format, ...) +{ +#define MAX_LEN_SINGLE_LINE 256 + char str[MAX_LEN_SINGLE_LINE]; + va_list a_start; + int lenght = 0; + + struct seq_file *seq = (struct seq_file *) writePtr; + + SK_MEMSET(str, 0, MAX_LEN_SINGLE_LINE); + + va_start(a_start, format); + vsprintf(str, format, a_start); + va_end(a_start); + + lenght = strlen(str); + seq_printf(seq, str); + return lenght; +} + +/***************************************************************************** + * + * sk_seq_show - show proc information of a particular adapter + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. It invokes the generic sk_gen_browse() to + * print out all items one per one. + * + * Returns: number of bytes written + * + */ +static int sk_seq_show(struct seq_file *seq, void *v) +{ + void *castedBuffer = (void *) seq; + currDev = seq->private; + sk_gen_browse(castedBuffer); + return 0; +} + +/***************************************************************************** + * + * sk_proc_open - register the show function when proc is open'ed + * + * Description: + * This function is called whenever a sk98lin proc file is queried. + * + * Returns: the return value of single_open() + * + */ static int sk_proc_open(struct inode *inode, struct file *file) { - return single_open(file, sk_seq_show, PDE(inode)->data); + return single_open(file, sk_seq_show, PDE(inode)->data); } -struct file_operations sk_proc_fops = { - .owner = THIS_MODULE, - .open = sk_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif +/******************************************************************************* + * + * End of file + * + ******************************************************************************/ --- linux-2.6.1-rc1/drivers/net/sk98lin/skqueue.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skqueue.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skqueue.c - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.19 $ - * Date: $Date: 2003/05/13 18:00:07 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.20 $ + * Date: $Date: 2003/09/16 13:44:00 $ * Purpose: Management of an event queue. * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: skqueue.c,v $ + * Revision 1.20 2003/09/16 13:44:00 rschmidt + * Added (C) Marvell to SysKonnectFileId + * Editorial changes + * * Revision 1.19 2003/05/13 18:00:07 mkarl * Removed calls to RLMT, TWSI, and PNMI for SLIM driver (SK_SLIM). * Editorial changes. @@ -85,18 +89,16 @@ * * Revision 1.1 1998/07/30 15:14:01 gklug * Initial version. Adapted from SMT - * - * * ******************************************************************************/ /* - Event queue and dispatcher -*/ + * Event queue and dispatcher + */ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.19 2003/05/13 18:00:07 mkarl Exp $" ; + "@(#) $Id: skqueue.c,v 1.20 2003/09/16 13:44:00 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -124,11 +126,11 @@ intro() void SkEventInit( SK_AC *pAC, /* Adapter context */ SK_IOC Ioc, /* IO context */ -int Level) /* Init level */ +int Level) /* Init level */ { switch (Level) { case SK_INIT_DATA: - pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue ; + pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue; break; default: break; @@ -144,14 +146,15 @@ SK_U32 Class, /* Event Class */ SK_U32 Event, /* Event to be queued */ SK_EVPARA Para) /* Event parameter */ { - pAC->Event.EvPut->Class = Class ; - pAC->Event.EvPut->Event = Event ; - pAC->Event.EvPut->Para = Para ; + pAC->Event.EvPut->Class = Class; + pAC->Event.EvPut->Event = Event; + pAC->Event.EvPut->Para = Para; + if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT]) - pAC->Event.EvPut = pAC->Event.EvQueue ; + pAC->Event.EvPut = pAC->Event.EvQueue; if (pAC->Event.EvPut == pAC->Event.EvGet) { - SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG); } } @@ -168,77 +171,79 @@ int SkEventDispatcher( SK_AC *pAC, /* Adapters Context */ SK_IOC Ioc) /* Io context */ { - SK_EVENTELEM *pEv ; /* pointer into queue */ - SK_U32 Class ; - int Rtv ; - - pEv = pAC->Event.EvGet ; - PRINTF("dispatch get %x put %x\n",pEv,pAC->Event.ev_put) ; + SK_EVENTELEM *pEv; /* pointer into queue */ + SK_U32 Class; + int Rtv; + + pEv = pAC->Event.EvGet; + + PRINTF("dispatch get %x put %x\n", pEv, pAC->Event.ev_put); + while (pEv != pAC->Event.EvPut) { - PRINTF("dispatch Class %d Event %d\n",pEv->Class,pEv->Event) ; - switch(Class = pEv->Class) { + PRINTF("dispatch Class %d Event %d\n", pEv->Class, pEv->Event); + + switch (Class = pEv->Class) { #ifndef SK_USE_LAC_EV #ifndef SK_SLIM - case SKGE_RLMT : /* RLMT Event */ - Rtv = SkRlmtEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; - case SKGE_I2C : /* I2C Event */ - Rtv = SkI2cEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; - case SKGE_PNMI : - Rtv = SkPnmiEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + case SKGE_RLMT: /* RLMT Event */ + Rtv = SkRlmtEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_I2C: /* I2C Event */ + Rtv = SkI2cEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_PNMI: /* PNMI Event */ + Rtv = SkPnmiEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* not SK_SLIM */ #endif /* not SK_USE_LAC_EV */ - case SKGE_DRV : /* Driver Event */ - Rtv = SkDrvEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; -#ifndef SK_USE_SW_TIMER - case SKGE_HWAC : - Rtv = SkGeSirqEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + case SKGE_DRV: /* Driver Event */ + Rtv = SkDrvEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#ifndef SK_USE_SW_TIMER + case SKGE_HWAC: + Rtv = SkGeSirqEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #else /* !SK_USE_SW_TIMER */ - case SKGE_SWT : - Rtv = SkSwtEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + case SKGE_SWT : + Rtv = SkSwtEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* !SK_USE_SW_TIMER */ -#ifdef SK_USE_LAC_EV +#ifdef SK_USE_LAC_EV case SKGE_LACP : - Rtv = SkLacpEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkLacpEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; case SKGE_RSF : - Rtv = SkRsfEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkRsfEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; case SKGE_MARKER : - Rtv = SkMarkerEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkMarkerEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; case SKGE_FD : - Rtv = SkFdEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkFdEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* SK_USE_LAC_EV */ #ifdef SK_USE_CSUM case SKGE_CSUM : - Rtv = SkCsEvent(pAC,Ioc,pEv->Event,pEv->Para); - break ; + Rtv = SkCsEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; #endif /* SK_USE_CSUM */ default : - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, - SKERR_Q_E002MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, SKERR_Q_E002MSG); Rtv = 0; } if (Rtv != 0) { - return(Rtv) ; + return(Rtv); } if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT]) - pEv = pAC->Event.EvQueue ; + pEv = pAC->Event.EvQueue; /* Renew get: it is used in queue_events to detect overruns */ pAC->Event.EvGet = pEv; } - return(0) ; + return(0); } /* End of file */ --- linux-2.6.1-rc1/drivers/net/sk98lin/sktimer.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/sktimer.c 2003-12-30 22:49:20.000000000 -0800 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: sktimer.c - * Project: Gigabit Ethernet Adapters, Schedule-Modul - * Version: $Revision: 1.13 $ - * Date: $Date: 2003/05/13 18:01:01 $ + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.14 $ + * Date: $Date: 2003/09/16 13:46:51 $ * Purpose: High level timer functions. * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: sktimer.c,v $ + * Revision 1.14 2003/09/16 13:46:51 rschmidt + * Added (C) Marvell to SysKonnectFileId + * Editorial changes + * * Revision 1.13 2003/05/13 18:01:01 mkarl * Editorial changes. * @@ -68,19 +72,16 @@ * * Revision 1.1 1998/08/05 11:27:55 gklug * first version: adapted from SMT - * - * - * * ******************************************************************************/ /* - Event queue and dispatcher -*/ + * Event queue and dispatcher + */ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.13 2003/05/13 18:01:01 mkarl Exp $" ; + "@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell."; #endif #include "h/skdrv1st.h" /* Driver Specific Definitions */ @@ -110,14 +111,14 @@ static void timer_done(SK_AC *pAC,SK_IOC void SkTimerInit( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ -int Level) /* Init Level */ +int Level) /* Init Level */ { switch (Level) { case SK_INIT_DATA: - pAC->Tim.StQueue = 0 ; + pAC->Tim.StQueue = 0; break; case SK_INIT_IO: - SkHwtInit(pAC,Ioc) ; + SkHwtInit(pAC, Ioc); SkTimerDone(pAC, Ioc); break; default: @@ -134,31 +135,34 @@ SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ SK_TIMER *pTimer) /* Timer Pointer to be started */ { - SK_TIMER **ppTimPrev ; - SK_TIMER *pTm ; + SK_TIMER **ppTimPrev; + SK_TIMER *pTm; /* * remove timer from queue */ - pTimer->TmActive = SK_FALSE ; + pTimer->TmActive = SK_FALSE; + if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) { - SkHwtStop(pAC,Ioc) ; + SkHwtStop(pAC, Ioc); } - for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ; + + for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev); ppTimPrev = &pTm->TmNext ) { + if (pTm == pTimer) { /* * Timer found in queue * - dequeue it and * - correct delta of the next timer */ - *ppTimPrev = pTm->TmNext ; + *ppTimPrev = pTm->TmNext; if (pTm->TmNext) { /* correct delta of next timer in queue */ - pTm->TmNext->TmDelta += pTm->TmDelta ; + pTm->TmNext->TmDelta += pTm->TmDelta; } - return ; + return; } } } @@ -175,65 +179,67 @@ SK_U32 Class, /* Event Class for this SK_U32 Event, /* Event Value for this timer */ SK_EVPARA Para) /* Event Parameter for this timer */ { - SK_TIMER **ppTimPrev ; - SK_TIMER *pTm ; - SK_U32 Delta ; + SK_TIMER **ppTimPrev; + SK_TIMER *pTm; + SK_U32 Delta; - Time /= 16 ; /* input is uS, clock ticks are 16uS */ + Time /= 16; /* input is uS, clock ticks are 16uS */ + if (!Time) - Time = 1 ; + Time = 1; - SkTimerStop(pAC,Ioc,pTimer) ; + SkTimerStop(pAC, Ioc, pTimer); - pTimer->TmClass = Class ; - pTimer->TmEvent = Event ; - pTimer->TmPara = Para ; - pTimer->TmActive = SK_TRUE ; + pTimer->TmClass = Class; + pTimer->TmEvent = Event; + pTimer->TmPara = Para; + pTimer->TmActive = SK_TRUE; if (!pAC->Tim.StQueue) { /* First Timer to be started */ - pAC->Tim.StQueue = pTimer ; - pTimer->TmNext = 0 ; - pTimer->TmDelta = Time ; - SkHwtStart(pAC,Ioc,Time) ; - return ; + pAC->Tim.StQueue = pTimer; + pTimer->TmNext = 0; + pTimer->TmDelta = Time; + + SkHwtStart(pAC, Ioc, Time); + + return; } /* * timer correction */ - timer_done(pAC,Ioc,0) ; + timer_done(pAC, Ioc, 0); /* * find position in queue */ - Delta = 0 ; - for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ; + Delta = 0; + for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev); ppTimPrev = &pTm->TmNext ) { + if (Delta + pTm->TmDelta > Time) { /* Position found */ /* Here the timer needs to be inserted. */ - break ; + break; } - Delta += pTm->TmDelta ; + Delta += pTm->TmDelta; } /* insert in queue */ - *ppTimPrev = pTimer ; - pTimer->TmNext = pTm ; - pTimer->TmDelta = Time - Delta ; + *ppTimPrev = pTimer; + pTimer->TmNext = pTm; + pTimer->TmDelta = Time - Delta; if (pTm) { /* There is a next timer * -> correct its Delta value. */ - pTm->TmDelta -= pTimer->TmDelta ; + pTm->TmDelta -= pTimer->TmDelta; } - /* - * start new with first - */ - SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ; + /* restart with first */ + SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta); } @@ -241,55 +247,56 @@ void SkTimerDone( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc) /* IoContext */ { - timer_done(pAC,Ioc,1) ; + timer_done(pAC, Ioc, 1); } static void timer_done( SK_AC *pAC, /* Adapters context */ SK_IOC Ioc, /* IoContext */ -int Restart) /* Do we need to restart the Hardware timer ? */ +int Restart) /* Do we need to restart the Hardware timer ? */ { - SK_U32 Delta ; - SK_TIMER *pTm ; - SK_TIMER *pTComp ; /* Timer completed now now */ - SK_TIMER **ppLast ; /* Next field of Last timer to be deq */ - int Done = 0 ; - - Delta = SkHwtRead(pAC,Ioc) ; - ppLast = &pAC->Tim.StQueue ; - pTm = pAC->Tim.StQueue ; + SK_U32 Delta; + SK_TIMER *pTm; + SK_TIMER *pTComp; /* Timer completed now now */ + SK_TIMER **ppLast; /* Next field of Last timer to be deq */ + int Done = 0; + + Delta = SkHwtRead(pAC, Ioc); + + ppLast = &pAC->Tim.StQueue; + pTm = pAC->Tim.StQueue; while (pTm && !Done) { if (Delta >= pTm->TmDelta) { /* Timer ran out */ - pTm->TmActive = SK_FALSE ; - Delta -= pTm->TmDelta ; - ppLast = &pTm->TmNext ; - pTm = pTm->TmNext ; - } else { + pTm->TmActive = SK_FALSE; + Delta -= pTm->TmDelta; + ppLast = &pTm->TmNext; + pTm = pTm->TmNext; + } + else { /* We found the first timer that did not run out */ - pTm->TmDelta -= Delta ; - Delta = 0 ; - Done = 1 ; + pTm->TmDelta -= Delta; + Delta = 0; + Done = 1; } } - *ppLast = 0 ; + *ppLast = 0; /* * pTm points to the first Timer that did not run out. * StQueue points to the first Timer that run out. */ - for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) { - SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, - pTComp->TmPara) ; + for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) { + SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara); } /* Set head of timer queue to the first timer that did not run out */ - pAC->Tim.StQueue = pTm ; + pAC->Tim.StQueue = pTm; if (Restart && pAC->Tim.StQueue) { /* Restart HW timer */ - SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ; + SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta); } } --- linux-2.6.1-rc1/drivers/net/sk98lin/skxmac2.c 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/net/sk98lin/skxmac2.c 2003-12-30 22:49:20.000000000 -0800 @@ -2,8 +2,8 @@ * * Name: skxmac2.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.99 $ - * Date: $Date: 2003/07/11 12:19:33 $ + * Version: $Revision: 1.102 $ + * Date: $Date: 2003/10/02 16:53:58 $ * Purpose: Contains functions to initialize the MACs and PHYs * ******************************************************************************/ @@ -27,6 +27,23 @@ * History: * * $Log: skxmac2.c,v $ + * Revision 1.102 2003/10/02 16:53:58 rschmidt + * Changed setting of GMAC parameters with new macros. + * Added define SLIM around SkGm...LowPowerMode(). + * Editorial changes. + * + * Revision 1.101 2003/09/16 14:49:07 rschmidt + * Added routines SkGmClearRst(), SkXmClearRst, SkMacClearRst(). + * Added WA code for Yukon-Lite's COMA mode in SkGmHardRst(). + * Replaced PCI-Config R/W through internal access. + * Fixed return from coma mode in SkGmLeaveLowPowerMode(). + * Fixed compiler warnings for different types. + * Editorial changes. + * + * Revision 1.100 2003/09/16 07:09:11 mschmid + * Added functions SkGmEnterLowPowerMode() and + * SkGmLeaveLowPowerMode() + * * Revision 1.99 2003/07/11 12:19:33 rschmidt * Reduced init values for Master & Slave downshift counters to * minimum values. @@ -164,7 +181,7 @@ * Revision 1.74 2002/08/12 14:00:17 rschmidt * Replaced usage of Broadcom PHY Ids with defines. * Corrected error messages in SkGmMacStatistic(). - * Made SkMacPromiscMode() public for ADDR-Modul. + * Made SkMacPromiscMode() public for ADDR-Module. * Editorial changes. * * Revision 1.73 2002/08/08 16:26:24 rschmidt @@ -475,7 +492,7 @@ typedef struct s_PhyHack { #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = - "@(#) $Id: skxmac2.c,v 1.99 2003/07/11 12:19:33 rschmidt Exp $ (C) Marvell."; + "@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell."; #endif #ifdef GENESIS @@ -1343,7 +1360,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Description: * The XMAC of the specified 'Port' and all connected devices * (PHY and SERDES) will receive a reset signal on its *Reset pins. - * External PHYs must be reset be clearing a bit in the GPIO register + * External PHYs must be reset by clearing a bit in the GPIO register * (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns). * * ATTENTION: @@ -1386,23 +1403,62 @@ int Port) /* Port Index (MAC_1 + n) */ /* For external PHYs there must be special handling */ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { - /* reset external PHY */ + SK_IN32(IoC, B2_GP_IO, &Reg); + if (Port == 0) { - Reg |= GP_DIR_0; /* set to output */ - Reg &= ~GP_IO_0; + Reg |= GP_DIR_0; /* set to output */ + Reg &= ~GP_IO_0; /* set PHY reset (active low) */ } else { - Reg |= GP_DIR_2; /* set to output */ - Reg &= ~GP_IO_2; + Reg |= GP_DIR_2; /* set to output */ + Reg &= ~GP_IO_2; /* set PHY reset (active low) */ } + /* reset external PHY */ SK_OUT32(IoC, B2_GP_IO, Reg); /* short delay */ SK_IN32(IoC, B2_GP_IO, &Reg); } - } /* SkXmHardRst */ + + +/****************************************************************************** + * + * SkXmClearRst() - Release the PHY & XMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkXmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + + /* clear HW reset */ + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); + + if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + if (Port == 0) { + DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */ + } + else { + DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */ + } + /* Clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + + /* Enable GMII interface */ + XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); + } +} /* SkXmClearRst */ #endif /* GENESIS */ @@ -1452,10 +1508,6 @@ int Port) /* Port Index (MAC_1 + n) */ * * Description: * - * ATTENTION: - * It is absolutely necessary to reset the SW_RST Bit first - * before calling this function. - * * Returns: * nothing */ @@ -1464,6 +1516,20 @@ SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { + SK_U32 DWord; + + /* WA code for COMA mode */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + DWord |= (GP_DIR_9 | GP_IO_9); + + /* set PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + } + /* set GPHY Control reset */ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET); @@ -1471,6 +1537,73 @@ int Port) /* Port Index (MAC_1 + n) */ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); } /* SkGmHardRst */ + + +/****************************************************************************** + * + * SkGmClearRst() - Release the GPHY & GMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkGmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + +#ifdef XXX + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR); + + /* set GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); +#endif /* XXX */ + + /* WA code for COMA mode */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + DWord |= GP_DIR_9; /* set to output */ + DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ + + /* clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + } + + /* set HWCFG_MODE */ + DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | + GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE | + (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP : + GPC_HWCFG_GMII_FIB); + + /* set GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET); + + /* release GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR); + +#ifdef VCPU + VCpuWait(9000); +#endif /* VCPU */ + + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); + +#ifdef VCPU + VCpuWait(2000); + + SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord); + + SK_IN32(IoC, B0_ISRC, &DWord); +#endif /* VCPU */ + +} /* SkGmClearRst */ #endif /* YUKON */ @@ -1553,6 +1686,38 @@ int Port) /* Port Index (MAC_1 + n) */ } /* SkMacHardRst */ +/****************************************************************************** + * + * SkMacClearRst() - Clear the MAC reset + * + * Description: calls a clear MAC reset routine dep. on board type + * + * Returns: + * nothing + */ +void SkMacClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + SkXmClearRst(pAC, IoC, Port); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + SkGmClearRst(pAC, IoC, Port); + } +#endif /* YUKON */ + +} /* SkMacClearRst */ + + #ifdef GENESIS /****************************************************************************** * @@ -1574,7 +1739,6 @@ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U32 Reg; int i; SK_U16 SWord; @@ -1594,32 +1758,10 @@ int Port) /* Port Index (MAC_1 + n) */ } if (pPrt->PState == SK_PRT_RESET) { - /* - * clear HW reset - * Note: The SW reset is self clearing, therefore there is - * nothing to do here. - */ - SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); - /* Ensure that XMAC reset release is done (errata from LReinbold?) */ - SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord); + SkXmClearRst(pAC, IoC, Port); - /* Clear PHY reset */ if (pPrt->PhyType != SK_PHY_XMAC) { - - SK_IN32(IoC, B2_GP_IO, &Reg); - - if (Port == 0) { - Reg |= (GP_DIR_0 | GP_IO_0); /* set to output */ - } - else { - Reg |= (GP_DIR_2 | GP_IO_2); /* set to output */ - } - SK_OUT32(IoC, B2_GP_IO, Reg); - - /* Enable GMII interface */ - XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); - /* read Id from external PHY (all have the same address) */ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1); @@ -1831,43 +1973,11 @@ int Port) /* Port Index (MAC_1 + n) */ } if (pPrt->PState == SK_PRT_RESET) { - /* set GPHY Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET); - - /* set GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); - -#ifdef XXX - /* clear GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR); - - /* set GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); -#endif /* XXX */ - - /* set HWCFG_MODE */ - DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | - GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE | - (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP : - GPC_HWCFG_GMII_FIB); - - /* set GPHY Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET); - - /* release GPHY Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR); - -#ifdef VCPU - VCpuWait(9000); -#endif /* VCPU */ - - /* clear GMAC Control reset */ - SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); - -#ifdef VCPU - VCpuWait(2000); -#endif /* VCPU */ + + SkGmHardRst(pAC, IoC, Port); + SkGmClearRst(pAC, IoC, Port); + /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { /* Auto-negotiation disabled */ @@ -1906,6 +2016,7 @@ int Port) /* Port Index (MAC_1 + n) */ SWord |= GM_GPCR_DUP_FULL; } + /* flow-control settings */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: /* set Pause Off */ @@ -1940,7 +2051,7 @@ int Port) /* Port Index (MAC_1 + n) */ (void)SkGmResetCounter(pAC, IoC, Port); /* setup Transmit Control Register */ - GM_OUT16(IoC, Port, GM_TX_CTRL, GM_TXCR_COL_THR); + GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres)); /* setup Receive Control Register */ GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA | @@ -1954,7 +2065,9 @@ int Port) /* Port Index (MAC_1 + n) */ GM_IN16(IoC, Port, GM_TX_PARAM, &SWord); #endif /* VCPU */ - SWord = (SK_U16)(JAM_LEN_VAL(3) | JAM_IPG_VAL(11) | IPG_JAM_DATA(26)); + SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) | + TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) | + TX_IPG_JAM_DATA(pPrt->PMacJamIpgData); GM_OUT16(IoC, Port, GM_TX_PARAM, SWord); @@ -1963,7 +2076,12 @@ int Port) /* Port Index (MAC_1 + n) */ GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord); #endif /* VCPU */ - SWord = GM_SMOD_VLAN_ENA | IPG_VAL_FAST_ETH; + SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData); + + if (pPrt->PMacLimit4) { + /* reset of collision counter after 4 consecutive collisions */ + SWord |= GM_SMOD_LIMIT_4; + } if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { /* enable jumbo mode (Max. Frame Length = 9018) */ @@ -2021,11 +2139,13 @@ int Port) /* Port Index (MAC_1 + n) */ GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0); GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0); +#if defined(SK_DIAG) || defined(DEBUG) /* read General Purpose Status */ GM_IN16(IoC, Port, GM_GP_STAT, &SWord); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("MAC Stat Reg=0x%04X\n", SWord)); + ("MAC Stat Reg.=0x%04X\n", SWord)); +#endif /* SK_DIAG || DEBUG */ #ifdef SK_DIAG c_print("MAC Stat Reg=0x%04X\n", SWord); @@ -2226,6 +2346,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl |= PHY_X_P_NO_PAUSE; @@ -2306,7 +2427,9 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyBcom: no auto-negotiation Port %d\n", Port)); /* Set DuplexMode in Config register */ - Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl1 |= PHY_CT_DUP_MD; + } /* Determine Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { @@ -2346,6 +2469,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl3 |= PHY_B_P_NO_PAUSE; @@ -2375,12 +2499,12 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Write 1000Base-T Control Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("1000B-T Ctrl Reg=0x%04X\n", Ctrl2)); + ("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2)); /* Write AutoNeg Advertisement Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3)); + ("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3)); if (DoLoop) { /* Set the Phy Loopback bit, too */ @@ -2409,6 +2533,281 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac #ifdef YUKON +#ifndef SK_SLIM +/****************************************************************************** + * + * SkGmEnterLowPowerMode() + * + * Description: + * This function sets the Marvell Alaska PHY to the low power mode + * given by parameter mode. + * The following low power modes are available: + * + * - Coma Mode (Deep Sleep): + * Power consumption: ~15 - 30 mW + * The PHY cannot wake up on its own. + * + * - IEEE 22.2.4.1.5 compatible power down mode + * Power consumption: ~240 mW + * The PHY cannot wake up on its own. + * + * - energy detect mode + * Power consumption: ~160 mW + * The PHY can wake up on its own by detecting activity + * on the CAT 5 cable. + * + * - energy detect plus mode + * Power consumption: ~150 mW + * The PHY can wake up on its own by detecting activity + * on the CAT 5 cable. + * Connected devices can be woken up by sending normal link + * pulses every one second. + * + * Note: + * + * Returns: + * 0: ok + * 1: error + */ +int SkGmEnterLowPowerMode( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (e.g. MAC_1) */ +SK_U8 Mode) /* low power mode */ +{ + SK_U16 Word; + SK_U32 DWord; + SK_U8 LastMode; + int Ret = 0; + + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + /* save current power mode */ + LastMode = pAC->GIni.GP[Port].PPhyPowerState; + pAC->GIni.GP[Port].PPhyPowerState = Mode; + + switch (Mode) { + /* coma mode (deep sleep) */ + case PHY_PM_DEEP_SLEEP: + /* setup General Purpose Control Register */ + GM_OUT16(IoC, 0, GM_GP_CTRL, GM_GPCR_FL_PASS | + GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); + + /* apply COMA mode workaround */ + SkGmPhyWrite(pAC, IoC, Port, 29, 0x001f); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xfff3); + + SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + /* Set PHY to Coma Mode */ + SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord | PCI_PHY_COMA); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + break; + + /* IEEE 22.2.4.1.5 compatible power down mode */ + case PHY_PM_IEEE_POWER_DOWN: + /* + * - disable MAC 125 MHz clock + * - allow MAC power down + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word |= PHY_M_PC_DIS_125CLK; + Word &= ~PHY_M_PC_MAC_POW_UP; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * register changes must be followed by a software + * reset to take effect + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word |= PHY_CT_RESET; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + + /* switch IEEE compatible power down mode on */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word |= PHY_CT_PDOWN; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + break; + + /* energy detect and energy detect plus mode */ + case PHY_PM_ENERGY_DETECT: + case PHY_PM_ENERGY_DETECT_PLUS: + /* + * - disable MAC 125 MHz clock + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word |= PHY_M_PC_DIS_125CLK; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* activate energy detect mode 1 */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + + /* energy detect mode */ + if (Mode == PHY_PM_ENERGY_DETECT) { + Word |= PHY_M_PC_EN_DET; + } + /* energy detect plus mode */ + else { + Word |= PHY_M_PC_EN_DET_PLUS; + } + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * reinitialize the PHY to force a software reset + * which is necessary after the register settings + * for the energy detect modes. + * Furthermore reinitialisation prevents that the + * PHY is running out of a stable state. + */ + SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); + break; + + /* don't change current power mode */ + default: + pAC->GIni.GP[Port].PPhyPowerState = LastMode; + Ret = 1; + break; + } + } + /* low power modes are not supported by this chip */ + else { + Ret = 1; + } + + return(Ret); + +} /* SkGmEnterLowPowerMode */ + +/****************************************************************************** + * + * SkGmLeaveLowPowerMode() + * + * Description: + * Leave the current low power mode and switch to normal mode + * + * Note: + * + * Returns: + * 0: ok + * 1: error + */ +int SkGmLeaveLowPowerMode( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (e.g. MAC_1) */ +{ + SK_U32 DWord; + SK_U16 Word; + SK_U8 LastMode; + int Ret = 0; + + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev == CHIP_REV_YU_LITE_A3) { + + /* save current power mode */ + LastMode = pAC->GIni.GP[Port].PPhyPowerState; + pAC->GIni.GP[Port].PPhyPowerState = PHY_PM_OPERATIONAL_MODE; + + switch (LastMode) { + /* coma mode (deep sleep) */ + case PHY_PM_DEEP_SLEEP: + SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + + /* Release PHY from Coma Mode */ + SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord & ~PCI_PHY_COMA); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + SK_IN32(IoC, B2_GP_IO, &DWord); + + /* set to output */ + DWord |= (GP_DIR_9 | GP_IO_9); + + /* set PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + + DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ + + /* clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + break; + + /* IEEE 22.2.4.1.5 compatible power down mode */ + case PHY_PM_IEEE_POWER_DOWN: + /* + * - enable MAC 125 MHz clock + * - set MAC power up + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word &= ~PHY_M_PC_DIS_125CLK; + Word |= PHY_M_PC_MAC_POW_UP; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * register changes must be followed by a software + * reset to take effect + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word |= PHY_CT_RESET; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + + /* switch IEEE compatible power down mode off */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); + Word &= ~PHY_CT_PDOWN; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); + break; + + /* energy detect and energy detect plus mode */ + case PHY_PM_ENERGY_DETECT: + case PHY_PM_ENERGY_DETECT_PLUS: + /* + * - enable MAC 125 MHz clock + */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word &= ~PHY_M_PC_DIS_125CLK; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* disable energy detect mode */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); + Word &= ~PHY_M_PC_EN_DET_MSK; + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); + + /* + * reinitialize the PHY to force a software reset + * which is necessary after the register settings + * for the energy detect modes. + * Furthermore reinitialisation prevents that the + * PHY is running out of a stable state. + */ + SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); + break; + + /* don't change current power mode */ + default: + pAC->GIni.GP[Port].PPhyPowerState = LastMode; + Ret = 1; + break; + } + } + /* low power modes are not supported by this chip */ + else { + Ret = 1; + } + + return(Ret); + +} /* SkGmLeaveLowPowerMode */ +#endif /* !SK_SLIM */ + + /****************************************************************************** * * SkGmInitPhyMarv() - Initialize the Marvell Phy registers @@ -2457,7 +2856,6 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n", Port, DoLoop); #else /* VCPU */ - if (DoLoop) { /* Set 'MAC Power up'-bit, set Manual MDI configuration */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, @@ -2475,16 +2873,20 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl)); + ("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl)); } /* Read PHY Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); + if (!AutoNeg) { + /* Disable Auto-negotiation */ + PhyCtrl &= ~PHY_CT_ANE; + } + PhyCtrl |= PHY_CT_RESET; /* Assert software reset */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); - #endif /* VCPU */ PhyCtrl = 0 /* PHY_CT_COL_TST */; @@ -2533,13 +2935,9 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac if (!DoLoop) { PhyCtrl |= PHY_CT_RESET; } - /* - * Do NOT enable Auto-negotiation here. This would hold - * the link down because no IDLES are transmitted - */ } else { - PhyCtrl |= PHY_CT_ANE; + /* Set Auto-negotiation advertisement */ if (pAC->GIni.GICopperType) { /* Set Speed capabilities */ @@ -2554,6 +2952,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac break; case SK_LSPEED_100MBPS: AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD | + /* advertise 10Base-T also */ PHY_M_AN_10_FD | PHY_M_AN_10_HD; break; case SK_LSPEED_10MBPS: @@ -2581,7 +2980,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } - /* Set Auto-negotiation advertisement */ + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: AutoNegAdv |= PHY_B_P_NO_PAUSE; @@ -2618,7 +3017,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } - /* Set Auto-negotiation advertisement */ + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: AutoNegAdv |= PHY_M_P_NO_PAUSE_X; @@ -2640,7 +3039,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac if (!DoLoop) { /* Restart Auto-negotiation */ - PhyCtrl |= PHY_CT_RE_CFG; + PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG; } } @@ -2659,12 +3058,12 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Write 1000Base-T Control Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("1000B-T Ctrl=0x%04X\n", C1000BaseT)); + ("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT)); /* Write AutoNeg Advertisement Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Auto-Neg.Ad.=0x%04X\n", AutoNegAdv)); + ("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv)); #endif /* VCPU */ if (DoLoop) { @@ -2694,6 +3093,8 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Write to the PHY Control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl)); #ifdef VCPU VCpuWait(2000); @@ -2712,7 +3113,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl); if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) { - /* only in forced 100Mbps mode */ + /* only in forced 100 Mbps mode */ if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) { SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER, @@ -2741,7 +3142,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Read AutoNeg Advertisement Register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, - ("Auto-Neg. Ad.=0x%04X\n", AutoNegAdv)); + ("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv)); /* Read Ext. PHY Specific Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl); @@ -2818,13 +3219,15 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { /* - * level one spec say: "1000Mbps: manual mode not allowed" + * level one spec say: "1000 Mbps: manual mode not allowed" * but lets see what happens... */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyLone: no auto-negotiation Port %d\n", Port)); /* Set DuplexMode in Config register */ - Ctrl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl1 |= PHY_CT_DUP_MD; + } /* Determine Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { @@ -2857,6 +3260,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac SKERR_HWI_E015MSG); } + /* Set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl3 |= PHY_L_P_NO_PAUSE; @@ -2877,7 +3281,6 @@ SK_BOOL DoLoop) /* Should a Phy LoopBac /* Restart Auto-negotiation */ Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG; - } /* Write 1000Base-T Control Register */ @@ -3019,10 +3422,10 @@ int Port) /* Port Index (MAC_1 + n) */ /* Check Duplex mismatch */ if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } else { /* Error */ @@ -3055,7 +3458,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; return(SK_AND_OK); } /* SkXmAutoNegDoneXmac */ @@ -3110,10 +3513,10 @@ int Port) /* Port Index (MAC_1 + n) */ /* Check Duplex mismatch */ if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } else { /* Error */ @@ -3156,7 +3559,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; return(SK_AND_OK); } /* SkXmAutoNegDoneBcom */ @@ -3192,6 +3595,8 @@ int Port) /* Port Index (MAC_1 + n) */ /* Get PHY parameters */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Link P.Abil.=0x%04X\n", LPAb)); if ((LPAb & PHY_M_AN_RF) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, @@ -3222,15 +3627,15 @@ int Port) /* Port Index (MAC_1 + n) */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; - pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; return(SK_AND_DUP_CAP); } if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } /* Check PAUSE mismatch ??? */ @@ -3255,13 +3660,13 @@ int Port) /* Port Index (MAC_1 + n) */ /* set used link speed */ switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) { case (unsigned)PHY_M_PS_SPEED_1000: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; break; case PHY_M_PS_SPEED_100: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; break; default: - pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; } return(SK_AND_OK); @@ -3312,10 +3717,10 @@ int Port) /* Port Index (MAC_1 + n) */ /* Check Duplex mismatch */ if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } /* Check Master/Slave resolution */ @@ -3338,6 +3743,7 @@ int Port) /* Port Index (MAC_1 + n) */ /* We are using IEEE 802.3z/D5.0 Table 37-4 */ /* we must manually resolve the abilities here */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; + switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: /* default */ @@ -3457,6 +3863,9 @@ int Port) /* Port Index (MAC_1 + n) */ return(Rtv); } + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg done Port %d\n", Port)); + /* We checked everything and may now enable the link */ pPrt->PAutoNegFail = SK_FALSE; --- linux-2.6.1-rc1/drivers/net/skfp/skfddi.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/skfp/skfddi.c 2003-12-30 22:49:20.000000000 -0800 @@ -39,12 +39,6 @@ * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. * The others belong to the SysKonnect FDDI Hardware Module and * should better not be changed. - * NOTE: - * Compiling this driver produces some warnings, but I did not fix - * this, because the Hardware Module source is used for different - * drivers, and fixing it for Linux might bring problems on other - * projects. To keep the source common for all those drivers (and - * thus simplify fixes to it), please do not clean it up! * * Modification History: * Date Name Description @@ -58,6 +52,7 @@ * 07-May-00 DM 64 bit fixes, new dma interface * 31-Jul-03 DB Audit copy_*_user in skfp_ioctl * Daniele Bellucci + * 03-Dec-03 SH Convert to PCI device model * * Compilation options (-Dxxx): * DRIVERDEBUG print lots of messages to log file @@ -70,7 +65,7 @@ /* Version information string - should be updated prior to */ /* each new release!!! */ -#define VERSION "2.06" +#define VERSION "2.07" static const char *boot_msg = "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" @@ -80,15 +75,11 @@ static const char *boot_msg = #include #include -#include -#include #include #include #include #include #include -#include -#include // isdigit #include #include #include @@ -106,17 +97,7 @@ static const char *boot_msg = #include "h/smtstate.h" -// Define global routines -int skfp_probe(struct net_device *dev); - - // Define module-wide (static) routines -static struct net_device *alloc_device(struct net_device *dev, u_long iobase); -static struct net_device *insert_device(struct net_device *dev, - int (*init) (struct net_device *)); -static int fddi_dev_index(unsigned char *s); -static void init_dev(struct net_device *dev, u_long iobase); -static void link_modules(struct net_device *dev, struct net_device *tmp); static int skfp_driver_init(struct net_device *dev); static int skfp_open(struct net_device *dev); static int skfp_close(struct net_device *dev); @@ -193,15 +174,6 @@ MODULE_AUTHOR("Mirko Lindner priv)->os)) /* - * ============== - * = skfp_probe = - * ============== + * ================= + * = skfp_init_one = + * ================= * * Overview: * Probes for supported FDDI PCI controllers @@ -223,30 +195,11 @@ static int loading_module; * Condition code * * Arguments: - * dev - pointer to device information + * pdev - pointer to PCI device information * * Functional Description: - * This routine is called by the OS for each FDDI device name (fddi0, - * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. - * If loaded as a module, it will detect and initialize all - * adapters the first time it is called. - * - * Let's say that skfp_probe() is getting called to initialize fddi0. - * Furthermore, let's say there are three supported controllers in the - * system. Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2 - * will be initialized and a global flag will be set to indicate that - * skfp_probe() has already been called. - * - * However...the OS doesn't know that we've already initialized - * devices fddi1 and fddi2 so skfp_probe() gets called again and again - * until it reaches the end of the device list for FDDI (presently, - * fddi7). It's important that the driver "pretend" to probe for - * devices fddi1 and fddi2 and return success. Devices fddi3 - * through fddi7 will return failure since they weren't initialized. - * - * This algorithm seems to work for the time being. As other FDDI - * drivers are written for Linux, a more generic approach (perhaps - * similar to the Ethernet card approach) may need to be implemented. + * This is now called by PCI driver registration process + * for each board found. * * Return Codes: * 0 - This device (fddi0, fddi1, etc) configured successfully @@ -259,374 +212,176 @@ static int loading_module; * initialized and the board resources are read and stored in * the device structure. */ -int skfp_probe(struct net_device *dev) +static int skfp_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int i; /* used in for loops */ - struct pci_dev *pdev = NULL; /* PCI device structure */ -#ifndef MEM_MAPPED_IO - u16 port; /* temporary I/O (port) address */ - int port_len; /* length of port address range (in bytes) */ -#else - unsigned long port; -#endif - u16 command; /* PCI Configuration space Command register val */ + struct net_device *dev; struct s_smc *smc; /* board pointer */ - struct net_device *tmp = dev; - u8 first_dev_used = 0; - u16 SubSysId; + u32 port, len; + int err; - PRINTK(KERN_INFO "entering skfp_probe\n"); - - /* - * Verify whether we're going through skfp_probe() again - * - * If so, see if we're going through for a subsequent fddi device that - * we've already initialized. If we are, return success (0). If not, - * return failure (-ENODEV). - */ - - if (autoprobed) { - PRINTK(KERN_INFO "Already entered skfp_probe\n"); - if (dev != NULL) { - if ((strncmp(dev->name, "fddi", 4) == 0) && - (dev->base_addr != 0)) { - return (0); - } - return (-ENODEV); - } - } - autoprobed = 1; /* set global flag */ + PRINTK(KERN_INFO "entering skfp_init_one\n"); - printk("%s\n", boot_msg); + if (num_boards == 0) + printk("%s\n", boot_msg); - /* Scan for Syskonnect FDDI PCI controllers */ - for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) { // scan for PCI cards - PRINTK(KERN_INFO "Check device %d\n", i); - if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, - pdev)) == 0) { - break; - } - if (pci_enable_device(pdev)) - continue; + err = pci_enable_device(pdev); + if (err) + goto err_out1; -#ifndef MEM_MAPPED_IO - /* Verify that I/O enable bit is set (PCI slot is enabled) */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_IO) == 0) { - PRINTK("I/O enable bit not set!"); - PRINTK(" Verify that slot is enabled\n"); - continue; - } - /* Turn off memory mapped space and enable mastering */ +#ifdef MEM_MAPPED_IO + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR "skfp: region is not an MMIO resource\n"); + err = -EIO; + goto err_out1; + } + port = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); - PRINTK(KERN_INFO "Command Reg: %04x\n", command); - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, command); - - /* Read I/O base address from PCI Configuration Space */ - - pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port); - port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0) - - /* Verify port address range is not already being used */ - - port_len = FP_IO_LEN; - if (check_region(port, port_len) != 0) { - printk("I/O range allocated to adapter"); - printk(" (0x%X-0x%X) is already being used!\n", port, - (port + port_len - 1)); - continue; - } + if (len < 0x4000) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", len); + err = -EIO; + goto err_out1; + } #else - /* Verify that MEM enable bit is set (PCI slot is enabled) */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_MEMORY) == 0) { - PRINTK("MEMORY-I/O enable bit not set!"); - PRINTK(" Verify that slot is enabled\n"); - continue; - } - - /* Turn off IO mapped space and enable mastering */ - - PRINTK(KERN_INFO "Command Reg: %04x\n", command); - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, command); - - port = pci_resource_start(pdev, 0); - - port = (unsigned long)ioremap(port, 0x4000); - if (!port){ - printk("skfp: Unable to map MEMORY register, " - "FDDI adapter will be disabled.\n"); - break; - } -#endif - - if ((!loading_module) || first_dev_used) { - /* Allocate a device structure for this adapter */ - tmp = alloc_device(dev, port); - } - first_dev_used = 1; // only significant first time - - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId); - - if (tmp != NULL) { - if (loading_module) - link_modules(dev, tmp); - dev = tmp; - init_dev(dev, port); - dev->irq = pdev->irq; - - /* Initialize board structure with bus-specific info */ - - smc = (struct s_smc *) dev->priv; - smc->os.dev = dev; - smc->os.bus_type = SK_BUS_TYPE_PCI; - smc->os.pdev = *pdev; - smc->os.QueueSkb = MAX_TX_QUEUE_LEN; - smc->os.MaxFrameSize = MAX_FRAME_SIZE; - smc->os.dev = dev; - smc->hw.slot = -1; - smc->os.ResetRequested = FALSE; - skb_queue_head_init(&smc->os.SendSkbQueue); - - if (skfp_driver_init(dev) == 0) { - // only increment global board - // count on success - num_boards++; - request_region(dev->base_addr, - FP_IO_LEN, dev->name); - if ((SubSysId & 0xff00) == 0x5500 || - (SubSysId & 0xff00) == 0x5800) { - printk("%s: SysKonnect FDDI PCI adapter" - " found (SK-%04X)\n", dev->name, - SubSysId); - } else { - printk("%s: FDDI PCI adapter found\n", - dev->name); - } - } else { - kfree(dev); - i = SKFP_MAX_NUM_BOARDS; // stop search - - } - - } // if (dev != NULL) - - } // for SKFP_MAX_NUM_BOARDS - - /* - * If we're at this point we're going through skfp_probe() for the - * first time. Return success (0) if we've initialized 1 or more - * boards. Otherwise, return failure (-ENODEV). - */ - - if (num_boards > 0) - return (0); - else { - printk("no SysKonnect FDDI adapter found\n"); - return (-ENODEV); + if (!(pci_resource_flags(pdev, 1) & IO_RESOURCE_IO)) { + printk(KERN_ERR "skfp: region is not PIO resource\n"); + err = -EIO; + goto err_out1; } -} // skfp_probe - - -/************************ - * - * Search the entire 'fddi' device list for a fixed probe. If a match isn't - * found then check for an autoprobe or unused device location. If they - * are not available then insert a new device structure at the end of - * the current list. - * - ************************/ -static struct net_device *alloc_device(struct net_device *dev, u_long iobase) -{ - struct net_device *adev = NULL; - int fixed = 0, new_dev = 0; - - PRINTK(KERN_INFO "entering alloc_device\n"); - if (!dev) - return dev; - num_fddi = fddi_dev_index(dev->name); - if (loading_module) { - num_fddi++; - dev = insert_device(dev, skfp_probe); - return dev; + port = pci_resource_start(pdev, 1); + len = pci_resource_len(pdev, 1); + if (len < FP_IO_LEN) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", + io_len); + err = -EIO; + goto err_out1; } - while (1) { - if (((dev->base_addr == NO_ADDRESS) || - (dev->base_addr == 0)) && !adev) { - adev = dev; - } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "fddi", 4) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) - break; - dev = dev->next; - num_fddi++; - } // while (1) - - if (adev && !fixed) { - dev = adev; - num_fddi = fddi_dev_index(dev->name); - new_dev = 0; - } - if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) && - (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_fddi++; /* New device */ - dev = insert_device(dev, skfp_probe); - } - if (dev) { - if (!dev->priv) { - /* Allocate space for private board structure */ - dev->priv = (void *) kmalloc(sizeof(struct s_smc), - GFP_KERNEL); - if (dev->priv == NULL) { - printk("%s: Could not allocate memory for", - dev->name); - printk(" private board structure!\n"); - return (NULL); - } - /* clear structure */ - memset(dev->priv, 0, sizeof(struct s_smc)); - } +#endif + err = pci_request_regions(pdev, "skfddi"); + if (err) + goto err_out1; + + pci_set_master(pdev); + + dev = alloc_fddidev(sizeof(struct s_smc)); + if (!dev) { + printk(KERN_ERR "skfp: Unable to allocate fddi device, " + "FDDI adapter will be disabled.\n"); + err = -ENOMEM; + goto err_out2; + } + +#ifdef MEM_MAPPED_IO + dev->base_addr = (unsigned long) ioremap(port, len); + if (!dev->base_addr) { + printk(KERN_ERR "skfp: Unable to map MEMORY register, " + "FDDI adapter will be disabled.\n"); + err = -EIO; + goto err_out3; } - return dev; -} // alloc_device - - - -/************************ - * - * Initialize device structure - * - ************************/ -static void init_dev(struct net_device *dev, u_long iobase) -{ - /* Initialize new device structure */ - - dev->mem_end = 0; /* shared memory isn't used */ - dev->mem_start = 0; /* shared memory isn't used */ - dev->base_addr = iobase; /* save port (I/O) base address */ - dev->if_port = 0; /* not applicable to FDDI adapters */ - dev->dma = 0; /* Bus Master DMA doesn't require channel */ - dev->irq = 0; - - netif_start_queue(dev); +#else + dev->base_addr = port; +#endif + dev->irq = pdev->irq; dev->get_stats = &skfp_ctl_get_stats; dev->open = &skfp_open; dev->stop = &skfp_close; dev->hard_start_xmit = &skfp_send_pkt; - dev->hard_header = NULL; /* set in fddi_setup() */ - dev->rebuild_header = NULL; /* set in fddi_setup() */ dev->set_multicast_list = &skfp_ctl_set_multicast_list; dev->set_mac_address = &skfp_ctl_set_mac_address; dev->do_ioctl = &skfp_ioctl; - dev->set_config = NULL; /* not supported for now &&& */ dev->header_cache_update = NULL; /* not supported */ - dev->change_mtu = NULL; /* set in fddi_setup() */ SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); - /* Initialize remaining device structure information */ - fddi_setup(dev); -} // init_device - - -/************************ - * - * If at end of fddi device list and can't use current entry, malloc - * one up. If memory could not be allocated, print an error message. - * -************************/ -static struct net_device *insert_device(struct net_device *dev, - int (*init) (struct net_device *)) -{ - struct net_device *new; - int len; - - PRINTK(KERN_INFO "entering insert_device\n"); - len = sizeof(struct net_device) + sizeof(struct s_smc); - new = (struct net_device *) kmalloc(len, GFP_KERNEL); - if (new == NULL) { - printk("fddi%d: Device not initialised, insufficient memory\n", - num_fddi); - return NULL; - } else { - memset((char *) new, 0, len); - new->priv = (struct s_smc *) (new + 1); - new->init = init; /* initialisation routine */ - if (!loading_module) { - new->next = dev->next; - dev->next = new; - } - /* create new device name */ - if (num_fddi > 999) { - sprintf(new->name, "fddi????"); - } else { - sprintf(new->name, "fddi%d", num_fddi); - } - } - return new; -} // insert_device - - -/************************ - * - * Get the number of a "fddiX" string - * - ************************/ -static int fddi_dev_index(unsigned char *s) -{ - int i = 0, j = 0; - - for (; *s; s++) { - if (isdigit(*s)) { - j = 1; - i = (i * 10) + (*s - '0'); - } else if (j) - break; - } - return i; -} // fddi_dev_index + /* Initialize board structure with bus-specific info */ + smc = (struct s_smc *) dev->priv; + smc->os.dev = dev; + smc->os.bus_type = SK_BUS_TYPE_PCI; + smc->os.pdev = *pdev; + smc->os.QueueSkb = MAX_TX_QUEUE_LEN; + smc->os.MaxFrameSize = MAX_FRAME_SIZE; + smc->os.dev = dev; + smc->hw.slot = -1; + smc->os.ResetRequested = FALSE; + skb_queue_head_init(&smc->os.SendSkbQueue); + + err = skfp_driver_init(dev); + if (err) + goto err_out4; + + err = register_netdev(dev); + if (err) + goto err_out5; + + ++num_boards; + pci_set_drvdata(pdev, dev); + + if ((pdev->subsystem_device & 0xff00) == 0x5500 || + (pdev->subsystem_device & 0xff00) == 0x5800) + printk("%s: SysKonnect FDDI PCI adapter" + " found (SK-%04X)\n", dev->name, + pdev->subsystem_device); + else + printk("%s: FDDI PCI adapter found\n", dev->name); + return 0; +err_out5: + if (smc->os.SharedMemAddr) + pci_free_consistent(pdev, smc->os.SharedMemSize, + smc->os.SharedMemAddr, + smc->os.SharedMemDMA); + pci_free_consistent(pdev, MAX_FRAME_SIZE, + smc->os.LocalRxBuffer, smc->os.LocalRxBufferDMA); +err_out4: +#ifdef MEM_MAPPED_IO + iounmap((void *) dev->base_addr); +#endif +err_out3: + free_netdev(dev); +err_out2: + pci_release_regions(pdev); +err_out1: + return err; +} -/************************ - * - * Used if loaded as module only. Link the device structures - * together. Needed to release them all at unload. - * -************************/ -static void link_modules(struct net_device *dev, struct net_device *tmp) +/* + * Called for each adapter board from pci_unregister_driver + */ +static void __devexit skfp_remove_one(struct pci_dev *pdev) { - struct net_device *p = dev; + struct net_device *p = pci_get_drvdata(pdev); + struct s_smc *lp = p->priv; - if (p) { - while (((struct s_smc *) (p->priv))->os.next_module) { - p = ((struct s_smc *) (p->priv))->os.next_module; - } + unregister_netdev(p); - if (dev != tmp) { - ((struct s_smc *) (p->priv))->os.next_module = tmp; - } else { - ((struct s_smc *) (p->priv))->os.next_module = NULL; - } + if (lp->os.SharedMemAddr) { + pci_free_consistent(&lp->os.pdev, + lp->os.SharedMemSize, + lp->os.SharedMemAddr, + lp->os.SharedMemDMA); + lp->os.SharedMemAddr = NULL; + } + if (lp->os.LocalRxBuffer) { + pci_free_consistent(&lp->os.pdev, + MAX_FRAME_SIZE, + lp->os.LocalRxBuffer, + lp->os.LocalRxBufferDMA); + lp->os.LocalRxBuffer = NULL; } - return; -} // link_modules - +#ifdef MEM_MAPPED_IO + iounmap((void *) p->base_addr); +#endif + pci_release_regions(pdev); + free_netdev(p); + pci_set_drvdata(pdev, NULL); +} /* * ==================== @@ -653,11 +408,11 @@ static void link_modules(struct net_devi * 0 - initialization succeeded * -1 - initialization failed */ -static int skfp_driver_init(struct net_device *dev) +static int skfp_driver_init(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; skfddi_priv *bp = PRIV(dev); - u8 val; /* used for I/O read/writes */ + int err = -EIO; PRINTK(KERN_INFO "entering skfp_driver_init\n"); @@ -666,9 +421,7 @@ static int skfp_driver_init(struct net_d smc->hw.iop = dev->base_addr; // Get the interrupt level from the PCI Configuration Table - val = dev->irq; - - smc->hw.irq = val; + smc->hw.irq = dev->irq; spin_lock_init(&bp->DriverLock); @@ -738,7 +491,7 @@ fail: bp->LocalRxBuffer, bp->LocalRxBufferDMA); bp->LocalRxBuffer = NULL; } - return (-1); + return err; } // skfp_driver_init @@ -766,14 +519,15 @@ fail: static int skfp_open(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; + int err; PRINTK(KERN_INFO "entering skfp_open\n"); /* Register IRQ - support shared interrupts by passing device ptr */ - if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, - dev->name, dev)) { - printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return (-EAGAIN); - } + err = request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) + return err; + /* * Set current address to factory MAC address * @@ -797,6 +551,7 @@ static int skfp_open(struct net_device * /* Disable promiscuous filter settings */ mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + netif_start_queue(dev); return (0); } // skfp_open @@ -831,7 +586,6 @@ static int skfp_open(struct net_device * static int skfp_close(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; - struct sk_buff *skb; skfddi_priv *bp = PRIV(dev); CLI_FBI(); @@ -844,13 +598,8 @@ static int skfp_close(struct net_device /* Deregister (free) IRQ */ free_irq(dev->irq, dev); - for (;;) { - skb = skb_dequeue(&bp->SendSkbQueue); - if (skb == NULL) - break; - bp->QueueSkb++; - dev_kfree_skb(skb); - } + skb_queue_purge(&bp->SendSkbQueue); + bp->QueueSkb = MAX_TX_QUEUE_LEN; return (0); } // skfp_close @@ -1285,6 +1034,8 @@ static int skfp_ioctl(struct net_device break; default: printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd); + status = -EOPNOTSUPP; + } // switch return status; @@ -2538,63 +2289,21 @@ void drv_reset_indication(struct s_smc * } // drv_reset_indication - -static struct net_device *mdev; +static struct pci_driver skfddi_pci_driver = { + .name = "skfddi", + .id_table = skfddi_pci_tbl, + .probe = skfp_init_one, + .remove = __devexit_p(skfp_remove_one), +}; static int __init skfd_init(void) { - struct net_device *p; - - if ((mdev = insert_device(NULL, skfp_probe)) == NULL) - return -ENOMEM; - - for (p = mdev; p != NULL; p = ((struct s_smc *)p->priv)->os.next_module) { - if (register_netdev(p) != 0) { - printk("skfddi init_module failed\n"); - return -EIO; - } - } - - return 0; + return pci_module_init(&skfddi_pci_driver); } -static struct net_device *unlink_modules(struct net_device *p) -{ - struct net_device *next = NULL; - - if (p->priv) { /* Private areas allocated? */ - struct s_smc *lp = (struct s_smc *) p->priv; - - next = lp->os.next_module; - - if (lp->os.SharedMemAddr) { - pci_free_consistent(&lp->os.pdev, - lp->os.SharedMemSize, - lp->os.SharedMemAddr, - lp->os.SharedMemDMA); - lp->os.SharedMemAddr = NULL; - } - if (lp->os.LocalRxBuffer) { - pci_free_consistent(&lp->os.pdev, - MAX_FRAME_SIZE, - lp->os.LocalRxBuffer, - lp->os.LocalRxBufferDMA); - lp->os.LocalRxBuffer = NULL; - } - release_region(p->base_addr, - (lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0)); - } - unregister_netdev(p); - printk("%s: unloaded\n", p->name); - free_netdev(p); /* Free the device structure */ - - return next; -} // unlink_modules - static void __exit skfd_exit(void) { - while (mdev) - mdev = unlink_modules(mdev); + pci_unregister_driver(&skfddi_pci_driver); } module_init(skfd_init); --- linux-2.6.1-rc1/drivers/net/sk_g16.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/sk_g16.c 2003-12-30 22:49:20.000000000 -0800 @@ -457,8 +457,6 @@ struct priv /* static variables */ static SK_RAM *board; /* pointer to our memory mapped board components */ -static struct net_device *SK_dev; -unsigned long SK_ioaddr; static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED; /* Macros */ @@ -472,7 +470,6 @@ static spinlock_t SK_lock = SPIN_LOCK_UN * See for short explanation of each function its definitions header. */ -int SK_init(struct net_device *dev); static int SK_probe(struct net_device *dev, short ioaddr); static void SK_timeout(struct net_device *dev); @@ -530,84 +527,71 @@ void SK_print_ram(struct net_device *dev * YY/MM/DD uid Description -*/ +static int io; /* 0 == probe */ + /* * Check for a network adaptor of this type, and return '0' if one exists. * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. */ -int __init SK_init(struct net_device *dev) +struct net_device * __init SK_init(int unit) { - int ioaddr; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ static unsigned version_printed; + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); + int err = -ENODEV; + + if (!dev) + return ERR_PTR(-ENOMEM); - /* get preconfigured base_addr from dev which is done in Space.c */ - int base_addr = dev->base_addr; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + } if (version_printed++ == 0) PRINTK(("%s: %s", SK_NAME, rcsid)); - if (base_addr > 0x0ff) /* Check a single specified address */ - { - int rc = -ENODEV; - - ioaddr = base_addr; - - /* Check if on specified address is a SK_G16 */ - if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) - return -EBUSY; - - if ( (inb(SK_POS0) == SK_IDLOW) || - (inb(SK_POS1) == SK_IDHIGH) ) - { - rc = SK_probe(dev, ioaddr); - } + if (io > 0xff) { /* Check a single specified address */ + err = -EBUSY; + /* Check if on specified address is a SK_G16 */ + if (request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) { + err = SK_probe(dev, io); + if (!err) + goto got_it; + release_region(io, ETHERCARD_TOTAL_SIZE); + } + } else if (io > 0) { /* Don't probe at all */ + err = -ENXIO; + } else { + /* Autoprobe base_addr */ + for (port = &ports[0]; *port; port++) { + io = *port; + + /* Check if I/O Port region is used by another board */ + if (!request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) + continue; /* Try next Port address */ + + /* Check if at ioaddr is a SK_G16 */ + if (SK_probe(dev, io) == 0) + goto got_it; - if (rc) - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - return rc; + release_region(io, ETHERCARD_TOTAL_SIZE); + } } - else if (base_addr > 0) /* Don't probe at all */ - { - return -ENXIO; +err_out: + free_netdev(dev); + return ERR_PTR(err); + +got_it: + err = register_netdev(dev); + if (err) { + release_region(dev->base_addr, ETHERCARD_TOTAL_SIZE); + goto err_out; } - - /* Autoprobe base_addr */ - - for (port = &ports[0]; *port; port++) - { - ioaddr = *port; /* we need ioaddr for accessing POS regs */ - - /* Check if I/O Port region is used by another board */ - - if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) - { - continue; /* Try next Port address */ - } - - /* Check if at ioaddr is a SK_G16 */ - - if ( !(inb(SK_POS0) == SK_IDLOW) || - !(inb(SK_POS1) == SK_IDHIGH) ) - { - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - continue; /* Try next Port address */ - } - - dev->base_addr = ioaddr; /* Set I/O Port Address */ - - if (SK_probe(dev, ioaddr) == 0) - { - return 0; /* Card found and initialized */ - } - - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - } - - dev->base_addr = base_addr; /* Write back original base_addr */ - - return -ENODEV; /* Failed to find or init driver */ + return dev; } /* End of SK_init */ @@ -620,54 +604,25 @@ MODULE_PARM_DESC(io, "0 to probe common #ifdef MODULE -static int io; /* 0 == probe */ + +static struct net_device *SK_dev; static int __init SK_init_module (void) { - int rc; - - SK_dev = init_etherdev (NULL, 0); - if (!SK_dev) - return -ENOMEM; - - SK_dev->base_addr = io; - - rc = SK_init (SK_dev); - if (rc) { - unregister_netdev (SK_dev); - kfree (SK_dev); - SK_dev = NULL; - } - - return rc; + SK_dev = SK_init(-1); + return IS_ERR(SK_dev) ? PTR_ERR(SK_dev) : 0; } -#endif /* MODULE */ - static void __exit SK_cleanup_module (void) { - if (SK_dev) { - if (SK_dev->priv) { - kfree(SK_dev->priv); - SK_dev->priv = NULL; - } - unregister_netdev(SK_dev); - free_netdev(SK_dev); - SK_dev = NULL; - } - if (SK_ioaddr) { - release_region(SK_ioaddr, ETHERCARD_TOTAL_SIZE); - SK_ioaddr = 0; - } - + unregister_netdev(SK_dev); + release_region(SK_dev->base_addr, ETHERCARD_TOTAL_SIZE); + free_netdev(SK_dev); } - -#ifdef MODULE module_init(SK_init_module); -#endif module_exit(SK_cleanup_module); - +#endif /*- @@ -695,7 +650,11 @@ int __init SK_probe(struct net_device *d int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ unsigned int rom_addr; /* used to store RAM address used for POS_ADDR */ - struct priv *p; /* SK_G16 private structure */ + struct priv *p = dev->priv; /* SK_G16 private structure */ + + if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH) + return -ENODEV; + dev->base_addr = ioaddr; if (SK_ADDR & 0x3fff || SK_ADDR < 0xa0000) { @@ -837,12 +796,6 @@ int __init SK_probe(struct net_device *d dev->dev_addr[4], dev->dev_addr[5]); - /* Allocate memory for private structure */ - p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL); - if (p == NULL) { - printk("%s: ERROR - no memory for driver data!\n", dev->name); - return -ENOMEM; - } memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */ /* Assign our Device Driver functions */ @@ -856,10 +809,6 @@ int __init SK_probe(struct net_device *d dev->watchdog_timeo = HZ/7; - /* Set the generic fields of the device structure */ - - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; /* Initialize private structure */ @@ -884,12 +833,7 @@ int __init SK_probe(struct net_device *d SK_print_pos(dev, "End of SK_probe"); SK_print_ram(dev); #endif - - SK_dev = dev; - SK_ioaddr = ioaddr; - return 0; /* Initialization done */ - } /* End of SK_probe() */ @@ -1280,7 +1224,7 @@ static int SK_send_packet(struct sk_buff memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); if (len != skb->len) - memcpy_toio((tmdp->u.buffer & 0x00ffffff) + sb->len, pad, len-skb->len); + memcpy_toio((tmdp->u.buffer & 0x00ffffff) + skb->len, pad, len-skb->len); writew(-len, &tmdp->blen); /* set length to transmit */ --- linux-2.6.1-rc1/drivers/net/sk_mca.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/sk_mca.c 2003-12-30 22:49:20.000000000 -0800 @@ -1022,18 +1022,39 @@ static void skmca_set_multicast_list(str static int startslot; /* counts through slots when probing multiple devices */ -int __init skmca_probe(struct net_device *dev) +static void cleanup_card(struct net_device *dev) { + skmca_priv *priv = dev->priv; + DeinitBoard(dev); + if (dev->irq != 0) + free_irq(dev->irq, dev); + mca_mark_as_unused(priv->slot); + mca_set_adapter_procfn(priv->slot, NULL, NULL); +} + +struct net_device * __init skmca_probe(int unit) +{ + struct net_device *dev; int force_detect = 0; int junior, slot, i; int base = 0, irq = 0; skmca_priv *priv; skmca_medium medium; + int err; /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(skmca_priv)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); @@ -1044,37 +1065,24 @@ int __init skmca_probe(struct net_device /* search through slots */ - if (dev != NULL) { - base = dev->mem_start; - irq = dev->irq; - } - slot = dofind(&junior, startslot); - - while (slot != -1) { + base = dev->mem_start; + irq = dev->base_addr; + for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, junior, &base, &irq, &medium); /* slot already in use ? */ - if (mca_is_adapter_used(slot)) { - slot = dofind(&junior, slot + 1); + if (mca_is_adapter_used(slot)) continue; - } /* were we looking for something different ? */ - if ((dev->irq != 0) || (dev->mem_start != 0)) { - if ((dev->irq != 0) && (dev->irq != irq)) { - slot = dofind(&junior, slot + 1); - continue; - } - if ((dev->mem_start != 0) - && (dev->mem_start != base)) { - slot = dofind(&junior, slot + 1); - continue; - } - } + if (dev->irq && dev->irq != irq) + continue; + if (dev->mem_start && dev->mem_start != base) + continue; /* found something that matches */ @@ -1083,8 +1091,10 @@ int __init skmca_probe(struct net_device /* nothing found ? */ - if (slot == -1) - return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV; + if (slot == -1) { + free_netdev(dev); + return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV); + } /* make procfs entries */ @@ -1102,17 +1112,14 @@ int __init skmca_probe(struct net_device junior ? "Junior MC2" : "MC2+", slot + 1); /* allocate structure */ - priv = dev->priv = - (skmca_priv *) kmalloc(sizeof(skmca_priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = dev->priv; priv->slot = slot; priv->macbase = base + 0x3fc0; priv->ioregaddr = base + 0x3ff0; priv->ctrladdr = base + 0x3ff2; priv->cmdaddr = base + 0x3ff3; priv->medium = medium; - memset(&(priv->stat), 0, sizeof(struct net_device_stats)); + memset(&priv->stat, 0, sizeof(struct net_device_stats)); spin_lock_init(&priv->lock); /* set base + irq for this device (irq not allocated so far) */ @@ -1146,9 +1153,6 @@ int __init skmca_probe(struct net_device dev->set_multicast_list = skmca_set_multicast_list; dev->flags |= IFF_MULTICAST; - /* generic setup */ - ether_setup(dev); - /* copy out MAC address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1)); @@ -1167,7 +1171,13 @@ int __init skmca_probe(struct net_device startslot = slot + 1; - return 0; + err = register_netdev(dev); + if (err) { + cleanup_card(dev); + free_netdev(dev); + dev = ERR_PTR(err); + } + return dev; } /* ------------------------------------------------------------------------ @@ -1179,51 +1189,34 @@ MODULE_LICENSE("GPL"); #define DEVMAX 5 -static struct net_device moddevs[DEVMAX] = { - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe } -}; - -int irq; -int io; +static struct net_device *moddevs[DEVMAX]; int init_module(void) { - int z, res; + int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { - strcpy(moddevs[z].name, " "); - res = register_netdev(moddevs + z); - if (res != 0) - return (z > 0) ? 0 : -EIO; + struct net_device *dev = skmca_probe(-1); + if (IS_ERR(dev)) + break; + moddevs[z] = dev; } - + if (!z) + return -EIO; return 0; } void cleanup_module(void) { - struct net_device *dev; - skmca_priv *priv; int z; for (z = 0; z < DEVMAX; z++) { - dev = moddevs + z; - if (dev->priv != NULL) { - priv = (skmca_priv *) dev->priv; - DeinitBoard(dev); - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; + struct net_device *dev = moddevs[z]; + if (dev) { unregister_netdev(dev); - mca_mark_as_unused(priv->slot); - mca_set_adapter_procfn(priv->slot, NULL, NULL); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/sk_mca.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/sk_mca.h 2003-12-30 22:49:20.000000000 -0800 @@ -178,7 +178,4 @@ typedef struct { /* LANCE Rx descriptor #endif /* _SK_MCA_DRIVER_ */ -extern int skmca_probe(struct net_device *); - - #endif /* _SK_MCA_INCLUDE_ */ --- linux-2.6.1-rc1/drivers/net/smc9194.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/smc9194.c 2003-12-30 22:49:20.000000000 -0800 @@ -191,7 +191,7 @@ struct smc_local { . . NB:This shouldn't be static since it is referred to externally. */ -int smc_init(struct net_device *dev); +struct net_device *smc_init(int unit); /* . The kernel calls this function when someone wants to use the device, @@ -672,7 +672,7 @@ static void smc_hardware_send_packet( st /*------------------------------------------------------------------------- | - | smc_init( struct net_device * dev ) + | smc_init(int unit) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code @@ -680,31 +680,56 @@ static void smc_hardware_send_packet( st | dev->base_addr == this is the address to check | | Output: - | 0 --> there is a device - | anything else, error + | pointer to net_device or ERR_PTR(error) | --------------------------------------------------------------------------- */ -int __init smc_init(struct net_device *dev) +static int io; +static int irq; +static int ifport; + +struct net_device * __init smc_init(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct smc_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } SET_MODULE_OWNER(dev); - /* try a specific location */ - if (base_addr > 0x1ff) - return smc_probe(dev, base_addr); - else if (base_addr != 0) - return -ENXIO; - - /* check every ethernet address */ - for (i = 0; smc_portlist[i]; i++) - if (smc_probe(dev, smc_portlist[i]) == 0) - return 0; - - /* couldn't find anything */ - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = smc_probe(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = smc_portlist; *port; port++) { + if (smc_probe(dev, *port) == 0) + break; + } + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, SMC_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /*---------------------------------------------------------------------- @@ -821,6 +846,9 @@ static int __init smc_probe(struct net_d if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; + dev->irq = irq; + dev->if_port = ifport; + /* First, see if the high byte is 0x33 */ bank = inw( ioaddr + BANK_SELECT ); if ( (bank & 0xFF00) != 0x3300 ) { @@ -969,28 +997,14 @@ static int __init smc_probe(struct net_d printk("%2.2x:", dev->dev_addr[i] ); printk("%2.2x \n", dev->dev_addr[5] ); - - /* Initialize the private structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } - } /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); - kfree(dev->priv); - dev->priv = NULL; goto err_out; } @@ -1524,10 +1538,7 @@ static void smc_set_multicast_list(struc #ifdef MODULE -static struct net_device devSMC9194; -static int io; -static int irq; -static int ifport; +static struct net_device *devSMC9194; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); @@ -1539,32 +1550,23 @@ MODULE_PARM_DESC(ifport, "SMC 99194 inte int init_module(void) { - int result; - if (io == 0) printk(KERN_WARNING CARDNAME": You shouldn't use auto-probing with insmod!\n" ); /* copy the parameters from insmod into the device structure */ - devSMC9194.base_addr = io; - devSMC9194.irq = irq; - devSMC9194.if_port = ifport; - devSMC9194.init = smc_init; - if ((result = register_netdev(&devSMC9194)) != 0) - return result; - + devSMC9194 = smc_init(-1); + if (IS_ERR(devSMC9194)) + return PTR_ERR(devSMC9194); return 0; } void cleanup_module(void) { - unregister_netdev(&devSMC9194); - - free_irq(devSMC9194.irq, &devSMC9194); - release_region(devSMC9194.base_addr, SMC_IO_EXTENT); - - if (devSMC9194.priv) - kfree(devSMC9194.priv); + unregister_netdev(devSMC9194); + free_irq(devSMC9194->irq, devSMC9194); + release_region(devSMC9194->base_addr, SMC_IO_EXTENT); + free_netdev(devSMC9194); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/smc-mca.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/smc-mca.c 2003-12-30 22:49:20.000000000 -0800 @@ -202,22 +202,18 @@ int __init ultramca_probe(struct device return -ENXIO; /* Adapter found. */ - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if(!dev) return -ENODEV; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gen_dev); - - rc = register_netdev(dev); - if (rc) - goto err_free_netdev; - - printk(KERN_INFO "%s: %s found in slot %d\n", - dev->name, smc_mca_adapter_names[adapter], slot + 1); - mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]); mca_device_set_claim(mca_dev, 1); + + printk(KERN_INFO "smc_mca: %s found in slot %d\n", + smc_mca_adapter_names[adapter], slot + 1); + ultra_found++; dev->base_addr = ioaddr = mca_device_transform_ioport(mca_dev, tbase); @@ -266,18 +262,18 @@ int __init ultramca_probe(struct device /* sanity check, shouldn't happen */ if (dev->mem_start == 0) { rc = -ENODEV; - goto err_unregister_netdev; + goto err_unclaim; } if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name)) { rc = -ENODEV; - goto err_unregister_netdev; + goto err_unclaim; } reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); - printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr); + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr); for (i = 0; i < 6; i++) printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); @@ -299,14 +295,6 @@ int __init ultramca_probe(struct device outb(reg4, ioaddr + 4); - /* Allocate dev->priv and fill in 8390 specific dev fields. - */ - - rc = ethdev_init(dev); - if (rc) { - printk (", no memory for dev->priv.\n"); - goto err_release_region; - } gen_dev->driver_data = dev; /* The 8390 isn't at the base address, so fake the offset @@ -339,13 +327,16 @@ int __init ultramca_probe(struct device NS8390_init(dev, 0); + rc = register_netdev(dev); + if (rc) + goto err_release_region; + return 0; err_release_region: release_region(ioaddr, ULTRA_IO_EXTENT); -err_unregister_netdev: - unregister_netdev(dev); -err_free_netdev: +err_unclaim: + mca_device_set_claim(mca_dev, 0); free_netdev(dev); return rc; } @@ -463,14 +454,14 @@ static int ultramca_remove(struct device struct mca_device *mca_dev = to_mca_device(gen_dev); struct net_device *dev = (struct net_device *)gen_dev->driver_data; - if(dev && dev->priv) { + if (dev) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); mca_device_set_claim(mca_dev, 0); release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); - kfree(dev->priv); + free_netdev(dev); } return 0; } --- linux-2.6.1-rc1/drivers/net/smc-ultra32.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/smc-ultra32.c 2003-12-30 22:49:20.000000000 -0800 @@ -61,7 +61,6 @@ static const char *version = "smc-ultra3 #include "8390.h" -int ultra32_probe(struct net_device *dev); static int ultra32_probe1(struct net_device *dev, int ioaddr); static int ultra32_open(struct net_device *dev); static void ultra32_reset_8390(struct net_device *dev); @@ -98,26 +97,59 @@ static int ultra32_close(struct net_devi #define ULTRA32_CFG6 (-0x15) /* 0xc8b */ #define ULTRA32_CFG7 0x0d /* 0xcad */ +static void cleanup_card(struct net_device *dev) +{ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; + /* NB: ultra32_close_card() does free_irq */ + release_region(ioaddr, ULTRA32_IO_EXTENT); +} /* Probe for the Ultra32. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. */ -int __init ultra32_probe(struct net_device *dev) +struct net_device * __init ultra32_probe(int unit) { - int ioaddr; - - if (!EISA_bus) return -ENODEV; + struct net_device *dev; + int base; + int irq; + int err = -ENODEV; + + if (!EISA_bus) + return ERR_PTR(-ENODEV); + + dev = alloc_ei_netdev(); + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - /* EISA spec allows for up to 16 slots, but 8 is typical. */ - for (ioaddr = 0x1000 + ULTRA32_BASE; ioaddr < 0x9000; ioaddr += 0x1000) - if (ultra32_probe1(dev, ioaddr) == 0) - return 0; + irq = dev->irq; - return -ENODEV; + /* EISA spec allows for up to 16 slots, but 8 is typical. */ + for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) { + if (ultra32_probe1(dev, base) == 0) + break; + dev->irq = irq; + } + if (base >= 0x9000) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init ultra32_probe1(struct net_device *dev, int ioaddr) @@ -210,13 +242,6 @@ static int __init ultra32_probe1(struct dev->irq = irq; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", no memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* The 8390 isn't at the base address, so fake the offset */ dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET; @@ -380,7 +405,7 @@ static void ultra32_block_output(struct #ifdef MODULE #define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device dev_ultra[MAX_ULTRA32_CARDS]; +static struct net_device *dev_ultra[MAX_ULTRA32_CARDS]; MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver"); MODULE_LICENSE("GPL"); @@ -390,18 +415,15 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - dev->init = ultra32_probe; - if (register_netdev(dev) != 0) { - if (found > 0) { /* Got at least one. */ - return 0; - } - printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); - return -ENXIO; - } - found++; + struct net_device *dev = ultra32_probe(-1); + if (IS_ERR(dev)) + break; + dev_ultra[found++] = dev; } - return 0; + if (found) + return 0; + printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); + return -ENXIO; } void cleanup_module(void) @@ -409,14 +431,11 @@ void cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; - void *priv = dev->priv; - /* NB: ultra32_close_card() does free_irq */ - release_region(ioaddr, ULTRA32_IO_EXTENT); + struct net_device *dev = dev_ultra[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/smc-ultra.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/smc-ultra.c 2003-12-30 22:49:20.000000000 -0800 @@ -76,7 +76,6 @@ static const char version[] = static unsigned int ultra_portlist[] __initdata = {0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0}; -int ultra_probe(struct net_device *dev); static int ultra_probe1(struct net_device *dev, int ioaddr); #ifdef __ISAPNP__ @@ -122,18 +121,30 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device #define ULTRA_IO_EXTENT 32 #define EN0_ERWCNT 0x08 /* Early receive warning count. */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ultra_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. */ -int __init ultra_probe(struct net_device *dev) +static int __init do_ultra_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &ultra_poll; +#endif if (base_addr > 0x1ff) /* Check a single specified location. */ return ultra_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -147,13 +158,51 @@ int __init ultra_probe(struct net_device printk(KERN_NOTICE "smc-ultra.c: No ISAPnP cards found, trying standard ones...\n"); #endif - for (i = 0; ultra_portlist[i]; i++) + for (i = 0; ultra_portlist[i]; i++) { + dev->irq = irq; if (ultra_probe1(dev, ultra_portlist[i]) == 0) return 0; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: ultra_close_card() does free_irq */ +#ifdef __ISAPNP__ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); +#endif + release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); +} + +struct net_device * __init ultra_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ultra_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ultra_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -226,13 +275,6 @@ static int __init ultra_probe1(struct ne eeprom_irq = 1; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", no memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* The 8390 isn't at the base address, so fake the offset */ dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; @@ -500,7 +542,7 @@ ultra_close_card(struct net_device *dev) #ifdef MODULE #define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device dev_ultra[MAX_ULTRA_CARDS]; +static struct net_device *dev_ultra[MAX_ULTRA_CARDS]; static int io[MAX_ULTRA_CARDS]; static int irq[MAX_ULTRA_CARDS]; @@ -516,26 +558,33 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = ultra_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_ultra_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ultra[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); + break; } - - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -544,20 +593,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - if (dev->priv != NULL) { - /* NB: ultra_close_card() does free_irq */ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; - -#ifdef __ISAPNP__ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); -#endif - + struct net_device *dev = dev_ultra[this_dev]; + if (dev) { unregister_netdev(dev); - release_region(ioaddr, ULTRA_IO_EXTENT); - kfree(dev->priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/Space.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/Space.c 2003-12-30 22:49:20.000000000 -0800 @@ -40,63 +40,62 @@ ethernet adaptor have the name "eth[0123...]". */ -extern int ne2_probe(struct net_device *dev); -extern int hp100_probe(struct net_device *dev); -extern int ultra_probe(struct net_device *dev); -extern int ultra32_probe(struct net_device *dev); -extern int wd_probe(struct net_device *dev); -extern int el2_probe(struct net_device *dev); -extern int ne_probe(struct net_device *dev); -extern int hp_probe(struct net_device *dev); -extern int hp_plus_probe(struct net_device *dev); -extern int express_probe(struct net_device *); -extern int eepro_probe(struct net_device *); -extern int at1500_probe(struct net_device *); -extern int at1700_probe(struct net_device *); -extern int fmv18x_probe(struct net_device *); -extern int eth16i_probe(struct net_device *); -extern int i82596_probe(struct net_device *); -extern int ewrk3_probe(struct net_device *); -extern int el1_probe(struct net_device *); -extern int wavelan_probe(struct net_device *); -extern int arlan_probe(struct net_device *); -extern int el16_probe(struct net_device *); -extern int elmc_probe(struct net_device *); -extern int skmca_probe(struct net_device *); -extern int elplus_probe(struct net_device *); -extern int ac3200_probe(struct net_device *); -extern int es_probe(struct net_device *); -extern int lne390_probe(struct net_device *); -extern int e2100_probe(struct net_device *); -extern int ni5010_probe(struct net_device *); -extern int ni52_probe(struct net_device *); -extern int ni65_probe(struct net_device *); -extern int sonic_probe(struct net_device *); -extern int SK_init(struct net_device *); -extern int seeq8005_probe(struct net_device *); -extern int smc_init( struct net_device * ); -extern int atarilance_probe(struct net_device *); -extern int sun3lance_probe(struct net_device *); -extern int sun3_82586_probe(struct net_device *); -extern int apne_probe(struct net_device *); -extern int bionet_probe(struct net_device *); -extern int pamsnet_probe(struct net_device *); -extern int cs89x0_probe(struct net_device *dev); -extern int hplance_probe(struct net_device *dev); -extern int bagetlance_probe(struct net_device *); -extern int mvme147lance_probe(struct net_device *dev); -extern int tc515_probe(struct net_device *dev); -extern int lance_probe(struct net_device *dev); -extern int mace_probe(struct net_device *dev); -extern int macsonic_probe(struct net_device *dev); -extern int mac8390_probe(struct net_device *dev); -extern int mac89x0_probe(struct net_device *dev); -extern int mc32_probe(struct net_device *dev); +extern struct net_device *ne2_probe(int unit); +extern struct net_device *hp100_probe(int unit); +extern struct net_device *ultra_probe(int unit); +extern struct net_device *ultra32_probe(int unit); +extern struct net_device *wd_probe(int unit); +extern struct net_device *el2_probe(int unit); +extern struct net_device *ne_probe(int unit); +extern struct net_device *hp_probe(int unit); +extern struct net_device *hp_plus_probe(int unit); +extern struct net_device *express_probe(int unit); +extern struct net_device *eepro_probe(int unit); +extern struct net_device *at1700_probe(int unit); +extern struct net_device *fmv18x_probe(int unit); +extern struct net_device *eth16i_probe(int unit); +extern struct net_device *i82596_probe(int unit); +extern struct net_device *ewrk3_probe(int unit); +extern struct net_device *el1_probe(int unit); +extern struct net_device *wavelan_probe(int unit); +extern struct net_device *arlan_probe(int unit); +extern struct net_device *el16_probe(int unit); +extern struct net_device *elmc_probe(int unit); +extern struct net_device *skmca_probe(int unit); +extern struct net_device *elplus_probe(int unit); +extern struct net_device *ac3200_probe(int unit); +extern struct net_device *es_probe(int unit); +extern struct net_device *lne390_probe(int unit); +extern struct net_device *e2100_probe(int unit); +extern struct net_device *ni5010_probe(int unit); +extern struct net_device *ni52_probe(int unit); +extern struct net_device *ni65_probe(int unit); +extern struct net_device *sonic_probe(int unit); +extern struct net_device *SK_init(int unit); +extern struct net_device *seeq8005_probe(int unit); +extern struct net_device *smc_init(int unit); +extern struct net_device *atarilance_probe(int unit); +extern struct net_device *sun3lance_probe(int unit); +extern struct net_device *sun3_82586_probe(int unit); +extern struct net_device *apne_probe(int unit); +extern struct net_device *bionet_probe(int unit); +extern struct net_device *pamsnet_probe(int unit); +extern struct net_device *cs89x0_probe(int unit); +extern struct net_device *hplance_probe(int unit); +extern struct net_device *bagetlance_probe(int unit); +extern struct net_device *mvme147lance_probe(int unit); +extern struct net_device *tc515_probe(int unit); +extern struct net_device *lance_probe(int unit); +extern struct net_device *mace_probe(int unit); +extern struct net_device *macsonic_probe(int unit); +extern struct net_device *mac8390_probe(int unit); +extern struct net_device *mac89x0_probe(int unit); +extern struct net_device *mc32_probe(int unit); extern struct net_device *cops_probe(int unit); extern struct net_device *ltpc_probe(void); /* Detachable devices ("pocket adaptors") */ -extern int de620_probe(struct net_device *); +extern struct net_device *de620_probe(int unit); /* Fibre Channel adapters */ extern int iph5526_probe(struct net_device *dev); @@ -104,33 +103,22 @@ extern int iph5526_probe(struct net_devi /* SBNI adapters */ extern int sbni_probe(int unit); -struct devprobe -{ - int (*probe)(struct net_device *dev); +struct devprobe2 { + struct net_device *(*probe)(int unit); int status; /* non-zero if autoprobe has failed */ }; -/* - * probe_list walks a list of probe functions and calls each so long - * as a non-zero ioaddr is given, or as long as it hasn't already failed - * to find a card in the past (as recorded by "status") when asked to - * autoprobe (i.e. a probe that fails to find a card when autoprobing - * will not be asked to autoprobe again). It exits when a card is found. - */ -static int __init probe_list(struct net_device *dev, struct devprobe *plist) +static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe) { - struct devprobe *p = plist; - unsigned long base_addr = dev->base_addr; - - while (p->probe != NULL) { - if (base_addr && p->probe(dev) == 0) /* probe given addr */ + struct net_device *dev; + for (; p->probe; p++) { + if (autoprobe && p->status) + continue; + dev = p->probe(unit); + if (!IS_ERR(dev)) return 0; - else if (p->status == 0) { /* has autoprobe failed yet? */ - p->status = p->probe(dev); /* no, try autoprobe */ - if (p->status == 0) - return 0; - } - p++; + if (autoprobe) + p->status = PTR_ERR(dev); } return -ENODEV; } @@ -141,7 +129,8 @@ static int __init probe_list(struct net_ * drivers that probe for EISA cards (in the ISA group). These are the * legacy EISA only driver probes, and also the legacy PCI probes */ -static struct devprobe eisa_probes[] __initdata = { + +static struct devprobe2 eisa_probes[] __initdata = { #ifdef CONFIG_ULTRA32 {ultra32_probe, 0}, #endif @@ -157,8 +146,7 @@ static struct devprobe eisa_probes[] __i {NULL, 0}, }; - -static struct devprobe mca_probes[] __initdata = { +static struct devprobe2 mca_probes[] __initdata = { #ifdef CONFIG_NE2_MCA {ne2_probe, 0}, #endif @@ -178,7 +166,7 @@ static struct devprobe mca_probes[] __in * ISA probes that touch addresses < 0x400 (including those that also * look for EISA/PCI/MCA cards in addition to ISA cards). */ -static struct devprobe isa_probes[] __initdata = { +static struct devprobe2 isa_probes[] __initdata = { #ifdef CONFIG_HP100 /* ISA, EISA & PCI */ {hp100_probe, 0}, #endif @@ -215,9 +203,6 @@ static struct devprobe isa_probes[] __in #ifdef CONFIG_SEEQ8005 {seeq8005_probe, 0}, #endif -#ifdef CONFIG_AT1500 - {at1500_probe, 0}, -#endif #ifdef CONFIG_CS89x0 {cs89x0_probe, 0}, #endif @@ -272,14 +257,14 @@ static struct devprobe isa_probes[] __in {NULL, 0}, }; -static struct devprobe parport_probes[] __initdata = { +static struct devprobe2 parport_probes[] __initdata = { #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ {de620_probe, 0}, #endif {NULL, 0}, }; -static struct devprobe m68k_probes[] __initdata = { +static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ {atarilance_probe, 0}, #endif @@ -319,7 +304,7 @@ static struct devprobe m68k_probes[] __i {NULL, 0}, }; -static struct devprobe mips_probes[] __initdata = { +static struct devprobe2 mips_probes[] __initdata = { #ifdef CONFIG_MIPS_JAZZ_SONIC {sonic_probe, 0}, #endif @@ -334,83 +319,65 @@ static struct devprobe mips_probes[] __i * per bus interface. This drives the legacy devices only for now. */ -static int __init ethif_probe(int unit) +static void __init ethif_probe2(int unit) { - struct net_device *dev; - int err = -ENODEV; + unsigned long base_addr = netdev_boot_base("eth", unit); - dev = alloc_etherdev(0); - if (!dev) - return -ENOMEM; - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - /* - * Backwards compatibility - historically an I/O base of 1 was - * used to indicate not to probe for this ethN interface - */ - if (dev->base_addr == 1) { - free_netdev(dev); - return -ENXIO; - } - - /* - * The arch specific probes are 1st so that any on-board ethernet - * will be probed before other ISA/EISA/MCA/PCI bus cards. - */ - if (probe_list(dev, m68k_probes) == 0 || - probe_list(dev, mips_probes) == 0 || - probe_list(dev, eisa_probes) == 0 || - probe_list(dev, mca_probes) == 0 || - probe_list(dev, isa_probes) == 0 || - probe_list(dev, parport_probes) == 0) - err = register_netdev(dev); - - if (err) - free_netdev(dev); - return err; + if (base_addr == 1) + return; + (void)( probe_list2(unit, m68k_probes, base_addr == 0) && + probe_list2(unit, mips_probes, base_addr == 0) && + probe_list2(unit, eisa_probes, base_addr == 0) && + probe_list2(unit, mca_probes, base_addr == 0) && + probe_list2(unit, isa_probes, base_addr == 0) && + probe_list2(unit, parport_probes, base_addr == 0)); } #ifdef CONFIG_TR /* Token-ring device probe */ -extern int ibmtr_probe(struct net_device *); -extern int sk_isa_probe(struct net_device *); -extern int proteon_probe(struct net_device *); -extern int smctr_probe(struct net_device *); +extern int ibmtr_probe_card(struct net_device *); +extern struct net_device *sk_isa_probe(int unit); +extern struct net_device *proteon_probe(int unit); +extern struct net_device *smctr_probe(int unit); + +static struct devprobe2 tr_probes2[] __initdata = { +#ifdef CONFIG_SKISA + {sk_isa_probe, 0}, +#endif +#ifdef CONFIG_PROTEON + {proteon_probe, 0}, +#endif +#ifdef CONFIG_SMCTR + {smctr_probe, 0}, +#endif + {NULL, 0}, +}; static __init int trif_probe(int unit) { - struct net_device *dev; int err = -ENODEV; - - dev = alloc_trdev(0); +#ifdef CONFIG_IBMTR + struct net_device *dev = alloc_trdev(0); if (!dev) return -ENOMEM; sprintf(dev->name, "tr%d", unit); netdev_boot_setup_check(dev); - if ( -#ifdef CONFIG_IBMTR - ibmtr_probe(dev) == 0 || -#endif -#ifdef CONFIG_SKISA - sk_isa_probe(dev) == 0 || -#endif -#ifdef CONFIG_PROTEON - proteon_probe(dev) == 0 || -#endif -#ifdef CONFIG_SMCTR - smctr_probe(dev) == 0 || -#endif - 0 ) - err = register_netdev(dev); - + err = ibmtr_probe_card(dev); if (err) free_netdev(dev); +#endif return err; +} + +static void __init trif_probe2(int unit) +{ + unsigned long base_addr = netdev_boot_base("tr", unit); + if (base_addr == 1) + return; + probe_list2(unit, tr_probes2, base_addr == 0); } #endif @@ -437,10 +404,11 @@ static int __init net_olddevs_init(void) #endif #ifdef CONFIG_TR for (num = 0; num < 8; ++num) - trif_probe(num); + if (!trif_probe(num)) + trif_probe2(num); #endif for (num = 0; num < 8; ++num) - ethif_probe(num); + ethif_probe2(num); #ifdef CONFIG_COPS cops_probe(0); --- linux-2.6.1-rc1/drivers/net/starfire.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/starfire.c 2003-12-30 22:49:20.000000000 -0800 @@ -139,7 +139,6 @@ TODO: bugfixes (no bugs known as of righ #include #include #include -#include #include #include #include --- linux-2.6.1-rc1/drivers/net/stnic.c 2003-06-14 12:18:25.000000000 -0700 +++ 25/drivers/net/stnic.c 2003-12-30 22:49:20.000000000 -0800 @@ -98,28 +98,20 @@ STNIC_WRITE (int reg, byte val) STNIC_DELAY (); } -int __init stnic_probe(void) +static int __init stnic_probe(void) { struct net_device *dev; - int i; + int i, err; /* If we are not running on a SolutionEngine, give up now */ if (! MACH_SE) return -ENODEV; /* New style probing API */ - dev = init_etherdev (NULL, 0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); - stnic_dev = dev; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init (dev)) - { - printk (KERN_EMERG "Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_get_node_addr (stnic_eadr); @@ -135,13 +127,11 @@ int __init stnic_probe(void) /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ - i = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); - if (i) { + err = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); + if (err) { printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); - unregister_netdev(dev); - kfree(dev->priv); - kfree(dev); - return i; + free_netdev(dev); + return err; } ei_status.name = dev->name; @@ -162,6 +152,14 @@ int __init stnic_probe(void) stnic_init (dev); + err = register_netdev(dev); + if (err) { + free_irq(dev->irq, dev); + free_netdev(dev); + return err; + } + stnic_dev = dev; + printk (KERN_INFO "NS ST-NIC 83902A\n"); return 0; @@ -305,15 +303,13 @@ stnic_init (struct net_device *dev) return; } -/* Hardware interrupt handler. */ -extern void ei_interrupt (int irq, void *dev_id, struct pt_regs *regs); - -void -do_stnic_intr (int irq, void *dev_id, struct pt_regs *regs) +static void __exit stnic_cleanup(void) { - ei_interrupt (0, stnic_dev, regs); + unregister_netdev(stnic_dev); + free_irq(stnic_dev->irq, stnic_dev); + free_netdev(stnic_dev); } module_init(stnic_probe); -/* No cleanup routine. */ +module_exit(stnic_cleanup); MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/net/sun3_82586.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/net/sun3_82586.c 2003-12-30 22:49:20.000000000 -0800 @@ -55,6 +55,7 @@ static int fifo=0x8; /* don't change */ #define DEBUG /* debug on */ #define SYSBUSVAL 0 /* 16 Bit */ +#define SUN3_82586_TOTAL_SIZE PAGE_SIZE #define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;} #define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;} @@ -277,10 +278,12 @@ static void alloc586(struct net_device * memset((char *)p->scb,0,sizeof(struct scb_struct)); } -int __init sun3_82586_probe(struct net_device *dev) +struct net_device * __init sun3_82586_probe(int unit) { + struct net_device *dev; unsigned long ioaddr; static int found = 0; + int err = -ENOMEM; /* check that this machine has an onboard 82586 */ switch(idprom->id_machtype) { @@ -290,31 +293,51 @@ int __init sun3_82586_probe(struct net_d break; default: - return(-ENODEV); + return ERR_PTR(-ENODEV); } - if(found) - return -ENODEV; + if (found) + return ERR_PTR(-ENODEV); - ioaddr = (unsigned long)ioremap(IE_OBIO, PAGE_SIZE); + ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE); + if (!ioaddr) + return ERR_PTR(-ENOMEM); found = 1; + dev = alloc_etherdev(sizeof(struct priv)); + if (!dev) + goto out; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); dev->irq = IE_IRQ; dev->base_addr = ioaddr; - if(sun3_82586_probe1(dev, ioaddr) == 0) - return 0; - - return -ENODEV; + err = sun3_82586_probe1(dev, ioaddr); + if (err) + goto out1; + err = register_netdev(dev); + if (err) + goto out2; + return dev; + +out2: + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); +out1: + free_netdev(dev); +out: + iounmap((void *)ioaddr); + return ERR_PTR(err); } static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; -// if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) -// return -EBUSY; + if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) + return -EBUSY; /* copy in the ethernet address from the prom */ for(i = 0; i < 6 ; i++) @@ -341,16 +364,6 @@ static int __init sun3_82586_probe1(stru goto out; } - dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); - if(dev->priv == NULL) { - printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); - retval = -ENOMEM; - goto out; - } - - /* warning: we don't free it on errors */ - memset((char *) dev->priv,0,sizeof(struct priv)); - ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start); ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0); alloc586(dev); @@ -374,11 +387,9 @@ static int __init sun3_82586_probe1(stru dev->set_multicast_list = set_multicast_list; dev->if_port = 0; - - ether_setup(dev); - return 0; out: + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); return retval; } @@ -1138,21 +1149,23 @@ static void set_multicast_list(struct ne #ifdef MODULE #error This code is not currently supported as a module -static struct net_device dev_sun3_82586; +static struct net_device *dev_sun3_82586; int init_module(void) { - dev_sun3_82586.init = sun3_82586_probe; - if (register_netdev(&dev_sun3_82586) != 0) - return -EIO; + dev_sun3_82586 = sun3_82586_probe(-1); + if (IS_ERR(dev_sun3_82586)) + return PTR_ERR(dev_sun3_82586); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_sun3_82586); - kfree(dev_sun3_82586.priv); - dev_sun3_82586.priv = NULL; + unsigned long ioaddr = dev_sun3_82586->base_addr; + unregister_netdev(dev_sun3_82586); + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); + iounmap((void *)ioaddr); + free_netdev(dev_sun3_82586); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/sun3lance.c 2003-06-14 12:18:32.000000000 -0700 +++ 25/drivers/net/sun3lance.c 2003-12-30 22:49:20.000000000 -0800 @@ -246,9 +246,11 @@ static void set_multicast_list( struct n /************************* End of Prototypes **************************/ -int __init sun3lance_probe( struct net_device *dev ) -{ +struct net_device * __init sun3lance_probe(int unit) +{ + struct net_device *dev; static int found; + int err = -ENODEV; /* check that this machine has an onboard lance */ switch(idprom->id_machtype) { @@ -259,18 +261,37 @@ int __init sun3lance_probe( struct net_d break; default: - return(-ENODEV); + return ERR_PTR(-ENODEV); } - if(found) - return(-ENODEV); + if (found) + return ERR_PTR(-ENODEV); - if (lance_probe(dev)) { - found = 1; - return( 0 ); + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); } + SET_MODULE_OWNER(dev); + + if (!lance_probe(dev)) + goto out; - return( -ENODEV ); + err = register_netdev(dev); + if (err) + goto out1; + found = 1; + return dev; + +out1: +#ifdef CONFIG_SUN3 + iounmap((void *)dev->base_addr); +#endif +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init lance_probe( struct net_device *dev) @@ -285,6 +306,8 @@ static int __init lance_probe( struct ne #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); + if (!ioaddr) + return 0; #else ioaddr = SUN3X_LANCE; #endif @@ -303,17 +326,15 @@ static int __init lance_probe( struct ne ioaddr_probe[0] = tmp1; ioaddr_probe[1] = tmp2; +#ifdef CONFIG_SUN3 + iounmap((void *)ioaddr); +#endif return 0; } - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; + /* XXX - leak? */ MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); lp->iobase = (volatile unsigned short *)ioaddr; @@ -921,32 +942,24 @@ static void set_multicast_list( struct n #ifdef MODULE -static char devicename[9]; -static struct net_device sun3lance_dev = -{ - devicename, /* filled in by register_netdev() */ - 0, 0, 0, 0, /* memory */ - 0, 0, /* base, irq */ - 0, 0, 0, NULL, sun3lance_probe, -}; +static struct net_device *sun3lance_dev; int init_module(void) { - int err; - - if ((err = register_netdev( &sun3lance_dev ))) { - if (err == -EIO) { - printk( "SUN3 Lance not detected. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); + sun3lance_dev = sun3lance_probe(-1); + if (IS_ERR(sun3lance_dev)) + return PTR_ERR(sun3lance_dev); + return 0; } void cleanup_module(void) { - unregister_netdev( &sun3lance_dev ); + unregister_netdev(sun3lance_dev); +#ifdef CONFIG_SUN3 + iounmap((void *)sun3lance_dev->base_addr); +#endif + free_netdev(sun3lance_dev); } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/tc35815.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tc35815.c 2003-12-30 22:49:20.000000000 -0800 @@ -463,7 +463,6 @@ static void tc35815_set_multicast_list(s static void tc35815_chip_reset(struct net_device *dev); static void tc35815_chip_init(struct net_device *dev); static void tc35815_phy_chip_init(struct net_device *dev); -static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); /* A list of all installed tc35815 devices. */ static struct net_device *root_tc35815_dev = NULL; @@ -482,78 +481,76 @@ int tc35815_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int called = 0; int err = 0; int ret; + unsigned long pci_memaddr; + unsigned int pci_irq_line; - if (called) - return -ENODEV; - called++; + printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); - if (pdev) { - unsigned int pci_memaddr; - unsigned int pci_irq_line; + err = pci_enable_device(pdev); + if (err) + return err; - printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); + pci_memaddr = pci_resource_start (pdev, 1); - pci_memaddr = pci_resource_start (pdev, 1); + printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); - printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); + if (!pci_memaddr) { + printk(KERN_WARNING "no PCI MEM resources, aborting\n"); + ret = -ENODEV; + goto err_out; + } + pci_irq_line = pdev->irq; + /* irq disabled. */ + if (pci_irq_line == 0) { + printk(KERN_WARNING "no PCI irq, aborting\n"); + ret = -ENODEV; + goto err_out; + } - if (!pci_memaddr) { - printk(KERN_WARNING "no PCI MEM resources, aborting\n"); - return -ENODEV; - } - pci_irq_line = pdev->irq; - /* irq disabled. */ - if (pci_irq_line == 0) { - printk(KERN_WARNING "no PCI irq, aborting\n"); - return -ENODEV; - } + ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + if (ret) + goto err_out; - ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + pci_set_master(pdev); - if (!ret) { - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err); - return err; - } - pci_set_master(pdev); - } + return 0; - return ret; - } - return -ENODEV; +err_out: + pci_disable_device(pdev); + return ret; } static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) { static unsigned version_printed = 0; - int i; + int i, ret; struct tc35815_local *lp; struct tc35815_regs *tr; struct net_device *dev; /* Allocate a new 'dev' if needed. */ - dev = init_etherdev(NULL, sizeof(struct tc35815_local)); + dev = alloc_etherdev(sizeof(struct tc35815_local)); if (dev == NULL) return -ENOMEM; /* - * init_etherdev allocs and zeros dev->priv + * alloc_etherdev allocs and zeros dev->priv */ lp = dev->priv; if (tc35815_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); - printk(KERN_INFO "%s: %s found at %#x, irq %d\n", - dev->name, cardname, base_addr, irq); - /* Fill in the 'dev' fields. */ dev->irq = irq; dev->base_addr = (unsigned long)ioremap(base_addr, sizeof(struct tc35815_regs)); + if (!dev->base_addr) { + ret = -ENOMEM; + goto err_out; + } tr = (struct tc35815_regs*)dev->base_addr; tc35815_chip_reset(dev); @@ -570,9 +567,6 @@ static int __devinit tc35815_probe1(stru dev->dev_addr[i] = data & 0xff; dev->dev_addr[i+1] = data >> 8; } - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk("\n"); /* Initialize the device structure. */ lp->pdev = pdev; @@ -594,8 +588,6 @@ static int __devinit tc35815_probe1(stru /* do auto negotiation */ tc35815_phy_chip_init(dev); - printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", - dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); dev->open = tc35815_open; dev->stop = tc35815_close; @@ -604,20 +596,34 @@ static int __devinit tc35815_probe1(stru dev->hard_start_xmit = tc35815_send_packet; dev->get_stats = tc35815_get_stats; dev->set_multicast_list = tc35815_set_multicast_list; + SET_MODULE_OWNER(dev); -#if 0 /* XXX called in init_etherdev */ - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); -#endif + ret = register_netdev(dev); + if (ret) + goto err_out_iounmap; + + printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", + dev->name, cardname, base_addr, irq); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk("\n"); + printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", + dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); return 0; + +err_out_iounmap: + iounmap((void *) dev->base_addr); +err_out: + free_netdev(dev); + return ret; } static int tc35815_init_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; unsigned long fd_addr; @@ -702,7 +708,7 @@ tc35815_init_queues(struct net_device *d static void tc35815_clear_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; for (i = 0; i < TX_FD_NUM; i++) { @@ -719,7 +725,7 @@ tc35815_clear_queues(struct net_device * static void tc35815_free_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; if (lp->tfd_base) { @@ -805,7 +811,7 @@ dump_frfd(struct FrFD *fd) static void panic_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; printk("TxFD base %p, start %d, end %d\n", @@ -823,6 +829,7 @@ panic_queues(struct net_device *dev) panic("%s: Illegal queue state.", dev->name); } +#if 0 static void print_buf(char *add, int length) { int i; @@ -839,6 +846,7 @@ static void print_buf(char *add, int len } printk("\n"); } +#endif static void print_eth(char *add) { @@ -864,7 +872,7 @@ static void print_eth(char *add) static int tc35815_open(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; /* * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. @@ -888,19 +896,17 @@ tc35815_open(struct net_device *dev) lp->tbusy = 0; netif_start_queue(dev); - MOD_INC_USE_COUNT; - return 0; } static void tc35815_tx_timeout(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; - int flags; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ tc35815_chip_reset(dev); @@ -914,7 +920,7 @@ static void tc35815_tx_timeout(struct ne static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; if (netif_queue_stopped(dev)) { @@ -925,7 +931,7 @@ static int tc35815_send_packet(struct sk int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ tc35815_chip_reset(dev); @@ -947,7 +953,7 @@ static int tc35815_send_packet(struct sk short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; - int flags; + unsigned long flags; lp->stats.tx_bytes += skb->len; @@ -1051,7 +1057,7 @@ static irqreturn_t tc35815_interrupt(int } tr = (struct tc35815_regs*)dev->base_addr; - lp = (struct tc35815_local *)dev->priv; + lp = dev->priv; do { status = tc_readl(&tr->Int_Src); @@ -1107,7 +1113,7 @@ static irqreturn_t tc35815_interrupt(int static void tc35815_rx(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned int fdctl; int i; @@ -1157,7 +1163,9 @@ tc35815_rx(struct net_device *dev) offset += len; cur_bd++; } - // print_buf(data,pkt_len); +#if 0 + print_buf(data,pkt_len); +#endif if (tc35815_debug > 3) print_eth(data); skb->protocol = eth_type_trans(skb, dev); @@ -1247,7 +1255,7 @@ tc35815_rx(struct net_device *dev) static void tc35815_check_tx_stat(struct net_device *dev, int status) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; const char *msg = NULL; /* count collisions */ @@ -1304,7 +1312,7 @@ tc35815_check_tx_stat(struct net_device static void tc35815_txdone(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; struct TxFD *txfd; unsigned int fdctl; @@ -1379,7 +1387,7 @@ tc35815_txdone(struct net_device *dev) static int tc35815_close(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; lp->tbusy = 1; netif_stop_queue(dev); @@ -1391,8 +1399,6 @@ tc35815_close(struct net_device *dev) tc35815_free_queues(dev); - MOD_DEC_USE_COUNT; - return 0; } @@ -1402,7 +1408,7 @@ tc35815_close(struct net_device *dev) */ static struct net_device_stats *tc35815_get_stats(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned long flags; @@ -1456,7 +1462,7 @@ static void tc35815_set_cam_entry(struct int i; for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { tc_writel(i * 4, &tr->CAM_Adr); - printk("CAM 0x%x: %08x", + printk("CAM 0x%x: %08lx", i * 4, tc_readl(&tr->CAM_Data)); } } @@ -1513,9 +1519,9 @@ tc35815_set_multicast_list(struct net_de static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; unsigned long data; - int flags; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1529,8 +1535,8 @@ static unsigned long tc_phy_read(struct static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; - int flags; + struct tc35815_local *lp = dev->priv; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1543,7 +1549,7 @@ static void tc_phy_write(struct net_devi static void tc35815_phy_chip_init(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; static int first = 1; unsigned short ctl; @@ -1648,9 +1654,9 @@ static void tc35815_chip_reset(struct ne static void tc35815_chip_init(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; - int flags; + unsigned long flags; unsigned long txctl = TX_CTL_CMD; tc35815_phy_chip_init(dev); @@ -1696,40 +1702,6 @@ static void tc35815_chip_init(struct net spin_unlock_irqrestore(&lp->lock, flags); } -static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) -{ - int len = 0; - off_t pos = 0; - off_t begin = 0; - struct net_device *dev; - - len += sprintf(buffer, "TC35815 statistics:\n"); - for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; - len += sprintf(buffer + len, - "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n", - dev->name, - lp->lstats.tx_ints, - lp->lstats.rx_ints, - lp->lstats.max_tx_qlen); - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset+length) break; - } - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return len; -} - /* XXX */ void tc35815_killall(void) --- linux-2.6.1-rc1/drivers/net/tg3.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/tg3.c 2003-12-30 22:49:20.000000000 -0800 @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "2.3" -#define DRV_MODULE_RELDATE "November 5, 2003" +#define DRV_MODULE_VERSION "2.4" +#define DRV_MODULE_RELDATE "December 2, 2003" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -176,6 +176,10 @@ static struct pci_device_id tg3_pci_tbl[ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX, @@ -2475,6 +2479,13 @@ static irqreturn_t tg3_interrupt(int irq static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tg3_poll_controller(struct net_device *dev) +{ + tg3_interrupt(dev->irq, dev, NULL); +} +#endif + static void tg3_reset_task(void *_data) { struct tg3 *tp = _data; @@ -2688,7 +2699,13 @@ static int tg3_start_xmit_4gbug(struct s mss |= (tsflags << 11); } } else { - mss += tcp_opt_len; + if (tcp_opt_len || skb->nh.iph->ihl > 5) { + int tsflags; + + tsflags = ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)); + base_flags |= tsflags << 12; + } } } #else @@ -2895,7 +2912,13 @@ static int tg3_start_xmit(struct sk_buff mss |= (tsflags << 11); } } else { - mss += tcp_opt_len; + if (tcp_opt_len || skb->nh.iph->ihl > 5) { + int tsflags; + + tsflags = ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)); + base_flags |= tsflags << 12; + } } } #else @@ -3860,180 +3883,181 @@ static int tg3_load_5701_a0_firmware_fix #if TG3_TSO_SUPPORT != 0 #define TG3_TSO_FW_RELEASE_MAJOR 0x1 -#define TG3_TSO_FW_RELASE_MINOR 0x3 +#define TG3_TSO_FW_RELASE_MINOR 0x4 #define TG3_TSO_FW_RELEASE_FIX 0x0 #define TG3_TSO_FW_START_ADDR 0x08000000 #define TG3_TSO_FW_TEXT_ADDR 0x08000000 -#define TG3_TSO_FW_TEXT_LEN 0x1ac0 -#define TG3_TSO_FW_RODATA_ADDR 0x08001650 +#define TG3_TSO_FW_TEXT_LEN 0x1a90 +#define TG3_TSO_FW_RODATA_ADDR 0x08001a900 #define TG3_TSO_FW_RODATA_LEN 0x60 -#define TG3_TSO_FW_DATA_ADDR 0x080016a0 +#define TG3_TSO_FW_DATA_ADDR 0x08001b20 #define TG3_TSO_FW_DATA_LEN 0x20 -#define TG3_TSO_FW_SBSS_ADDR 0x080016c0 +#define TG3_TSO_FW_SBSS_ADDR 0x08001b40 #define TG3_TSO_FW_SBSS_LEN 0x2c -#define TG3_TSO_FW_BSS_ADDR 0x080016e0 -#define TG3_TSO_FW_BSS_LEN 0x890 +#define TG3_TSO_FW_BSS_ADDR 0x08001b70 +#define TG3_TSO_FW_BSS_LEN 0x894 static u32 tg3TsoFwText[] = { 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd4000, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000010, 0x00000000, 0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0x3c04fefe, - 0xafbf0018, 0x0e0005e0, 0x34840002, 0x0e000670, 0x00000000, 0x3c030800, - 0x90631b78, 0x24020002, 0x3c040800, 0x24841acc, 0x14620003, 0x24050001, - 0x3c040800, 0x24841ac0, 0x24060002, 0x00003821, 0xafa00010, 0x0e000684, + 0xafbf0018, 0x0e0005d4, 0x34840002, 0x0e000664, 0x00000000, 0x3c030800, + 0x90631b58, 0x24020002, 0x3c040800, 0x24841a9c, 0x14620003, 0x24050001, + 0x3c040800, 0x24841a90, 0x24060003, 0x00003821, 0xafa00010, 0x0e000678, 0xafa00014, 0x8f625c50, 0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001, 0xaf625c90, 0x2402ffff, 0x0e000034, 0xaf625404, 0x8fbf0018, 0x03e00008, - 0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0xafbf0018, - 0xafb10014, 0x0e000052, 0xafb00010, 0x24110001, 0x8f706820, 0x32020100, - 0x10400003, 0x00000000, 0x0e0000b2, 0x00000000, 0x8f706820, 0x32022000, - 0x10400004, 0x32020001, 0x0e0001e3, 0x24040001, 0x32020001, 0x10400003, - 0x00000000, 0x0e00009a, 0x00000000, 0x0a00003a, 0xaf715028, 0x8fbf0018, - 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, - 0x24841ae0, 0x00002821, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, - 0x0e000684, 0xafa00014, 0x3c040800, 0x248423e8, 0xa4800000, 0x3c010800, - 0xa0201ba8, 0x3c010800, 0xac201bac, 0x3c010800, 0xac201bb0, 0x3c010800, - 0xac201bb4, 0x3c010800, 0xac201bbc, 0x3c010800, 0xac201bc8, 0x3c010800, - 0xac201bcc, 0x8f624434, 0x3c010800, 0xac221b98, 0x8f624438, 0x3c010800, - 0xac221b9c, 0x8f624410, 0xac80f7a8, 0x3c010800, 0xac201b94, 0x3c010800, - 0xac2023f0, 0x3c010800, 0xac2023d8, 0x3c010800, 0xac2023dc, 0x3c010800, - 0xac202410, 0x3c010800, 0xac221ba0, 0x8f620068, 0x24030007, 0x00021702, - 0x10430005, 0x00000000, 0x8f620068, 0x00021702, 0x14400004, 0x24020001, - 0x3c010800, 0x0a00008e, 0xac20241c, 0xac820034, 0x3c040800, 0x24841aec, - 0x3c050800, 0x8ca5241c, 0x00003021, 0x00003821, 0xafa00010, 0x0e000684, - 0xafa00014, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, - 0x24841af8, 0x00002821, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, - 0x0e000684, 0xafa00014, 0x0e000052, 0x00000000, 0x0e0000ab, 0x00002021, - 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x24020001, 0x8f636820, 0x00821004, - 0x00021027, 0x00621824, 0x03e00008, 0xaf636820, 0x27bdffd0, 0xafbf002c, - 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, - 0xafb00010, 0x8f665c5c, 0x3c030800, 0x24631bcc, 0x8c620000, 0x14460005, - 0x3c0200ff, 0x3c020800, 0x90421ba8, 0x14400115, 0x3c0200ff, 0x3442fff8, - 0x00c28824, 0xac660000, 0x00111902, 0x306300ff, 0x30c20003, 0x000211c0, - 0x00623825, 0x00e02821, 0x00061602, 0x3c030800, 0x90631ba8, 0x3044000f, - 0x1460002b, 0x00804021, 0x24020001, 0x3c010800, 0xa0221ba8, 0x00071100, - 0x00821025, 0x3c010800, 0xac201bac, 0x3c010800, 0xac201bb0, 0x3c010800, - 0xac201bb4, 0x3c010800, 0xac201bbc, 0x3c010800, 0xac201bc8, 0x3c010800, - 0xac201bc0, 0x3c010800, 0xac201bc4, 0x3c010800, 0xa42223e8, 0x9623000c, - 0x30628000, 0x10400008, 0x30627fff, 0x2442003e, 0x3c010800, 0xa4221ba6, - 0x24020001, 0x3c010800, 0x0a0000f9, 0xac222404, 0x24620036, 0x3c010800, - 0xa4221ba6, 0x3c010800, 0xac202404, 0x3c010800, 0xac202400, 0x3c010800, - 0x0a000101, 0xac202408, 0x9622000c, 0x3c010800, 0xa42223fc, 0x3c040800, - 0x24841bac, 0x8c820000, 0x00021100, 0x3c010800, 0x00220821, 0xac311bd8, - 0x8c820000, 0x00021100, 0x3c010800, 0x00220821, 0xac261bdc, 0x8c820000, - 0x24a30001, 0x306701ff, 0x00021100, 0x3c010800, 0x00220821, 0xac271be0, - 0x8c820000, 0x00021100, 0x3c010800, 0x00220821, 0xac281be4, 0x96230008, - 0x3c020800, 0x8c421bbc, 0x00432821, 0x3c010800, 0xac251bbc, 0x9622000a, - 0x30420004, 0x14400018, 0x00071100, 0x8f630c14, 0x3063000f, 0x2c620002, - 0x1440000b, 0x3c02c000, 0x8f630c14, 0x3c020800, 0x8c421b50, 0x3063000f, - 0x24420001, 0x3c010800, 0xac221b50, 0x2c620002, 0x1040fff7, 0x3c02c000, - 0x00c21825, 0xaf635c5c, 0x8f625c50, 0x30420002, 0x10400014, 0x00000000, - 0x0a000133, 0x00000000, 0x3c030800, 0x8c631b90, 0x3c040800, 0x94841ba4, - 0x01021025, 0x3c010800, 0xa42223ea, 0x24020001, 0x3c010800, 0xac221bc8, - 0x24630001, 0x0085202a, 0x3c010800, 0x10800003, 0xac231b90, 0x3c010800, - 0xa4251ba4, 0x3c060800, 0x24c61bac, 0x8cc20000, 0x24420001, 0xacc20000, - 0x28420080, 0x14400005, 0x00000000, 0x0e00065e, 0x24040002, 0x0a0001d9, - 0x00000000, 0x3c020800, 0x8c421bc8, 0x1040007f, 0x24020001, 0x3c040800, - 0x90841ba8, 0x14820077, 0x24020003, 0x3c150800, 0x96b51ba6, 0x3c050800, - 0x8ca51bbc, 0x32a3ffff, 0x00a3102a, 0x14400073, 0x00000000, 0x14a30003, - 0x00000000, 0x3c010800, 0xac242400, 0x10600061, 0x00009021, 0x24d60004, - 0x0060a021, 0x24d30014, 0x8ec20000, 0x00028100, 0x3c110800, 0x02308821, - 0x0e00062d, 0x8e311bd8, 0x00403021, 0x10c00059, 0x00000000, 0x9628000a, - 0x31020040, 0x10400004, 0x2407180c, 0x8e22000c, 0x2407188c, 0xacc20018, - 0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, - 0x3c030800, 0x00701821, 0x8c631be0, 0x3c020800, 0x00501021, 0x8c421be4, - 0x00031d00, 0x00021400, 0x00621825, 0xacc30014, 0x8ec30004, 0x96220008, - 0x00432023, 0x3242ffff, 0x3083ffff, 0x00431021, 0x0282102a, 0x14400002, - 0x02b22823, 0x00802821, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000, - 0x8e220000, 0xacc20000, 0x8e220004, 0x8e63fff4, 0x00431021, 0xacc20004, - 0xa4c5000e, 0x8e62fff4, 0x00441021, 0xae62fff4, 0x96230008, 0x0043102a, - 0x14400005, 0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0, - 0xacc00008, 0x3242ffff, 0x14540008, 0x24020305, 0x31020080, 0x54400001, - 0x34e70010, 0x24020905, 0xa4c2000c, 0x0a0001bc, 0x34e70020, 0xa4c2000c, - 0x3c020800, 0x8c422400, 0x10400003, 0x3c024b65, 0x0a0001c4, 0x34427654, - 0x3c02b49a, 0x344289ab, 0xacc2001c, 0x30e2ffff, 0xacc20010, 0x0e0005aa, - 0x00c02021, 0x3242ffff, 0x0054102b, 0x1440ffa4, 0x00000000, 0x24020002, - 0x3c010800, 0x0a0001d9, 0xa0221ba8, 0x8ec2083c, 0x24420001, 0x0a0001d9, - 0xaec2083c, 0x14820003, 0x00000000, 0x0e0004b9, 0x00000000, 0x8fbf002c, + 0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0xafbf001c, + 0xafb20018, 0xafb10014, 0x0e00005b, 0xafb00010, 0x24120002, 0x24110001, + 0x8f706820, 0x32020100, 0x10400003, 0x00000000, 0x0e0000bb, 0x00000000, + 0x8f706820, 0x32022000, 0x10400004, 0x32020001, 0x0e0001ef, 0x24040001, + 0x32020001, 0x10400003, 0x00000000, 0x0e0000a3, 0x00000000, 0x3c020800, + 0x90421b88, 0x14520003, 0x00000000, 0x0e0004bf, 0x00000000, 0x0a00003c, + 0xaf715028, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, + 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841ab0, 0x00002821, 0x00003021, + 0x00003821, 0xafbf0018, 0xafa00010, 0x0e000678, 0xafa00014, 0x3c040800, + 0x248423c8, 0xa4800000, 0x3c010800, 0xa0201b88, 0x3c010800, 0xac201b8c, + 0x3c010800, 0xac201b90, 0x3c010800, 0xac201b94, 0x3c010800, 0xac201b9c, + 0x3c010800, 0xac201ba8, 0x3c010800, 0xac201bac, 0x8f624434, 0x3c010800, + 0xac221b78, 0x8f624438, 0x3c010800, 0xac221b7c, 0x8f624410, 0xac80f7a8, + 0x3c010800, 0xac201b74, 0x3c010800, 0xac2023d0, 0x3c010800, 0xac2023b8, + 0x3c010800, 0xac2023bc, 0x3c010800, 0xac2023f0, 0x3c010800, 0xac221b80, + 0x8f620068, 0x24030007, 0x00021702, 0x10430005, 0x00000000, 0x8f620068, + 0x00021702, 0x14400004, 0x24020001, 0x3c010800, 0x0a000097, 0xac2023fc, + 0xac820034, 0x3c040800, 0x24841abc, 0x3c050800, 0x8ca523fc, 0x00003021, + 0x00003821, 0xafa00010, 0x0e000678, 0xafa00014, 0x8fbf0018, 0x03e00008, + 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841ac8, 0x00002821, 0x00003021, + 0x00003821, 0xafbf0018, 0xafa00010, 0x0e000678, 0xafa00014, 0x0e00005b, + 0x00000000, 0x0e0000b4, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020, + 0x24020001, 0x8f636820, 0x00821004, 0x00021027, 0x00621824, 0x03e00008, + 0xaf636820, 0x27bdffd0, 0xafbf002c, 0xafb60028, 0xafb50024, 0xafb40020, + 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x8f675c5c, 0x3c030800, + 0x24631bac, 0x8c620000, 0x14470005, 0x3c0200ff, 0x3c020800, 0x90421b88, + 0x14400118, 0x3c0200ff, 0x3442fff8, 0x00e28824, 0xac670000, 0x00111902, + 0x306300ff, 0x30e20003, 0x000211c0, 0x00622825, 0x00a04021, 0x00071602, + 0x3c030800, 0x90631b88, 0x3044000f, 0x14600036, 0x00804821, 0x24020001, + 0x3c010800, 0xa0221b88, 0x00051100, 0x00821025, 0x3c010800, 0xac201b8c, + 0x3c010800, 0xac201b90, 0x3c010800, 0xac201b94, 0x3c010800, 0xac201b9c, + 0x3c010800, 0xac201ba8, 0x3c010800, 0xac201ba0, 0x3c010800, 0xac201ba4, + 0x3c010800, 0xa42223c8, 0x9622000c, 0x30437fff, 0x3c010800, 0xa4222400, + 0x30428000, 0x3c010800, 0xa4231bb6, 0x10400005, 0x24020001, 0x3c010800, + 0xac2223e4, 0x0a000102, 0x2406003e, 0x24060036, 0x3c010800, 0xac2023e4, + 0x9622000a, 0x3c030800, 0x94631bb6, 0x3c010800, 0xac2023e0, 0x3c010800, + 0xac2023e8, 0x00021302, 0x00021080, 0x00c21021, 0x00621821, 0x3c010800, + 0xa42223c0, 0x3c010800, 0x0a000115, 0xa4231b86, 0x9622000c, 0x3c010800, + 0xa42223dc, 0x3c040800, 0x24841b8c, 0x8c820000, 0x00021100, 0x3c010800, + 0x00220821, 0xac311bb8, 0x8c820000, 0x00021100, 0x3c010800, 0x00220821, + 0xac271bbc, 0x8c820000, 0x25030001, 0x306601ff, 0x00021100, 0x3c010800, + 0x00220821, 0xac261bc0, 0x8c820000, 0x00021100, 0x3c010800, 0x00220821, + 0xac291bc4, 0x96230008, 0x3c020800, 0x8c421b9c, 0x00432821, 0x3c010800, + 0xac251b9c, 0x9622000a, 0x30420004, 0x14400018, 0x00061100, 0x8f630c14, + 0x3063000f, 0x2c620002, 0x1440000b, 0x3c02c000, 0x8f630c14, 0x3c020800, + 0x8c421b30, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b30, 0x2c620002, + 0x1040fff7, 0x3c02c000, 0x00e21825, 0xaf635c5c, 0x8f625c50, 0x30420002, + 0x10400014, 0x00000000, 0x0a000147, 0x00000000, 0x3c030800, 0x8c631b70, + 0x3c040800, 0x94841b84, 0x01221025, 0x3c010800, 0xa42223ca, 0x24020001, + 0x3c010800, 0xac221ba8, 0x24630001, 0x0085202a, 0x3c010800, 0x10800003, + 0xac231b70, 0x3c010800, 0xa4251b84, 0x3c060800, 0x24c61b8c, 0x8cc20000, + 0x24420001, 0xacc20000, 0x28420080, 0x14400005, 0x00000000, 0x0e000652, + 0x24040002, 0x0a0001e5, 0x00000000, 0x3c020800, 0x8c421ba8, 0x10400077, + 0x24020001, 0x3c050800, 0x90a51b88, 0x14a20071, 0x00000000, 0x3c150800, + 0x96b51b86, 0x3c040800, 0x8c841b9c, 0x32a3ffff, 0x0083102a, 0x1440006b, + 0x00000000, 0x14830003, 0x00000000, 0x3c010800, 0xac2523e0, 0x1060005b, + 0x00009021, 0x24d60004, 0x0060a021, 0x24d30014, 0x8ec20000, 0x00028100, + 0x3c110800, 0x02308821, 0x0e000621, 0x8e311bb8, 0x00402821, 0x10a00053, + 0x00000000, 0x9628000a, 0x31020040, 0x10400004, 0x2407180c, 0x8e22000c, + 0x2407188c, 0xaca20018, 0x3c030800, 0x00701821, 0x8c631bc0, 0x3c020800, + 0x00501021, 0x8c421bc4, 0x00031d00, 0x00021400, 0x00621825, 0xaca30014, + 0x8ec30004, 0x96220008, 0x00432023, 0x3242ffff, 0x3083ffff, 0x00431021, + 0x0282102a, 0x14400002, 0x02b23023, 0x00803021, 0x8e620000, 0x30c4ffff, + 0x00441021, 0xae620000, 0x8e220000, 0xaca20000, 0x8e220004, 0x8e63fff4, + 0x00431021, 0xaca20004, 0xa4a6000e, 0x8e62fff4, 0x00441021, 0xae62fff4, + 0x96230008, 0x0043102a, 0x14400005, 0x02469021, 0x8e62fff0, 0xae60fff4, + 0x24420001, 0xae62fff0, 0xaca00008, 0x3242ffff, 0x14540008, 0x24020305, + 0x31020080, 0x54400001, 0x34e70010, 0x24020905, 0xa4a2000c, 0x0a0001ca, + 0x34e70020, 0xa4a2000c, 0x3c020800, 0x8c4223e0, 0x10400003, 0x3c024b65, + 0x0a0001d2, 0x34427654, 0x3c02b49a, 0x344289ab, 0xaca2001c, 0x30e2ffff, + 0xaca20010, 0x0e00059f, 0x00a02021, 0x3242ffff, 0x0054102b, 0x1440ffaa, + 0x00000000, 0x24020002, 0x3c010800, 0x0a0001e5, 0xa0221b88, 0x8ec2083c, + 0x24420001, 0x0a0001e5, 0xaec2083c, 0x0e0004bf, 0x00000000, 0x8fbf002c, 0x8fb60028, 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0030, 0x27bdffd0, 0xafbf0028, 0xafb30024, 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f725c9c, 0x3c0200ff, 0x3442fff8, - 0x3c060800, 0x24c61bc4, 0x02428824, 0x9623000e, 0x8cc20000, 0x00431021, - 0xacc20000, 0x8e220010, 0x30420020, 0x14400011, 0x00809821, 0x0e000643, + 0x3c060800, 0x24c61ba4, 0x02428824, 0x9623000e, 0x8cc20000, 0x00431021, + 0xacc20000, 0x8e220010, 0x30420020, 0x14400011, 0x00809821, 0x0e000637, 0x02202021, 0x3c02c000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x10400121, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1040011c, - 0x00000000, 0x0a000200, 0x00000000, 0x8e240008, 0x8e230014, 0x00041402, + 0x00000000, 0x0a00020c, 0x00000000, 0x8e240008, 0x8e230014, 0x00041402, 0x000241c0, 0x00031502, 0x304201ff, 0x2442ffff, 0x3042007f, 0x00031942, 0x30637800, 0x00021100, 0x24424000, 0x00625021, 0x9542000a, 0x3084ffff, - 0x30420008, 0x104000b3, 0x000429c0, 0x3c020800, 0x8c422410, 0x1440002d, - 0x25050008, 0x95020014, 0x3c010800, 0xa42223e0, 0x8d070010, 0x00071402, - 0x3c010800, 0xa42223e2, 0x3c010800, 0xa42723e4, 0x9502000e, 0x30e3ffff, - 0x00431023, 0x3c010800, 0xac222418, 0x8f626800, 0x3c030010, 0x00431024, - 0x10400005, 0x00000000, 0x9503001a, 0x9502001c, 0x0a000235, 0x00431021, - 0x9502001a, 0x3c010800, 0xac22240c, 0x3c02c000, 0x02421825, 0x3c010800, - 0xac282410, 0x3c010800, 0xac322414, 0xaf635c9c, 0x8f625c90, 0x30420002, + 0x30420008, 0x104000b3, 0x000429c0, 0x3c020800, 0x8c4223f0, 0x1440002d, + 0x25050008, 0x95020014, 0x3c010800, 0xa42223c0, 0x8d070010, 0x00071402, + 0x3c010800, 0xa42223c2, 0x3c010800, 0xa42723c4, 0x9502000e, 0x30e3ffff, + 0x00431023, 0x3c010800, 0xac2223f8, 0x8f626800, 0x3c030010, 0x00431024, + 0x10400005, 0x00000000, 0x9503001a, 0x9502001c, 0x0a000241, 0x00431021, + 0x9502001a, 0x3c010800, 0xac2223ec, 0x3c02c000, 0x02421825, 0x3c010800, + 0xac2823f0, 0x3c010800, 0xac3223f4, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x104000df, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x104000da, - 0x00000000, 0x0a000242, 0x00000000, 0x9502000e, 0x3c030800, 0x946323e4, + 0x00000000, 0x0a00024e, 0x00000000, 0x9502000e, 0x3c030800, 0x946323c4, 0x00434823, 0x3123ffff, 0x2c620008, 0x1040001c, 0x00000000, 0x95020014, 0x24420028, 0x00a22821, 0x00031042, 0x1840000b, 0x00002021, 0x24c60848, 0x00403821, 0x94a30000, 0x8cc20000, 0x24840001, 0x00431021, 0xacc20000, 0x0087102a, 0x1440fff9, 0x24a50002, 0x31220001, 0x1040001f, 0x3c024000, - 0x3c040800, 0x2484240c, 0xa0a00001, 0x94a30000, 0x8c820000, 0x00431021, - 0x0a000281, 0xac820000, 0x8f626800, 0x3c030010, 0x00431024, 0x10400009, - 0x00000000, 0x9502001a, 0x3c030800, 0x8c63240c, 0x00431021, 0x3c010800, - 0xac22240c, 0x0a000282, 0x3c024000, 0x9502001a, 0x9504001c, 0x3c030800, - 0x8c63240c, 0x00441023, 0x00621821, 0x3c010800, 0xac23240c, 0x3c024000, + 0x3c040800, 0x248423ec, 0xa0a00001, 0x94a30000, 0x8c820000, 0x00431021, + 0x0a00028d, 0xac820000, 0x8f626800, 0x3c030010, 0x00431024, 0x10400009, + 0x00000000, 0x9502001a, 0x3c030800, 0x8c6323ec, 0x00431021, 0x3c010800, + 0xac2223ec, 0x0a00028e, 0x3c024000, 0x9502001a, 0x9504001c, 0x3c030800, + 0x8c6323ec, 0x00441023, 0x00621821, 0x3c010800, 0xac2323ec, 0x3c024000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, - 0x9542000a, 0x30420010, 0x10400095, 0x00000000, 0x3c060800, 0x24c62410, - 0x3c020800, 0x944223e4, 0x8cc50000, 0x3c040800, 0x8c842418, 0x24420030, - 0x00a22821, 0x94a20004, 0x3c030800, 0x8c63240c, 0x00441023, 0x00621821, + 0x9542000a, 0x30420010, 0x10400095, 0x00000000, 0x3c060800, 0x24c623f0, + 0x3c020800, 0x944223c4, 0x8cc50000, 0x3c040800, 0x8c8423f8, 0x24420030, + 0x00a22821, 0x94a20004, 0x3c030800, 0x8c6323ec, 0x00441023, 0x00621821, 0x00603821, 0x00032402, 0x30e2ffff, 0x00823821, 0x00071402, 0x00e23821, - 0x00071027, 0x3c010800, 0xac23240c, 0xa4a20006, 0x3c030800, 0x8c632414, + 0x00071027, 0x3c010800, 0xac2323ec, 0xa4a20006, 0x3c030800, 0x8c6323f4, 0x3c0200ff, 0x3442fff8, 0x00628824, 0x96220008, 0x24040001, 0x24034000, 0x000241c0, 0x00e01021, 0xa502001a, 0xa500001c, 0xacc00000, 0x3c010800, - 0xac241b70, 0xaf635cb8, 0x8f625cb0, 0x30420002, 0x10400003, 0x00000000, - 0x3c010800, 0xac201b70, 0x8e220008, 0xaf625cb8, 0x8f625cb0, 0x30420002, - 0x10400003, 0x00000000, 0x3c010800, 0xac201b70, 0x3c020800, 0x8c421b70, - 0x1040ffec, 0x00000000, 0x3c040800, 0x0e000643, 0x8c842414, 0x0a000320, - 0x00000000, 0x3c030800, 0x90631ba8, 0x24020002, 0x14620003, 0x3c034b65, - 0x0a0002d7, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002, 0x24100002, - 0x24100001, 0x01002021, 0x0e000346, 0x02003021, 0x24020003, 0x3c010800, - 0xa0221ba8, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c632400, - 0x10620006, 0x00000000, 0x3c020800, 0x944223e8, 0x00021400, 0x0a000315, - 0xae220014, 0x3c040800, 0x248423ea, 0x94820000, 0x00021400, 0xae220014, - 0x3c020800, 0x8c421bcc, 0x3c03c000, 0x3c010800, 0xa0201ba8, 0x00431025, + 0xac241b50, 0xaf635cb8, 0x8f625cb0, 0x30420002, 0x10400003, 0x00000000, + 0x3c010800, 0xac201b50, 0x8e220008, 0xaf625cb8, 0x8f625cb0, 0x30420002, + 0x10400003, 0x00000000, 0x3c010800, 0xac201b50, 0x3c020800, 0x8c421b50, + 0x1040ffec, 0x00000000, 0x3c040800, 0x0e000637, 0x8c8423f4, 0x0a00032c, + 0x00000000, 0x3c030800, 0x90631b88, 0x24020002, 0x14620003, 0x3c034b65, + 0x0a0002e3, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002, 0x24100002, + 0x24100001, 0x01002021, 0x0e000352, 0x02003021, 0x24020003, 0x3c010800, + 0xa0221b88, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c6323e0, + 0x10620006, 0x00000000, 0x3c020800, 0x944223c8, 0x00021400, 0x0a000321, + 0xae220014, 0x3c040800, 0x248423ca, 0x94820000, 0x00021400, 0xae220014, + 0x3c020800, 0x8c421bac, 0x3c03c000, 0x3c010800, 0xa0201b88, 0x00431025, 0xaf625c5c, 0x8f625c50, 0x30420002, 0x10400009, 0x00000000, 0x2484f7e2, 0x8c820000, 0x00431025, 0xaf625c5c, 0x8f625c50, 0x30420002, 0x1440fffa, - 0x00000000, 0x3c020800, 0x24421b94, 0x8c430000, 0x24630001, 0xac430000, + 0x00000000, 0x3c020800, 0x24421b74, 0x8c430000, 0x24630001, 0xac430000, 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000c, 0x3c024000, 0x8f630c14, - 0x3c020800, 0x8c421b50, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b50, + 0x3c020800, 0x8c421b30, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b30, 0x2c620002, 0x1040fff7, 0x00000000, 0x3c024000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, 0x12600003, 0x00000000, - 0x0e0004b9, 0x00000000, 0x8fbf0028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, - 0x8fb00018, 0x03e00008, 0x27bd0030, 0x8f634450, 0x3c040800, 0x24841b98, + 0x0e0004bf, 0x00000000, 0x8fbf0028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, + 0x8fb00018, 0x03e00008, 0x27bd0030, 0x8f634450, 0x3c040800, 0x24841b78, 0x8c820000, 0x00031c02, 0x0043102b, 0x14400007, 0x3c038000, 0x8c840004, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008, 0x3042ffff, 0x3c024000, 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc, 0x00000000, 0x03e00008, 0x00000000, 0x27bdffe0, 0x00805821, - 0x14c00017, 0x256e0008, 0x3c020800, 0x8c422404, 0x1040000a, 0x2402003e, - 0x3c010800, 0xa42223e0, 0x24020016, 0x3c010800, 0xa42223e2, 0x2402002a, - 0x3c010800, 0x0a000360, 0xa42223e4, 0x95620014, 0x3c010800, 0xa42223e0, - 0x8d670010, 0x00071402, 0x3c010800, 0xa42223e2, 0x3c010800, 0xa42723e4, - 0x3c040800, 0x948423e4, 0x3c030800, 0x946323e2, 0x95cf0006, 0x3c020800, - 0x944223e0, 0x00832023, 0x01e2c023, 0x3065ffff, 0x24a20028, 0x01c24821, + 0x14c00011, 0x256e0008, 0x3c020800, 0x8c4223e4, 0x10400007, 0x24020016, + 0x3c010800, 0xa42223c2, 0x2402002a, 0x3c010800, 0x0a000366, 0xa42223c4, + 0x8d670010, 0x00071402, 0x3c010800, 0xa42223c2, 0x3c010800, 0xa42723c4, + 0x3c040800, 0x948423c4, 0x3c030800, 0x946323c2, 0x95cf0006, 0x3c020800, + 0x944223c0, 0x00832023, 0x01e2c023, 0x3065ffff, 0x24a20028, 0x01c24821, 0x3082ffff, 0x14c0001a, 0x01226021, 0x9582000c, 0x3042003f, 0x3c010800, - 0xa42223e6, 0x95820004, 0x95830006, 0x3c010800, 0xac2023f4, 0x3c010800, - 0xac2023f8, 0x00021400, 0x00431025, 0x3c010800, 0xac221bd0, 0x95220004, - 0x3c010800, 0xa4221bd4, 0x95230002, 0x01e51023, 0x0043102a, 0x10400010, - 0x24020001, 0x3c010800, 0x0a000394, 0xac222408, 0x3c030800, 0x8c6323f8, - 0x3c020800, 0x94421bd4, 0x00431021, 0xa5220004, 0x3c020800, 0x94421bd0, - 0xa5820004, 0x3c020800, 0x8c421bd0, 0xa5820006, 0x3c020800, 0x8c422400, - 0x3c0d0800, 0x8dad23f4, 0x3c0a0800, 0x144000e5, 0x8d4a23f8, 0x3c020800, - 0x94421bd4, 0x004a1821, 0x3063ffff, 0x0062182b, 0x24020002, 0x10c2000d, - 0x01435023, 0x3c020800, 0x944223e6, 0x30420009, 0x10400008, 0x00000000, - 0x9582000c, 0x3042fff6, 0xa582000c, 0x3c020800, 0x944223e6, 0x30420009, - 0x01a26823, 0x3c020800, 0x8c422408, 0x1040004a, 0x01203821, 0x3c020800, - 0x944223e2, 0x00004021, 0xa520000a, 0x01e21023, 0xa5220002, 0x3082ffff, + 0xa42223c6, 0x95820004, 0x95830006, 0x3c010800, 0xac2023d4, 0x3c010800, + 0xac2023d8, 0x00021400, 0x00431025, 0x3c010800, 0xac221bb0, 0x95220004, + 0x3c010800, 0xa4221bb4, 0x95230002, 0x01e51023, 0x0043102a, 0x10400010, + 0x24020001, 0x3c010800, 0x0a00039a, 0xac2223e8, 0x3c030800, 0x8c6323d8, + 0x3c020800, 0x94421bb4, 0x00431021, 0xa5220004, 0x3c020800, 0x94421bb0, + 0xa5820004, 0x3c020800, 0x8c421bb0, 0xa5820006, 0x3c020800, 0x8c4223e0, + 0x3c0d0800, 0x8dad23d4, 0x3c0a0800, 0x144000e5, 0x8d4a23d8, 0x3c020800, + 0x94421bb4, 0x004a1821, 0x3063ffff, 0x0062182b, 0x24020002, 0x10c2000d, + 0x01435023, 0x3c020800, 0x944223c6, 0x30420009, 0x10400008, 0x00000000, + 0x9582000c, 0x3042fff6, 0xa582000c, 0x3c020800, 0x944223c6, 0x30420009, + 0x01a26823, 0x3c020800, 0x8c4223e8, 0x1040004a, 0x01203821, 0x3c020800, + 0x944223c2, 0x00004021, 0xa520000a, 0x01e21023, 0xa5220002, 0x3082ffff, 0x00021042, 0x18400008, 0x00003021, 0x00401821, 0x94e20000, 0x25080001, 0x00c23021, 0x0103102a, 0x1440fffb, 0x24e70002, 0x00061c02, 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c02821, 0x00061027, 0xa522000a, @@ -4044,131 +4068,127 @@ static u32 tg3TsoFwText[] = { 0x30e2007f, 0x14400006, 0x25080001, 0x8d630000, 0x3c02007f, 0x3442ff80, 0x00625824, 0x25670008, 0x0109102a, 0x1440fff3, 0x00000000, 0x30820001, 0x10400005, 0x00061c02, 0xa0e00001, 0x94e20000, 0x00c23021, 0x00061c02, - 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x0a000479, 0x30c6ffff, - 0x24020002, 0x14c20081, 0x00000000, 0x3c020800, 0x8c42241c, 0x14400007, - 0x00000000, 0x3c020800, 0x944223e2, 0x95230002, 0x01e21023, 0x10620077, - 0x00000000, 0x3c020800, 0x944223e2, 0x01e21023, 0xa5220002, 0x3c020800, - 0x8c42241c, 0x1040001a, 0x31e3ffff, 0x8dc70010, 0x3c020800, 0x94421ba6, + 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x0a00047f, 0x30c6ffff, + 0x24020002, 0x14c20081, 0x00000000, 0x3c020800, 0x8c4223fc, 0x14400007, + 0x00000000, 0x3c020800, 0x944223c2, 0x95230002, 0x01e21023, 0x10620077, + 0x00000000, 0x3c020800, 0x944223c2, 0x01e21023, 0xa5220002, 0x3c020800, + 0x8c4223fc, 0x1040001a, 0x31e3ffff, 0x8dc70010, 0x3c020800, 0x94421b86, 0x00e04021, 0x00072c02, 0x00aa2021, 0x00431023, 0x00823823, 0x00072402, 0x30e2ffff, 0x00823821, 0x00071027, 0xa522000a, 0x3102ffff, 0x3c040800, - 0x948423e4, 0x00453023, 0x00e02821, 0x00641823, 0x006d1821, 0x00c33021, - 0x00061c02, 0x30c2ffff, 0x0a000479, 0x00623021, 0x01203821, 0x00004021, + 0x948423c4, 0x00453023, 0x00e02821, 0x00641823, 0x006d1821, 0x00c33021, + 0x00061c02, 0x30c2ffff, 0x0a00047f, 0x00623021, 0x01203821, 0x00004021, 0x3082ffff, 0x00021042, 0x18400008, 0x00003021, 0x00401821, 0x94e20000, 0x25080001, 0x00c23021, 0x0103102a, 0x1440fffb, 0x24e70002, 0x00061c02, 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c02821, 0x00061027, 0xa522000a, 0x00003021, 0x2527000c, 0x00004021, 0x94e20000, 0x25080001, 0x00c23021, 0x2d020004, 0x1440fffb, 0x24e70002, 0x95220002, 0x00004021, 0x91230009, 0x00442023, 0x01803821, 0x3082ffff, 0xa4e00010, 0x3c040800, - 0x948423e4, 0x00621821, 0x00c33021, 0x00061c02, 0x30c2ffff, 0x00623021, - 0x00061c02, 0x3c020800, 0x944223e0, 0x00c34821, 0x00441023, 0x00021fc2, + 0x948423c4, 0x00621821, 0x00c33021, 0x00061c02, 0x30c2ffff, 0x00623021, + 0x00061c02, 0x3c020800, 0x944223c0, 0x00c34821, 0x00441023, 0x00021fc2, 0x00431021, 0x00021043, 0x18400010, 0x00003021, 0x00402021, 0x94e20000, 0x24e70002, 0x00c23021, 0x30e2007f, 0x14400006, 0x25080001, 0x8d630000, 0x3c02007f, 0x3442ff80, 0x00625824, 0x25670008, 0x0104102a, 0x1440fff3, - 0x00000000, 0x3c020800, 0x944223fc, 0x00c23021, 0x3122ffff, 0x00c23021, + 0x00000000, 0x3c020800, 0x944223dc, 0x00c23021, 0x3122ffff, 0x00c23021, 0x00061c02, 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c04021, - 0x00061027, 0xa5820010, 0xadc00014, 0x0a000499, 0xadc00000, 0x8dc70010, + 0x00061027, 0xa5820010, 0xadc00014, 0x0a00049f, 0xadc00000, 0x8dc70010, 0x00e04021, 0x11400007, 0x00072c02, 0x00aa3021, 0x00061402, 0x30c3ffff, 0x00433021, 0x00061402, 0x00c22821, 0x00051027, 0xa522000a, 0x3c030800, - 0x946323e4, 0x3102ffff, 0x01e21021, 0x00433023, 0x00cd3021, 0x00061c02, + 0x946323c4, 0x3102ffff, 0x01e21021, 0x00433023, 0x00cd3021, 0x00061c02, 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c04021, 0x00061027, 0xa5820010, 0x3102ffff, 0x00051c00, 0x00431025, 0xadc20010, 0x3c020800, - 0x8c422404, 0x10400002, 0x25e2fff2, 0xa5c20034, 0x3c020800, 0x8c4223f8, - 0x3c040800, 0x8c8423f4, 0x24420001, 0x3c010800, 0xac2223f8, 0x3c020800, - 0x8c421bd0, 0x3303ffff, 0x00832021, 0x3c010800, 0xac2423f4, 0x00431821, - 0x0062102b, 0x10400003, 0x2482ffff, 0x3c010800, 0xac2223f4, 0x3c010800, - 0xac231bd0, 0x03e00008, 0x27bd0020, 0x27bdffb8, 0x3c050800, 0x24a51ba8, + 0x8c4223e4, 0x10400002, 0x25e2fff2, 0xa5c20034, 0x3c020800, 0x8c4223d8, + 0x3c040800, 0x8c8423d4, 0x24420001, 0x3c010800, 0xac2223d8, 0x3c020800, + 0x8c421bb0, 0x3303ffff, 0x00832021, 0x3c010800, 0xac2423d4, 0x00431821, + 0x0062102b, 0x10400003, 0x2482ffff, 0x3c010800, 0xac2223d4, 0x3c010800, + 0xac231bb0, 0x03e00008, 0x27bd0020, 0x27bdffb8, 0x3c050800, 0x24a51b86, 0xafbf0044, 0xafbe0040, 0xafb7003c, 0xafb60038, 0xafb50034, 0xafb40030, - 0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 0x90a30000, 0x24020003, - 0x146200d5, 0x00000000, 0x3c090800, 0x95291ba6, 0x3c020800, 0x944223e0, - 0x3c030800, 0x8c631bc0, 0x3c040800, 0x8c841bbc, 0x01221023, 0x0064182a, - 0xa7a9001e, 0x106000c8, 0xa7a20016, 0x24be0020, 0x97b6001e, 0x24b30018, - 0x24b70014, 0x8fc20000, 0x14400008, 0x00000000, 0x8fc2fff8, 0x97a30016, - 0x8fc4fff4, 0x00431021, 0x0082202a, 0x148000ba, 0x00000000, 0x97d50818, - 0x32a2ffff, 0x104000ad, 0x00009021, 0x0040a021, 0x00008821, 0x0e00062d, - 0x00000000, 0x00403021, 0x14c00007, 0x00000000, 0x3c020800, 0x8c4223ec, - 0x24420001, 0x3c010800, 0x0a00059e, 0xac2223ec, 0x3c100800, 0x02118021, - 0x8e101bd8, 0x9608000a, 0x31020040, 0x10400004, 0x2407180c, 0x8e02000c, - 0x2407188c, 0xacc20018, 0x31021000, 0x10400004, 0x34e32000, 0x00081040, - 0x3042c000, 0x00623825, 0x31020080, 0x54400001, 0x34e70010, 0x3c020800, - 0x00511021, 0x8c421be0, 0x3c030800, 0x00711821, 0x8c631be4, 0x00021500, - 0x00031c00, 0x00431025, 0xacc20014, 0x96040008, 0x3242ffff, 0x00821021, - 0x0282102a, 0x14400002, 0x02b22823, 0x00802821, 0x8e020000, 0x02459021, - 0xacc20000, 0x8e020004, 0x00c02021, 0x26310010, 0xac820004, 0x30e2ffff, - 0xac800008, 0xa485000e, 0xac820010, 0x24020305, 0x0e0005aa, 0xa482000c, - 0x3242ffff, 0x0054102b, 0x1440ffc0, 0x3242ffff, 0x0a000596, 0x00000000, - 0x8e620000, 0x8e63fffc, 0x0043102a, 0x1040006c, 0x00000000, 0x8e62fff0, - 0x00028900, 0x3c100800, 0x02118021, 0x0e00062d, 0x8e101bd8, 0x00403021, - 0x14c00005, 0x00000000, 0x8e62082c, 0x24420001, 0x0a00059e, 0xae62082c, - 0x9608000a, 0x31020040, 0x10400004, 0x2407180c, 0x8e02000c, 0x2407188c, - 0xacc20018, 0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, - 0x00623825, 0x3c020800, 0x00511021, 0x8c421be0, 0x3c030800, 0x00711821, - 0x8c631be4, 0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x8e63fff4, - 0x96020008, 0x00432023, 0x3242ffff, 0x3083ffff, 0x00431021, 0x02c2102a, - 0x10400003, 0x00802821, 0x97a9001e, 0x01322823, 0x8e620000, 0x30a4ffff, - 0x00441021, 0xae620000, 0xa4c5000e, 0x8e020000, 0xacc20000, 0x8e020004, - 0x8e63fff4, 0x00431021, 0xacc20004, 0x8e63fff4, 0x96020008, 0x00641821, - 0x0062102a, 0x14400006, 0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, - 0x0a000579, 0xae62fff0, 0xae63fff4, 0xacc00008, 0x3242ffff, 0x10560003, - 0x31020004, 0x10400006, 0x24020305, 0x31020080, 0x54400001, 0x34e70010, - 0x34e70020, 0x24020905, 0xa4c2000c, 0x8ee30000, 0x8ee20004, 0x14620007, - 0x3c02b49a, 0x8ee20860, 0x54400001, 0x34e70400, 0x3c024b65, 0x0a000590, - 0x34427654, 0x344289ab, 0xacc2001c, 0x30e2ffff, 0xacc20010, 0x0e0005aa, - 0x00c02021, 0x3242ffff, 0x0056102b, 0x1440ff96, 0x00000000, 0x8e620000, - 0x8e63fffc, 0x0043102a, 0x1440ff3e, 0x00000000, 0x8fbf0044, 0x8fbe0040, - 0x8fb7003c, 0x8fb60038, 0x8fb50034, 0x8fb40030, 0x8fb3002c, 0x8fb20028, - 0x8fb10024, 0x8fb00020, 0x03e00008, 0x27bd0048, 0x27bdffe8, 0xafbf0014, - 0xafb00010, 0x8f624450, 0x8f634410, 0x0a0005b9, 0x00808021, 0x8f626820, - 0x30422000, 0x10400003, 0x00000000, 0x0e0001e3, 0x00002021, 0x8f624450, - 0x8f634410, 0x3042ffff, 0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14, - 0x3063000f, 0x2c620002, 0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800, - 0x8c421b50, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b50, 0x2c620002, - 0x1040fff7, 0x00000000, 0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009, - 0x00000000, 0x8f626820, 0x30422000, 0x1040fff8, 0x00000000, 0x0e0001e3, - 0x00002021, 0x0a0005cc, 0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, - 0x27bd0018, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe8, 0x3c1bc000, + 0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 0x94a90000, 0x3c020800, + 0x944223c0, 0x3c030800, 0x8c631ba0, 0x3c040800, 0x8c841b9c, 0x01221023, + 0x0064182a, 0xa7a9001e, 0x106000bc, 0xa7a20016, 0x24be0022, 0x97b6001e, + 0x24b3001a, 0x24b70016, 0x8fc20000, 0x14400008, 0x00000000, 0x8fc2fff8, + 0x97a30016, 0x8fc4fff4, 0x00431021, 0x0082202a, 0x148000ae, 0x00000000, + 0x97d50818, 0x32a2ffff, 0x104000a1, 0x00009021, 0x0040a021, 0x00008821, + 0x0e000621, 0x00000000, 0x00403021, 0x14c00007, 0x00000000, 0x3c020800, + 0x8c4223cc, 0x24420001, 0x3c010800, 0x0a000593, 0xac2223cc, 0x3c100800, + 0x02118021, 0x8e101bb8, 0x9608000a, 0x31020040, 0x10400004, 0x2407180c, + 0x8e02000c, 0x2407188c, 0xacc20018, 0x31020080, 0x54400001, 0x34e70010, + 0x3c020800, 0x00511021, 0x8c421bc0, 0x3c030800, 0x00711821, 0x8c631bc4, + 0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x96040008, 0x3242ffff, + 0x00821021, 0x0282102a, 0x14400002, 0x02b22823, 0x00802821, 0x8e020000, + 0x02459021, 0xacc20000, 0x8e020004, 0x00c02021, 0x26310010, 0xac820004, + 0x30e2ffff, 0xac800008, 0xa485000e, 0xac820010, 0x24020305, 0x0e00059f, + 0xa482000c, 0x3242ffff, 0x0054102b, 0x1440ffc6, 0x3242ffff, 0x0a00058b, + 0x00000000, 0x8e620000, 0x8e63fffc, 0x0043102a, 0x10400066, 0x00000000, + 0x8e62fff0, 0x00028900, 0x3c100800, 0x02118021, 0x0e000621, 0x8e101bb8, + 0x00403021, 0x14c00005, 0x00000000, 0x8e62082c, 0x24420001, 0x0a000593, + 0xae62082c, 0x9608000a, 0x31020040, 0x10400004, 0x2407180c, 0x8e02000c, + 0x2407188c, 0xacc20018, 0x3c020800, 0x00511021, 0x8c421bc0, 0x3c030800, + 0x00711821, 0x8c631bc4, 0x00021500, 0x00031c00, 0x00431025, 0xacc20014, + 0x8e63fff4, 0x96020008, 0x00432023, 0x3242ffff, 0x3083ffff, 0x00431021, + 0x02c2102a, 0x10400003, 0x00802821, 0x97a9001e, 0x01322823, 0x8e620000, + 0x30a4ffff, 0x00441021, 0xae620000, 0xa4c5000e, 0x8e020000, 0xacc20000, + 0x8e020004, 0x8e63fff4, 0x00431021, 0xacc20004, 0x8e63fff4, 0x96020008, + 0x00641821, 0x0062102a, 0x14400006, 0x02459021, 0x8e62fff0, 0xae60fff4, + 0x24420001, 0x0a00056e, 0xae62fff0, 0xae63fff4, 0xacc00008, 0x3242ffff, + 0x10560003, 0x31020004, 0x10400006, 0x24020305, 0x31020080, 0x54400001, + 0x34e70010, 0x34e70020, 0x24020905, 0xa4c2000c, 0x8ee30000, 0x8ee20004, + 0x14620007, 0x3c02b49a, 0x8ee20860, 0x54400001, 0x34e70400, 0x3c024b65, + 0x0a000585, 0x34427654, 0x344289ab, 0xacc2001c, 0x30e2ffff, 0xacc20010, + 0x0e00059f, 0x00c02021, 0x3242ffff, 0x0056102b, 0x1440ff9c, 0x00000000, + 0x8e620000, 0x8e63fffc, 0x0043102a, 0x1440ff4a, 0x00000000, 0x8fbf0044, + 0x8fbe0040, 0x8fb7003c, 0x8fb60038, 0x8fb50034, 0x8fb40030, 0x8fb3002c, + 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x03e00008, 0x27bd0048, 0x27bdffe8, + 0xafbf0014, 0xafb00010, 0x8f624450, 0x8f634410, 0x0a0005ae, 0x00808021, + 0x8f626820, 0x30422000, 0x10400003, 0x00000000, 0x0e0001ef, 0x00002021, + 0x8f624450, 0x8f634410, 0x3042ffff, 0x0043102b, 0x1440fff5, 0x00000000, + 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000b, 0x00000000, 0x8f630c14, + 0x3c020800, 0x8c421b30, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b30, + 0x2c620002, 0x1040fff7, 0x00000000, 0xaf705c18, 0x8f625c10, 0x30420002, + 0x10400009, 0x00000000, 0x8f626820, 0x30422000, 0x1040fff8, 0x00000000, + 0x0e0001ef, 0x00002021, 0x0a0005c1, 0x00000000, 0x8fbf0014, 0x8fb00010, + 0x03e00008, 0x27bd0018, 0x00000000, 0x00000000, 0x27bdffe8, 0x3c1bc000, 0xafbf0014, 0xafb00010, 0xaf60680c, 0x8f626804, 0x34420082, 0xaf626804, - 0x8f634000, 0x24020b50, 0x3c010800, 0xac221b64, 0x24020b78, 0x3c010800, - 0xac221b74, 0x34630002, 0xaf634000, 0x0e00060d, 0x00808021, 0x3c010800, - 0xa0221b78, 0x304200ff, 0x24030002, 0x14430005, 0x00000000, 0x3c020800, - 0x8c421b64, 0x0a000600, 0xac5000c0, 0x3c020800, 0x8c421b64, 0xac5000bc, - 0x8f624434, 0x8f634438, 0x8f644410, 0x3c010800, 0xac221b6c, 0x3c010800, - 0xac231b7c, 0x3c010800, 0xac241b68, 0x8fbf0014, 0x8fb00010, 0x03e00008, + 0x8f634000, 0x24020b50, 0x3c010800, 0xac221b44, 0x24020b78, 0x3c010800, + 0xac221b54, 0x34630002, 0xaf634000, 0x0e000601, 0x00808021, 0x3c010800, + 0xa0221b58, 0x304200ff, 0x24030002, 0x14430005, 0x00000000, 0x3c020800, + 0x8c421b44, 0x0a0005f4, 0xac5000c0, 0x3c020800, 0x8c421b44, 0xac5000bc, + 0x8f624434, 0x8f634438, 0x8f644410, 0x3c010800, 0xac221b4c, 0x3c010800, + 0xac231b5c, 0x3c010800, 0xac241b48, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c040800, 0x8c870000, 0x3c03aa55, 0x3463aa55, 0x3c06c003, 0xac830000, 0x8cc20000, 0x14430007, 0x24050002, 0x3c0355aa, 0x346355aa, 0xac830000, 0x8cc20000, 0x50430001, 0x24050001, 0x3c020800, 0xac470000, 0x03e00008, 0x00a01021, 0x27bdfff8, 0x18800009, 0x00002821, 0x8f63680c, 0x8f62680c, 0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a, 0x1440fff9, - 0x00000000, 0x03e00008, 0x27bd0008, 0x8f634450, 0x3c020800, 0x8c421b6c, - 0x00031c02, 0x0043102b, 0x14400008, 0x3c038000, 0x3c040800, 0x8c841b7c, + 0x00000000, 0x03e00008, 0x27bd0008, 0x8f634450, 0x3c020800, 0x8c421b4c, + 0x00031c02, 0x0043102b, 0x14400008, 0x3c038000, 0x3c040800, 0x8c841b5c, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008, 0x3042ffff, 0x3082ffff, 0x2442e000, 0x2c422001, 0x14400003, 0x3c024000, - 0x0a000650, 0x2402ffff, 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002, + 0x0a000644, 0x2402ffff, 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc, 0x00001021, 0x03e00008, 0x00000000, 0x8f624450, 0x3c030800, - 0x8c631b68, 0x0a000659, 0x3042ffff, 0x8f624450, 0x3042ffff, 0x0043102b, + 0x8c631b48, 0x0a00064d, 0x3042ffff, 0x8f624450, 0x3042ffff, 0x0043102b, 0x1440fffc, 0x00000000, 0x03e00008, 0x00000000, 0x27bdffe0, 0x00802821, - 0x3c040800, 0x24841b10, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, - 0x0e000684, 0xafa00014, 0x0a000668, 0x00000000, 0x8fbf0018, 0x03e00008, + 0x3c040800, 0x24841ae0, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, + 0x0e000678, 0xafa00014, 0x0a00065c, 0x00000000, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x3c020800, 0x34423000, - 0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac221b84, - 0x24020040, 0x3c010800, 0xac221b88, 0x3c010800, 0xac201b80, 0xac600000, + 0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac221b64, + 0x24020040, 0x3c010800, 0xac221b68, 0x3c010800, 0xac201b60, 0xac600000, 0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000, - 0x00804821, 0x8faa0010, 0x3c020800, 0x8c421b80, 0x3c040800, 0x8c841b88, - 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac231b80, 0x14400003, - 0x00004021, 0x3c010800, 0xac201b80, 0x3c020800, 0x8c421b80, 0x3c030800, - 0x8c631b84, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001, - 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c421b80, - 0x3c030800, 0x8c631b84, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008, + 0x00804821, 0x8faa0010, 0x3c020800, 0x8c421b60, 0x3c040800, 0x8c841b68, + 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac231b60, 0x14400003, + 0x00004021, 0x3c010800, 0xac201b60, 0x3c020800, 0x8c421b60, 0x3c030800, + 0x8c631b64, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001, + 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c421b60, + 0x3c030800, 0x8c631b64, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008, 0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000, }; u32 tg3TsoFwRodata[] = { - 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, - 0x00000000, 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, - 0x496e0000, 0x73746b6f, 0x66662a2a, 0x00000000, 0x53774576, - 0x656e7430, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x66617461, 0x6c457272, 0x00000000, 0x00000000, 0x00000000 + 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000, + 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f, + 0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x66617461, 0x6c457272, 0x00000000, 0x00000000, }; #if 0 /* All zeros, don't eat up space with it. */ @@ -4541,7 +4561,10 @@ static int tg3_reset_hw(struct tg3 *tp) tg3_chip_reset(tp); - tw32(GRC_MODE, tp->grc_mode); + val = tr32(GRC_MODE); + val &= GRC_MODE_HOST_STACKUP; + tw32(GRC_MODE, val | tp->grc_mode); + tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, NIC_SRAM_FIRMWARE_MBOX_MAGIC1); @@ -4597,17 +4620,6 @@ static int tg3_reset_hw(struct tg3 *tp) */ tg3_init_rings(tp); - /* Clear statistics/status block in chip, and status block in ram. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { - for (i = NIC_SRAM_STATS_BLK; - i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; - i += sizeof(u32)) { - tg3_write_mem(tp, i, 0); - udelay(40); - } - } - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); - /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -4706,6 +4718,17 @@ static int tg3_reset_hw(struct tg3 *tp) return -ENODEV; } + /* Clear statistics/status block in chip, and status block in ram. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { + for (i = NIC_SRAM_STATS_BLK; + i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; + i += sizeof(u32)) { + tg3_write_mem(tp, i, 0); + udelay(40); + } + } + memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + /* Setup replenish threshold. */ tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8); @@ -5760,14 +5783,20 @@ static void __tg3_set_rx_mode(struct net rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC | RX_MODE_KEEP_VLAN_TAG); + + /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG + * flag clear. + */ #if TG3_VLAN_TAG_USED - if (!tp->vlgrp) + if (!tp->vlgrp && + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) rx_mode |= RX_MODE_KEEP_VLAN_TAG; #else /* By definition, VLAN is disabled always in this * case. */ - rx_mode |= RX_MODE_KEEP_VLAN_TAG; + if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + rx_mode |= RX_MODE_KEEP_VLAN_TAG; #endif if (dev->flags & IFF_PROMISC) { @@ -6402,25 +6431,22 @@ struct subsys_tbl_ent { static struct subsys_tbl_ent subsys_id_to_phy_id[] = { /* Broadcom boards. */ - { 0x14e4, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */ - { 0x14e4, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */ - { 0x14e4, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */ - { 0x14e4, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */ - { 0x14e4, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */ - { 0x14e4, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */ - { 0x14e4, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */ - { 0x14e4, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */ - { 0x14e4, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */ - { 0x14e4, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */ - { 0x14e4, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */ + { PCI_VENDOR_ID_BROADCOM, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */ + { PCI_VENDOR_ID_BROADCOM, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */ + { PCI_VENDOR_ID_BROADCOM, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */ + { PCI_VENDOR_ID_BROADCOM, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */ + { PCI_VENDOR_ID_BROADCOM, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */ + { PCI_VENDOR_ID_BROADCOM, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */ + { PCI_VENDOR_ID_BROADCOM, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */ + { PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */ + { PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */ + { PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */ + { PCI_VENDOR_ID_BROADCOM, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */ /* 3com boards. */ { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */ { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */ - /* { PCI_VENDOR_ID_3COM, 0x1002, PHY_ID_XXX }, 3C996CT */ - /* { PCI_VENDOR_ID_3COM, 0x1003, PHY_ID_XXX }, 3C997T */ { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES }, /* 3C996SX */ - /* { PCI_VENDOR_ID_3COM, 0x1005, PHY_ID_XXX }, 3C997SZ */ { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */ { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */ @@ -6435,7 +6461,10 @@ static struct subsys_tbl_ent subsys_id_t { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */ { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES }, /* CHANGELING */ { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */ - { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 } /* NC7780_2 */ + { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */ + + /* IBM boards. */ + { PCI_VENDOR_ID_IBM, 0x0281, PHY_ID_SERDES } /* IBM??? */ }; static int __devinit tg3_phy_probe(struct tg3 *tp) @@ -6716,6 +6745,7 @@ static int __devinit tg3_get_invariants( u32 misc_ctrl_reg; u32 cacheline_sz_reg; u32 pci_state_reg, grc_misc_cfg; + u32 val; u16 pci_cmd; int err; @@ -6912,7 +6942,9 @@ static int __devinit tg3_get_invariants( udelay(40); /* Initialize data/descriptor byte/word swapping. */ - tw32(GRC_MODE, tp->grc_mode); + val = tr32(GRC_MODE); + val &= GRC_MODE_HOST_STACKUP; + tw32(GRC_MODE, val | tp->grc_mode); tg3_switch_clocks(tp); @@ -6975,7 +7007,8 @@ static int __devinit tg3_get_invariants( (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM && (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901 || - tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2))) + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 || + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F))) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); @@ -7636,6 +7669,9 @@ static int __devinit tg3_init_one(struct dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = tg3_poll_controller; +#endif err = tg3_get_invariants(tp); if (err) { --- linux-2.6.1-rc1/drivers/net/tlan.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/tlan.c 2003-12-30 22:49:20.000000000 -0800 @@ -814,6 +814,14 @@ static void __init TLan_EisaProbe (void } /* TLan_EisaProbe */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void TLan_Poll(struct net_device *dev) +{ + disable_irq(dev->irq); + TLan_HandleInterrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif @@ -893,6 +901,9 @@ static int TLan_Init( struct net_device dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &TLan_Poll; +#endif dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; --- linux-2.6.1-rc1/drivers/net/tokenring/3c359.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/tokenring/3c359.c 2003-12-30 22:49:20.000000000 -0800 @@ -314,7 +314,6 @@ int __devinit xl_probe(struct pci_dev *p dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev,0) ; - dev->init=NULL ; /* Must be null with new api, otherwise get called twice */ xl_priv->xl_card_name = pci_name(pdev); xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); xl_priv->pdev = pdev ; @@ -332,7 +331,7 @@ int __devinit xl_probe(struct pci_dev *p if((i = xl_init(dev))) { iounmap(xl_priv->xl_mmio) ; - kfree(dev) ; + free_netdev(dev) ; pci_release_regions(pdev) ; return i ; } @@ -352,7 +351,7 @@ int __devinit xl_probe(struct pci_dev *p printk(KERN_ERR "3C359, register netdev failed\n") ; pci_set_drvdata(pdev,NULL) ; iounmap(xl_priv->xl_mmio) ; - kfree(dev) ; + free_netdev(dev) ; pci_release_regions(pdev) ; return i ; } --- linux-2.6.1-rc1/drivers/net/tokenring/abyss.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tokenring/abyss.c 2003-12-30 22:49:20.000000000 -0800 @@ -181,7 +181,7 @@ err_out_irq: err_out_region: release_region(pci_ioaddr, ABYSS_IO_EXTENT); err_out_trdev: - kfree(dev); + free_netdev(dev); return ret; } --- linux-2.6.1-rc1/drivers/net/tokenring/ibmtr.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/tokenring/ibmtr.c 2003-12-30 22:49:20.000000000 -0800 @@ -187,7 +187,7 @@ char __devinit *adapter_def(char type) #define TRC_INITV 0x02 /* verbose init trace points */ unsigned char ibmtr_debug_trace = 0; -int ibmtr_probe(struct net_device *dev); +static int ibmtr_probe(struct net_device *dev); static int ibmtr_probe1(struct net_device *dev, int ioaddr); static unsigned char get_sram_size(struct tok_info *adapt_info); static int trdev_init(struct net_device *dev); @@ -313,6 +313,39 @@ static void __devinit find_turbo_adapter } } +static void ibmtr_cleanup_card(struct net_device *dev) +{ + if (dev->base_addr) { + outb(0,dev->base_addr+ADAPTRESET); + + schedule_timeout(TR_RST_TIME); /* wait 50ms */ + + outb(0,dev->base_addr+ADAPTRESETREL); + } + +#ifndef PCMCIA + free_irq(dev->irq, dev); + release_region(dev->base_addr, IBMTR_IO_EXTENT); + + { + struct tok_info *ti = (struct tok_info *) dev->priv; + iounmap((u32 *)ti->mmio); + iounmap((u32 *)ti->sram_virt); + } +#endif +} + +int ibmtr_probe_card(struct net_device *dev) +{ + int err = ibmtr_probe(dev); + if (!err) { + err = register_netdev(dev); + if (err) + ibmtr_cleanup_card(dev); + } + return err; +} + /**************************************************************************** * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: @@ -325,7 +358,7 @@ static void __devinit find_turbo_adapter * which references it. ****************************************************************************/ -int __devinit ibmtr_probe(struct net_device *dev) +static int ibmtr_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; @@ -1925,23 +1958,24 @@ static int __init ibmtr_init(void) find_turbo_adapters(io); for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) { + struct net_device *dev; irq[i] = 0; mem[i] = 0; - dev_ibmtr[i] = alloc_trdev(sizeof(struct tok_info)); - if (dev_ibmtr[i] == NULL) { + dev = alloc_trdev(sizeof(struct tok_info)); + if (dev == NULL) { if (i == 0) return -ENOMEM; break; } - dev_ibmtr[i]->base_addr = io[i]; - dev_ibmtr[i]->irq = irq[i]; - dev_ibmtr[i]->mem_start = mem[i]; - dev_ibmtr[i]->init = &ibmtr_probe; - if (register_netdev(dev_ibmtr[i]) != 0) { - kfree(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; + dev->base_addr = io[i]; + dev->irq = irq[i]; + dev->mem_start = mem[i]; + + if (ibmtr_probe_card(dev)) { + free_netdev(dev); continue; } + dev_ibmtr[i] = dev; count++; } if (count) return 0; @@ -1957,27 +1991,9 @@ static void __exit ibmtr_cleanup(void) for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ if (!dev_ibmtr[i]) continue; - if (dev_ibmtr[i]->base_addr) { - outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET); - - schedule_timeout(TR_RST_TIME); /* wait 50ms */ - - outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL); - } - unregister_netdev(dev_ibmtr[i]); - free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); - release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); -#ifndef PCMCIA - { - struct tok_info *ti = (struct tok_info *) - dev_ibmtr[i]->priv; - iounmap((u32 *)ti->mmio); - iounmap((u32 *)ti->sram_virt); - } -#endif + ibmtr_cleanup_card(dev_ibmtr[i]); free_netdev(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; } } module_exit(ibmtr_cleanup); --- linux-2.6.1-rc1/drivers/net/tokenring/madgemc.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/tokenring/madgemc.c 2003-12-30 22:49:20.000000000 -0800 @@ -197,7 +197,7 @@ static int __init madgemc_probe(void) card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); if (card==NULL) { printk("madgemc: unable to allocate card struct\n"); - kfree(dev); + free_netdev(dev); if (madgemc_card_list) return 0; return -1; @@ -360,7 +360,7 @@ static int __init madgemc_probe(void) kfree(card); tmsdev_term(dev); - kfree(dev); + free_netdev(dev); if (madgemc_card_list) return 0; return -1; @@ -399,7 +399,7 @@ static int __init madgemc_probe(void) MADGEMC_IO_EXTENT); getout1: kfree(card); - kfree(dev); + free_netdev(dev); slot++; } --- linux-2.6.1-rc1/drivers/net/tokenring/olympic.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tokenring/olympic.c 2003-12-30 22:49:20.000000000 -0800 @@ -228,7 +228,6 @@ static int __devinit olympic_probe(struc #endif dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev, 0); - dev->init=NULL; /* Must be NULL otherwise we get called twice */ olympic_priv->olympic_card_name = pci_name(pdev); olympic_priv->pdev = pdev; olympic_priv->olympic_mmio = ioremap(pci_resource_start(pdev,1),256); --- linux-2.6.1-rc1/drivers/net/tokenring/proteon.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tokenring/proteon.c 2003-12-30 22:49:20.000000000 -0800 @@ -63,7 +63,7 @@ static int dmalist[] __initdata = { static char cardname[] = "Proteon 1392\0"; -int proteon_probe(struct net_device *dev); +struct net_device *proteon_probe(int unit); static int proteon_open(struct net_device *dev); static int proteon_close(struct net_device *dev); static void proteon_read_eeprom(struct net_device *dev); @@ -89,80 +89,69 @@ static void proteon_sifwritew(struct net outw(val, dev->base_addr + reg); } -struct proteon_card { - struct net_device *dev; - struct proteon_card *next; -}; - -static struct proteon_card *proteon_card_list; - -static int __init proteon_probe1(int ioaddr) +static int __init proteon_probe1(struct net_device *dev, int ioaddr) { unsigned char chk1, chk2; int i; + if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname)) + return -ENODEV; + + chk1 = inb(ioaddr + 0x1f); /* Get Proteon ID reg 1 */ - if (chk1 != 0x1f) - return (-1); + if (chk1 != 0x1f) + goto nodev; + chk1 = inb(ioaddr + 0x1e) & 0x07; /* Get Proteon ID reg 0 */ for (i=0; i<16; i++) { chk2 = inb(ioaddr + 0x1e) & 0x07; if (((chk1 + 1) & 0x07) != chk2) - return (-1); + goto nodev; chk1 = chk2; } + + dev->base_addr = ioaddr; return (0); +nodev: + release_region(ioaddr, PROTEON_IO_EXTENT); + return -ENODEV; } -int __init proteon_probe(struct net_device *dev) +struct net_device * __init proteon_probe(int unit) { - static int versionprinted; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); struct net_local *tp; - int i,j; - struct proteon_card *card; - -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + static int versionprinted; + const unsigned *port; + int j,err = 0; - SET_MODULE_OWNER(dev); - if (!dev->base_addr) - { - for(i = 0; portlist[i]; i++) - { - if (!request_region(portlist[i], PROTEON_IO_EXTENT, cardname)) - continue; + if (!dev) + return ERR_PTR(-ENOMEM); - if(proteon_probe1(portlist[i])) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - continue; - } + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } - dev->base_addr = portlist[i]; - break; + SET_MODULE_OWNER(dev); + if (dev->base_addr) /* probe specific location */ + err = proteon_probe1(dev, dev->base_addr); + else { + for (port = portlist; *port; port++) { + err = proteon_probe1(dev, *port); + if (!err) + break; } - if(!dev->base_addr) - return -1; } - else - { - if (!request_region(dev->base_addr, PROTEON_IO_EXTENT, cardname)) - return -1; - - if(proteon_probe1(dev->base_addr)) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; - } - } + if (err) + goto out4; /* At this point we have found a valid card. */ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); + err = -EIO; if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) goto out4; @@ -264,14 +253,11 @@ int __init proteon_probe(struct net_devi printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - /* Enlist in the card list */ - card = kmalloc(sizeof(struct proteon_card), GFP_KERNEL); - if (!card) + err = register_netdev(dev); + if (err) goto out; - card->next = proteon_card_list; - proteon_card_list = card; - card->dev = dev; - return 0; + + return dev; out: free_dma(dev->dma); out2: @@ -280,7 +266,8 @@ out3: tmsdev_term(dev); out4: release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; + free_netdev(dev); + return ERR_PTR(err); } /* @@ -370,50 +357,50 @@ MODULE_PARM(io, "1-" __MODULE_STRING(ISA MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); -static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS]; + +static struct net_device * __init setup_card(unsigned long io, unsigned irq, unsigned char dma) { - int res = -ENOMEM; - struct proteon_card *this_card; - struct net_device *dev = alloc_trdev(0); - - if (dev) { - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - res = -ENODEV; - if (proteon_probe(dev) == 0) { - res = register_netdev(dev); - if (!res) - return 0; - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - this_card = proteon_card_list; - proteon_card_list = this_card->next; - kfree(this_card); - } - kfree(dev); - } - return res; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->irq = irq; + dev->dma = dma; + err = proteon_probe1(dev, io); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: + release_region(dev->base_addr, PROTEON_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + out: + free_netdev(dev); + return ERR_PTR(err); } int init_module(void) { - int i, num; + struct net_device *dev; + int i, num = 0; - num = 0; - if (io[0]) { /* Only probe addresses from command line */ - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) - num++; - } - } else { - for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { - if (setup_card(portlist[i], irq[num], dma[num]) == 0) - num++; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + dev = io[0] ? setup_card(io[i], irq[i], dma[i]) + : proteon_probe(-1); + if (!IS_ERR(dev)) { + proteon_dev[i] = dev; + ++num; } } + printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { @@ -425,11 +412,13 @@ int init_module(void) void cleanup_module(void) { - struct net_device *dev; - struct proteon_card *this_card; + int i; - while (proteon_card_list) { - dev = proteon_card_list->dev; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + struct net_device *dev = proteon_dev[i]; + + if (!dev) + continue; unregister_netdev(dev); release_region(dev->base_addr, PROTEON_IO_EXTENT); @@ -437,9 +426,6 @@ void cleanup_module(void) free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); - this_card = proteon_card_list; - proteon_card_list = this_card->next; - kfree(this_card); } } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/tokenring/skisa.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tokenring/skisa.c 2003-12-30 22:49:20.000000000 -0800 @@ -56,7 +56,7 @@ static unsigned int portlist[] __initdat /* A zero-terminated list of IRQs to be probed. * Used again after initial probe for sktr_chipset_init, called from sktr_open. */ -static unsigned short irqlist[] = { +static const unsigned short irqlist[] = { 3, 5, 9, 10, 11, 12, 15, 0 }; @@ -69,7 +69,6 @@ static int dmalist[] __initdata = { static char isa_cardname[] = "SK NET TR 4/16 ISA\0"; -int sk_isa_probe(struct net_device *dev); static int sk_isa_open(struct net_device *dev); static int sk_isa_close(struct net_device *dev); static void sk_isa_read_eeprom(struct net_device *dev); @@ -95,17 +94,14 @@ static void sk_isa_sifwritew(struct net_ outw(val, dev->base_addr + reg); } -struct sk_isa_card { - struct net_device *dev; - struct sk_isa_card *next; -}; - -static struct sk_isa_card *sk_isa_card_list; -static int __init sk_isa_probe1(int ioaddr) +static int __init sk_isa_probe1(struct net_device *dev, int ioaddr) { unsigned char old, chk1, chk2; + if (!request_region(ioaddr, SK_ISA_IO_EXTENT, isa_cardname)) + return -ENODEV; + old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ chk1 = 0; /* Begin with check value 0 */ @@ -122,8 +118,10 @@ static int __init sk_isa_probe1(int ioad chk2 = inb(ioaddr + SIFADD); chk2 ^= 0x0FE; - if(chk1 != chk2) - return (-1); /* No adapter */ + if(chk1 != chk2) { + release_region(ioaddr, SK_ISA_IO_EXTENT); + return -ENODEV; + } chk1 -= 2; } while(chk1 != 0); /* Repeat 128 times (all byte values) */ @@ -131,58 +129,45 @@ static int __init sk_isa_probe1(int ioad /* Restore the SIFADR value */ outb(old, ioaddr + SIFADR); - return (0); + dev->base_addr = ioaddr; + return 0; } -int __init sk_isa_probe(struct net_device *dev) +struct net_device * __init sk_isa_probe(int unit) { - static int versionprinted; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); struct net_local *tp; - int i,j; - struct sk_isa_card *card; + static int versionprinted; + const unsigned *port; + int j, err = 0; -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + if (!dev) + return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (!dev->base_addr) - { - for(i = 0; portlist[i]; i++) - { - if (!request_region(portlist[i], SK_ISA_IO_EXTENT, isa_cardname)) - continue; - - if(sk_isa_probe1(portlist[i])) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - continue; - } + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } - dev->base_addr = portlist[i]; - break; + SET_MODULE_OWNER(dev); + if (dev->base_addr) /* probe specific location */ + err = sk_isa_probe1(dev, dev->base_addr); + else { + for (port = portlist; *port; port++) { + err = sk_isa_probe1(dev, *port); + if (!err) + break; } - if(!dev->base_addr) - return -1; } - else - { - if (!request_region(dev->base_addr, SK_ISA_IO_EXTENT, isa_cardname)) - return -1; - - if(sk_isa_probe1(dev->base_addr)) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; - } - } + if (err) + goto out4; /* At this point we have found a valid card. */ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); + err = -EIO; if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) goto out4; @@ -284,14 +269,11 @@ int __init sk_isa_probe(struct net_devic printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - /* Enlist in the card list */ - card = kmalloc(sizeof(struct sk_isa_card), GFP_KERNEL); - if (!card) + err = register_netdev(dev); + if (err) goto out; - card->next = sk_isa_card_list; - sk_isa_card_list = card; - card->dev = dev; - return 0; + + return dev; out: free_dma(dev->dma); out2: @@ -300,7 +282,8 @@ out3: tmsdev_term(dev); out4: release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; + free_netdev(dev); + return ERR_PTR(err); } /* @@ -373,6 +356,8 @@ static int sk_isa_close(struct net_devic #define ISATR_MAX_ADAPTERS 3 +static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; + static int io[ISATR_MAX_ADAPTERS]; static int irq[ISATR_MAX_ADAPTERS]; static int dma[ISATR_MAX_ADAPTERS]; @@ -383,50 +368,54 @@ MODULE_PARM(io, "1-" __MODULE_STRING(ISA MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); -static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +static struct net_device * __init setup_card(unsigned long io, unsigned irq, unsigned char dma) { - int res = -ENOMEM; - struct sk_isa_card *this_card; - struct net_device *dev = alloc_trdev(0); - - if (dev) { - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - res = -ENODEV; - if (sk_isa_probe(dev) == 0) { - res = register_netdev(dev); - if (!res) - return 0; - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - this_card = sk_isa_card_list; - sk_isa_card_list = this_card->next; - kfree(this_card); - } - kfree(dev); - } - return res; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + + err = sk_isa_probe1(dev, io); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + + out1: + release_region(dev->base_addr, SK_ISA_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + out: + free_netdev(dev); + return ERR_PTR(err); } int init_module(void) { + struct net_device *dev; int i, num; num = 0; - if (io[0]) { /* Only probe addresses from command line */ - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) - num++; - } - } else { - for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { - if (setup_card(portlist[i], irq[num], dma[num]) == 0) - num++; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + if (io[0]) /* Only probe addresses from command line */ + dev = setup_card(io[i], irq[i], dma[i]); + else + dev = sk_isa_probe(-1); + if (!IS_ERR(dev)) { + sk_isa_dev[i] = dev; + ++num; } } + printk(KERN_NOTICE "skisa.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { @@ -438,11 +427,13 @@ int init_module(void) void cleanup_module(void) { - struct net_device *dev; - struct sk_isa_card *this_card; + int i; + + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + struct net_device *dev = sk_isa_dev[i]; - while (sk_isa_card_list) { - dev = sk_isa_card_list->dev; + if (!dev) + continue; unregister_netdev(dev); release_region(dev->base_addr, SK_ISA_IO_EXTENT); @@ -450,9 +441,6 @@ void cleanup_module(void) free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); - this_card = sk_isa_card_list; - sk_isa_card_list = this_card->next; - kfree(this_card); } } #endif /* MODULE */ --- linux-2.6.1-rc1/drivers/net/tokenring/smctr.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/tokenring/smctr.c 2003-12-30 22:49:20.000000000 -0800 @@ -69,13 +69,6 @@ static const char cardname[] = "smctr"; #define SMCTR_IO_EXTENT 20 -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int smctr_portlist[] __initdata = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, - 0x320, 0x340, 0x360, 0x380, - 0 -}; - #ifdef CONFIG_MCA static unsigned int smctr_posid = 0x6ec6; #endif @@ -219,7 +212,7 @@ static int smctr_open(struct net_device static int smctr_open_tr(struct net_device *dev); /* P */ -int __init smctr_probe (struct net_device *dev); +struct net_device *smctr_probe(int unit); static int __init smctr_probe1(struct net_device *dev, int ioaddr); static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, struct net_device *dev, __u16 rx_status); @@ -729,10 +722,6 @@ static int smctr_close(struct net_device netif_stop_queue(dev); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - tp->cleanup = 1; /* Check to see if adapter is already in a closed state. */ @@ -3490,10 +3479,6 @@ static int smctr_open(struct net_device if(err < 0) return (err); -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return (err); } @@ -3591,71 +3576,72 @@ out: return (err); } -/* Check for a network adapter of this type, and return '0 if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. +/* Check for a network adapter of this type, + * and return device structure if one exists. */ -int __init smctr_probe (struct net_device *dev) +struct net_device __init *smctr_probe(int unit) { - int i; - int base_addr; - -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + static const unsigned ports[] = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, + 0x320, 0x340, 0x360, 0x380, 0 + }; + const unsigned *port; + int err = 0; - base_addr = dev->base_addr; - if(base_addr > 0x1ff) /* Check a single specified location. */ - return (smctr_probe1(dev, base_addr)); - else if(base_addr != 0) /* Don't probe at all. */ - return (-ENXIO); + if (!dev) + return ERR_PTR(-ENOMEM); - for(i = 0; smctr_portlist[i]; i++) - { - int ioaddr = smctr_portlist[i]; - if (!smctr_probe1(dev, ioaddr)) - return (0); - } + SET_MODULE_OWNER(dev); - return (-ENODEV); -} + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } -static void cleanup_card(struct net_device *dev) -{ + if (dev->base_addr > 0x1ff) /* Check a single specified location. */ + err = smctr_probe1(dev, dev->base_addr); + else if(dev->base_addr != 0) /* Don't probe at all. */ + err =-ENXIO; + else { + for (port = ports; *port; port++) { + err = smctr_probe1(dev, *port); + if (!err) + break; + } + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: #ifdef CONFIG_MCA - struct net_local *tp = (struct net_local *)dev->priv; - if (tp->slot_num) + { struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) mca_mark_as_unused(tp->slot_num); + } #endif release_region(dev->base_addr, SMCTR_IO_EXTENT); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->priv) - kfree(dev->priv); + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); } + static int __init smctr_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; - struct net_local *tp; + struct net_local *tp = dev->priv; int err; __u32 *ram; if(smctr_debug && version_printed++ == 0) printk(version); - /* Setup this devices private information structure */ - tp = (struct net_local *)kmalloc(sizeof(struct net_local), - GFP_KERNEL); - if(tp == NULL) { - err = -ENOMEM; - goto out; - } - memset(tp, 0, sizeof(struct net_local)); spin_lock_init(&tp->lock); - - dev->priv = tp; dev->base_addr = ioaddr; /* Actually detect an adapter now. */ @@ -3664,7 +3650,7 @@ static int __init smctr_probe1(struct ne { if ((err = smctr_chk_mca(dev)) < 0) { err = -ENODEV; - goto out_tp; + goto out; } } @@ -3679,7 +3665,6 @@ static int __init smctr_probe1(struct ne if(err != UCODE_PRESENT && err != SUCCESS) { printk(KERN_ERR "%s: Firmware load failed (%d)\n", dev->name, err); - cleanup_card(dev); err = -EIO; goto out; } @@ -3704,8 +3689,6 @@ static int __init smctr_probe1(struct ne dev->set_multicast_list = &smctr_set_multicast_list; return (0); -out_tp: - kfree(tp); out: return err; } @@ -5677,47 +5660,59 @@ static int smctr_wait_while_cbusy(struct static struct net_device* dev_smctr[SMCTR_MAX_ADAPTERS]; static int io[SMCTR_MAX_ADAPTERS]; static int irq[SMCTR_MAX_ADAPTERS]; -static int mem[SMCTR_MAX_ADAPTERS]; MODULE_LICENSE("GPL"); -MODULE_PARM(io, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); -MODULE_PARM(ringspeed, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); +MODULE_PARM(ringspeed, "i"); + +static struct net_device *setup_card(int n) +{ + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->irq = irq[n]; + err = smctr_probe1(dev, io[n]); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: +#ifdef CONFIG_MCA + { struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); + } +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + int init_module(void) { - int i; + int i, found = 0; + struct net_device *dev; for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { - struct net_device *dev = alloc_trdev(0); - irq[i] = 0; - mem[i] = 0; - if (!dev) - return -ENOMEM; - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->mem_start = mem[i]; - - if (smctr_probe(dev) != 0) { - kfree(dev); - if (i == 0) { - printk(KERN_ERR "%s: smctr_probe failed.\n", - cardname); - return -EIO; - } - return 0; - } - if (register_netdev(dev) != 0) { - cleanup_card(dev); - kfree(dev); - continue; - } - dev_smctr[i] = dev; + dev = io[0]? setup_card(i) : smctr_probe(-1); + if (!IS_ERR(dev)) { + ++found; + dev_smctr[i] = dev; + } } - return (0); + return found ? 0 : -ENODEV; } void cleanup_module(void) @@ -5726,9 +5721,20 @@ void cleanup_module(void) for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { struct net_device *dev = dev_smctr[i]; + if (dev) { + unregister_netdev(dev); - cleanup_card(dev); +#ifdef CONFIG_MCA + { struct net_local *tp = dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); + } +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + if (dev->irq) + free_irq(dev->irq, dev); + free_netdev(dev); } } --- linux-2.6.1-rc1/drivers/net/tokenring/tms380tr.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tokenring/tms380tr.c 2003-12-30 22:49:20.000000000 -0800 @@ -147,7 +147,6 @@ static void tms380tr_hardware_send_pack struct net_local* tp); /* "I" */ static int tms380tr_init_adapter(struct net_device *dev); -static int tms380tr_init_card(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); static void tms380tr_init_net_local(struct net_device *dev); static void tms380tr_init_opb(struct net_device *dev); @@ -232,15 +231,6 @@ static int madgemc_sifprobe(struct net_d } #endif -/* Dummy function */ -static int tms380tr_init_card(struct net_device *dev) -{ - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: tms380tr_init_card\n", dev->name); - - return (0); -} - /* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. @@ -2386,7 +2376,6 @@ int tmsdev_init(struct net_device *dev, } /* These can be overridden by the card driver if needed */ - dev->init = tms380tr_init_card; dev->open = tms380tr_open; dev->stop = tms380tr_close; dev->do_ioctl = NULL; --- linux-2.6.1-rc1/drivers/net/tokenring/tmspci.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tokenring/tmspci.c 2003-12-30 22:49:20.000000000 -0800 @@ -179,7 +179,7 @@ err_out_irq: err_out_region: release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); err_out_trdev: - kfree(dev); + free_netdev(dev); return ret; } --- linux-2.6.1-rc1/drivers/net/tulip/de2104x.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/tulip/de2104x.c 2003-12-30 22:49:20.000000000 -0800 @@ -2084,7 +2084,7 @@ err_out_res: err_out_disable: pci_disable_device(pdev); err_out_free: - kfree(dev); + free_netdev(dev); return rc; } --- linux-2.6.1-rc1/drivers/net/tulip/dmfe.c 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/net/tulip/dmfe.c 2003-12-30 22:49:20.000000000 -0800 @@ -457,7 +457,7 @@ err_out_disable: pci_disable_device(pdev); err_out_free: pci_set_drvdata(pdev, NULL); - kfree(dev); + free_netdev(dev); return err; } --- linux-2.6.1-rc1/drivers/net/tulip/interrupt.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/tulip/interrupt.c 2003-12-30 22:49:20.000000000 -0800 @@ -19,13 +19,13 @@ #include #include - int tulip_rx_copybreak; unsigned int tulip_max_interrupt_work; -#ifdef CONFIG_NET_HW_FLOWCONTROL - +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION #define MIT_SIZE 15 +#define MIT_TABLE 15 /* We use 0 or max */ + unsigned int mit_table[MIT_SIZE+1] = { /* CRS11 21143 hardware Mitigation Control Interrupt @@ -99,16 +99,28 @@ int tulip_refill_rx(struct net_device *d return refilled; } +#ifdef CONFIG_TULIP_NAPI -static int tulip_rx(struct net_device *dev) +void oom_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + netif_rx_schedule(dev); +} + +int tulip_poll(struct net_device *dev, int *budget) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int rx_work_limit = *budget; int received = 0; -#ifdef CONFIG_NET_HW_FLOWCONTROL - int drop = 0, mit_sel = 0; + if (!netif_running(dev)) + goto done; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION /* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ @@ -119,6 +131,237 @@ static int tulip_rx(struct net_device *d if (tulip_debug > 4) printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, tp->rx_ring[entry].status); + + do { + /* Acknowledge current RX interrupt sources. */ + outl((RxIntr | RxNoBuf), dev->base_addr + CSR5); + + + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + + + if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) + break; + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + dev->name, entry, status); + if (--rx_work_limit < 0) + goto not_done; + + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < tulip_rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); +#if ! defined(__alpha__) + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), + tp->rx_buffers[entry].skb->tail, + pkt_len); +#endif + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_buffers[entry].skb, + pkt_len); + +#ifndef final_version + 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. %08x %p / %p.\n", + dev->name, + le32_to_cpu(tp->rx_ring[entry].buffer1), + tp->rx_buffers[entry].mapping, + skb->head, temp); + } +#endif + + pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + + tp->rx_buffers[entry].skb = NULL; + tp->rx_buffers[entry].mapping = 0; + } + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); + + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; + + entry = (++tp->cur_rx) % RX_RING_SIZE; + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) + tulip_refill_rx(dev); + + } + + /* New ack strategy... irq does not ack Rx any longer + hopefully this helps */ + + /* Really bad things can happen here... If new packet arrives + * and an irq arrives (tx or just due to occasionally unset + * mask), it will be acked by irq handler, but new thread + * is not scheduled. It is major hole in design. + * No idea how to fix this if "playing with fire" will fail + * tomorrow (night 011029). If it will not fail, we won + * finally: amount of IO did not increase at all. */ + } while ((inl(dev->base_addr + CSR5) & RxIntr)); + +done: + + #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + + /* We use this simplistic scheme for IM. It's proven by + real life installations. We can have IM enabled + continuesly but this would cause unnecessary latency. + Unfortunely we can't use all the NET_RX_* feedback here. + This would turn on IM for devices that is not contributing + to backlog congestion with unnecessary latency. + + We monitor the the device RX-ring and have: + + HW Interrupt Mitigation either ON or OFF. + + ON: More then 1 pkt received (per intr.) OR we are dropping + OFF: Only 1 pkt received + + Note. We only use min and max (0, 15) settings from mit_table */ + + + if( tp->flags & HAS_INTR_MITIGATION) { + if( received > 1 ) { + if( ! tp->mit_on ) { + tp->mit_on = 1; + outl(mit_table[MIT_TABLE], dev->base_addr + CSR11); + } + } + else { + if( tp->mit_on ) { + tp->mit_on = 0; + outl(0, dev->base_addr + CSR11); + } + } + } + +#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ + + dev->quota -= received; + *budget -= received; + + tulip_refill_rx(dev); + + /* If RX ring is not full we are out of memory. */ + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + + /* Remove us from polling list and enable RX intr. */ + + netif_rx_complete(dev); + outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); + + /* The last op happens after poll completion. Which means the following: + * 1. it can race with disabling irqs in irq handler + * 2. it can race with dise/enabling irqs in other poll threads + * 3. if an irq raised after beginning loop, it will be immediately + * triggered here. + * + * Summarizing: the logic results in some redundant irqs both + * due to races in masking and due to too late acking of already + * processed irqs. But it must not result in losing events. + */ + + return 0; + + not_done: + if (!received) { + + received = dev->quota; /* Not to happen */ + } + dev->quota -= received; + *budget -= received; + + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || + tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + tulip_refill_rx(dev); + + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + + return 1; + + + oom: /* Executed with RX ints disabled */ + + + /* Start timer, stop polling, but do not enable rx interrupts. */ + mod_timer(&tp->oom_timer, jiffies+1); + + /* Think: timer_pending() was an explicit signature of bug. + * Timer can be pending now but fired and completed + * before we did netif_rx_complete(). See? We would lose it. */ + + /* remove ourselves from the polling list */ + netif_rx_complete(dev); + + return 0; +} + +#else /* CONFIG_TULIP_NAPI */ + +static int tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int received = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); @@ -163,11 +406,6 @@ static int tulip_rx(struct net_device *d } #endif -#ifdef CONFIG_NET_HW_FLOWCONTROL - drop = atomic_read(&netdev_dropping); - if (drop) - goto throttle; -#endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak @@ -209,44 +447,9 @@ static int tulip_rx(struct net_device *d tp->rx_buffers[entry].mapping = 0; } skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = -#endif - netif_rx(skb); -#ifdef CONFIG_NET_HW_FLOWCONTROL - switch (mit_sel) { - case NET_RX_SUCCESS: - case NET_RX_CN_LOW: - case NET_RX_CN_MOD: - break; - - case NET_RX_CN_HIGH: - rx_work_limit -= NET_RX_CN_HIGH; /* additional*/ - break; - case NET_RX_DROP: - rx_work_limit = -1; - break; - default: - printk("unknown feedback return code %d\n", mit_sel); - break; - } + netif_rx(skb); - drop = atomic_read(&netdev_dropping); - if (drop) { -throttle: - rx_work_limit = -1; - mit_sel = NET_RX_DROP; - - if (tp->fc_bit) { - long ioaddr = dev->base_addr; - - /* disable Rx & RxNoBuf ints. */ - outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7); - set_bit(tp->fc_bit, &netdev_fc_xoff); - } - } -#endif dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; @@ -254,42 +457,9 @@ throttle: received++; entry = (++tp->cur_rx) % RX_RING_SIZE; } -#ifdef CONFIG_NET_HW_FLOWCONTROL - - /* We use this simplistic scheme for IM. It's proven by - real life installations. We can have IM enabled - continuesly but this would cause unnecessary latency. - Unfortunely we can't use all the NET_RX_* feedback here. - This would turn on IM for devices that is not contributing - to backlog congestion with unnecessary latency. - - We monitor the device RX-ring and have: - - HW Interrupt Mitigation either ON or OFF. - - ON: More then 1 pkt received (per intr.) OR we are dropping - OFF: Only 1 pkt received - - Note. We only use min and max (0, 15) settings from mit_table */ - - - if( tp->flags & HAS_INTR_MITIGATION) { - if((received > 1 || mit_sel == NET_RX_DROP) - && tp->mit_sel != 15 ) { - tp->mit_sel = 15; - tp->mit_change = 1; /* Force IM change */ - } - if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) { - tp->mit_sel = 0; - tp->mit_change = 1; /* Force IM change */ - } - } - - return RX_RING_SIZE+1; /* maxrx+1 */ -#else return received; -#endif } +#endif /* CONFIG_TULIP_NAPI */ static inline unsigned int phy_interrupt (struct net_device *dev) { @@ -323,7 +493,6 @@ irqreturn_t tulip_interrupt(int irq, voi struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int csr5; - int entry; int missed; int rx = 0; int tx = 0; @@ -331,6 +500,11 @@ irqreturn_t tulip_interrupt(int irq, voi int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; +#ifdef CONFIG_TULIP_NAPI + int rxd = 0; +#else + int entry; +#endif unsigned int work_count = tulip_max_interrupt_work; unsigned int handled = 0; @@ -346,22 +520,41 @@ irqreturn_t tulip_interrupt(int irq, voi tp->nir++; do { + +#ifdef CONFIG_TULIP_NAPI + + if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { + rxd++; + /* Mask RX intrs and add the device to poll list. */ + outl(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); + netif_rx_schedule(dev); + + if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) + break; + } + + /* Acknowledge the interrupt sources we handle here ASAP + the poll function does Rx and RxNoBuf acking */ + + outl(csr5 & 0x0001ff3f, ioaddr + CSR5); + +#else /* Acknowledge all of the current interrupt sources ASAP. */ outl(csr5 & 0x0001ffff, ioaddr + CSR5); - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); if (csr5 & (RxIntr | RxNoBuf)) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if ((!tp->fc_bit) || - (!test_bit(tp->fc_bit, &netdev_fc_xoff))) -#endif rx += tulip_rx(dev); tulip_refill_rx(dev); } +#endif /* CONFIG_TULIP_NAPI */ + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx; @@ -462,15 +655,8 @@ irqreturn_t tulip_interrupt(int irq, voi } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) { - tp->stats.rx_errors++; - tulip_start_rxtx(tp); - } -#else tp->stats.rx_errors++; tulip_start_rxtx(tp); -#endif } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this @@ -504,10 +690,6 @@ irqreturn_t tulip_interrupt(int irq, voi if (tulip_debug > 2) printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", dev->name, csr5); -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff))) - if (net_ratelimit()) printk("BUG!! enabling interrupt when FC off (timerintr.) \n"); -#endif outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tp->ttimer = 0; oi++; @@ -520,16 +702,9 @@ irqreturn_t tulip_interrupt(int irq, voi /* Acknowledge all interrupt sources. */ outl(0x8001ffff, ioaddr + CSR5); if (tp->flags & HAS_INTR_MITIGATION) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if(tp->mit_change) { - outl(mit_table[tp->mit_sel], ioaddr + CSR11); - tp->mit_change = 0; - } -#else /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ outl(0x8b240000, ioaddr + CSR11); -#endif } else if (tp->chip_id == LC82C168) { /* the LC82C168 doesn't have a hw timer.*/ outl(0x00, ioaddr + CSR7); @@ -537,10 +712,8 @@ irqreturn_t tulip_interrupt(int irq, voi } else { /* Mask all interrupting sources, set timer to re-enable. */ -#ifndef CONFIG_NET_HW_FLOWCONTROL outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); outl(0x0012, ioaddr + CSR11); -#endif } break; } @@ -550,6 +723,21 @@ irqreturn_t tulip_interrupt(int irq, voi break; csr5 = inl(ioaddr + CSR5); + +#ifdef CONFIG_TULIP_NAPI + if (rxd) + csr5 &= ~RxPollInt; + } while ((csr5 & (TxNoBuf | + TxDied | + TxIntr | + TimerInt | + /* Abnormal intr. */ + RxDied | + TxFIFOUnderflow | + TxJabber | + TPLnkFail | + SytemError )) != 0); +#else } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); tulip_refill_rx(dev); @@ -574,6 +762,7 @@ irqreturn_t tulip_interrupt(int irq, voi } } } +#endif /* CONFIG_TULIP_NAPI */ if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; --- linux-2.6.1-rc1/drivers/net/tulip/Kconfig 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/tulip/Kconfig 2003-12-30 22:49:20.000000000 -0800 @@ -68,6 +68,26 @@ config TULIP_MMIO obscure bugs if your mainboard has memory controller timing issues. If in doubt, say N. +config TULIP_NAPI + bool "Use NAPI RX polling " + depends on TULIP + ---help--- + This is of useful for servers and routers dealing with high network loads. + + See . + + If in doubt, say N. + +config TULIP_NAPI_HW_MITIGATION + bool "Use Interrupt Mitigation " + depends on TULIP_NAPI + ---help--- + Use HW to reduce RX interrupts. Not strict necessary since NAPI reduces + RX interrupts but itself. Although this reduces RX interrupts even at + low levels traffic at the cost of a small latency. + + If in doubt, say Y. + config DE4X5 tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA" depends on NET_TULIP && (PCI || EISA) --- linux-2.6.1-rc1/drivers/net/tulip/tulip_core.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/drivers/net/tulip/tulip_core.c 2003-12-30 22:50:15.000000000 -0800 @@ -14,11 +14,17 @@ */ +#include + #define DRV_NAME "tulip" +#ifdef CONFIG_TULIP_NAPI +#define DRV_VERSION "1.1.13-NAPI" /* Keep at least for test */ +#else #define DRV_VERSION "1.1.13" +#endif #define DRV_RELDATE "May 11, 2002" -#include + #include #include "tulip.h" #include @@ -247,7 +253,7 @@ static void tulip_down(struct net_device static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); - +static void poll_tulip(struct net_device *dev); static void tulip_set_power_state (struct tulip_private *tp, @@ -466,29 +472,16 @@ media_picked: to an alternate media type. */ tp->timer.expires = RUN_AT(next_tick); add_timer(&tp->timer); -} - -#ifdef CONFIG_NET_HW_FLOWCONTROL -/* Enable receiver */ -void tulip_xon(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - - clear_bit(tp->fc_bit, &netdev_fc_xoff); - if (netif_running(dev)){ - - tulip_refill_rx(dev); - outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); - } -} +#ifdef CONFIG_TULIP_NAPI + init_timer(&tp->oom_timer); + tp->oom_timer.data = (unsigned long)dev; + tp->oom_timer.function = oom_timer; #endif +} static int tulip_open(struct net_device *dev) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - struct tulip_private *tp = (struct tulip_private *)dev->priv; -#endif int retval; if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) @@ -498,10 +491,6 @@ tulip_open(struct net_device *dev) tulip_up (dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - tp->fc_bit = netdev_register_fc(dev, tulip_xon); -#endif - netif_start_queue (dev); return 0; @@ -582,10 +571,7 @@ static void tulip_tx_timeout(struct net_ #endif /* Stop and restart the chip's Tx processes . */ -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff)) - printk("BUG tx_timeout restarting rx when fc on\n"); -#endif + tulip_restart_rxtx(tp); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); @@ -742,7 +728,9 @@ static void tulip_down (struct net_devic unsigned long flags; del_timer_sync (&tp->timer); - +#ifdef CONFIG_TULIP_NAPI + del_timer_sync (&tp->oom_timer); +#endif spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts by clearing the interrupt mask. */ @@ -781,13 +769,6 @@ static int tulip_close (struct net_devic netif_stop_queue (dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit) { - int bit = tp->fc_bit; - tp->fc_bit = 0; - netdev_unregister_fc(bit); - } -#endif tulip_down (dev); if (tulip_debug > 1) @@ -1531,7 +1512,7 @@ static int __devinit tulip_init_one (str } } /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02) && dev->dev_addr[1] == 0x00) for (i = 0; i < 6; i+=2) { char tmp = dev->dev_addr[i]; @@ -1629,10 +1610,17 @@ static int __devinit tulip_init_one (str dev->hard_start_xmit = tulip_start_xmit; dev->tx_timeout = tulip_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_TULIP_NAPI + dev->poll = tulip_poll; + dev->weight = 16; +#endif dev->stop = tulip_close; dev->get_stats = tulip_get_stats; dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_tulip; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1725,7 +1713,7 @@ err_out_free_res: pci_release_regions (pdev); err_out_free_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } @@ -1789,6 +1777,22 @@ static void __devexit tulip_remove_one ( /* pci_power_off (pdev, -1); */ } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_tulip (struct net_device *dev) +{ + /* disable_irq here is not very nice, but with the lockless + interrupt handler we have no other choice. */ + disable_irq(dev->irq); + tulip_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static struct pci_driver tulip_driver = { .name = DRV_NAME, --- linux-2.6.1-rc1/drivers/net/tulip/tulip.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/net/tulip/tulip.h 2003-12-30 22:49:20.000000000 -0800 @@ -126,6 +126,7 @@ enum pci_cfg_driver_reg { CFDD_Snooze = (1 << 30), }; +#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber) /* The bits in the CSR5 status registers, mostly interrupt sources. */ enum status_bits { @@ -251,9 +252,9 @@ enum t21143_csr6_bits { Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 32 +#define RX_RING_SIZE 128 #define MEDIA_MASK 31 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -343,17 +344,15 @@ struct tulip_private { int flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ + struct timer_list oom_timer; /* Out of memory timer. */ u32 mc_filter[2]; spinlock_t lock; spinlock_t mii_lock; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ -#ifdef CONFIG_NET_HW_FLOWCONTROL -#define RX_A_NBF_STOP 0xffffff3f /* To disable RX and RX-NOBUF ints. */ - int fc_bit; - int mit_sel; - int mit_change; /* Signal for Interrupt Mitigtion */ +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + int mit_on; #endif unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; @@ -415,6 +414,10 @@ extern unsigned int tulip_max_interrupt_ extern int tulip_rx_copybreak; irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); int tulip_refill_rx(struct net_device *dev); +#ifdef CONFIG_TULIP_NAPI +int tulip_poll(struct net_device *dev, int *budget); +#endif + /* media.c */ int tulip_mdio_read(struct net_device *dev, int phy_id, int location); @@ -438,6 +441,7 @@ extern int tulip_debug; extern const char * const medianame[]; extern const char tulip_media_cap[]; extern struct tulip_chip_table tulip_tbl[]; +void oom_timer(unsigned long data); extern u8 t21040_csr13[]; #ifndef USE_IO_OPS --- linux-2.6.1-rc1/drivers/net/tulip/winbond-840.c 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/net/tulip/winbond-840.c 2003-12-30 22:49:20.000000000 -0800 @@ -530,7 +530,7 @@ err_out_free_res: #endif pci_release_regions(pdev); err_out_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } --- linux-2.6.1-rc1/drivers/net/tulip/xircom_tulip_cb.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/tulip/xircom_tulip_cb.c 2003-12-30 22:49:20.000000000 -0800 @@ -648,8 +648,7 @@ err_out_cleardev: pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); err_out_free_netdev: - unregister_netdev(dev); - kfree(dev); + free_netdev(dev); return -ENODEV; } --- linux-2.6.1-rc1/drivers/net/tun.c 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/net/tun.c 2003-12-30 22:49:20.000000000 -0800 @@ -377,6 +377,7 @@ static struct tun_struct *tun_get_by_nam static int tun_set_iff(struct file *file, struct ifreq *ifr) { struct tun_struct *tun; + struct net_device *dev; int err; tun = tun_get_by_name(ifr->ifr_name); @@ -394,7 +395,6 @@ static int tun_set_iff(struct file *file else { char *name; unsigned long flags = 0; - struct net_device *dev; err = -EINVAL; @@ -424,16 +424,13 @@ static int tun_set_iff(struct file *file if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); - if (err < 0) { - kfree(dev); - goto failed; - } + if (err < 0) + goto err_free_dev; } - if ((err = register_netdevice(tun->dev))) { - kfree(dev); - goto failed; - } + err = register_netdevice(tun->dev); + if (err < 0) + goto err_free_dev; list_add(&tun->list, &tun_dev_list); } @@ -451,6 +448,9 @@ static int tun_set_iff(struct file *file strcpy(ifr->ifr_name, tun->dev->name); return 0; + + err_free_dev: + free_netdev(dev); failed: return err; } --- linux-2.6.1-rc1/drivers/net/via-rhine.c 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/net/via-rhine.c 2003-12-30 22:49:20.000000000 -0800 @@ -615,6 +615,15 @@ static void __devinit reload_eeprom(long break; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void via_rhine_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + via_rhine_interrupt(dev->irq, (void *)dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -784,6 +793,9 @@ static int __devinit via_rhine_init_one dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = via_rhine_poll; +#endif if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; --- linux-2.6.1-rc1/drivers/net/wan/cosa.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/wan/cosa.c 2003-12-30 22:49:20.000000000 -0800 @@ -594,40 +594,47 @@ err_out: /*---------- SPPP/HDLC netdevice ---------- */ +static void cosa_setup(struct net_device *d) +{ + d->open = cosa_sppp_open; + d->stop = cosa_sppp_close; + d->hard_start_xmit = cosa_sppp_tx; + d->do_ioctl = cosa_sppp_ioctl; + d->get_stats = cosa_net_stats; + d->tx_timeout = cosa_sppp_timeout; + d->watchdog_timeo = TX_TIMEOUT; +} + static void sppp_channel_init(struct channel_data *chan) { struct net_device *d; chan->if_ptr = &chan->pppdev; - chan->pppdev.dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(chan->pppdev.dev, 0, sizeof(struct net_device)); + d = alloc_netdev(0, chan->name, cosa_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", chan->name); + return; + } + chan->pppdev.dev = d; sppp_attach(&chan->pppdev); - d=chan->pppdev.dev; - strcpy(d->name, chan->name); d->base_addr = chan->cosa->datareg; d->irq = chan->cosa->irq; d->dma = chan->cosa->dma; d->priv = chan; - d->init = NULL; - d->open = cosa_sppp_open; - d->stop = cosa_sppp_close; - d->hard_start_xmit = cosa_sppp_tx; - d->do_ioctl = cosa_sppp_ioctl; - d->get_stats = cosa_net_stats; - d->tx_timeout = cosa_sppp_timeout; - d->watchdog_timeo = TX_TIMEOUT; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(chan->pppdev.dev); - free_netdev(chan->pppdev.dev); + sppp_detach(d); + free_netdev(d); + chan->pppdev.dev = NULL; return; } } static void sppp_channel_delete(struct channel_data *chan) { - sppp_detach(chan->pppdev.dev); unregister_netdev(chan->pppdev.dev); + sppp_detach(chan->pppdev.dev); free_netdev(chan->pppdev.dev); + chan->pppdev.dev = NULL; } static int cosa_sppp_open(struct net_device *d) --- linux-2.6.1-rc1/drivers/net/wan/farsync.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/wan/farsync.c 2003-12-30 22:49:20.000000000 -0800 @@ -1313,8 +1313,6 @@ fst_open ( struct net_device *dev ) if ( err ) return err; - MOD_INC_USE_COUNT; - fst_openport ( dev_to_port ( dev )); netif_wake_queue ( dev ); return 0; @@ -1326,7 +1324,6 @@ fst_close ( struct net_device *dev ) netif_stop_queue ( dev ); fst_closeport ( dev_to_port ( dev )); hdlc_close ( dev_to_hdlc ( dev )); - MOD_DEC_USE_COUNT; return 0; } --- linux-2.6.1-rc1/drivers/net/wan/hd64572.h 2003-06-14 12:18:28.000000000 -0700 +++ 25/drivers/net/wan/hd64572.h 2003-12-30 22:49:20.000000000 -0800 @@ -23,8 +23,8 @@ * */ -#ifndef _HD64572_H -#define _HD64572_H +#ifndef __HD64572_H +#define __HD64572_H /* Illegal Access Register */ #define ILAR 0x00 @@ -59,6 +59,9 @@ #define IR0_M(val, chan) ((val)<<(8*(chan))) /* Int MSCI */ /* MSCI Channel Registers */ +#define MSCI0_OFFSET 0x00 +#define MSCI1_OFFSET 0x80 + #define MD0 0x138 /* Mode reg 0 */ #define MD1 0x139 /* Mode reg 1 */ #define MD2 0x13a /* Mode reg 2 */ @@ -107,6 +110,11 @@ #define RCR 0x156 /* Rx DMA Critical Request Reg */ /* Timer Registers */ +#define TIMER0RX_OFFSET 0x00 +#define TIMER0TX_OFFSET 0x10 +#define TIMER1RX_OFFSET 0x20 +#define TIMER1TX_OFFSET 0x30 + #define TCNTL 0x200 /* Timer Upcounter L */ #define TCNTH 0x201 /* Timer Upcounter H */ #define TCONRL 0x204 /* Timer Constant Register L */ @@ -132,6 +140,11 @@ #define DCR_TX(chan) (0x59 + 2*chan) /* DMA Command Reg (Tx) */ /* DMA Channel Registers */ +#define DMAC0RX_OFFSET 0x00 +#define DMAC0TX_OFFSET 0x20 +#define DMAC1RX_OFFSET 0x40 +#define DMAC1TX_OFFSET 0x60 + #define DARL 0x80 /* Dest Addr Register L (single-block, RX only) */ #define DARH 0x81 /* Dest Addr Register H (single-block, RX only) */ #define DARB 0x82 /* Dest Addr Register B (single-block, RX only) */ @@ -166,7 +179,17 @@ typedef struct { unsigned char filler[5]; /* alignment filler (16 bytes) */ } pcsca_bd_t; -/* +/* Block Descriptor Structure */ +typedef struct { + u32 cp; /* pointer to next block descriptor */ + u32 bp; /* buffer pointer */ + u16 len; /* data length */ + u8 stat; /* status */ + u8 unused; /* pads to 4-byte boundary */ +}pkt_desc; + + +/* Descriptor Status definitions: Bit Transmission Reception @@ -190,6 +213,23 @@ typedef struct { #define DST_SHRT 0x40 /* Short Frame */ #define DST_EOM 0x80 /* End of Message */ +/* Packet Descriptor Status bits */ + +#define ST_TX_EOM 0x80 /* End of frame */ +#define ST_TX_UNDRRUN 0x08 +#define ST_TX_OWNRSHP 0x02 +#define ST_TX_EOT 0x01 /* End of transmition */ + +#define ST_RX_EOM 0x80 /* End of frame */ +#define ST_RX_SHORT 0x40 /* Short frame */ +#define ST_RX_ABORT 0x20 /* Abort */ +#define ST_RX_RESBIT 0x10 /* Residual bit */ +#define ST_RX_OVERRUN 0x08 /* Overrun */ +#define ST_RX_CRC 0x04 /* CRC */ +#define ST_RX_OWNRSHP 0x02 + +#define ST_ERROR_MASK 0x7C + /* Status Counter Registers */ #define CMCR 0x158 /* Counter Master Ctl Reg */ #define TECNTL 0x160 /* Tx EOM Counter L */ @@ -246,11 +286,25 @@ typedef struct { #define MD0_BIT_SYNC 0x80 #define MD0_TRANSP 0xc0 +#define MD0_HDLC 0x80 /* Bit-sync HDLC mode */ + +#define MD0_CRC_NONE 0x00 +#define MD0_CRC_16_0 0x04 +#define MD0_CRC_16 0x05 +#define MD0_CRC_ITU32 0x06 +#define MD0_CRC_ITU 0x07 + #define MD1_NOADDR 0x00 #define MD1_SADDR1 0x40 #define MD1_SADDR2 0x80 #define MD1_DADDR 0xc0 +#define MD2_NRZI_IEEE 0x40 +#define MD2_MANCHESTER 0x80 +#define MD2_FM_MARK 0xA0 +#define MD2_FM_SPACE 0xC0 +#define MD2_LOOPBACK 0x03 /* Local data Loopback */ + #define MD2_F_DUPLEX 0x00 #define MD2_AUTO_ECHO 0x01 #define MD2_LOOP_HI_Z 0x02 @@ -274,6 +328,10 @@ typedef struct { #define CTL_URSKP 0x40 #define CTL_URCT 0x80 +#define CTL_NORTS 0x01 +#define CTL_NODTR 0x02 +#define CTL_IDLE 0x10 + #define RXS_BR0 0x01 #define RXS_BR1 0x02 #define RXS_BR2 0x04 @@ -302,6 +360,12 @@ typedef struct { #define EXS_TES1 0x20 #define EXS_TES2 0x40 +#define CLK_BRG_MASK 0x0F +#define CLK_PIN_OUT 0x80 +#define CLK_LINE 0x00 /* clock line input */ +#define CLK_BRG 0x40 /* internal baud rate generator */ +#define CLK_TX_RXCLK 0x60 /* TX clock from RX clock */ + #define CMD_RX_RST 0x11 #define CMD_RX_ENA 0x12 #define CMD_RX_DIS 0x13 @@ -324,6 +388,10 @@ typedef struct { #define CMD_SRCH_MODE 0x31 #define CMD_NOP 0x00 +#define CMD_RESET 0x21 +#define CMD_TX_ENABLE 0x02 +#define CMD_RX_ENABLE 0x12 + #define ST0_RXRDY 0x01 #define ST0_TXRDY 0x02 #define ST0_RXINTB 0x20 @@ -374,6 +442,8 @@ typedef struct { #define IE0_RXINTB 0x20 #define IE0_RXINTA 0x40 #define IE0_TXINT 0x80 +#define IE0_UDRN 0x00008000 /* TX underrun MSCI interrupt enable */ +#define IE0_CDCD 0x00000400 /* CD level change interrupt enable */ #define IE1_IDLD 0x01 #define IE1_ABTD 0x02 @@ -424,14 +494,28 @@ typedef struct { #define DIR_EOM 0x40 #define DIR_EOT 0x80 +#define DIR_REFE 0x04 +#define DIR_UDRFE 0x04 +#define DIR_COAE 0x08 +#define DIR_COFE 0x10 +#define DIR_BOFE 0x20 +#define DIR_EOME 0x40 +#define DIR_EOTE 0x80 + #define DMR_CNTE 0x02 #define DMR_NF 0x04 #define DMR_SEOME 0x08 #define DMR_TMOD 0x10 +#define DMER_DME 0x80 /* DMA Master Enable */ + #define DCR_SW_ABT 0x01 #define DCR_FCT_CLR 0x02 +#define DCR_ABORT 0x01 +#define DCR_CLEAR_EOF 0x02 + +#define PCR_COTE 0x80 #define PCR_PR0 0x01 #define PCR_PR1 0x02 #define PCR_PR2 0x04 @@ -440,4 +524,4 @@ typedef struct { #define PCR_OSB 0x40 #define PCR_BURST 0x80 -#endif /* (_HD64572_H) */ +#endif /* (__HD64572_H) */ --- linux-2.6.1-rc1/drivers/net/wan/Kconfig 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/wan/Kconfig 2003-12-30 22:49:20.000000000 -0800 @@ -325,6 +325,21 @@ config HDLC_X25 comment "X.25/LAPB support is disabled" depends on WAN && HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y +config PCI200SYN + tristate "Goramo PCI200SYN support" + depends on HDLC && PCI + help + This driver is for PCI200SYN cards made by Goramo sp. j. + If you have such a card, say Y here and see + + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called pci200syn. + + If unsure, say N here. + config WANXL tristate "SBE Inc. wanXL support" depends on HDLC && PCI --- linux-2.6.1-rc1/drivers/net/wan/lmc/lmc_main.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/wan/lmc/lmc_main.c 2003-12-30 22:49:20.000000000 -0800 @@ -78,30 +78,22 @@ #include "lmc_debug.h" #include "lmc_proto.h" - -static int Lmc_Count = 0; -static struct net_device *Lmc_root_dev = NULL; -static u8 cards_found = 0; - static int lmc_first_load = 0; -int LMC_PKT_BUF_SZ = 1542; +static int LMC_PKT_BUF_SZ = 1542; -#ifdef MODULE static struct pci_device_id lmc_pci_tbl[] = { - { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0}, - { 0, } + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + PCI_VENDOR_ID_LMC, PCI_ANY_ID }, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + PCI_ANY_ID, PCI_VENDOR_ID_LMC }, + { 0 } }; MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); - MODULE_LICENSE("GPL"); -#endif -int lmc_probe_fake(struct net_device *dev); -static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq, - int chip_id, int subdevice, int board_idx); static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lmc_rx (struct net_device *dev); @@ -115,12 +107,9 @@ static void lmc_softreset(lmc_softc_t * static void lmc_running_reset(struct net_device *dev); static int lmc_ifdown(struct net_device * const); static void lmc_watchdog(unsigned long data); -static int lmc_init(struct net_device * const); static void lmc_reset(lmc_softc_t * const sc); static void lmc_dec_reset(lmc_softc_t * const sc); static void lmc_driver_timeout(struct net_device *dev); -int lmc_setup(void); - /* * linux reserves 16 device specific IOCTLs. We call them @@ -815,67 +804,77 @@ kick_timer: } -static int lmc_init(struct net_device * const dev) /*fold00*/ +static void lmc_setup(struct net_device * const dev) /*fold00*/ { - lmc_trace(dev, "lmc_init in"); - lmc_trace(dev, "lmc_init out"); - - return 0; + lmc_trace(dev, "lmc_setup in"); + + dev->type = ARPHRD_HDLC; + dev->hard_start_xmit = lmc_start_xmit; + dev->open = lmc_open; + dev->stop = lmc_close; + dev->get_stats = lmc_get_stats; + dev->do_ioctl = lmc_ioctl; + dev->set_config = lmc_set_config; + dev->tx_timeout = lmc_driver_timeout; + dev->watchdog_timeo = (HZ); /* 1 second */ + + lmc_trace(dev, "lmc_setup out"); } -/* This initializes each card from lmc_probe() */ -static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/ - int chip_id, int subdevice, int board_idx) + +static int __devinit lmc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - lmc_softc_t *sc = NULL; + struct net_device *dev; + lmc_softc_t *sc; + u16 subdevice; u_int16_t AdapModelNum; - - /* - * Allocate our own device structure - */ - - dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL); - if (dev == NULL){ - printk (KERN_ERR "lmc: kmalloc for device failed\n"); - return NULL; - } - memset (dev, 0, sizeof (struct net_device)); - + int err = -ENOMEM; + static int cards_found; #ifndef GCOM - /* - * Switch to common hdlc%d naming. We name by type not by vendor - */ - - dev_alloc_name(dev, "hdlc%d"); + /* We name by type not by vendor */ + static const char lmcname[] = "hdlc%d"; #else - /* + /* * GCOM uses LMC vendor name so that clients can know which card * to attach to. */ - dev_alloc_name(dev, "lmc%d"); + static const char lmcname[] = "lmc%d"; #endif - lmc_trace(dev, "lmc_probe1 in"); + + /* + * Allocate our own device structure + */ + dev = alloc_netdev(sizeof(lmc_softc_t), lmcname, lmc_setup); + if (!dev) { + printk (KERN_ERR "lmc:alloc_netdev for device failed\n"); + goto out1; + } + + lmc_trace(dev, "lmc_init_one in"); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "lmc: pci enable failed:%d\n", err); + goto out2; + } - Lmc_Count++; + if (pci_request_regions(pdev, "lmc")) { + printk(KERN_ERR "lmc: pci_request_region failed\n"); + err = -EIO; + goto out3; + } + + pci_set_drvdata(pdev, dev); if(lmc_first_load == 0){ - printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); + printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n", + DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); lmc_first_load = 1; } - /* - * Allocate space for the private data structure - */ - - sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL); - if (sc == NULL) { - printk (KERN_WARNING "%s: Cannot allocate memory for device state\n", - dev->name); - return (NULL); - } - memset (sc, 0, sizeof (lmc_softc_t)); - dev->priv = sc; + sc = dev->priv; sc->lmc_device = dev; sc->name = dev->name; @@ -883,8 +882,12 @@ static struct net_device *lmc_probe1 (st /* An ioctl can cause a subsequent detach for raw frame interface */ sc->if_type = LMC_PPP; sc->check = 0xBEAFCAFE; - dev->base_addr = ioaddr; - dev->irq = irq; + dev->base_addr = pci_resource_start(pdev, 0); + dev->irq = pdev->irq; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + /* * This will get the protocol layer ready and do any 1 time init's * Must have a valid sc and dev structure @@ -893,19 +896,6 @@ static struct net_device *lmc_probe1 (st lmc_proto_attach(sc); - /* Just fill in the entries for the device */ - - dev->init = lmc_init; - dev->type = ARPHRD_HDLC; - dev->hard_start_xmit = lmc_start_xmit; - dev->open = lmc_open; - dev->stop = lmc_close; - dev->get_stats = lmc_get_stats; - dev->do_ioctl = lmc_ioctl; - dev->set_config = lmc_set_config; - dev->tx_timeout = lmc_driver_timeout; - dev->watchdog_timeo = (HZ); /* 1 second */ - /* * Why were we changing this??? dev->tx_queue_len = 100; @@ -914,44 +904,45 @@ static struct net_device *lmc_probe1 (st /* Init the spin lock so can call it latter */ spin_lock_init(&sc->lmc_lock); + pci_set_master(pdev); - printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq); + printk ("%s: detected at %lx, irq %d\n", dev->name, + dev->base_addr, dev->irq); if (register_netdev (dev) != 0) { printk (KERN_ERR "%s: register_netdev failed.\n", dev->name); - lmc_proto_detach(sc); - kfree (dev->priv); - kfree (dev); - return NULL; + goto out4; } - /* - * Request the region of registers we need, so that - * later on, no one else will take our card away from - * us. - */ - request_region (ioaddr, LMC_REG_RANGE, dev->name); - sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN; sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + /* + * + * Check either the subvendor or the subdevice, some systems reverse + * the setting in the bois, seems to be version and arch dependent? + * Fix the error, exchange the two values + */ + if ((subdevice = pdev->subsystem_device) == PCI_VENDOR_ID_LMC) + subdevice = pdev->subsystem_vendor; + switch (subdevice) { - case PCI_PRODUCT_LMC_HSSI: + case PCI_DEVICE_ID_LMC_HSSI: printk ("%s: LMC HSSI\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_HSSI; sc->lmc_media = &lmc_hssi_media; break; - case PCI_PRODUCT_LMC_DS3: + case PCI_DEVICE_ID_LMC_DS3: printk ("%s: LMC DS3\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_DS3; sc->lmc_media = &lmc_ds3_media; break; - case PCI_PRODUCT_LMC_SSI: + case PCI_DEVICE_ID_LMC_SSI: printk ("%s: LMC SSI\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_SSI; sc->lmc_media = &lmc_ssi_media; break; - case PCI_PRODUCT_LMC_T1: + case PCI_DEVICE_ID_LMC_T1: printk ("%s: LMC T1\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_T1; sc->lmc_media = &lmc_t1_media; @@ -976,13 +967,13 @@ static struct net_device *lmc_probe1 (st AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4; if ((AdapModelNum == LMC_ADAP_T1 - && subdevice == PCI_PRODUCT_LMC_T1) || /* detect LMC1200 */ + && subdevice == PCI_DEVICE_ID_LMC_T1) || /* detect LMC1200 */ (AdapModelNum == LMC_ADAP_SSI - && subdevice == PCI_PRODUCT_LMC_SSI) || /* detect LMC1000 */ + && subdevice == PCI_DEVICE_ID_LMC_SSI) || /* detect LMC1000 */ (AdapModelNum == LMC_ADAP_DS3 - && subdevice == PCI_PRODUCT_LMC_DS3) || /* detect LMC5245 */ + && subdevice == PCI_DEVICE_ID_LMC_DS3) || /* detect LMC5245 */ (AdapModelNum == LMC_ADAP_HSSI - && subdevice == PCI_PRODUCT_LMC_HSSI)) + && subdevice == PCI_DEVICE_ID_LMC_HSSI)) { /* detect LMC5200 */ } @@ -996,10 +987,7 @@ static struct net_device *lmc_probe1 (st */ LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL); - sc->board_idx = board_idx; - - memset (&sc->stats, 0, sizeof (struct lmc_statistics)); - + sc->board_idx = cards_found++; sc->stats.check = STATCHECK; sc->stats.version_size = (DRIVER_VERSION << 16) + sizeof (struct lmc_statistics); @@ -1008,105 +996,40 @@ static struct net_device *lmc_probe1 (st sc->lmc_ok = 0; sc->last_link_status = 0; - lmc_trace(dev, "lmc_probe1 out"); - - return dev; -} - - -/* This is the entry point. This is what is called immediately. */ -/* This goes out and finds the card */ + lmc_trace(dev, "lmc_init_one out"); + return 0; -int lmc_probe_fake(struct net_device *dev) /*fold00*/ -{ - lmc_probe(NULL); - /* Return 1 to unloaded bogus device */ - return 1; + out4: + lmc_proto_detach(sc); + out3: + if (pdev) { + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } + out2: + free_netdev(dev); + out1: + return err; } -int lmc_probe (struct net_device *dev) /*fold00*/ +/* + * Called from pci when removing module. + */ +static void __devexit lmc_remove_one (struct pci_dev *pdev) { - int pci_index = 0; - unsigned long pci_ioaddr; - unsigned int pci_irq_line; - u16 vendor, subvendor, device, subdevice; - u32 foundaddr = 0; - u8 intcf = 0; - struct pci_dev *pdev = NULL; - - /* Loop basically until we don't find anymore. */ - while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { - if (pci_enable_device(pdev)) - break; - - vendor = pdev->vendor; - device = pdev->device; - pci_irq_line = pdev->irq; - pci_ioaddr = pci_resource_start (pdev, 0); - subvendor = pdev->subsystem_vendor; - subdevice = pdev->subsystem_device; - - pci_set_master (pdev); - - /* - * Make sure it's the correct card. CHECK SUBVENDOR ID! - * There are lots of tulip's out there. - * Also check the region of registers we will soon be - * poking, to make sure no one else has reserved them. - * This prevents taking someone else's device. - * - * Check either the subvendor or the subdevice, some systems reverse - * the setting in the bois, seems to be version and arch dependent? - * Fix the two variables - * - */ - if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) && - (vendor == CORRECT_VENDOR_ID) && - (device == CORRECT_DEV_ID) && - ((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){ - struct net_device *cur, *prev = NULL; - - /* Fix the error, exchange the two values */ - if(subdevice == PCI_VENDOR_LMC){ - subdevice = subvendor; - subvendor = PCI_VENDOR_LMC ; - } - - /* Make the call to actually setup this card */ - dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line, - device, subdevice, cards_found); - if (dev == NULL) { - printk ("lmc_probe: lmc_probe1 failed\n"); - goto lmc_probe_next_card; - } - /* insert the device into the chain of lmc devices */ - for (cur = Lmc_root_dev; - cur != NULL; - cur = ((lmc_softc_t *) cur->priv)->next_module) { - prev = cur; - } - - if (prev == NULL) - Lmc_root_dev = dev; - else - ((lmc_softc_t *) prev->priv)->next_module = dev; - - ((lmc_softc_t *) dev->priv)->next_module = NULL; - /* end insert */ - - foundaddr = dev->base_addr; - - cards_found++; - intcf++; - } - lmc_probe_next_card: - pci_index++; + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + lmc_softc_t *sc = dev->priv; + + printk("%s: removing...\n", dev->name); + lmc_proto_detach(sc); + unregister_netdev(dev); + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); } - - if (cards_found < 1) - return -1; - - return foundaddr; } /* After this is called, packets can be sent. @@ -1181,8 +1104,6 @@ static int lmc_open (struct net_device * sc->stats.tx_tbusy0++ ; - MOD_INC_USE_COUNT; - /* * select what interrupts we want to get */ @@ -1352,7 +1273,6 @@ static int lmc_ifdown (struct net_device lmc_trace(dev, "lmc_ifdown out"); - MOD_DEC_USE_COUNT; return 0; } @@ -1850,12 +1770,11 @@ skip_out_of_mem: static struct net_device_stats *lmc_get_stats (struct net_device *dev) /*fold00*/ { - lmc_softc_t *sc; + lmc_softc_t *sc = dev->priv; unsigned long flags; lmc_trace(dev, "lmc_get_stats in"); - sc = dev->priv; spin_lock_irqsave(&sc->lmc_lock, flags); @@ -1868,58 +1787,21 @@ static struct net_device_stats *lmc_get_ return (struct net_device_stats *) &sc->stats; } +static struct pci_driver lmc_driver = { + .name = "lmc", + .id_table = lmc_pci_tbl, + .probe = lmc_init_one, + .remove = __devexit_p(lmc_remove_one), +}; + static int __init init_lmc(void) { - printk ("lmc: module loaded\n"); - - /* Have lmc_probe search for all the cards, and allocate devices */ - if (lmc_probe (NULL) < 0) - return -EIO; - - return 0; + return pci_module_init(&lmc_driver); } static void __exit exit_lmc(void) { - struct net_device *dev, *next; - lmc_softc_t *sc; - - /* we have no pointer to our devices, since they are all dynamically - * allocated. So, here we loop through all the network devices - * looking for ours. When found, dispose of them properly. - */ - - for (dev = Lmc_root_dev; - dev != NULL; - dev = next ) - { - - next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */ - printk ("%s: removing...\n", dev->name); - - /* close the syncppp stuff, and release irq. Close is run on unreg net */ - lmc_close (dev); - sc = dev->priv; - if (sc != NULL) - lmc_proto_detach(sc); - - /* Remove the device from the linked list */ - unregister_netdev (dev); - - /* Let go of the io region */; - release_region (dev->base_addr, LMC_REG_RANGE); - - /* free our allocated structures. */ - kfree (dev->priv); - dev->priv = NULL; - - free_netdev (dev); - dev = NULL; - } - - - Lmc_root_dev = NULL; - printk ("lmc module unloaded\n"); + pci_unregister_driver(&lmc_driver); } module_init(init_lmc); @@ -2326,8 +2208,3 @@ bug_out: } - -int lmc_setup(void) { /*FOLD00*/ - return lmc_probe(NULL); -} - --- linux-2.6.1-rc1/drivers/net/wan/lmc/lmc_var.h 2003-06-14 12:18:09.000000000 -0700 +++ 25/drivers/net/wan/lmc/lmc_var.h 2003-12-30 22:49:20.000000000 -0800 @@ -390,7 +390,7 @@ struct lmc___softc { struct timer_list timer; lmc_ctl_t ictl; u_int32_t TxDescriptControlInit; - struct net_device *next_module; /* Link to the next module */ + int tx_TimeoutInd; /* additional driver state */ int tx_TimeoutDisplay; unsigned int lastlmc_taint_tx; @@ -519,18 +519,7 @@ struct lmc___softc { #define TULIP_CMD_RECEIVEALL 0x40000000L #endif - -/* PCI register values */ -#define CORRECT_VENDOR_ID 0x1011 -#define CORRECT_DEV_ID 9 - -#define PCI_VENDOR_LMC 0x1376 -#define PCI_PRODUCT_LMC_HSSI 0x0003 -#define PCI_PRODUCT_LMC_DS3 0x0004 -#define PCI_PRODUCT_LMC_SSI 0x0005 -#define PCI_PRODUCT_LMC_T1 0x0006 - -/* Adapcter module number */ +/* Adapter module number */ #define LMC_ADAP_HSSI 2 #define LMC_ADAP_DS3 3 #define LMC_ADAP_SSI 4 --- linux-2.6.1-rc1/drivers/net/wan/Makefile 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wan/Makefile 2003-12-30 22:49:20.000000000 -0800 @@ -67,6 +67,7 @@ endif obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o +obj-$(CONFIG_PCI200SYN) += pci200syn.o ifeq ($(CONFIG_WANXL_BUILD_FIRMWARE),y) ifeq ($(ARCH),m68k) --- linux-2.6.1-rc1/drivers/net/wan/pc300_drv.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wan/pc300_drv.c 2003-12-30 22:49:20.000000000 -0800 @@ -3165,7 +3165,6 @@ int cpc_open(struct net_device *dev) return result; } - MOD_INC_USE_COUNT; sprintf(ifr.ifr_name, "%s", dev->name); cpc_opench(d); netif_start_queue(dev); @@ -3201,7 +3200,6 @@ int cpc_close(struct net_device *dev) } #endif - MOD_DEC_USE_COUNT; return 0; } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/net/wan/pci200syn.c 2003-12-30 22:49:20.000000000 -0800 @@ -0,0 +1,475 @@ +/* + * Goramo PCI200SYN synchronous serial card driver for Linux + * + * Copyright (C) 2002-2003 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * For information see http://hq.pm.waw.pl/hdlc/ + * + * Sources of information: + * Hitachi HD64572 SCA-II User's Manual + * PLX Technology Inc. PCI9052 Data Book + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd64572.h" + +static const char* version = "Goramo PCI200SYN driver version: 1.16"; +static const char* devname = "PCI200SYN"; + +#undef DEBUG_PKT +#define DEBUG_RINGS + +#define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */ +#define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */ +#define ALL_PAGES_ALWAYS_MAPPED +#define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR +#define MAX_TX_BUFFERS 10 + +static int pci_clock_freq = 33000000; +#define CLOCK_BASE pci_clock_freq + +#define PCI_VENDOR_ID_GORAMO 0x10B5 /* uses PLX:9050 ID - this card */ +#define PCI_DEVICE_ID_PCI200SYN 0x9050 /* doesn't have its own ID */ + + +/* + * PLX PCI9052 local configuration and shared runtime registers. + * This structure can be used to access 9052 registers (memory mapped). + */ +typedef struct { + u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ + u32 loc_rom_range; /* 10h : Local ROM Range */ + u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ + u32 loc_rom_base; /* 24h : Local ROM Base */ + u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ + u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ + u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ + u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ + u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */ +}plx9052; + + + +typedef struct port_s { + hdlc_device hdlc; /* HDLC device struct - must be first */ + struct card_s *card; + spinlock_t lock; /* TX lock */ + sync_serial_settings settings; + int rxpart; /* partial frame received, next frame invalid*/ + unsigned short encoding; + unsigned short parity; + u16 rxin; /* rx ring buffer 'in' pointer */ + u16 txin; /* tx ring buffer 'in' and 'last' pointers */ + u16 txlast; + u8 rxs, txs, tmc; /* SCA registers */ + u8 phy_node; /* physical port # - 0 or 1 */ +}port_t; + + + +typedef struct card_s { + u8* rambase; /* buffer memory base (virtual) */ + u8* scabase; /* SCA memory base (virtual) */ + plx9052* plxbase; /* PLX registers memory base (virtual) */ + u16 rx_ring_buffers; /* number of buffers in a ring */ + u16 tx_ring_buffers; + u16 buff_offset; /* offset of first buffer of first channel */ + u8 irq; /* interrupt request level */ + + port_t ports[2]; +}card_t; + + +#define sca_in(reg, card) readb(card->scabase + (reg)) +#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) +#define sca_inw(reg, card) readw(card->scabase + (reg)) +#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) +#define sca_inl(reg, card) readl(card->scabase + (reg)) +#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) + +#define port_to_card(port) (port->card) +#define log_node(port) (port->phy_node) +#define phy_node(port) (port->phy_node) +#define winbase(card) (card->rambase) +#define get_port(card, port) (&card->ports[port]) +#define sca_flush(card) (sca_in(IER0, card)); + +static inline void new_memcpy_toio(char *dest, char *src, int length) +{ + int len; + do { + len = length > 256 ? 256 : length; + memcpy_toio(dest, src, len); + dest += len; + src += len; + length -= len; + readb(dest); + } while (len); +} + +#undef memcpy_toio +#define memcpy_toio new_memcpy_toio + +#include "hd6457x.c" + + +static void pci200_set_iface(port_t *port) +{ + card_t *card = port->card; + u16 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port_to_card(port)); + switch(port->settings.clock_type) { + case CLOCK_INT: + rxs |= CLK_BRG; /* BRG output */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + case CLOCK_TXINT: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + default: /* EXTernal clock */ + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ + break; + } + + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, card); + sca_out(txs, msci + TXS, card); + sca_set_port(port); +} + + + +static int pci200_open(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + port_t *port = hdlc_to_port(hdlc); + + int result = hdlc_open(hdlc); + if (result) + return result; + + sca_open(hdlc); + pci200_set_iface(port); + sca_flush(port_to_card(port)); + return 0; +} + + + +static int pci200_close(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + sca_close(hdlc); + sca_flush(port_to_card(dev_to_port(dev))); + hdlc_close(hdlc); + return 0; +} + + + +static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync; + hdlc_device *hdlc = dev_to_hdlc(dev); + port_t *port = hdlc_to_port(hdlc); + +#ifdef DEBUG_RINGS + if (cmd == SIOCDEVPRIVATE) { + sca_dump_rings(hdlc); + return 0; + } +#endif + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: + ifr->ifr_settings.type = IF_IFACE_V35; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + if (copy_to_user(line, &port->settings, size)) + return -EFAULT; + return 0; + + case IF_IFACE_V35: + case IF_IFACE_SYNC_SERIAL: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + if (new_line.clock_type != CLOCK_EXT && + new_line.clock_type != CLOCK_TXFROMRX && + new_line.clock_type != CLOCK_INT && + new_line.clock_type != CLOCK_TXINT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + memcpy(&port->settings, &new_line, size); /* Update settings */ + pci200_set_iface(port); + sca_flush(port_to_card(port)); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } +} + + + +static void pci200_pci_remove_one(struct pci_dev *pdev) +{ + int i; + card_t *card = pci_get_drvdata(pdev); + + for(i = 0; i < 2; i++) + if (card->ports[i].card) + unregister_hdlc_device(&card->ports[i].hdlc); + + if (card->irq) + free_irq(card->irq, card); + + if (card->rambase) + iounmap(card->rambase); + if (card->scabase) + iounmap(card->scabase); + if (card->plxbase) + iounmap(card->plxbase); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(card); +} + + + +static int __devinit pci200_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + card_t *card; + u8 rev_id; + u32 *p; + int i; + u32 ramsize; + u32 ramphys; /* buffer memory base */ + u32 scaphys; /* SCA memory base */ + u32 plxphys; /* PLX registers memory base */ + +#ifndef MODULE + static int printed_version; + if (!printed_version++) + printk(KERN_INFO "%s\n", version); +#endif + + i = pci_enable_device(pdev); + if (i) + return i; + + i = pci_request_regions(pdev, "PCI200SYN"); + if (i) { + pci_disable_device(pdev); + return i; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "pci200syn: unable to allocate memory\n"); + pci_release_regions(pdev); + pci_disable_device(pdev); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + pci_set_drvdata(pdev, card); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE || + pci_resource_len(pdev, 2) != PCI200SYN_SCA_SIZE || + pci_resource_len(pdev, 3) < 16384) { + printk(KERN_ERR "pci200syn: invalid card EEPROM parameters\n"); + pci200_pci_remove_one(pdev); + return -EFAULT; + } + + plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; + card->plxbase = ioremap(plxphys, PCI200SYN_PLX_SIZE); + + scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; + card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE); + + ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; + card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + + if (card->plxbase == NULL || + card->scabase == NULL || + card->rambase == NULL) { + printk(KERN_ERR "pci200syn: ioremap() failed\n"); + pci200_pci_remove_one(pdev); + } + + /* Reset PLX */ + p = &card->plxbase->init_ctrl; + writel(readl(p) | 0x40000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + writel(readl(p) & ~0x40000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + ramsize = sca_detect_ram(card, card->rambase, + pci_resource_len(pdev, 3)); + + /* number of TX + RX buffers for one port - this is dual port card */ + i = ramsize / (2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); + card->rx_ring_buffers = i - card->tx_ring_buffers; + + card->buff_offset = 2 * sizeof(pkt_desc) * (card->tx_ring_buffers + + card->rx_ring_buffers); + + printk(KERN_INFO "pci200syn: %u KB RAM at 0x%x, IRQ%u, using %u TX +" + " %u RX packets rings\n", ramsize / 1024, ramphys, + pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers); + + if (card->tx_ring_buffers < 1) { + printk(KERN_ERR "pci200syn: RAM test failed\n"); + pci200_pci_remove_one(pdev); + return -EFAULT; + } + + /* Enable interrupts on the PCI bridge */ + p = &card->plxbase->intr_ctrl_stat; + writew(readw(p) | 0x0040, p); + + /* Allocate IRQ */ + if(request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) { + printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n", + pdev->irq); + pci200_pci_remove_one(pdev); + return -EBUSY; + } + card->irq = pdev->irq; + + sca_init(card, 0); + + for(i = 0; i < 2; i++) { + port_t *port = &card->ports[i]; + struct net_device *dev = hdlc_to_dev(&port->hdlc); + port->phy_node = i; + + spin_lock_init(&port->lock); + SET_MODULE_OWNER(dev); + dev->irq = card->irq; + dev->mem_start = ramphys; + dev->mem_end = ramphys + ramsize - 1; + dev->tx_queue_len = 50; + dev->do_ioctl = pci200_ioctl; + dev->open = pci200_open; + dev->stop = pci200_close; + port->hdlc.attach = sca_attach; + port->hdlc.xmit = sca_xmit; + port->settings.clock_type = CLOCK_EXT; + if(register_hdlc_device(&port->hdlc)) { + printk(KERN_ERR "pci200syn: unable to register hdlc " + "device\n"); + pci200_pci_remove_one(pdev); + return -ENOBUFS; + } + port->card = card; + sca_init_sync_port(port); /* Set up SCA memory */ + + printk(KERN_INFO "%s: PCI200SYN node %d\n", + hdlc_to_name(&port->hdlc), port->phy_node); + } + + sca_flush(card); + return 0; +} + + + +static struct pci_device_id pci200_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_GORAMO, PCI_DEVICE_ID_PCI200SYN, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + + +static struct pci_driver pci200_pci_driver = { + name: "PCI200SYN", + id_table: pci200_pci_tbl, + probe: pci200_pci_init_one, + remove: pci200_pci_remove_one, +}; + + +static int __init pci200_init_module(void) +{ +#ifdef MODULE + printk(KERN_INFO "%s\n", version); +#endif + if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { + printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); + return -EINVAL; + } + return pci_module_init(&pci200_pci_driver); +} + + + +static void __exit pci200_cleanup_module(void) +{ + pci_unregister_driver(&pci200_pci_driver); +} + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Goramo PCI200SYN serial port driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(pci, pci200_pci_tbl); +module_param(pci_clock_freq, int, 0444); +MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz"); +module_init(pci200_init_module); +module_exit(pci200_cleanup_module); --- linux-2.6.1-rc1/drivers/net/wan/x25_asy.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/wan/x25_asy.c 2003-12-30 22:49:20.000000000 -0800 @@ -94,7 +94,7 @@ static struct x25_asy *x25_asy_alloc(voi return sl; } else { printk("x25_asy_alloc() - register_netdev() failure.\n"); - kfree(dev); + free_netdev(dev); } } return NULL; --- linux-2.6.1-rc1/drivers/net/wd.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wd.c 2003-12-30 22:49:20.000000000 -0800 @@ -47,7 +47,6 @@ static const char version[] = static unsigned int wd_portlist[] __initdata = {0x300, 0x280, 0x380, 0x240, 0}; -int wd_probe(struct net_device *dev); static int wd_probe1(struct net_device *dev, int ioaddr); static int wd_open(struct net_device *dev); @@ -83,11 +82,14 @@ static int wd_close(struct net_device *d The wd_probe1() routine initializes the card and fills the station address field. */ -int __init wd_probe(struct net_device *dev) +static int __init do_wd_probe(struct net_device *dev) { int i; struct resource *r; int base_addr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; + int mem_end = dev->mem_end; SET_MODULE_OWNER(dev); @@ -115,11 +117,45 @@ int __init wd_probe(struct net_device *d return 0; } release_region(ioaddr, WD_IO_EXTENT); + dev->irq = irq; + dev->mem_start = mem_start; + dev->mem_end = mem_end; } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); +} + +struct net_device * __init wd_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_wd_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init wd_probe1(struct net_device *dev, int ioaddr) { int i; @@ -262,19 +298,11 @@ static int __init wd_probe1(struct net_d } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ dev->irq = 9; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ i = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); if (i) { printk (" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; return i; } @@ -446,7 +474,7 @@ wd_close(struct net_device *dev) #ifdef MODULE #define MAX_WD_CARDS 4 /* Max number of wd cards per module */ -static struct net_device dev_wd[MAX_WD_CARDS]; +static struct net_device *dev_wd[MAX_WD_CARDS]; static int io[MAX_WD_CARDS]; static int irq[MAX_WD_CARDS]; static int mem[MAX_WD_CARDS]; @@ -468,29 +496,35 @@ ISA device autoprobes on a running machi int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = &dev_wd[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = mem_end[this_dev]; - dev->init = wd_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->mem_end = mem_end[this_dev]; + if (do_wd_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_wd[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; - } - return 0; + free_netdev(dev); + printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); + break; + } + if (found) + return 0; + return -ENXIO; } void @@ -499,14 +533,11 @@ cleanup_module(void) int this_dev; for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = &dev_wd[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - int ioaddr = dev->base_addr - WD_NIC_OFFSET; - free_irq(dev->irq, dev); - release_region(ioaddr, WD_IO_EXTENT); + struct net_device *dev = dev_wd[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } --- linux-2.6.1-rc1/drivers/net/wireless/airo.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/net/wireless/airo.c 2003-12-30 22:49:20.000000000 -0800 @@ -1027,7 +1027,6 @@ struct airo_info { #define FLAG_802_11 7 #define FLAG_PENDING_XMIT 9 #define FLAG_PENDING_XMIT11 10 -#define FLAG_PCI 11 #define JOB_MASK 0x1ff0000 #define JOB_DIE 16 #define JOB_XMIT 17 @@ -4623,7 +4622,6 @@ static int __devinit airo_pci_probe(stru return -ENODEV; pci_set_drvdata(pdev, dev); - set_bit (FLAG_PCI, &((struct airo_info *)dev->priv)->flags); return 0; } @@ -4653,7 +4651,7 @@ static int __init airo_init_module( void #ifdef CONFIG_PCI printk( KERN_INFO "airo: Probing for PCI adapters\n" ); - pci_module_init(&airo_driver); + pci_register_driver(&airo_driver); printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); #endif @@ -4665,22 +4663,15 @@ static int __init airo_init_module( void static void __exit airo_cleanup_module( void ) { - int is_pci = 0; while( airo_devices ) { printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); -#ifdef CONFIG_PCI - if (test_bit(FLAG_PCI, &((struct airo_info *)airo_devices->dev->priv)->flags)) - is_pci = 1; -#endif stop_airo_card( airo_devices->dev, 1 ); } remove_proc_entry("aironet", proc_root_driver); - if (is_pci) { #ifdef CONFIG_PCI - pci_unregister_driver(&airo_driver); + pci_unregister_driver(&airo_driver); #endif - } } #ifdef WIRELESS_EXT --- linux-2.6.1-rc1/drivers/net/wireless/airo_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/airo_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -233,7 +233,7 @@ static dev_link_t *airo_attach(void) client_reg.event_handler = &airo_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); airo_detach(link); @@ -277,7 +277,7 @@ static void airo_detach(dev_link_t *link /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); @@ -298,11 +298,8 @@ static void airo_detach(dev_link_t *link ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void airo_config(dev_link_t *link) { @@ -329,9 +326,9 @@ static void airo_config(dev_link_t *link tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -351,12 +348,13 @@ static void airo_config(dev_link_t *link will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto next_entry; @@ -405,7 +403,8 @@ static void airo_config(dev_link_t *link } /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; /* Now set up a common memory window, if needed. There is room @@ -425,16 +424,17 @@ static void airo_config(dev_link_t *link req.Base = mem->win[0].host_addr; req.Size = mem->win[0].len; req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - CFG_CHECK(RequestWindow, &link->win, &req); + if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) + goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - CFG_CHECK(MapMemPage, link->win, &map); + if (pcmcia_map_mem_page(link->win, &map) != 0) + goto next_entry; } /* If we got this far, we're cool! */ break; next_entry: - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } /* @@ -443,14 +443,14 @@ static void airo_config(dev_link_t *link irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); ((local_info_t*)link->priv)->eth_dev = init_airo_card( link->irq.AssignedIRQ, link->io.BasePort1, 1 ); @@ -526,12 +526,12 @@ static void airo_release(dev_link_t *lin /* Don't bother checking to see if these succeed or not */ if (link->win) - CardServices(ReleaseWindow, link->win); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_CONFIG) @@ -576,7 +576,7 @@ static int airo_event(event_t event, int case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { netif_device_detach(local->eth_dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -584,7 +584,7 @@ static int airo_event(event_t event, int /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); reset_airo_card(local->eth_dev); netif_device_attach(local->eth_dev); } --- linux-2.6.1-rc1/drivers/net/wireless/airport.c 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/net/wireless/airport.c 2003-12-30 22:49:20.000000000 -0800 @@ -216,7 +216,7 @@ airport_attach(struct macio_dev *mdev, c if (! request_OF_resource(of_node, 0, " (airport)")) { printk(KERN_ERR "airport: can't request IO resource !\n"); - kfree(dev); + free_netdev(dev); return -ENODEV; } --- linux-2.6.1-rc1/drivers/net/wireless/arlan.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/arlan.h 2003-12-30 22:49:20.000000000 -0800 @@ -57,12 +57,8 @@ extern int arlan_command(struct net_ #define SIDUNKNOWN -1 #define radioNodeIdUNKNOWN -1 -#define encryptionKeyUNKNOWN '\0'; #define irqUNKNOWN 0 -#define memUNKNOWN 0 #define debugUNKNOWN 0 -#define probeUNKNOWN 1 -#define numDevicesUNKNOWN 1 #define testMemoryUNKNOWN 1 #define spreadingCodeUNKNOWN 0 #define channelNumberUNKNOWN 0 @@ -82,6 +78,8 @@ extern int arlan_command(struct net_ #define ARLAN_DEBUG(a,b) #endif +#define ARLAN_SHMEM_SIZE 0x2000 + struct arlan_shmem { /* Header Signature */ --- linux-2.6.1-rc1/drivers/net/wireless/arlan-main.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/net/wireless/arlan-main.c 2003-12-30 22:49:20.000000000 -0800 @@ -19,9 +19,7 @@ struct net_device *arlan_device[MAX_ARLA static int SID = SIDUNKNOWN; static int radioNodeId = radioNodeIdUNKNOWN; static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; -static int mem = memUNKNOWN; int arlan_debug = debugUNKNOWN; -static int numDevices = numDevicesUNKNOWN; static int spreadingCode = spreadingCodeUNKNOWN; static int channelNumber = channelNumberUNKNOWN; static int channelSet = channelSetUNKNOWN; @@ -45,9 +43,7 @@ static int mdebug; MODULE_PARM(irq, "i"); MODULE_PARM(mem, "i"); -MODULE_PARM(probe, "i"); MODULE_PARM(arlan_debug, "i"); -MODULE_PARM(numDevices, "i"); MODULE_PARM(testMemory, "i"); MODULE_PARM(spreadingCode, "i"); MODULE_PARM(channelNumber, "i"); @@ -69,9 +65,7 @@ MODULE_PARM(arlan_entry_and_exit_debug, MODULE_PARM(arlan_EEPROM_bad, "i"); MODULE_PARM_DESC(irq, "(unused)"); MODULE_PARM_DESC(mem, "Arlan memory address for single device probing"); -MODULE_PARM_DESC(probe, "Arlan probe at initialization (0-1)"); MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)"); -MODULE_PARM_DESC(numDevices, "Number of Arlan devices; ignored if >1"); MODULE_PARM_DESC(testMemory, "(unused)"); MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)"); MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions"); @@ -88,7 +82,6 @@ MODULE_PARM_DESC(arlan_entry_and_exit_de struct arlan_conf_stru arlan_conf[MAX_ARLANS]; static int arlans_found; -static int arlan_probe_here(struct net_device *dev, int ioaddr); static int arlan_open(struct net_device *dev); static int arlan_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -975,24 +968,27 @@ static int lastFoundAt = 0xbe000; * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ - -static int __init arlan_check_fingerprint(int memaddr) +#define ARLAN_SHMEM_SIZE 0x2000 +static int __init arlan_check_fingerprint(unsigned long memaddr) { - static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; - char tempBuf[49]; + static const char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; + unsigned long paddr = virt_to_phys((void *) memaddr); + char tempBuf[49]; ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); - if (check_mem_region(virt_to_phys((void *)memaddr),0x2000 )){ - // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",virt_to_phys((void*)memaddr)); + + if (!request_mem_region(paddr, ARLAN_SHMEM_SIZE, "arlan")) { + // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",paddr); return -ENODEV; } + memcpy_fromio(tempBuf, arlan->textRegion, 29); tempBuf[30] = 0; /* check for card at this address */ if (0 != strncmp(tempBuf, probeText, 29)){ -// not release_mem_region(virt_to_phys((void*)memaddr),0x2000); + release_mem_region(paddr, ARLAN_SHMEM_SIZE); return -ENODEV; } @@ -1000,51 +996,8 @@ static int __init arlan_check_fingerprin ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); return 0; - - -} - -static int __init arlan_probe_everywhere(struct net_device *dev) -{ - int m; - int probed = 0; - int found = 0; - - SET_MODULE_OWNER(dev); - - ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); - if (mem != 0 && numDevices == 1) /* Check a single specified location. */ - { - if (arlan_probe_here(dev, (int) phys_to_virt( mem) ) == 0) - return 0; - else - return -ENODEV; - } - for (m = (int)phys_to_virt(lastFoundAt) + 0x2000; m <= (int)phys_to_virt(0xDE000); m += 0x2000) - { - if (arlan_probe_here(dev, m) == 0) - { - found++; - lastFoundAt = (int)virt_to_phys((void*)m); - break; - } - probed++; - } - if (found == 0 && probed != 0) - { - if (lastFoundAt == 0xbe000) - printk(KERN_ERR "arlan: No Arlan devices found \n"); - return -ENODEV; - } - else - return 0; - - ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); - - return -ENODEV; } - static int arlan_change_mtu(struct net_device *dev, int new_mtu) { struct arlan_private *priv = dev->priv; @@ -1085,47 +1038,15 @@ static int arlan_mac_addr(struct net_dev - -static int __init - arlan_allocate_device(int num, struct net_device *devs) +static int __init arlan_setup_device(struct net_device *dev, int num) { + struct arlan_private *ap = dev->priv; + int err; - struct net_device *dev; - struct arlan_private *ap; + ARLAN_DEBUG_ENTRY("arlan_setup_device"); - ARLAN_DEBUG_ENTRY("arlan_allocate_device"); + ap->conf = (struct arlan_shmem *)(ap+1); - if (!devs) { - dev = init_etherdev(0, sizeof(struct arlan_private) + sizeof(struct arlan_shmem)); - if (!dev) { - printk(KERN_ERR "ARLAN: init_etherdev failed\n"); - return 0; - } - ap = dev->priv; - ap->conf = dev->priv + sizeof(struct arlan_private); - ap->init_etherdev_alloc = 1; - } else { - dev = devs; - dev->priv = kmalloc(sizeof(struct arlan_private) + sizeof(struct arlan_shmem), GFP_KERNEL); - if (!dev->priv) { - printk(KERN_ERR "ARLAN: kmalloc of dev->priv failed\n"); - return 0; - } - ap = dev->priv; - ap->conf = dev->priv + sizeof(struct arlan_private); - memset(ap, 0, sizeof(*ap)); - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = 0; - dev->mem_start = 0; - dev->mem_end = 0; - dev->mtu = 1500; - dev->flags = 0; /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */ - dev->irq = 0; - dev->dma = 0; - dev->tx_queue_len = tx_queue_len; - ether_setup(dev); dev->tx_queue_len = tx_queue_len; dev->open = arlan_open; dev->stop = arlan_close; @@ -1138,41 +1059,45 @@ static int __init dev->watchdog_timeo = 3*HZ; ap->irq_test_done = 0; - arlan_device[num] = dev; ap->Conf = &arlan_conf[num]; ap->Conf->pre_Command_Wait = 40; ap->Conf->rx_tweak1 = 30; ap->Conf->rx_tweak2 = 0; - ARLAN_DEBUG_EXIT("arlan_allocate_device"); - return (int) dev; -} + err = register_netdev(dev); + if (err) { + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + return err; + } + arlan_device[num] = dev; + ARLAN_DEBUG_EXIT("arlan_setup_device"); + return 0; +} -static int __init arlan_probe_here(struct net_device *dev, int memaddr) +static int __init arlan_probe_here(struct net_device *dev, + unsigned long memaddr) { - volatile struct arlan_shmem *arlan; + struct arlan_private *ap = dev->priv; ARLAN_DEBUG_ENTRY("arlan_probe_here"); if (arlan_check_fingerprint(memaddr)) return -ENODEV; - printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, (int) virt_to_phys((void*)memaddr)); - - if (!arlan_allocate_device(arlans_found, dev)) - return -1; - - ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr; - arlan = (void *) memaddr; + printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, + (int) virt_to_phys((void*)memaddr)); + ap->card = (void *) memaddr; dev->mem_start = memaddr; - dev->mem_end = memaddr + 0x1FFF; + dev->mem_end = memaddr + ARLAN_SHMEM_SIZE-1; if (dev->irq < 2) { - READSHM(dev->irq, arlan->irqLevel, u_char); + READSHM(dev->irq, ap->card->irqLevel, u_char); } else if (dev->irq == 2) dev->irq = 9; @@ -1183,8 +1108,6 @@ static int __init arlan_probe_here(struc } - - static int arlan_open(struct net_device *dev) { struct arlan_private *priv = dev->priv; @@ -1193,12 +1116,6 @@ static int arlan_open(struct net_device ARLAN_DEBUG_ENTRY("arlan_open"); - if (dev->mem_start == 0) - ret = arlan_probe_everywhere(dev); - if (ret != 0) - return ret; - - arlan = priv->card; ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev); if (ret) { @@ -1768,14 +1685,9 @@ static int arlan_close(struct net_device { struct arlan_private *priv = dev->priv; - if (!priv) - { - printk(KERN_CRIT "arlan: No Device priv \n"); - return 0; - } ARLAN_DEBUG_ENTRY("arlan_close"); - del_timer(&priv->timer); + del_timer_sync(&priv->timer); arlan_command(dev, ARLAN_COMMAND_POWERDOWN); @@ -1867,39 +1779,70 @@ static void arlan_set_multicast(struct n } -int __init arlan_probe(struct net_device *dev) +struct net_device * __init arlan_probe(int unit) { - printk("Arlan driver %s\n", arlan_version); + struct net_device *dev; + int err; + int m; - if (arlan_probe_everywhere(dev)) - return -ENODEV; + ARLAN_DEBUG_ENTRY("arlan_probe"); - arlans_found++; - return 0; -} + if (arlans_found == MAX_ARLANS) + return ERR_PTR(-ENODEV); -#ifdef MODULE + /* + * Reserve space for local data and a copy of the shared memory + * that is used by the /proc interface. + */ + dev = alloc_etherdev(sizeof(struct arlan_private) + + sizeof(struct arlan_shmem)); + if (!dev) + return ERR_PTR(-ENOMEM); -static int probe = probeUNKNOWN; + SET_MODULE_OWNER(dev); -static int __init arlan_find_devices(void) -{ - int m; - int found = 0; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + if (dev->mem_start) { + if (arlan_probe_here(dev, dev->mem_start) == 0) + goto found; + goto not_found; + } + + } - ARLAN_DEBUG_ENTRY("arlan_find_devices"); - if (mem != 0 && numDevices == 1) /* Check a single specified location. */ - return 1; - for (m =(int) phys_to_virt(0xc0000); m <=(int) phys_to_virt(0xDE000); m += 0x2000) + + for (m = (int)phys_to_virt(lastFoundAt) + ARLAN_SHMEM_SIZE; + m <= (int)phys_to_virt(0xDE000); + m += ARLAN_SHMEM_SIZE) { - if (arlan_check_fingerprint(m) == 0) - found++; + if (arlan_probe_here(dev, m) == 0) + { + lastFoundAt = (int)virt_to_phys((void*)m); + goto found; + } } - ARLAN_DEBUG_EXIT("arlan_find_devices"); - return found; + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + + not_found: + free_netdev(dev); + return ERR_PTR(-ENODEV); + + found: + err = arlan_setup_device(dev, arlans_found); + if (err) + dev = ERR_PTR(err); + else if (!arlans_found++) + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + + return dev; } +#ifdef MODULE int init_module(void) { int i = 0; @@ -1909,21 +1852,11 @@ int init_module(void) if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) return -EINVAL; - numDevices = arlan_find_devices(); - if (numDevices == 0) - return -ENODEV; - - for (i = 0; i < numDevices && i < MAX_ARLANS; i++) - { - if (!arlan_allocate_device(i, NULL)) - return -ENOMEM; + for (i = 0; i < MAX_ARLANS; i++) { + struct net_device *dev = arlan_probe(i); - if (arlan_device[i] == NULL) - return -ENOMEM; - - if (probe) - arlan_probe_everywhere(arlan_device[i]); -// arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); + if (IS_ERR(dev)) + return PTR_ERR(dev); } init_arlan_proc(); printk(KERN_INFO "Arlan driver %s\n", arlan_version); @@ -1935,7 +1868,7 @@ int init_module(void) void cleanup_module(void) { int i = 0; - struct arlan_private *ap; + struct net_device *dev; ARLAN_DEBUG_ENTRY("cleanup_module"); @@ -1946,22 +1879,18 @@ void cleanup_module(void) for (i = 0; i < MAX_ARLANS; i++) { - if (arlan_device[i]) - { - arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); - -// release_mem_region(virt_to_phys(arlan_device[i]->mem_start), 0x2000 ); - unregister_netdev(arlan_device[i]); - ap = arlan_device[i]->priv; - if (ap->init_etherdev_alloc) { - free_netdev(arlan_device[i]); - arlan_device[i] = NULL; - } else { - kfree(ap); - ap = NULL; - } + dev = arlan_device[i]; + if (dev) { + arlan_command(dev, ARLAN_COMMAND_POWERDOWN ); + + unregister_netdev(dev); + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + arlan_device[i] = NULL; } } + ARLAN_DEBUG_EXIT("cleanup_module"); } --- linux-2.6.1-rc1/drivers/net/wireless/atmel.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/net/wireless/atmel.c 2003-12-30 22:49:20.000000000 -0800 @@ -1443,7 +1443,7 @@ struct net_device *init_atmel_card( unsi err_out_irq: free_irq(dev->irq, dev); err_out_free: - kfree(dev); + free_netdev(dev); return NULL; } --- linux-2.6.1-rc1/drivers/net/wireless/atmel_cs.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/wireless/atmel_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -246,7 +246,7 @@ static dev_link_t *atmel_attach(void) client_reg.event_handler = &atmel_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); atmel_detach(link); @@ -282,7 +282,7 @@ static void atmel_detach(dev_link_t *lin /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; @@ -299,11 +299,8 @@ static void atmel_detach(dev_link_t *lin ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) /* Call-back function to interrogate PCMCIA-specific information about the current existance of the card */ @@ -372,11 +369,11 @@ static void atmel_config(dev_link_t *lin tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_MANFID; - if (CardServices(GetFirstTuple, handle, &tuple) == 0) { + if (pcmcia_get_first_tuple(handle, &tuple) == 0) { int i; cistpl_manfid_t *manfid; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); manfid = &(parse.manfid); for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { if (!card_table[i].ver1 && @@ -389,11 +386,11 @@ static void atmel_config(dev_link_t *lin } tuple.DesiredTuple = CISTPL_VERS_1; - if (!done && (CardServices(GetFirstTuple, handle, &tuple) == 0)) { + if (!done && (pcmcia_get_first_tuple(handle, &tuple) == 0)) { int i, j, k; cistpl_vers_1_t *ver1; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); ver1 = &(parse.version_1); for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { @@ -429,9 +426,9 @@ static void atmel_config(dev_link_t *lin registers. */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -451,12 +448,13 @@ static void atmel_config(dev_link_t *lin will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto next_entry; @@ -505,12 +503,14 @@ static void atmel_config(dev_link_t *lin } /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; + /* If we got this far, we're cool! */ break; next_entry: - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } /* @@ -519,14 +519,14 @@ static void atmel_config(dev_link_t *lin irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); if (link->irq.AssignedIRQ == 0) { printk(KERN_ALERT @@ -602,11 +602,11 @@ static void atmel_release(dev_link_t *li ((local_info_t*)link->priv)->eth_dev = 0; /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } @@ -648,7 +648,7 @@ static int atmel_event(event_t event, in case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { netif_device_detach(local->eth_dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -656,7 +656,7 @@ static int atmel_event(event_t event, in /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); reset_atmel_card(local->eth_dev); netif_device_attach(local->eth_dev); } --- linux-2.6.1-rc1/drivers/net/wireless/netwave_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/netwave_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -513,7 +513,7 @@ static dev_link_t *netwave_attach(void) client_reg.event_handler = &netwave_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); netwave_detach(link); @@ -555,7 +555,7 @@ static void netwave_detach(dev_link_t *l /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) @@ -998,8 +998,8 @@ static int netwave_ioctl(struct net_devi * */ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void netwave_pcmcia_config(dev_link_t *link) { client_handle_t handle = link->handle; @@ -1024,9 +1024,9 @@ static void netwave_pcmcia_config(dev_li tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -1040,7 +1040,7 @@ static void netwave_pcmcia_config(dev_li */ for (i = j = 0x0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { @@ -1052,13 +1052,13 @@ static void netwave_pcmcia_config(dev_li * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); /* * Allocate a 32K memory window. Note that the dev_link_t @@ -1071,10 +1071,9 @@ static void netwave_pcmcia_config(dev_li req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = mem_speed; - link->win = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &link->win, &req); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); mem.CardOffset = 0x20000; mem.Page = 0; - CS_CHECK(MapMemPage, link->win, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); /* Store base address of the common window frame */ ramBase = ioremap(req.Base, 0x8000); @@ -1145,11 +1144,11 @@ static void netwave_release(dev_link_t * /* Don't bother checking to see if these succeed or not */ if (link->win) { iounmap(priv->ramBase); - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); } - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; @@ -1201,7 +1200,7 @@ static int netwave_event(event_t event, if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -1209,7 +1208,7 @@ static int netwave_event(event_t event, /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { netwave_reset(dev); netif_device_attach(dev); --- linux-2.6.1-rc1/drivers/net/wireless/orinoco_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/orinoco_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -131,7 +131,7 @@ orinoco_cs_hard_reset(struct orinoco_pri /* We need atomic ops here, because we're not holding the lock */ set_bit(0, &card->hard_reset_in_progress); - err = CardServices(ResetCard, link->handle, NULL); + err = pcmcia_reset_card(link->handle, NULL); if (err) return err; @@ -150,7 +150,7 @@ static void orinoco_cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); + pcmcia_report_error(handle, &err); } /* @@ -214,7 +214,7 @@ orinoco_cs_attach(void) client_reg.Version = 0x0210; /* FIXME: what does this mean? */ client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { orinoco_cs_error(link->handle, RegisterClient, ret); orinoco_cs_detach(link); @@ -250,7 +250,7 @@ orinoco_cs_detach(dev_link_t * link) /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, and free it */ *linkp = link->next; @@ -269,11 +269,8 @@ orinoco_cs_detach(dev_link_t * link) * device available to the system. */ -#define CS_CHECK(fn, args...) \ - while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ - if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void orinoco_cs_config(dev_link_t *link) @@ -290,7 +287,7 @@ orinoco_cs_config(dev_link_t *link) tuple_t tuple; cisparse_t parse; - CS_CHECK(ValidateCIS, handle, &info); + CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info)); /* * This reads the card's CONFIG tuple to find its @@ -301,9 +298,9 @@ orinoco_cs_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -311,7 +308,7 @@ orinoco_cs_config(dev_link_t *link) link->state |= DEV_CONFIG; /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* @@ -329,13 +326,14 @@ orinoco_cs_config(dev_link_t *link) * implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_cftable_entry_t dflt = { .index = 0 }; - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; @@ -400,7 +398,8 @@ orinoco_cs_config(dev_link_t *link) } /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; } @@ -410,8 +409,8 @@ orinoco_cs_config(dev_link_t *link) next_entry: if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - last_ret = CardServices(GetNextTuple, handle, &tuple); + pcmcia_release_io(link->handle, &link->io); + last_ret = pcmcia_get_next_tuple(handle, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { printk(KERN_ERR "GetNextTuple(). No matching CIS configuration, " "maybe you need the ignore_cis_vcc=1 parameter.\n"); @@ -438,7 +437,7 @@ orinoco_cs_config(dev_link_t *link) link->irq.Handler = orinoco_interrupt; link->irq.Instance = dev; - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); } /* We initialize the hermes structure before completing PCMCIA @@ -452,7 +451,7 @@ orinoco_cs_config(dev_link_t *link) * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; @@ -521,11 +520,11 @@ orinoco_cs_release(dev_link_t *link) spin_unlock_irqrestore(&priv->lock, flags); /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } /* orinoco_cs_release */ @@ -587,7 +586,7 @@ orinoco_cs_event(event_t event, int prio spin_unlock_irqrestore(&priv->lock, flags); } - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; @@ -598,8 +597,7 @@ orinoco_cs_event(event_t event, int prio if (link->state & DEV_CONFIG) { /* FIXME: should we double check that this is * the same card as we had before */ - CardServices(RequestConfiguration, link->handle, - &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (! test_bit(0, &card->hard_reset_in_progress)) { err = orinoco_reinit_firmware(dev); --- linux-2.6.1-rc1/drivers/net/wireless/orinoco_pci.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/wireless/orinoco_pci.c 2003-12-30 22:49:20.000000000 -0800 @@ -261,7 +261,7 @@ static int orinoco_pci_init_one(struct p if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pci_ioaddr) @@ -360,6 +360,7 @@ static int orinoco_pci_resume(struct pci } static struct pci_device_id orinoco_pci_pci_id_table[] = { + {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; --- linux-2.6.1-rc1/drivers/net/wireless/orinoco_plx.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/wireless/orinoco_plx.c 2003-12-30 22:49:20.000000000 -0800 @@ -263,7 +263,7 @@ static int orinoco_plx_init_one(struct p if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) --- linux-2.6.1-rc1/drivers/net/wireless/orinoco_tmd.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/wireless/orinoco_tmd.c 2003-12-30 22:49:20.000000000 -0800 @@ -157,7 +157,7 @@ static int orinoco_tmd_init_one(struct p if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) --- linux-2.6.1-rc1/drivers/net/wireless/ray_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/ray_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -344,19 +344,14 @@ static dev_link_t *ray_attach(void) return NULL; /* Allocate space for private device-specific data */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + dev = alloc_etherdev(sizeof(ray_dev_t)); if (!dev) goto fail_alloc_dev; - local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL); - - if (!local) - goto fail_alloc_local; + local = dev->priv; memset(link, 0, sizeof(struct dev_link_t)); - memset(dev, 0, sizeof(struct net_device)); - memset(local, 0, sizeof(ray_dev_t)); /* The io structure describes IO port mapping. None used here */ link->io.NumPorts1 = 0; @@ -379,7 +374,6 @@ static dev_link_t *ray_attach(void) link->priv = dev; link->irq.Instance = dev; - dev->priv = local; local->finder = link; local->card_status = CARD_INSERTED; local->authentication_state = UNAUTHENTICATED; @@ -401,7 +395,6 @@ static dev_link_t *ray_attach(void) DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); SET_MODULE_OWNER(dev); - ether_setup(dev); dev->init = &ray_dev_init; dev->open = &ray_open; dev->stop = &ray_dev_close; @@ -420,7 +413,7 @@ static dev_link_t *ray_attach(void) client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - DEBUG(2,"ray_cs ray_attach calling CardServices(RegisterClient...)\n"); + DEBUG(2,"ray_cs ray_attach calling pcmcia_register_client(...)\n"); init_timer(&local->timer); @@ -434,8 +427,6 @@ static dev_link_t *ray_attach(void) DEBUG(2,"ray_cs ray_attach ending\n"); return link; -fail_alloc_local: - kfree(dev); fail_alloc_dev: kfree(link); return NULL; @@ -478,9 +469,7 @@ static void ray_detach(dev_link_t *link) if (link->priv) { struct net_device *dev = link->priv; if (link->dev) unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); + free_netdev(dev); } kfree(link); DEBUG(2,"ray_cs ray_detach ending\n"); @@ -490,8 +479,8 @@ static void ray_detach(dev_link_t *link) is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. =============================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=fn(args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) #define MAX_TUPLE_SIZE 128 static void ray_config(dev_link_t *link) { @@ -510,23 +499,23 @@ static void ray_config(dev_link_t *link) /* This reads the card's CONFIG tuple to find its configuration regs */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(pcmcia_get_first_tuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 0; - CS_CHECK(pcmcia_get_tuple_data, handle, &tuple); - CS_CHECK(pcmcia_parse_tuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Determine card type and firmware version */ buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(pcmcia_get_first_tuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 2; - CS_CHECK(pcmcia_get_tuple_data, handle, &tuple); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); for (i=0; ihandle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); dev->irq = link->irq.AssignedIRQ; /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping. */ - CS_CHECK(pcmcia_request_configuration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); /*** Set up 32k window for shared memory (transmit and control) ************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(pcmcia_request_window, &link->handle, &req, &link->win); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); mem.CardOffset = 0x0000; mem.Page = 0; - CS_CHECK(pcmcia_map_mem_page, link->win, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); local->sram = (UCHAR *)(ioremap(req.Base,req.Size)); /*** Set up 16k window for shared memory (receive buffer) ***************/ @@ -561,9 +550,9 @@ static void ray_config(dev_link_t *link) req.Base = 0; req.Size = 0x4000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(pcmcia_request_window, &link->handle, &req, &local->rmem_handle); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle)); mem.CardOffset = 0x8000; mem.Page = 0; - CS_CHECK(pcmcia_map_mem_page, local->rmem_handle, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); local->rmem = (UCHAR *)(ioremap(req.Base,req.Size)); /*** Set up window for attribute memory ***********************************/ @@ -571,9 +560,9 @@ static void ray_config(dev_link_t *link) req.Base = 0; req.Size = 0x1000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(pcmcia_request_window, &link->handle, &req, &local->amem_handle); + CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle)); mem.CardOffset = 0x0000; mem.Page = 0; - CS_CHECK(pcmcia_map_mem_page, local->amem_handle, &mem); + CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); local->amem = (UCHAR *)(ioremap(req.Base,req.Size)); DEBUG(3,"ray_config sram=%p\n",local->sram); --- linux-2.6.1-rc1/drivers/net/wireless/strip.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/strip.c 2003-12-30 22:49:20.000000000 -0800 @@ -2564,7 +2564,7 @@ static void strip_free(struct strip *str strip_info->magic = 0; - kfree(strip_info->dev); + free_netdev(strip_info->dev); } --- linux-2.6.1-rc1/drivers/net/wireless/wavelan.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/wireless/wavelan.c 2003-12-30 22:49:20.000000000 -0800 @@ -153,7 +153,7 @@ static inline void wv_16_on(unsigned lon * Disable interrupts on the WaveLAN hardware. * (called by wv_82586_stop()) */ -static inline void wv_ints_off(device * dev) +static inline void wv_ints_off(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -167,7 +167,7 @@ static inline void wv_ints_off(device * * Enable interrupts on the WaveLAN hardware. * (called by wv_hw_reset()) */ -static inline void wv_ints_on(device * dev) +static inline void wv_ints_on(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -268,7 +268,7 @@ static inline u16 psa_crc(u8 * psa, /* T /* * update the checksum field in the Wavelan's PSA */ -static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr) +static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) { #ifdef SET_PSA_CRC psa_t psa; @@ -547,7 +547,7 @@ static inline void obram_write(unsigned /* * Acknowledge the reading of the status issued by the i82586. */ -static void wv_ack(device * dev) +static void wv_ack(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -589,7 +589,7 @@ static void wv_ack(device * dev) * Set channel attention bit and busy wait until command has * completed, then acknowledge completion of the command. */ -static inline int wv_synchronous_cmd(device * dev, const char *str) +static inline int wv_synchronous_cmd(struct net_device * dev, const char *str) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -636,7 +636,7 @@ static inline int wv_synchronous_cmd(dev * Check if done, and if OK. */ static inline int -wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) +wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) { unsigned short mcs_addr; unsigned short status; @@ -703,7 +703,7 @@ wv_config_complete(device * dev, unsigne * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */ -static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) +static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) { int nreaped = 0; @@ -845,7 +845,7 @@ if (lp->tx_n_in_use > 0) * wavelan_interrupt is not an option), so you may experience * delays sometimes. */ -static inline void wv_82586_reconfig(device * dev) +static inline void wv_82586_reconfig(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -954,7 +954,7 @@ static void wv_psa_show(psa_t * p) * Print the formatted status of the Modem Management Controller. * This function needs to be completed. */ -static void wv_mmc_show(device * dev) +static void wv_mmc_show(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -1137,7 +1137,7 @@ static void wv_scb_show(unsigned long io /* * Print the formatted status of the i82586's receive unit. */ -static void wv_ru_show(device * dev) +static void wv_ru_show(struct net_device * dev) { /* net_local *lp = (net_local *) dev->priv; */ @@ -1154,7 +1154,7 @@ static void wv_ru_show(device * dev) /* * Display info about one control block of the i82586 memory. */ -static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p) +static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) { unsigned long ioaddr; ac_tx_t actx; @@ -1183,7 +1183,7 @@ static void wv_cu_show_one(device * dev, /* * Print status of the command unit of the i82586. */ -static void wv_cu_show(device * dev) +static void wv_cu_show(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned int i; @@ -1209,7 +1209,7 @@ static void wv_cu_show(device * dev) /* * Print the formatted status of the WaveLAN PCMCIA device driver. */ -static void wv_dev_show(device * dev) +static void wv_dev_show(struct net_device * dev) { printk(KERN_DEBUG "dev:"); printk(" state=%lX,", dev->state); @@ -1223,7 +1223,7 @@ static void wv_dev_show(device * dev) * Print the formatted status of the WaveLAN PCMCIA device driver's * private information. */ -static void wv_local_show(device * dev) +static void wv_local_show(struct net_device * dev) { net_local *lp; @@ -1285,7 +1285,7 @@ static inline void wv_packet_info(u8 * p * This is the information which is displayed by the driver at startup. * There are lots of flags for configuring it to your liking. */ -static inline void wv_init_info(device * dev) +static inline void wv_init_info(struct net_device * dev) { short ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -1395,7 +1395,7 @@ static inline void wv_init_info(device * * card open or closed. * Used when the user read /proc/net/dev */ -static en_stats *wavelan_get_stats(device * dev) +static en_stats *wavelan_get_stats(struct net_device * dev) { #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); @@ -1412,7 +1412,7 @@ static en_stats *wavelan_get_stats(devic * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */ -static void wavelan_set_multicast_list(device * dev) +static void wavelan_set_multicast_list(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; @@ -1485,7 +1485,7 @@ static void wavelan_set_multicast_list(d * (Note : it was a nice way to test the reconfigure stuff...) */ #ifdef SET_MAC_ADDRESS -static int wavelan_set_mac_address(device * dev, void *addr) +static int wavelan_set_mac_address(struct net_device * dev, void *addr) { struct sockaddr *mac = addr; @@ -1724,7 +1724,7 @@ static inline int wv_frequency_list(unsi * address with our list, and if they match, get the statistics. * Sorry, but this function really needs the wireless extensions. */ -static inline void wl_spy_gather(device * dev, +static inline void wl_spy_gather(struct net_device * dev, u8 * mac, /* MAC address */ u8 * stats) /* Statistics to gather */ { @@ -1750,7 +1750,7 @@ static inline void wl_spy_gather(device * With this histogram you may detect if one WaveLAN is really weak, * or you may also calculate the mean and standard deviation of the level. */ -static inline void wl_his_gather(device * dev, u8 * stats) +static inline void wl_his_gather(struct net_device * dev, u8 * stats) { /* Statistics to gather */ net_local *lp = (net_local *) dev->priv; u8 level = stats[0] & MMR_SIGNAL_LVL; @@ -2415,7 +2415,7 @@ static const struct iw_handler_def wavel * Get wireless statistics. * Called by /proc/net/wireless */ -static iw_stats *wavelan_get_wireless_stats(device * dev) +static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -2492,7 +2492,7 @@ static iw_stats *wavelan_get_wireless_st * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, u16 buf_off, int sksize) +wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2587,7 +2587,7 @@ wv_packet_read(device * dev, u16 buf_off * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */ -static inline void wv_receive(device * dev) +static inline void wv_receive(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -2770,7 +2770,7 @@ static inline void wv_receive(device * d * * (called in wavelan_packet_xmit()) */ -static inline int wv_packet_write(device * dev, void *buf, short length) +static inline int wv_packet_write(struct net_device * dev, void *buf, short length) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2901,7 +2901,7 @@ static inline int wv_packet_write(device * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ -static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) +static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -2966,7 +2966,7 @@ static int wavelan_packet_xmit(struct sk * Routine to initialize the Modem Management Controller. * (called by wv_hw_reset()) */ -static inline int wv_mmc_init(device * dev) +static inline int wv_mmc_init(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -3138,7 +3138,7 @@ static inline int wv_mmc_init(device * d * Start the receive unit. * (called by wv_hw_reset()) */ -static inline int wv_ru_start(device * dev) +static inline int wv_ru_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3230,7 +3230,7 @@ static inline int wv_ru_start(device * d * * (called by wv_hw_reset()) */ -static inline int wv_cu_start(device * dev) +static inline int wv_cu_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3331,7 +3331,7 @@ static inline int wv_cu_start(device * d * * (called by wv_hw_reset()) */ -static inline int wv_82586_start(device * dev) +static inline int wv_82586_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3463,7 +3463,7 @@ static inline int wv_82586_start(device * * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) */ -static void wv_82586_config(device * dev) +static void wv_82586_config(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3643,7 +3643,7 @@ static void wv_82586_config(device * dev * WaveLAN controller (i82586). * (called by wavelan_close()) */ -static inline void wv_82586_stop(device * dev) +static inline void wv_82586_stop(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3680,7 +3680,7 @@ static inline void wv_82586_stop(device * 5. Start the LAN controller's receive unit * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) */ -static int wv_hw_reset(device * dev) +static int wv_hw_reset(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3770,7 +3770,7 @@ static int wv_check_ioaddr(unsigned long */ static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - device *dev; + struct net_device *dev; unsigned long ioaddr; net_local *lp; u16 hasr; @@ -3923,7 +3923,7 @@ static irqreturn_t wavelan_interrupt(int * kernel. If the transmission completes, this timer is disabled. If * the timer expires, we are called and we try to unlock the hardware. */ -static void wavelan_watchdog(device * dev) +static void wavelan_watchdog(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; @@ -4003,7 +4003,7 @@ static void wavelan_watchdog(device * de * Configure and start up the WaveLAN PCMCIA adaptor. * Called by NET3 when it "opens" the device. */ -static int wavelan_open(device * dev) +static int wavelan_open(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; unsigned long flags; @@ -4058,7 +4058,7 @@ static int wavelan_open(device * dev) * Shut down the WaveLAN ISA card. * Called by NET3 when it "closes" the device. */ -static int wavelan_close(device * dev) +static int wavelan_close(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -4091,12 +4091,24 @@ static int wavelan_close(device * dev) * device structure * (called by wavelan_probe() and via init_module()). */ -static int __init wavelan_config(device * dev) +static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) { - unsigned long ioaddr = dev->base_addr; u8 irq_mask; int irq; net_local *lp; + mac_addr mac; + int err; + + if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) + return -EADDRINUSE; + + err = wv_check_ioaddr(ioaddr, mac); + if (err) + goto out; + + memcpy(dev->dev_addr, mac, 6); + + dev->base_addr = ioaddr; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", @@ -4136,25 +4148,18 @@ static int __init wavelan_config(device "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", dev->name, irq_mask); #endif - return -EAGAIN; + err = -EAGAIN; + goto out; } dev->irq = irq; - if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) - return -EBUSY; - dev->mem_start = 0x0000; dev->mem_end = 0x0000; dev->if_port = 0; /* Initialize device structures */ - dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); - if (dev->priv == NULL) { - release_region(ioaddr, sizeof(ha_t)); - return -ENOMEM; - } - memset(dev->priv, 0x00, sizeof(net_local)); + memset(dev->priv, 0, sizeof(net_local)); lp = (net_local *) dev->priv; /* Back link to the device structure. */ @@ -4172,12 +4177,6 @@ static int __init wavelan_config(device /* Init spinlock */ spin_lock_init(&lp->spinlock); - /* - * Fill in the fields of the device structure - * with generic Ethernet values. - */ - ether_setup(dev); - SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; @@ -4204,6 +4203,9 @@ static int __init wavelan_config(device printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); #endif return 0; +out: + release_region(ioaddr, sizeof(ha_t)); + return err; } /*------------------------------------------------------------------*/ @@ -4214,19 +4216,13 @@ static int __init wavelan_config(device * We follow the example in drivers/net/ne.c. * (called in "Space.c") */ -int __init wavelan_probe(device * dev) +struct net_device * __init wavelan_probe(int unit) { + struct net_device *dev; short base_addr; - mac_addr mac; /* MAC address (check existence of WaveLAN) */ + int def_irq; int i; - int r; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG - "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", - dev->name, (unsigned int) dev, - (unsigned int) dev->base_addr); -#endif + int r = 0; #ifdef STRUCT_CHECK if (wv_struct_check() != (char *) NULL) { @@ -4237,8 +4233,20 @@ int __init wavelan_probe(device * dev) } #endif /* STRUCT_CHECK */ - /* Check the value of the command line parameter for base address. */ + dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); base_addr = dev->base_addr; + def_irq = dev->irq; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", + dev->name, dev, (unsigned int) dev->base_addr); +#endif /* Don't probe at all. */ if (base_addr < 0) { @@ -4247,16 +4255,9 @@ int __init wavelan_probe(device * dev) "%s: wavelan_probe(): invalid base address\n", dev->name); #endif - return -ENXIO; - } - - /* Check a single specified location. */ - if (base_addr > 0x100) { - /* Check if there is something at this base address */ - if ((r = wv_check_ioaddr(base_addr, mac)) == 0) { - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - r = wavelan_config(dev); - } + r = -ENXIO; + } else if (base_addr > 0x100) { /* Check a single specified location. */ + r = wavelan_config(dev, base_addr); #ifdef DEBUG_CONFIG_INFO if (r != 0) printk(KERN_DEBUG @@ -4267,35 +4268,33 @@ int __init wavelan_probe(device * dev) #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return r; - } - - /* Scan all possible addresses of the WaveLAN hardware. */ - for (i = 0; i < NELS(iobase); i++) { - /* Check whether there is something at this base address. */ - if (wv_check_ioaddr(iobase[i], mac) == 0) { - dev->base_addr = iobase[i]; /* Copy base address. */ - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - if (wavelan_config(dev) == 0) { + } else { /* Scan all possible addresses of the WaveLAN hardware. */ + for (i = 0; i < NELS(iobase); i++) { + dev->irq = def_irq; + if (wavelan_config(dev, iobase[i]) == 0) { #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return 0; + break; } } + if (i == NELS(iobase)) + r = -ENODEV; } - - /* We may have touched base_addr. Another driver may not like it. */ - dev->base_addr = base_addr; - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", - dev->name); -#endif - - return -ENODEV; + if (r) + goto out; + r = register_netdev(dev); + if (r) + goto out1; + return dev; +out1: + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; +out: + free_netdev(dev); + return ERR_PTR(r); } /****************************** MODULE ******************************/ @@ -4311,7 +4310,6 @@ int __init wavelan_probe(device * dev) */ int init_module(void) { - mac_addr mac; /* MAC address (check WaveLAN existence) */ int ret = -EIO; /* Return error if no cards found */ int i; @@ -4337,38 +4335,28 @@ int init_module(void) /* Loop on all possible base addresses. */ i = -1; while ((io[++i] != 0) && (i < NELS(io))) { - /* Check if there is something at this base address. */ - if (wv_check_ioaddr(io[i], mac) == 0) { - device *dev; - - /* Create device and set basic arguments. */ - dev = - kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == NULL) { - ret = -ENOMEM; - break; - } - memset(dev, 0x00, sizeof(struct net_device)); - memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->init = &wavelan_config; - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + struct net_device *dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + break; + memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ + dev->base_addr = io[i]; + dev->irq = irq[i]; - /* Try to create the device. */ + /* Check if there is something at this base address. */ + if (wavelan_config(dev, io[i]) == 0) { if (register_netdev(dev) != 0) { - /* Deallocate everything. */ - /* Note: if dev->priv is mallocated, there is no way to fail. */ - kfree(dev); + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; } else { - /* If at least one device OK, we do not fail */ ret = 0; + continue; } - } /* if there is something at the address */ - } /* Loop on all addresses. */ + } + free_netdev(dev); + } #ifdef DEBUG_CONFIG_ERROR - if (wavelan_list == (net_local *) NULL) + if (!wavelan_list) printk(KERN_WARNING "WaveLAN init_module(): no device found\n"); #endif @@ -4390,26 +4378,19 @@ void cleanup_module(void) #endif /* Loop on all devices and release them. */ - while (wavelan_list != (net_local *) NULL) { - device *dev = wavelan_list->dev; + while (wavelan_list) { + struct net_device *dev = wavelan_list->dev; #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n", dev->name, (unsigned int) dev); #endif - - /* Release the ioport region. */ - release_region(dev->base_addr, sizeof(ha_t)); - - /* Definitely remove the device. */ unregister_netdev(dev); - /* Unlink the device. */ + release_region(dev->base_addr, sizeof(ha_t)); wavelan_list = wavelan_list->next; - /* Free pieces. */ - kfree(dev->priv); free_netdev(dev); } --- linux-2.6.1-rc1/drivers/net/wireless/wavelan_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/wavelan_cs.c 2003-12-30 22:50:03.000000000 -0800 @@ -131,7 +131,7 @@ hacr_write_slow(u_long base, * Read the Parameter Storage Area from the WaveLAN card's memory */ static void -psa_read(device * dev, +psa_read(struct net_device * dev, int o, /* offset in PSA */ u_char * b, /* buffer to fill */ int n) /* size to read */ @@ -155,7 +155,7 @@ psa_read(device * dev, * Write the Paramter Storage Area to the WaveLAN card's memory */ static void -psa_write(device * dev, +psa_write(struct net_device * dev, int o, /* Offset in psa */ u_char * b, /* Buffer in memory */ int n) /* Length of buffer */ @@ -229,7 +229,7 @@ psa_crc(unsigned char * psa, /* The PSA * update the checksum field in the Wavelan's PSA */ static void -update_psa_checksum(device * dev) +update_psa_checksum(struct net_device * dev) { #ifdef SET_PSA_CRC psa_t psa; @@ -753,7 +753,7 @@ void wv_roam_handover(wavepoint_history } /* Called when a WavePoint beacon is received */ -static inline void wl_roam_gather(device * dev, +static inline void wl_roam_gather(struct net_device * dev, u_char * hdr, /* Beacon header */ u_char * stats) /* SNR, Signal quality of packet */ @@ -831,7 +831,7 @@ static inline int WAVELAN_BEACON(unsigne * wv_82593_config() & wv_diag()) */ static int -wv_82593_cmd(device * dev, +wv_82593_cmd(struct net_device * dev, char * str, int cmd, int result) @@ -942,7 +942,7 @@ wv_82593_cmd(device * dev, * status for the WaveLAN. */ static inline int -wv_diag(device * dev) +wv_diag(struct net_device * dev) { int ret = FALSE; @@ -963,7 +963,7 @@ wv_diag(device * dev) * The return value is the address to use for next the call. */ static int -read_ringbuf(device * dev, +read_ringbuf(struct net_device * dev, int addr, char * buf, int len) @@ -1004,10 +1004,10 @@ read_ringbuf(device * dev, * some delay sometime... */ static inline void -wv_82593_reconfig(device * dev) +wv_82593_reconfig(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; - dev_link_t * link = ((net_local *) dev->priv)->link; + dev_link_t * link = lp->link; unsigned long flags; /* Arm the flag, will be cleard in wv_82593_config() */ @@ -1132,7 +1132,7 @@ wv_psa_show(psa_t * p) * This function need to be completed... */ static void -wv_mmc_show(device * dev) +wv_mmc_show(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *)dev->priv; @@ -1222,7 +1222,7 @@ wv_mmc_show(device * dev) * Print the formatted status of the i82593's receive unit. */ static void -wv_ru_show(device * dev) +wv_ru_show(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; @@ -1241,7 +1241,7 @@ wv_ru_show(device * dev) * Print the formatted status of the WaveLAN PCMCIA device driver. */ static void -wv_dev_show(device * dev) +wv_dev_show(struct net_device * dev) { printk(KERN_DEBUG "dev:"); printk(" state=%lX,", dev->state); @@ -1256,7 +1256,7 @@ wv_dev_show(device * dev) * private information. */ static void -wv_local_show(device * dev) +wv_local_show(struct net_device * dev) { net_local *lp; @@ -1314,7 +1314,7 @@ wv_packet_info(u_char * p, /* Packet t * There is a lot of flag to configure it at your will... */ static inline void -wv_init_info(device * dev) +wv_init_info(struct net_device * dev) { ioaddr_t base = dev->base_addr; psa_t psa; @@ -1412,7 +1412,7 @@ wv_init_info(device * dev) * Used when the user read /proc/net/dev */ static en_stats * -wavelan_get_stats(device * dev) +wavelan_get_stats(struct net_device * dev) { #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); @@ -1431,7 +1431,7 @@ wavelan_get_stats(device * dev) */ static void -wavelan_set_multicast_list(device * dev) +wavelan_set_multicast_list(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; @@ -1529,7 +1529,7 @@ wavelan_set_multicast_list(device * dev) */ #ifdef SET_MAC_ADDRESS static int -wavelan_set_mac_address(device * dev, +wavelan_set_mac_address(struct net_device * dev, void * addr) { struct sockaddr * mac = addr; @@ -1796,7 +1796,7 @@ wv_frequency_list(u_long base, /* i/o po * Sorry, but this function really need wireless extensions... */ static inline void -wl_spy_gather(device * dev, +wl_spy_gather(struct net_device * dev, u_char * mac, /* MAC address */ u_char * stats) /* Statistics to gather */ { @@ -1823,7 +1823,7 @@ wl_spy_gather(device * dev, * or you may also calculate the mean and standard deviation of the level... */ static inline void -wl_his_gather(device * dev, +wl_his_gather(struct net_device * dev, u_char * stats) /* Statistics to gather */ { net_local * lp = (net_local *) dev->priv; @@ -2785,7 +2785,7 @@ wavelan_ioctl(struct net_device * dev, / * Called by /proc/net/wireless... */ static iw_stats * -wavelan_get_wireless_stats(device * dev) +wavelan_get_wireless_stats(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -2847,7 +2847,7 @@ wavelan_get_wireless_stats(device * dev) * (called by wv_packet_rcv()) */ static inline int -wv_start_of_frame(device * dev, +wv_start_of_frame(struct net_device * dev, int rfp, /* end of frame */ int wrap) /* start of buffer */ { @@ -2909,7 +2909,7 @@ wv_start_of_frame(device * dev, * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, +wv_packet_read(struct net_device * dev, int fd_p, int sksize) { @@ -3012,7 +3012,7 @@ wv_packet_read(device * dev, * Note : the spinlock is already grabbed for us and irq are disabled. */ static inline void -wv_packet_rcv(device * dev) +wv_packet_rcv(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3146,7 +3146,7 @@ wv_packet_rcv(device * dev) * (called in wavelan_packet_xmit()) */ static inline void -wv_packet_write(device * dev, +wv_packet_write(struct net_device * dev, void * buf, short length) { @@ -3209,7 +3209,7 @@ wv_packet_write(device * dev, */ static int wavelan_packet_xmit(struct sk_buff * skb, - device * dev) + struct net_device * dev) { net_local * lp = (net_local *)dev->priv; unsigned long flags; @@ -3273,7 +3273,7 @@ wavelan_packet_xmit(struct sk_buff * skb * (called by wv_hw_config()) */ static inline int -wv_mmc_init(device * dev) +wv_mmc_init(struct net_device * dev) { ioaddr_t base = dev->base_addr; psa_t psa; @@ -3467,7 +3467,7 @@ wv_mmc_init(device * dev) * (called in wv_ru_start() and wavelan_close() and wavelan_event()) */ static int -wv_ru_stop(device * dev) +wv_ru_stop(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3530,7 +3530,7 @@ wv_ru_stop(device * dev) * (called in wv_hw_reset() & wavelan_open()) */ static int -wv_ru_start(device * dev) +wv_ru_start(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3618,7 +3618,7 @@ wv_ru_start(device * dev) * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) */ static int -wv_82593_config(device * dev) +wv_82593_config(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3792,7 +3792,7 @@ wv_82593_config(device * dev) * (called by wv_config()) */ static inline int -wv_pcmcia_reset(device * dev) +wv_pcmcia_reset(struct net_device * dev) { int i; conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; @@ -3802,7 +3802,7 @@ wv_pcmcia_reset(device * dev) printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); #endif - i = CardServices(AccessConfigurationRegister, link->handle, ®); + i = pcmcia_access_configuration_register(link->handle, ®); if(i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); @@ -3816,7 +3816,7 @@ wv_pcmcia_reset(device * dev) reg.Action = CS_WRITE; reg.Value = reg.Value | COR_SW_RESET; - i = CardServices(AccessConfigurationRegister, link->handle, ®); + i = pcmcia_access_configuration_register(link->handle, ®); if(i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); @@ -3825,7 +3825,7 @@ wv_pcmcia_reset(device * dev) reg.Action = CS_WRITE; reg.Value = COR_LEVEL_IRQ | COR_CONFIG; - i = CardServices(AccessConfigurationRegister, link->handle, ®); + i = pcmcia_access_configuration_register(link->handle, ®); if(i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); @@ -3854,7 +3854,7 @@ wv_pcmcia_reset(device * dev) * (called by wavelan_event() & wv_hw_reset()) */ static int -wv_hw_config(device * dev) +wv_hw_config(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; @@ -3961,7 +3961,7 @@ wv_hw_config(device * dev) * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) */ static inline void -wv_hw_reset(device * dev) +wv_hw_reset(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; @@ -4004,7 +4004,7 @@ wv_pcmcia_config(dev_link_t * link) memreq_t mem; handle = link->handle; - dev = (device *) link->priv; + dev = (struct net_device *) link->priv; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); @@ -4018,16 +4018,16 @@ wv_pcmcia_config(dev_link_t * link) { tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - i = CardServices(GetFirstTuple, handle, &tuple); + i = pcmcia_get_first_tuple(handle, &tuple); if(i != CS_SUCCESS) break; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = CardServices(GetTupleData, handle, &tuple); + i = pcmcia_get_tuple_data(handle, &tuple); if(i != CS_SUCCESS) break; - i = CardServices(ParseTuple, handle, &tuple, &parse); + i = pcmcia_parse_tuple(handle, &tuple, &parse); if(i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; @@ -4045,7 +4045,7 @@ wv_pcmcia_config(dev_link_t * link) link->state |= DEV_CONFIG; do { - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if(i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); @@ -4056,7 +4056,7 @@ wv_pcmcia_config(dev_link_t * link) * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if(i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); @@ -4068,7 +4068,7 @@ wv_pcmcia_config(dev_link_t * link) * the I/O windows and the interrupt mapping. */ link->conf.ConfigIndex = 1; - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if(i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); @@ -4084,8 +4084,7 @@ wv_pcmcia_config(dev_link_t * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = mem_speed; - link->win = (window_handle_t)link->handle; - i = CardServices(RequestWindow, &link->win, &req); + i = pcmcia_request_window(&link->handle, &req, &link->win); if(i != CS_SUCCESS) { cs_error(link->handle, RequestWindow, i); @@ -4096,7 +4095,7 @@ wv_pcmcia_config(dev_link_t * link) dev->mem_end = dev->mem_start + req.Size; mem.CardOffset = 0; mem.Page = 0; - i = CardServices(MapMemPage, link->win, &mem); + i = pcmcia_map_mem_page(link->win, &mem); if(i != CS_SUCCESS) { cs_error(link->handle, MapMemPage, i); @@ -4150,7 +4149,7 @@ wv_pcmcia_config(dev_link_t * link) static void wv_pcmcia_release(dev_link_t *link) { - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); @@ -4170,10 +4169,10 @@ wv_pcmcia_release(dev_link_t *link) /* Don't bother checking to see if these succeed or not */ iounmap((u_char *)dev->mem_start); - CardServices(ReleaseWindow, link->win); - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; @@ -4200,13 +4199,13 @@ wavelan_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - device * dev; + struct net_device * dev; net_local * lp; ioaddr_t base; int status0; u_int tx_status; - if((dev = (device *)dev_id) == (device *) NULL) + if ((dev = dev_id) == NULL) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", @@ -4467,7 +4466,7 @@ wavelan_interrupt(int irq, * deal with the multiple Tx buffers... */ static void -wavelan_watchdog(device * dev) +wavelan_watchdog(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; @@ -4542,7 +4541,7 @@ wavelan_watchdog(device * dev) * Called by NET3 when it "open" the device. */ static int -wavelan_open(device * dev) +wavelan_open(struct net_device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; net_local * lp = (net_local *)dev->priv; @@ -4597,7 +4596,7 @@ wavelan_open(device * dev) * Called by NET3 when it "close" the device. */ static int -wavelan_close(device * dev) +wavelan_close(struct net_device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; ioaddr_t base = dev->base_addr; @@ -4661,7 +4660,7 @@ wavelan_attach(void) { client_reg_t client_reg; /* Register with cardmgr */ dev_link_t * link; /* Info for cardmgr */ - device * dev; /* Interface generic data */ + struct net_device * dev; /* Interface generic data */ net_local * lp; /* Interface specific data */ int i, ret; @@ -4699,22 +4698,14 @@ wavelan_attach(void) dev_list = link; /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + dev = alloc_etherdev(sizeof(net_local)); if (!dev) { kfree(link); return NULL; } - memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; - /* Allocate the wavelan-specific data structure. */ - dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - if (!lp) { - kfree(link); - kfree(dev); - return NULL; - } - memset(lp, 0x00, sizeof(net_local)); + lp = dev->priv; /* Init specific data */ lp->configured = 0; @@ -4732,9 +4723,6 @@ wavelan_attach(void) lp->link = link; lp->dev = dev; - /* Standard setup for generic data */ - ether_setup(dev); - /* wavelan NET3 callbacks */ SET_MODULE_OWNER(dev); dev->open = &wavelan_open; @@ -4772,10 +4760,10 @@ wavelan_attach(void) client_reg.event_callback_args.client_data = link; #ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n"); + printk(KERN_DEBUG "wavelan_attach(): almost done, calling pcmcia_register_client\n"); #endif - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if(ret != 0) { cs_error(link->handle, RegisterClient, ret); @@ -4826,7 +4814,7 @@ wavelan_detach(dev_link_t * link) /* Break the link with Card Services */ if(link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Remove the interface data from the linked list */ if(dev_list == link) @@ -4852,22 +4840,16 @@ wavelan_detach(dev_link_t * link) /* Free pieces */ if(link->priv) { - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; /* Remove ourselves from the kernel list of ethernet devices */ /* Warning : can't be called from interrupt, timer or wavelan_close() */ - if(link->dev != NULL) + if (link->dev) unregister_netdev(dev); link->dev = NULL; - - if(dev->priv) - { - /* Sound strange, but safe... */ - ((net_local *) dev->priv)->link = (dev_link_t *) NULL; - ((net_local *) dev->priv)->dev = (device *) NULL; - kfree(dev->priv); - } - kfree(link->priv); + ((net_local *) dev->priv)->link = NULL; + ((net_local *) dev->priv)->dev = NULL; + free_netdev(dev); } kfree(link); @@ -4889,7 +4871,7 @@ wavelan_event(event_t event, /* The ev event_callback_args_t * args) { dev_link_t * link = (dev_link_t *) args->client_data; - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "->wavelan_event(): %s\n", @@ -4955,7 +4937,7 @@ wavelan_event(event_t event, /* The ev { if(link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; @@ -4965,7 +4947,7 @@ wavelan_event(event_t event, /* The ev case CS_EVENT_CARD_RESET: if(link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if(link->open) /* If RESET -> True, If RESUME -> False ? */ { wv_hw_reset(dev); --- linux-2.6.1-rc1/drivers/net/wireless/wavelan_cs.p.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/wavelan_cs.p.h 2003-12-30 22:49:20.000000000 -0800 @@ -588,7 +588,6 @@ struct wavepoint_table /****************************** TYPES ******************************/ /* Shortcuts */ -typedef struct net_device device; typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; @@ -611,7 +610,7 @@ typedef u_char mac_addr[WAVELAN_ADDR_SI struct net_local { dev_node_t node; /* ???? What is this stuff ???? */ - device * dev; /* Reverse link... */ + struct net_device * dev; /* Reverse link... */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_link_t * link; /* pcmcia structure */ en_stats stats; /* Ethernet interface statistics */ @@ -673,11 +672,11 @@ static inline void hacr_write_slow(u_long, u_char); static void - psa_read(device *, /* Read the Parameter Storage Area */ + psa_read(struct net_device *, /* Read the Parameter Storage Area */ int, /* offset in PSA */ u_char *, /* buffer to fill */ int), /* size to read */ - psa_write(device *, /* Write to the PSA */ + psa_write(struct net_device *, /* Write to the PSA */ int, /* Offset in psa */ u_char *, /* Buffer in memory */ int); /* Length of buffer */ @@ -707,57 +706,57 @@ static void int); /* number of registers */ /* ---------------------- I82593 SUBROUTINES ----------------------- */ static int - wv_82593_cmd(device *, /* synchronously send a command to i82593 */ + wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ char *, int, int); static inline int - wv_diag(device *); /* Diagnostique the i82593 */ + wv_diag(struct net_device *); /* Diagnostique the i82593 */ static int - read_ringbuf(device *, /* Read a receive buffer */ + read_ringbuf(struct net_device *, /* Read a receive buffer */ int, char *, int); static inline void - wv_82593_reconfig(device *); /* Reconfigure the controller */ + wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ static inline void - wv_init_info(device *); /* display startup info */ + wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * - wavelan_get_stats(device *); /* Give stats /proc/net/dev */ + wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ /* ----------------------- PACKET RECEPTION ----------------------- */ static inline int - wv_start_of_frame(device *, /* Seek beggining of current frame */ + wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ int, /* end of frame */ int); /* start of buffer */ static inline void - wv_packet_read(device *, /* Read a packet from a frame */ + wv_packet_read(struct net_device *, /* Read a packet from a frame */ int, int), - wv_packet_rcv(device *); /* Read all packets waiting */ + wv_packet_rcv(struct net_device *); /* Read all packets waiting */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline void - wv_packet_write(device *, /* Write a packet to the Tx buffer */ + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ void *, short); static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ - device *); + struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *); /* Initialize the modem */ + wv_mmc_init(struct net_device *); /* Initialize the modem */ static int - wv_ru_stop(device *), /* Stop the i82593 receiver unit */ - wv_ru_start(device *); /* Start the i82593 receiver unit */ + wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ + wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ static int - wv_82593_config(device *); /* Configure the i82593 */ + wv_82593_config(struct net_device *); /* Configure the i82593 */ static inline int - wv_pcmcia_reset(device *); /* Reset the pcmcia interface */ + wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ static int - wv_hw_config(device *); /* Reset & configure the whole hardware */ + wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ static inline void - wv_hw_reset(device *); /* Same, + start receiver unit */ + wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ static inline int wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ static void @@ -768,11 +767,11 @@ static irqreturn_t void *, struct pt_regs *); static void - wavelan_watchdog(device *); /* Transmission watchdog */ + wavelan_watchdog(struct net_device *); /* Transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device */ - wavelan_close(device *); /* Close the device */ + wavelan_open(struct net_device *), /* Open the device */ + wavelan_close(struct net_device *); /* Close the device */ static dev_link_t * wavelan_attach(void); /* Create a new device */ static void --- linux-2.6.1-rc1/drivers/net/wireless/wavelan.p.h 2003-06-14 12:18:28.000000000 -0700 +++ 25/drivers/net/wireless/wavelan.p.h 2003-12-30 22:49:20.000000000 -0800 @@ -469,7 +469,6 @@ static const char *version = "wavelan.c /****************************** TYPES ******************************/ /* Shortcuts */ -typedef struct net_device device; typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; @@ -492,7 +491,7 @@ typedef u_char mac_addr[WAVELAN_ADDR_SI struct net_local { net_local * next; /* linked list of the devices */ - device * dev; /* reverse link */ + struct net_device * dev; /* reverse link */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* number of hardware resets */ @@ -542,8 +541,8 @@ static inline void u_short), /* hacr */ wv_16_on(u_long, /* ioaddr */ u_short), /* hacr */ - wv_ints_off(device *), - wv_ints_on(device *); + wv_ints_off(struct net_device *), + wv_ints_on(struct net_device *); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ static void psa_read(u_long, /* Read the Parameter Storage Area. */ @@ -592,57 +591,57 @@ static inline void u_char *, /* b */ int); /* n */ static void - wv_ack(device *); + wv_ack(struct net_device *); static inline int - wv_synchronous_cmd(device *, + wv_synchronous_cmd(struct net_device *, const char *), - wv_config_complete(device *, + wv_config_complete(struct net_device *, u_long, net_local *); static int - wv_complete(device *, + wv_complete(struct net_device *, u_long, net_local *); static inline void - wv_82586_reconfig(device *); + wv_82586_reconfig(struct net_device *); /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ #ifdef DEBUG_I82586_SHOW static void wv_scb_show(unsigned short); #endif static inline void - wv_init_info(device *); /* display startup info */ + wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * - wavelan_get_stats(device *); /* Give stats /proc/net/dev */ + wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ static void - wavelan_set_multicast_list(device *); + wavelan_set_multicast_list(struct net_device *); /* ----------------------- PACKET RECEPTION ----------------------- */ static inline void - wv_packet_read(device *, /* Read a packet from a frame. */ + wv_packet_read(struct net_device *, /* Read a packet from a frame. */ u_short, int), - wv_receive(device *); /* Read all packets waiting. */ + wv_receive(struct net_device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline int - wv_packet_write(device *, /* Write a packet to the Tx buffer. */ + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ void *, short); static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ - device *); + struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *), /* Initialize the modem. */ - wv_ru_start(device *), /* Start the i82586 receiver unit. */ - wv_cu_start(device *), /* Start the i82586 command unit. */ - wv_82586_start(device *); /* Start the i82586. */ + wv_mmc_init(struct net_device *), /* Initialize the modem. */ + wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ + wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ + wv_82586_start(struct net_device *); /* Start the i82586. */ static void - wv_82586_config(device *); /* Configure the i82586. */ + wv_82586_config(struct net_device *); /* Configure the i82586. */ static inline void - wv_82586_stop(device *); + wv_82586_stop(struct net_device *); static int - wv_hw_reset(device *), /* Reset the WaveLAN hardware. */ + wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ wv_check_ioaddr(u_long, /* ioaddr */ u_char *); /* mac address (read) */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ @@ -651,14 +650,13 @@ static irqreturn_t void *, struct pt_regs *); static void - wavelan_watchdog(device *); /* transmission watchdog */ + wavelan_watchdog(struct net_device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device. */ - wavelan_close(device *), /* Close the device. */ - wavelan_config(device *); /* Configure one device. */ -extern int - wavelan_probe(device *); /* See Space.c. */ + wavelan_open(struct net_device *), /* Open the device. */ + wavelan_close(struct net_device *), /* Close the device. */ + wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ +extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ /**************************** VARIABLES ****************************/ --- linux-2.6.1-rc1/drivers/net/wireless/wl3501_cs.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/net/wireless/wl3501_cs.c 2003-12-30 22:50:02.000000000 -0800 @@ -1449,18 +1449,6 @@ fail: goto out; } -/** - * wl3501_init - "initialize" board - * @dev - network device - * - * We never need to do anything when a wl3501 device is "initialized" by the net - * software, because we only register already-found cards. - */ -static int wl3501_init(struct net_device *dev) -{ - return 0; -} - struct net_device_stats *wl3501_get_stats(struct net_device *dev) { struct wl3501_card *this = dev->priv; @@ -1586,7 +1574,7 @@ static void wl3501_detach(dev_link_t *li /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; @@ -2056,7 +2044,6 @@ static dev_link_t *wl3501_attach(void) dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) goto out_link; - dev->init = wl3501_init; dev->open = wl3501_open; dev->stop = wl3501_close; dev->hard_start_xmit = wl3501_hard_start_xmit; @@ -2083,7 +2070,7 @@ static dev_link_t *wl3501_attach(void) client_reg.event_handler = wl3501_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret) { cs_error(link->handle, RegisterClient, ret); wl3501_detach(link); @@ -2097,8 +2084,8 @@ out_link: goto out; } -#define CS_CHECK(fn, args...) \ -while ((last_ret = CardServices(last_fn = (fn), args)) != 0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) /** * wl3501_config - configure the PCMCIA socket and make eth device available @@ -2121,12 +2108,12 @@ static void wl3501_config(dev_link_t *li /* This reads the card's CONFIG tuple to find its config registers. */ tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); tuple.TupleData = bf; tuple.TupleDataMax = sizeof(bf); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -2142,7 +2129,7 @@ static void wl3501_config(dev_link_t *li * 0x200-0x2ff, and so on, because this seems safer */ link->io.BasePort1 = j; link->io.BasePort2 = link->io.BasePort1 + 0x10; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) break; } @@ -2154,12 +2141,12 @@ static void wl3501_config(dev_link_t *li /* Now allocate an interrupt line. Note that this does not actually * assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O * windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -2249,9 +2236,9 @@ static void wl3501_release(dev_link_t *l } /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_CONFIG) @@ -2301,7 +2288,7 @@ static int wl3501_event(event_t event, i if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -2310,8 +2297,7 @@ static int wl3501_event(event_t event, i /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, - &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { wl3501_reset(dev); netif_device_attach(dev); --- linux-2.6.1-rc1/drivers/net/znet.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/znet.c 2003-12-30 22:49:20.000000000 -0800 @@ -372,10 +372,8 @@ static int __init znet_probe (void) struct znet_private *znet; struct net_device *dev; char *p; + int err = -ENOMEM; - if (znet_dev) /* Only look for a single adaptor */ - return -ENODEV; - /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) @@ -387,12 +385,14 @@ static int __init znet_probe (void) return -ENODEV; } - if (!(znet_dev = dev = init_etherdev(0, sizeof(struct znet_private)))) - return -ENOMEM; + dev = alloc_etherdev(sizeof(struct znet_private)); + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER (dev); znet = dev->priv; - SET_MODULE_OWNER (dev); netinfo = (struct netidblk *)p; dev->base_addr = netinfo->iobase1; dev->irq = netinfo->irq1; @@ -430,7 +430,7 @@ static int __init znet_probe (void) znet->io_size = 2; if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) - goto free_netdev; + goto free_dev; if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) goto free_rx; @@ -452,19 +452,19 @@ static int __init znet_probe (void) dev->set_multicast_list = &znet_set_multicast_list; dev->tx_timeout = znet_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - + err = register_netdev(dev); + if (err) + goto free_tx; + znet_dev = dev; return 0; free_tx: - kfree (znet->tx_start); + kfree(znet->tx_start); free_rx: - kfree (znet->rx_start); - free_netdev: - unregister_netdev (dev); - kfree (dev); - znet_dev = NULL; - - return -ENOMEM; + kfree(znet->rx_start); + free_dev: + free_netdev(dev); + return err; } @@ -934,16 +934,14 @@ static void update_stop_hit(short ioaddr static __exit void znet_cleanup (void) { -#ifdef MODULE if (znet_dev) { struct znet_private *znet = znet_dev->priv; + unregister_netdev (znet_dev); kfree (znet->rx_start); kfree (znet->tx_start); - unregister_netdev (znet_dev); free_netdev (znet_dev); } -#endif } module_init (znet_probe); --- linux-2.6.1-rc1/drivers/net/zorro8390.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/net/zorro8390.c 2003-12-30 22:49:20.000000000 -0800 @@ -103,18 +103,18 @@ static int __init zorro8390_probe(void) continue; board = z->resource.start; ioaddr = board+cards[i].offset; - dev = init_etherdev(0, 0); - SET_MODULE_OWNER(dev); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; + SET_MODULE_OWNER(dev); if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) { - kfree(dev); + free_netdev(dev); continue; } if ((err = zorro8390_init(dev, board, cards[i].name, ZTWO_VADDR(ioaddr)))) { release_mem_region(ioaddr, NE_IO_EXTENT*2); - kfree(dev); + free_netdev(dev); return err; } err = 0; @@ -129,6 +129,7 @@ static int __init zorro8390_init(struct const char *name, unsigned long ioaddr) { int i; + int err; unsigned char SA_prom[32]; int start_page, stop_page; static u32 zorro8390_offsets[16] = { @@ -195,12 +196,6 @@ static int __init zorro8390_init(struct i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { #ifdef DEBUG printk(" %2.2x", SA_prom[i]); @@ -232,7 +227,10 @@ static int __init zorro8390_init(struct root_zorro8390_dev = dev; #endif NS8390_init(dev, 0); - return 0; + err = register_netdev(dev); + if (err) + free_irq(IRQ_AMIGA_PORTS, dev); + return err; } static int zorro8390_open(struct net_device *dev) --- linux-2.6.1-rc1/drivers/parport/parport_cs.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/parport/parport_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -151,7 +151,7 @@ static dev_link_t *parport_attach(void) client_reg.event_handler = &parport_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); parport_detach(link); @@ -187,7 +187,7 @@ static void parport_detach(dev_link_t *l parport_cs_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -206,11 +206,8 @@ static void parport_detach(dev_link_t *l ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) void parport_config(dev_link_t *link) { @@ -231,9 +228,9 @@ void parport_config(dev_link_t *link) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -241,14 +238,15 @@ void parport_config(dev_link_t *link) link->state |= DEV_CONFIG; /* Not sure if this is right... look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; @@ -262,18 +260,19 @@ void parport_config(dev_link_t *link) link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; /* If we've got this far, we're done */ break; } next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); release_region(link->io.BasePort1, link->io.NumPorts1); if (link->io.NumPorts2) @@ -335,9 +334,9 @@ void parport_cs_release(dev_link_t *link info->ndev = 0; link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; @@ -372,14 +371,14 @@ int parport_event(event_t event, int pri /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; --- linux-2.6.1-rc1/drivers/pci/pci.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/pci/pci.c 2003-12-30 22:49:48.000000000 -0800 @@ -223,6 +223,8 @@ pci_set_power_state(struct pci_dev *dev, int pm; u16 pmcsr; + might_sleep(); + /* bound the state we're entering */ if (state > 3) state = 3; --- linux-2.6.1-rc1/drivers/pci/pci.ids 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/pci/pci.ids 2003-12-30 22:49:20.000000000 -0800 @@ -3247,8 +3247,6 @@ 1148 5061 SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter 1148 5071 SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter 1148 9521 SK-9521 10/100/1000Base-T Adapter - 4400 SK-9Dxx Gigabit Ethernet Adapter - 4500 SK-9Mxx Gigabit Ethernet Adapter 1149 Win System Corporation 114a VMIC 5579 VMIPCI-5579 (Reflective Memory Card) @@ -3540,7 +3538,22 @@ 11ab Galileo Technology Ltd. 0146 GT-64010/64010A System Controller 4320 Gigabit Ethernet Adapter - 11ab 9521 Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter + 1019 0f38 Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) + 1019 8001 Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) + 1043 173c Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) + 1043 811a Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) + 105b 0c19 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn) + 10b8 b452 SMC EZ Card 1000 (SMC9452TXV.2) + 11ab 0121 Marvell RDK-8001 Adapter + 11ab 0321 Marvell RDK-8003 Adapter + 11ab 1021 Marvell RDK-8010 Adapter + 11ab 5021 Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit) + 11ab 9521 Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit) + 1458 e000 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte) + 147b 1406 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit) + 15d4 0047 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill) + 1695 9025 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox) + 17f2 1c03 Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron) 4611 GT-64115 System Controller 4620 GT-64120/64120A/64121A System Controller 4801 GT-48001 @@ -3803,8 +3816,6 @@ 0802 Rocketport UPCI 8 port w/external I/F 0803 Rocketport UPCI 16 port w/external I/F 0805 Rocketport UPCI 8 port w/octa cable - 080C RocketModem III 8 port - 080D RocketModem III 4 port 0903 Rocketport Compact PCI 16 port w/external I/F 11ff Scion Corporation 1200 CSS Corporation @@ -5312,11 +5323,13 @@ 10b7 2000 3C998-T Dual Port 10/100/1000 PCI-X 10b7 3000 3C999-T Quad Port 10/100/1000 PCI-X 1166 1648 NetXtreme CIOB-E 1000Base-T + 1649 NetXtreme BCM5704S Gigabit Ethernet 164d NetXtreme BCM5702FE Gigabit Ethernet 1653 NetXtreme BCM5705 Gigabit Ethernet 1654 NetXtreme BCM5705 Gigabit Ethernet 165d NetXtreme BCM5705M Gigabit Ethernet 165e NetXtreme BCM5705M Gigabit Ethernet + 166e NetXtreme BCM5705F Gigabit Ethernet 1696 NetXtreme BCM5782 Gigabit Ethernet 14e4 000d NetXtreme BCM5782 1000Base-T 169c NetXtreme BCM5788 Gigabit Ethernet --- linux-2.6.1-rc1/drivers/pci/probe.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/pci/probe.c 2003-12-30 22:49:43.000000000 -0800 @@ -176,7 +176,7 @@ void __devinit pci_read_bridge_bases(str limit |= (io_limit_hi << 16); } - if (base && base <= limit) { + if (base <= limit) { res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; res->start = base; res->end = limit + 0xfff; @@ -187,7 +187,7 @@ void __devinit pci_read_bridge_bases(str pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; - if (base && base <= limit) { + if (base <= limit) { res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; res->start = base; res->end = limit + 0xfffff; @@ -213,7 +213,7 @@ void __devinit pci_read_bridge_bases(str } #endif } - if (base && base <= limit) { + if (base <= limit) { res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; res->start = base; res->end = limit + 0xfffff; --- linux-2.6.1-rc1/drivers/pcmcia/cs.c 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/pcmcia/cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -2289,149 +2289,6 @@ int pcmcia_report_error(client_handle_t return CS_SUCCESS; } /* report_error */ -/*====================================================================*/ - -int CardServices(int func, void *a1, void *a2, void *a3) -{ - -#ifdef PCMCIA_DEBUG - if (pc_debug > 2) { - int i; - for (i = 0; i < SERVICE_COUNT; i++) - if (service_table[i].key == func) break; - if (i < SERVICE_COUNT) - printk(KERN_DEBUG "cs: CardServices(%s, 0x%p, 0x%p)\n", - service_table[i].msg, a1, a2); - else - printk(KERN_DEBUG "cs: CardServices(Unknown func %d, " - "0x%p, 0x%p)\n", func, a1, a2); - } -#endif - switch (func) { - case AccessConfigurationRegister: - return pcmcia_access_configuration_register(a1, a2); break; - case AdjustResourceInfo: - return pcmcia_adjust_resource_info(a1, a2); break; - case CheckEraseQueue: - return pcmcia_check_erase_queue(a1); break; - case CloseMemory: - return pcmcia_close_memory(a1); break; - case CopyMemory: - return pcmcia_copy_memory(a1, a2); break; - case DeregisterClient: - return pcmcia_deregister_client(a1); break; - case DeregisterEraseQueue: - return pcmcia_deregister_erase_queue(a1); break; - case GetFirstClient: - return pcmcia_get_first_client(a1, a2); break; - case GetCardServicesInfo: - return pcmcia_get_card_services_info(a1); break; - case GetConfigurationInfo: - return pcmcia_get_configuration_info(a1, a2); break; - case GetNextClient: - return pcmcia_get_next_client(a1, a2); break; - case GetFirstRegion: - return pcmcia_get_first_region(a1, a2); break; - case GetFirstTuple: - return pcmcia_get_first_tuple(a1, a2); break; - case GetNextRegion: - return pcmcia_get_next_region(a1, a2); break; - case GetNextTuple: - return pcmcia_get_next_tuple(a1, a2); break; - case GetStatus: - return pcmcia_get_status(a1, a2); break; - case GetTupleData: - return pcmcia_get_tuple_data(a1, a2); break; - case MapMemPage: - return pcmcia_map_mem_page(a1, a2); break; - case ModifyConfiguration: - return pcmcia_modify_configuration(a1, a2); break; - case ModifyWindow: - return pcmcia_modify_window(a1, a2); break; - case OpenMemory: -/* return pcmcia_open_memory(a1, a2); */ - { - memory_handle_t m; - int ret = pcmcia_open_memory(a1, a2, &m); - *(memory_handle_t *)a1 = m; - return ret; - } - break; - case ParseTuple: - return pcmcia_parse_tuple(a1, a2, a3); break; - case ReadMemory: - return pcmcia_read_memory(a1, a2, a3); break; - case RegisterClient: - return pcmcia_register_client(a1, a2); break; - case RegisterEraseQueue: - { - eraseq_handle_t w; - int ret = pcmcia_register_erase_queue(a1, a2, &w); - *(eraseq_handle_t *)a1 = w; - return ret; - } - break; -/* return pcmcia_register_erase_queue(a1, a2); break; */ - - return pcmcia_register_mtd(a1, a2); break; - case ReleaseConfiguration: - return pcmcia_release_configuration(a1); break; - case ReleaseIO: - return pcmcia_release_io(a1, a2); break; - case ReleaseIRQ: - return pcmcia_release_irq(a1, a2); break; - case ReleaseWindow: - return pcmcia_release_window(a1); break; - case RequestConfiguration: - return pcmcia_request_configuration(a1, a2); break; - case RequestIO: - return pcmcia_request_io(a1, a2); break; - case RequestIRQ: - return pcmcia_request_irq(a1, a2); break; - case RequestWindow: - { - window_handle_t w; - int ret = pcmcia_request_window(a1, a2, &w); - *(window_handle_t *)a1 = w; - return ret; - } - break; - case ResetCard: - return pcmcia_reset_card(a1, a2); break; - case SetEventMask: - return pcmcia_set_event_mask(a1, a2); break; - case ValidateCIS: - return pcmcia_validate_cis(a1, a2); break; - case WriteMemory: - return pcmcia_write_memory(a1, a2, a3); break; - case BindDevice: - return pcmcia_bind_device(a1); break; - case BindMTD: - return pcmcia_bind_mtd(a1); break; - case ReportError: - return pcmcia_report_error(a1, a2); break; - case SuspendCard: - return pcmcia_suspend_card(a1, a2); break; - case ResumeCard: - return pcmcia_resume_card(a1, a2); break; - case EjectCard: - return pcmcia_eject_card(a1, a2); break; - case InsertCard: - return pcmcia_insert_card(a1, a2); break; - case ReplaceCIS: - return pcmcia_replace_cis(a1, a2); break; - case GetFirstWindow: - return pcmcia_get_first_window(a1, a2); break; - case GetNextWindow: - return pcmcia_get_next_window(a1, a2); break; - case GetMemPage: - return pcmcia_get_mem_page(a1, a2); break; - default: - return CS_UNSUPPORTED_FUNCTION; break; - } - -} /* CardServices */ - /*====================================================================== OS-specific module glue goes here @@ -2489,7 +2346,6 @@ EXPORT_SYMBOL(pcmcia_validate_cis); EXPORT_SYMBOL(pcmcia_write_memory); EXPORT_SYMBOL(dead_socket); -EXPORT_SYMBOL(CardServices); EXPORT_SYMBOL(MTDHelperEntry); EXPORT_SYMBOL(pcmcia_parse_events); --- linux-2.6.1-rc1/drivers/pcmcia/Kconfig 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/pcmcia/Kconfig 2003-12-30 22:50:04.000000000 -0800 @@ -26,6 +26,15 @@ config PCMCIA To compile this driver as modules, choose M here: the modules will be called pcmcia_core and ds. +config PCMCIA_COMPAT + tristate "Compatibility layer for out-of-tree PCMCIA drivers" + depends on PCMCIA && !X86_64 + help + Say Y or M here if you need to use out-of-tree PCMCIA drivers + which still use deprecated interfaces to the PCMCIA core. + + If unsure, choose M here. + config YENTA tristate "CardBus yenta-compatible bridge support" depends on PCMCIA && PCI --- linux-2.6.1-rc1/drivers/pcmcia/Makefile 2003-06-22 12:04:44.000000000 -0700 +++ 25/drivers/pcmcia/Makefile 2003-12-30 22:50:04.000000000 -0800 @@ -38,3 +38,5 @@ sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa sa1100_cs-$(CONFIG_SA1100_STORK) += sa1100_stork.o sa1100_cs-$(CONFIG_SA1100_TRIZEPS) += sa1100_trizeps.o sa1100_cs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o + +obj-$(CONFIG_PCMCIA_COMPAT) += pcmcia_compat.o --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/pcmcia/pcmcia_compat.c 2003-12-30 22:50:04.000000000 -0800 @@ -0,0 +1,163 @@ +/* + * drivers/pcmcia/pcmcia_compat.c - compatibility layer for 2.4. PCMCIA drivers + * + * + * Copyright (C) 2003 Dominik Brodowski + * + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#define IN_CARD_SERVICES +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +/* CardServices -- removed in 2.6.0-mm2 */ + +int __deprecated CardServices(int func, void *a1, void *a2, void *a3) +{ + switch (func) { + case AccessConfigurationRegister: + return pcmcia_access_configuration_register(a1, a2); break; + case AdjustResourceInfo: + return pcmcia_adjust_resource_info(a1, a2); break; + case CheckEraseQueue: + return pcmcia_check_erase_queue(a1); break; + case CloseMemory: + return pcmcia_close_memory(a1); break; + case CopyMemory: + return pcmcia_copy_memory(a1, a2); break; + case DeregisterClient: + return pcmcia_deregister_client(a1); break; + case DeregisterEraseQueue: + return pcmcia_deregister_erase_queue(a1); break; + case GetFirstClient: + return pcmcia_get_first_client(a1, a2); break; + case GetCardServicesInfo: + return pcmcia_get_card_services_info(a1); break; + case GetConfigurationInfo: + return pcmcia_get_configuration_info(a1, a2); break; + case GetNextClient: + return pcmcia_get_next_client(a1, a2); break; + case GetFirstRegion: + return pcmcia_get_first_region(a1, a2); break; + case GetFirstTuple: + return pcmcia_get_first_tuple(a1, a2); break; + case GetNextRegion: + return pcmcia_get_next_region(a1, a2); break; + case GetNextTuple: + return pcmcia_get_next_tuple(a1, a2); break; + case GetStatus: + return pcmcia_get_status(a1, a2); break; + case GetTupleData: + return pcmcia_get_tuple_data(a1, a2); break; + case MapMemPage: + return pcmcia_map_mem_page(a1, a2); break; + case ModifyConfiguration: + return pcmcia_modify_configuration(a1, a2); break; + case ModifyWindow: + return pcmcia_modify_window(a1, a2); break; + case OpenMemory: + { + memory_handle_t m; + int ret = pcmcia_open_memory(a1, a2, &m); + *(memory_handle_t *)a1 = m; + return ret; + } + break; + case ParseTuple: + return pcmcia_parse_tuple(a1, a2, a3); break; + case ReadMemory: + return pcmcia_read_memory(a1, a2, a3); break; + case RegisterClient: + return pcmcia_register_client(a1, a2); break; + case RegisterEraseQueue: + { + eraseq_handle_t w; + int ret = pcmcia_register_erase_queue(a1, a2, &w); + *(eraseq_handle_t *)a1 = w; + return ret; + } + break; + case RegisterMTD: + return pcmcia_register_mtd(a1, a2); break; + case ReleaseConfiguration: + return pcmcia_release_configuration(a1); break; + case ReleaseIO: + return pcmcia_release_io(a1, a2); break; + case ReleaseIRQ: + return pcmcia_release_irq(a1, a2); break; + case ReleaseWindow: + return pcmcia_release_window(a1); break; + case RequestConfiguration: + return pcmcia_request_configuration(a1, a2); break; + case RequestIO: + return pcmcia_request_io(a1, a2); break; + case RequestIRQ: + return pcmcia_request_irq(a1, a2); break; + case RequestWindow: + { + window_handle_t w; + int ret = pcmcia_request_window(a1, a2, &w); + *(window_handle_t *)a1 = w; + return ret; + } + break; + case ResetCard: + return pcmcia_reset_card(a1, a2); break; + case SetEventMask: + return pcmcia_set_event_mask(a1, a2); break; + case ValidateCIS: + return pcmcia_validate_cis(a1, a2); break; + case WriteMemory: + return pcmcia_write_memory(a1, a2, a3); break; + case BindDevice: + return pcmcia_bind_device(a1); break; + case BindMTD: + return pcmcia_bind_mtd(a1); break; + case ReportError: + return pcmcia_report_error(a1, a2); break; + case SuspendCard: + return pcmcia_suspend_card(a1, a2); break; + case ResumeCard: + return pcmcia_resume_card(a1, a2); break; + case EjectCard: + return pcmcia_eject_card(a1, a2); break; + case InsertCard: + return pcmcia_insert_card(a1, a2); break; + case ReplaceCIS: + return pcmcia_replace_cis(a1, a2); break; + case GetFirstWindow: + return pcmcia_get_first_window(a1, a2); break; + case GetNextWindow: + return pcmcia_get_next_window(a1, a2); break; + case GetMemPage: + return pcmcia_get_mem_page(a1, a2); break; + default: + return CS_UNSUPPORTED_FUNCTION; break; + } + +} /* CardServices */ +EXPORT_SYMBOL(CardServices); + + +MODULE_AUTHOR("Dominik Brodowski "); +MODULE_DESCRIPTION("2.4. PCMCIA drivers compatibility layer"); +MODULE_LICENSE("GPL"); --- linux-2.6.1-rc1/drivers/pnp/isapnp/core.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/pnp/isapnp/core.c 2003-12-30 22:49:55.000000000 -0800 @@ -890,11 +890,9 @@ static int __init isapnp_build_device_li header[4], header[5], header[6], header[7], header[8]); printk(KERN_DEBUG "checksum = 0x%x\n", checksum); #endif - /* Don't be strict on the checksum, here ! - e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/ - if (header[8] == 0) - ; - else if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */ + /* Per Section 6.1 of the Plug and Play ISA Specification (Version 1.0a), */ + /* Bit[7] of Vendor ID Byte 0 must be 0 */ + if (header[0] & 0x80) /* not valid CSN */ continue; if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL) continue; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/pnp/isapnp/Kconfig 2003-12-30 22:49:55.000000000 -0800 @@ -0,0 +1,11 @@ +# +# ISA Plug and Play configuration +# +config ISAPNP + bool "ISA Plug and Play support (EXPERIMENTAL)" + depends on PNP && EXPERIMENTAL + help + Say Y here if you would like support for ISA Plug and Play devices. + Some information is in . + + If unsure, say Y. --- linux-2.6.1-rc1/drivers/pnp/Kconfig 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/pnp/Kconfig 2003-12-30 22:49:55.000000000 -0800 @@ -30,33 +30,9 @@ config PNP_DEBUG comment "Protocols" depends on PNP -config ISAPNP - bool "ISA Plug and Play support (EXPERIMENTAL)" - depends on PNP && EXPERIMENTAL - help - Say Y here if you would like support for ISA Plug and Play devices. - Some information is in . +source "drivers/pnp/isapnp/Kconfig" - If unsure, say Y. - -config PNPBIOS - bool "Plug and Play BIOS support (EXPERIMENTAL)" - depends on PNP && EXPERIMENTAL - ---help--- - Linux uses the PNPBIOS as defined in "Plug and Play BIOS - Specification Version 1.0A May 5, 1994" to autodetect built-in - mainboard resources (e.g. parallel port resources). - - Some features (e.g. event notification, docking station information, - ISAPNP services) are not used. - - Note: ACPI is expected to supersede PNPBIOS some day, currently it - co-exists nicely. - - See latest pcmcia-cs (stand-alone package) for a nice "lspnp" tools, - or have a look at /proc/bus/pnp. - - If unsure, say Y. +source "drivers/pnp/pnpbios/Kconfig" endmenu --- linux-2.6.1-rc1/drivers/pnp/pnpbios/bioscalls.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/pnp/pnpbios/bioscalls.c 2003-12-30 22:50:08.000000000 -0800 @@ -493,7 +493,7 @@ static int __pnp_bios_read_escd(char *da if (!pnp_bios_present()) return ESCD_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0, - data, 65536, (void *)nvram_base, 65536); + data, 65536, __va((void *)nvram_base), 65536); return status; } @@ -516,7 +516,7 @@ static int pnp_bios_write_escd(char *dat if (!pnp_bios_present()) return ESCD_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0, - data, 65536, nvram_base, 65536); + data, 65536, __va((void *)nvram_base), 65536); return status; } #endif --- linux-2.6.1-rc1/drivers/pnp/pnpbios/core.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/pnp/pnpbios/core.c 2003-12-30 22:49:55.000000000 -0800 @@ -353,16 +353,8 @@ static void __init build_devlist(void) for(nodenum=0; nodenum<0xff; ) { u8 thisnodenum = nodenum; - /* eventually we will want to use PNPMODE_STATIC here but for now - * dynamic will help us catch buggy bioses to add to the blacklist. - */ - if (!pnpbios_dont_use_current_config) { - if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) - break; - } else { - if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node)) - break; - } + if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node)) + break; nodes_got++; dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL); if (!dev) --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/drivers/pnp/pnpbios/Kconfig 2003-12-30 22:49:55.000000000 -0800 @@ -0,0 +1,41 @@ +# +# Plug and Play BIOS configuration +# +config PNPBIOS + bool "Plug and Play BIOS support (EXPERIMENTAL)" + depends on PNP && EXPERIMENTAL + ---help--- + Linux uses the PNPBIOS as defined in "Plug and Play BIOS + Specification Version 1.0A May 5, 1994" to autodetect built-in + mainboard resources (e.g. parallel port resources). + + Some features (e.g. event notification, docking station information, + ISAPNP services) are not currently implemented. + + If you would like the kernel to detect and allocate resources to + your mainboard devices (on some systems they are disabled by the + BIOS) say Y here. Also the PNPBIOS can help prevent resource + conflicts between mainboard devices and other bus devices. + + Note: ACPI is expected to supersede PNPBIOS some day, currently it + co-exists nicely. If you have a non-ISA system that supports ACPI, + you probably don't need PNPBIOS support. + +config PNPBIOS_PROC_FS + bool "Plug and Play BIOS /proc interface" + depends on PNPBIOS && PROC_FS + ---help--- + If you say Y here and to "/proc file system support", you will be + able to directly access the PNPBIOS. This includes resource + allocation, ESCD, and other PNPBIOS services. Using this + interface is potentially dangerous because the PNPBIOS driver will + not be notified of any resource changes made by writting directly. + Also some buggy systems will fault when accessing certain features + in the PNPBIOS /proc interface (e.g. ESCD). + + See the latest pcmcia-cs (stand-alone package) for a nice set of + PNPBIOS /proc interface tools (lspnp and setpnp). + + Unless you are debugging or have other specific reasons, it is + recommended that you say N here. + --- linux-2.6.1-rc1/drivers/pnp/pnpbios/Makefile 2003-08-08 22:55:12.000000000 -0700 +++ 25/drivers/pnp/pnpbios/Makefile 2003-12-30 22:49:55.000000000 -0800 @@ -2,6 +2,6 @@ # Makefile for the kernel PNPBIOS driver. # -pnpbios-proc-$(CONFIG_PROC_FS) = proc.o +pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y) --- linux-2.6.1-rc1/drivers/pnp/pnpbios/pnpbios.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/pnp/pnpbios/pnpbios.h 2003-12-30 22:49:55.000000000 -0800 @@ -36,7 +36,7 @@ extern void pnpid32_to_pnpid(u32 id, cha extern void pnpbios_print_status(const char * module, u16 status); extern void pnpbios_calls_init(union pnp_bios_install_struct * header); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_PNPBIOS_PROC_FS extern int pnpbios_interface_attach_device(struct pnp_bios_node * node); extern int pnpbios_proc_init (void); extern void pnpbios_proc_exit (void); @@ -44,4 +44,4 @@ extern void pnpbios_proc_exit (void); static inline int pnpbios_interface_attach_device(struct pnp_bios_node * node) { return 0; } static inline int pnpbios_proc_init (void) { return 0; } static inline void pnpbios_proc_exit (void) { ; } -#endif /* CONFIG_PROC */ +#endif /* CONFIG_PNPBIOS_PROC_FS */ --- linux-2.6.1-rc1/drivers/s390/block/dasd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/s390/block/dasd.c 2003-12-30 22:49:33.000000000 -0800 @@ -1643,9 +1643,9 @@ dasd_flush_request_queue(struct dasd_dev } static int -dasd_open(struct inode *inp, struct file *filp) +dasd_open(struct block_device *bdev, struct file *filp) { - struct gendisk *disk = inp->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct dasd_device *device = disk->private_data; int rc; @@ -1676,10 +1676,8 @@ out: return rc; } -static int -dasd_release(struct inode *inp, struct file *filp) +static int dasd_release(struct gendisk *disk) { - struct gendisk *disk = inp->i_bdev->bd_disk; struct dasd_device *device = disk->private_data; if (device->state < DASD_STATE_BASIC) { --- linux-2.6.1-rc1/drivers/s390/block/dasd_int.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/s390/block/dasd_int.h 2003-12-30 22:49:29.000000000 -0800 @@ -493,7 +493,7 @@ int dasd_ioctl_init(void); void dasd_ioctl_exit(void); int dasd_ioctl_no_register(struct module *, int, dasd_ioctl_fn_t); int dasd_ioctl_no_unregister(struct module *, int, dasd_ioctl_fn_t); -int dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int dasd_ioctl(struct block_device *, struct file *, unsigned int, unsigned long); /* externals in dasd_proc.c */ int dasd_proc_init(void); --- linux-2.6.1-rc1/drivers/s390/block/dasd_ioctl.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/s390/block/dasd_ioctl.c 2003-12-30 22:49:29.000000000 -0800 @@ -78,10 +78,9 @@ dasd_ioctl_no_unregister(struct module * } int -dasd_ioctl(struct inode *inp, struct file *filp, +dasd_ioctl(struct block_device *bdev, struct file *filp, unsigned int no, unsigned long data) { - struct block_device *bdev = inp->i_bdev; struct dasd_device *device = bdev->bd_disk->private_data; struct dasd_ioctl *ioctl; const char *dir; --- linux-2.6.1-rc1/drivers/s390/block/xpram.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/s390/block/xpram.c 2003-12-30 22:49:29.000000000 -0800 @@ -328,7 +328,7 @@ fail: return 0; } -static int xpram_ioctl (struct inode *inode, struct file *filp, +static int xpram_ioctl (struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long arg) { struct hd_geometry *geo; --- linux-2.6.1-rc1/drivers/s390/char/tape_block.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/s390/char/tape_block.c 2003-12-30 22:49:33.000000000 -0800 @@ -27,8 +27,8 @@ /* * file operation structure for tape block frontend */ -static int tapeblock_open(struct inode *, struct file *); -static int tapeblock_release(struct inode *, struct file *); +static int tapeblock_open(block_device *, struct file *); +static int tapeblock_release(struct gendisk *); static struct block_device_operations tapeblock_fops = { .owner = THIS_MODULE, @@ -299,9 +299,9 @@ static int tapeblock_mediumdetect(struct * Block frontend tape device open function. */ static int -tapeblock_open(struct inode *inode, struct file *filp) +tapeblock_open(struct block_device *bdev, struct file *filp) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct tape_device *device = disk->private_data; int rc; @@ -336,9 +336,8 @@ tapeblock_open(struct inode *inode, stru * Block frontend tape device release function. */ static int -tapeblock_release(struct inode *inode, struct file *filp) +tapeblock_release(struct gendisk *disk) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct tape_device *device = disk->private_data; tape_release(device); --- linux-2.6.1-rc1/drivers/s390/net/qeth.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/s390/net/qeth.c 2003-12-30 22:49:20.000000000 -0800 @@ -9739,28 +9739,28 @@ static int qeth_get_internal_functions(void) { struct net_device *dev; - - dev = (struct net_device *) kmalloc(sizeof (struct net_device), - GFP_KERNEL); +#ifdef CONFIG_NET_ETHERNET + dev = alloc_etherdev(0); if (!dev) { PRINT_ERR("Not enough memory for internal functions.\n"); return -ENOMEM; } -#ifdef CONFIG_NET_ETHERNET - ether_setup(dev); qeth_my_eth_header = dev->hard_header; qeth_my_eth_rebuild_header = dev->rebuild_header; qeth_my_eth_header_cache = dev->hard_header_cache; qeth_my_eth_header_cache_update = dev->header_cache_update; + free_netdev(dev); #endif #ifdef CONFIG_TR - tr_setup(dev); + dev = alloc_trdev(0); + if (!dev) { + PRINT_ERR("Not enough memory for internal functions.\n"); + return -ENOMEM; + } qeth_my_tr_header = dev->hard_header; qeth_my_tr_rebuild_header = dev->rebuild_header; + free_netdev(dev); #endif - - kfree(dev); - return 0; } --- linux-2.6.1-rc1/drivers/scsi/aic7xxx_old/aic7xxx_proc.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/scsi/aic7xxx_old/aic7xxx_proc.c 2003-12-30 22:49:46.000000000 -0800 @@ -90,9 +90,7 @@ aic7xxx_proc_info ( struct Scsi_Host *HB unsigned char i; unsigned char tindex; - HBAptr = NULL; - - for(p=first_aic7xxx; p->host != HBAptr; p=p->next) + for(p=first_aic7xxx; p && p->host != HBAptr; p=p->next) ; if (!p) --- linux-2.6.1-rc1/drivers/scsi/ide-scsi.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/scsi/ide-scsi.c 2003-12-30 22:49:33.000000000 -0800 @@ -636,24 +636,23 @@ static ide_driver_t idescsi_driver = { .drives = LIST_HEAD_INIT(idescsi_driver.drives), }; -static int idescsi_ide_open(struct inode *inode, struct file *filp) +static int idescsi_ide_open(struct block_device *bdev, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = bdev->bd_disk->private_data; drive->usage++; return 0; } -static int idescsi_ide_release(struct inode *inode, struct file *filp) +static int idescsi_ide_release(struct gendisk *disk) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + ide_drive_t *drive = disk->private_data; drive->usage--; return 0; } -static int idescsi_ide_ioctl(struct inode *inode, struct file *file, +static int idescsi_ide_ioctl(struct block_device *bdev, struct file *file, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; return generic_ide_ioctl(bdev, cmd, arg); } --- linux-2.6.1-rc1/drivers/scsi/Kconfig 2003-12-30 22:37:21.000000000 -0800 +++ 25/drivers/scsi/Kconfig 2003-12-30 22:49:48.000000000 -0800 @@ -55,6 +55,14 @@ config BLK_DEV_SD In this case, do not compile the driver for your SCSI host adapter (below) as a module either. +config MAX_SD_DISKS + int "Maximum number of SCSI disks to support (256-8192)" + depends on BLK_DEV_SD + default "256" + help + The maximum number SCSI disks to support. Default is 256. + Change this value if you want kernel to support lots of SCSI devices. + config CHR_DEV_ST tristate "SCSI tape support" depends on SCSI --- linux-2.6.1-rc1/drivers/scsi/pcmcia/aha152x_stub.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/scsi/pcmcia/aha152x_stub.c 2003-12-30 22:50:04.000000000 -0800 @@ -153,7 +153,7 @@ static dev_link_t *aha152x_attach(void) CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); aha152x_detach(link); @@ -181,7 +181,7 @@ static void aha152x_detach(dev_link_t *l aha152x_release_cs(link); if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; @@ -191,11 +191,8 @@ static void aha152x_detach(dev_link_t *l /*====================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void aha152x_config_cs(dev_link_t *link) { @@ -214,19 +211,20 @@ static void aha152x_config_cs(dev_link_t tuple.TupleData = tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* Configure card */ link->state |= DEV_CONFIG; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; /* For New Media T&J, look for a SCSI window */ if (parse.cftable_entry.io.win[0].len >= 0x20) link->io.BasePort1 = parse.cftable_entry.io.win[0].base; @@ -236,15 +234,15 @@ static void aha152x_config_cs(dev_link_t if ((parse.cftable_entry.io.nwin > 0) && (link->io.BasePort1 < 0xffff)) { link->conf.ConfigIndex = parse.cftable_entry.index; - i = CardServices(RequestIO, handle, &link->io); + i = pcmcia_request_io(handle, &link->io); if (i == CS_SUCCESS) break; } next_entry: - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); @@ -291,9 +289,9 @@ static void aha152x_release_cs(dev_link_ scsi_remove_host(info->host); link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; scsi_unregister(info->host); @@ -322,7 +320,7 @@ static int aha152x_event(event_t event, /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; @@ -330,7 +328,7 @@ static int aha152x_event(event_t event, case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { Scsi_Cmnd tmp; - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); tmp.device->host = info->host; aha152x_host_reset(&tmp); } --- linux-2.6.1-rc1/drivers/scsi/pcmcia/fdomain_stub.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/scsi/pcmcia/fdomain_stub.c 2003-12-30 22:50:04.000000000 -0800 @@ -142,7 +142,7 @@ static dev_link_t *fdomain_attach(void) CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); fdomain_detach(link); @@ -170,7 +170,7 @@ static void fdomain_detach(dev_link_t *l fdomain_release(link); if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; @@ -180,11 +180,8 @@ static void fdomain_detach(dev_link_t *l /*====================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void fdomain_config(dev_link_t *link) { @@ -203,29 +200,30 @@ static void fdomain_config(dev_link_t *l tuple.TupleData = tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* Configure card */ link->state |= DEV_CONFIG; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - i = CardServices(RequestIO, handle, &link->io); + i = pcmcia_request_io(handle, &link->io); if (i == CS_SUCCESS) break; next_entry: - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); @@ -271,9 +269,9 @@ static void fdomain_release(dev_link_t * scsi_remove_host(info->host); link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); scsi_unregister(info->host); @@ -304,14 +302,14 @@ static int fdomain_event(event_t event, /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); fdomain_16x0_bus_reset(NULL); } break; --- linux-2.6.1-rc1/drivers/scsi/pcmcia/nsp_cs.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/scsi/pcmcia/nsp_cs.c 2003-12-30 22:50:04.000000000 -0800 @@ -1681,7 +1681,7 @@ static dev_link_t *nsp_cs_attach(void) client_reg.event_handler = &nsp_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); nsp_cs_detach(link); @@ -1721,7 +1721,7 @@ static void nsp_cs_detach(dev_link_t *li /* Break the link with Card Services */ if (link->handle) { - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); } /* Unlink device structure, free bits */ @@ -1737,10 +1737,8 @@ static void nsp_cs_detach(dev_link_t *li is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) /*====================================================================*/ static void nsp_cs_config(dev_link_t *link) { @@ -1768,9 +1766,9 @@ static void nsp_cs_config(dev_link_t *li tuple.TupleData = tuple_data; tuple.TupleDataMax = sizeof(tuple_data); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -1778,16 +1776,17 @@ static void nsp_cs_config(dev_link_t *li link->state |= DEV_CONFIG; /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } if (cfg->index == 0) { goto next_entry; } @@ -1842,7 +1841,8 @@ static void nsp_cs_config(dev_link_t *li link->io.NumPorts2 = io->win[1].len; } /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; } if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { @@ -1856,10 +1856,11 @@ static void nsp_cs_config(dev_link_t *li req.Size = 0x1000; } req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - CFG_CHECK(RequestWindow, &link->win, &req); + if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) + goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - CFG_CHECK(MapMemPage, link->win, &map); + if (pcmcia_map_mem_page(link->win, &map) != 0) + goto next_entry; data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size); data->MmioLength = req.Size; @@ -1871,15 +1872,15 @@ static void nsp_cs_config(dev_link_t *li nsp_dbg(NSP_DEBUG_INIT, "next"); if (link->io.NumPorts1) { - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); } - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } if (link->conf.Attributes & CONF_ENABLE_IRQ) { - CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); } - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); if (free_ports) { if (link->io.BasePort1) { @@ -2007,7 +2008,6 @@ static void nsp_cs_config(dev_link_t *li return; } /* nsp_cs_config */ #undef CS_CHECK -#undef CFG_CHECK /*====================================================================== @@ -2042,14 +2042,14 @@ static void nsp_cs_release(dev_link_t *l if (data != NULL) { iounmap((void *)(data->MmioAddress)); } - CardServices(ReleaseWindow, link->win); + pcmcia_release_window(link->win); } - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) { - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_io(link->handle, &link->io); } if (link->irq.AssignedIRQ) { - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_irq(link->handle, &link->irq); } link->state &= ~DEV_CONFIG; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) @@ -2119,7 +2119,7 @@ static int nsp_cs_event(event_t info->stop = 1; if (link->state & DEV_CONFIG) { - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; @@ -2130,7 +2130,7 @@ static int nsp_cs_event(event_t case CS_EVENT_CARD_RESET: nsp_dbg(NSP_DEBUG_INIT, "event: reset"); if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); } info->stop = 0; @@ -2177,7 +2177,7 @@ static int __init nsp_cs_init(void) servinfo_t serv; nsp_msg(KERN_INFO, "loading..."); - CardServices(GetCardServicesInfo, &serv); + pcmcia_get_card_services_info(&serv); if (serv.Revision != CS_RELEASE_CODE) { nsp_msg(KERN_DEBUG, "Card Services release does not match!"); return -EINVAL; --- linux-2.6.1-rc1/drivers/scsi/pcmcia/nsp_cs.h 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/scsi/pcmcia/nsp_cs.h 2003-12-30 22:50:04.000000000 -0800 @@ -457,7 +457,7 @@ static inline struct Scsi_Host *scsi_hos static void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); + pcmcia_report_error(handle, &err); } /* scatter-gather table */ --- linux-2.6.1-rc1/drivers/scsi/pcmcia/qlogic_stub.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/scsi/pcmcia/qlogic_stub.c 2003-12-30 22:50:04.000000000 -0800 @@ -140,7 +140,7 @@ static dev_link_t *qlogic_attach(void) client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); qlogic_detach(link); @@ -169,7 +169,7 @@ static void qlogic_detach(dev_link_t * l qlogic_release(link); if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; @@ -179,11 +179,8 @@ static void qlogic_detach(dev_link_t * l /*====================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void qlogic_config(dev_link_t * link) { @@ -201,37 +198,38 @@ static void qlogic_config(dev_link_t * l tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; tuple.DesiredTuple = CISTPL_MANFID; - if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) + if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) info->manf_id = le16_to_cpu(tuple.TupleData[0]); /* Configure card */ link->state |= DEV_CONFIG; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; if (link->io.BasePort1 != 0) { - i = CardServices(RequestIO, handle, &link->io); + i = pcmcia_request_io(handle, &link->io); if (i == CS_SUCCESS) break; } next_entry: - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { /* set ATAcmd */ @@ -284,9 +282,9 @@ static void qlogic_release(dev_link_t *l scsi_remove_host(info->host); link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); scsi_unregister(info->host); @@ -316,7 +314,7 @@ static int qlogic_event(event_t event, i /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; @@ -324,7 +322,7 @@ static int qlogic_event(event_t event, i case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { scsi_info_t *info = link->priv; - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { outb(0x80, link->io.BasePort1 + 0xd); outb(0x24, link->io.BasePort1 + 0x9); --- linux-2.6.1-rc1/drivers/scsi/qla1280.c 2003-12-17 21:20:02.000000000 -0800 +++ 25/drivers/scsi/qla1280.c 2003-12-30 22:49:45.000000000 -0800 @@ -4,6 +4,7 @@ * QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver * Copyright (C) 2000 Qlogic Corporation (www.qlogic.com) * Copyright (C) 2001-2003 Jes Sorensen, Wild Open Source Inc. +* Copyright (C) 2003 Christoph Hellwig * * 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 @@ -16,13 +17,17 @@ * General Public License for more details. * ******************************************************************************/ -#define QLA1280_VERSION "3.23.37.1" +#define QLA1280_VERSION "3.23.38.1" /***************************************************************************** Revision History: Rev 3.23.37.1 December 17, 2003, Jes Sorensen - Delete completion queue from srb if mailbox command failed to to avoid qla1280_done completeting qla1280_error_action's obsolete context + Rev 3.23.38 October 18, 2003, Christoph Hellwig + - Convert to new-style hotplugable driver for 2.6 + - Fix missing scsi_unregister/scsi_host_put on HBA removal + - Kill some of cruft Rev 3.23.37 October 1, 2003, Jes Sorensen - Make MMIO depend on CONFIG_X86_VISWS instead of yet another random CONFIG option @@ -341,9 +346,6 @@ * Compile time Options: * 0 - Disable and 1 - Enable */ -#define QL1280_LUN_SUPPORT 0 -#define WATCHDOGTIMER 0 - #define DEBUG_QLA1280_INTR 0 #define DEBUG_PRINT_NVRAM 0 #define DEBUG_QLA1280 0 @@ -423,6 +425,14 @@ scsi_adjust_queue_depth(Scsi_Device *dev } device->queue_depth = depth; } +static inline struct Scsi_Host *scsi_host_alloc(Scsi_Host_Template *t, size_t s) +{ + return scsi_register(t, s); +} +static inline void scsi_host_put(struct Scsi_Host *h) +{ + scsi_unregister(h); +} #else #define HOST_LOCK ha->host->host_lock #endif @@ -435,30 +445,23 @@ scsi_adjust_queue_depth(Scsi_Device *dev #define ia64_platform_is(foo) (!strcmp(x, platform_name)) #endif +static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *); +static void qla1280_remove_one(struct pci_dev *); + /* * QLogic Driver Support Function Prototypes. */ static void qla1280_done(struct scsi_qla_host *, struct srb **, struct srb **); -static void qla1280_done_q_put(struct srb *, struct srb **, struct srb **); -static int qla1280_slave_configure(Scsi_Device *); #if LINUX_VERSION_CODE < 0x020545 -static void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *); static void qla1280_get_target_options(struct scsi_cmnd *, struct scsi_qla_host *); #endif - -static int qla1280_return_status(struct response * sts, Scsi_Cmnd * cp); -static void qla1280_mem_free(struct scsi_qla_host *ha); static int qla1280_get_token(char *); static int qla1280_setup(char *s) __init; -static inline void qla1280_enable_intrs(struct scsi_qla_host *); -static inline void qla1280_disable_intrs(struct scsi_qla_host *); /* * QLogic ISP1280 Hardware Support Function Prototypes. */ -static int qla1280_initialize_adapter(struct scsi_qla_host *ha); static int qla1280_isp_firmware(struct scsi_qla_host *); -static int qla1280_pci_config(struct scsi_qla_host *); static int qla1280_chip_diag(struct scsi_qla_host *); static int qla1280_setup_chip(struct scsi_qla_host *); static int qla1280_init_rings(struct scsi_qla_host *); @@ -477,7 +480,6 @@ static void qla1280_poll(struct scsi_qla static void qla1280_reset_adapter(struct scsi_qla_host *); static void qla1280_marker(struct scsi_qla_host *, int, int, int, u8); static void qla1280_isp_cmd(struct scsi_qla_host *); -irqreturn_t qla1280_intr_handler(int, void *, struct pt_regs *); static void qla1280_isr(struct scsi_qla_host *, struct srb **, struct srb **); static void qla1280_rst_aen(struct scsi_qla_host *); static void qla1280_status_entry(struct scsi_qla_host *, struct response *, @@ -490,11 +492,9 @@ static uint16_t qla1280_debounce_registe static request_t *qla1280_req_pkt(struct scsi_qla_host *); static int qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *, unsigned int); -static int qla1280_mem_alloc(struct scsi_qla_host *ha); - -static void qla12160_get_target_parameters(struct scsi_qla_host *, +static void qla1280_get_target_parameters(struct scsi_qla_host *, Scsi_Device *); -static int qla12160_set_target_parameters(struct scsi_qla_host *, int, int); +static int qla1280_set_target_parameters(struct scsi_qla_host *, int, int); static struct qla_driver_setup driver_setup __initdata; @@ -529,10 +529,6 @@ qla1280_data_direction(struct scsi_cmnd return flags; } -#if QL1280_LUN_SUPPORT -static void qla1280_enable_lun(struct scsi_qla_host *, int, int); -#endif - #if DEBUG_QLA1280 static void __qla1280_print_scsi_cmd(Scsi_Cmnd * cmd); static void __qla1280_dump_buffer(char *, int); @@ -551,8 +547,6 @@ MODULE_PARM(qla1280, "s"); __setup("qla1280=", qla1280_setup); #endif -MODULE_LICENSE("GPL"); - /* We use the Scsi_Pointer structure that's included with each command * SCSI_Cmnd as a scratchpad for our SRB. @@ -576,28 +570,23 @@ MODULE_LICENSE("GPL"); #define CMD_RESULT(Cmnd) Cmnd->result #define CMD_HANDLE(Cmnd) Cmnd->host_scribble #if LINUX_VERSION_CODE < 0x020545 -#define CMD_HOST(Cmnd) Cmnd->host #define CMD_REQUEST(Cmnd) Cmnd->request.cmd -#define SCSI_BUS_32(Cmnd) Cmnd->channel -#define SCSI_TCN_32(Cmnd) Cmnd->target -#define SCSI_LUN_32(Cmnd) Cmnd->lun #else -#define CMD_HOST(Cmnd) Cmnd->device->host #define CMD_REQUEST(Cmnd) Cmnd->request->cmd +#endif + +#define CMD_HOST(Cmnd) Cmnd->device->host #define SCSI_BUS_32(Cmnd) Cmnd->device->channel #define SCSI_TCN_32(Cmnd) Cmnd->device->id #define SCSI_LUN_32(Cmnd) Cmnd->device->lun -#endif + /*****************************************/ /* ISP Boards supported by this driver */ /*****************************************/ -#define NUM_OF_ISP_DEVICES 6 - struct qla_boards { unsigned char name[9]; /* Board ID String */ - unsigned long device_id; /* Device PCI ID */ int numPorts; /* Number of SCSI ports */ unsigned short *fwcode; /* pointer to FW array */ unsigned short *fwlen; /* number of words in array */ @@ -605,28 +594,38 @@ struct qla_boards { unsigned char *fwver; /* Ptr to F/W version array */ }; -struct qla_boards ql1280_board_tbl[NUM_OF_ISP_DEVICES] = { - /* Name , Board PCI Device ID, Number of ports */ - {"QLA12160", PCI_DEVICE_ID_QLOGIC_ISP12160, 2, - &fw12160i_code01[0], &fw12160i_length01, +/* NOTE: qla1280_pci_tbl and ql1280_board_tbl must be in the same order */ +static struct pci_device_id qla1280_pci_tbl[] = { + {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP12160, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1080, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1240, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1280, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP10160, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl); + +static struct qla_boards ql1280_board_tbl[] = { + /* Name , Number of ports, FW details */ + {"QLA12160", 2, &fw12160i_code01[0], &fw12160i_length01, &fw12160i_addr01, &fw12160i_version_str[0]}, - {"QLA1080", PCI_DEVICE_ID_QLOGIC_ISP1080, 1, - &fw1280ei_code01[0], &fw1280ei_length01, + {"QLA1080", 1, &fw1280ei_code01[0], &fw1280ei_length01, &fw1280ei_addr01, &fw1280ei_version_str[0]}, - {"QLA1240", PCI_DEVICE_ID_QLOGIC_ISP1240, 2, - &fw1280ei_code01[0], &fw1280ei_length01, + {"QLA1240", 2, &fw1280ei_code01[0], &fw1280ei_length01, &fw1280ei_addr01, &fw1280ei_version_str[0]}, - {"QLA1280", PCI_DEVICE_ID_QLOGIC_ISP1280, 2, - &fw1280ei_code01[0], &fw1280ei_length01, + {"QLA1280", 2, &fw1280ei_code01[0], &fw1280ei_length01, &fw1280ei_addr01, &fw1280ei_version_str[0]}, - {"QLA10160", PCI_DEVICE_ID_QLOGIC_ISP10160, 1, - &fw12160i_code01[0], &fw12160i_length01, + {"QLA10160", 1, &fw12160i_code01[0], &fw12160i_length01, &fw12160i_addr01, &fw12160i_version_str[0]}, - {" ", 0, 0} + {" ", 0} }; static int qla1280_verbose = 1; -static struct scsi_qla_host *qla1280_hostlist; static int qla1280_buffer_size; static char *qla1280_buffer; @@ -675,31 +674,19 @@ static int qla1280_proc_info(struct Scsi int size = 0; int len = 0; struct qla_boards *bdp; -#ifdef BOGUS_QUEUE - struct scsi_lu *up; - uint32_t b, t, l; -#endif -#if LINUX_VERSION_CODE >= 0x020600 - ha = (struct scsi_qla_host *)host->hostdata; -#else +#if LINUX_VERSION_CODE < 0x020600 struct Scsi_Host *host; - /* Find the host that was specified */ - for (ha = qla1280_hostlist; (ha != NULL) - && ha->host->host_no != hostno; ha = ha->next) ; - - /* if host wasn't found then exit */ - if (!ha) { - size = sprintf(buffer, "Can't find adapter for host " - "number %d\n", hostno); - if (size > length) { - return size; - } else { - return 0; - } + + for (host = scsi_hostlist; host; host = host->next) { + if (host->host_no == hostno) + goto found; } - host = ha->host; + return -ESRCH; + + found: #endif + ha = (struct scsi_qla_host *)host->hostdata; if (inout) return -ENOSYS; @@ -753,51 +740,6 @@ static int qla1280_proc_info(struct Scsi size = sprintf(PROC_BUF, "\n"); /* 1 */ len += size; - size = sprintf(PROC_BUF, "SCSI device Information:\n"); - len += size; -#ifdef BOGUS_QUEUE - /* scan for all equipment stats */ - for (b = 0; b < MAX_BUSES; b++) - for (t = 0; t < MAX_TARGETS; t++) { - for (l = 0; l < MAX_LUNS; l++) { - up = LU_Q(ha, b, t, l); - if (up == NULL) - continue; - /* unused device/lun */ - if (up->io_cnt == 0 || up->io_cnt < 2) - continue; - /* total reads since boot */ - /* total writes since boot */ - /* total requests since boot */ - size = sprintf (PROC_BUF, - "(%2d:%2d:%2d): Total reqs %ld,", - b, t, l, up->io_cnt); - len += size; - /* current number of pending requests */ - size = sprintf(PROC_BUF, " Pend reqs %d,", - up->q_outcnt); - len += size; -#if 0 - /* avg response time */ - size = sprintf(PROC_BUF, " Avg resp time %ld%%,", - (up->resp_time / up->io_cnt) * - 100); - len += size; - - /* avg active time */ - size = sprintf(PROC_BUF, - " Avg active time %ld%%\n", - (up->act_time / up->io_cnt) * 100); -#else - size = sprintf(PROC_BUF, "\n"); -#endif - len += size; - } - if (len >= qla1280_buffer_size) - break; - } -#endif - if (len >= qla1280_buffer_size) { printk(KERN_WARNING "qla1280: Overflow buffer in qla1280_proc.c\n"); @@ -875,312 +817,6 @@ static int qla1280_read_nvram(struct scs return chksum; } - -/************************************************************************** - * qla1280_do_device_init - * This routine will register the device with the SCSI subsystem, - * initialize the host adapter structure and call the device init - * routines. - * - * Input: - * pdev - pointer to struct pci_dev for adapter - * template - pointer to SCSI template - * devnum - the device number - * bdp - pointer to struct _qlaboards - * num_hosts - the host number - * - * Returns: - * host - pointer to SCSI host structure - **************************************************************************/ -struct Scsi_Host * -qla1280_do_device_init(struct pci_dev *pdev, Scsi_Host_Template * template, - int devnum, struct qla_boards *bdp, int num_hosts) -{ - struct Scsi_Host *host; - struct scsi_qla_host *ha; - - printk(KERN_INFO "qla1280: %s found on PCI bus %i, dev %i\n", - bdp->name, pdev->bus->number, PCI_SLOT(pdev->devfn)); - - host = scsi_register(template, sizeof(struct scsi_qla_host)); - if (!host) { - printk(KERN_WARNING - "qla1280: Failed to register host, aborting.\n"); - goto error; - } - -#if LINUX_VERSION_CODE < 0x020545 - scsi_set_pci_device(host, pdev); -#else - scsi_set_device(host, &pdev->dev); -#endif - ha = (struct scsi_qla_host *)host->hostdata; - /* Clear our data area */ - memset(ha, 0, sizeof(struct scsi_qla_host)); - /* Sanitize the information from PCI BIOS. */ - host->irq = pdev->irq; - ha->pci_bus = pdev->bus->number; - ha->pci_device_fn = pdev->devfn; - ha->pdev = pdev; - ha->device_id = bdp->device_id; - ha->devnum = devnum; /* specifies microcode load address */ - - if (qla1280_mem_alloc(ha)) { - printk(KERN_INFO "qla1x160: Failed to get memory\n"); - goto error_scsi_unregister; - } - - ha->ports = bdp->numPorts; - /* following needed for all cases of OS versions */ - ha->host = host; - ha->host_no = host->host_no; - - host->can_queue = 0xfffff; /* unlimited */ - host->cmd_per_lun = 1; - host->base = (unsigned long)ha->mmpbase; - host->max_channel = bdp->numPorts - 1; - host->max_lun = MAX_LUNS - 1; - host->max_id = MAX_TARGETS; - host->max_sectors = 1024; -#if LINUX_VERSION_CODE < 0x020545 - host->select_queue_depths = qla1280_select_queue_depth; -#endif - - ha->instance = num_hosts; - host->unique_id = ha->instance; - - if (qla1280_pci_config(ha)) { - printk(KERN_INFO "qla1x160: Unable to configure PCI\n"); - goto error_mem_alloced; - } - - /* Disable ISP interrupts. */ - qla1280_disable_intrs(ha); - - /* Register the IRQ with Linux (sharable) */ - if (request_irq(host->irq, qla1280_intr_handler, SA_SHIRQ, - "qla1280", ha)) { - printk("qla1280 : Failed to reserve interrupt %d already " - "in use\n", host->irq); - goto error_iounmap; - } -#if !MEMORY_MAPPED_IO - /* Register the I/O space with Linux */ - if (!request_region(host->io_port, 0xff, "qla1280")) { - printk("qla1280: Failed to reserve i/o region 0x%04lx-0x%04lx" - " already in use\n", - host->io_port, host->io_port + 0xff); - goto error_free_irq; - } -#endif - - /* load the F/W, read paramaters, and init the H/W */ - if (qla1280_initialize_adapter(ha)) { - printk(KERN_INFO "qla1x160: Failed to initialize adapter\n"); - goto error_release_region; - } - - /* set our host ID (need to do something about our two IDs) */ - host->this_id = ha->bus_settings[0].id; - - return host; - - error_release_region: -#if !MEMORY_MAPPED_IO - release_region(host->io_port, 0xff); - error_free_irq: -#endif - free_irq(host->irq, ha); - error_iounmap: -#if MEMORY_MAPPED_IO - if (ha->mmpbase) - iounmap((void *)(((unsigned long) ha->mmpbase) & PAGE_MASK)); -#endif - error_mem_alloced: - qla1280_mem_free(ha); - error_scsi_unregister: - scsi_unregister(host); - error: - return NULL; -} - -/************************************************************************** - * qla1280_detect - * This routine will probe for Qlogic 1280 SCSI host adapters. - * It returns the number of host adapters of a particular - * type that were found. It also initialize all data necessary for - * the driver. It is passed-in the host number, so that it - * knows where its first entry is in the scsi_hosts[] array. - * - * Input: - * template - pointer to SCSI template - * - * Returns: - * num - number of host adapters found. - **************************************************************************/ -static int -qla1280_detect(Scsi_Host_Template * template) -{ - struct pci_dev *pdev = NULL; - struct Scsi_Host *host; - struct scsi_qla_host *ha, *cur_ha; - struct qla_boards *bdp; - uint16_t subsys_vendor, subsys_device; - int num_hosts = 0; - int devnum = 0; - - ENTER("qla1280_detect"); - - if (sizeof(struct srb) > sizeof(Scsi_Pointer)) { - printk(KERN_WARNING - "qla1280_detect: [WARNING] struct srb too big\n"); - return 0; - } -#ifdef MODULE - /* - * If we are called as a module, the qla1280 pointer may not be null - * and it would point to our bootup string, just like on the lilo - * command line. IF not NULL, then process this config string with - * qla1280_setup - * - * Boot time Options - * To add options at boot time add a line to your lilo.conf file like: - * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" - * which will result in the first four devices on the first two - * controllers being set to a tagged queue depth of 32. - */ - if (qla1280) - qla1280_setup(qla1280); -#endif - - bdp = &ql1280_board_tbl[0]; - qla1280_hostlist = NULL; - template->proc_name = "qla1280"; - - /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */ - while ((pdev = pci_find_subsys(PCI_VENDOR_ID_QLOGIC, bdp->device_id, - PCI_ANY_ID, PCI_ANY_ID, pdev))) { - - /* find QLA12160 device on PCI bus=1 slot=2 */ - if ((pdev->bus->number != 1) || (PCI_SLOT(pdev->devfn) != 2)) - continue; - - /* Bypass all AMI SUBSYS VENDOR IDs */ - if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) { - printk(KERN_INFO - "qla1x160: Skip AMI SubSys Vendor ID Chip\n"); - continue; - } - - if (pci_enable_device(pdev)) - goto find_devices; - - host = qla1280_do_device_init(pdev, template, devnum, - bdp, num_hosts); - if (!host) - continue; - ha = (struct scsi_qla_host *)host->hostdata; - - /* this preferred device will always be the first one found */ - cur_ha = qla1280_hostlist = ha; - num_hosts++; - } - - find_devices: - - pdev = NULL; - /* Try and find each different type of adapter we support */ - for (devnum = 0; bdp->device_id != 0 && devnum < NUM_OF_ISP_DEVICES; - devnum++, bdp++) { - /* PCI_SUBSYSTEM_IDS supported */ - while ((pdev = pci_find_subsys(PCI_VENDOR_ID_QLOGIC, - bdp->device_id, PCI_ANY_ID, - PCI_ANY_ID, pdev))) { - if (pci_enable_device(pdev)) - continue; - /* found an adapter */ - subsys_vendor = pdev->subsystem_vendor; - subsys_device = pdev->subsystem_device; - - /* - * skip QLA12160 already initialized on - * PCI Bus 1 Dev 2 since we already initialized - * and presented it - */ - if ((bdp->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160)&& - (pdev->bus->number == 1) && - (PCI_SLOT(pdev->devfn) == 2)) - continue; - - /* Bypass all AMI SUBSYS VENDOR IDs */ - if (subsys_vendor == PCI_VENDOR_ID_AMI) { - printk(KERN_INFO - "qla1x160: Skip AMI SubSys Vendor ID Chip\n"); - continue; - } - dprintk(1, "qla1x160: Supported Device Found VID=%x " - "DID=%x SSVID=%x SSDID=%x\n", pdev->vendor, - pdev->device, subsys_vendor, subsys_device); - - host = qla1280_do_device_init(pdev, template, - devnum, bdp, num_hosts); - if (!host) - continue; - ha = (struct scsi_qla_host *)host->hostdata; - - if (qla1280_hostlist == NULL) { - cur_ha = qla1280_hostlist = ha; - } else { - cur_ha = qla1280_hostlist; - while (cur_ha->next != NULL) - cur_ha = cur_ha->next; - cur_ha->next = ha; - } - num_hosts++; - } /* end of WHILE */ - } /* end of FOR */ - - LEAVE("qla1280_detect"); - return num_hosts; -} - -/************************************************************************** - * qla1280_release - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - **************************************************************************/ -static int -qla1280_release(struct Scsi_Host *host) -{ - struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; - - ENTER("qla1280_release"); - - if (!ha->flags.online) - return 0; - - /* turn-off interrupts on the card */ - WRT_REG_WORD(&ha->iobase->ictrl, 0); - - /* Detach interrupts */ - if (host->irq) - free_irq(host->irq, ha); - -#if MEMORY_MAPPED_IO - if (ha->mmpbase) - iounmap(ha->mmpbase); -#else - /* release io space registers */ - if (host->io_port) - release_region(host->io_port, 0xff); -#endif /* MEMORY_MAPPED_IO */ - - qla1280_mem_free(ha); - - ENTER("qla1280_release"); - return 0; -} - /************************************************************************** * qla1280_info * Return a string describing the driver. @@ -1197,11 +833,11 @@ qla1280_info(struct Scsi_Host *host) ha = (struct scsi_qla_host *)host->hostdata; bdp = &ql1280_board_tbl[ha->devnum]; memset(bp, 0, sizeof(qla1280_scsi_name_buffer)); + sprintf (bp, - "QLogic %s PCI to SCSI Host Adapter: bus %d device %d irq %d\n" + "QLogic %s PCI to SCSI Host Adapter\n" " Firmware version: %2d.%02d.%02d, Driver version %s", - &bdp->name[0], ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, - host->irq, bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], + &bdp->name[0], bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], QLA1280_VERSION); return bp; } @@ -1220,38 +856,19 @@ qla1280_info(struct Scsi_Host *host) static int qla1280_queuecommand(Scsi_Cmnd * cmd, void (*fn) (Scsi_Cmnd *)) { - struct scsi_qla_host *ha; - struct srb *sp; - struct Scsi_Host *host; - int bus, target, lun; - int status; - - /*ENTER("qla1280_queuecommand"); - */ - dprintk(2, "qla1280_queuecommand(): jiffies %li\n", jiffies); - - host = CMD_HOST(cmd); - ha = (struct scsi_qla_host *)host->hostdata; + struct Scsi_Host *host = cmd->device->host; + struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; + struct srb *sp = (struct srb *)&cmd->SCp; - /* send command to adapter */ - sp = (struct srb *)CMD_SP(cmd); - sp->cmd = cmd; cmd->scsi_done = fn; + sp->cmd = cmd; sp->flags = 0; qla1280_print_scsi_cmd(5, cmd); - /* Generate LU queue on bus, target, LUN */ - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); if (ha->flags.enable_64bit_addressing) - status = qla1280_64bit_start_scsi(ha, sp); - else - status = qla1280_32bit_start_scsi(ha, sp); - - /*LEAVE("qla1280_queuecommand"); */ - return status; + return qla1280_64bit_start_scsi(ha, sp); + return qla1280_32bit_start_scsi(ha, sp); } enum action { @@ -1564,29 +1181,105 @@ qla1280_biosparam(struct scsi_device *sd unsigned long capacity = disk->capacity; #endif - heads = 64; - sectors = 32; - cylinders = (unsigned long)capacity / (heads * sectors); - if (cylinders > 1024) { - heads = 255; - sectors = 63; - cylinders = (unsigned long)capacity / (heads * sectors); - /* if (cylinders > 1023) - cylinders = 1023; */ + heads = 64; + sectors = 32; + cylinders = (unsigned long)capacity / (heads * sectors); + if (cylinders > 1024) { + heads = 255; + sectors = 63; + cylinders = (unsigned long)capacity / (heads * sectors); + /* if (cylinders > 1023) + cylinders = 1023; */ + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return 0; +} + +#if LINUX_VERSION_CODE < 0x020600 +static int +qla1280_detect(Scsi_Host_Template *template) +{ + struct pci_device_id *id = &qla1280_pci_tbl[0]; + struct pci_dev *pdev = NULL; + int num_hosts = 0; + + if (sizeof(struct srb) > sizeof(Scsi_Pointer)) { + printk(KERN_WARNING + "qla1280: struct srb too big, aborting\n"); + return 0; + } + +#ifdef MODULE + /* + * If we are called as a module, the qla1280 pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * qla1280_setup + * + * Boot time Options + * To add options at boot time add a line to your lilo.conf file like: + * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + */ + if (qla1280) + qla1280_setup(qla1280); +#endif + + /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */ + while ((pdev = pci_find_device(id->vendor, id->device, pdev))) { + if (pdev->bus->number == 1 && PCI_SLOT(pdev->devfn) == 2) { + if (!qla1280_probe_one(pdev, id)) + num_hosts++; + } + } + + pdev = NULL; + /* Try and find each different type of adapter we support */ + for (id = &qla1280_pci_tbl[0]; id->device; id++) { + while ((pdev = pci_find_device(id->vendor, id->device, pdev))) { + /* + * skip QLA12160 already initialized on + * PCI Bus 1 Dev 2 since we already initialized + * and presented it + */ + if (id->device == PCI_DEVICE_ID_QLOGIC_ISP12160 && + pdev->bus->number == 1 && + PCI_SLOT(pdev->devfn) == 2) + continue; + + if (!qla1280_probe_one(pdev, id)) + num_hosts++; + } } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; + return num_hosts; +} + +/* + * This looks a bit ugly as we could just pass down host to + * qla1280_remove_one, but I want to keep qla1280_release purely a wrapper + * around pci_driver::remove as used from 2.6 onwards. + */ +static int +qla1280_release(struct Scsi_Host *host) +{ + struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; + qla1280_remove_one(ha->pdev); return 0; } +#endif /************************************************************************** * qla1280_intr_handler * Handles the H/W interrupt **************************************************************************/ -irqreturn_t +static irqreturn_t qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) { struct scsi_qla_host *ha; @@ -1624,7 +1317,7 @@ qla1280_intr_handler(int irq, void *dev_ static int -qla12160_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) +qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) { uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; @@ -1633,8 +1326,8 @@ qla12160_set_target_parameters(struct sc nv = &ha->nvram; - if (ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) + if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) is1x160 = 1; else is1x160 = 0; @@ -1721,8 +1414,8 @@ qla1280_slave_configure(Scsi_Device *dev (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) nv->bus[bus].target[target].parameter.f.enable_wide = 0; - if (ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) { + if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && (~driver_setup.ppr_mask & (1 << target)))) @@ -1730,11 +1423,9 @@ qla1280_slave_configure(Scsi_Device *dev } spin_lock_irqsave(HOST_LOCK, flags); - if (nv->bus[bus].target[target].parameter.f.enable_sync) { - status = qla12160_set_target_parameters(ha, bus, target); - } - - qla12160_get_target_parameters(ha, device); + if (nv->bus[bus].target[target].parameter.f.enable_sync) + status = qla1280_set_target_parameters(ha, bus, target); + qla1280_get_target_parameters(ha, device); spin_unlock_irqrestore(HOST_LOCK, flags); return status; } @@ -1761,16 +1452,11 @@ qla1280_select_queue_depth(struct Scsi_H if (scsi_devs) qla1280_check_for_dead_scsi_bus(ha, scsi_devs->channel); - LEAVE("qla1280_select_queue_depth"); } #endif /* - * Driver Support Routines - */ - -/* * qla1280_done * Process completed commands. * @@ -1972,100 +1658,19 @@ qla1280_done_q_put(struct srb * sp, stru LEAVE("qla1280_put_done_q"); } - -/* -* qla1280_mem_alloc -* Allocates adapter memory. -* -* Returns: -* 0 = success. -* 1 = failure. -*/ -static int -qla1280_mem_alloc(struct scsi_qla_host *ha) -{ - int status = 1; - dma_addr_t dma_handle; - - ENTER("qla1280_mem_alloc"); - - /* get consistent memory allocated for request and response rings */ - ha->request_ring = pci_alloc_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * - (sizeof(request_t))), - &dma_handle); - if (!ha->request_ring) - goto error; - ha->request_dma = dma_handle; - ha->response_ring = pci_alloc_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * - (sizeof(struct response))), - &dma_handle); - if (!ha->response_ring) - goto error; - ha->response_dma = dma_handle; - status = 0; - goto finish; - - error: - if (status) - dprintk(2, "qla1280_mem_alloc: **** FAILED ****\n"); - - if (ha->request_ring) - pci_free_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * - (sizeof(request_t))), - ha->request_ring, ha->request_dma); - finish: - LEAVE("qla1280_mem_alloc"); - return status; -} - -/* - * qla1280_mem_free - * Frees adapter allocated memory. - * - * Input: - * ha = adapter block pointer. - */ -static void -qla1280_mem_free(struct scsi_qla_host *ha) -{ - ENTER("qlc1280_mem_free"); - /* free consistent memory allocated for request and response rings */ - if (ha->request_ring) - pci_free_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * - (sizeof(request_t))), - ha->request_ring, ha->request_dma); - - if (ha->response_ring) - pci_free_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * - (sizeof(struct response))), - ha->response_ring, ha->response_dma); - - if (qla1280_buffer) { - free_page((unsigned long) qla1280_buffer); - qla1280_buffer = NULL; - } - - LEAVE("qlc1280_mem_free"); -} - /****************************************************************************/ /* QLogic ISP1280 Hardware Support Functions. */ /****************************************************************************/ /* - * qla2100_enable_intrs - * qla2100_disable_intrs - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * None + * qla2100_enable_intrs + * qla2100_disable_intrs + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * None */ static inline void qla1280_enable_intrs(struct scsi_qla_host *ha) @@ -2101,7 +1706,7 @@ qla1280_disable_intrs(struct scsi_qla_ho * Returns: * 0 = success */ -static int +static int __devinit qla1280_initialize_adapter(struct scsi_qla_host *ha) { struct device_reg *reg; @@ -2297,7 +1902,7 @@ qla1280_isp_firmware(struct scsi_qla_hos * Returns: * 0 = success. */ -static int +static int __devinit qla1280_pci_config(struct scsi_qla_host *ha) { #if MEMORY_MAPPED_IO @@ -2724,8 +2329,8 @@ qla1280_nvram_config(struct scsi_qla_hos ENTER("qla1280_nvram_config"); - if (ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) + if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) is1x160 = 1; else is1x160 = 0; @@ -4207,48 +3812,6 @@ qla1280_isp_cmd(struct scsi_qla_host *ha LEAVE("qla1280_isp_cmd"); } -#if QL1280_LUN_SUPPORT -/* - * qla1280_enable_lun - * Issue enable LUN entry IOCB. - * - * Input: - * ha = adapter block pointer. - * bus = SCSI BUS number. - * lun = LUN number. - */ -static void -qla1280_enable_lun(struct scsi_qla_host *ha, int bus, int lun) -{ - struct elun_entry *pkt; - - ENTER("qla1280_enable_lun"); - - /* Get request packet. */ - /* - if (pkt = (struct elun_entry *)qla1280_req_pkt(ha)) - { - pkt->entry_type = ENABLE_LUN_TYPE; - pkt->lun = cpu_to_le16(bus ? lun | BIT_15 : lun); - pkt->command_count = 32; - pkt->immed_notify_count = 1; - pkt->group_6_length = MAX_CMDSZ; - pkt->group_7_length = MAX_CMDSZ; - pkt->timeout = cpu_to_le16(0x30); - - qla1280_isp_cmd(ha); - } - */ - pkt = (struct elun_entry *) 1; - - if (!pkt) - dprintk(2, "qla1280_enable_lun: **** FAILED ****\n"); - else - dprintk(3, "qla1280_enable_lun: exiting normally\n"); -} -#endif - - /****************************************************************************/ /* Interrupt Service Routine. */ /****************************************************************************/ @@ -4894,7 +4457,7 @@ qla1280_check_for_dead_scsi_bus(struct s } static void -qla12160_get_target_parameters(struct scsi_qla_host *ha, Scsi_Device *device) +qla1280_get_target_parameters(struct scsi_qla_host *ha, Scsi_Device *device) { uint16_t mb[MAILBOX_REGISTER_COUNT]; int bus, target, lun; @@ -5136,34 +4699,270 @@ qla1280_get_token(char *str) return ret; } - -static Scsi_Host_Template driver_template = { - .proc_info = qla1280_proc_info, +static Scsi_Host_Template qla1280_driver_template = { + .proc_name = "qla1280", .name = "Qlogic ISP 1280/12160", +#if LINUX_VERSION_CODE >= 0x020545 + .slave_configure = qla1280_slave_configure, +#else .detect = qla1280_detect, .release = qla1280_release, +#endif .info = qla1280_info, .queuecommand = qla1280_queuecommand, -#if LINUX_VERSION_CODE >= 0x020545 - .slave_configure = qla1280_slave_configure, -#endif .eh_abort_handler = qla1280_eh_abort, .eh_device_reset_handler= qla1280_eh_device_reset, .eh_bus_reset_handler = qla1280_eh_bus_reset, .eh_host_reset_handler = qla1280_eh_adapter_reset, .bios_param = qla1280_biosparam, - .can_queue = 255, + .proc_info = qla1280_proc_info, + .can_queue = 0xfffff, .this_id = -1, .sg_tablesize = SG_ALL, - .cmd_per_lun = 3, + .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, #if LINUX_VERSION_CODE < 0x020545 .use_new_eh_code = 1, #endif }; -#include "scsi_module.c" +static int __devinit +qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int devnum = id->driver_data; + struct qla_boards *bdp = &ql1280_board_tbl[devnum]; + struct Scsi_Host *host; + struct scsi_qla_host *ha; + int error = -ENODEV; + + /* Bypass all AMI SUBSYS VENDOR IDs */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) { + printk(KERN_INFO + "qla1280: Skipping AMI SubSys Vendor ID Chip\n"); + goto error; + } + + printk(KERN_INFO "qla1280: %s found on PCI bus %i, dev %i\n", + bdp->name, pdev->bus->number, PCI_SLOT(pdev->devfn)); + + if (pci_enable_device(pdev)) { + printk(KERN_WARNING + "qla1280: Failed to enabled pci device, aborting.\n"); + goto error; + } + + error = -ENOMEM; + host = scsi_host_alloc(&qla1280_driver_template, sizeof(*ha)); + if (!host) { + printk(KERN_WARNING + "qla1280: Failed to register host, aborting.\n"); + goto error; + } + + ha = (struct scsi_qla_host *)host->hostdata; + memset(ha, 0, sizeof(struct scsi_qla_host)); + + ha->pdev = pdev; + ha->devnum = devnum; /* specifies microcode load address */ + + ha->request_ring = pci_alloc_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + &ha->request_dma); + if (!ha->request_ring) { + printk(KERN_INFO "qla1280: Failed to get request memory\n"); + goto error_put_host; + } + + ha->response_ring = pci_alloc_consistent(ha->pdev, + ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + &ha->response_dma); + if (!ha->response_ring) { + printk(KERN_INFO "qla1280: Failed to get response memory\n"); + goto error_free_request_ring; + } + + ha->ports = bdp->numPorts; + + ha->host = host; + ha->host_no = host->host_no; + + host->irq = pdev->irq; + host->base = (unsigned long)ha->mmpbase; + host->max_channel = bdp->numPorts - 1; + host->max_lun = MAX_LUNS - 1; + host->max_id = MAX_TARGETS; + host->max_sectors = 1024; + host->unique_id = host->host_no; + +#if LINUX_VERSION_CODE < 0x020545 + host->select_queue_depths = qla1280_select_queue_depth; +#endif + + error = -ENODEV; + if (qla1280_pci_config(ha)) { + printk(KERN_INFO "qla1280: Unable to configure PCI\n"); + goto error_free_response_ring; + } + + /* Disable ISP interrupts. */ + qla1280_disable_intrs(ha); + + /* Register the IRQ with Linux (sharable) */ + if (request_irq(pdev->irq, qla1280_intr_handler, SA_SHIRQ, + "qla1280", ha)) { + printk("qla1280 : Failed to reserve interrupt %d already " + "in use\n", pdev->irq); + goto error_iounmap; + } + +#if !MEMORY_MAPPED_IO + /* Register the I/O space with Linux */ + if (!request_region(host->io_port, 0xff, "qla1280")) { + printk("qla1280: Failed to reserve i/o region 0x%04lx-0x%04lx" + " already in use\n", + host->io_port, host->io_port + 0xff); + goto error_free_irq; + } +#endif + + /* load the F/W, read paramaters, and init the H/W */ + if (qla1280_initialize_adapter(ha)) { + printk(KERN_INFO "qla1x160: Failed to initialize adapter\n"); + goto error_release_region; + } + + /* set our host ID (need to do something about our two IDs) */ + host->this_id = ha->bus_settings[0].id; + + pci_set_drvdata(pdev, host); + +#if LINUX_VERSION_CODE >= 0x020600 + error = scsi_add_host(host, &pdev->dev); + if (error) + goto error_disable_adapter; + scsi_scan_host(host); +#else + scsi_set_pci_device(host, pdev); +#endif + + return 0; + +#if LINUX_VERSION_CODE >= 0x020600 + error_disable_adapter: + WRT_REG_WORD(&ha->iobase->ictrl, 0); +#endif + error_release_region: +#if !MEMORY_MAPPED_IO + release_region(host->io_port, 0xff); + error_free_irq: +#endif + free_irq(pdev->irq, ha); + error_iounmap: +#if MEMORY_MAPPED_IO + iounmap((void *)(((unsigned long) ha->mmpbase) & PAGE_MASK)); +#endif + error_free_response_ring: + pci_free_consistent(ha->pdev, + ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + ha->response_ring, ha->response_dma); + error_free_request_ring: + pci_free_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ha->request_ring, ha->request_dma); + error_put_host: + scsi_host_put(host); + error: + return error; +} + +/* + * Older ia64 toolchains have problems with relative links when this + * goes into the .exit.text section + */ +static void +qla1280_remove_one(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; + +#if LINUX_VERSION_CODE >= 0x020600 + scsi_remove_host(host); +#endif + + WRT_REG_WORD(&ha->iobase->ictrl, 0); + + free_irq(pdev->irq, ha); + +#if MEMORY_MAPPED_IO + iounmap(ha->mmpbase); +#else + release_region(host->io_port, 0xff); +#endif + + pci_free_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ha->request_ring, ha->request_dma); + pci_free_consistent(ha->pdev, + ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + ha->response_ring, ha->response_dma); + + scsi_host_put(host); +} + +#if LINUX_VERSION_CODE >= 0x020600 +static struct pci_driver qla1280_pci_driver = { + .name = "qla1280", + .id_table = qla1280_pci_tbl, + .probe = qla1280_probe_one, + .remove = __devexit_p(qla1280_remove_one), +}; + +static int __init +qla1280_init(void) +{ + if (sizeof(struct srb) > sizeof(Scsi_Pointer)) { + printk(KERN_WARNING + "qla1280: struct srb too big, aborting\n"); + return -EINVAL; + } + +#ifdef MODULE + /* + * If we are called as a module, the qla1280 pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * qla1280_setup + * + * Boot time Options + * To add options at boot time add a line to your lilo.conf file like: + * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + */ + if (qla1280) + qla1280_setup(qla1280); +#endif + + return pci_module_init(&qla1280_pci_driver); +} +static void __exit +qla1280_exit(void) +{ + pci_unregister_driver(&qla1280_pci_driver); +} + +module_init(qla1280_init); +module_exit(qla1280_exit); + +#else +# define driver_template qla1280_driver_template +# include "scsi_module.c" +#endif + +MODULE_AUTHOR("Qlogic & Jes Sorensen"); +MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver"); +MODULE_LICENSE("GPL"); /* * Overrides for Emacs so that we almost follow Linus's tabbing style. --- linux-2.6.1-rc1/drivers/scsi/qla1280.h 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/scsi/qla1280.h 2003-12-30 22:49:45.000000000 -0800 @@ -1021,11 +1021,7 @@ struct scsi_qla_host { unsigned char *mmpbase; /* memory mapped address */ unsigned long host_no; - unsigned long instance; struct pci_dev *pdev; - uint32_t device_id; - uint8_t pci_bus; - uint8_t pci_device_fn; uint8_t devnum; uint8_t revision; uint8_t ports; @@ -1040,18 +1036,9 @@ struct scsi_qla_host { /* BUS configuration data */ struct bus_param bus_settings[MAX_BUSES]; -#if 0 - /* bottom half run queue */ - struct tq_struct run_qla_bh; -#endif - /* Received ISP mailbox data. */ volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; -#ifdef UNUSED - struct timer_list dev_timer[MAX_TARGETS]; -#endif - dma_addr_t request_dma; /* Physical Address */ request_t *request_ring; /* Base virtual address */ request_t *request_ring_ptr; /* Current address. */ @@ -1063,15 +1050,6 @@ struct scsi_qla_host { struct response *response_ring_ptr; /* Current address. */ uint16_t rsp_ring_index; /* Current index. */ -#if WATCHDOGTIMER - /* Watchdog queue, lock and total timer */ - uint8_t watchdog_q_lock; /* Lock for watchdog queue */ - struct srb *wdg_q_first; /* First job on watchdog queue */ - struct srb *wdg_q_last; /* Last job on watchdog queue */ - uint32_t total_timeout; /* Total timeout (quantum count) */ - uint32_t watchdogactive; -#endif - struct srb *done_q_first; /* First job on done queue */ struct srb *done_q_last; /* Last job on done queue */ --- linux-2.6.1-rc1/drivers/scsi/sd.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/scsi/sd.c 2003-12-30 22:49:48.000000000 -0800 @@ -62,6 +62,7 @@ */ #define SD_MAJORS 16 #define SD_DISKS (SD_MAJORS << 4) +#define TOTAL_SD_DISKS CONFIG_MAX_SD_DISKS /* * Time out in seconds for disks and Magneto-opticals (which are slower). @@ -95,7 +96,7 @@ struct scsi_disk { }; -static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; +static unsigned long sd_index_bits[TOTAL_SD_DISKS / BITS_PER_LONG]; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; static int sd_revalidate_disk(struct gendisk *disk); @@ -130,6 +131,9 @@ static int sd_major(int major_idx) return SCSI_DISK1_MAJOR + major_idx - 1; case 8 ... 15: return SCSI_DISK8_MAJOR + major_idx - 8; +#define MAX_IDX (TOTAL_SD_DISKS >> 4) + case 16 ... MAX_IDX: + return SCSI_DISK15_MAJOR; default: BUG(); return 0; /* shut up gcc */ @@ -378,9 +382,9 @@ queue: * In the latter case @inode and @filp carry an abridged amount * of information as noted above. **/ -static int sd_open(struct inode *inode, struct file *filp) +static int sd_open(struct block_device *bdev, struct file *filp) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdev; int retval; @@ -402,7 +406,7 @@ static int sd_open(struct inode *inode, goto error_out; if (sdev->removable || sdkp->write_prot) - check_disk_change(inode->i_bdev); + check_disk_change(bdev); /* * If the drive is empty, just let the open fail. @@ -453,9 +457,8 @@ error_out: * Note: may block (uninterruptible) if error recovery is underway * on this disk. **/ -static int sd_release(struct inode *inode, struct file *filp) +static int sd_release(struct gendisk *disk) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdev = sdkp->device; @@ -518,10 +521,9 @@ static int sd_hdio_getgeo(struct block_d * Note: most ioctls are forward onto the block subsystem or further * down in the scsi subsytem. **/ -static int sd_ioctl(struct inode * inode, struct file * filp, +static int sd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; struct gendisk *disk = bdev->bd_disk; struct scsi_device *sdp = scsi_disk(disk)->device; int error; @@ -1320,8 +1322,8 @@ static int sd_probe(struct device *dev) goto out_free; spin_lock(&sd_index_lock); - index = find_first_zero_bit(sd_index_bits, SD_DISKS); - if (index == SD_DISKS) { + index = find_first_zero_bit(sd_index_bits, TOTAL_SD_DISKS); + if (index == TOTAL_SD_DISKS) { spin_unlock(&sd_index_lock); error = -EBUSY; goto out_put; @@ -1336,15 +1338,24 @@ static int sd_probe(struct device *dev) sdkp->openers = 0; gd->major = sd_major(index >> 4); - gd->first_minor = (index & 15) << 4; + if (index > SD_DISKS) + gd->first_minor = ((index - SD_DISKS) & 15) << 4; + else + gd->first_minor = (index & 15) << 4; gd->minors = 16; gd->fops = &sd_fops; - if (index >= 26) { + if (index < 26) { + sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + } else if (index < (26*27)) { sprintf(gd->disk_name, "sd%c%c", 'a' + index/26-1,'a' + index % 26); } else { - sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + const unsigned int m1 = (index/ 26 - 1) / 26 - 1; + const unsigned int m2 = (index / 26 - 1) % 26; + const unsigned int m3 = index % 26; + sprintf(gd->disk_name, "sd%c%c%c", + 'a' + m1, 'a' + m2, 'a' + m3); } strcpy(gd->devfs_name, sdp->devfs_name); --- linux-2.6.1-rc1/drivers/scsi/sr.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/drivers/scsi/sr.c 2003-12-30 22:49:59.000000000 -0800 @@ -67,7 +67,8 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioc (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_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET) + CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ + CDC_MRW|CDC_MRW_W|CDC_RAM) static int sr_probe(struct device *); static int sr_remove(struct device *); @@ -413,22 +414,22 @@ queue: return 1; } -static int sr_block_open(struct inode *inode, struct file *file) +static int sr_block_open(struct block_device *bdev, struct file *file) { - struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk); - return cdrom_open(&cd->cdi, inode, file); + struct scsi_cd *cd = scsi_cd(bdev->bd_disk); + return cdrom_open(&cd->cdi, bdev, file); } -static int sr_block_release(struct inode *inode, struct file *file) +static int sr_block_release(struct gendisk *disk) { - struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk); - return cdrom_release(&cd->cdi, file); + struct scsi_cd *cd = scsi_cd(disk); + return cdrom_release(&cd->cdi); } -static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd, - unsigned long arg) +static int sr_block_ioctl(struct block_device *bdev, struct file *file, + unsigned cmd, unsigned long arg) { - struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk); + struct scsi_cd *cd = scsi_cd(bdev->bd_disk); struct scsi_device *sdev = cd->device; /* @@ -440,7 +441,7 @@ static int sr_block_ioctl(struct inode * case SCSI_IOCTL_GET_BUS_NUMBER: return scsi_ioctl(sdev, cmd, (void *)arg); } - return cdrom_ioctl(&cd->cdi, inode, cmd, arg); + return cdrom_ioctl(&cd->cdi, bdev, cmd, arg); } static int sr_block_media_changed(struct gendisk *disk) @@ -692,7 +693,7 @@ Enomem: static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; - int rc, n; + int rc, n, mrw_write = 0, mrw = 1; struct scsi_mode_data data; struct scsi_request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; @@ -765,6 +766,15 @@ static void get_capabilities(struct scsi printk("%s: scsi-1 drive\n", cd->cdi.name); return; } + + if (cdrom_is_mrw(&cd->cdi, &mrw_write)) { + mrw = 0; + cd->cdi.mask |= CDC_MRW; + cd->cdi.mask |= CDC_MRW_W; + } + if (!mrw_write) + cd->cdi.mask |= CDC_MRW_W; + n = data.header_length + data.block_descriptor_length; cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; cd->readcd_known = 1; @@ -788,9 +798,7 @@ static void get_capabilities(struct scsi if ((buffer[n + 3] & 0x20) == 0) { /* can't write DVD-RAM media */ cd->cdi.mask |= CDC_DVD_RAM; - } else { - cd->device->writeable = 1; - } + } else if ((buffer[n + 3] & 0x10) == 0) /* can't write DVD-R media */ cd->cdi.mask |= CDC_DVD_R; @@ -814,6 +822,12 @@ static void get_capabilities(struct scsi /*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ + /* + * if DVD-RAM of MRW-W, we are randomly writeable + */ + if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W)) != (CDC_DVD_RAM | CDC_MRW_W)) + cd->device->writeable = 1; + scsi_release_request(SRpnt); kfree(buffer); } --- linux-2.6.1-rc1/drivers/scsi/sym53c8xx_2/sym_hipd.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/drivers/scsi/sym53c8xx_2/sym_hipd.c 2003-12-30 22:49:46.000000000 -0800 @@ -1058,12 +1058,10 @@ static int sym_prepare_setting(hcb_p np, * and BUS width. */ if (np->features & FE_ULTRA3) { - if (tp->tinfo.user.period <= 9 && - tp->tinfo.user.width == BUS_16_BIT) { - tp->tinfo.user.options |= PPR_OPT_DT; - tp->tinfo.user.offset = np->maxoffs_dt; - tp->tinfo.user.spi_version = 3; - } + tp->tinfo.user.options |= PPR_OPT_DT; + tp->tinfo.user.period = np->minsync_dt; + tp->tinfo.user.offset = np->maxoffs_dt; + tp->tinfo.user.spi_version = 3; } if (!tp->usrtags) @@ -2126,9 +2124,15 @@ sym_setsync(hcb_p np, int target, sym_settrans(np, target, 0, ofs, per, wide, div, fak); - tp->tinfo.goal.period = tp->tinfo.curr.period = per; - tp->tinfo.goal.offset = tp->tinfo.curr.offset = ofs; - tp->tinfo.goal.options = tp->tinfo.curr.options = 0; + tp->tinfo.curr.period = per; + tp->tinfo.curr.offset = ofs; + tp->tinfo.curr.options = 0; + + if (!(tp->tinfo.goal.options & PPR_OPT_MASK)) { + tp->tinfo.goal.period = per; + tp->tinfo.goal.offset = ofs; + tp->tinfo.goal.options = 0; + } sym_xpt_async_nego_sync(np, target); } --- linux-2.6.1-rc1/drivers/scsi/sym53c8xx_2/sym_misc.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/scsi/sym53c8xx_2/sym_misc.c 2003-12-30 22:49:57.000000000 -0800 @@ -328,7 +328,6 @@ printf("XXXXXX [%d] inq_version=%x inq_b tp->inq_byte56 != inq_byte56) { tp->inq_version = inq_version; tp->inq_byte7 = inq_byte7; - tp->inq_byte56 = inq_byte56; return 1; } return 0; --- linux-2.6.1-rc1/drivers/serial/8250.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/drivers/serial/8250.c 2003-12-30 22:49:25.000000000 -0800 @@ -844,7 +844,7 @@ receive_chars(struct uart_8250_port *up, if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { tty->flip.work.func((void *)tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) - return; // if TTY_DONT_FLIP is set + return; /* if TTY_DONT_FLIP is set */ } ch = serial_inp(up, UART_RX); *tty->flip.char_buf_ptr = ch; @@ -1205,12 +1205,21 @@ static void serial8250_break_ctl(struct spin_unlock_irqrestore(&up->port.lock, flags); } +#ifdef CONFIG_KGDB +static int kgdb_irq = -1; +#endif + static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; int retval; +#ifdef CONFIG_KGDB + if (up->port.irq == kgdb_irq) + return -EBUSY; +#endif + up->capabilities = uart_config[up->port.type].flags; if (up->port.type == PORT_16C950) { @@ -1876,6 +1885,10 @@ static void __init serial8250_register_p for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; +#ifdef CONFIG_KGDB + if (up->port.irq == kgdb_irq) + up->port.kgdb = 1; +#endif up->port.line = i; up->port.ops = &serial8250_pops; init_timer(&up->timer); @@ -2145,6 +2158,31 @@ void serial8250_resume_port(int line) uart_resume_port(&serial8250_reg, &serial8250_ports[line].port); } +#ifdef CONFIG_KGDB +/* + * Find all the ports using the given irq and shut them down. + * Result should be that the irq will be released. + */ +void shutdown_for_kgdb(struct async_struct * info) +{ + int irq = info->state->irq; + struct uart_8250_port *up; + int ttyS; + + kgdb_irq = irq; /* save for later init */ + for (ttyS = 0; ttyS < UART_NR; ttyS++){ + up = &serial8250_ports[ttyS]; + if (up->port.irq == irq && (irq_lists + irq)->head) { +#ifdef CONFIG_DEBUG_SPINLOCK /* ugly business... */ + if(up->port.lock.magic != SPINLOCK_MAGIC) + spin_lock_init(&up->port.lock); +#endif + serial8250_shutdown(&up->port); + } + } +} +#endif /* CONFIG_KGDB */ + static int __init serial8250_init(void) { int ret, i; --- linux-2.6.1-rc1/drivers/serial/serial_core.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/drivers/serial/serial_core.c 2003-12-30 22:49:25.000000000 -0800 @@ -1978,6 +1978,11 @@ uart_configure_port(struct uart_driver * { unsigned int flags; +#ifdef CONFIG_KGDB + if (port->kgdb) + return; +#endif + /* * If there isn't a port here, don't do anything further. */ --- linux-2.6.1-rc1/drivers/serial/serial_cs.c 2003-09-27 18:57:46.000000000 -0700 +++ 25/drivers/serial/serial_cs.c 2003-12-30 22:50:03.000000000 -0800 @@ -149,9 +149,9 @@ static void serial_remove(dev_link_t *li info->link.dev = NULL; if (!info->slave) { - CardServices(ReleaseConfiguration, info->link.handle); - CardServices(ReleaseIO, info->link.handle, &info->link.io); - CardServices(ReleaseIRQ, info->link.handle, &info->link.irq); + pcmcia_release_configuration(info->link.handle); + pcmcia_release_io(info->link.handle, &info->link.io); + pcmcia_release_irq(info->link.handle, &info->link.irq); } info->link.state &= ~DEV_CONFIG; @@ -211,7 +211,7 @@ static dev_link_t *serial_attach(void) client_reg.event_handler = &serial_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); serial_detach(link); @@ -256,7 +256,7 @@ static void serial_detach(dev_link_t * l serial_remove(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -300,20 +300,30 @@ static int setup_serial(struct serial_in /*====================================================================*/ static int -get_tuple(int fn, client_handle_t handle, tuple_t * tuple, cisparse_t * parse) +first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) { int i; - i = CardServices(fn, handle, tuple); + i = pcmcia_get_first_tuple(handle, tuple); if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS; - i = CardServices(GetTupleData, handle, tuple); + i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); + return pcmcia_parse_tuple(handle, tuple, parse); } -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) +static int +next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) +{ + int i; + i = pcmcia_get_next_tuple(handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + i = pcmcia_get_tuple_data(handle, tuple); + if (i != CS_SUCCESS) + return i; + return pcmcia_parse_tuple(handle, tuple, parse); +} /*====================================================================*/ @@ -330,7 +340,7 @@ static int simple_config(dev_link_t * li int i, j, try; /* If the card is already configured, look up the port and irq */ - i = CardServices(GetConfigurationInfo, handle, &config); + i = pcmcia_get_configuration_info(handle, &config); if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { ioaddr_t port = 0; if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { @@ -367,9 +377,7 @@ static int simple_config(dev_link_t * li link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = - CardServices(RequestIO, link->handle, - &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -389,8 +397,7 @@ static int simple_config(dev_link_t * li for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = CardServices(RequestIO, link->handle, - &link->io); + i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } @@ -406,14 +413,14 @@ static int simple_config(dev_link_t * li return -1; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } if (info->multi && (info->manfid == MANFID_3COM)) link->conf.ConfigIndex &= ~(0x08); - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); return -1; @@ -433,7 +440,7 @@ static int multi_config(dev_link_t * lin config_info_t config; int i, base2 = 0; - i = CardServices(GetConfigurationInfo, handle, &config); + i = pcmcia_get_configuration_info(handle, &config); if (i != CS_SUCCESS) { cs_error(handle, GetConfigurationInfo, i); return -1; @@ -458,7 +465,7 @@ static int multi_config(dev_link_t * lin link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); + i = pcmcia_request_io(link->handle, &link->io); base2 = link->io.BasePort1 + 8; if (i == CS_SUCCESS) break; @@ -478,9 +485,7 @@ static int multi_config(dev_link_t * lin link->io.BasePort2 = cf->io.win[1].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = - CardServices(RequestIO, link->handle, - &link->io); + i = pcmcia_request_io(link->handle, &link->io); base2 = link->io.BasePort2; if (i == CS_SUCCESS) break; @@ -494,7 +499,7 @@ static int multi_config(dev_link_t * lin return -1; } - i = CardServices(RequestIRQ, link->handle, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); @@ -506,7 +511,7 @@ static int multi_config(dev_link_t * lin link->conf.Present |= PRESENT_EXT_STATUS; link->conf.ExtStatus = ESR_REQ_ATTN_ENA; } - i = CardServices(RequestConfiguration, link->handle, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); return -1; @@ -543,9 +548,6 @@ static int multi_config(dev_link_t * lin ======================================================================*/ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - void serial_config(dev_link_t * link) { client_handle_t handle = link->handle; @@ -619,10 +621,18 @@ void serial_config(dev_link_t * link) if (info->manfid == MANFID_IBM) { conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; - CS_CHECK(AccessConfigurationRegister, link->handle, ®); + last_ret = pcmcia_access_configuration_register(link->handle, ®); + if (last_ret) { + last_fn = AccessConfigurationRegister; + goto cs_failed; + } reg.Action = CS_WRITE; reg.Value = reg.Value | 1; - CS_CHECK(AccessConfigurationRegister, link->handle, ®); + last_ret = pcmcia_access_configuration_register(link->handle, ®); + if (last_ret) { + last_fn = AccessConfigurationRegister; + goto cs_failed; + } } link->dev = &info->node[0]; @@ -668,7 +678,7 @@ serial_event(event_t event, int priority /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if ((link->state & DEV_CONFIG) && !info->slave) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: @@ -676,8 +686,7 @@ serial_event(event_t event, int priority /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link) && !info->slave) - CardServices(RequestConfiguration, link->handle, - &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; --- linux-2.6.1-rc1/drivers/telephony/ixj_pcmcia.c 2003-09-27 18:57:46.000000000 -0700 +++ 25/drivers/telephony/ixj_pcmcia.c 2003-12-30 22:50:04.000000000 -0800 @@ -77,7 +77,7 @@ static dev_link_t *ixj_attach(void) client_reg.event_handler = &ixj_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); ixj_detach(link); @@ -100,7 +100,7 @@ static void ixj_detach(dev_link_t * link if (link->state & DEV_CONFIG) ixj_cs_release(link); if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); + ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } @@ -110,11 +110,8 @@ static void ixj_detach(dev_link_t * link kfree(link); } -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void ixj_get_serial(dev_link_t * link, IXJ * j) { @@ -130,8 +127,8 @@ static void ixj_get_serial(dev_link_t * tuple.TupleDataMax = 80; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); str = (char *) buf; printk("PCMCIA Version %d.%d\n", str[0], str[1]); str += 2; @@ -202,19 +199,20 @@ static void ixj_config(dev_link_t * link tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; link->state |= DEV_CONFIG; - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->conf.ConfigIndex = cfg->index; @@ -224,17 +222,18 @@ static void ixj_config(dev_link_t * link link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } - CFG_CHECK(RequestIO, link->handle, &link->io); + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; /* If we've got this far, we're done */ break; } next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - CS_CHECK(GetNextTuple, handle, &tuple); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } - CS_CHECK(RequestConfiguration, handle, &link->conf); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); /* * Register the card with the core. @@ -258,8 +257,8 @@ static void ixj_cs_release(dev_link_t *l DEBUG(0, "ixj_cs_release(0x%p)\n", link); info->ndev = 0; link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); link->state &= ~DEV_CONFIG; } @@ -284,14 +283,14 @@ static int ixj_event(event_t event, int /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; --- linux-2.6.1-rc1/drivers/usb/gadget/ether.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/drivers/usb/gadget/ether.c 2003-12-30 22:49:20.000000000 -0800 @@ -1782,9 +1782,7 @@ eth_bind (struct usb_gadget *gadget) /* network device setup */ dev->net = net; SET_MODULE_OWNER (net); - net->priv = dev; strcpy (net->name, "usb%d"); - ether_setup (net); /* one random address for the gadget device ... both of these could * reasonably come from an id prom or a module parameter. --- linux-2.6.1-rc1/drivers/video/aty/aty128fb.c 2003-10-17 15:58:04.000000000 -0700 +++ 25/drivers/video/aty/aty128fb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1536,6 +1536,7 @@ aty128_init(struct pci_dev *pdev, const /* fill in info */ info->fbops = &aty128fb_ops; info->flags = FBINFO_FLAG_DEFAULT; + info->dev = &pdev->dev; #ifdef CONFIG_PMAC_PBOOK par->lcd_on = default_lcd_on; --- linux-2.6.1-rc1/drivers/video/cirrusfb.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/drivers/video/cirrusfb.c 2003-12-30 22:50:07.000000000 -0800 @@ -2787,6 +2787,7 @@ int __init clgenfb_init(void) fb_info->gen.info.switch_con = &fbgen_switch; fb_info->gen.info.updatevar = &fbgen_update_var; fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; + fb_info->gen.info.dev = fb_info->pdev; for (j = 0; j < 256; j++) { if (j < 16) { --- linux-2.6.1-rc1/drivers/video/cyber2000fb.c 2003-08-08 22:55:13.000000000 -0700 +++ 25/drivers/video/cyber2000fb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1366,6 +1366,7 @@ static int __devinit cyberpro_common_pro cfb->fb.fix.smem_len = smem_size; cfb->fb.fix.mmio_len = MMIO_SIZE; cfb->fb.screen_base = cfb->region; + cfb->fb.dev = &cfb->dev->dev; err = -EINVAL; if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, --- linux-2.6.1-rc1/drivers/video/fbmem.c 2003-09-08 13:58:58.000000000 -0700 +++ 25/drivers/video/fbmem.c 2003-12-30 22:50:07.000000000 -0800 @@ -31,6 +31,7 @@ #include #endif #include +#include #if defined(__mc68000__) || defined(CONFIG_APUS) #include @@ -1199,6 +1200,10 @@ static struct file_operations fb_fops = #endif }; +static struct class fb_class = { + .name = "video", +}; + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1242,6 +1247,8 @@ register_framebuffer(struct fb_info *fb_ devfs_mk_cdev(MKDEV(FB_MAJOR, i), S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); + + simple_add_class_device(&fb_class, MKDEV(FB_MAJOR, i), fb_info->dev, "fb%d", i); return 0; } @@ -1270,6 +1277,7 @@ unregister_framebuffer(struct fb_info *f kfree(fb_info->pixmap.addr); registered_fb[i]=NULL; num_registered_fb--; + simple_remove_class_device(MKDEV(FB_MAJOR, i)); return 0; } @@ -1294,6 +1302,8 @@ fbmem_init(void) if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); + class_register(&fb_class); + #ifdef CONFIG_FB_OF if (ofonly) { offb_init(); --- linux-2.6.1-rc1/drivers/video/i810/i810_main.c 2003-09-27 18:57:46.000000000 -0700 +++ 25/drivers/video/i810/i810_main.c 2003-12-30 22:50:07.000000000 -0800 @@ -1880,6 +1880,7 @@ static int __devinit i810fb_init_pci (st info->fbops = &par->i810fb_ops; info->pseudo_palette = par->pseudo_palette; info->flags = FBINFO_FLAG_DEFAULT; + info->dev = &dev->dev; fb_alloc_cmap(&info->cmap, 256, 0); --- linux-2.6.1-rc1/drivers/video/igafb.c 2003-11-26 13:53:35.000000000 -0800 +++ 25/drivers/video/igafb.c 2003-12-30 22:50:07.000000000 -0800 @@ -332,7 +332,7 @@ static struct fb_ops igafb_ops = { #endif }; -static int __init iga_init(struct fb_info *info, struct iga_par *par) +static int __init iga_init(struct fb_info *info, struct iga_par *par, struct pci_dev *dev) { char vramsz = iga_inb(par, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) & MEM_SIZE_ALIAS; @@ -358,6 +358,7 @@ static int __init iga_init(struct fb_inf info->fbops = &igafb_ops; info->flags = FBINFO_FLAG_DEFAULT; + info->dev = &dev->dev; fb_alloc_cmap(&info->cmap, video_cmap_len, 0); @@ -529,7 +530,7 @@ int __init igafb_init(void) info->fix = igafb_fix; info->pseudo_palette = (void *)(par + 1); - if (!iga_init(info, par)) { + if (!iga_init(info, par, pdev)) { iounmap((void *)par->io_base); iounmap(info->screen_base); if (par->mmap_map) --- linux-2.6.1-rc1/drivers/video/imsttfb.c 2003-10-17 15:58:04.000000000 -0700 +++ 25/drivers/video/imsttfb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1348,7 +1348,7 @@ static struct fb_ops imsttfb_ops = { }; static void __init -init_imstt(struct fb_info *info) +init_imstt(struct fb_info *info, struct pci_dev *pdev) { struct imstt_par *par = (struct imstt_par *) info->par; __u32 i, tmp, *ip, *end; @@ -1442,6 +1442,7 @@ init_imstt(struct fb_info *info) info->fbops = &imsttfb_ops; info->flags = FBINFO_FLAG_DEFAULT; + info->dev = &pdev->dev; fb_alloc_cmap(&info->cmap, 0, 0); @@ -1520,7 +1521,7 @@ imsttfb_probe(struct pci_dev *pdev, cons par->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000); info->par = par; info->pseudo_palette = (void *) (par + 1); - init_imstt(info); + init_imstt(info, pdev); pci_set_drvdata(pdev, info); return 0; --- linux-2.6.1-rc1/drivers/video/matrox/matroxfb_crtc2.c 2003-08-08 22:55:13.000000000 -0700 +++ 25/drivers/video/matrox/matroxfb_crtc2.c 2003-12-30 22:50:07.000000000 -0800 @@ -605,6 +605,7 @@ static int matroxfb_dh_regit(CPMINFO str m2info->fbcon.flags = FBINFO_FLAG_DEFAULT; m2info->fbcon.currcon = -1; m2info->fbcon.pseudo_palette = m2info->cmap; + m2info->fbcon.dev = &m2info->primary_dev->pcidev->dev; fb_alloc_cmap(&m2info->fbcon.cmap, 256, 1); if (mem < 64) --- linux-2.6.1-rc1/drivers/video/neofb.c 2003-08-08 22:55:13.000000000 -0700 +++ 25/drivers/video/neofb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1943,6 +1943,7 @@ static struct fb_info *__devinit neo_all info->flags = FBINFO_FLAG_DEFAULT; info->par = par; info->pseudo_palette = (void *) (par + 1); + info->dev = &dev->dev; fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); --- linux-2.6.1-rc1/drivers/video/radeonfb.c 2003-11-23 19:03:01.000000000 -0800 +++ 25/drivers/video/radeonfb.c 2003-12-30 22:50:07.000000000 -0800 @@ -679,7 +679,7 @@ static __inline__ int _max(int val1, int */ static char *mode_option __initdata; -static char noaccel = 1; +static char noaccel = 0; static char mirror = 0; static int panel_yres __initdata = 0; static char force_dfp __initdata = 0; @@ -1099,7 +1099,7 @@ static int radeon_get_dfpinfo_BIOS(struc printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n", rinfo->panel_xres, rinfo->panel_yres); - for(i=0; i<20; i++) { + for(i=0; i<21; i++) { tmp0 = rinfo->bios_seg + readw(tmp+64+i*2); if (tmp0 == 0) break; @@ -1241,9 +1241,6 @@ static void radeon_engine_init (struct r radeon_fifo_wait (1); OUTREG(RB2D_DSTCACHE_MODE, 0); - /* XXX */ - rinfo->pitch = ((rinfo->xres_virtual * (rinfo->bpp / 8) + 0x3f)) >> 6; - radeon_fifo_wait (1); temp = INREG(DEFAULT_PITCH_OFFSET); OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | @@ -1782,6 +1779,7 @@ static int radeonfb_set_par (struct fb_i int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; int primary_mon = PRIMARY_MONITOR(rinfo); int depth = var_to_depth(mode); + int accel = (mode->accel_flags & FB_ACCELF_TEXT) != 0; rinfo->xres = mode->xres; rinfo->yres = mode->yres; @@ -1878,7 +1876,15 @@ static int radeonfb_set_par (struct fb_i newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23)); - newmode.crtc_pitch = (mode->xres_virtual >> 3); + if (accel) { + /* We first calculate the engine pitch */ + rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) >> 6; + + /* Then, re-multiply it to get the CRTC pitch */ + newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); + } else + newmode.crtc_pitch = (mode->xres_virtual >> 3); newmode.crtc_pitch |= (newmode.crtc_pitch << 16); #if defined(__BIG_ENDIAN) @@ -2085,18 +2091,21 @@ static int radeonfb_set_par (struct fb_i if (!rinfo->asleep) { radeon_write_mode (rinfo, &newmode); /* (re)initialize the engine */ - if (!noaccel) + if (noaccel) radeon_engine_init (rinfo); } /* Update fix */ - info->fix.line_length = rinfo->pitch*64; + if (accel) + info->fix.line_length = rinfo->pitch*64; + else + info->fix.line_length = mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8); info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; #ifdef CONFIG_BOOTX_TEXT /* Update debug text engine */ btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres, - rinfo->depth, rinfo->pitch*64); + rinfo->depth, info->fix.line_length); #endif return 0; @@ -3022,17 +3031,13 @@ static int radeonfb_pci_register (struct */ radeon_save_state (rinfo, &rinfo->init_state); - if (!noaccel) { - /* initialize the engine */ - radeon_engine_init (rinfo); - } - /* set all the vital stuff */ radeon_set_fbinfo (rinfo); pci_set_drvdata(pdev, rinfo); rinfo->next = board_list; board_list = rinfo; + rinfo->info.dev = &pdev->dev; if (register_framebuffer ((struct fb_info *) rinfo) < 0) { printk ("radeonfb: could not register framebuffer\n"); --- linux-2.6.1-rc1/drivers/video/riva/fbdev.c 2003-09-27 18:57:46.000000000 -0700 +++ 25/drivers/video/riva/fbdev.c 2003-12-30 22:50:07.000000000 -0800 @@ -1751,6 +1751,7 @@ static int __devinit rivafb_probe(struct if (info->pixmap.addr == NULL) goto err_out_kfree1; memset(info->pixmap.addr, 0, 64 * 1024); + info->dev = &pd->dev; strcat(rivafb_fix.id, rci->name); default_par->riva.Architecture = rci->arch_rev; --- linux-2.6.1-rc1/drivers/video/sis/sis_main.c 2003-06-14 12:18:25.000000000 -0700 +++ 25/drivers/video/sis/sis_main.c 2003-12-30 22:50:07.000000000 -0800 @@ -4507,6 +4507,7 @@ int __init sisfb_init(void) sis_fb_info.par = &ivideo; sis_fb_info.screen_base = ivideo.video_vbase; sis_fb_info.fbops = &sisfb_ops; + sis_fb_info.dev = &pdev->dev; sisfb_get_fix(&sis_fb_info.fix, -1, &sis_fb_info); sis_fb_info.pseudo_palette = pseudo_palette; --- linux-2.6.1-rc1/drivers/video/sstfb.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/video/sstfb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1477,6 +1477,7 @@ static int __devinit sstfb_probe(struct info->fbops = &sstfb_ops; info->currcon = -1; info->pseudo_palette = &all->pseudo_palette; + info->dev = &pdev->dev; fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_TRUECOLOR; --- linux-2.6.1-rc1/drivers/video/tdfxfb.c 2003-08-08 22:55:13.000000000 -0700 +++ 25/drivers/video/tdfxfb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1248,6 +1248,7 @@ static int __devinit tdfxfb_probe(struct info->par = default_par; info->pseudo_palette = (void *)(default_par + 1); info->flags = FBINFO_FLAG_DEFAULT; + info->dev = &pdev->dev; #ifndef MODULE if (!mode_option) --- linux-2.6.1-rc1/drivers/video/tgafb.c 2003-06-14 12:18:28.000000000 -0700 +++ 25/drivers/video/tgafb.c 2003-12-30 22:50:07.000000000 -0800 @@ -1430,6 +1430,7 @@ tgafb_pci_register(struct pci_dev *pdev, all->info.currcon = -1; all->info.par = &all->par; all->info.pseudo_palette = all->pseudo_palette; + all->info.dev = &pdev->dev; /* This should give a reasonable default video mode. */ --- linux-2.6.1-rc1/drivers/video/tridentfb.c 2003-10-17 15:58:04.000000000 -0700 +++ 25/drivers/video/tridentfb.c 2003-12-30 22:50:08.000000000 -0800 @@ -723,7 +723,7 @@ static int tridentfb_check_var(struct fb if (bpp == 24 ) bpp = var->bits_per_pixel = 32; /* check whether resolution fits on panel and in memory*/ - if (var->xres > nativex) + if (flatpanel && nativex && var->xres > nativex) return -EINVAL; if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len) return -EINVAL; @@ -1156,6 +1156,7 @@ static int __devinit trident_pci_probe(s default_var.accel_flags &= ~FB_ACCELF_TEXT; default_var.activate |= FB_ACTIVATE_NOW; fb_info.var = default_var; + fb_info.dev = &dev->dev; if (register_framebuffer(&fb_info) < 0) { output("Could not register Trident framebuffer\n"); return -EINVAL; --- linux-2.6.1-rc1/fs/aio.c 2003-11-23 19:03:01.000000000 -0800 +++ 25/fs/aio.c 2003-12-30 22:50:25.000000000 -0800 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -38,6 +40,9 @@ #define dprintk(x...) do { ; } while (0) #endif +long aio_run = 0; /* for testing only */ +long aio_wakeups = 0; /* for testing only */ + /*------ sysctl variables----*/ atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */ unsigned aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ @@ -47,6 +52,7 @@ static kmem_cache_t *kiocb_cachep; static kmem_cache_t *kioctx_cachep; static struct workqueue_struct *aio_wq; +static struct workqueue_struct *aio_fput_wq; /* Used for rare fput completion. */ static void aio_fput_routine(void *); @@ -74,6 +80,7 @@ static int __init aio_setup(void) panic("unable to create kioctx cache"); aio_wq = create_workqueue("aio"); + aio_fput_wq = create_workqueue("aio_fput"); pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page)); @@ -281,6 +288,7 @@ static void aio_cancel_all(struct kioctx struct kiocb *iocb = list_kiocb(pos); list_del_init(&iocb->ki_list); cancel = iocb->ki_cancel; + kiocbSetCancelled(iocb); if (cancel) { iocb->ki_users++; spin_unlock_irq(&ctx->ctx_lock); @@ -341,6 +349,11 @@ void exit_aio(struct mm_struct *mm) aio_cancel_all(ctx); wait_for_all_aios(ctx); + /* + * this is an overkill, but ensures we don't leave + * the ctx on the aio_wq + */ + flush_workqueue(aio_wq); if (1 != atomic_read(&ctx->users)) printk(KERN_DEBUG @@ -400,6 +413,7 @@ static struct kiocb *__aio_get_req(struc req->ki_cancel = NULL; req->ki_retry = NULL; req->ki_user_obj = NULL; + INIT_LIST_HEAD(&req->ki_run_list); /* Check if the completion queue has enough free space to * accept an event from this io. @@ -499,7 +513,7 @@ static int __aio_put_req(struct kioctx * spin_lock(&fput_lock); list_add(&req->ki_list, &fput_head); spin_unlock(&fput_lock); - queue_work(aio_wq, &fput_work); + queue_work(aio_fput_wq, &fput_work); } else really_put_req(ctx, req); return 1; @@ -541,65 +555,324 @@ struct kioctx *lookup_ioctx(unsigned lon return ioctx; } +/* + * use_mm + * Makes the calling kernel thread take on the specified + * mm context. + * Called by the retry thread execute retries within the + * iocb issuer's mm context, so that copy_from/to_user + * operations work seamlessly for aio. + * (Note: this routine is intended to be called only + * from a kernel thread context) + */ static void use_mm(struct mm_struct *mm) { - struct mm_struct *active_mm = current->active_mm; + struct mm_struct *active_mm; + struct task_struct *tsk = current; + + task_lock(tsk); + active_mm = tsk->active_mm; atomic_inc(&mm->mm_count); - current->mm = mm; - if (mm != active_mm) { - current->active_mm = mm; - activate_mm(active_mm, mm); - } + tsk->mm = mm; + tsk->active_mm = mm; + activate_mm(active_mm, mm); + task_unlock(tsk); + mmdrop(active_mm); } -static void unuse_mm(struct mm_struct *mm) +/* + * unuse_mm + * Reverses the effect of use_mm, i.e. releases the + * specified mm context which was earlier taken on + * by the calling kernel thread + * (Note: this routine is intended to be called only + * from a kernel thread context) + * + * Comments: Called with ctx->ctx_lock held. This nests + * task_lock instead ctx_lock. + */ +void unuse_mm(struct mm_struct *mm) { - current->mm = NULL; + struct task_struct *tsk = current; + + task_lock(tsk); + tsk->mm = NULL; /* active_mm is still 'mm' */ - enter_lazy_tlb(mm, current); + enter_lazy_tlb(mm, tsk); + task_unlock(tsk); } -/* Run on kevent's context. FIXME: needs to be per-cpu and warn if an - * operation blocks. +/* + * Queue up a kiocb to be retried. Assumes that the kiocb + * has already been marked as kicked, and places it on + * the retry run list for the corresponding ioctx, if it + * isn't already queued. Returns 1 if it actually queued + * the kiocb (to tell the caller to activate the work + * queue to process it), or 0, if it found that it was + * already queued. + * + * Should be called with the spin lock iocb->ki_ctx->ctx_lock + * held */ -static void aio_kick_handler(void *data) +static inline int __queue_kicked_iocb(struct kiocb *iocb) { - struct kioctx *ctx = data; + struct kioctx *ctx = iocb->ki_ctx; - use_mm(ctx->mm); + if (list_empty(&iocb->ki_run_list)) { + list_add_tail(&iocb->ki_run_list, + &ctx->run_list); + iocb->ki_queued++; + return 1; + } + return 0; +} - spin_lock_irq(&ctx->ctx_lock); - while (!list_empty(&ctx->run_list)) { - struct kiocb *iocb; - long ret; +/* aio_run_iocb + * This is the core aio execution routine. It is + * invoked both for initial i/o submission and + * subsequent retries via the aio_kick_handler. + * Expects to be invoked with iocb->ki_ctx->lock + * already held. The lock is released and reaquired + * as needed during processing. + * + * Calls the iocb retry method (already setup for the + * iocb on initial submission) for operation specific + * handling, but takes care of most of common retry + * execution details for a given iocb. The retry method + * needs to be non-blocking as far as possible, to avoid + * holding up other iocbs waiting to be serviced by the + * retry kernel thread. + * + * The trickier parts in this code have to do with + * ensuring that only one retry instance is in progress + * for a given iocb at any time. Providing that guarantee + * simplifies the coding of individual aio operations as + * it avoids various potential races. + */ +static ssize_t aio_run_iocb(struct kiocb *iocb) +{ + struct kioctx *ctx = iocb->ki_ctx; + ssize_t (*retry)(struct kiocb *); + ssize_t ret; - iocb = list_entry(ctx->run_list.next, struct kiocb, - ki_run_list); - list_del(&iocb->ki_run_list); - iocb->ki_users ++; - spin_unlock_irq(&ctx->ctx_lock); + if (iocb->ki_retried++ > 1024*1024) { + printk("Maximal retry count. Bytes done %Zd\n", + iocb->ki_nbytes - iocb->ki_left); + return -EAGAIN; + } - kiocbClearKicked(iocb); - ret = iocb->ki_retry(iocb); + if (!(iocb->ki_retried & 0xff)) { + pr_debug("%ld retry: %d of %d (kick %ld, Q %ld run %ld, wake %ld)\n", + iocb->ki_retried, + iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes, + iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups); + } + + if (!(retry = iocb->ki_retry)) { + printk("aio_run_iocb: iocb->ki_retry = NULL\n"); + return 0; + } + + /* + * We don't want the next retry iteration for this + * operation to start until this one has returned and + * updated the iocb state. However, wait_queue functions + * can trigger a kick_iocb from interrupt context in the + * meantime, indicating that data is available for the next + * iteration. We want to remember that and enable the + * next retry iteration _after_ we are through with + * this one. + * + * So, in order to be able to register a "kick", but + * prevent it from being queued now, we clear the kick + * flag, but make the kick code *think* that the iocb is + * still on the run list until we are actually done. + * When we are done with this iteration, we check if + * the iocb was kicked in the meantime and if so, queue + * it up afresh. + */ + + kiocbClearKicked(iocb); + + /* + * This is so that aio_complete knows it doesn't need to + * pull the iocb off the run list (We can't just call + * INIT_LIST_HEAD because we don't want a kick_iocb to + * queue this on the run list yet) + */ + iocb->ki_run_list.next = iocb->ki_run_list.prev = NULL; + iocb->ki_retry = NULL; + spin_unlock_irq(&ctx->ctx_lock); + + /* Quit retrying if the i/o has been cancelled */ + if (kiocbIsCancelled(iocb)) { + ret = -EINTR; + aio_complete(iocb, ret, 0); + /* must not access the iocb after this */ + goto out; + } + + /* + * Now we are all set to call the retry method in async + * context. By setting this thread's io_wait context + * to point to the wait queue entry inside the currently + * running iocb for the duration of the retry, we ensure + * that async notification wakeups are queued by the + * operation instead of blocking waits, and when notified, + * cause the iocb to be kicked for continuation (through + * the aio_wake_function callback). + */ + BUG_ON(current->io_wait != NULL); + current->io_wait = &iocb->ki_wait; + ret = retry(iocb); + current->io_wait = NULL; + + if (-EIOCBRETRY != ret) { if (-EIOCBQUEUED != ret) { + BUG_ON(!list_empty(&iocb->ki_wait.task_list)); aio_complete(iocb, ret, 0); - iocb = NULL; + /* must not access the iocb after this */ } + } else { + /* + * Issue an additional retry to avoid waiting forever if + * no waits were queued (e.g. in case of a short read). + */ + if (list_empty(&iocb->ki_wait.task_list)) + kiocbSetKicked(iocb); + } +out: + spin_lock_irq(&ctx->ctx_lock); - spin_lock_irq(&ctx->ctx_lock); - if (NULL != iocb) - __aio_put_req(ctx, iocb); + if (-EIOCBRETRY == ret) { + /* + * OK, now that we are done with this iteration + * and know that there is more left to go, + * this is where we let go so that a subsequent + * "kick" can start the next iteration + */ + iocb->ki_retry = retry; + /* will make __queue_kicked_iocb succeed from here on */ + INIT_LIST_HEAD(&iocb->ki_run_list); + /* we must queue the next iteration ourselves, if it + * has already been kicked */ + if (kiocbIsKicked(iocb)) { + __queue_kicked_iocb(iocb); + } } + return ret; +} + +/* + * __aio_run_iocbs: + * Process all pending retries queued on the ioctx + * run list. + * Assumes it is operating within the aio issuer's mm + * context. Expects to be called with ctx->ctx_lock held + */ +static int __aio_run_iocbs(struct kioctx *ctx) +{ + struct kiocb *iocb; + int count = 0; + LIST_HEAD(run_list); + + list_splice_init(&ctx->run_list, &run_list); + while (!list_empty(&run_list)) { + iocb = list_entry(run_list.next, struct kiocb, + ki_run_list); + list_del(&iocb->ki_run_list); + /* + * Hold an extra reference while retrying i/o. + */ + iocb->ki_users++; /* grab extra reference */ + aio_run_iocb(iocb); + if (__aio_put_req(ctx, iocb)) /* drop extra ref */ + put_ioctx(ctx); + count++; + } + aio_run++; + if (!list_empty(&ctx->run_list)) + return 1; + return 0; +} + +/* + * aio_run_iocbs: + * Process all pending retries queued on the ioctx + * run list. + * Assumes it is operating within the aio issuer's mm + * context. + */ +static inline void aio_run_iocbs(struct kioctx *ctx) +{ + int requeue; + + spin_lock_irq(&ctx->ctx_lock); + requeue = __aio_run_iocbs(ctx); spin_unlock_irq(&ctx->ctx_lock); + if (requeue) + queue_work(aio_wq, &ctx->wq); +} +/* + * aio_kick_handler: + * Work queue handler triggered to process pending + * retries on an ioctx. Takes on the aio issuer's + * mm context before running the iocbs, so that + * copy_xxx_user operates on the issuer's address + * space. + * Run on aiod's context. + */ +static void aio_kick_handler(void *data) +{ + struct kioctx *ctx = data; + mm_segment_t oldfs = get_fs(); + int requeue; + + set_fs(USER_DS); + use_mm(ctx->mm); + spin_lock_irq(&ctx->ctx_lock); + requeue = __aio_run_iocbs(ctx); unuse_mm(ctx->mm); + spin_unlock_irq(&ctx->ctx_lock); + set_fs(oldfs); + if (requeue) + queue_work(aio_wq, &ctx->wq); } -void kick_iocb(struct kiocb *iocb) + +/* + * Called by kick_iocb to queue the kiocb for retry + * and if required activate the aio work queue to process + * it + */ +void queue_kicked_iocb(struct kiocb *iocb) { struct kioctx *ctx = iocb->ki_ctx; + unsigned long flags; + int run = 0; + + WARN_ON((!list_empty(&iocb->ki_wait.task_list))); + spin_lock_irqsave(&ctx->ctx_lock, flags); + run = __queue_kicked_iocb(iocb); + spin_unlock_irqrestore(&ctx->ctx_lock, flags); + if (run) { + queue_work(aio_wq, &ctx->wq); + aio_wakeups++; + } +} + +/* + * kick_iocb: + * Called typically from a wait queue callback context + * (aio_wake_function) to trigger a retry of the iocb. + * The retry is usually executed by aio workqueue + * threads (See aio_kick_handler). + */ +void kick_iocb(struct kiocb *iocb) +{ /* sync iocbs are easy: they can only ever be executing from a * single context. */ if (is_sync_kiocb(iocb)) { @@ -608,12 +881,10 @@ void kick_iocb(struct kiocb *iocb) return; } + iocb->ki_kicked++; + /* If its already kicked we shouldn't queue it again */ if (!kiocbTryKick(iocb)) { - unsigned long flags; - spin_lock_irqsave(&ctx->ctx_lock, flags); - list_add_tail(&iocb->ki_run_list, &ctx->run_list); - spin_unlock_irqrestore(&ctx->ctx_lock, flags); - schedule_work(&ctx->wq); + queue_kicked_iocb(iocb); } } @@ -666,6 +937,9 @@ int aio_complete(struct kiocb *iocb, lon */ spin_lock_irqsave(&ctx->ctx_lock, flags); + if (iocb->ki_run_list.prev && !list_empty(&iocb->ki_run_list)) + list_del_init(&iocb->ki_run_list); + ring = kmap_atomic(info->ring_pages[0], KM_IRQ1); tail = info->tail; @@ -694,6 +968,11 @@ int aio_complete(struct kiocb *iocb, lon pr_debug("added to ring %p at [%lu]\n", iocb, tail); + pr_debug("%ld retries: %d of %d (kicked %ld, Q %ld run %ld wake %ld)\n", + iocb->ki_retried, + iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes, + iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups); + /* everything turned out well, dispose of the aiocb. */ ret = __aio_put_req(ctx, iocb); @@ -808,6 +1087,7 @@ static int read_events(struct kioctx *ct int i = 0; struct io_event ent; struct timeout to; + int event_loop = 0; /* testing only */ /* needed to zero any padding within an entry (there shouldn't be * any, but C is fun! @@ -857,7 +1137,6 @@ static int read_events(struct kioctx *ct add_wait_queue_exclusive(&ctx->wait, &wait); do { set_task_state(tsk, TASK_INTERRUPTIBLE); - ret = aio_read_evt(ctx, &ent); if (ret) break; @@ -867,6 +1146,7 @@ static int read_events(struct kioctx *ct if (to.timed_out) /* Only check after read evt */ break; schedule(); + event_loop++; if (signal_pending(tsk)) { ret = -EINTR; break; @@ -894,6 +1174,9 @@ static int read_events(struct kioctx *ct if (timeout) clear_timeout(&to); out: + pr_debug("event loop executed %d times\n", event_loop); + pr_debug("aio_run %ld\n", aio_run); + pr_debug("aio_wakeups %ld\n", aio_wakeups); return i ? i : ret; } @@ -923,6 +1206,11 @@ static void io_destroy(struct kioctx *io aio_cancel_all(ioctx); wait_for_all_aios(ioctx); + /* + * this is an overkill, but ensures we don't leave + * the ctx on the aio_wq + */ + flush_workqueue(aio_wq); put_ioctx(ioctx); /* once for the lookup */ } @@ -985,13 +1273,191 @@ asmlinkage long sys_io_destroy(aio_conte return -EINVAL; } +/* + * Retry method for aio_read (also used for first time submit) + * Responsible for updating iocb state as retries progress + */ +static ssize_t aio_pread(struct kiocb *iocb) +{ + struct file *file = iocb->ki_filp; + ssize_t ret = 0; + + ret = file->f_op->aio_read(iocb, iocb->ki_buf, + iocb->ki_left, iocb->ki_pos); + + /* + * Can't just depend on iocb->ki_left to determine + * whether we are done. This may have been a short read. + */ + if (ret > 0) { + iocb->ki_buf += ret; + iocb->ki_left -= ret; + + ret = -EIOCBRETRY; + } + + /* This means we must have transferred all that we could */ + /* No need to retry anymore */ + if ((ret == 0) || (iocb->ki_left == 0)) + ret = iocb->ki_nbytes - iocb->ki_left; + + return ret; +} + +/* + * Retry method for aio_write (also used for first time submit) + * Responsible for updating iocb state as retries progress + */ +static ssize_t aio_pwrite(struct kiocb *iocb) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret = 0; + + ret = file->f_op->aio_write(iocb, iocb->ki_buf, + iocb->ki_left, iocb->ki_pos); + + /* + * Even if iocb->ki_left = 0, we may need to wait + * for a balance_dirty_pages to complete + */ + if (ret > 0) { + iocb->ki_buf += iocb->ki_buf ? ret : 0; + iocb->ki_left -= ret; + + ret = -EIOCBRETRY; + } + + /* This means we must have transferred all that we could */ + /* No need to retry anymore unless we need to osync data */ + if (ret == 0) { + ret = iocb->ki_nbytes - iocb->ki_left; + if (!iocb->ki_buf) + return ret; + + /* Set things up for potential O_SYNC */ + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + iocb->ki_buf = NULL; + iocb->ki_pos -= ret; /* back up fpos */ + iocb->ki_left = ret; /* sync what we have written out */ + iocb->ki_nbytes = ret; + ret = -EIOCBRETRY; + } + } + + return ret; +} + +static ssize_t aio_fdsync(struct kiocb *iocb) +{ + struct file *file = iocb->ki_filp; + ssize_t ret = -EINVAL; + + if (file->f_op->aio_fsync) + ret = file->f_op->aio_fsync(iocb, 1); + return ret; +} + +static ssize_t aio_fsync(struct kiocb *iocb) +{ + struct file *file = iocb->ki_filp; + ssize_t ret = -EINVAL; + + if (file->f_op->aio_fsync) + ret = file->f_op->aio_fsync(iocb, 0); + return ret; +} + +/* + * aio_setup_iocb: + * Performs the initial checks and aio retry method + * setup for the kiocb at the time of io submission. + */ +ssize_t aio_setup_iocb(struct kiocb *kiocb) +{ + struct file *file = kiocb->ki_filp; + ssize_t ret = 0; + + switch (kiocb->ki_opcode) { + case IOCB_CMD_PREAD: + ret = -EBADF; + if (unlikely(!(file->f_mode & FMODE_READ))) + break; + ret = -EFAULT; + if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf, + kiocb->ki_left))) + break; + ret = -EINVAL; + if (file->f_op->aio_read) + kiocb->ki_retry = aio_pread; + break; + case IOCB_CMD_PWRITE: + ret = -EBADF; + if (unlikely(!(file->f_mode & FMODE_WRITE))) + break; + ret = -EFAULT; + if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf, + kiocb->ki_left))) + break; + ret = -EINVAL; + if (file->f_op->aio_write) + kiocb->ki_retry = aio_pwrite; + break; + case IOCB_CMD_FDSYNC: + ret = -EINVAL; + if (file->f_op->aio_fsync) + kiocb->ki_retry = aio_fdsync; + break; + case IOCB_CMD_FSYNC: + ret = -EINVAL; + if (file->f_op->aio_fsync) + kiocb->ki_retry = aio_fsync; + break; + default: + dprintk("EINVAL: io_submit: no operation provided\n"); + ret = -EINVAL; + } + + if (!kiocb->ki_retry) + return ret; + + return 0; +} + +/* + * aio_wake_function: + * wait queue callback function for aio notification, + * Simply triggers a retry of the operation via kick_iocb. + * + * This callback is specified in the wait queue entry in + * a kiocb (current->io_wait points to this wait queue + * entry when an aio operation executes; it is used + * instead of a synchronous wait when an i/o blocking + * condition is encountered during aio). + * + * Note: + * This routine is executed with the wait queue lock held. + * Since kick_iocb acquires iocb->ctx->ctx_lock, it nests + * the ioctx lock inside the wait queue lock. This is safe + * because this callback isn't used for wait queues which + * are nested inside ioctx lock (i.e. ctx->wait) + */ +int aio_wake_function(wait_queue_t *wait, unsigned mode, int sync) +{ + struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait); + + list_del_init(&wait->task_list); + kick_iocb(iocb); + return 1; +} + int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, struct iocb *iocb) { struct kiocb *req; struct file *file; ssize_t ret; - char *buf; /* enforce forwards compatibility on users */ if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 || @@ -1032,52 +1498,31 @@ int io_submit_one(struct kioctx *ctx, st req->ki_user_data = iocb->aio_data; req->ki_pos = iocb->aio_offset; - buf = (char *)(unsigned long)iocb->aio_buf; + req->ki_buf = (char *)(unsigned long)iocb->aio_buf; + req->ki_left = req->ki_nbytes = iocb->aio_nbytes; + req->ki_opcode = iocb->aio_lio_opcode; + init_waitqueue_func_entry(&req->ki_wait, aio_wake_function); + INIT_LIST_HEAD(&req->ki_wait.task_list); + req->ki_run_list.next = req->ki_run_list.prev = NULL; + req->ki_retry = NULL; + req->ki_retried = 0; + req->ki_kicked = 0; + req->ki_queued = 0; + aio_run = 0; + aio_wakeups = 0; - switch (iocb->aio_lio_opcode) { - case IOCB_CMD_PREAD: - ret = -EBADF; - if (unlikely(!(file->f_mode & FMODE_READ))) - goto out_put_req; - ret = -EFAULT; - if (unlikely(!access_ok(VERIFY_WRITE, buf, iocb->aio_nbytes))) - goto out_put_req; - ret = -EINVAL; - if (file->f_op->aio_read) - ret = file->f_op->aio_read(req, buf, - iocb->aio_nbytes, req->ki_pos); - break; - case IOCB_CMD_PWRITE: - ret = -EBADF; - if (unlikely(!(file->f_mode & FMODE_WRITE))) - goto out_put_req; - ret = -EFAULT; - if (unlikely(!access_ok(VERIFY_READ, buf, iocb->aio_nbytes))) - goto out_put_req; - ret = -EINVAL; - if (file->f_op->aio_write) - ret = file->f_op->aio_write(req, buf, - iocb->aio_nbytes, req->ki_pos); - break; - case IOCB_CMD_FDSYNC: - ret = -EINVAL; - if (file->f_op->aio_fsync) - ret = file->f_op->aio_fsync(req, 1); - break; - case IOCB_CMD_FSYNC: - ret = -EINVAL; - if (file->f_op->aio_fsync) - ret = file->f_op->aio_fsync(req, 0); - break; - default: - dprintk("EINVAL: io_submit: no operation provided\n"); - ret = -EINVAL; - } + ret = aio_setup_iocb(req); + + if (ret) + goto out_put_req; + + spin_lock_irq(&ctx->ctx_lock); + ret = aio_run_iocb(req); + spin_unlock_irq(&ctx->ctx_lock); + if (-EIOCBRETRY == ret) + queue_work(aio_wq, &ctx->wq); aio_put_req(req); /* drop extra ref to req */ - if (likely(-EIOCBQUEUED == ret)) - return 0; - aio_complete(req, ret, 0); /* will drop i/o ref to req */ return 0; out_put_req: --- linux-2.6.1-rc1/fs/block_dev.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/block_dev.c 2003-12-30 22:49:38.000000000 -0800 @@ -25,6 +25,22 @@ #include #include +struct bdev_inode { + struct block_device bdev; + struct inode vfs_inode; +}; + +static inline struct bdev_inode *BDEV_I(struct inode *inode) +{ + return container_of(inode, struct bdev_inode, vfs_inode); +} + +inline struct block_device *I_BDEV(struct inode *inode) +{ + return &BDEV_I(inode)->bdev; +} + +EXPORT_SYMBOL(I_BDEV); static sector_t max_block(struct block_device *bdev) { @@ -100,10 +116,10 @@ static int blkdev_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create) { - if (iblock >= max_block(inode->i_bdev)) + if (iblock >= max_block(I_BDEV(inode))) return -EIO; - bh->b_bdev = inode->i_bdev; + bh->b_bdev = I_BDEV(inode); bh->b_blocknr = iblock; set_buffer_mapped(bh); return 0; @@ -113,10 +129,10 @@ static int blkdev_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks, struct buffer_head *bh, int create) { - if ((iblock + max_blocks) > max_block(inode->i_bdev)) + if ((iblock + max_blocks) > max_block(I_BDEV(inode))) return -EIO; - bh->b_bdev = inode->i_bdev; + bh->b_bdev = I_BDEV(inode); bh->b_blocknr = iblock; bh->b_size = max_blocks << inode->i_blkbits; set_buffer_mapped(bh); @@ -128,9 +144,9 @@ blkdev_direct_IO(int rw, struct kiocb *i loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; - return blockdev_direct_IO(rw, iocb, inode, inode->i_bdev, iov, offset, + return blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset, nr_segs, blkdev_get_blocks, NULL); } @@ -161,11 +177,10 @@ static int blkdev_commit_write(struct fi */ static loff_t block_llseek(struct file *file, loff_t offset, int origin) { - struct inode *bd_inode; + struct inode *bd_inode = file->f_mapping->host; loff_t size; loff_t retval; - bd_inode = file->f_dentry->d_inode->i_bdev->bd_inode; down(&bd_inode->i_sem); size = i_size_read(bd_inode); @@ -188,15 +203,13 @@ static loff_t block_llseek(struct file * } /* - * Filp may be NULL when we are called by an msync of a vma - * since the vma has no handle. + * Filp is never NULL; the only case when ->fsync() is called with + * NULL first argument is nfsd_sync_dir() and that's not a directory. */ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) { - struct inode * inode = dentry->d_inode; - - return sync_blockdev(inode->i_bdev); + return sync_blockdev(I_BDEV(filp->f_mapping->host)); } /* @@ -206,16 +219,6 @@ static int block_fsync(struct file *filp static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; static kmem_cache_t * bdev_cachep; -struct bdev_inode { - struct block_device bdev; - struct inode vfs_inode; -}; - -static inline struct bdev_inode *BDEV_I(struct inode *inode) -{ - return container_of(inode, struct bdev_inode, vfs_inode); -} - static struct inode *bdev_alloc_inode(struct super_block *sb) { struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, SLAB_KERNEL); @@ -387,26 +390,27 @@ void bdput(struct block_device *bdev) EXPORT_SYMBOL(bdput); -int bd_acquire(struct inode *inode) +static struct block_device *bd_acquire(struct inode *inode) { struct block_device *bdev; spin_lock(&bdev_lock); - if (inode->i_bdev && igrab(inode->i_bdev->bd_inode)) { + bdev = inode->i_bdev; + if (bdev && igrab(bdev->bd_inode)) { spin_unlock(&bdev_lock); - return 0; + return bdev; } spin_unlock(&bdev_lock); bdev = bdget(inode->i_rdev); - if (!bdev) - return -ENOMEM; - spin_lock(&bdev_lock); - if (inode->i_bdev) - __bd_forget(inode); - inode->i_bdev = bdev; - inode->i_mapping = bdev->bd_inode->i_mapping; - list_add(&inode->i_devices, &bdev->bd_inodes); - spin_unlock(&bdev_lock); - return 0; + if (bdev) { + spin_lock(&bdev_lock); + if (inode->i_bdev) + __bd_forget(inode); + inode->i_bdev = bdev; + inode->i_mapping = bdev->bd_inode->i_mapping; + list_add(&inode->i_devices, &bdev->bd_inodes); + spin_unlock(&bdev_lock); + } + return bdev; } /* Call when you free inode */ @@ -531,13 +535,14 @@ static void bd_set_size(struct block_dev bdev->bd_inode->i_blkbits = blksize_bits(bsize); } -static int do_open(struct block_device *bdev, struct inode *inode, struct file *file) +static int do_open(struct block_device *bdev, struct file *file) { struct module *owner = NULL; struct gendisk *disk; int ret = -ENXIO; int part; + file->f_mapping = bdev->bd_inode->i_mapping; lock_kernel(); disk = get_gendisk(bdev->bd_dev, &part); if (!disk) { @@ -554,7 +559,7 @@ static int do_open(struct block_device * if (!part) { struct backing_dev_info *bdi; if (disk->fops->open) { - ret = disk->fops->open(inode, file); + ret = disk->fops->open(bdev, file); if (ret) goto out_first; } @@ -599,7 +604,7 @@ static int do_open(struct block_device * module_put(owner); if (bdev->bd_contains == bdev) { if (bdev->bd_disk->fops->open) { - ret = bdev->bd_disk->fops->open(inode, file); + ret = bdev->bd_disk->fops->open(bdev, file); if (ret) goto out; } @@ -647,7 +652,7 @@ int blkdev_get(struct block_device *bdev fake_file.f_dentry = &fake_dentry; fake_dentry.d_inode = bdev->bd_inode; - return do_open(bdev, bdev->bd_inode, &fake_file); + return do_open(bdev, &fake_file); } EXPORT_SYMBOL(blkdev_get); @@ -665,10 +670,9 @@ int blkdev_open(struct inode * inode, st */ filp->f_flags |= O_LARGEFILE; - bd_acquire(inode); - bdev = inode->i_bdev; + bdev = bd_acquire(inode); - res = do_open(bdev, inode, filp); + res = do_open(bdev, filp); if (res) return res; @@ -687,7 +691,6 @@ EXPORT_SYMBOL(blkdev_open); int blkdev_put(struct block_device *bdev, int kind) { int ret = 0; - struct inode *bd_inode = bdev->bd_inode; struct gendisk *disk = bdev->bd_disk; down(&bdev->bd_sem); @@ -696,14 +699,14 @@ int blkdev_put(struct block_device *bdev switch (kind) { case BDEV_FILE: case BDEV_FS: - sync_blockdev(bd_inode->i_bdev); + sync_blockdev(bdev); break; } kill_bdev(bdev); } if (bdev->bd_contains == bdev) { if (disk->fops->release) - ret = disk->fops->release(bd_inode, NULL); + ret = disk->fops->release(disk); } else { down(&bdev->bd_contains->bd_sem); bdev->bd_contains->bd_part_count--; @@ -734,11 +737,12 @@ int blkdev_put(struct block_device *bdev EXPORT_SYMBOL(blkdev_put); -int blkdev_close(struct inode * inode, struct file * filp) +static int blkdev_close(struct inode * inode, struct file * filp) { - if (inode->i_bdev->bd_holder == filp) - bd_release(inode->i_bdev); - return blkdev_put(inode->i_bdev, BDEV_FILE); + struct block_device *bdev = I_BDEV(filp->f_mapping->host); + if (bdev->bd_holder == filp) + bd_release(bdev); + return blkdev_put(bdev, BDEV_FILE); } static ssize_t blkdev_file_write(struct file *file, const char __user *buf, @@ -757,6 +761,11 @@ static ssize_t blkdev_file_aio_write(str return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); } +static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd, + unsigned long arg) +{ + return blkdev_ioctl(I_BDEV(file->f_mapping->host), file, cmd, arg); +} struct address_space_operations def_blk_aops = { .readpage = blkdev_readpage, @@ -778,7 +787,7 @@ struct file_operations def_blk_fops = { .aio_write = blkdev_file_aio_write, .mmap = generic_file_mmap, .fsync = block_fsync, - .ioctl = blkdev_ioctl, + .ioctl = block_ioctl, .readv = generic_file_readv, .writev = generic_file_writev, .sendfile = generic_file_sendfile, @@ -791,7 +800,7 @@ int ioctl_by_bdev(struct block_device *b int res; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - res = blkdev_ioctl(bdev->bd_inode, NULL, cmd, arg); + res = blkdev_ioctl(bdev, NULL, cmd, arg); set_fs(old_fs); return res; } @@ -828,11 +837,10 @@ struct block_device *lookup_bdev(const c error = -EACCES; if (nd.mnt->mnt_flags & MNT_NODEV) goto fail; - error = bd_acquire(inode); - if (error) + error = -ENOMEM; + bdev = bd_acquire(inode); + if (!bdev) goto fail; - bdev = inode->i_bdev; - out: path_release(&nd); return bdev; --- linux-2.6.1-rc1/fs/buffer.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/buffer.c 2003-12-30 22:50:23.000000000 -0800 @@ -116,27 +116,50 @@ void unlock_buffer(struct buffer_head *b } /* - * Block until a buffer comes unlocked. This doesn't stop it + * Wait until a buffer comes unlocked. This doesn't stop it * from becoming locked again - you have to lock it yourself * if you want to preserve its state. + * If the wait queue parameter specifies an async i/o callback, + * then instead of blocking, we just queue up the callback + * on the wait queue for async notification when the buffer gets + * unlocked. + * A NULL wait queue parameter defaults to synchronous behaviour */ -void __wait_on_buffer(struct buffer_head * bh) +int __wait_on_buffer_wq(struct buffer_head * bh, wait_queue_t *wait) { wait_queue_head_t *wqh = bh_waitq_head(bh); - DEFINE_WAIT(wait); + DEFINE_WAIT(local_wait); + + if (!wait) + wait = &local_wait; if (atomic_read(&bh->b_count) == 0 && (!bh->b_page || !PageLocked(bh->b_page))) buffer_error(); do { - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE); if (buffer_locked(bh)) { blk_run_queues(); + if (!is_sync_wait(wait)) { + /* + * if we've queued an async wait queue + * callback do not block; just tell the + * caller to return and retry later when + * the callback is notified + */ + return -EIOCBRETRY; + } io_schedule(); } } while (buffer_locked(bh)); - finish_wait(wqh, &wait); + finish_wait(wqh, wait); + return 0; +} + +void __wait_on_buffer(struct buffer_head * bh) +{ + __wait_on_buffer_wq(bh, NULL); } static void @@ -314,8 +337,7 @@ int file_fsync(struct file *filp, struct asmlinkage long sys_fsync(unsigned int fd) { struct file * file; - struct dentry * dentry; - struct inode * inode; + struct address_space *mapping; int ret, err; ret = -EBADF; @@ -323,8 +345,7 @@ asmlinkage long sys_fsync(unsigned int f if (!file) goto out; - dentry = file->f_dentry; - inode = dentry->d_inode; + mapping = file->f_mapping; ret = -EINVAL; if (!file->f_op || !file->f_op->fsync) { @@ -333,17 +354,17 @@ asmlinkage long sys_fsync(unsigned int f } /* We need to protect against concurrent writers.. */ - down(&inode->i_sem); + down(&mapping->host->i_sem); current->flags |= PF_SYNCWRITE; - ret = filemap_fdatawrite(inode->i_mapping); - err = file->f_op->fsync(file, dentry, 0); + ret = filemap_fdatawrite(mapping); + err = file->f_op->fsync(file, file->f_dentry, 0); if (!ret) ret = err; - err = filemap_fdatawait(inode->i_mapping); + err = filemap_fdatawait(mapping); if (!ret) ret = err; current->flags &= ~PF_SYNCWRITE; - up(&inode->i_sem); + up(&mapping->host->i_sem); out_putf: fput(file); @@ -354,8 +375,7 @@ out: asmlinkage long sys_fdatasync(unsigned int fd) { struct file * file; - struct dentry * dentry; - struct inode * inode; + struct address_space *mapping; int ret, err; ret = -EBADF; @@ -363,24 +383,23 @@ asmlinkage long sys_fdatasync(unsigned i if (!file) goto out; - dentry = file->f_dentry; - inode = dentry->d_inode; - ret = -EINVAL; if (!file->f_op || !file->f_op->fsync) goto out_putf; - down(&inode->i_sem); + mapping = file->f_mapping; + + down(&mapping->host->i_sem); current->flags |= PF_SYNCWRITE; - ret = filemap_fdatawrite(inode->i_mapping); - err = file->f_op->fsync(file, dentry, 1); + ret = filemap_fdatawrite(mapping); + err = file->f_op->fsync(file, file->f_dentry, 1); if (!ret) ret = err; - err = filemap_fdatawait(inode->i_mapping); + err = filemap_fdatawait(mapping); if (!ret) ret = err; current->flags &= ~PF_SYNCWRITE; - up(&inode->i_sem); + up(&mapping->host->i_sem); out_putf: fput(file); @@ -432,6 +451,7 @@ __find_get_block_slow(struct block_devic printk("block=%llu, b_blocknr=%llu\n", (unsigned long long)block, (unsigned long long)bh->b_blocknr); printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size); + printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits); out_unlock: spin_unlock(&bd_mapping->private_lock); page_cache_release(page); @@ -487,7 +507,7 @@ void invalidate_bdev(struct block_device */ static void free_more_memory(void) { - struct zone *zone; + struct zone **zones; pg_data_t *pgdat; wakeup_bdflush(1024); @@ -495,9 +515,9 @@ static void free_more_memory(void) yield(); for_each_pgdat(pgdat) { - zone = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones[0]; - if (zone) - try_to_free_pages(zone, GFP_NOFS, 0); + zones = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones; + if (*zones) + try_to_free_pages(zones, GFP_NOFS, 0); } } @@ -1296,9 +1316,12 @@ void __bforget(struct buffer_head *bh) __brelse(bh); } -static struct buffer_head *__bread_slow(struct buffer_head *bh) +static struct buffer_head *__bread_slow_wq(struct buffer_head *bh, + wait_queue_t *wait) { - lock_buffer(bh); + if (-EIOCBRETRY == lock_buffer_wq(bh, wait)) + return ERR_PTR(-EIOCBRETRY); + if (buffer_uptodate(bh)) { unlock_buffer(bh); return bh; @@ -1308,7 +1331,8 @@ static struct buffer_head *__bread_slow( get_bh(bh); bh->b_end_io = end_buffer_read_sync; submit_bh(READ, bh); - wait_on_buffer(bh); + if (-EIOCBRETRY == wait_on_buffer_wq(bh, wait)) + return ERR_PTR(-EIOCBRETRY); if (buffer_uptodate(bh)) return bh; } @@ -1316,6 +1340,11 @@ static struct buffer_head *__bread_slow( return NULL; } +static inline struct buffer_head *__bread_slow(struct buffer_head *bh) +{ + return __bread_slow_wq(bh, NULL); +} + /* * Per-cpu buffer LRU implementation. To reduce the cost of __find_get_block(). * The bhs[] array is sorted - newest buffer is at bhs[0]. Buffers have their @@ -1503,6 +1532,18 @@ __bread(struct block_device *bdev, secto } EXPORT_SYMBOL(__bread); +struct buffer_head * +__bread_wq(struct block_device *bdev, sector_t block, int size, + wait_queue_t *wait) +{ + struct buffer_head *bh = __getblk(bdev, block, size); + + if (!buffer_uptodate(bh)) + bh = __bread_slow_wq(bh, wait); + return bh; +} +EXPORT_SYMBOL(__bread_wq); + /* * invalidate_bh_lrus() is called rarely - at unmount. Because it is only for * unmount it only needs to ensure that all buffers from the target device are @@ -1980,8 +2021,9 @@ static int __block_prepare_write(struct /* * If we issued read requests - let them complete. */ - while(wait_bh > wait) { - wait_on_buffer(*--wait_bh); + while (wait_bh > wait) { + if ((err = wait_on_buffer_wq(*--wait_bh, current->io_wait))) + return err; if (!buffer_uptodate(*wait_bh)) return -EIO; } @@ -2944,10 +2986,8 @@ static void recalc_bh_state(void) if (__get_cpu_var(bh_accounting).ratelimit++ < 4096) return; __get_cpu_var(bh_accounting).ratelimit = 0; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_online(i)) - tot += per_cpu(bh_accounting, i).nr; - } + for_each_cpu(i) + tot += per_cpu(bh_accounting, i).nr; buffer_heads_over_limit = (tot > max_buffer_heads); } @@ -3039,6 +3079,7 @@ void __init buffer_init(void) EXPORT_SYMBOL(__bforget); EXPORT_SYMBOL(__brelse); EXPORT_SYMBOL(__wait_on_buffer); +EXPORT_SYMBOL(__wait_on_buffer_wq); EXPORT_SYMBOL(block_commit_write); EXPORT_SYMBOL(block_prepare_write); EXPORT_SYMBOL(block_read_full_page); --- linux-2.6.1-rc1/fs/coda/file.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/coda/file.c 2003-12-30 22:49:34.000000000 -0800 @@ -89,6 +89,7 @@ coda_file_mmap(struct file *coda_file, s coda_inode = coda_file->f_dentry->d_inode; host_inode = host_file->f_dentry->d_inode; + coda_file->f_mapping = host_file->f_mapping; if (coda_inode->i_mapping == &coda_inode->i_data) coda_inode->i_mapping = host_inode->i_mapping; --- linux-2.6.1-rc1/fs/cramfs/inode.c 2003-11-23 19:03:01.000000000 -0800 +++ 25/fs/cramfs/inode.c 2003-12-30 22:49:38.000000000 -0800 @@ -112,8 +112,8 @@ static int next_buffer; */ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) { - struct buffer_head * bh_array[BLKS_PER_BUF]; - struct buffer_head * read_array[BLKS_PER_BUF]; + struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + struct page *pages[BLKS_PER_BUF]; unsigned i, blocknr, buffer, unread; unsigned long devsize; char *data; @@ -138,33 +138,36 @@ static void *cramfs_read(struct super_bl return read_buffers[i] + blk_offset; } - devsize = sb->s_bdev->bd_inode->i_size >> 12; - if (!devsize) - devsize = ~0UL; + devsize = mapping->host->i_size >> PAGE_CACHE_SHIFT; /* Ok, read in BLKS_PER_BUF pages completely first. */ unread = 0; for (i = 0; i < BLKS_PER_BUF; i++) { - struct buffer_head *bh; + struct page *page = NULL; - bh = NULL; if (blocknr + i < devsize) { - bh = sb_getblk(sb, blocknr + i); - if (!buffer_uptodate(bh)) - read_array[unread++] = bh; + page = read_cache_page(mapping, blocknr + i, + (filler_t *)mapping->a_ops->readpage, + NULL); + /* synchronous error? */ + if (IS_ERR(page)) + page = NULL; } - bh_array[i] = bh; + pages[i] = page; } - if (unread) { - ll_rw_block(READ, unread, read_array); - do { - unread--; - wait_on_buffer(read_array[unread]); - } while (unread); + for (i = 0; i < BLKS_PER_BUF; i++) { + struct page *page = pages[i]; + if (page) { + wait_on_page_locked(page); + if (!PageUptodate(page)) { + /* asynchronous error */ + page_cache_release(page); + pages[i] = NULL; + } + } } - /* Ok, copy them to the staging area without sleeping. */ buffer = next_buffer; next_buffer = NEXT_BUFFER(buffer); buffer_blocknr[buffer] = blocknr; @@ -172,10 +175,11 @@ static void *cramfs_read(struct super_bl data = read_buffers[buffer]; for (i = 0; i < BLKS_PER_BUF; i++) { - struct buffer_head * bh = bh_array[i]; - if (bh) { - memcpy(data, bh->b_data, PAGE_CACHE_SIZE); - brelse(bh); + struct page *page = pages[i]; + if (page) { + memcpy(data, kmap(page), PAGE_CACHE_SIZE); + kunmap(page); + page_cache_release(page); } else memset(data, 0, PAGE_CACHE_SIZE); data += PAGE_CACHE_SIZE; @@ -202,8 +206,6 @@ static int cramfs_fill_super(struct supe sb->s_fs_info = sbi; memset(sbi, 0, sizeof(struct cramfs_sb_info)); - sb_set_blocksize(sb, PAGE_CACHE_SIZE); - /* Invalidate the read buffers on mount: think disk change.. */ down(&read_mutex); for (i = 0; i < READ_BUFFERS; i++) --- linux-2.6.1-rc1/fs/devfs/base.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/devfs/base.c 2003-12-30 22:49:37.000000000 -0800 @@ -1955,15 +1955,9 @@ static int devfs_notify_change (struct d return 0; } /* End Function devfs_notify_change */ -static void devfs_clear_inode (struct inode *inode) -{ - if ( S_ISBLK (inode->i_mode) ) bdput (inode->i_bdev); -} /* End Function devfs_clear_inode */ - static struct super_operations devfs_sops = { .drop_inode = generic_delete_inode, - .clear_inode = devfs_clear_inode, .statfs = simple_statfs, }; @@ -2015,11 +2009,7 @@ static struct inode *_devfs_get_vfs_inod inode->i_rdev = de->u.cdev.dev; } else if ( S_ISBLK (de->mode) ) - { - inode->i_rdev = de->u.bdev.dev; - if (bd_acquire (inode) != 0) - PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino); - } + init_special_inode(inode, de->mode, de->u.bdev.dev); else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops; else if ( S_ISDIR (de->mode) ) @@ -2118,11 +2108,7 @@ static int devfs_open (struct inode *ino if (de == NULL) return -ENODEV; if ( S_ISDIR (de->mode) ) return 0; file->private_data = de->info; - if ( S_ISBLK (inode->i_mode) ) - { - file->f_op = &def_blk_fops; - err = def_blk_fops.open (inode, file); /* Module refcount unchanged */ - } else if (S_ISCHR(inode->i_mode)) { + if (S_ISCHR(inode->i_mode)) { ops = devfs_get_ops (de); /* Now have module refcount */ file->f_op = ops; if (file->f_op) --- linux-2.6.1-rc1/fs/direct-io.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/direct-io.c 2003-12-30 22:50:20.000000000 -0800 @@ -52,6 +52,10 @@ * * If blkfactor is zero then the user's request was aligned to the filesystem's * blocksize. + * + * needs_locking is set for regular files on direct-IO-naive filesystems. It + * determines whether we need to do the fancy locking which prevents direct-IO + * from being able to read uninitialised disk blocks. */ struct dio { @@ -59,6 +63,7 @@ struct dio { struct bio *bio; /* bio under assembly */ struct inode *inode; int rw; + int needs_locking; /* doesn't change */ unsigned blkbits; /* doesn't change */ unsigned blkfactor; /* When we're using an alignment which is finer than the filesystem's soft @@ -204,8 +209,10 @@ static struct page *dio_get_page(struct */ static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) { - if (dio->end_io) + if (dio->end_io && dio->result) dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private); + if (dio->needs_locking) + up_read(&dio->inode->i_alloc_sem); } /* @@ -218,8 +225,14 @@ static void finished_one_bio(struct dio if (dio->is_async) { dio_complete(dio, dio->block_in_file << dio->blkbits, dio->result); - aio_complete(dio->iocb, dio->result, 0); - kfree(dio); + /* Complete AIO later if falling back to buffered i/o */ + if (dio->result != -ENOTBLK) { + aio_complete(dio->iocb, dio->result, 0); + kfree(dio); + } else { + if (dio->waiter) + wake_up_process(dio->waiter); + } } } } @@ -449,6 +462,7 @@ static int get_more_blocks(struct dio *d unsigned long fs_count; /* Number of filesystem-sized blocks */ unsigned long dio_count;/* Number of dio_block-sized blocks */ unsigned long blkmask; + int beyond_eof = 0; /* * If there was a memory error and we've overwritten all the @@ -466,8 +480,19 @@ static int get_more_blocks(struct dio *d if (dio_count & blkmask) fs_count++; + if (dio->needs_locking) { + if (dio->block_in_file >= (i_size_read(dio->inode) >> + dio->blkbits)) + beyond_eof = 1; + } + /* + * For writes inside i_size we forbid block creations: only + * overwrites are permitted. We fall back to buffered writes + * at a higher level for inside-i_size block-instantiating + * writes. + */ ret = (*dio->get_blocks)(dio->inode, fs_startblk, fs_count, - map_bh, dio->rw == WRITE); + map_bh, (dio->rw == WRITE) && beyond_eof); } return ret; } @@ -774,6 +799,10 @@ do_holes: if (!buffer_mapped(map_bh)) { char *kaddr; + /* AKPM: eargh, -ENOTBLK is a hack */ + if (dio->rw == WRITE) + return -ENOTBLK; + if (dio->block_in_file >= i_size_read(dio->inode)>>blkbits) { /* We hit eof */ @@ -839,23 +868,21 @@ out: return ret; } +/* + * Releases both i_sem and i_alloc_sem + */ static int direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, const struct iovec *iov, loff_t offset, unsigned long nr_segs, - unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io) + unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io, + struct dio *dio) { unsigned long user_addr; int seg; int ret = 0; int ret2; - struct dio *dio; size_t bytes; - dio = kmalloc(sizeof(*dio), GFP_KERNEL); - if (!dio) - return -ENOMEM; - dio->is_async = !is_sync_kiocb(iocb); - dio->bio = NULL; dio->inode = inode; dio->rw = rw; @@ -864,7 +891,6 @@ direct_io_worker(int rw, struct kiocb *i dio->start_zero_done = 0; dio->block_in_file = offset >> blkbits; dio->blocks_available = 0; - dio->cur_page = NULL; dio->boundary = 0; @@ -953,14 +979,45 @@ direct_io_worker(int rw, struct kiocb *i dio_cleanup(dio); /* + * All block lookups have been performed. For READ requests + * we can let i_sem go now that its achieved its purpose + * of protecting us from looking up uninitialized blocks. + */ + if ((rw == READ) && dio->needs_locking) + up(&dio->inode->i_sem); + + /* * OK, all BIOs are submitted, so we can decrement bio_count to truly * reflect the number of to-be-processed BIOs. */ if (dio->is_async) { if (ret == 0) ret = dio->result; /* Bytes written */ + if (ret == -ENOTBLK) { + /* + * The request will be reissued via buffered I/O + * when we return; Any I/O already issued + * effectively becomes redundant. + */ + dio->result = ret; + dio->waiter = current; + } finished_one_bio(dio); /* This can free the dio */ blk_run_queues(); + if (ret == -ENOTBLK) { + /* + * Wait for already issued I/O to drain out and + * release its references to user-space pages + * before returning to fallback on buffered I/O + */ + set_current_state(TASK_UNINTERRUPTIBLE); + while (atomic_read(&dio->bio_count)) { + io_schedule(); + set_current_state(TASK_UNINTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + dio->waiter = NULL; + } } else { finished_one_bio(dio); ret2 = dio_await_completion(dio); @@ -980,6 +1037,9 @@ direct_io_worker(int rw, struct kiocb *i ret = i_size - offset; } dio_complete(dio, offset, ret); + /* We could have also come here on an AIO file extend */ + if (!is_sync_kiocb(iocb) && (ret != -ENOTBLK)) + aio_complete(iocb, ret, 0); kfree(dio); } return ret; @@ -987,11 +1047,17 @@ direct_io_worker(int rw, struct kiocb *i /* * This is a library function for use by filesystem drivers. + * + * For writes to S_ISREG files, we are called under i_sem and return with i_sem + * held, even though it is internally dropped. + * + * For writes to S_ISBLK files, i_sem is not held on entry; it is never taken. */ int -blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, +__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, struct block_device *bdev, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io) + unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io, + int needs_special_locking) { int seg; size_t size; @@ -1000,6 +1066,9 @@ blockdev_direct_IO(int rw, struct kiocb unsigned bdev_blkbits = 0; unsigned blocksize_mask = (1 << blkbits) - 1; ssize_t retval = -EINVAL; + loff_t end = offset; + struct dio *dio; + int needs_locking; if (bdev) bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev)); @@ -1016,6 +1085,7 @@ blockdev_direct_IO(int rw, struct kiocb for (seg = 0; seg < nr_segs; seg++) { addr = (unsigned long)iov[seg].iov_base; size = iov[seg].iov_len; + end += size; if ((addr & blocksize_mask) || (size & blocksize_mask)) { if (bdev) blkbits = bdev_blkbits; @@ -1025,10 +1095,43 @@ blockdev_direct_IO(int rw, struct kiocb } } - retval = direct_io_worker(rw, iocb, inode, iov, offset, - nr_segs, blkbits, get_blocks, end_io); + dio = kmalloc(sizeof(*dio), GFP_KERNEL); + retval = -ENOMEM; + if (!dio) + goto out; + + /* + * For regular files, + * readers need to grab i_sem and i_alloc_sem + * writers need to grab i_alloc_sem only (i_sem is already held) + */ + needs_locking = 0; + if (S_ISREG(inode->i_mode) && needs_special_locking) { + needs_locking = 1; + if (rw == READ) { + down(&inode->i_sem); + retval = filemap_write_and_wait(inode->i_mapping); + if (retval) { + up(&inode->i_sem); + kfree(dio); + goto out; + } + } + down_read(&inode->i_alloc_sem); + } + dio->needs_locking = needs_locking; + /* + * For file extending writes updating i_size before data + * writeouts complete can expose uninitialized blocks. So + * even for AIO, we need to wait for i/o to complete before + * returning in this case. + */ + dio->is_async = !is_sync_kiocb(iocb) && !((rw == WRITE) && + (end > i_size_read(inode))); + + retval = direct_io_worker(rw, iocb, inode, iov, offset, + nr_segs, blkbits, get_blocks, end_io, dio); out: return retval; } - -EXPORT_SYMBOL(blockdev_direct_IO); +EXPORT_SYMBOL(__blockdev_direct_IO); --- linux-2.6.1-rc1/fs/eventpoll.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/eventpoll.c 2003-12-30 22:50:08.000000000 -0800 @@ -93,6 +93,8 @@ #define EPI_SLAB_DEBUG 0 #endif /* #if DEBUG_EPI != 0 */ +/* Epoll private bits inside the event mask */ +#define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET) /* Maximum number of poll wake up nests we are allowing */ #define EP_MAX_POLLWAKE_NESTS 4 @@ -740,6 +742,7 @@ static int ep_getfd(int *efd, struct ino d_add(dentry, inode); file->f_vfsmnt = mntget(eventpoll_mnt); file->f_dentry = dget(dentry); + file->f_mapping = inode->i_mapping; file->f_pos = 0; file->f_flags = O_RDONLY; @@ -1305,6 +1308,15 @@ static int ep_poll_callback(wait_queue_t write_lock_irqsave(&ep->lock, flags); + /* + * If the event mask does not contain any poll(2) event, we consider the + * descriptor to be disabled. This condition is likely the effect of the + * EPOLLONESHOT bit that disables the descriptor when an event is received, + * until the next EPOLL_CTL_MOD will be issued. + */ + if (!(epi->event.events & ~EP_PRIVATE_BITS)) + goto is_disabled; + /* If this file is already in the ready list we exit soon */ if (EP_IS_LINKED(&epi->rdllink)) goto is_linked; @@ -1321,6 +1333,7 @@ is_linked: if (waitqueue_active(&ep->poll_wait)) pwake++; +is_disabled: write_unlock_irqrestore(&ep->lock, flags); /* We have to call this outside the lock */ @@ -1457,6 +1470,8 @@ static int ep_send_events(struct eventpo eventcnt += eventbuf; eventbuf = 0; } + if (epi->event.events & EPOLLONESHOT) + epi->event.events &= EP_PRIVATE_BITS; } } --- linux-2.6.1-rc1/fs/ext2/inode.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/ext2/inode.c 2003-12-30 22:50:23.000000000 -0800 @@ -257,11 +257,12 @@ static int ext2_block_to_path(struct ino * or when it reads all @depth-1 indirect blocks successfully and finds * the whole chain, all way to the data (returns %NULL, *err == 0). */ -static Indirect *ext2_get_branch(struct inode *inode, +static Indirect *ext2_get_branch_wq(struct inode *inode, int depth, int *offsets, Indirect chain[4], - int *err) + int *err, + wait_queue_t *wait) { struct super_block *sb = inode->i_sb; Indirect *p = chain; @@ -273,8 +274,8 @@ static Indirect *ext2_get_branch(struct if (!p->key) goto no_block; while (--depth) { - bh = sb_bread(sb, le32_to_cpu(p->key)); - if (!bh) + bh = sb_bread_wq(sb, le32_to_cpu(p->key), wait); + if (!bh || IS_ERR(bh)) goto failure; read_lock(&EXT2_I(inode)->i_meta_lock); if (!verify_chain(chain, p)) @@ -292,11 +293,21 @@ changed: *err = -EAGAIN; goto no_block; failure: - *err = -EIO; + *err = IS_ERR(bh) ? PTR_ERR(bh) : -EIO; no_block: return p; } +static Indirect *ext2_get_branch(struct inode *inode, + int depth, + int *offsets, + Indirect chain[4], + int *err) +{ + return ext2_get_branch_wq(inode, depth, offsets, chain, + err, NULL); +} + /** * ext2_find_near - find a place for allocation with sufficient locality * @inode: owner @@ -536,7 +547,8 @@ changed: * reachable from inode. */ -static int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) +static int ext2_get_block_wq(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create, wait_queue_t *wait) { int err = -EIO; int offsets[4]; @@ -551,7 +563,8 @@ static int ext2_get_block(struct inode * goto out; reread: - partial = ext2_get_branch(inode, depth, offsets, chain, &err); + partial = ext2_get_branch_wq(inode, depth, offsets, chain, &err, + wait); /* Simplest case - block found, no allocation needed */ if (!partial) { @@ -565,7 +578,7 @@ got_it: } /* Next simple case - plain lookup or failed read of indirect block */ - if (!create || err == -EIO) { + if (!create || err == -EIO || err == -EIOCBRETRY) { cleanup: while (partial > chain) { brelse(partial->bh); @@ -606,6 +619,19 @@ changed: goto reread; } +static int ext2_get_block_async(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + return ext2_get_block_wq(inode, iblock, bh_result, create, + current->io_wait); +} + +static int ext2_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + return ext2_get_block_wq(inode, iblock, bh_result, create, NULL); +} + static int ext2_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, ext2_get_block, wbc); @@ -627,7 +653,7 @@ static int ext2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { - return block_prepare_write(page,from,to,ext2_get_block); + return block_prepare_write(page,from,to,ext2_get_block_async); } static int @@ -659,7 +685,7 @@ ext2_direct_IO(int rw, struct kiocb *ioc loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext2_get_blocks, NULL); --- linux-2.6.1-rc1/fs/ext3/inode.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/ext3/inode.c 2003-12-30 22:49:35.000000000 -0800 @@ -1532,7 +1532,7 @@ static int ext3_direct_IO(int rw, struct unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; struct ext3_inode_info *ei = EXT3_I(inode); handle_t *handle = NULL; int ret; --- linux-2.6.1-rc1/fs/fcntl.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/fcntl.c 2003-12-30 22:50:09.000000000 -0800 @@ -229,8 +229,8 @@ static int setfl(int fd, struct file * f arg |= O_NONBLOCK; if (arg & O_DIRECT) { - if (!inode->i_mapping || !inode->i_mapping->a_ops || - !inode->i_mapping->a_ops->direct_IO) + if (!filp->f_mapping || !filp->f_mapping->a_ops || + !filp->f_mapping->a_ops->direct_IO) return -EINVAL; } @@ -609,9 +609,15 @@ EXPORT_SYMBOL(__kill_fasync); void kill_fasync(struct fasync_struct **fp, int sig, int band) { - read_lock(&fasync_lock); - __kill_fasync(*fp, sig, band); - read_unlock(&fasync_lock); + /* First a quick test without locking: usually + * the list is empty. + */ + if (*fp) { + read_lock(&fasync_lock); + /* reread *fp after obtaining the lock */ + __kill_fasync(*fp, sig, band); + read_unlock(&fasync_lock); + } } EXPORT_SYMBOL(kill_fasync); --- linux-2.6.1-rc1/fs/file_table.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/file_table.c 2003-12-30 22:49:34.000000000 -0800 @@ -120,6 +120,7 @@ int open_private_file(struct file *filp, filp->f_mode = (flags+1) & O_ACCMODE; atomic_set(&filp->f_count, 1); filp->f_dentry = dentry; + filp->f_mapping = dentry->d_inode->i_mapping; filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; --- linux-2.6.1-rc1/fs/fs-writeback.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/fs-writeback.c 2003-12-30 22:49:36.000000000 -0800 @@ -514,7 +514,7 @@ EXPORT_SYMBOL(write_inode_now); * OSYNC_INODE: the inode itself */ -int generic_osync_inode(struct inode *inode, int what) +int generic_osync_inode(struct inode *inode, struct address_space *mapping, int what) { int err = 0; int need_write_inode_now = 0; @@ -522,14 +522,14 @@ int generic_osync_inode(struct inode *in current->flags |= PF_SYNCWRITE; if (what & OSYNC_DATA) - err = filemap_fdatawrite(inode->i_mapping); + err = filemap_fdatawrite(mapping); if (what & (OSYNC_METADATA|OSYNC_DATA)) { - err2 = sync_mapping_buffers(inode->i_mapping); + err2 = sync_mapping_buffers(mapping); if (!err) err = err2; } if (what & OSYNC_DATA) { - err2 = filemap_fdatawait(inode->i_mapping); + err2 = filemap_fdatawait(mapping); if (!err) err = err2; } --- linux-2.6.1-rc1/fs/hugetlbfs/inode.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/hugetlbfs/inode.c 2003-12-30 22:50:25.000000000 -0800 @@ -165,7 +165,7 @@ void truncate_hugepages(struct address_s pagevec_init(&pvec, 0); next = start; while (1) { - if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + if (!pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) { if (next == start) break; next = start; @@ -176,9 +176,6 @@ void truncate_hugepages(struct address_s struct page *page = pvec.pages[i]; lock_page(page); - if (page->index > next) - next = page->index; - ++next; truncate_huge_page(page); unlock_page(page); hugetlb_put_quota(mapping); @@ -194,6 +191,7 @@ static void hugetlbfs_delete_inode(struc hlist_del_init(&inode->i_hash); list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -236,6 +234,7 @@ static void hugetlbfs_forget_inode(struc hlist_del_init(&inode->i_hash); out_truncate: list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -788,6 +787,7 @@ struct file *hugetlb_zero_setup(size_t s inode->i_nlink = 0; file->f_vfsmnt = mntget(hugetlbfs_vfsmount); file->f_dentry = dentry; + file->f_mapping = inode->i_mapping; file->f_op = &hugetlbfs_file_operations; file->f_mode = FMODE_WRITE | FMODE_READ; return file; --- linux-2.6.1-rc1/fs/inode.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/inode.c 2003-12-30 22:50:19.000000000 -0800 @@ -183,6 +183,7 @@ void inode_init_once(struct inode *inode INIT_LIST_HEAD(&inode->i_dentry); INIT_LIST_HEAD(&inode->i_devices); sema_init(&inode->i_sem, 1); + init_rwsem(&inode->i_alloc_sem); INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); spin_lock_init(&inode->i_data.page_lock); init_MUTEX(&inode->i_data.i_shared_sem); @@ -285,7 +286,7 @@ static void dispose_list(struct list_hea /* * Invalidate all inodes for a device. */ -static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose) +static int invalidate_list(struct list_head *head, struct list_head *dispose) { struct list_head *next; int busy = 0, count = 0; @@ -298,13 +299,12 @@ static int invalidate_list(struct list_h next = next->next; if (tmp == head) break; - inode = list_entry(tmp, struct inode, i_list); - if (inode->i_sb != sb) - continue; + inode = list_entry(tmp, struct inode, i_sb_list); invalidate_inode_buffers(inode); if (!atomic_read(&inode->i_count)) { hlist_del_init(&inode->i_hash); list_del(&inode->i_list); + list_del(&inode->i_sb_list); list_add(&inode->i_list, dispose); inode->i_state |= I_FREEING; count++; @@ -340,10 +340,7 @@ int invalidate_inodes(struct super_block down(&iprune_sem); spin_lock(&inode_lock); - busy = invalidate_list(&inode_in_use, sb, &throw_away); - busy |= invalidate_list(&inode_unused, sb, &throw_away); - busy |= invalidate_list(&sb->s_dirty, sb, &throw_away); - busy |= invalidate_list(&sb->s_io, sb, &throw_away); + busy = invalidate_list(&sb->s_inodes, &throw_away); spin_unlock(&inode_lock); dispose_list(&throw_away); @@ -443,6 +440,7 @@ static void prune_icache(int nr_to_scan) continue; } hlist_del_init(&inode->i_hash); + list_del_init(&inode->i_sb_list); list_move(&inode->i_list, &freeable); inode->i_state |= I_FREEING; nr_pruned++; @@ -553,6 +551,7 @@ struct inode *new_inode(struct super_blo spin_lock(&inode_lock); inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); + list_add(&inode->i_sb_list, &sb->s_inodes); inode->i_ino = ++last_ino; inode->i_state = 0; spin_unlock(&inode_lock); @@ -601,6 +600,7 @@ static struct inode * get_new_inode(stru inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); + list_add(&inode->i_sb_list, &sb->s_inodes); hlist_add_head(&inode->i_hash, head); inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); @@ -649,6 +649,7 @@ static struct inode * get_new_inode_fast inode->i_ino = ino; inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); + list_add(&inode->i_sb_list, &sb->s_inodes); hlist_add_head(&inode->i_hash, head); inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); @@ -984,6 +985,7 @@ void generic_delete_inode(struct inode * struct super_operations *op = inode->i_sb->s_op; list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state|=I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -1031,6 +1033,7 @@ static void generic_forget_inode(struct hlist_del_init(&inode->i_hash); } list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state|=I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -1221,34 +1224,17 @@ int remove_inode_dquot_ref(struct inode void remove_dquot_ref(struct super_block *sb, int type) { struct inode *inode; - struct list_head *act_head; LIST_HEAD(tofree_head); if (!sb->dq_op) return; /* nothing to do */ spin_lock(&inode_lock); /* This lock is for inodes code */ /* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */ - - list_for_each(act_head, &inode_in_use) { - inode = list_entry(act_head, struct inode, i_list); - if (inode->i_sb == sb && IS_QUOTAINIT(inode)) - remove_inode_dquot_ref(inode, type, &tofree_head); - } - list_for_each(act_head, &inode_unused) { - inode = list_entry(act_head, struct inode, i_list); - if (inode->i_sb == sb && IS_QUOTAINIT(inode)) - remove_inode_dquot_ref(inode, type, &tofree_head); - } - list_for_each(act_head, &sb->s_dirty) { - inode = list_entry(act_head, struct inode, i_list); - if (IS_QUOTAINIT(inode)) - remove_inode_dquot_ref(inode, type, &tofree_head); - } - list_for_each(act_head, &sb->s_io) { - inode = list_entry(act_head, struct inode, i_list); + + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) if (IS_QUOTAINIT(inode)) remove_inode_dquot_ref(inode, type, &tofree_head); - } + spin_unlock(&inode_lock); put_dquot_list(&tofree_head); --- linux-2.6.1-rc1/fs/intermezzo/file.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/intermezzo/file.c 2003-12-30 22:49:34.000000000 -0800 @@ -336,7 +336,7 @@ static void presto_apply_write_policy(st unlock_kernel(); return; } - error = presto_journal_close(&rec, fset, file, + error = presto_journal_close(&rec, fset, fdata, file->f_dentry, &fdata->fd_version, &new_file_ver); --- linux-2.6.1-rc1/fs/intermezzo/intermezzo_fs.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/intermezzo/intermezzo_fs.h 2003-12-30 22:49:34.000000000 -0800 @@ -603,7 +603,7 @@ int presto_journal_rename(struct rec_inf int presto_journal_open(struct rec_info *, struct presto_file_set *, struct dentry *, struct presto_version *old_ver); int presto_journal_close(struct rec_info *rec, struct presto_file_set *, - struct file *, struct dentry *, + struct presto_file_data *, struct dentry *, struct presto_version *old_file_ver, struct presto_version *new_file_ver); int presto_write_lml_close(struct rec_info *rec, --- linux-2.6.1-rc1/fs/intermezzo/journal.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/intermezzo/journal.c 2003-12-30 22:49:34.000000000 -0800 @@ -2103,12 +2103,11 @@ int presto_journal_unlink(struct rec_inf int presto_journal_close(struct rec_info *rec, struct presto_file_set *fset, - struct file *file, struct dentry *dentry, + struct presto_file_data *fd, struct dentry *dentry, struct presto_version *old_file_ver, struct presto_version *new_file_ver) { int opcode = KML_OPCODE_CLOSE; - struct presto_file_data *fd; char *buffer, *path, *logrecord, record[316]; struct dentry *root; int error, size, i; @@ -2137,7 +2136,6 @@ presto_journal_close(struct rec_info *re root = fset->fset_dentry; - fd = (struct presto_file_data *)file->private_data; if (fd) { open_ngroups = fd->fd_ngroups; for (i = 0; i < fd->fd_ngroups; i++) --- linux-2.6.1-rc1/fs/intermezzo/presto.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/intermezzo/presto.c 2003-12-30 22:49:34.000000000 -0800 @@ -259,11 +259,8 @@ int lento_cancel_lml(char *path, if (info->flags & LENTO_FL_WRITE_KML) { - struct file file; - file.private_data = NULL; - file.f_dentry = dentry; presto_getversion(&new_ver, dentry->d_inode); - error = presto_journal_close(&rec, fset, &file, dentry, + error = presto_journal_close(&rec, fset, NULL, dentry, &new_ver); if ( error ) { EXIT; --- linux-2.6.1-rc1/fs/intermezzo/vfs.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/intermezzo/vfs.c 2003-12-30 22:49:34.000000000 -0800 @@ -321,7 +321,7 @@ int presto_do_close(struct presto_file_s } if (fdata->fd_info.flags & LENTO_FL_KML) - rc = presto_journal_close(&rec, fset, file, file->f_dentry, + rc = presto_journal_close(&rec, fset, fdata, file->f_dentry, &fdata->fd_version, &fdata->fd_info.remote_version); if (rc) { @@ -431,14 +431,11 @@ int presto_do_setattr(struct presto_file if ( presto_do_kml(info, dentry) ) { if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) { - struct file file; /* Journal a close whenever we see a potential truncate * At the receiving end, lento should explicitly remove * ATTR_SIZE from the list of valid attributes */ presto_getversion(&new_ver, inode); - file.private_data = NULL; - file.f_dentry = dentry; - error = presto_journal_close(&rec, fset, &file, dentry, + error = presto_journal_close(&rec, fset, NULL, dentry, &old_ver, &new_ver); } @@ -2086,7 +2083,9 @@ static struct file *presto_filp_dopen(st } } + /* XXX: where the fuck is ->f_vfsmnt? */ f->f_dentry = dentry; + f->f_mapping = dentry->d_inode->i_mapping; f->f_pos = 0; //f->f_reada = 0; f->f_op = NULL; --- linux-2.6.1-rc1/fs/ioctl.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/ioctl.c 2003-12-30 22:49:36.000000000 -0800 @@ -22,7 +22,7 @@ static int file_ioctl(struct file *filp, switch (cmd) { case FIBMAP: { - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = filp->f_mapping; int res; /* do we support this mess? */ if (!mapping->a_ops->bmap) --- linux-2.6.1-rc1/fs/jffs/intrep.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/jffs/intrep.c 2003-12-30 22:49:48.000000000 -0800 @@ -3337,18 +3337,16 @@ jffs_garbage_collect_thread(void *ptr) int result = 0; D1(int i = 1); + daemonize("jffs_gcd"); + c->gc_task = current; lock_kernel(); - exit_mm(c->gc_task); - - set_special_pids(1, 1); init_completion(&c->gc_thread_comp); /* barrier */ spin_lock_irq(¤t->sighand->siglock); siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - strcpy(current->comm, "jffs_gcd"); D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n")); --- linux-2.6.1-rc1/fs/jfs/inode.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/jfs/inode.c 2003-12-30 22:49:35.000000000 -0800 @@ -306,7 +306,7 @@ static int jfs_direct_IO(int rw, struct loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, jfs_get_blocks, NULL); --- linux-2.6.1-rc1/fs/jfs/namei.c 2003-11-23 19:03:01.000000000 -0800 +++ 25/fs/jfs/namei.c 2003-12-30 22:49:59.000000000 -0800 @@ -1439,14 +1439,18 @@ static struct dentry *jfs_lookup(struct struct dentry *jfs_get_parent(struct dentry *dentry) { struct super_block *sb = dentry->d_inode->i_sb; - struct dentry *parent = ERR_PTR(-EACCES); + struct dentry *parent = ERR_PTR(-ENOENT); struct inode *inode; + unsigned long parent_ino; - inode = iget(sb, JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot); + parent_ino = + le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot); + inode = iget(sb, parent_ino); if (inode) { - if (is_bad_inode(inode)) + if (is_bad_inode(inode)) { iput(inode); - else { + parent = ERR_PTR(-EACCES); + } else { parent = d_alloc_anon(inode); if (!parent) { parent = ERR_PTR(-ENOMEM); --- linux-2.6.1-rc1/fs/Kconfig 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/Kconfig 2003-12-30 22:49:49.000000000 -0800 @@ -768,6 +768,30 @@ config PROC_KCORE bool default y if !ARM +config SYSFS + bool "sysfs file system support" if EMBEDDED + default y + help + The sysfs filesystem is a virtual filesystem that the kernel uses to export + internal kernel objects, their attributes, and their relationships to one + another. + + Users can use sysfs to ascertain useful information about the running kernel, + such as the devices the kernel has discovered on each bus and which driver + each is bound to. sysfs can also be used to tune devices and other kernel + subsystems. + + Some system agents rely on the information in sysfs to operate. /sbin/hotplug + uses device and object attributes in sysfs to assist in delegating policy + decisions, like persistantly naming devices. + + sysfs is currently needed by the block subsystem to mount the root partition. + Therefore, you MUST say Y if you're booting from a hard drive. If you use any + type of hotpluggable device, you'll also need sysfs for /sbin/hotplug support. + + However, designers of embedded systems may want to say Y here to conserve + space. + config DEVFS_FS bool "/dev file system support (OBSOLETE)" depends on EXPERIMENTAL --- linux-2.6.1-rc1/fs/locks.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/locks.c 2003-12-30 22:49:36.000000000 -0800 @@ -1454,7 +1454,7 @@ int fcntl_setlk(struct file *filp, unsig */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = filp->f_mapping; if (!list_empty(&mapping->i_mmap_shared)) { error = -EAGAIN; @@ -1592,7 +1592,7 @@ int fcntl_setlk64(struct file *filp, uns */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = filp->f_mapping; if (!list_empty(&mapping->i_mmap_shared)) { error = -EAGAIN; --- linux-2.6.1-rc1/fs/Makefile 2003-08-22 19:23:42.000000000 -0700 +++ 25/fs/Makefile 2003-12-30 22:49:49.000000000 -0800 @@ -39,7 +39,7 @@ obj-$(CONFIG_QUOTACTL) += quota.o obj-$(CONFIG_PROC_FS) += proc/ obj-y += partitions/ -obj-y += sysfs/ +obj-$(CONFIG_SYSFS) += sysfs/ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o --- linux-2.6.1-rc1/fs/namespace.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/fs/namespace.c 2003-12-30 22:49:49.000000000 -0800 @@ -24,7 +24,15 @@ #include extern int __init init_rootfs(void); + +#ifdef CONFIG_SYSFS extern int __init sysfs_init(void); +#else +static inline int sysfs_init(void) +{ + return 0; +} +#endif /* spinlock for vfsmount related operations, inplace of dcache_lock */ spinlock_t vfsmount_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; --- linux-2.6.1-rc1/fs/nfs/file.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/nfs/file.c 2003-12-30 22:49:35.000000000 -0800 @@ -266,7 +266,7 @@ out_swapfile: int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode * inode = filp->f_mapping->host; int status = 0; int status2; @@ -309,13 +309,13 @@ nfs_lock(struct file *filp, int cmd, str * Flush all pending writes before doing anything * with locks.. */ - status = filemap_fdatawrite(inode->i_mapping); + status = filemap_fdatawrite(filp->f_mapping); down(&inode->i_sem); status2 = nfs_wb_all(inode); if (!status) status = status2; up(&inode->i_sem); - status2 = filemap_fdatawait(inode->i_mapping); + status2 = filemap_fdatawait(filp->f_mapping); if (!status) status = status2; if (status < 0) @@ -335,11 +335,11 @@ nfs_lock(struct file *filp, int cmd, str */ out_ok: if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { - filemap_fdatawrite(inode->i_mapping); + filemap_fdatawrite(filp->f_mapping); down(&inode->i_sem); nfs_wb_all(inode); /* we may have slept */ up(&inode->i_sem); - filemap_fdatawait(inode->i_mapping); + filemap_fdatawait(filp->f_mapping); nfs_zap_caches(inode); } return status; --- linux-2.6.1-rc1/fs/open.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/open.c 2003-12-30 22:50:19.000000000 -0800 @@ -192,7 +192,9 @@ int do_truncate(struct dentry *dentry, l newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; down(&dentry->d_inode->i_sem); + down_write(&dentry->d_inode->i_alloc_sem); err = notify_change(dentry, &newattrs); + up_write(&dentry->d_inode->i_alloc_sem); up(&dentry->d_inode->i_sem); return err; } @@ -776,7 +778,8 @@ struct file *dentry_open(struct dentry * goto cleanup_file; } - file_ra_state_init(&f->f_ra, inode->i_mapping); + f->f_mapping = inode->i_mapping; + file_ra_state_init(&f->f_ra, f->f_mapping); f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; @@ -792,8 +795,8 @@ struct file *dentry_open(struct dentry * /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { - if (!inode->i_mapping || !inode->i_mapping->a_ops || - !inode->i_mapping->a_ops->direct_IO) { + if (!f->f_mapping || !f->f_mapping->a_ops || + !f->f_mapping->a_ops->direct_IO) { fput(f); f = ERR_PTR(-EINVAL); } --- linux-2.6.1-rc1/fs/pipe.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/pipe.c 2003-12-30 22:49:34.000000000 -0800 @@ -650,6 +650,7 @@ int do_pipe(int *fd) d_add(dentry, inode); f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt)); f1->f_dentry = f2->f_dentry = dget(dentry); + f1->f_mapping = f2->f_mapping = inode->i_mapping; /* read file */ f1->f_pos = f2->f_pos = 0; --- linux-2.6.1-rc1/fs/proc/proc_misc.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/proc/proc_misc.c 2003-12-30 22:50:17.000000000 -0800 @@ -378,10 +378,9 @@ int show_stat(struct seq_file *p, void * jif = ((u64)now.tv_sec * HZ) + (now.tv_usec/(1000000/HZ)) - jif; do_div(jif, HZ); - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu(i) { int j; - if (!cpu_online(i)) continue; user += kstat_cpu(i).cpustat.user; nice += kstat_cpu(i).cpustat.nice; system += kstat_cpu(i).cpustat.system; @@ -401,8 +400,7 @@ int show_stat(struct seq_file *p, void * jiffies_to_clock_t(iowait), jiffies_to_clock_t(irq), jiffies_to_clock_t(softirq)); - for (i = 0; i < NR_CPUS; i++){ - if (!cpu_online(i)) continue; + for_each_online_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), @@ -654,6 +652,36 @@ static void create_seq_entry(char *name, entry->proc_fops = f; } +#ifdef CONFIG_LOCKMETER +extern ssize_t get_lockmeter_info(char *, size_t, loff_t *); +extern ssize_t put_lockmeter_info(const char *, size_t); +extern int get_lockmeter_info_size(void); + +/* + * This function accesses lock metering information. + */ +static ssize_t read_lockmeter(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return get_lockmeter_info(buf, count, ppos); +} + +/* + * Writing to /proc/lockmeter resets the counters + */ +static ssize_t write_lockmeter(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + return put_lockmeter_info(buf, count); +} + +static struct file_operations proc_lockmeter_operations = { + NULL, /* lseek */ + read: read_lockmeter, + write: write_lockmeter, +}; +#endif /* CONFIG_LOCKMETER */ + void __init proc_misc_init(void) { struct proc_dir_entry *entry; @@ -721,6 +749,13 @@ void __init proc_misc_init(void) if (entry) entry->proc_fops = &proc_sysrq_trigger_operations; #endif +#ifdef CONFIG_LOCKMETER + entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL); + if (entry) { + entry->proc_fops = &proc_lockmeter_operations; + entry->size = get_lockmeter_info_size(); + } +#endif #ifdef CONFIG_PPC32 { extern struct file_operations ppc_htab_operations; --- linux-2.6.1-rc1/fs/read_write.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/read_write.c 2003-12-30 22:49:35.000000000 -0800 @@ -28,7 +28,7 @@ EXPORT_SYMBOL(generic_ro_fops); loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) { long long retval; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; down(&inode->i_sem); switch (origin) { --- linux-2.6.1-rc1/fs/reiserfs/file.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/reiserfs/file.c 2003-12-30 22:49:37.000000000 -0800 @@ -1052,7 +1052,7 @@ ssize_t reiserfs_file_write( struct file /* Check if we can write to specified region of file, file is not overly big and this kind of stuff. Adjust pos and count, if needed */ - res = generic_write_checks(inode, file, &pos, &count, 0); + res = generic_write_checks(file, &pos, &count, 0); if (res) goto out; @@ -1179,7 +1179,7 @@ ssize_t reiserfs_file_write( struct file } if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) - res = generic_osync_inode(inode, OSYNC_METADATA|OSYNC_DATA); + res = generic_osync_inode(inode, file->f_mapping, OSYNC_METADATA|OSYNC_DATA); up(&inode->i_sem); return (already_written != 0)?already_written:res; --- linux-2.6.1-rc1/fs/reiserfs/inode.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/reiserfs/inode.c 2003-12-30 22:49:35.000000000 -0800 @@ -2375,7 +2375,7 @@ static int reiserfs_direct_IO(int rw, st loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, reiserfs_get_blocks_direct_io, NULL); --- linux-2.6.1-rc1/fs/reiserfs/journal.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/fs/reiserfs/journal.c 2003-12-30 22:49:38.000000000 -0800 @@ -1937,18 +1937,13 @@ static int journal_init_dev( struct supe journal -> j_dev_file = filp_open( jdev_name, 0, 0 ); if( !IS_ERR( journal -> j_dev_file ) ) { - struct inode *jdev_inode; - - jdev_inode = journal -> j_dev_file -> f_dentry -> d_inode; - journal -> j_dev_bd = jdev_inode -> i_bdev; + struct inode *jdev_inode = journal->j_dev_file->f_mapping->host; if( !S_ISBLK( jdev_inode -> i_mode ) ) { printk( "journal_init_dev: '%s' is not a block device\n", jdev_name ); result = -ENOTBLK; - } else if( jdev_inode -> i_bdev == NULL ) { - printk( "journal_init_dev: bdev uninitialized for '%s'\n", jdev_name ); - result = -ENOMEM; } else { /* ok */ + journal->j_dev_bd = I_BDEV(jdev_inode); set_blocksize(journal->j_dev_bd, super->s_blocksize); } } else { --- linux-2.6.1-rc1/fs/super.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/super.c 2003-12-30 22:49:38.000000000 -0800 @@ -66,6 +66,7 @@ static struct super_block *alloc_super(v INIT_LIST_HEAD(&s->s_files); INIT_LIST_HEAD(&s->s_instances); INIT_HLIST_HEAD(&s->s_anon); + INIT_LIST_HEAD(&s->s_inodes); init_rwsem(&s->s_umount); sema_init(&s->s_lock, 1); down_write(&s->s_umount); --- linux-2.6.1-rc1/fs/sysfs/dir.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/sysfs/dir.c 2003-12-30 22:50:05.000000000 -0800 @@ -83,7 +83,8 @@ static void remove_dir(struct dentry * d struct dentry * parent = dget(d->d_parent); down(&parent->d_inode->i_sem); d_delete(d); - simple_rmdir(parent->d_inode,d); + if (d->d_inode) + simple_rmdir(parent->d_inode,d); pr_debug(" o %s removing done (%d)\n",d->d_name.name, atomic_read(&d->d_count)); @@ -122,8 +123,8 @@ void sysfs_remove_dir(struct kobject * k node = dentry->d_subdirs.next; while (node != &dentry->d_subdirs) { struct dentry * d = list_entry(node,struct dentry,d_child); - list_del_init(node); + node = node->next; pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count)); if (d->d_inode) { d = dget_locked(d); @@ -139,9 +140,7 @@ void sysfs_remove_dir(struct kobject * k spin_lock(&dcache_lock); } pr_debug(" done\n"); - node = dentry->d_subdirs.next; } - list_del_init(&dentry->d_child); spin_unlock(&dcache_lock); up(&dentry->d_inode->i_sem); --- linux-2.6.1-rc1/fs/xfs/linux/xfs_aops.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/xfs/linux/xfs_aops.c 2003-12-30 22:50:19.000000000 -0800 @@ -974,7 +974,7 @@ linvfs_direct_IO( unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; vnode_t *vp = LINVFS_GET_VP(inode); page_buf_bmap_t pbmap; int maps = 1; @@ -984,7 +984,8 @@ linvfs_direct_IO( if (error) return -error; - return blockdev_direct_IO(rw, iocb, inode, pbmap.pbm_target->pbr_bdev, + return blockdev_direct_IO_no_locking(rw, iocb, inode, + pbmap.pbm_target->pbr_bdev, iov, offset, nr_segs, linvfs_get_blocks_direct, linvfs_unwritten_convert_direct); --- linux-2.6.1-rc1/fs/xfs/linux/xfs_file.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/fs/xfs/linux/xfs_file.c 2003-12-30 22:49:35.000000000 -0800 @@ -112,7 +112,7 @@ __linvfs_write( { struct iovec iov = {(void *)buf, count}; struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; vnode_t *vp = LINVFS_GET_VP(inode); int error; @@ -160,7 +160,7 @@ __linvfs_readv( unsigned long nr_segs, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; vnode_t *vp = LINVFS_GET_VP(inode); struct kiocb kiocb; int error; @@ -207,7 +207,7 @@ __linvfs_writev( unsigned long nr_segs, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + struct inode *inode = file->f_mapping->host; vnode_t *vp = LINVFS_GET_VP(inode); struct kiocb kiocb; int error; --- linux-2.6.1-rc1/fs/xfs/pagebuf/page_buf.c 2003-10-08 15:07:10.000000000 -0700 +++ 25/fs/xfs/pagebuf/page_buf.c 2003-12-30 22:49:58.000000000 -0800 @@ -1395,7 +1395,6 @@ next_chunk: break; offset = 0; - sector += nbytes >> BBSHIFT; size -= nbytes; total_nr_pages--; @@ -1403,15 +1402,11 @@ next_chunk: submit_io: if (likely(bio->bi_size)) { - if (pb->pb_flags & PBF_READ) { - submit_bio(READ, bio); - } else { - submit_bio(WRITE, bio); - } - + submit_bio((pb->pb_flags & PBF_READ) ? READ : WRITE, bio); if (size) goto next_chunk; } else { + bio_put(bio); pagebuf_ioerror(pb, EIO); } --- linux-2.6.1-rc1/fs/xfs/xfs_vfsops.c 2003-10-17 15:58:04.000000000 -0700 +++ 25/fs/xfs/xfs_vfsops.c 2003-12-30 22:49:58.000000000 -0800 @@ -1598,8 +1598,9 @@ xfs_vget( #define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ #define MNTOPT_NOLOGFLUSH "nologflush" /* don't hard flush on log writes */ #define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */ -#define MNTOPT_64BITINODE "inode64" /* inodes can be allocated anywhere */ -#define MNTOPT_IKEEP "ikeep" /* free empty inode clusters */ +#define MNTOPT_64BITINODE "inode64" /* inodes can be allocated anywhere */ +#define MNTOPT_IKEEP "ikeep" /* do not free empty inode clusters */ +#define MNTOPT_NOIKEEP "noikeep" /* free empty inode clusters */ int @@ -1614,7 +1615,9 @@ xfs_parseargs( int dsunit, dswidth, vol_dsunit, vol_dswidth; int iosize; +#if 0 /* XXX: off by default, until some remaining issues ironed out */ args->flags |= XFSMNT_IDELETE; /* default to on */ +#endif if (!options) return 0; @@ -1722,6 +1725,8 @@ xfs_parseargs( args->flags |= XFSMNT_NOLOGFLUSH; } else if (!strcmp(this_char, MNTOPT_IKEEP)) { args->flags &= ~XFSMNT_IDELETE; + } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) { + args->flags |= XFSMNT_IDELETE; } else if (!strcmp(this_char, "osyncisdsync")) { /* no-op, this is now the default */ printk("XFS: osyncisdsync is now the default, option is deprecated.\n"); --- linux-2.6.1-rc1/include/acpi/acconfig.h 2003-10-17 15:58:04.000000000 -0700 +++ 25/include/acpi/acconfig.h 2003-12-30 22:49:41.000000000 -0800 @@ -64,7 +64,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20031002 +#define ACPI_CA_VERSION 0x20031203 /* Maximum objects in the various object caches */ --- linux-2.6.1-rc1/include/acpi/acevents.h 2003-06-14 12:18:23.000000000 -0700 +++ 25/include/acpi/acevents.h 2003-12-30 22:49:41.000000000 -0800 @@ -182,6 +182,17 @@ acpi_ev_detach_region ( union acpi_operand_object *region_obj, u8 acpi_ns_is_locked); +acpi_status +acpi_ev_execute_reg_method ( + union acpi_operand_object *region_obj, + u32 function); + +acpi_status +acpi_ev_reg_run ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); /* * Evregini - Region initialization and setup --- linux-2.6.1-rc1/include/acpi/acglobal.h 2003-06-22 12:04:44.000000000 -0700 +++ 25/include/acpi/acglobal.h 2003-12-30 22:49:41.000000000 -0800 @@ -106,6 +106,9 @@ ACPI_EXTERN struct acpi_common_facs ACPI_EXTERN u8 acpi_gbl_integer_bit_width; 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; --- linux-2.6.1-rc1/include/acpi/acmacros.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/include/acpi/acmacros.h 2003-12-30 22:49:41.000000000 -0800 @@ -48,7 +48,6 @@ /* * Data manipulation macros */ - #define ACPI_LOWORD(l) ((u16)(u32)(l)) #define ACPI_HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF)) #define ACPI_LOBYTE(l) ((u8)(u16)(l)) @@ -94,10 +93,18 @@ #endif #endif - /* - * Extract a byte of data using a pointer. Any more than a byte and we - * get into potential aligment issues -- see the STORE macros below - */ +/* + * printf() format helpers + */ + +/* Split 64-bit integer into two 32-bit values. use with %8,8_x%8.8X */ + +#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i) + +/* + * Extract a byte of data using a pointer. Any more than a byte and we + * get into potential aligment issues -- see the STORE macros below + */ #define ACPI_GET8(addr) (*(u8*)(addr)) /* Pointer arithmetic */ @@ -129,7 +136,6 @@ * If the hardware supports the transfer of unaligned data, just do the store. * Otherwise, we have to move one byte at a time. */ - #ifdef ACPI_BIG_ENDIAN /* * Macros for big-endian machines @@ -299,7 +305,6 @@ /* * Fast power-of-two math macros for non-optimized compilers */ - #define _ACPI_DIV(value,power_of2) ((u32) ((value) >> (power_of2))) #define _ACPI_MUL(value,power_of2) ((u32) ((value) << (power_of2))) #define _ACPI_MOD(value,divisor) ((u32) ((value) & ((divisor) -1))) @@ -443,7 +448,6 @@ /* * Reporting macros that are never compiled out */ - #define ACPI_PARAM_LIST(pl) pl /* @@ -451,7 +455,6 @@ * _THIS_MODULE gets compiled out when ACPI_DEBUG_OUTPUT isn't defined, only * use it in debug mode. */ - #ifdef ACPI_DEBUG_OUTPUT #define ACPI_REPORT_INFO(fp) {acpi_ut_report_info(_THIS_MODULE,__LINE__,_COMPONENT); \ @@ -490,7 +493,6 @@ /* * Debug macros that are conditionally compiled */ - #ifdef ACPI_DEBUG_OUTPUT #define ACPI_MODULE_NAME(name) static char ACPI_UNUSED_VAR *_THIS_MODULE = name; @@ -500,7 +502,6 @@ * The first parameter should be the procedure name as a quoted string. This is declared * as a local string ("_proc_name) so that it can be also used by the function exit macros below. */ - #define ACPI_FUNCTION_NAME(a) struct acpi_debug_print_info _dbg; \ _dbg.component_id = _COMPONENT; \ _dbg.proc_name = a; \ @@ -562,7 +563,6 @@ /* * Generate INT3 on ACPI_ERROR (Debug only!) */ - #define ACPI_ERROR_BREAK #ifdef ACPI_ERROR_BREAK #define ACPI_BREAK_ON_ERROR(lvl) if ((lvl)&ACPI_ERROR) \ @@ -577,7 +577,6 @@ * 1) Debug print for the current component is enabled * 2) Debug error level or trace level for the print statement is enabled */ - #define ACPI_DEBUG_PRINT(pl) acpi_ut_debug_print ACPI_PARAM_LIST(pl) #define ACPI_DEBUG_PRINT_RAW(pl) acpi_ut_debug_print_raw ACPI_PARAM_LIST(pl) @@ -587,7 +586,6 @@ * This is the non-debug case -- make everything go away, * leaving no executable debug code! */ - #define ACPI_MODULE_NAME(name) #define _THIS_MODULE "" @@ -662,7 +660,6 @@ /* * Memory allocation tracking (DEBUG ONLY) */ - #ifndef ACPI_DBG_TRACK_ALLOCATIONS /* Memory allocation */ --- linux-2.6.1-rc1/include/acpi/acobject.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/include/acpi/acobject.h 2003-12-30 22:49:41.000000000 -0800 @@ -114,7 +114,7 @@ #define ACPI_COMMON_NOTIFY_INFO \ union acpi_operand_object *system_notify; /* Handler for system notifies */\ union acpi_operand_object *device_notify; /* Handler for driver notifies */\ - union acpi_operand_object *address_space; /* Handler for Address space */ + union acpi_operand_object *handler; /* Handler for Address space */ /****************************************************************************** @@ -214,7 +214,7 @@ struct acpi_object_region ACPI_OBJECT_COMMON_HEADER u8 space_id; - union acpi_operand_object *address_space; /* Handler for region access */ + union acpi_operand_object *handler; /* Handler for region access */ struct acpi_namespace_node *node; /* containing object */ union acpi_operand_object *next; u32 length; @@ -464,21 +464,22 @@ union acpi_operand_object /* Object descriptor types */ -#define ACPI_DESC_TYPE_CACHED 0x11 /* Used only when object is cached */ -#define ACPI_DESC_TYPE_STATE 0x20 -#define ACPI_DESC_TYPE_STATE_UPDATE 0x21 -#define ACPI_DESC_TYPE_STATE_PACKAGE 0x22 -#define ACPI_DESC_TYPE_STATE_CONTROL 0x23 -#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x24 -#define ACPI_DESC_TYPE_STATE_PSCOPE 0x25 -#define ACPI_DESC_TYPE_STATE_WSCOPE 0x26 -#define ACPI_DESC_TYPE_STATE_RESULT 0x27 -#define ACPI_DESC_TYPE_STATE_NOTIFY 0x28 -#define ACPI_DESC_TYPE_STATE_THREAD 0x29 -#define ACPI_DESC_TYPE_WALK 0x44 -#define ACPI_DESC_TYPE_PARSER 0x66 -#define ACPI_DESC_TYPE_OPERAND 0x88 -#define ACPI_DESC_TYPE_NAMED 0xAA +#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */ +#define ACPI_DESC_TYPE_STATE 0x02 +#define ACPI_DESC_TYPE_STATE_UPDATE 0x03 +#define ACPI_DESC_TYPE_STATE_PACKAGE 0x04 +#define ACPI_DESC_TYPE_STATE_CONTROL 0x05 +#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x06 +#define ACPI_DESC_TYPE_STATE_PSCOPE 0x07 +#define ACPI_DESC_TYPE_STATE_WSCOPE 0x08 +#define ACPI_DESC_TYPE_STATE_RESULT 0x09 +#define ACPI_DESC_TYPE_STATE_NOTIFY 0x0A +#define ACPI_DESC_TYPE_STATE_THREAD 0x0B +#define ACPI_DESC_TYPE_WALK 0x0C +#define ACPI_DESC_TYPE_PARSER 0x0D +#define ACPI_DESC_TYPE_OPERAND 0x0E +#define ACPI_DESC_TYPE_NAMED 0x0F +#define ACPI_DESC_TYPE_MAX 0x0F union acpi_descriptor --- linux-2.6.1-rc1/include/acpi/acpi_drivers.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/acpi/acpi_drivers.h 2003-12-30 22:49:41.000000000 -0800 @@ -53,10 +53,6 @@ #define ACPI_PCI_COMPONENT 0x00400000 -/* ACPI PCI Root Bridge (pci_root.c) */ - -void acpi_pci_get_translations (struct acpi_pci_id* id, u64* mem_tra, u64* io_tra); - /* ACPI PCI Interrupt Link (pci_link.c) */ int acpi_pci_link_check (void); --- linux-2.6.1-rc1/include/acpi/acutils.h 2003-06-14 12:17:56.000000000 -0700 +++ 25/include/acpi/acutils.h 2003-12-30 22:49:41.000000000 -0800 @@ -125,6 +125,14 @@ acpi_ut_get_type_name ( acpi_object_type type); char * +acpi_ut_get_node_name ( + void *object); + +char * +acpi_ut_get_descriptor_name ( + void *object); + +char * acpi_ut_get_object_type_name ( union acpi_operand_object *obj_desc); --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-alpha/lockmeter.h 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,90 @@ +/* + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Peter Rival (frival@zk3.dec.com) + */ + +#ifndef _ALPHA_LOCKMETER_H +#define _ALPHA_LOCKMETER_H + +#include +#define CPU_CYCLE_FREQUENCY hwrpb->cycle_freq + +#define get_cycles64() get_cycles() + +#define THIS_CPU_NUMBER smp_processor_id() + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define local_irq_save(x) \ + __save_and_cli(x) +#define local_irq_restore(x) \ + __restore_flags(x) +#endif /* Linux version 2.2.x */ + +#define SPINLOCK_MAGIC_INIT /**/ + +/* + * Macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * We also assume that the hash table has less than 32767 entries. + * the high order bit is used for write locking a rw_lock + * Note: although these defines and macros are the same as what is being used + * in include/asm-i386/lockmeter.h, they are present here to easily + * allow an alternate Alpha implementation. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Alpha is little endian */ + unsigned short lock; + unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1) +#define IABS(x) ((x) > 0 ? (x) : -(x)) + +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock; + /* readers subtract 2, so we have to: */ + /* - andnot off a possible writer (bit 0) */ + /* - get the absolute value */ + /* - divide by 2 (right shift by one) */ + /* to find the number of readers */ + if (tmp == 0) return(0); + else return(IABS(tmp & ~1)>>1); +} + +#endif /* _ALPHA_LOCKMETER_H */ --- linux-2.6.1-rc1/include/asm-alpha/smp.h 2003-09-27 18:57:46.000000000 -0700 +++ 25/include/asm-alpha/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -48,8 +48,8 @@ extern struct cpuinfo_alpha cpu_data[NR_ extern cpumask_t cpu_present_mask; extern cpumask_t cpu_online_map; extern int smp_num_cpus; +#define cpu_possible_map cpu_present_map -#define cpu_possible(cpu) cpu_isset(cpu, cpu_present_mask) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) extern int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, int wait, unsigned long cpu); --- linux-2.6.1-rc1/include/asm-alpha/spinlock.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-alpha/spinlock.h 2003-12-30 22:50:17.000000000 -0800 @@ -6,6 +6,10 @@ #include #include +#ifdef CONFIG_LOCKMETER +#undef DEBUG_SPINLOCK +#undef DEBUG_RWLOCK +#endif /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -95,9 +99,18 @@ static inline int _raw_spin_trylock(spin typedef struct { volatile int write_lock:1, read_counter:31; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* need this storage for CPU and lock INDEX ............. */ + unsigned magic; +#endif } /*__attribute__((aligned(32)))*/ rwlock_t; +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *)(x) != 0) @@ -169,4 +182,41 @@ static inline void _raw_read_unlock(rwlo : "m" (*lock) : "memory"); } +#ifdef CONFIG_LOCKMETER +static inline int _raw_write_trylock(rwlock_t *lock) +{ + long temp,result; + + __asm__ __volatile__( + " ldl_l %1,%0\n" + " mov $31,%2\n" + " bne %1,1f\n" + " or $31,1,%2\n" + " stl_c %2,%0\n" + "1: mb\n" + : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result) + : "m" (*(volatile int *)lock) + ); + + return (result); +} + +static inline int _raw_read_trylock(rwlock_t *lock) +{ + unsigned long temp,result; + + __asm__ __volatile__( + " ldl_l %1,%0\n" + " mov $31,%2\n" + " blbs %1,1f\n" + " subl %1,2,%2\n" + " stl_c %2,%0\n" + "1: mb\n" + : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result) + : "m" (*(volatile int *)lock) + ); + return (result); +} +#endif /* CONFIG_LOCKMETER */ + #endif /* _ALPHA_SPINLOCK_H */ --- linux-2.6.1-rc1/include/asm-cris/arch-v10/byteorder.h 2003-07-10 18:50:32.000000000 -0700 +++ 25/include/asm-cris/arch-v10/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -2,20 +2,21 @@ #define _CRIS_ARCH_BYTEORDER_H #include +#include /* we just define these two (as we can do the swap in a single * asm instruction in CRIS) and the arch-independent files will put * them together into ntohl etc. */ -extern __inline__ __const__ __u32 ___arch__swab32(__u32 x) +extern __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) { __asm__ ("swapwb %0" : "=r" (x) : "0" (x)); return(x); } -extern __inline__ __const__ __u16 ___arch__swab16(__u16 x) +extern __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) { __asm__ ("swapb %0" : "=r" (x) : "0" (x)); --- linux-2.6.1-rc1/include/asm-generic/percpu.h 2003-07-27 12:14:40.000000000 -0700 +++ 25/include/asm-generic/percpu.h 2003-12-30 22:49:59.000000000 -0800 @@ -29,7 +29,7 @@ do { \ #define DEFINE_PER_CPU(type, name) \ __typeof__(type) per_cpu__##name -#define per_cpu(var, cpu) ((void)cpu, per_cpu__##var) +#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var #endif /* SMP */ --- linux-2.6.1-rc1/include/asm-i386/acpi.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-i386/acpi.h 2003-12-30 22:49:41.000000000 -0800 @@ -109,7 +109,7 @@ #ifdef CONFIG_ACPI_BOOT extern int acpi_lapic; extern int acpi_ioapic; - +extern int acpi_noirq; /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 @@ -139,6 +139,14 @@ static inline void disable_ioapic_setup( #endif +#ifdef CONFIG_ACPI_PCI +static inline void acpi_noirq_set(void) { acpi_noirq = 1; } +extern int acpi_irq_balance_set(char *str); +#else +static inline void acpi_noirq_set(void) { } +static inline int acpi_irq_balance_set(char *str) { return 0; } +#endif + #ifdef CONFIG_ACPI_SLEEP /* routines for saving/restoring kernel state */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-i386/atomic_kmap.h 2003-12-30 22:50:18.000000000 -0800 @@ -0,0 +1,95 @@ +/* + * atomic_kmap.h: temporary virtual kernel memory mappings + * + * Copyright (C) 2003 Ingo Molnar + */ + +#ifndef _ASM_ATOMIC_KMAP_H +#define _ASM_ATOMIC_KMAP_H + +#ifdef __KERNEL__ + +#include +#include + +#ifdef CONFIG_DEBUG_HIGHMEM +#define HIGHMEM_DEBUG 1 +#else +#define HIGHMEM_DEBUG 0 +#endif + +extern pte_t *kmap_pte; +#define kmap_prot PAGE_KERNEL + +#define PKMAP_BASE (0xff000000UL) +#define NR_SHARED_PMDS ((0xffffffff-PKMAP_BASE+1)/PMD_SIZE) + +static inline unsigned long __kmap_atomic_vaddr(enum km_type type) +{ + enum fixed_addresses idx; + + idx = type + KM_TYPE_NR*smp_processor_id(); + return __fix_to_virt(FIX_KMAP_BEGIN + idx); +} + +static inline void *__kmap_atomic_noflush(struct page *page, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + /* + * NOTE: entries that rely on some secondary TLB-flush + * effect must not be global: + */ + set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); + + return (void*) vaddr; +} + +static inline void *__kmap_atomic(struct page *page, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#if HIGHMEM_DEBUG + BUG_ON(!pte_none(*(kmap_pte-idx))); +#else + /* + * Performance optimization - do not flush if the new + * pte is the same as the old one: + */ + if (pte_val(*(kmap_pte-idx)) == pte_val(mk_pte(page, kmap_prot))) + return (void *) vaddr; +#endif + set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); + __flush_tlb_one(vaddr); + + return (void*) vaddr; +} + +static inline void __kunmap_atomic(void *kvaddr, enum km_type type) +{ +#if HIGHMEM_DEBUG + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); + + BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)); + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(kmap_pte-idx); + __flush_tlb_one(vaddr); +#endif +} + +#define __kunmap_atomic_type(type) \ + __kunmap_atomic((void *)__kmap_atomic_vaddr(type), (type)) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_ATOMIC_KMAP_H */ --- linux-2.6.1-rc1/include/asm-i386/bugs.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/bugs.h 2003-12-30 22:49:25.000000000 -0800 @@ -1,11 +1,11 @@ /* * include/asm-i386/bugs.h * - * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 1994 Linus Torvalds * * Cyrix stuff, June 1998 by: * - Rafael R. Reilova (moved everything from head.S), - * + * * - Channing Corn (tests & fixes), * - Andrew D. Balsa (code cleanup). * @@ -25,7 +25,20 @@ #include #include #include - +#ifdef CONFIG_KGDB +/* + * Provied the command line "gdb" initial break + */ +int __init kgdb_initial_break(char * str) +{ + if (*str == '\0'){ + breakpoint(); + return 1; + } + return 0; +} +__setup("gdb",kgdb_initial_break); +#endif static int __init no_halt(char *s) { boot_cpu_data.hlt_works_ok = 0; @@ -140,7 +153,7 @@ static void __init check_popad(void) : "ecx", "edi" ); /* If this fails, it means that any user program may lock the CPU hard. Too bad. */ if (res != 12345678) printk( "Buggy.\n" ); - else printk( "OK.\n" ); + else printk( "OK.\n" ); #endif } --- linux-2.6.1-rc1/include/asm-i386/byteorder.h 2003-06-14 12:18:23.000000000 -0700 +++ 25/include/asm-i386/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -2,6 +2,7 @@ #define _I386_BYTEORDER_H #include +#include #ifdef __GNUC__ @@ -10,7 +11,7 @@ #include #endif -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) { #ifdef CONFIG_X86_BSWAP __asm__("bswap %0" : "=r" (x) : "0" (x)); @@ -24,18 +25,7 @@ static __inline__ __const__ __u32 ___arc return x; } -/* gcc should generate this for open coded C now too. May be worth switching to - it because inline assembly cannot be scheduled. -AK */ -static __inline__ __const__ __u16 ___arch__swab16(__u16 x) -{ - __asm__("xchgb %b0,%h0" /* swap bytes */ - : "=q" (x) - : "0" (x)); - return x; -} - - -static inline __u64 ___arch__swab64(__u64 val) +static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 val) { union { struct { __u32 a,b; } s; @@ -54,9 +44,11 @@ static inline __u64 ___arch__swab64(__u6 return v.u; } +/* Do not define swab16. Gcc is smart enough to recognize "C" version and + convert it into rotation or exhange. */ + #define __arch__swab64(x) ___arch__swab64(x) #define __arch__swab32(x) ___arch__swab32(x) -#define __arch__swab16(x) ___arch__swab16(x) #define __BYTEORDER_HAS_U64__ --- linux-2.6.1-rc1/include/asm-i386/checksum.h 2003-11-23 19:03:01.000000000 -0800 +++ 25/include/asm-i386/checksum.h 2003-12-30 22:50:18.000000000 -0800 @@ -25,7 +25,7 @@ asmlinkage unsigned int csum_partial(con * better 64-bit) boundary */ -asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum, +asmlinkage unsigned int direct_csum_partial_copy_generic( const char *src, char *dst, int len, int sum, int *src_err_ptr, int *dst_err_ptr); /* @@ -39,14 +39,19 @@ static __inline__ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst, int len, int sum) { - return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); + /* + * The direct function is OK for kernel-space => kernel-space copies: + */ + return direct_csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); } static __inline__ unsigned int csum_partial_copy_from_user ( const char *src, char *dst, int len, int sum, int *err_ptr) { - return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL); + if (copy_from_user(dst, src, len)) + *err_ptr = -EFAULT; + return csum_partial(dst, len, sum); } /* @@ -172,11 +177,26 @@ static __inline__ unsigned short int csu * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, +static __inline__ unsigned int direct_csum_and_copy_to_user(const char *src, char *dst, int len, int sum, int *err_ptr) { if (access_ok(VERIFY_WRITE, dst, len)) - return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + return direct_csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + + if (len) + *err_ptr = -EFAULT; + + return -1; /* invalid checksum */ +} + +static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, + int len, int sum, int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) { + if (copy_to_user(dst, src, len)) + *err_ptr = -EFAULT; + return csum_partial(src, len, sum); + } if (len) *err_ptr = -EFAULT; --- linux-2.6.1-rc1/include/asm-i386/desc.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/desc.h 2003-12-30 22:50:18.000000000 -0800 @@ -21,6 +21,13 @@ struct Xgt_desc_struct { extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS]; +extern void trap_init_virtual_IDT(void); +extern void trap_init_virtual_GDT(void); + +asmlinkage int system_call(void); +asmlinkage void lcall7(void); +asmlinkage void lcall27(void); + #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8)) @@ -30,6 +37,7 @@ extern struct Xgt_desc_struct idt_descr, */ extern struct desc_struct default_ldt[]; extern void set_intr_gate(unsigned int irq, void * addr); +extern void set_trap_gate(unsigned int n, void *addr); #define _set_tssldt_desc(n,addr,limit,type) \ __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ @@ -90,31 +98,8 @@ static inline void load_TLS(struct threa #undef C } -static inline void clear_LDT(void) -{ - int cpu = get_cpu(); - - set_ldt_desc(cpu, &default_ldt[0], 5); - load_LDT_desc(); - put_cpu(); -} - -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) -{ - void *segments = pc->ldt; - int count = pc->size; - - if (likely(!count)) { - segments = &default_ldt[0]; - count = 5; - } - - set_ldt_desc(cpu, segments, count); - load_LDT_desc(); -} +extern struct page *default_ldt_page; +extern void load_LDT_nolock(mm_context_t *pc, int cpu); static inline void load_LDT(mm_context_t *pc) { @@ -123,6 +108,6 @@ static inline void load_LDT(mm_context_t put_cpu(); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLY__ */ #endif --- linux-2.6.1-rc1/include/asm-i386/fixmap.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/fixmap.h 2003-12-30 22:50:18.000000000 -0800 @@ -18,17 +18,15 @@ #include #include #include -#ifdef CONFIG_HIGHMEM #include #include -#endif /* * Here we define all the compile-time 'special' virtual * addresses. The point is to have a constant address at * compile time, but to set the physical address only - * in the boot process. We allocate these special addresses - * from the end of virtual memory (0xfffff000) backwards. + * in the boot process. We allocate these special addresses + * from the end of virtual memory (0xffffe000) backwards. * Also this lets us do fail-safe vmalloc(), we * can guarantee that these special addresses and * vmalloc()-ed addresses never overlap. @@ -41,11 +39,20 @@ * TLB entries of such buffers will not be flushed across * task switches. */ + +/* + * on UP currently we will have no trace of the fixmap mechanizm, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ enum fixed_addresses { FIX_HOLE, FIX_VSYSCALL, #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ +#else + FIX_VSTACK_HOLE_1, #endif #ifdef CONFIG_X86_IO_APIC FIX_IO_APIC_BASE_0, @@ -57,16 +64,21 @@ enum fixed_addresses { FIX_LI_PCIA, /* Lithium PCI Bridge A */ FIX_LI_PCIB, /* Lithium PCI Bridge B */ #endif -#ifdef CONFIG_X86_F00F_BUG - FIX_F00F_IDT, /* Virtual mapping for IDT */ -#endif + FIX_IDT, + FIX_GDT_1, + FIX_GDT_0, + FIX_TSS_3, + FIX_TSS_2, + FIX_TSS_1, + FIX_TSS_0, + FIX_ENTRY_TRAMPOLINE_1, + FIX_ENTRY_TRAMPOLINE_0, #ifdef CONFIG_X86_CYCLONE_TIMER FIX_CYCLONE_TIMER, /*cyclone timer register*/ + FIX_VSTACK_HOLE_2, #endif -#ifdef CONFIG_HIGHMEM FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, -#endif #ifdef CONFIG_ACPI_BOOT FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, @@ -95,12 +107,15 @@ extern void __set_fixmap (enum fixed_add __set_fixmap(idx, 0, __pgprot(0)) /* - * used by vmalloc.c. + * used by vmalloc.c and various other places. * * Leave one empty page between vmalloc'ed areas and * the start of the fixmap. + * + * IMPORTANT: dont change FIXADDR_TOP without adjusting KM_VSTACK0 + * and KM_VSTACK1 so that the virtual stack is 8K aligned. */ -#define FIXADDR_TOP (0xfffff000UL) +#define FIXADDR_TOP (0xffffe000UL) #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) --- linux-2.6.1-rc1/include/asm-i386/genapic.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-i386/genapic.h 2003-12-30 22:49:40.000000000 -0800 @@ -45,6 +45,7 @@ struct genapic { void (*setup_portio_remap)(void); int (*check_phys_apicid_present)(int boot_cpu_physical_apicid); void (*enable_apic_mode)(void); + u32 (*phys_pkg_id)(u32 cpuid_apic, int index_msb); /* mpparse */ void (*mpc_oem_bus_info)(struct mpc_config_bus *, char *, @@ -105,6 +106,7 @@ struct genapic { APICFUNC(send_IPI_allbutself), \ APICFUNC(send_IPI_all), \ APICFUNC(enable_apic_mode), \ + APICFUNC(phys_pkg_id), \ } extern struct genapic *genapic; --- linux-2.6.1-rc1/include/asm-i386/highmem.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/highmem.h 2003-12-30 22:50:18.000000000 -0800 @@ -25,26 +25,19 @@ #include #include #include +#include /* declarations for highmem.c */ extern unsigned long highstart_pfn, highend_pfn; -extern pte_t *kmap_pte; -extern pgprot_t kmap_prot; extern pte_t *pkmap_page_table; - -extern void kmap_init(void); +extern void kmap_init(void) __init; /* * Right now we initialize only a single pte table. It can be extended * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#if NR_CPUS <= 32 -#define PKMAP_BASE (0xff800000UL) -#else -#define PKMAP_BASE (0xff600000UL) -#endif #ifdef CONFIG_X86_PAE #define LAST_PKMAP 512 #else --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-i386/kgdb.h 2003-12-30 22:49:27.000000000 -0800 @@ -0,0 +1,69 @@ +#ifndef __KGDB +#define __KGDB + +/* + * This file should not include ANY others. This makes it usable + * most anywhere without the fear of include order or inclusion. + * Make it so! + * + * This file may be included all the time. It is only active if + * CONFIG_KGDB is defined, otherwise it stubs out all the macros + * and entry points. + */ +#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) + +extern void breakpoint(void); +#define INIT_KGDB_INTS kgdb_enable_ints() + +#ifndef BREAKPOINT +#define BREAKPOINT asm(" int $3") +#endif + +extern void kgdb_schedule_breakpoint(void); +extern void kgdb_process_breakpoint(void); + +extern int kgdb_tty_hook(void); +extern int kgdb_eth_hook(void); +extern int kgdboe; + +/* + * GDB debug stub (or any debug stub) can point the 'linux_debug_hook' + * pointer to its routine and it will be entered as the first thing + * when a trap occurs. + * + * Return values are, at present, undefined. + * + * The debug hook routine does not necessarily return to its caller. + * It has the register image and thus may choose to resume execution + * anywhere it pleases. + */ +struct pt_regs; + +extern int kgdb_handle_exception(int trapno, + int signo, int err_code, struct pt_regs *regs); +extern int in_kgdb(struct pt_regs *regs); + +#ifdef CONFIG_KGDB_TS +void kgdb_tstamp(int line, char *source, int data0, int data1); +/* + * This is the time stamp function. The macro adds the source info and + * does a cast on the data to allow most any 32-bit value. + */ + +#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1) +#else +#define kgdb_ts(data0,data1) +#endif +#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */ +#ifndef BREAKPOINT +#define BREAKPOINT +#endif +#define kgdb_ts(data0,data1) +#define in_kgdb +#define kgdb_handle_exception +#define breakpoint +#define INIT_KGDB_INTS +#define kgdb_process_breakpoint() do {} while(0) + +#endif +#endif /* __KGDB */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-i386/kgdb_local.h 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,102 @@ +#ifndef __KGDB_LOCAL +#define ___KGDB_LOCAL +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 0x3f8 +#ifdef CONFIG_KGDB_PORT +#undef PORT +#define PORT CONFIG_KGDB_PORT +#endif +#define IRQ 4 +#ifdef CONFIG_KGDB_IRQ +#undef IRQ +#define IRQ CONFIG_KGDB_IRQ +#endif +#define SB_CLOCK 1843200 +#define SB_BASE (SB_CLOCK/16) +#define SB_BAUD9600 SB_BASE/9600 +#define SB_BAUD192 SB_BASE/19200 +#define SB_BAUD384 SB_BASE/38400 +#define SB_BAUD576 SB_BASE/57600 +#define SB_BAUD1152 SB_BASE/115200 +#ifdef CONFIG_KGDB_9600BAUD +#define SB_BAUD SB_BAUD9600 +#endif +#ifdef CONFIG_KGDB_19200BAUD +#define SB_BAUD SB_BAUD192 +#endif +#ifdef CONFIG_KGDB_38400BAUD +#define SB_BAUD SB_BAUD384 +#endif +#ifdef CONFIG_KGDB_57600BAUD +#define SB_BAUD SB_BAUD576 +#endif +#ifdef CONFIG_KGDB_115200BAUD +#define SB_BAUD SB_BAUD1152 +#endif +#ifndef SB_BAUD +#define SB_BAUD SB_BAUD1152 /* Start with this if not given */ +#endif + +#ifndef CONFIG_X86_TSC +#undef rdtsc +#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;} +#undef rdtscll +#define rdtscll(s) s++ +#endif + +#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */ +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#define spin_lock _raw_spin_lock +#define spin_trylock _raw_spin_trylock +#define spin_unlock _raw_spin_unlock +#else +#endif +#undef spin_unlock_wait +#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \ + while(spin_is_locked(x)) + +#define SB_IER 1 +#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS + +#define FLAGS 0 +#define SB_STATE { \ + magic: SSTATE_MAGIC, \ + baud_base: SB_BASE, \ + port: PORT, \ + irq: IRQ, \ + flags: FLAGS, \ + custom_divisor:SB_BAUD} +#define SB_INFO { \ + magic: SERIAL_MAGIC, \ + port: PORT,0,FLAGS, \ + state: &state, \ + tty: (struct tty_struct *)&state, \ + IER: SB_IER, \ + MCR: SB_MCR} +extern void putDebugChar(int); +/* RTAI support needs us to really stop/start interrupts */ + +#define kgdb_sti() __asm__ __volatile__("sti": : :"memory") +#define kgdb_cli() __asm__ __volatile__("cli": : :"memory") +#define kgdb_local_save_flags(x) __asm__ __volatile__(\ + "pushfl ; popl %0":"=g" (x): /* no input */) +#define kgdb_local_irq_restore(x) __asm__ __volatile__(\ + "pushl %0 ; popfl": \ + /* no output */ :"g" (x):"memory", "cc") +#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli() + +#ifdef CONFIG_SERIAL +extern void shutdown_for_kgdb(struct async_struct *info); +#endif +#define INIT_KDEBUG putDebugChar("+"); +#endif /* __KGDB_LOCAL */ --- linux-2.6.1-rc1/include/asm-i386/kmap_types.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/kmap_types.h 2003-12-30 22:50:18.000000000 -0800 @@ -3,30 +3,36 @@ #include -#ifdef CONFIG_DEBUG_HIGHMEM -# define D(n) __KM_FENCE_##n , -#else -# define D(n) -#endif - enum km_type { -D(0) KM_BOUNCE_READ, -D(1) KM_SKB_SUNRPC_DATA, -D(2) KM_SKB_DATA_SOFTIRQ, -D(3) KM_USER0, -D(4) KM_USER1, -D(5) KM_BIO_SRC_IRQ, -D(6) KM_BIO_DST_IRQ, -D(7) KM_PTE0, -D(8) KM_PTE1, -D(9) KM_PTE2, -D(10) KM_IRQ0, -D(11) KM_IRQ1, -D(12) KM_SOFTIRQ0, -D(13) KM_SOFTIRQ1, -D(14) KM_TYPE_NR -}; - -#undef D + /* + * IMPORTANT: don't move these 3 entries, and only add entries in + * pairs: the 4G/4G virtual stack must be 8K aligned on each cpu. + */ + KM_BOUNCE_READ, + KM_VSTACK1, + KM_VSTACK0, + KM_LDT_PAGE15, + KM_LDT_PAGE0 = KM_LDT_PAGE15 + 16-1, + KM_USER_COPY, + KM_VSTACK_HOLE, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_PTE2, + KM_IRQ0, + KM_IRQ1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + /* + * Add new entries in pairs: + * the 4G/4G virtual stack must be 8K aligned on each cpu. + */ + KM_TYPE_NR +}; #endif --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-i386/lockmeter.h 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,123 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks. + * Added support for hold time statistics for read and write + * locks. + * Moved machine dependent code here from include/lockmeter.h. + * + */ + +#ifndef _I386_LOCKMETER_H +#define _I386_LOCKMETER_H + +#include +#include + +#include + +#ifdef __KERNEL__ +extern unsigned long cpu_khz; +#define CPU_CYCLE_FREQUENCY (cpu_khz * 1000) +#else +#define CPU_CYCLE_FREQUENCY 450000000 +#endif + +#define THIS_CPU_NUMBER smp_processor_id() + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define local_irq_save(x) \ + __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") + +#define local_irq_restore(x) \ + __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") +#endif /* Linux version 2.2.x */ + +/* + * macros to cache and retrieve an index value inside of a spin lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. Not normally a problem!! + * we also assume that the hash table has less than 65535 entries. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Intel is little endian */ + unsigned short lock; + unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) rwlock_ptr->lock; + /* read and write lock attempts may cause the lock value to temporarily */ + /* be negative. Until it is >= 0 we know nothing (i. e. can't tell if */ + /* is -1 because it was write locked and somebody tried to read lock it */ + /* or if it is -1 because it was read locked and somebody tried to write*/ + /* lock it. ........................................................... */ + do { + tmp = (int) rwlock_ptr->lock; + } while (tmp < 0); + if (tmp == 0) return(0); + else return(RW_LOCK_BIAS-tmp); +} + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0) +#define IABS(x) ((x) > 0 ? (x) : -(x)) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0) + +/* this is a lot of typing just to get gcc to emit "rdtsc" */ +static inline long long get_cycles64 (void) +{ + union longlong_u { + long long intlong; + struct intint_s { + uint32_t eax; + uint32_t edx; + } intint; + } longlong; + + rdtsc(longlong.intint.eax,longlong.intint.edx); + return longlong.intlong; +} + +#endif /* _I386_LOCKMETER_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-bigsmp/mach_apic.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-i386/mach-bigsmp/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -173,4 +173,9 @@ static inline unsigned int cpu_mask_to_a return apicid; } +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-default/mach_apic.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/asm-i386/mach-default/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -127,4 +127,9 @@ static inline void enable_apic_mode(void { } +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-es7000/mach_apic.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/asm-i386/mach-es7000/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -192,4 +192,9 @@ static inline unsigned int cpu_mask_to_a return apicid; } +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-generic/mach_apic.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-i386/mach-generic/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -27,5 +27,6 @@ #define check_apicid_used (genapic->check_apicid_used) #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) #define enable_apic_mode (genapic->enable_apic_mode) +#define phys_pkg_id (genapic->phys_pkg_id) #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-numaq/mach_apic.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-i386/mach-numaq/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -141,4 +141,10 @@ static inline unsigned int cpu_mask_to_a return (int) 0xF; } +/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */ +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-summit/mach_apic.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-i386/mach-summit/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -173,4 +173,15 @@ static inline unsigned int cpu_mask_to_a return apicid; } +/* cpuid returns the value latched in the HW at reset, not the APIC ID + * register's value. For any box whose BIOS changes APIC IDs, like + * clustered APIC systems, we must use hard_smp_processor_id. + * + * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID. + */ +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return hard_smp_processor_id() >> index_msb; +} + #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mach-visws/mach_apic.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-i386/mach-visws/mach_apic.h 2003-12-30 22:49:40.000000000 -0800 @@ -88,4 +88,10 @@ static inline unsigned int cpu_mask_to_a { return cpus_coerce_const(cpumask); } + +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + #endif /* __ASM_MACH_APIC_H */ --- linux-2.6.1-rc1/include/asm-i386/mmu_context.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/mmu_context.h 2003-12-30 22:50:18.000000000 -0800 @@ -29,6 +29,10 @@ static inline void switch_mm(struct mm_s { int cpu = smp_processor_id(); +#ifdef CONFIG_X86_SWITCH_PAGETABLES + if (tsk->mm) + tsk->thread_info->user_pgd = (void *)__pa(tsk->mm->pgd); +#endif if (likely(prev != next)) { /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); @@ -39,12 +43,14 @@ static inline void switch_mm(struct mm_s cpu_set(cpu, next->cpu_vm_mask); /* Re-load page tables */ +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) load_cr3(next->pgd); +#endif /* * load the LDT, if the LDT is different: */ - if (unlikely(prev->context.ldt != next->context.ldt)) + if (unlikely(prev->context.size + next->context.size)) load_LDT_nolock(&next->context, cpu); } #ifdef CONFIG_SMP @@ -56,7 +62,9 @@ static inline void switch_mm(struct mm_s /* We were in lazy tlb mode and leave_mm disabled * tlb flush IPI delivery. We must reload %cr3. */ +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) load_cr3(next->pgd); +#endif load_LDT_nolock(&next->context, cpu); } } @@ -67,6 +75,6 @@ static inline void switch_mm(struct mm_s asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0)) #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL) + switch_mm((prev),(next),current) #endif --- linux-2.6.1-rc1/include/asm-i386/mmu.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/mmu.h 2003-12-30 22:50:18.000000000 -0800 @@ -8,10 +8,13 @@ * * cpu_vm_mask is used to optimize ldt flushing. */ + +#define MAX_LDT_PAGES 16 + typedef struct { int size; struct semaphore sem; - void *ldt; + struct page *ldt_pages[MAX_LDT_PAGES]; } mm_context_t; #endif --- linux-2.6.1-rc1/include/asm-i386/page.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/page.h 2003-12-30 22:50:18.000000000 -0800 @@ -1,6 +1,8 @@ #ifndef _I386_PAGE_H #define _I386_PAGE_H +#include + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -9,11 +11,10 @@ #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ - #include +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ #ifdef CONFIG_X86_USE_3DNOW #include @@ -88,8 +89,19 @@ typedef struct { unsigned long pgprot; } * * If you want more physical memory than this then see the CONFIG_HIGHMEM4G * and CONFIG_HIGHMEM64G options in the kernel configuration. + * + * Note: on PAE the kernel must never go below 32 MB, we use the + * first 8 entries of the 2-level boot pgd for PAE magic. */ +#ifdef CONFIG_X86_4G_VM_LAYOUT +#define __PAGE_OFFSET (0x02000000) +#define TASK_SIZE (0xff000000) +#else +#define __PAGE_OFFSET (0xc0000000) +#define TASK_SIZE (0xc0000000) +#endif + /* * This much address space is reserved for vmalloc() and iomap() * as well as fixmap mappings. @@ -114,16 +126,10 @@ static __inline__ int get_order(unsigned #endif /* __ASSEMBLY__ */ -#ifdef __ASSEMBLY__ -#define __PAGE_OFFSET (0xC0000000) -#else -#define __PAGE_OFFSET (0xC0000000UL) -#endif - - #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) -#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define __MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) --- linux-2.6.1-rc1/include/asm-i386/pgtable.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/pgtable.h 2003-12-30 22:50:18.000000000 -0800 @@ -32,16 +32,17 @@ #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) extern unsigned long empty_zero_page[1024]; extern pgd_t swapper_pg_dir[1024]; -extern kmem_cache_t *pgd_cache; -extern kmem_cache_t *pmd_cache; +extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; extern spinlock_t pgd_lock; extern struct list_head pgd_list; void pmd_ctor(void *, kmem_cache_t *, unsigned long); +void kpmd_ctor(void *, kmem_cache_t *, unsigned long); void pgd_ctor(void *, kmem_cache_t *, unsigned long); void pgd_dtor(void *, kmem_cache_t *, unsigned long); void pgtable_cache_init(void); void paging_init(void); +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end); #endif /* !__ASSEMBLY__ */ @@ -51,6 +52,11 @@ void paging_init(void); * newer 3-level PAE-mode page tables. */ #ifndef __ASSEMBLY__ + +extern void set_system_gate(unsigned int n, void *addr); +extern void init_entry_mappings(void); +extern void entry_trampoline_setup(void); + #ifdef CONFIG_X86_PAE # include #else @@ -63,7 +69,12 @@ void paging_init(void); #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) +#if defined(CONFIG_X86_PAE) && defined(CONFIG_X86_4G_VM_LAYOUT) +# define USER_PTRS_PER_PGD 4 +#else +# define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) + ((TASK_SIZE % PGDIR_SIZE) + PGDIR_SIZE-1)/PGDIR_SIZE) +#endif + #define FIRST_USER_PGD_NR 0 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) @@ -233,6 +244,7 @@ static inline void ptep_mkdirty(pte_t *p #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) #define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE) +#define mk_pte_phys(physpage, pgprot) pfn_pte((physpage) >> PAGE_SHIFT, pgprot) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { --- linux-2.6.1-rc1/include/asm-i386/processor.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/asm-i386/processor.h 2003-12-30 22:50:18.000000000 -0800 @@ -291,11 +291,6 @@ extern unsigned int machine_submodel_id; extern unsigned int BIOS_revision; extern unsigned int mca_pentium_flag; -/* - * User space process size: 3GB (default). - */ -#define TASK_SIZE (PAGE_OFFSET) - /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ @@ -406,6 +401,7 @@ struct tss_struct { struct thread_struct { /* cached TLS descriptors. */ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; + void *stack_page0, *stack_page1; unsigned long esp0; unsigned long sysenter_cs; unsigned long eip; @@ -449,7 +445,8 @@ struct thread_struct { .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \ } -static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread) +static inline void +load_esp0(struct tss_struct *tss, struct thread_struct *thread) { tss->esp0 = thread->esp0; /* This can only happen when SEP is enabled, no need to test "SEP"arately */ @@ -485,6 +482,23 @@ extern void prepare_to_copy(struct task_ */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +#ifdef CONFIG_X86_HIGH_ENTRY +#define virtual_esp0(tsk) \ + ((unsigned long)(tsk)->thread_info->virtual_stack + ((tsk)->thread.esp0 - (unsigned long)(tsk)->thread_info->real_stack)) +#else +# define virtual_esp0(tsk) ((tsk)->thread.esp0) +#endif + +#define load_virtual_esp0(tss, task) \ + do { \ + tss->esp0 = virtual_esp0(task); \ + if (likely(cpu_has_sep) && unlikely(tss->ss1 != task->thread.sysenter_cs)) { \ + tss->ss1 = task->thread.sysenter_cs; \ + wrmsr(MSR_IA32_SYSENTER_CS, \ + task->thread.sysenter_cs, 0); \ + } \ + } while (0) + extern unsigned long thread_saved_pc(struct task_struct *tsk); void show_trace(struct task_struct *task, unsigned long *stack); --- linux-2.6.1-rc1/include/asm-i386/rwlock.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/rwlock.h 2003-12-30 22:49:43.000000000 -0800 @@ -20,28 +20,52 @@ #define RW_LOCK_BIAS 0x01000000 #define RW_LOCK_BIAS_STR "0x01000000" -#define __build_read_lock_ptr(rw, helper) \ - asm volatile(LOCK "subl $1,(%0)\n\t" \ - "js 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tcall " helper "\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - ::"a" (rw) : "memory") - -#define __build_read_lock_const(rw, helper) \ - asm volatile(LOCK "subl $1,%0\n\t" \ - "js 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tpushl %%eax\n\t" \ - "leal %0,%%eax\n\t" \ - "call " helper "\n\t" \ - "popl %%eax\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - :"=m" (*(volatile int *)rw) : : "memory") +#ifdef CONFIG_SPINLINE + + #define __build_read_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $1,(%0)\n\t" \ + "jns 1f\n\t" \ + "call " helper "\n\t" \ + "1:\t" \ + ::"a" (rw) : "memory") + + #define __build_read_lock_const(rw, helper) \ + asm volatile(LOCK "subl $1,%0\n\t" \ + "jns 1f\n\t" \ + "pushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "1:\t" \ + :"=m" (*(volatile int *)rw) : : "memory") + +#else /* !CONFIG_SPINLINE */ + + #define __build_read_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $1,(%0)\n\t" \ + "js 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tcall " helper "\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + ::"a" (rw) : "memory") + + #define __build_read_lock_const(rw, helper) \ + asm volatile(LOCK "subl $1,%0\n\t" \ + "js 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tpushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + :"=m" (*(volatile int *)rw) : : "memory") + +#endif /* CONFIG_SPINLINE */ + #define __build_read_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ @@ -50,28 +74,51 @@ __build_read_lock_ptr(rw, helper); \ } while (0) -#define __build_write_lock_ptr(rw, helper) \ - asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ - "jnz 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tcall " helper "\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - ::"a" (rw) : "memory") - -#define __build_write_lock_const(rw, helper) \ - asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ - "jnz 2f\n" \ - "1:\n" \ - LOCK_SECTION_START("") \ - "2:\tpushl %%eax\n\t" \ - "leal %0,%%eax\n\t" \ - "call " helper "\n\t" \ - "popl %%eax\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END \ - :"=m" (*(volatile int *)rw) : : "memory") +#ifdef CONFIG_SPINLINE + + #define __build_write_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ + "jz 1f\n\t" \ + "call " helper "\n\t" \ + "1:\n" \ + ::"a" (rw) : "memory") + + #define __build_write_lock_const(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ + "jz 1f\n\t" \ + "pushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "1:\n" \ + :"=m" (*(volatile int *)rw) : : "memory") + +#else /* !CONFIG_SPINLINE */ + + #define __build_write_lock_ptr(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ + "jnz 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tcall " helper "\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + ::"a" (rw) : "memory") + + #define __build_write_lock_const(rw, helper) \ + asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ + "jnz 2f\n" \ + "1:\n" \ + LOCK_SECTION_START("") \ + "2:\tpushl %%eax\n\t" \ + "leal %0,%%eax\n\t" \ + "call " helper "\n\t" \ + "popl %%eax\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END \ + :"=m" (*(volatile int *)rw) : : "memory") + +#endif /* CONFIG_SPINLINE */ #define __build_write_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ --- linux-2.6.1-rc1/include/asm-i386/smp.h 2003-09-08 13:58:59.000000000 -0700 +++ 25/include/asm-i386/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -53,8 +53,7 @@ extern void zap_low_mappings (void); #define smp_processor_id() (current_thread_info()->cpu) extern cpumask_t cpu_callout_map; - -#define cpu_possible(cpu) cpu_isset(cpu, cpu_callout_map) +#define cpu_possible_map cpu_callout_map /* We don't mark CPUs online until __cpu_up(), so we need another measure */ static inline int num_booting_cpus(void) --- linux-2.6.1-rc1/include/asm-i386/spinlock.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/spinlock.h 2003-12-30 22:50:17.000000000 -0800 @@ -43,18 +43,35 @@ typedef struct { #define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) -#define spin_lock_string \ - "\n1:\t" \ - "lock ; decb %0\n\t" \ - "js 2f\n" \ - LOCK_SECTION_START("") \ - "2:\t" \ - "rep;nop\n\t" \ - "cmpb $0,%0\n\t" \ - "jle 2b\n\t" \ - "jmp 1b\n" \ - LOCK_SECTION_END +#ifdef CONFIG_SPINLINE + #define spin_lock_string \ + "\n1:\t" \ + "lock ; decb %0\n\t" \ + "js 2f\n" \ + "jmp 3f\n" \ + "2:\t" \ + "rep;nop\n\t" \ + "cmpb $0,%0\n\t" \ + "jle 2b\n\t" \ + "jmp 1b\n" \ + "3:\t" + +#else /* !CONFIG_SPINLINE */ + + #define spin_lock_string \ + "\n1:\t" \ + "lock ; decb %0\n\t" \ + "js 2f\n" \ + LOCK_SECTION_START("") \ + "2:\t" \ + "rep;nop\n\t" \ + "cmpb $0,%0\n\t" \ + "jle 2b\n\t" \ + "jmp 1b\n" \ + LOCK_SECTION_END + +#endif /* CONFIG_SPINLINE */ /* * This works. Despite all the confusion. * (except on PPro SMP or if we are using OOSTORE) @@ -138,6 +155,11 @@ here: */ typedef struct { volatile unsigned int lock; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif #ifdef CONFIG_DEBUG_SPINLOCK unsigned magic; #endif @@ -145,11 +167,19 @@ typedef struct { #define RWLOCK_MAGIC 0xdeaf1eed +#ifdef CONFIG_LOCKMETER +#ifdef CONFIG_DEBUG_SPINLOCK +#define RWLOCK_MAGIC_INIT , 0, RWLOCK_MAGIC +#else +#define RWLOCK_MAGIC_INIT , 0 +#endif +#else /* !CONFIG_LOCKMETER */ #ifdef CONFIG_DEBUG_SPINLOCK #define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC #else #define RWLOCK_MAGIC_INIT /* */ #endif +#endif /* !CONFIG_LOCKMETER */ #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } @@ -196,4 +226,60 @@ static inline int _raw_write_trylock(rwl return 0; } +#ifdef CONFIG_LOCKMETER +static inline int _raw_read_trylock(rwlock_t *lock) +{ +/* FIXME -- replace with assembler */ + atomic_t *count = (atomic_t *)lock; + atomic_dec(count); + if (count->counter > 0) + return 1; + atomic_inc(count); + return 0; +} +#endif + +#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK) +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock(spinlock_t *lock); + +/* + * Matches what is in arch/i386/lib/dec_and_lock.c, except this one is + * "static inline" so that the spin_lock(), if actually invoked, is charged + * against the real caller, not against the catch-all atomic_dec_and_lock + */ +static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + int counter; + int newcount; + +repeat: + counter = atomic_read(atomic); + newcount = counter-1; + + if (!newcount) + goto slow_path; + + asm volatile("lock; cmpxchgl %1,%2" + :"=a" (newcount) + :"r" (newcount), "m" (atomic->counter), "0" (counter)); + + /* If the above failed, "eax" will have changed */ + if (newcount != counter) + goto repeat; + return 0; + +slow_path: + preempt_disable(); + _metered_spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + _metered_spin_unlock(lock); + preempt_enable(); + return 0; +} + +#define ATOMIC_DEC_AND_LOCK +#endif + #endif /* __ASM_SPINLOCK_H */ --- linux-2.6.1-rc1/include/asm-i386/string.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/asm-i386/string.h 2003-12-30 22:50:18.000000000 -0800 @@ -56,6 +56,29 @@ __asm__ __volatile__( return dest; } +/* + * This is a more generic variant of strncpy_count() suitable for + * implementing string-access routines with all sorts of return + * code semantics. It's used by mm/usercopy.c. + */ +static inline size_t strncpy_count(char * dest,const char *src,size_t count) +{ + __asm__ __volatile__( + + "1:\tdecl %0\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "2:" + "incl %0" + : "=c" (count) + :"S" (src),"D" (dest),"0" (count) : "memory"); + + return count; +} + #define __HAVE_ARCH_STRCAT static inline char * strcat(char * dest,const char * src) { --- linux-2.6.1-rc1/include/asm-i386/system.h 2003-06-14 12:17:56.000000000 -0700 +++ 25/include/asm-i386/system.h 2003-12-30 22:49:41.000000000 -0800 @@ -470,6 +470,7 @@ void enable_hlt(void); extern unsigned long dmi_broken; extern int is_sony_vaio_laptop; +extern int es7000_plat; #define BROKEN_ACPI_Sx 0x0001 #define BROKEN_INIT_AFTER_S1 0x0002 --- linux-2.6.1-rc1/include/asm-i386/thread_info.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/thread_info.h 2003-12-30 22:50:18.000000000 -0800 @@ -33,23 +33,12 @@ struct thread_info { 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ - struct restart_block restart_block; + void *real_stack, *virtual_stack, *user_pgd; + struct restart_block restart_block; __u8 supervisor_stack[0]; }; -#else /* !__ASSEMBLY__ */ - -/* offsets into the thread_info struct for assembly code access */ -#define TI_TASK 0x00000000 -#define TI_EXEC_DOMAIN 0x00000004 -#define TI_FLAGS 0x00000008 -#define TI_STATUS 0x0000000C -#define TI_CPU 0x00000010 -#define TI_PRE_COUNT 0x00000014 -#define TI_ADDR_LIMIT 0x00000018 -#define TI_RESTART_BLOCK 0x000001C - #endif #define PREEMPT_ACTIVE 0x4000000 @@ -61,7 +50,7 @@ struct thread_info { */ #ifndef __ASSEMBLY__ -#define INIT_THREAD_INFO(tsk) \ +#define INIT_THREAD_INFO(tsk, thread_info) \ { \ .task = &tsk, \ .exec_domain = &default_exec_domain, \ @@ -72,6 +61,7 @@ struct thread_info { .restart_block = { \ .fn = do_no_restart_syscall, \ }, \ + .real_stack = &thread_info, \ } #define init_thread_info (init_thread_union.thread_info) @@ -113,6 +103,7 @@ static inline struct thread_info *curren #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_IRET 5 /* return with iret */ +#define TIF_DB7 6 /* has debug registers */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define _TIF_SYSCALL_TRACE (1<active_mm) __flush_tlb(); +#endif } static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (vma->vm_mm == current->active_mm) __flush_tlb_one(addr); +#endif } static inline void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (vma->vm_mm == current->active_mm) __flush_tlb(); +#endif } #else @@ -111,11 +117,10 @@ static inline void flush_tlb_range(struc __flush_tlb() extern void flush_tlb_all(void); -extern void flush_tlb_current_task(void); extern void flush_tlb_mm(struct mm_struct *); extern void flush_tlb_page(struct vm_area_struct *, unsigned long); -#define flush_tlb() flush_tlb_current_task() +#define flush_tlb() flush_tlb_all() static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end) { --- linux-2.6.1-rc1/include/asm-i386/uaccess.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/uaccess.h 2003-12-30 22:50:18.000000000 -0800 @@ -26,7 +26,7 @@ #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) +#define USER_DS MAKE_MM_SEG(TASK_SIZE) #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) @@ -149,6 +149,45 @@ extern void __get_user_4(void); :"=a" (ret),"=d" (x) \ :"0" (ptr)) +extern int get_user_size(unsigned int size, void *val, const void *ptr); +extern int put_user_size(unsigned int size, const void *val, void *ptr); +extern int zero_user_size(unsigned int size, void *ptr); +extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr); +extern int strlen_fromuser_size(unsigned int size, const void *ptr); + + +# define indirect_get_user(x,ptr) \ +({ int __ret_gu,__val_gu; \ + __typeof__(ptr) __ptr_gu = (ptr); \ + __ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\ + (x) = (__typeof__(*__ptr_gu))__val_gu; \ + __ret_gu; \ +}) +#define indirect_put_user(x,ptr) \ +({ \ + __typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x); \ + put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \ +}) +#define __indirect_put_user indirect_put_user +#define __indirect_get_user indirect_get_user + +#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from) +#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to) + +#define __indirect_copy_from_user indirect_copy_from_user +#define __indirect_copy_to_user indirect_copy_to_user + +#define indirect_strncpy_from_user(dst, src, count) \ + copy_str_fromuser_size(count, dst, src) + +extern int strlen_fromuser_size(unsigned int size, const void *ptr); +#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str) +#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1) + +extern int zero_user_size(unsigned int size, void *ptr); + +#define indirect_clear_user(mem, len) zero_user_size(len, mem) +#define __indirect_clear_user clear_user /* Careful: we have to cast the result to the type of the pointer for sign reasons */ /** @@ -168,7 +207,7 @@ extern void __get_user_4(void); * Returns zero on success, or -EFAULT on error. * On error, the variable @x is set to zero. */ -#define get_user(x,ptr) \ +#define direct_get_user(x,ptr) \ ({ int __ret_gu,__val_gu; \ switch(sizeof (*(ptr))) { \ case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ @@ -198,7 +237,7 @@ extern void __put_user_bad(void); * * Returns zero on success, or -EFAULT on error. */ -#define put_user(x,ptr) \ +#define direct_put_user(x,ptr) \ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) @@ -222,7 +261,7 @@ extern void __put_user_bad(void); * Returns zero on success, or -EFAULT on error. * On error, the variable @x is set to zero. */ -#define __get_user(x,ptr) \ +#define __direct_get_user(x,ptr) \ __get_user_nocheck((x),(ptr),sizeof(*(ptr))) @@ -245,7 +284,7 @@ extern void __put_user_bad(void); * * Returns zero on success, or -EFAULT on error. */ -#define __put_user(x,ptr) \ +#define __direct_put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __put_user_nocheck(x,ptr,size) \ @@ -396,7 +435,7 @@ unsigned long __copy_from_user_ll(void * * On success, this will be zero. */ static inline unsigned long -__copy_to_user(void __user *to, const void *from, unsigned long n) +__direct_copy_to_user(void __user *to, const void *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -434,7 +473,7 @@ __copy_to_user(void __user *to, const vo * data to the requested size using zero bytes. */ static inline unsigned long -__copy_from_user(void *to, const void __user *from, unsigned long n) +__direct_copy_from_user(void *to, const void __user *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -468,11 +507,11 @@ __copy_from_user(void *to, const void __ * On success, this will be zero. */ static inline unsigned long -copy_to_user(void __user *to, const void *from, unsigned long n) +direct_copy_to_user(void __user *to, const void *from, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) - n = __copy_to_user(to, from, n); + n = __direct_copy_to_user(to, from, n); return n; } @@ -493,11 +532,11 @@ copy_to_user(void __user *to, const void * data to the requested size using zero bytes. */ static inline unsigned long -copy_from_user(void *to, const void __user *from, unsigned long n) +direct_copy_from_user(void *to, const void __user *from, unsigned long n) { might_sleep(); if (access_ok(VERIFY_READ, from, n)) - n = __copy_from_user(to, from, n); + n = __direct_copy_from_user(to, from, n); else memset(to, 0, n); return n; @@ -520,10 +559,68 @@ long __strncpy_from_user(char *dst, cons * If there is a limit on the length of a valid string, you may wish to * consider using strnlen_user() instead. */ -#define strlen_user(str) strnlen_user(str, ~0UL >> 1) -long strnlen_user(const char __user *str, long n); -unsigned long clear_user(void __user *mem, unsigned long len); -unsigned long __clear_user(void __user *mem, unsigned long len); +long direct_strncpy_from_user(char *dst, const char *src, long count); +long __direct_strncpy_from_user(char *dst, const char *src, long count); +#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1) +long direct_strnlen_user(const char *str, long n); +unsigned long direct_clear_user(void *mem, unsigned long len); +unsigned long __direct_clear_user(void *mem, unsigned long len); + +extern int indirect_uaccess; + +#ifdef CONFIG_X86_UACCESS_INDIRECT + +/* + * Return code and zeroing semantics: + + __clear_user 0 <-> bytes not done + clear_user 0 <-> bytes not done + __copy_to_user 0 <-> bytes not done + copy_to_user 0 <-> bytes not done + __copy_from_user 0 <-> bytes not done, zero rest + copy_from_user 0 <-> bytes not done, zero rest + __get_user 0 <-> -EFAULT + get_user 0 <-> -EFAULT + __put_user 0 <-> -EFAULT + put_user 0 <-> -EFAULT + strlen_user strlen + 1 <-> 0 + strnlen_user strlen + 1 (or n+1) <-> 0 + strncpy_from_user strlen (or n) <-> -EFAULT + + */ + +#define __clear_user(mem,len) __indirect_clear_user(mem,len) +#define clear_user(mem,len) indirect_clear_user(mem,len) +#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n) +#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n) +#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n) +#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n) +#define __get_user(val,ptr) __indirect_get_user(val,ptr) +#define get_user(val,ptr) indirect_get_user(val,ptr) +#define __put_user(val,ptr) __indirect_put_user(val,ptr) +#define put_user(val,ptr) indirect_put_user(val,ptr) +#define strlen_user(str) indirect_strlen_user(str) +#define strnlen_user(src,count) indirect_strnlen_user(src,count) +#define strncpy_from_user(dst,src,count) \ + indirect_strncpy_from_user(dst,src,count) + +#else + +#define __clear_user __direct_clear_user +#define clear_user direct_clear_user +#define __copy_to_user __direct_copy_to_user +#define copy_to_user direct_copy_to_user +#define __copy_from_user __direct_copy_from_user +#define copy_from_user direct_copy_from_user +#define __get_user __direct_get_user +#define get_user direct_get_user +#define __put_user __direct_put_user +#define put_user direct_put_user +#define strlen_user direct_strlen_user +#define strnlen_user direct_strnlen_user +#define strncpy_from_user direct_strncpy_from_user + +#endif /* CONFIG_X86_UACCESS_INDIRECT */ #endif /* __i386_UACCESS_H */ --- linux-2.6.1-rc1/include/asm-ia64/byteorder.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-ia64/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -8,8 +8,9 @@ #include #include +#include -static __inline__ __const__ __u64 +static __inline__ __attribute_const__ __u64 __ia64_swab64 (__u64 x) { __u64 result; @@ -18,13 +19,13 @@ __ia64_swab64 (__u64 x) return result; } -static __inline__ __const__ __u32 +static __inline__ __attribute_const__ __u32 __ia64_swab32 (__u32 x) { return __ia64_swab64(x) >> 32; } -static __inline__ __const__ __u16 +static __inline__ __attribute_const__ __u16 __ia64_swab16(__u16 x) { return __ia64_swab64(x) >> 48; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-ia64/lockmeter.h 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + */ + +#ifndef _IA64_LOCKMETER_H +#define _IA64_LOCKMETER_H + +#ifdef local_cpu_data +#define CPU_CYCLE_FREQUENCY local_cpu_data->itc_freq +#else +#define CPU_CYCLE_FREQUENCY my_cpu_data.itc_freq +#endif +#define get_cycles64() get_cycles() + +#define THIS_CPU_NUMBER smp_processor_id() + +/* + * macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * we also assume that the hash table has less than 32767 entries. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Intel is little endian */ + volatile unsigned short lock; + volatile unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int read_counter:31; + volatile int write_lock:1; + volatile unsigned short index; + volatile unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) ((rwlock_ptr)->read_counter) + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((rwlock_ptr)->read_counter) + +#endif /* _IA64_LOCKMETER_H */ + --- linux-2.6.1-rc1/include/asm-ia64/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-ia64/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -48,7 +48,7 @@ extern volatile int ia64_cpu_to_sapicid[ extern unsigned long ap_wakeup_vector; -#define cpu_possible(cpu) cpu_isset(cpu, phys_cpu_present_map) +#define cpu_possible_map phys_cpu_present_map /* * Function to map hard smp processor id to logical id. Slow, so don't use this in --- linux-2.6.1-rc1/include/asm-ia64/spinlock.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/asm-ia64/spinlock.h 2003-12-30 22:50:17.000000000 -0800 @@ -110,8 +110,18 @@ do { \ typedef struct { volatile int read_counter : 31; volatile int write_lock : 1; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif } rwlock_t; + +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *) (x) != 0) @@ -127,6 +137,48 @@ do { \ } \ } while (0) +#ifdef CONFIG_LOCKMETER +/* + * HACK: This works, but still have a timing window that affects performance: + * we see that no one owns the Write lock, then someone * else grabs for Write + * lock before we do a read_lock(). + * This means that on rare occasions our read_lock() will stall and spin-wait + * until we acquire for Read, instead of simply returning a trylock failure. + */ +static inline int _raw_read_trylock(rwlock_t *rw) +{ + if (rw->write_lock) { + return 0; + } else { + _raw_read_lock(rw); + return 1; + } +} + +static inline int _raw_write_trylock(rwlock_t *rw) +{ + if (!(rw->write_lock)) { + /* isn't currently write-locked... that looks promising... */ + if (test_and_set_bit(31, rw) == 0) { + /* now it is write-locked by me... */ + if (rw->read_counter) { + /* really read-locked, so release write-lock and fail */ + clear_bit(31, rw); + } else { + /* we've the the write-lock, no read-lockers... success! */ + barrier(); + return 1; + } + + } + } + + /* falls through ... fails to write-lock */ + barrier(); + return 0; +} +#endif + #define _raw_read_unlock(rw) \ do { \ rwlock_t *__read_lock_ptr = (rw); \ @@ -190,4 +242,25 @@ do { \ clear_bit(31, (x)); \ }) +#ifdef CONFIG_LOCKMETER +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock(spinlock_t *lock); + +/* + * Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering + * so we can see the callerPC of who is actually doing the spin_lock(). + * Otherwise, all we see is the generic rollup of all locks done by + * atomic_dec_and_lock(). + */ +static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + _metered_spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + _metered_spin_unlock(lock); + return 0; +} +#define ATOMIC_DEC_AND_LOCK +#endif + #endif /* _ASM_IA64_SPINLOCK_H */ --- linux-2.6.1-rc1/include/asm-m68k/byteorder.h 2003-06-14 12:18:08.000000000 -0700 +++ 25/include/asm-m68k/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -2,10 +2,11 @@ #define _M68K_BYTEORDER_H #include +#include #ifdef __GNUC__ -static __inline__ __const__ __u32 ___arch__swab32(__u32 val) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 val) { __asm__("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); return val; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-mips/lockmeter.h 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * Ported to mips32 for Asita Technologies + * by D.J. Barrow ( dj.barrow@asitatechnologies.com ) + */ +#ifndef _ASM_LOCKMETER_H +#define _ASM_LOCKMETER_H + +/* do_gettimeoffset is a function pointer on mips */ +/* & it is not included by */ +#include +#include +#include + +#define SPINLOCK_MAGIC_INIT /* */ + +#define CPU_CYCLE_FREQUENCY get_cpu_cycle_frequency() + +#define THIS_CPU_NUMBER smp_processor_id() + +static uint32_t cpu_cycle_frequency = 0; + +static uint32_t get_cpu_cycle_frequency(void) +{ + /* a total hack, slow and invasive, but ... it works */ + int sec; + uint32_t start_cycles; + struct timeval tv; + + if (cpu_cycle_frequency == 0) { /* uninitialized */ + do_gettimeofday(&tv); + sec = tv.tv_sec; /* set up to catch the tv_sec rollover */ + while (sec == tv.tv_sec) { do_gettimeofday(&tv); } + sec = tv.tv_sec; /* rolled over to a new sec value */ + start_cycles = get_cycles(); + while (sec == tv.tv_sec) { do_gettimeofday(&tv); } + cpu_cycle_frequency = get_cycles() - start_cycles; + } + + return cpu_cycle_frequency; +} + +extern struct timeval xtime; + +static uint64_t get_cycles64(void) +{ + static uint64_t last_get_cycles64 = 0; + uint64_t ret; + unsigned long sec; + unsigned long usec, usec_offset; + +again: + sec = xtime.tv_sec; + usec = xtime.tv_usec; + usec_offset = do_gettimeoffset(); + if ((xtime.tv_sec != sec) || + (xtime.tv_usec != usec)|| + (usec_offset >= 20000)) + goto again; + + ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency); + /* We can't do a normal 64 bit division on mips without libgcc.a */ + do_div(ret,1000000); + ret += ((uint64_t)sec * cpu_cycle_frequency); + + /* XXX why does time go backwards? do_gettimeoffset? general time adj? */ + if (ret <= last_get_cycles64) + ret = last_get_cycles64+1; + last_get_cycles64 = ret; + + return ret; +} + +/* + * macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * we also assume that the hash table has less than 32767 entries. + * the high order bit is used for write locking a rw_lock + */ +#define INDEX_MASK 0x7FFF0000 +#define READERS_MASK 0x0000FFFF +#define INDEX_SHIFT 16 +#define PUT_INDEX(lockp,index) \ + lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT) +#define GET_INDEX(lockp) \ + (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT) + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) rwlock_ptr->lock; + return (tmp >= 0) ? tmp : 0; +} + +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock > 0) + +#endif /* _ASM_LOCKMETER_H */ --- linux-2.6.1-rc1/include/asm-mips/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-mips/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -48,8 +48,8 @@ extern struct call_data_struct *call_dat extern cpumask_t phys_cpu_present_map; extern cpumask_t cpu_online_map; +#define cpu_possible_map phys_cpu_present_map -#define cpu_possible(cpu) cpu_isset(cpu, phys_cpu_present_map) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) static inline unsigned int num_online_cpus(void) --- linux-2.6.1-rc1/include/asm-mips/spinlock.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-mips/spinlock.h 2003-12-30 22:50:17.000000000 -0800 @@ -91,9 +91,18 @@ static inline unsigned int _raw_spin_try typedef struct { volatile unsigned int lock; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif } rwlock_t; +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) --- linux-2.6.1-rc1/include/asm-parisc/byteorder.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-parisc/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -2,10 +2,11 @@ #define _PARISC_BYTEORDER_H #include +#include #ifdef __GNUC__ -static __inline__ __const__ __u16 ___arch__swab16(__u16 x) +static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) { __asm__("dep %0, 15, 8, %0\n\t" /* deposit 00ab -> 0bab */ "shd %%r0, %0, 8, %0" /* shift 000000ab -> 00ba */ @@ -14,7 +15,7 @@ static __inline__ __const__ __u16 ___arc return x; } -static __inline__ __const__ __u32 ___arch__swab24(__u32 x) +static __inline__ __attribute_const__ __u32 ___arch__swab24(__u32 x) { __asm__("shd %0, %0, 8, %0\n\t" /* shift xabcxabc -> cxab */ "dep %0, 15, 8, %0\n\t" /* deposit cxab -> cbab */ @@ -24,7 +25,7 @@ static __inline__ __const__ __u32 ___arc return x; } -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) { unsigned int temp; __asm__("shd %0, %0, 16, %1\n\t" /* shift abcdabcd -> cdab */ @@ -47,7 +48,7 @@ static __inline__ __const__ __u32 ___arc ** HSHR 67452301 -> *6*4*2*0 into %0 ** OR %0 | %1 -> 76543210 into %0 (all done!) */ -static __inline__ __const__ __u64 ___arch__swab64(__u64 x) { +static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) { __u64 temp; __asm__("permh,3210 %0, %0\n\t" "hshl %0, 8, %1\n\t" @@ -60,7 +61,7 @@ static __inline__ __const__ __u64 ___arc #define __arch__swab64(x) ___arch__swab64(x) #define __BYTEORDER_HAS_U64__ #elif !defined(__STRICT_ANSI__) -static __inline__ __const__ __u64 ___arch__swab64(__u64 x) +static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) { __u32 t1 = ___arch__swab32((__u32) x); __u32 t2 = ___arch__swab32((__u32) (x >> 32)); --- linux-2.6.1-rc1/include/asm-parisc/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-parisc/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -54,7 +54,7 @@ extern unsigned long cpu_present_mask; #define smp_processor_id() (current_thread_info()->cpu) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) -#define cpu_possible(cpu) cpu_isset(cpu, cpu_present_mask) +#define cpu_possible_map cpu_present_map #endif /* CONFIG_SMP */ --- linux-2.6.1-rc1/include/asm-ppc64/byteorder.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/include/asm-ppc64/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -9,6 +9,7 @@ */ #include +#include #ifdef __GNUC__ #ifdef __KERNEL__ @@ -40,7 +41,7 @@ static __inline__ void st_le32(volatile } #if 0 -static __inline__ __const__ __u16 ___arch__swab16(__u16 value) +static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value) { __u16 result; @@ -50,7 +51,7 @@ static __inline__ __const__ __u16 ___arc return result; } -static __inline__ __const__ __u32 ___arch__swab32(__u32 value) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) { __u32 result; @@ -62,7 +63,7 @@ static __inline__ __const__ __u32 ___arc return result; } -static __inline__ __const__ __u64 ___arch__swab64(__u64 value) +static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 value) { __u64 result; #error implement me --- linux-2.6.1-rc1/include/asm-ppc/byteorder.h 2003-06-14 12:18:09.000000000 -0700 +++ 25/include/asm-ppc/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -2,6 +2,7 @@ #define _PPC_BYTEORDER_H #include +#include #ifdef __GNUC__ #ifdef __KERNEL__ @@ -32,7 +33,7 @@ extern __inline__ void st_le32(volatile __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } -static __inline__ __const__ __u16 ___arch__swab16(__u16 value) +static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value) { __u16 result; @@ -40,7 +41,7 @@ static __inline__ __const__ __u16 ___arc return result; } -static __inline__ __const__ __u32 ___arch__swab32(__u32 value) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) { __u32 result; --- linux-2.6.1-rc1/include/asm-ppc/ibm4xx.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-ppc/ibm4xx.h 2003-12-30 22:49:58.000000000 -0800 @@ -90,8 +90,6 @@ void ppc4xx_init(unsigned long r3, unsig #include #endif -#endif /* CONFIG_40x */ - #ifndef __ASSEMBLY__ /* * The "residual" board information structure the boot loader passes @@ -99,6 +97,7 @@ void ppc4xx_init(unsigned long r3, unsig */ extern bd_t __res; #endif +#endif /* CONFIG_40x */ #endif /* __ASM_IBM4XX_H__ */ #endif /* __KERNEL__ */ --- linux-2.6.1-rc1/include/asm-ppc/mpc8260.h 2003-06-14 12:17:56.000000000 -0700 +++ 25/include/asm-ppc/mpc8260.h 2003-12-30 22:49:58.000000000 -0800 @@ -1,15 +1,36 @@ -/* This is the single file included by all MPC8260 build options. +/* * Since there are many different boards and no standard configuration, * we have a unique include file for each. Rather than change every * file that has to include MPC8260 configuration, they all include * this one and the configuration switching is done here. */ #ifdef __KERNEL__ -#ifndef __CONFIG_8260_DEFS -#define __CONFIG_8260_DEFS +#ifndef __ASM_PPC_MPC8260_H__ +#define __ASM_PPC_MPC8260_H__ #include -#include + +#ifdef CONFIG_8260 + +#ifdef CONFIG_EST8260 +#include +#endif + +#ifdef CONFIG_SBS8260 +#include +#endif + +#ifdef CONFIG_RPX6 +#include +#endif + +#ifdef CONFIG_WILLOW +#include +#endif + +#ifdef CONFIG_TQM8260 +#include +#endif /* Make sure the memory translation stuff is there if PCI not used. */ @@ -34,10 +55,13 @@ #define IO_VIRT_ADDR IO_PHYS_ADDR #endif +#ifndef __ASSEMBLY__ /* The "residual" data board information structure the boot loader * hands to us. */ extern unsigned char __res[]; +#endif -#endif /* !__CONFIG_8260_DEFS */ +#endif /* CONFIG_8260 */ +#endif /* !__ASM_PPC_MPC8260_H__ */ #endif /* __KERNEL__ */ --- linux-2.6.1-rc1/include/asm-ppc/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-ppc/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -48,7 +48,6 @@ extern void smp_local_timer_interrupt(st #define smp_processor_id() (current_thread_info()->cpu) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) -#define cpu_possible(cpu) cpu_isset(cpu, cpu_possible_map) extern int __cpu_up(unsigned int cpu); --- linux-2.6.1-rc1/include/asm-s390/byteorder.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/include/asm-s390/byteorder.h 2003-12-30 22:50:05.000000000 -0800 @@ -10,11 +10,12 @@ */ #include +#include #ifdef __GNUC__ #ifdef __s390x__ -static __inline__ __const__ __u64 ___arch__swab64p(__u64 *x) +static __inline__ __attribute_pure__ __u64 ___arch__swab64p(__const__ __u64 *x) { __u64 result; @@ -24,7 +25,7 @@ static __inline__ __const__ __u64 ___arc return result; } -static __inline__ __const__ __u64 ___arch__swab64(__u64 x) +static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) { __u64 result; @@ -40,7 +41,7 @@ static __inline__ void ___arch__swab64s( } #endif /* __s390x__ */ -static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x) +static __inline__ __attribute_pure__ __u32 ___arch__swab32p(__const__ __u32 *x) { __u32 result; @@ -58,7 +59,7 @@ static __inline__ __const__ __u32 ___arc return result; } -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) { #ifndef __s390x__ return ___arch__swab32p(&x); @@ -77,7 +78,7 @@ static __inline__ void ___arch__swab32s( *x = ___arch__swab32p(x); } -static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x) +static __inline__ __attribute_pure__ __u16 ___arch__swab16p(__const__ __u16 *x) { __u16 result; @@ -93,7 +94,7 @@ static __inline__ __const__ __u16 ___arc return result; } -static __inline__ __const__ __u16 ___arch__swab16(__u16 x) +static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) { return ___arch__swab16p(&x); } --- linux-2.6.1-rc1/include/asm-s390/smp.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-s390/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -49,7 +49,6 @@ extern cpumask_t cpu_possible_map; #define smp_processor_id() (S390_lowcore.cpu_data.cpu_nr) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) -#define cpu_possible(cpu) cpu_isset(cpu, cpu_possible_map) extern __inline__ __u16 hard_smp_processor_id(void) { --- linux-2.6.1-rc1/include/asm-sh/byteorder.h 2003-07-02 14:53:18.000000000 -0700 +++ 25/include/asm-sh/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -6,8 +6,9 @@ */ #include +#include -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) { __asm__("swap.b %0, %0\n\t" "swap.w %0, %0\n\t" @@ -17,7 +18,7 @@ static __inline__ __const__ __u32 ___arc return x; } -static __inline__ __const__ __u16 ___arch__swab16(__u16 x) +static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) { __asm__("swap.b %0, %0" : "=r" (x) --- linux-2.6.1-rc1/include/asm-sh/smp.h 2003-07-02 14:53:18.000000000 -0700 +++ 25/include/asm-sh/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -16,7 +16,6 @@ extern unsigned long cpu_online_map; #define cpu_online(cpu) (cpu_online_map & (1 << (cpu))) -#define cpu_possible(cpu) (cpu_online(cpu)) #define smp_processor_id() (current_thread_info()->cpu) --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/asm-sparc64/lockmeter.h 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#ifndef _SPARC64_LOCKMETER_H +#define _SPARC64_LOCKMETER_H + +#include +#include +#include +#include + +/* Actually, this is not the CPU frequency by the system tick + * frequency which is good enough for lock metering. + */ +#define CPU_CYCLE_FREQUENCY (timer_tick_offset * HZ) +#define THIS_CPU_NUMBER smp_processor_id() + +#define PUT_INDEX(lock_ptr,indexv) (lock_ptr)->index = (indexv) +#define GET_INDEX(lock_ptr) (lock_ptr)->index + +#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv) +#define GET_RWINDEX(rwlock_ptr) (rwlock_ptr)->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) (rwlock_ptr)->cpu = (cpuv) +#define GET_RW_CPU(rwlock_ptr) (rwlock_ptr)->cpu + +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + signed int tmp = rwlock_ptr->lock; + + if (tmp > 0) + return tmp; + else + return 0; +} + +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((signed int)((rwlock_ptr)->lock) < 0) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((signed int)((rwlock_ptr)->lock) > 0) + +#define get_cycles64() get_cycles() + +#endif /* _SPARC64_LOCKMETER_H */ --- linux-2.6.1-rc1/include/asm-sparc64/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-sparc64/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -33,7 +33,7 @@ extern unsigned char boot_cpu_id; extern cpumask_t phys_cpu_present_map; -#define cpu_possible(cpu) cpu_isset(cpu, phys_cpu_present_map) +#define cpu_possible_map phys_cpu_present_map #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) --- linux-2.6.1-rc1/include/asm-sparc64/spinlock.h 2003-11-23 19:03:02.000000000 -0800 +++ 25/include/asm-sparc64/spinlock.h 2003-12-30 22:50:17.000000000 -0800 @@ -30,15 +30,23 @@ #ifndef CONFIG_DEBUG_SPINLOCK -typedef unsigned char spinlock_t; -#define SPIN_LOCK_UNLOCKED 0 +typedef struct { + unsigned char lock; + unsigned int index; +} spinlock_t; -#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0) -#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) +#ifdef CONFIG_LOCKMETER +#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, 0} +#else +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +#endif -#define spin_unlock_wait(lock) \ +#define spin_lock_init(__lock) do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0) +#define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0) + +#define spin_unlock_wait(__lock) \ do { membar("#LoadLoad"); \ -} while(*((volatile unsigned char *)lock)) +} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock)))) static __inline__ void _raw_spin_lock(spinlock_t *lock) { @@ -109,17 +117,31 @@ extern int _spin_trylock (spinlock_t *lo #ifndef CONFIG_DEBUG_SPINLOCK -typedef unsigned int rwlock_t; -#define RW_LOCK_UNLOCKED 0 -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) -#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED) +#ifdef CONFIG_LOCKMETER +typedef struct { + unsigned int lock; + unsigned int index; + unsigned int cpu; +} rwlock_t; +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0xff } +#else +typedef struct { + unsigned int lock; +} rwlock_t; +#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif + +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) +#define rwlock_is_locked(x) ((x)->lock != 0) +extern int __read_trylock(rwlock_t *); extern void __read_lock(rwlock_t *); extern void __read_unlock(rwlock_t *); extern void __write_lock(rwlock_t *); extern void __write_unlock(rwlock_t *); extern int __write_trylock(rwlock_t *); +#define _raw_read_trylock(p) __read_trylock(p) #define _raw_read_lock(p) __read_lock(p) #define _raw_read_unlock(p) __read_unlock(p) #define _raw_write_lock(p) __write_lock(p) --- linux-2.6.1-rc1/include/asm-um/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/asm-um/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -20,7 +20,7 @@ extern int hard_smp_processor_id(void); #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) extern int ncpus; -#define cpu_possible(cpu) (cpu < ncpus) + extern inline void smp_cpus_done(unsigned int maxcpus) { --- linux-2.6.1-rc1/include/asm-v850/byteorder.h 2003-06-14 12:18:30.000000000 -0700 +++ 25/include/asm-v850/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -15,17 +15,18 @@ #define __V850_BYTEORDER_H__ #include +#include #ifdef __GNUC__ -static __inline__ __const__ __u32 ___arch__swab32 (__u32 word) +static __inline__ __attribute_const__ __u32 ___arch__swab32 (__u32 word) { __u32 res; __asm__ ("bsw %1, %0" : "=r" (res) : "r" (word)); return res; } -static __inline__ __const__ __u16 ___arch__swab16 (__u16 half_word) +static __inline__ __attribute_const__ __u16 ___arch__swab16 (__u16 half_word) { __u16 res; __asm__ ("bsh %1, %0" : "=r" (res) : "r" (half_word)); --- linux-2.6.1-rc1/include/asm-x86_64/acpi.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/include/asm-x86_64/acpi.h 2003-12-30 22:49:41.000000000 -0800 @@ -104,25 +104,26 @@ :"0"(n_hi), "1"(n_lo)) -#ifndef CONFIG_ACPI_BOOT -#define acpi_lapic 0 -#define acpi_ioapic 0 -#else -#ifdef CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_ACPI_BOOT extern int acpi_lapic; -#else -#define acpi_lapic 0 -#endif -#ifdef CONFIG_X86_IO_APIC extern int acpi_ioapic; -#else -#define acpi_ioapic 0 -#endif +extern int acpi_noirq; /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 -#endif /*CONFIG_ACPI_BOOT*/ +#else /* !CONFIG_ACPI_BOOT */ +#define acpi_lapic 0 +#define acpi_ioapic 0 +#endif /* !CONFIG_ACPI_BOOT */ + +#ifdef CONFIG_ACPI_PCI +static inline void acpi_noirq_set(void) { acpi_noirq = 1; } +extern int acpi_irq_balance_set(char *str); +#else +static inline void acpi_noirq_set(void) { } +static inline int acpi_irq_balance_set(char *str) { return 0; } +#endif #ifdef CONFIG_ACPI_SLEEP --- linux-2.6.1-rc1/include/asm-x86_64/byteorder.h 2003-06-14 12:18:29.000000000 -0700 +++ 25/include/asm-x86_64/byteorder.h 2003-12-30 22:50:04.000000000 -0800 @@ -2,16 +2,17 @@ #define _X86_64_BYTEORDER_H #include +#include #ifdef __GNUC__ -static __inline__ __const__ __u64 ___arch__swab64(__u64 x) +static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) { __asm__("bswapq %0" : "=r" (x) : "0" (x)); return x; } -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) { __asm__("bswapl %0" : "=r" (x) : "0" (x)); return x; --- linux-2.6.1-rc1/include/asm-x86_64/smp.h 2003-11-23 19:03:02.000000000 -0800 +++ 25/include/asm-x86_64/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -57,8 +57,7 @@ void smp_stop_cpu(void); */ extern cpumask_t cpu_callout_map; - -#define cpu_possible(cpu) cpu_isset(cpu, cpu_callout_map) +#define cpu_possible_map cpu_callout_map #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) static inline int num_booting_cpus(void) --- linux-2.6.1-rc1/include/linux/aio.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/aio.h 2003-12-30 22:50:25.000000000 -0800 @@ -29,21 +29,26 @@ struct kioctx; #define KIF_LOCKED 0 #define KIF_KICKED 1 #define KIF_CANCELLED 2 +#define KIF_SYNCED 3 #define kiocbTryLock(iocb) test_and_set_bit(KIF_LOCKED, &(iocb)->ki_flags) #define kiocbTryKick(iocb) test_and_set_bit(KIF_KICKED, &(iocb)->ki_flags) +#define kiocbTrySync(iocb) test_and_set_bit(KIF_SYNCED, &(iocb)->ki_flags) #define kiocbSetLocked(iocb) set_bit(KIF_LOCKED, &(iocb)->ki_flags) #define kiocbSetKicked(iocb) set_bit(KIF_KICKED, &(iocb)->ki_flags) #define kiocbSetCancelled(iocb) set_bit(KIF_CANCELLED, &(iocb)->ki_flags) +#define kiocbSetSynced(iocb) set_bit(KIF_SYNCED, &(iocb)->ki_flags) #define kiocbClearLocked(iocb) clear_bit(KIF_LOCKED, &(iocb)->ki_flags) #define kiocbClearKicked(iocb) clear_bit(KIF_KICKED, &(iocb)->ki_flags) #define kiocbClearCancelled(iocb) clear_bit(KIF_CANCELLED, &(iocb)->ki_flags) +#define kiocbClearSynced(iocb) clear_bit(KIF_SYNCED, &(iocb)->ki_flags) #define kiocbIsLocked(iocb) test_bit(KIF_LOCKED, &(iocb)->ki_flags) #define kiocbIsKicked(iocb) test_bit(KIF_KICKED, &(iocb)->ki_flags) #define kiocbIsCancelled(iocb) test_bit(KIF_CANCELLED, &(iocb)->ki_flags) +#define kiocbIsSynced(iocb) test_bit(KIF_SYNCED, &(iocb)->ki_flags) struct kiocb { struct list_head ki_run_list; @@ -54,7 +59,7 @@ struct kiocb { struct file *ki_filp; struct kioctx *ki_ctx; /* may be NULL for sync ops */ int (*ki_cancel)(struct kiocb *, struct io_event *); - long (*ki_retry)(struct kiocb *); + ssize_t (*ki_retry)(struct kiocb *); struct list_head ki_list; /* the aio core uses this * for cancellation */ @@ -63,6 +68,16 @@ struct kiocb { __u64 ki_user_data; /* user's data for completion */ loff_t ki_pos; + /* State that we remember to be able to restart/retry */ + unsigned short ki_opcode; + size_t ki_nbytes; /* copy of iocb->aio_nbytes */ + char *ki_buf; /* remaining iocb->aio_buf */ + size_t ki_left; /* remaining bytes */ + wait_queue_t ki_wait; + long ki_retried; /* just for testing */ + long ki_kicked; /* just for testing */ + long ki_queued; /* just for testing */ + char private[KIOCB_PRIVATE_SIZE]; }; @@ -77,6 +92,8 @@ struct kiocb { (x)->ki_ctx = &tsk->active_mm->default_kioctx; \ (x)->ki_cancel = NULL; \ (x)->ki_user_obj = tsk; \ + (x)->ki_user_data = 0; \ + init_wait((&(x)->ki_wait)); \ } while (0) #define AIO_RING_MAGIC 0xa10a10a1 @@ -159,6 +176,17 @@ int FASTCALL(io_submit_one(struct kioctx #define get_ioctx(kioctx) do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0) #define put_ioctx(kioctx) do { if (unlikely(atomic_dec_and_test(&(kioctx)->users))) __put_ioctx(kioctx); else if (unlikely(atomic_read(&(kioctx)->users) < 0)) BUG(); } while (0) +#define in_aio() !is_sync_wait(current->io_wait) +/* may be used for debugging */ +#define warn_if_async() if (in_aio()) {\ + printk(KERN_ERR "%s(%s:%d) called in async context!\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } + +#define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait) +#define is_retried_kiocb(iocb) ((iocb)->ki_retried > 1) + #include static inline struct kiocb *list_kiocb(struct list_head *h) @@ -167,6 +195,7 @@ static inline struct kiocb *list_kiocb(s } /* for sysctl: */ -extern unsigned aio_max_nr, aio_max_size, aio_max_pinned; +extern atomic_t aio_nr; +extern unsigned aio_max_nr; #endif /* __LINUX__AIO_H */ --- linux-2.6.1-rc1/include/linux/arcdevice.h 2003-07-27 12:14:40.000000000 -0700 +++ 25/include/linux/arcdevice.h 2003-12-30 22:49:20.000000000 -0800 @@ -331,6 +331,7 @@ void arcnet_dump_packet(struct net_devic void arcnet_unregister_proto(struct ArcProto *proto); irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); void arcdev_setup(struct net_device *dev); +struct net_device *alloc_arcdev(char *name); void arcnet_rx(struct net_device *dev, int bufnum); #endif /* __KERNEL__ */ --- linux-2.6.1-rc1/include/linux/blkdev.h 2003-12-17 21:20:03.000000000 -0800 +++ 25/include/linux/blkdev.h 2003-12-30 22:50:23.000000000 -0800 @@ -195,11 +195,6 @@ enum rq_flag_bits { __REQ_PM_SUSPEND, /* suspend request */ __REQ_PM_RESUME, /* resume request */ __REQ_PM_SHUTDOWN, /* shutdown request */ - __REQ_IDETAPE_PC1, /* packet command (first stage) */ - __REQ_IDETAPE_PC2, /* packet command (second stage) */ - __REQ_IDETAPE_READ, - __REQ_IDETAPE_WRITE, - __REQ_IDETAPE_READ_BUFFER, __REQ_NR_BITS, /* stops here */ }; @@ -225,11 +220,6 @@ enum rq_flag_bits { #define REQ_PM_SUSPEND (1 << __REQ_PM_SUSPEND) #define REQ_PM_RESUME (1 << __REQ_PM_RESUME) #define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN) -#define REQ_IDETAPE_PC1 (1 << __REQ_IDETAPE_PC1) -#define REQ_IDETAPE_PC2 (1 << __REQ_IDETAPE_PC2) -#define REQ_IDETAPE_READ (1 << __REQ_IDETAPE_READ) -#define REQ_IDETAPE_WRITE (1 << __REQ_IDETAPE_WRITE) -#define REQ_IDETAPE_READ_BUFFER (1 << __REQ_IDETAPE_READ_BUFFER) /* * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME @@ -597,6 +587,7 @@ extern void blk_queue_free_tags(request_ extern int blk_queue_resize_tags(request_queue_t *, int); extern void blk_queue_invalidate_tags(request_queue_t *); extern void blk_congestion_wait(int rw, long timeout); +extern int blk_congestion_wait_wq(int rw, long timeout, wait_queue_t *wait); extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); extern void blk_rq_prep_restart(struct request *); --- linux-2.6.1-rc1/include/linux/buffer_head.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/buffer_head.h 2003-12-30 22:50:23.000000000 -0800 @@ -162,6 +162,7 @@ void mark_buffer_async_write(struct buff void invalidate_bdev(struct block_device *, int); int sync_blockdev(struct block_device *bdev); void __wait_on_buffer(struct buffer_head *); +int __wait_on_buffer_wq(struct buffer_head *, wait_queue_t *wait); wait_queue_head_t *bh_waitq_head(struct buffer_head *bh); void wake_up_buffer(struct buffer_head *bh); int fsync_bdev(struct block_device *); @@ -173,6 +174,8 @@ void __brelse(struct buffer_head *); void __bforget(struct buffer_head *); void __breadahead(struct block_device *, sector_t block, int size); struct buffer_head *__bread(struct block_device *, sector_t block, int size); +struct buffer_head *__bread_wq(struct block_device *, sector_t block, + int size, wait_queue_t *wait); struct buffer_head *alloc_buffer_head(int gfp_flags); void free_buffer_head(struct buffer_head * bh); void FASTCALL(unlock_buffer(struct buffer_head *bh)); @@ -207,12 +210,6 @@ int nobh_prepare_write(struct page*, uns int nobh_commit_write(struct file *, struct page *, unsigned, unsigned); int nobh_truncate_page(struct address_space *, loff_t); -#define OSYNC_METADATA (1<<0) -#define OSYNC_DATA (1<<1) -#define OSYNC_INODE (1<<2) -int generic_osync_inode(struct inode *, int); - - /* * inline definitions */ @@ -230,13 +227,13 @@ static inline void put_bh(struct buffer_ static inline void brelse(struct buffer_head *bh) { - if (bh) + if (bh && !IS_ERR(bh)) __brelse(bh); } static inline void bforget(struct buffer_head *bh) { - if (bh) + if (bh && !IS_ERR(bh)) __bforget(bh); } @@ -253,7 +250,12 @@ sb_breadahead(struct super_block *sb, se } static inline struct buffer_head * -sb_getblk(struct super_block *sb, sector_t block) +sb_bread_wq(struct super_block *sb, sector_t block, wait_queue_t *wait) +{ + return __bread_wq(sb->s_bdev, block, sb->s_blocksize, wait); +} + +static inline struct buffer_head *sb_getblk(struct super_block *sb, sector_t block) { return __getblk(sb->s_bdev, block, sb->s_blocksize); } @@ -277,16 +279,34 @@ map_bh(struct buffer_head *bh, struct su * __wait_on_buffer() just to trip a debug check. Because debug code in inline * functions is bloaty. */ -static inline void wait_on_buffer(struct buffer_head *bh) + +static inline int wait_on_buffer_wq(struct buffer_head *bh, wait_queue_t *wait) { if (buffer_locked(bh) || atomic_read(&bh->b_count) == 0) - __wait_on_buffer(bh); + return __wait_on_buffer_wq(bh, wait); + + return 0; +} + +static inline void wait_on_buffer(struct buffer_head *bh) +{ + wait_on_buffer_wq(bh, NULL); +} + +static inline int lock_buffer_wq(struct buffer_head *bh, wait_queue_t *wait) +{ + while (test_set_buffer_locked(bh)) { + int ret = __wait_on_buffer_wq(bh, wait); + if (ret) + return ret; + } + + return 0; } static inline void lock_buffer(struct buffer_head *bh) { - while (test_set_buffer_locked(bh)) - __wait_on_buffer(bh); + lock_buffer_wq(bh, NULL); } #endif /* _LINUX_BUFFER_HEAD_H */ --- linux-2.6.1-rc1/include/linux/byteorder/swab.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/include/linux/byteorder/swab.h 2003-12-30 22:50:04.000000000 -0800 @@ -15,6 +15,8 @@ * */ +#include + /* casts are necessary for constants, because we never know how for sure * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way. */ @@ -128,7 +130,7 @@ #endif /* OPTIMIZE */ -static __inline__ __const__ __u16 __fswab16(__u16 x) +static __inline__ __attribute_const__ __u16 __fswab16(__u16 x) { return __arch__swab16(x); } @@ -141,7 +143,7 @@ static __inline__ void __swab16s(__u16 * __arch__swab16s(addr); } -static __inline__ __const__ __u32 __fswab32(__u32 x) +static __inline__ __attribute_const__ __u32 __fswab32(__u32 x) { return __arch__swab32(x); } @@ -155,7 +157,7 @@ static __inline__ void __swab32s(__u32 * } #ifdef __BYTEORDER_HAS_U64__ -static __inline__ __const__ __u64 __fswab64(__u64 x) +static __inline__ __attribute_const__ __u64 __fswab64(__u64 x) { # ifdef __SWAB_64_THRU_32__ __u32 h = x >> 32; --- linux-2.6.1-rc1/include/linux/cdrom.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/cdrom.h 2003-12-30 22:49:59.000000000 -0800 @@ -5,7 +5,7 @@ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de * 1996 David van Leeuwen, david@tm.tno.nl * 1997, 1998 Erik Andersen, andersee@debian.org - * 1998-2000 Jens Axboe, axboe@suse.de + * 1998-2002 Jens Axboe, axboe@suse.de */ #ifndef _LINUX_CDROM_H @@ -388,6 +388,9 @@ struct cdrom_generic_command #define CDC_DVD_R 0x10000 /* drive can write DVD-R */ #define CDC_DVD_RAM 0x20000 /* drive can write DVD-RAM */ #define CDC_MO_DRIVE 0x40000 /* drive is an MO device */ +#define CDC_MRW 0x80000 /* drive can read MRW */ +#define CDC_MRW_W 0x100000 /* drive can write MRW */ +#define CDC_RAM 0x200000 /* ok to open for WRITE */ /* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */ #define CDS_NO_INFO 0 /* if not implemented */ @@ -715,92 +718,57 @@ struct request_sense { __u8 asb[46]; }; -#ifdef __KERNEL__ -#include /* not really needed, later.. */ -#include - -struct cdrom_write_settings { - unsigned char fpacket; /* fixed/variable packets */ - unsigned long packet_size; /* write out this number of packets */ - unsigned long nwa; /* next writeable address */ - unsigned char writeable; /* cdrom is writeable */ -}; - -/* Uniform cdrom data structures for cdrom.c */ -struct cdrom_device_info { - struct cdrom_device_ops *ops; /* link to device_ops */ - struct cdrom_device_info *next; /* next device_info for this major */ - void *handle; /* driver-dependent data */ -/* specifications */ - int mask; /* mask of capability: disables them */ - int speed; /* maximum speed for reading data */ - int capacity; /* number of discs in jukebox */ -/* device-related storage */ - int options : 30; /* options flags */ - unsigned mc_flags : 2; /* media change buffer flags */ - int use_count; /* number of times device opened */ - char name[20]; /* name of the device type */ -/* per-device flags */ - __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 reserved : 6; /* not used yet */ - struct cdrom_write_settings write; -}; - -struct cdrom_device_ops { -/* routines */ - int (*open) (struct cdrom_device_info *, int); - void (*release) (struct cdrom_device_info *); - int (*drive_status) (struct cdrom_device_info *, int); - int (*media_changed) (struct cdrom_device_info *, int); - int (*tray_move) (struct cdrom_device_info *, int); - int (*lock_door) (struct cdrom_device_info *, int); - int (*select_speed) (struct cdrom_device_info *, int); - int (*select_disc) (struct cdrom_device_info *, int); - int (*get_last_session) (struct cdrom_device_info *, - struct cdrom_multisession *); - int (*get_mcn) (struct cdrom_device_info *, - struct cdrom_mcn *); - /* hard reset device */ - int (*reset) (struct cdrom_device_info *); - /* play stuff */ - int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *); - /* dev-specific */ - int (*dev_ioctl) (struct cdrom_device_info *, - unsigned int, unsigned long); -/* driver specifications */ - const int capability; /* capability flags */ - int n_minors; /* number of active minor devices */ - /* handle uniform packets for scsi type devices (scsi,atapi) */ - int (*generic_packet) (struct cdrom_device_info *, - struct cdrom_generic_command *); -}; +/* + * feature profile + */ +#define CDF_MRW 0x28 -/* the general block_device operations structure: */ -extern int cdrom_open(struct cdrom_device_info *, struct inode *, struct file *); -extern int cdrom_release(struct cdrom_device_info *, struct file *); -extern int cdrom_ioctl(struct cdrom_device_info *, struct inode *, unsigned, unsigned long); -extern int cdrom_media_changed(struct cdrom_device_info *); +/* + * media status bits + */ +#define CDM_MRW_NOTMRW 0 +#define CDM_MRW_BGFORMAT_INACTIVE 1 +#define CDM_MRW_BGFORMAT_ACTIVE 2 +#define CDM_MRW_BGFORMAT_COMPLETE 3 -extern int register_cdrom(struct cdrom_device_info *cdi); -extern int unregister_cdrom(struct cdrom_device_info *cdi); +/* + * mrw address spaces + */ +#define MRW_LBA_DMA 0 +#define MRW_LBA_GAA 1 -typedef struct { - int data; - int audio; - int cdi; - int xa; - long error; -} tracktype; +/* + * mrw mode pages (first is deprecated) -- probed at init time and + * cdi->mrw_mode_page is set + */ +#define MRW_MODE_PC_PRE1 0x2c +#define MRW_MODE_PC 0x03 -extern int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written); -extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); -extern int cdrom_mode_select(struct cdrom_device_info *cdi, - struct cdrom_generic_command *cgc); -extern int cdrom_mode_sense(struct cdrom_device_info *cdi, - struct cdrom_generic_command *cgc, - int page_code, int page_control); -extern void init_cdrom_command(struct cdrom_generic_command *cgc, - void *buffer, int len, int type); +struct mrw_feature_desc { + __u16 feature_code; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 2; + __u8 feature_version : 4; + __u8 persistent : 1; + __u8 curr : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 curr : 1; + __u8 persistent : 1; + __u8 feature_version : 4; + __u8 reserved1 : 2; +#endif + __u8 add_len; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved2 : 7; + __u8 write : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 write : 1; + __u8 reserved2 : 7; +#endif + __u8 reserved3; + __u8 reserved4; + __u8 reserved5; +}; typedef struct { __u16 disc_information_length; @@ -825,9 +793,13 @@ typedef struct { __u8 did_v : 1; __u8 dbc_v : 1; __u8 uru : 1; - __u8 reserved2 : 5; + __u8 reserved2 : 2; + __u8 dbit : 1; + __u8 mrw_status : 2; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved2 : 5; + __u8 mrw_status : 2; + __u8 dbit : 1; + __u8 reserved2 : 2; __u8 uru : 1; __u8 dbc_v : 1; __u8 did_v : 1; @@ -884,6 +856,104 @@ typedef struct { __u32 last_rec_address; } track_information; +struct feature_header { + __u32 data_len; + __u8 reserved1; + __u8 reserved2; + __u16 curr_profile; +}; + +struct mode_page_header { + __u16 mode_data_length; + __u8 medium_type; + __u8 reserved1; + __u8 reserved2; + __u8 reserved3; + __u16 desc_length; +}; + +#ifdef __KERNEL__ +#include /* not really needed, later.. */ +#include + +/* Uniform cdrom data structures for cdrom.c */ +struct cdrom_device_info { + struct cdrom_device_ops *ops; /* link to device_ops */ + struct cdrom_device_info *next; /* next device_info for this major */ + void *handle; /* driver-dependent data */ +/* specifications */ + int mask; /* mask of capability: disables them */ + int speed; /* maximum speed for reading data */ + int capacity; /* number of discs in jukebox */ +/* device-related storage */ + int options : 30; /* options flags */ + unsigned mc_flags : 2; /* media change buffer flags */ + int use_count; /* number of times device opened */ + char name[20]; /* name of the device type */ +/* per-device flags */ + __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ + __u8 reserved : 6; /* not used yet */ + int for_data; + int (*exit)(struct cdrom_device_info *); + int mrw_mode_page; +}; + +struct cdrom_device_ops { +/* routines */ + int (*open) (struct cdrom_device_info *, int); + void (*release) (struct cdrom_device_info *); + int (*drive_status) (struct cdrom_device_info *, int); + int (*media_changed) (struct cdrom_device_info *, int); + int (*tray_move) (struct cdrom_device_info *, int); + int (*lock_door) (struct cdrom_device_info *, int); + int (*select_speed) (struct cdrom_device_info *, int); + int (*select_disc) (struct cdrom_device_info *, int); + int (*get_last_session) (struct cdrom_device_info *, + struct cdrom_multisession *); + int (*get_mcn) (struct cdrom_device_info *, + struct cdrom_mcn *); + /* hard reset device */ + int (*reset) (struct cdrom_device_info *); + /* play stuff */ + int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *); + /* dev-specific */ + int (*dev_ioctl) (struct cdrom_device_info *, + unsigned int, unsigned long); +/* driver specifications */ + const int capability; /* capability flags */ + int n_minors; /* number of active minor devices */ + /* handle uniform packets for scsi type devices (scsi,atapi) */ + int (*generic_packet) (struct cdrom_device_info *, + struct cdrom_generic_command *); +}; + +/* the general block_device operations structure: */ +extern int cdrom_open(struct cdrom_device_info *, struct block_device *, struct file *); +extern int cdrom_release(struct cdrom_device_info *); +extern int cdrom_ioctl(struct cdrom_device_info *, struct block_device *, unsigned, unsigned long); +extern int cdrom_media_changed(struct cdrom_device_info *); + +extern int register_cdrom(struct cdrom_device_info *cdi); +extern int unregister_cdrom(struct cdrom_device_info *cdi); + +typedef struct { + int data; + int audio; + int cdi; + int xa; + long error; +} tracktype; + +extern int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written); +extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); +extern int cdrom_mode_select(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc); +extern int cdrom_mode_sense(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int page_code, int page_control); +extern void init_cdrom_command(struct cdrom_generic_command *cgc, + void *buffer, int len, int type); + /* The SCSI spec says there could be 256 slots. */ #define CDROM_MAX_SLOTS 256 @@ -934,15 +1004,6 @@ typedef enum { mechtype_cartridge_changer = 5 } mechtype_t; -struct mode_page_header { - __u16 mode_data_length; - __u8 medium_type; - __u8 reserved1; - __u8 reserved2; - __u8 reserved3; - __u16 desc_length; -}; - typedef struct { #if defined(__BIG_ENDIAN_BITFIELD) __u8 ps : 1; @@ -1032,6 +1093,41 @@ typedef struct { __u8 reserved3; } rpc_state_t; +struct event_header { + __u16 data_len; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 nea : 1; + __u8 reserved1 : 4; + __u8 notification_class : 3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 notification_class : 3; + __u8 reserved1 : 4; + __u8 nea : 1; +#endif + __u8 supp_event_class; +}; + +struct media_event_desc { +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 4; + __u8 media_event_code : 4; + __u8 reserved2 : 6; + __u8 media_present : 1; + __u8 door_open : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 media_event_code : 4; + __u8 reserved1 : 4; + __u8 door_open : 1; + __u8 media_present : 1; + __u8 reserved2 : 6; +#endif + __u8 start_slot; + __u8 end_slot; +}; + +extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med); +extern int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write); + #endif /* End of kernel only stuff */ #endif /* _LINUX_CDROM_H */ --- linux-2.6.1-rc1/include/linux/com20020.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/include/linux/com20020.h 2003-12-30 22:49:20.000000000 -0800 @@ -29,7 +29,6 @@ int com20020_check(struct net_device *dev); int com20020_found(struct net_device *dev, int shared); -void com20020_remove(struct net_device *dev); /* The number of low I/O ports used by the card. */ #define ARCNET_TOTAL_SIZE 8 --- linux-2.6.1-rc1/include/linux/compiler-gcc2.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/linux/compiler-gcc2.h 2003-12-30 22:50:04.000000000 -0800 @@ -20,4 +20,5 @@ */ #if __GNUC_MINOR__ >= 96 # define __attribute_pure__ __attribute__((pure)) +# define __attribute_const__ __attribute__((__const__)) #endif --- linux-2.6.1-rc1/include/linux/compiler-gcc3.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/linux/compiler-gcc3.h 2003-12-30 22:50:04.000000000 -0800 @@ -20,3 +20,4 @@ #endif #define __attribute_pure__ __attribute__((pure)) +#define __attribute_const__ __attribute__((__const__)) --- linux-2.6.1-rc1/include/linux/compiler-gcc.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/compiler-gcc.h 2003-12-30 22:49:43.000000000 -0800 @@ -13,5 +13,5 @@ shouldn't recognize the original var, and make assumptions about it */ #define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ - __asm__ ("" : "=g"(__ptr) : "0"(ptr)); \ + __asm__ ("" : "=r"(__ptr) : "0"(ptr)); \ (typeof(ptr)) (__ptr + (off)); }) --- linux-2.6.1-rc1/include/linux/compiler-gcc+.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/linux/compiler-gcc+.h 2003-12-30 22:50:04.000000000 -0800 @@ -12,3 +12,4 @@ #define __deprecated __attribute__((deprecated)) #define __attribute_used__ __attribute__((__used__)) #define __attribute_pure__ __attribute__((pure)) +#define __attribute_const__ __attribute__((__const__)) --- linux-2.6.1-rc1/include/linux/compiler.h 2003-11-23 19:03:02.000000000 -0800 +++ 25/include/linux/compiler.h 2003-12-30 22:50:04.000000000 -0800 @@ -76,6 +76,24 @@ # define __attribute_pure__ /* unimplemented */ #endif +/* + * From the GCC manual: + * + * Many functions do not examine any values except their arguments, + * and have no effects except the return value. Basically this is + * just slightly more strict class than the `pure' attribute above, + * since function is not allowed to read global memory. + * + * Note that a function that has pointer arguments and examines the + * data pointed to must _not_ be declared `const'. Likewise, a + * function that calls a non-`const' function usually must not be + * `const'. It does not make sense for a `const' function to return + * `void'. + */ +#ifndef __attribute_const__ +# define __attribute_const__ /* unimplemented */ +#endif + /* Optimization barrier */ #ifndef barrier # define barrier() __memory_barrier() --- linux-2.6.1-rc1/include/linux/config.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/config.h 2003-12-30 22:49:25.000000000 -0800 @@ -2,5 +2,8 @@ #define _LINUX_CONFIG_H #include +#if defined(__i386__) && !defined(IN_BOOTLOADER) +#include +#endif #endif --- linux-2.6.1-rc1/include/linux/cpumask.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/cpumask.h 2003-12-30 22:50:14.000000000 -0800 @@ -8,32 +8,28 @@ #ifdef CONFIG_SMP extern cpumask_t cpu_online_map; +extern cpumask_t cpu_possible_map; #define num_online_cpus() cpus_weight(cpu_online_map) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) +#define cpu_possible(cpu) cpu_isset(cpu, cpu_possible_map) + +#define for_each_cpu_mask(cpu, mask) \ + for (cpu = first_cpu_const(mask); \ + cpu < NR_CPUS; \ + cpu = next_cpu_const(cpu, mask)) + +#define for_each_cpu(cpu) for_each_cpu_mask(cpu, cpu_possible_map) +#define for_each_online_cpu(cpu) for_each_cpu_mask(cpu, cpu_online_map) #else #define cpu_online_map cpumask_of_cpu(0) #define num_online_cpus() 1 #define cpu_online(cpu) ({ BUG_ON((cpu) != 0); 1; }) -#endif +#define cpu_possible(cpu) ({ BUG_ON((cpu) != 0); 1; }) -static inline int next_online_cpu(int cpu, cpumask_t map) -{ - do - cpu = next_cpu_const(cpu, mk_cpumask_const(map)); - while (cpu < NR_CPUS && !cpu_online(cpu)); - return cpu; -} - -#define for_each_cpu(cpu, map) \ - for (cpu = first_cpu_const(mk_cpumask_const(map)); \ - cpu < NR_CPUS; \ - cpu = next_cpu_const(cpu,mk_cpumask_const(map))) - -#define for_each_online_cpu(cpu, map) \ - for (cpu = first_cpu_const(mk_cpumask_const(map)); \ - cpu < NR_CPUS; \ - cpu = next_online_cpu(cpu,map)) +#define for_each_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) +#define for_each_online_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) +#endif extern int __mask_snprintf_len(char *buf, unsigned int buflen, const unsigned long *maskp, unsigned int maskbytes); --- linux-2.6.1-rc1/include/linux/device.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/device.h 2003-12-30 22:50:05.000000000 -0800 @@ -246,6 +246,11 @@ struct class_interface { extern int class_interface_register(struct class_interface *); extern void class_interface_unregister(struct class_interface *); +/* interface for simple class devices */ +extern struct class_device *simple_add_class_device(struct class *class, dev_t dev, struct device *device, const char *fmt, ...) + __attribute__((format(printf,4,5))); +extern void simple_remove_class_device(dev_t dev); + struct device { struct list_head node; /* node in sibling list */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/linux/dwarf2.h 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,738 @@ +/* Declarations and definitions of codes relating to the DWARF2 symbolic + debugging information format. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State Unviversity and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + GCC 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 GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification. */ + +/* This file is shared between GCC and GDB, and should not contain + prototypes. */ + +#ifndef _ELF_DWARF2_H +#define _ELF_DWARF2_H + +/* Structure found in the .debug_line section. */ +#ifndef __ASSEMBLY__ +typedef struct +{ + unsigned char li_length [4]; + unsigned char li_version [2]; + unsigned char li_prologue_length [4]; + unsigned char li_min_insn_length [1]; + unsigned char li_default_is_stmt [1]; + unsigned char li_line_base [1]; + unsigned char li_line_range [1]; + unsigned char li_opcode_base [1]; +} +DWARF2_External_LineInfo; + +typedef struct +{ + unsigned long li_length; + unsigned short li_version; + unsigned int li_prologue_length; + unsigned char li_min_insn_length; + unsigned char li_default_is_stmt; + int li_line_base; + unsigned char li_line_range; + unsigned char li_opcode_base; +} +DWARF2_Internal_LineInfo; + +/* Structure found in .debug_pubnames section. */ +typedef struct +{ + unsigned char pn_length [4]; + unsigned char pn_version [2]; + unsigned char pn_offset [4]; + unsigned char pn_size [4]; +} +DWARF2_External_PubNames; + +typedef struct +{ + unsigned long pn_length; + unsigned short pn_version; + unsigned long pn_offset; + unsigned long pn_size; +} +DWARF2_Internal_PubNames; + +/* Structure found in .debug_info section. */ +typedef struct +{ + unsigned char cu_length [4]; + unsigned char cu_version [2]; + unsigned char cu_abbrev_offset [4]; + unsigned char cu_pointer_size [1]; +} +DWARF2_External_CompUnit; + +typedef struct +{ + unsigned long cu_length; + unsigned short cu_version; + unsigned long cu_abbrev_offset; + unsigned char cu_pointer_size; +} +DWARF2_Internal_CompUnit; + +typedef struct +{ + unsigned char ar_length [4]; + unsigned char ar_version [2]; + unsigned char ar_info_offset [4]; + unsigned char ar_pointer_size [1]; + unsigned char ar_segment_size [1]; +} +DWARF2_External_ARange; + +typedef struct +{ + unsigned long ar_length; + unsigned short ar_version; + unsigned long ar_info_offset; + unsigned char ar_pointer_size; + unsigned char ar_segment_size; +} +DWARF2_Internal_ARange; + +#define ENUM(name) enum name { +#define IF_NOT_ASM(a) a +#define COMMA , +#else +#define ENUM(name) +#define IF_NOT_ASM(a) +#define COMMA + +#endif + +/* Tag names and codes. */ +ENUM(dwarf_tag) + + DW_TAG_padding = 0x00 COMMA + DW_TAG_array_type = 0x01 COMMA + DW_TAG_class_type = 0x02 COMMA + DW_TAG_entry_point = 0x03 COMMA + DW_TAG_enumeration_type = 0x04 COMMA + DW_TAG_formal_parameter = 0x05 COMMA + DW_TAG_imported_declaration = 0x08 COMMA + DW_TAG_label = 0x0a COMMA + DW_TAG_lexical_block = 0x0b COMMA + DW_TAG_member = 0x0d COMMA + DW_TAG_pointer_type = 0x0f COMMA + DW_TAG_reference_type = 0x10 COMMA + DW_TAG_compile_unit = 0x11 COMMA + DW_TAG_string_type = 0x12 COMMA + DW_TAG_structure_type = 0x13 COMMA + DW_TAG_subroutine_type = 0x15 COMMA + DW_TAG_typedef = 0x16 COMMA + DW_TAG_union_type = 0x17 COMMA + DW_TAG_unspecified_parameters = 0x18 COMMA + DW_TAG_variant = 0x19 COMMA + DW_TAG_common_block = 0x1a COMMA + DW_TAG_common_inclusion = 0x1b COMMA + DW_TAG_inheritance = 0x1c COMMA + DW_TAG_inlined_subroutine = 0x1d COMMA + DW_TAG_module = 0x1e COMMA + DW_TAG_ptr_to_member_type = 0x1f COMMA + DW_TAG_set_type = 0x20 COMMA + DW_TAG_subrange_type = 0x21 COMMA + DW_TAG_with_stmt = 0x22 COMMA + DW_TAG_access_declaration = 0x23 COMMA + DW_TAG_base_type = 0x24 COMMA + DW_TAG_catch_block = 0x25 COMMA + DW_TAG_const_type = 0x26 COMMA + DW_TAG_constant = 0x27 COMMA + DW_TAG_enumerator = 0x28 COMMA + DW_TAG_file_type = 0x29 COMMA + DW_TAG_friend = 0x2a COMMA + DW_TAG_namelist = 0x2b COMMA + DW_TAG_namelist_item = 0x2c COMMA + DW_TAG_packed_type = 0x2d COMMA + DW_TAG_subprogram = 0x2e COMMA + DW_TAG_template_type_param = 0x2f COMMA + DW_TAG_template_value_param = 0x30 COMMA + DW_TAG_thrown_type = 0x31 COMMA + DW_TAG_try_block = 0x32 COMMA + DW_TAG_variant_part = 0x33 COMMA + DW_TAG_variable = 0x34 COMMA + DW_TAG_volatile_type = 0x35 COMMA + /* DWARF 3. */ + DW_TAG_dwarf_procedure = 0x36 COMMA + DW_TAG_restrict_type = 0x37 COMMA + DW_TAG_interface_type = 0x38 COMMA + DW_TAG_namespace = 0x39 COMMA + DW_TAG_imported_module = 0x3a COMMA + DW_TAG_unspecified_type = 0x3b COMMA + DW_TAG_partial_unit = 0x3c COMMA + DW_TAG_imported_unit = 0x3d COMMA + /* SGI/MIPS Extensions. */ + DW_TAG_MIPS_loop = 0x4081 COMMA + /* GNU extensions. */ + DW_TAG_format_label = 0x4101 COMMA /* For FORTRAN 77 and Fortran 90. */ + DW_TAG_function_template = 0x4102 COMMA /* For C++. */ + DW_TAG_class_template = 0x4103 COMMA /* For C++. */ + DW_TAG_GNU_BINCL = 0x4104 COMMA + DW_TAG_GNU_EINCL = 0x4105 COMMA + /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ + DW_TAG_upc_shared_type = 0x8765 COMMA + DW_TAG_upc_strict_type = 0x8766 COMMA + DW_TAG_upc_relaxed_type = 0x8767 +IF_NOT_ASM(};) + +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +/* Flag that tells whether entry has a child or not. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +/* Form names and codes. */ +ENUM(dwarf_form) + + DW_FORM_addr = 0x01 COMMA + DW_FORM_block2 = 0x03 COMMA + DW_FORM_block4 = 0x04 COMMA + DW_FORM_data2 = 0x05 COMMA + DW_FORM_data4 = 0x06 COMMA + DW_FORM_data8 = 0x07 COMMA + DW_FORM_string = 0x08 COMMA + DW_FORM_block = 0x09 COMMA + DW_FORM_block1 = 0x0a COMMA + DW_FORM_data1 = 0x0b COMMA + DW_FORM_flag = 0x0c COMMA + DW_FORM_sdata = 0x0d COMMA + DW_FORM_strp = 0x0e COMMA + DW_FORM_udata = 0x0f COMMA + DW_FORM_ref_addr = 0x10 COMMA + DW_FORM_ref1 = 0x11 COMMA + DW_FORM_ref2 = 0x12 COMMA + DW_FORM_ref4 = 0x13 COMMA + DW_FORM_ref8 = 0x14 COMMA + DW_FORM_ref_udata = 0x15 COMMA + DW_FORM_indirect = 0x16 +IF_NOT_ASM(};) + +/* Attribute names and codes. */ + +ENUM(dwarf_attribute) + + DW_AT_sibling = 0x01 COMMA + DW_AT_location = 0x02 COMMA + DW_AT_name = 0x03 COMMA + DW_AT_ordering = 0x09 COMMA + DW_AT_subscr_data = 0x0a COMMA + DW_AT_byte_size = 0x0b COMMA + DW_AT_bit_offset = 0x0c COMMA + DW_AT_bit_size = 0x0d COMMA + DW_AT_element_list = 0x0f COMMA + DW_AT_stmt_list = 0x10 COMMA + DW_AT_low_pc = 0x11 COMMA + DW_AT_high_pc = 0x12 COMMA + DW_AT_language = 0x13 COMMA + DW_AT_member = 0x14 COMMA + DW_AT_discr = 0x15 COMMA + DW_AT_discr_value = 0x16 COMMA + DW_AT_visibility = 0x17 COMMA + DW_AT_import = 0x18 COMMA + DW_AT_string_length = 0x19 COMMA + DW_AT_common_reference = 0x1a COMMA + DW_AT_comp_dir = 0x1b COMMA + DW_AT_const_value = 0x1c COMMA + DW_AT_containing_type = 0x1d COMMA + DW_AT_default_value = 0x1e COMMA + DW_AT_inline = 0x20 COMMA + DW_AT_is_optional = 0x21 COMMA + DW_AT_lower_bound = 0x22 COMMA + DW_AT_producer = 0x25 COMMA + DW_AT_prototyped = 0x27 COMMA + DW_AT_return_addr = 0x2a COMMA + DW_AT_start_scope = 0x2c COMMA + DW_AT_stride_size = 0x2e COMMA + DW_AT_upper_bound = 0x2f COMMA + DW_AT_abstract_origin = 0x31 COMMA + DW_AT_accessibility = 0x32 COMMA + DW_AT_address_class = 0x33 COMMA + DW_AT_artificial = 0x34 COMMA + DW_AT_base_types = 0x35 COMMA + DW_AT_calling_convention = 0x36 COMMA + DW_AT_count = 0x37 COMMA + DW_AT_data_member_location = 0x38 COMMA + DW_AT_decl_column = 0x39 COMMA + DW_AT_decl_file = 0x3a COMMA + DW_AT_decl_line = 0x3b COMMA + DW_AT_declaration = 0x3c COMMA + DW_AT_discr_list = 0x3d COMMA + DW_AT_encoding = 0x3e COMMA + DW_AT_external = 0x3f COMMA + DW_AT_frame_base = 0x40 COMMA + DW_AT_friend = 0x41 COMMA + DW_AT_identifier_case = 0x42 COMMA + DW_AT_macro_info = 0x43 COMMA + DW_AT_namelist_items = 0x44 COMMA + DW_AT_priority = 0x45 COMMA + DW_AT_segment = 0x46 COMMA + DW_AT_specification = 0x47 COMMA + DW_AT_static_link = 0x48 COMMA + DW_AT_type = 0x49 COMMA + DW_AT_use_location = 0x4a COMMA + DW_AT_variable_parameter = 0x4b COMMA + DW_AT_virtuality = 0x4c COMMA + DW_AT_vtable_elem_location = 0x4d COMMA + /* DWARF 3 values. */ + DW_AT_allocated = 0x4e COMMA + DW_AT_associated = 0x4f COMMA + DW_AT_data_location = 0x50 COMMA + DW_AT_stride = 0x51 COMMA + DW_AT_entry_pc = 0x52 COMMA + DW_AT_use_UTF8 = 0x53 COMMA + DW_AT_extension = 0x54 COMMA + DW_AT_ranges = 0x55 COMMA + DW_AT_trampoline = 0x56 COMMA + DW_AT_call_column = 0x57 COMMA + DW_AT_call_file = 0x58 COMMA + DW_AT_call_line = 0x59 COMMA + /* SGI/MIPS extensions. */ + DW_AT_MIPS_fde = 0x2001 COMMA + DW_AT_MIPS_loop_begin = 0x2002 COMMA + DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA + DW_AT_MIPS_epilog_begin = 0x2004 COMMA + DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA + DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA + DW_AT_MIPS_linkage_name = 0x2007 COMMA + DW_AT_MIPS_stride = 0x2008 COMMA + DW_AT_MIPS_abstract_name = 0x2009 COMMA + DW_AT_MIPS_clone_origin = 0x200a COMMA + DW_AT_MIPS_has_inlines = 0x200b COMMA + /* GNU extensions. */ + DW_AT_sf_names = 0x2101 COMMA + DW_AT_src_info = 0x2102 COMMA + DW_AT_mac_info = 0x2103 COMMA + DW_AT_src_coords = 0x2104 COMMA + DW_AT_body_begin = 0x2105 COMMA + DW_AT_body_end = 0x2106 COMMA + DW_AT_GNU_vector = 0x2107 COMMA + /* VMS extensions. */ + DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA + /* UPC extension. */ + DW_AT_upc_threads_scaled = 0x3210 +IF_NOT_ASM(};) + +#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ +#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ + +/* Location atom names and codes. */ +ENUM(dwarf_location_atom) + + DW_OP_addr = 0x03 COMMA + DW_OP_deref = 0x06 COMMA + DW_OP_const1u = 0x08 COMMA + DW_OP_const1s = 0x09 COMMA + DW_OP_const2u = 0x0a COMMA + DW_OP_const2s = 0x0b COMMA + DW_OP_const4u = 0x0c COMMA + DW_OP_const4s = 0x0d COMMA + DW_OP_const8u = 0x0e COMMA + DW_OP_const8s = 0x0f COMMA + DW_OP_constu = 0x10 COMMA + DW_OP_consts = 0x11 COMMA + DW_OP_dup = 0x12 COMMA + DW_OP_drop = 0x13 COMMA + DW_OP_over = 0x14 COMMA + DW_OP_pick = 0x15 COMMA + DW_OP_swap = 0x16 COMMA + DW_OP_rot = 0x17 COMMA + DW_OP_xderef = 0x18 COMMA + DW_OP_abs = 0x19 COMMA + DW_OP_and = 0x1a COMMA + DW_OP_div = 0x1b COMMA + DW_OP_minus = 0x1c COMMA + DW_OP_mod = 0x1d COMMA + DW_OP_mul = 0x1e COMMA + DW_OP_neg = 0x1f COMMA + DW_OP_not = 0x20 COMMA + DW_OP_or = 0x21 COMMA + DW_OP_plus = 0x22 COMMA + DW_OP_plus_uconst = 0x23 COMMA + DW_OP_shl = 0x24 COMMA + DW_OP_shr = 0x25 COMMA + DW_OP_shra = 0x26 COMMA + DW_OP_xor = 0x27 COMMA + DW_OP_bra = 0x28 COMMA + DW_OP_eq = 0x29 COMMA + DW_OP_ge = 0x2a COMMA + DW_OP_gt = 0x2b COMMA + DW_OP_le = 0x2c COMMA + DW_OP_lt = 0x2d COMMA + DW_OP_ne = 0x2e COMMA + DW_OP_skip = 0x2f COMMA + DW_OP_lit0 = 0x30 COMMA + DW_OP_lit1 = 0x31 COMMA + DW_OP_lit2 = 0x32 COMMA + DW_OP_lit3 = 0x33 COMMA + DW_OP_lit4 = 0x34 COMMA + DW_OP_lit5 = 0x35 COMMA + DW_OP_lit6 = 0x36 COMMA + DW_OP_lit7 = 0x37 COMMA + DW_OP_lit8 = 0x38 COMMA + DW_OP_lit9 = 0x39 COMMA + DW_OP_lit10 = 0x3a COMMA + DW_OP_lit11 = 0x3b COMMA + DW_OP_lit12 = 0x3c COMMA + DW_OP_lit13 = 0x3d COMMA + DW_OP_lit14 = 0x3e COMMA + DW_OP_lit15 = 0x3f COMMA + DW_OP_lit16 = 0x40 COMMA + DW_OP_lit17 = 0x41 COMMA + DW_OP_lit18 = 0x42 COMMA + DW_OP_lit19 = 0x43 COMMA + DW_OP_lit20 = 0x44 COMMA + DW_OP_lit21 = 0x45 COMMA + DW_OP_lit22 = 0x46 COMMA + DW_OP_lit23 = 0x47 COMMA + DW_OP_lit24 = 0x48 COMMA + DW_OP_lit25 = 0x49 COMMA + DW_OP_lit26 = 0x4a COMMA + DW_OP_lit27 = 0x4b COMMA + DW_OP_lit28 = 0x4c COMMA + DW_OP_lit29 = 0x4d COMMA + DW_OP_lit30 = 0x4e COMMA + DW_OP_lit31 = 0x4f COMMA + DW_OP_reg0 = 0x50 COMMA + DW_OP_reg1 = 0x51 COMMA + DW_OP_reg2 = 0x52 COMMA + DW_OP_reg3 = 0x53 COMMA + DW_OP_reg4 = 0x54 COMMA + DW_OP_reg5 = 0x55 COMMA + DW_OP_reg6 = 0x56 COMMA + DW_OP_reg7 = 0x57 COMMA + DW_OP_reg8 = 0x58 COMMA + DW_OP_reg9 = 0x59 COMMA + DW_OP_reg10 = 0x5a COMMA + DW_OP_reg11 = 0x5b COMMA + DW_OP_reg12 = 0x5c COMMA + DW_OP_reg13 = 0x5d COMMA + DW_OP_reg14 = 0x5e COMMA + DW_OP_reg15 = 0x5f COMMA + DW_OP_reg16 = 0x60 COMMA + DW_OP_reg17 = 0x61 COMMA + DW_OP_reg18 = 0x62 COMMA + DW_OP_reg19 = 0x63 COMMA + DW_OP_reg20 = 0x64 COMMA + DW_OP_reg21 = 0x65 COMMA + DW_OP_reg22 = 0x66 COMMA + DW_OP_reg23 = 0x67 COMMA + DW_OP_reg24 = 0x68 COMMA + DW_OP_reg25 = 0x69 COMMA + DW_OP_reg26 = 0x6a COMMA + DW_OP_reg27 = 0x6b COMMA + DW_OP_reg28 = 0x6c COMMA + DW_OP_reg29 = 0x6d COMMA + DW_OP_reg30 = 0x6e COMMA + DW_OP_reg31 = 0x6f COMMA + DW_OP_breg0 = 0x70 COMMA + DW_OP_breg1 = 0x71 COMMA + DW_OP_breg2 = 0x72 COMMA + DW_OP_breg3 = 0x73 COMMA + DW_OP_breg4 = 0x74 COMMA + DW_OP_breg5 = 0x75 COMMA + DW_OP_breg6 = 0x76 COMMA + DW_OP_breg7 = 0x77 COMMA + DW_OP_breg8 = 0x78 COMMA + DW_OP_breg9 = 0x79 COMMA + DW_OP_breg10 = 0x7a COMMA + DW_OP_breg11 = 0x7b COMMA + DW_OP_breg12 = 0x7c COMMA + DW_OP_breg13 = 0x7d COMMA + DW_OP_breg14 = 0x7e COMMA + DW_OP_breg15 = 0x7f COMMA + DW_OP_breg16 = 0x80 COMMA + DW_OP_breg17 = 0x81 COMMA + DW_OP_breg18 = 0x82 COMMA + DW_OP_breg19 = 0x83 COMMA + DW_OP_breg20 = 0x84 COMMA + DW_OP_breg21 = 0x85 COMMA + DW_OP_breg22 = 0x86 COMMA + DW_OP_breg23 = 0x87 COMMA + DW_OP_breg24 = 0x88 COMMA + DW_OP_breg25 = 0x89 COMMA + DW_OP_breg26 = 0x8a COMMA + DW_OP_breg27 = 0x8b COMMA + DW_OP_breg28 = 0x8c COMMA + DW_OP_breg29 = 0x8d COMMA + DW_OP_breg30 = 0x8e COMMA + DW_OP_breg31 = 0x8f COMMA + DW_OP_regx = 0x90 COMMA + DW_OP_fbreg = 0x91 COMMA + DW_OP_bregx = 0x92 COMMA + DW_OP_piece = 0x93 COMMA + DW_OP_deref_size = 0x94 COMMA + DW_OP_xderef_size = 0x95 COMMA + DW_OP_nop = 0x96 COMMA + /* DWARF 3 extensions. */ + DW_OP_push_object_address = 0x97 COMMA + DW_OP_call2 = 0x98 COMMA + DW_OP_call4 = 0x99 COMMA + DW_OP_call_ref = 0x9a COMMA + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0 +IF_NOT_ASM(};) + +#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ +#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ + +/* Type encodings. */ +ENUM(dwarf_type) + + DW_ATE_void = 0x0 COMMA + DW_ATE_address = 0x1 COMMA + DW_ATE_boolean = 0x2 COMMA + DW_ATE_complex_float = 0x3 COMMA + DW_ATE_float = 0x4 COMMA + DW_ATE_signed = 0x5 COMMA + DW_ATE_signed_char = 0x6 COMMA + DW_ATE_unsigned = 0x7 COMMA + DW_ATE_unsigned_char = 0x8 COMMA + /* DWARF 3. */ + DW_ATE_imaginary_float = 0x9 +IF_NOT_ASM(};) + +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff + +/* Array ordering names and codes. */ +ENUM(dwarf_array_dim_ordering) + + DW_ORD_row_major = 0 COMMA + DW_ORD_col_major = 1 +IF_NOT_ASM(};) + +/* Access attribute. */ +ENUM(dwarf_access_attribute) + + DW_ACCESS_public = 1 COMMA + DW_ACCESS_protected = 2 COMMA + DW_ACCESS_private = 3 +IF_NOT_ASM(};) + +/* Visibility. */ +ENUM(dwarf_visibility_attribute) + + DW_VIS_local = 1 COMMA + DW_VIS_exported = 2 COMMA + DW_VIS_qualified = 3 +IF_NOT_ASM(};) + +/* Virtuality. */ +ENUM(dwarf_virtuality_attribute) + + DW_VIRTUALITY_none = 0 COMMA + DW_VIRTUALITY_virtual = 1 COMMA + DW_VIRTUALITY_pure_virtual = 2 +IF_NOT_ASM(};) + +/* Case sensitivity. */ +ENUM(dwarf_id_case) + + DW_ID_case_sensitive = 0 COMMA + DW_ID_up_case = 1 COMMA + DW_ID_down_case = 2 COMMA + DW_ID_case_insensitive = 3 +IF_NOT_ASM(};) + +/* Calling convention. */ +ENUM(dwarf_calling_convention) + + DW_CC_normal = 0x1 COMMA + DW_CC_program = 0x2 COMMA + DW_CC_nocall = 0x3 +IF_NOT_ASM(};) + +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff + +/* Inline attribute. */ +ENUM(dwarf_inline_attribute) + + DW_INL_not_inlined = 0 COMMA + DW_INL_inlined = 1 COMMA + DW_INL_declared_not_inlined = 2 COMMA + DW_INL_declared_inlined = 3 +IF_NOT_ASM(};) + +/* Discriminant lists. */ +ENUM(dwarf_discrim_list) + + DW_DSC_label = 0 COMMA + DW_DSC_range = 1 +IF_NOT_ASM(};) + +/* Line number opcodes. */ +ENUM(dwarf_line_number_ops) + + DW_LNS_extended_op = 0 COMMA + DW_LNS_copy = 1 COMMA + DW_LNS_advance_pc = 2 COMMA + DW_LNS_advance_line = 3 COMMA + DW_LNS_set_file = 4 COMMA + DW_LNS_set_column = 5 COMMA + DW_LNS_negate_stmt = 6 COMMA + DW_LNS_set_basic_block = 7 COMMA + DW_LNS_const_add_pc = 8 COMMA + DW_LNS_fixed_advance_pc = 9 COMMA + /* DWARF 3. */ + DW_LNS_set_prologue_end = 10 COMMA + DW_LNS_set_epilogue_begin = 11 COMMA + DW_LNS_set_isa = 12 +IF_NOT_ASM(};) + +/* Line number extended opcodes. */ +ENUM(dwarf_line_number_x_ops) + + DW_LNE_end_sequence = 1 COMMA + DW_LNE_set_address = 2 COMMA + DW_LNE_define_file = 3 +IF_NOT_ASM(};) + +/* Call frame information. */ +ENUM(dwarf_call_frame_info) + + DW_CFA_advance_loc = 0x40 COMMA + DW_CFA_offset = 0x80 COMMA + DW_CFA_restore = 0xc0 COMMA + DW_CFA_nop = 0x00 COMMA + DW_CFA_set_loc = 0x01 COMMA + DW_CFA_advance_loc1 = 0x02 COMMA + DW_CFA_advance_loc2 = 0x03 COMMA + DW_CFA_advance_loc4 = 0x04 COMMA + DW_CFA_offset_extended = 0x05 COMMA + DW_CFA_restore_extended = 0x06 COMMA + DW_CFA_undefined = 0x07 COMMA + DW_CFA_same_value = 0x08 COMMA + DW_CFA_register = 0x09 COMMA + DW_CFA_remember_state = 0x0a COMMA + DW_CFA_restore_state = 0x0b COMMA + DW_CFA_def_cfa = 0x0c COMMA + DW_CFA_def_cfa_register = 0x0d COMMA + DW_CFA_def_cfa_offset = 0x0e COMMA + + /* DWARF 3. */ + DW_CFA_def_cfa_expression = 0x0f COMMA + DW_CFA_expression = 0x10 COMMA + DW_CFA_offset_extended_sf = 0x11 COMMA + DW_CFA_def_cfa_sf = 0x12 COMMA + DW_CFA_def_cfa_offset_sf = 0x13 COMMA + + /* SGI/MIPS specific. */ + DW_CFA_MIPS_advance_loc8 = 0x1d COMMA + + /* GNU extensions. */ + DW_CFA_GNU_window_save = 0x2d COMMA + DW_CFA_GNU_args_size = 0x2e COMMA + DW_CFA_GNU_negative_offset_extended = 0x2f +IF_NOT_ASM(};) + +#define DW_CIE_ID 0xffffffff +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ +ENUM(dwarf_source_language) + + DW_LANG_C89 = 0x0001 COMMA + DW_LANG_C = 0x0002 COMMA + DW_LANG_Ada83 = 0x0003 COMMA + DW_LANG_C_plus_plus = 0x0004 COMMA + DW_LANG_Cobol74 = 0x0005 COMMA + DW_LANG_Cobol85 = 0x0006 COMMA + DW_LANG_Fortran77 = 0x0007 COMMA + DW_LANG_Fortran90 = 0x0008 COMMA + DW_LANG_Pascal83 = 0x0009 COMMA + DW_LANG_Modula2 = 0x000a COMMA + DW_LANG_Java = 0x000b COMMA + /* DWARF 3. */ + DW_LANG_C99 = 0x000c COMMA + DW_LANG_Ada95 = 0x000d COMMA + DW_LANG_Fortran95 = 0x000e COMMA + /* MIPS. */ + DW_LANG_Mips_Assembler = 0x8001 COMMA + /* UPC. */ + DW_LANG_Upc = 0x8765 +IF_NOT_ASM(};) + +#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ +#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ + +/* Names and codes for macro information. */ +ENUM(dwarf_macinfo_record_type) + + DW_MACINFO_define = 1 COMMA + DW_MACINFO_undef = 2 COMMA + DW_MACINFO_start_file = 3 COMMA + DW_MACINFO_end_file = 4 COMMA + DW_MACINFO_vendor_ext = 255 +IF_NOT_ASM(};) + +/* @@@ For use with GNU frame unwind information. */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +#endif /* _ELF_DWARF2_H */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/linux/dwarf2-lang.h 2003-12-30 22:49:25.000000000 -0800 @@ -0,0 +1,132 @@ +#ifndef DWARF2_LANG +#define DWARF2_LANG +#include + +/* + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2, or (at your option) any later + * version. + */ +/* + * This file defines macros that allow generation of DWARF debug records + * for asm files. This file is platform independent. Register numbers + * (which are about the only thing that is platform dependent) are to be + * supplied by a platform defined file. + */ +#define DWARF_preamble() .section .debug_frame,"",@progbits +/* + * This macro starts a debug frame section. The debug_frame describes + * where to find the registers that the enclosing function saved on + * entry. + * + * ORD is use by the label generator and should be the same as what is + * passed to CFI_postamble. + * + * pc, pc register gdb ordinal. + * + * code_align this is the factor used to define locations or regions + * where the given definitions apply. If you use labels to define these + * this should be 1. + * + * data_align this is the factor used to define register offsets. If + * you use struct offset, this should be the size of the register in + * bytes or the negative of that. This is how it is used: you will + * define a register as the reference register, say the stack pointer, + * then you will say where a register is located relative to this + * reference registers value, say 40 for register 3 (the gdb register + * number). The <40> will be multiplied by to define the + * byte offset of the given register (3, in this example). So if your + * <40> is the byte offset and the reference register points at the + * begining, you would want 1 for the data_offset. If <40> was the 40th + * 4-byte element in that structure you would want 4. And if your + * reference register points at the end of the structure you would want + * a negative data_align value(and you would have to do other math as + * well). + */ + +#define CFI_preamble(ORD, pc, code_align, data_align) \ +.section .debug_frame,"",@progbits ; \ +frame/**/_/**/ORD: \ + .long end/**/_/**/ORD-start/**/_/**/ORD; \ +start/**/_/**/ORD: \ + .long DW_CIE_ID; \ + .byte DW_CIE_VERSION; \ + .byte 0 ; \ + .uleb128 code_align; \ + .sleb128 data_align; \ + .byte pc; + +/* + * After the above macro and prior to the CFI_postamble, you need to + * define the initial state. This starts with defining the reference + * register and, usually the pc. Here are some helper macros: + */ + +#define CFA_define_reference(reg, offset) \ + .byte DW_CFA_def_cfa; \ + .uleb128 reg; \ + .uleb128 (offset); + +#define CFA_define_offset(reg, offset) \ + .byte (DW_CFA_offset + reg); \ + .uleb128 (offset); + +#define CFI_postamble(ORD) \ + .align 4; \ +end/**/_/**/ORD: +/* + * So now your code pushs stuff on the stack, you need a new location + * and the rules for what to do. This starts a running description of + * the call frame. You need to describe what changes with respect to + * the call registers as the location of the pc moves through the code. + * The following builds an FDE (fram descriptor entry?). Like the + * above, it has a preamble and a postamble. It also is tied to the CFI + * above. + * The first entry after the preamble must be the location in the code + * that the call frame is being described for. + */ +#define FDE_preamble(ORD, fde_no, initial_address, length) \ + .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no; \ +FDE_start/**/_/**/fde_no: \ + .long frame/**/_/**/ORD; \ + .long initial_address; \ + .long length; + +#define FDE_postamble(fde_no) \ + .align 4; \ +FDE_end/**/_/**/fde_no: +/* + * That done, you can now add registers, subtract registers, move the + * reference and even change the reference. You can also define a new + * area of code the info applies to. For discontinuous bits you should + * start a new FDE. You may have as many as you like. + */ + +/* + * To advance the address by + */ + +#define FDE_advance(bytes) \ + .byte DW_CFA_advance_loc4 \ + .long bytes + + + +/* + * With the above you can define all the register locations. But + * suppose the reference register moves... Takes the new offset NOT an + * increment. This is how esp is tracked if it is not saved. + */ + +#define CFA_define_cfa_offset(offset) \ + .byte $DW_CFA_def_cfa_offset; \ + .uleb128 (offset); +/* + * Or suppose you want to use a different reference register... + */ +#define CFA_define_cfa_register(reg) \ + .byte DW_CFA_def_cfa_register; \ + .uleb128 reg; + +#endif --- linux-2.6.1-rc1/include/linux/elevator.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/elevator.h 2003-12-30 22:49:43.000000000 -0800 @@ -94,6 +94,11 @@ extern elevator_t iosched_deadline; */ extern elevator_t iosched_as; +/* + * completely fair queueing I/O scheduler + */ +extern elevator_t iosched_cfq; + extern int elevator_init(request_queue_t *, elevator_t *); extern void elevator_exit(request_queue_t *); extern inline int elv_rq_merge_ok(struct request *, struct bio *); --- linux-2.6.1-rc1/include/linux/errno.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/errno.h 2003-12-30 22:50:20.000000000 -0800 @@ -22,6 +22,7 @@ #define EBADTYPE 527 /* Type not supported by server */ #define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ #define EIOCBQUEUED 529 /* iocb queued, will get completion event */ +#define EIOCBRETRY 530 /* iocb queued, will trigger a retry */ #endif --- linux-2.6.1-rc1/include/linux/eventpoll.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/linux/eventpoll.h 2003-12-30 22:50:08.000000000 -0800 @@ -22,6 +22,9 @@ #define EPOLL_CTL_DEL 2 #define EPOLL_CTL_MOD 3 +/* Set the One Shot behaviour for the target file descriptor */ +#define EPOLLONESHOT (1 << 30) + /* Set the Edge Triggered behaviour for the target file descriptor */ #define EPOLLET (1 << 31) --- linux-2.6.1-rc1/include/linux/fb.h 2003-06-14 12:18:06.000000000 -0700 +++ 25/include/linux/fb.h 2003-12-30 22:50:07.000000000 -0800 @@ -352,6 +352,7 @@ struct fb_pixmap { struct fb_info; struct vm_area_struct; struct file; +struct device; /* * Frame buffer operations @@ -412,6 +413,7 @@ struct fb_info { struct vc_data *display_fg; /* Console visible on this display */ int currcon; /* Current VC. */ void *pseudo_palette; /* Fake palette of 16 colors */ + struct device *dev; /* pointer to the device for this fb */ /* From here on everything is device dependent */ void *par; }; --- linux-2.6.1-rc1/include/linux/fs.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/fs.h 2003-12-30 22:50:23.000000000 -0800 @@ -369,6 +369,7 @@ struct block_device { struct inode { struct hlist_node i_hash; struct list_head i_list; + struct list_head i_sb_list; struct list_head i_dentry; unsigned long i_ino; atomic_t i_count; @@ -388,6 +389,7 @@ struct inode { unsigned short i_bytes; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ struct semaphore i_sem; + struct rw_semaphore i_alloc_sem; struct inode_operations *i_op; struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct super_block *i_sb; @@ -480,6 +482,8 @@ static inline unsigned imajor(struct ino return MAJOR(inode->i_rdev); } +extern struct block_device *I_BDEV(struct inode *inode); + struct fown_struct { rwlock_t lock; /* protects pid, uid, euid fields */ int pid; /* pid or -pgrp where SIGIO should be sent */ @@ -523,9 +527,12 @@ struct file { /* needed for tty driver, and maybe others */ void *private_data; +#ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; spinlock_t f_ep_lock; +#endif /* #ifdef CONFIG_EPOLL */ + struct address_space *f_mapping; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); @@ -688,6 +695,7 @@ struct super_block { atomic_t s_active; void *s_security; + struct list_head s_inodes; /* all inodes */ struct list_head s_dirty; /* dirty inodes */ struct list_head s_io; /* parked for writeback */ struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */ @@ -750,6 +758,11 @@ extern int vfs_rename(struct inode *, st #define DT_SOCK 12 #define DT_WHT 14 +#define OSYNC_METADATA (1<<0) +#define OSYNC_DATA (1<<1) +#define OSYNC_INODE (1<<2) +int generic_osync_inode(struct inode *, struct address_space *, int); + /* * This is the "filldir" function type, used by readdir() to let * the kernel specify what kind of dirent layout it wants to have. @@ -759,9 +772,9 @@ extern int vfs_rename(struct inode *, st typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned); struct block_device_operations { - int (*open) (struct inode *, struct file *); - int (*release) (struct inode *, struct file *); - int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); + int (*open) (struct block_device *, struct file *); + int (*release) (struct gendisk *); + int (*ioctl) (struct block_device *, struct file *, unsigned, unsigned long); int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); struct module *owner; @@ -1124,11 +1137,9 @@ enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDE extern int register_blkdev(unsigned int, const char *); extern int unregister_blkdev(unsigned int, const char *); extern struct block_device *bdget(dev_t); -extern int bd_acquire(struct inode *inode); extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); extern int blkdev_open(struct inode *, struct file *); -extern int blkdev_close(struct inode *, struct file *); extern struct block_device *open_by_devnum(dev_t, unsigned, int); extern struct file_operations def_blk_fops; extern struct address_space_operations def_blk_aops; @@ -1136,7 +1147,7 @@ extern struct file_operations def_chr_fo extern struct file_operations bad_sock_fops; extern struct file_operations def_fifo_fops; extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); -extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long); +extern int blkdev_ioctl(struct block_device *, struct file *, unsigned, unsigned long); extern int blkdev_get(struct block_device *, mode_t, unsigned, int); extern int blkdev_put(struct block_device *, int); extern int bd_claim(struct block_device *, void *); @@ -1203,6 +1214,7 @@ extern void write_inode_now(struct inode extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); extern int filemap_fdatawait(struct address_space *); +extern int filemap_write_and_wait(struct address_space *mapping); extern void sync_supers(void); extern void sync_filesystems(int wait); extern void emergency_sync(void); @@ -1296,8 +1308,7 @@ extern int generic_file_readonly_mmap(st extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *); -int generic_write_checks(struct inode *inode, struct file *file, - loff_t *pos, size_t *count, int isblk); +int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk); extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t); extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *); @@ -1315,9 +1326,6 @@ extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); extern ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs); -extern int blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_blocks_t *get_blocks, dio_iodone_t *end_io); extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos); ssize_t generic_file_writev(struct file *filp, const struct iovec *iov, @@ -1331,7 +1339,7 @@ static inline void do_generic_file_read( read_descriptor_t * desc, read_actor_t actor) { - do_generic_mapping_read(filp->f_dentry->d_inode->i_mapping, + do_generic_mapping_read(filp->f_mapping, &filp->f_ra, filp, ppos, @@ -1339,6 +1347,32 @@ static inline void do_generic_file_read( actor); } +int __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, + struct block_device *bdev, const struct iovec *iov, loff_t offset, + unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io, + int needs_special_locking); + +/* + * For filesystems which need locking between buffered and direct access + */ +static inline int blockdev_direct_IO(int rw, struct kiocb *iocb, + struct inode *inode, struct block_device *bdev, const struct iovec *iov, + loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks, + dio_iodone_t end_io) +{ + return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, + nr_segs, get_blocks, end_io, 1); +} + +static inline int blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb, + struct inode *inode, struct block_device *bdev, const struct iovec *iov, + loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks, + dio_iodone_t end_io) +{ + return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, + nr_segs, get_blocks, end_io, 0); +} + extern struct file_operations generic_ro_fops; #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) --- linux-2.6.1-rc1/include/linux/ide.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/ide.h 2003-12-30 22:50:14.000000000 -0800 @@ -51,9 +51,6 @@ #ifndef SUPPORT_VLB_SYNC /* 1 to support weird 32-bit chips */ #define SUPPORT_VLB_SYNC 1 /* 0 to reduce kernel size */ #endif -#ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */ -#define DISK_RECOVERY_TIME 0 /* for hardware that needs it */ -#endif #ifndef OK_TO_RESET_CONTROLLER /* 1 needed for good error recovery */ #define OK_TO_RESET_CONTROLLER 1 /* 0 for use with AH2372A/B interface */ #endif @@ -999,10 +996,6 @@ typedef struct hwif_s { unsigned dma_extra; /* extra addr for dma ports */ unsigned long config_data; /* for use by chipset-specific code */ unsigned long select_data; /* for use by chipset-specific code */ -#if (DISK_RECOVERY_TIME > 0) - unsigned long last_time; /* time when previous rq was done */ -#endif - unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ --- linux-2.6.1-rc1/include/linux/if_bonding.h 2003-06-14 12:18:30.000000000 -0700 +++ 25/include/linux/if_bonding.h 2003-12-30 22:49:20.000000000 -0800 @@ -1,7 +1,7 @@ /* * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. * - * + * * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes * NCM: Network and Communications Management, Inc. * @@ -10,11 +10,11 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * 2003/03/18 - Amir Noam * - Added support for getting slave's speed and duplex via ethtool. * Needed for 802.3ad and other future modes. - * + * * 2003/03/18 - Tsippy Mendelson and * Shmulik Hen * - Enable support of modes that need to use the unique mac address of @@ -42,7 +42,7 @@ #include /* userland - kernel ABI version (2003/05/08) */ -#define BOND_ABI_VERSION 1 +#define BOND_ABI_VERSION 2 /* * We can remove these ioctl definitions in 2.5. People should use the @@ -77,10 +77,6 @@ #define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */ -#define BOND_MULTICAST_DISABLED 0 -#define BOND_MULTICAST_ACTIVE 1 -#define BOND_MULTICAST_ALL 2 - typedef struct ifbond { __s32 bond_mode; __s32 num_slaves; @@ -90,9 +86,9 @@ typedef struct ifbond { typedef struct ifslave { __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ - char slave_name[IFNAMSIZ]; - char link; - char state; + __s8 slave_name[IFNAMSIZ]; + __s8 link; + __s8 state; __u32 link_failure_count; } ifslave; @@ -115,3 +111,4 @@ struct ad_info { * tab-width: 8 * End: */ + --- linux-2.6.1-rc1/include/linux/init_task.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/init_task.h 2003-12-30 22:50:20.000000000 -0800 @@ -108,6 +108,7 @@ .proc_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \ .journal_info = NULL, \ + .io_wait = NULL, \ } --- linux-2.6.1-rc1/include/linux/list.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/list.h 2003-12-30 22:50:16.000000000 -0800 @@ -142,8 +142,11 @@ static inline void __list_del(struct lis * Note: list_empty on entry does not return true after this, the entry is * in an undefined state. */ +#include /* BUG_ON */ static inline void list_del(struct list_head *entry) { + BUG_ON(entry->prev->next != entry); + BUG_ON(entry->next->prev != entry); __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/linux/lockmeter.h 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,320 @@ +/* + * Copyright (C) 1999-2002 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000 + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks + * Added support for hold time statistics for read and write + * locks. + * Moved machine dependent code to include/asm/lockmeter.h. + * + */ + +#ifndef _LINUX_LOCKMETER_H +#define _LINUX_LOCKMETER_H + + +/*--------------------------------------------------- + * architecture-independent lockmeter.h + *-------------------------------------------------*/ + +/* + * raybry -- version 2: added efficient hold time statistics + * requires lstat recompile, so flagged as new version + * raybry -- version 3: added global reader lock data + * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port + */ +#define LSTAT_VERSION 5 + +int lstat_update(void*, void*, int); +int lstat_update_time(void*, void*, int, uint32_t); + +/* + * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we + * need to force compatibility in the inter-communication data structure. + */ + +#if defined(CONFIG_MIPS32_COMPAT) +#define TIME_T uint32_t +#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64) +#define TIME_T uint64_t +#else +#define TIME_T time_t +#endif + +#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32) +#define POINTER void * +#else +#define POINTER int64_t +#endif + +/* + * Values for the "action" parameter passed to lstat_update. + * ZZZ - do we want a try-success status here??? + */ +#define LSTAT_ACT_NO_WAIT 0 +#define LSTAT_ACT_SPIN 1 +#define LSTAT_ACT_REJECT 2 +#define LSTAT_ACT_WW_SPIN 3 +#define LSTAT_ACT_SLEPT 4 /* UNUSED */ + +#define LSTAT_ACT_MAX_VALUES 4 /* NOTE: Increase to 5 if use ACT_SLEPT */ + +/* + * Special values for the low 2 bits of an RA passed to + * lstat_update. + */ +/* we use these values to figure out what kind of lock data */ +/* is stored in the statistics table entry at index ....... */ +#define LSTAT_RA_SPIN 0 /* spin lock data */ +#define LSTAT_RA_READ 1 /* read lock statistics */ +#define LSTAT_RA_SEMA 2 /* RESERVED */ +#define LSTAT_RA_WRITE 3 /* write lock statistics*/ + +#define LSTAT_RA(n) \ + ((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) ) + +/* + * Constants used for lock addresses in the lstat_directory + * to indicate special values of the lock address. + */ +#define LSTAT_MULTI_LOCK_ADDRESS NULL + +/* + * Maximum size of the lockstats tables. Increase this value + * if its not big enough. (Nothing bad happens if its not + * big enough although some locks will not be monitored.) + * We record overflows of this quantity in lstat_control.dir_overflows + * + * Note: The max value here must fit into the field set + * and obtained by the macro's PUT_INDEX() and GET_INDEX(). + * This value depends on how many bits are available in the + * lock word in the particular machine implementation we are on. + */ +#define LSTAT_MAX_STAT_INDEX 2000 + +/* + * Size and mask for the hash table into the directory. + */ +#define LSTAT_HASH_TABLE_SIZE 4096 /* must be 2**N */ +#define LSTAT_HASH_TABLE_MASK (LSTAT_HASH_TABLE_SIZE-1) + +#define DIRHASH(ra) ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK) + +/* + * This defines an entry in the lockstat directory. It contains + * information about a lock being monitored. + * A directory entry only contains the lock identification - + * counts on usage of the lock are kept elsewhere in a per-cpu + * data structure to minimize cache line pinging. + */ +typedef struct { + POINTER caller_ra; /* RA of code that set lock */ + POINTER lock_ptr; /* lock address */ + ushort next_stat_index; /* Used to link multiple locks that have the same hash table value */ +} lstat_directory_entry_t; + +/* + * A multi-dimensioned array used to contain counts for lock accesses. + * The array is 3-dimensional: + * - CPU number. Keep from thrashing cache lines between CPUs + * - Directory entry index. Identifies the lock + * - Action. Indicates what kind of contention occurred on an + * access to the lock. + * + * The index of an entry in the directory is the same as the 2nd index + * of the entry in the counts array. + */ +/* + * This table contains data for spin_locks, write locks, and read locks + * Not all data is used for all cases. In particular, the hold time + * information is not stored here for read locks since that is a global + * (e. g. cannot be separated out by return address) quantity. + * See the lstat_read_lock_counts_t structure for the global read lock + * hold time. + */ +typedef struct { + uint64_t cum_wait_ticks; /* sum of wait times */ + /* for write locks, sum of time a */ + /* writer is waiting for a reader */ + int64_t cum_hold_ticks; /* cumulative sum of holds */ + /* not used for read mode locks */ + /* must be signed. ............... */ + uint32_t max_wait_ticks; /* max waiting time */ + uint32_t max_hold_ticks; /* max holding time */ + uint64_t cum_wait_ww_ticks; /* sum times writer waits on writer*/ + uint32_t max_wait_ww_ticks; /* max wait time writer vs writer */ + /* prev 2 only used for write locks*/ + uint32_t acquire_time; /* time lock acquired this CPU */ + uint32_t count[LSTAT_ACT_MAX_VALUES]; +} lstat_lock_counts_t; + +typedef lstat_lock_counts_t lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX]; + +/* + * User request to: + * - turn statistic collection on/off, or to reset + */ +#define LSTAT_OFF 0 +#define LSTAT_ON 1 +#define LSTAT_RESET 2 +#define LSTAT_RELEASE 3 + +#define LSTAT_MAX_READ_LOCK_INDEX 1000 +typedef struct { + POINTER lock_ptr; /* address of lock for output stats */ + uint32_t read_lock_count; + int64_t cum_hold_ticks; /* sum of read lock hold times over */ + /* all callers. ....................*/ + uint32_t write_index; /* last write lock hash table index */ + uint32_t busy_periods; /* count of busy periods ended this */ + uint64_t start_busy; /* time this busy period started. ..*/ + uint64_t busy_ticks; /* sum of busy periods this lock. ..*/ + uint64_t max_busy; /* longest busy period for this lock*/ + uint32_t max_readers; /* maximum number of readers ...... */ +#ifdef USER_MODE_TESTING + rwlock_t entry_lock; /* lock for this read lock entry... */ + /* avoid having more than one rdr at*/ + /* needed for user space testing... */ + /* not needed for kernel 'cause it */ + /* is non-preemptive. ............. */ +#endif +} lstat_read_lock_counts_t; +typedef lstat_read_lock_counts_t lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX]; + +#if defined(__KERNEL__) || defined(USER_MODE_TESTING) + +#ifndef USER_MODE_TESTING +#include +#else +#include "asm_newlockmeter.h" +#endif + +/* + * Size and mask for the hash table into the directory. + */ +#define LSTAT_HASH_TABLE_SIZE 4096 /* must be 2**N */ +#define LSTAT_HASH_TABLE_MASK (LSTAT_HASH_TABLE_SIZE-1) + +#define DIRHASH(ra) ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK) + +/* + * This version eliminates the per processor lock stack. What we do is to + * store the index of the lock hash structure in unused bits in the lock + * itself. Then on unlock we can find the statistics record without doing + * any additional hash or lock stack lookup. This works for spin_locks. + * Hold time reporting is now basically as cheap as wait time reporting + * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT + * as in version 1.1.* of lockmeter. + * + * For rw_locks, we store the index of a global reader stats structure in + * the lock and the writer index is stored in the latter structure. + * For read mode locks we hash at the time of the lock to find an entry + * in the directory for reader wait time and the like. + * At unlock time for read mode locks, we update just the global structure + * so we don't need to know the reader directory index value at unlock time. + * + */ + +/* + * Protocol to change lstat_control.state + * This is complicated because we don't want the cum_hold_time for + * a rw_lock to be decremented in _read_lock_ without making sure it + * is incremented in _read_lock_ and vice versa. So here is the + * way we change the state of lstat_control.state: + * I. To Turn Statistics On + * After allocating storage, set lstat_control.state non-zero. + * This works because we don't start updating statistics for in use + * locks until the reader lock count goes to zero. + * II. To Turn Statistics Off: + * (0) Disable interrupts on this CPU + * (1) Seize the lstat_control.directory_lock + * (2) Obtain the current value of lstat_control.next_free_read_lock_index + * (3) Store a zero in lstat_control.state. + * (4) Release the lstat_control.directory_lock + * (5) For each lock in the read lock list up to the saved value + * (well, -1) of the next_free_read_lock_index, do the following: + * (a) Check validity of the stored lock address + * by making sure that the word at the saved addr + * has an index that matches this entry. If not + * valid, then skip this entry. + * (b) If there is a write lock already set on this lock, + * skip to (d) below. + * (c) Set a non-metered write lock on the lock + * (d) set the cached INDEX in the lock to zero + * (e) Release the non-metered write lock. + * (6) Re-enable interrupts + * + * These rules ensure that a read lock will not have its statistics + * partially updated even though the global lock recording state has + * changed. See put_lockmeter_info() for implementation. + * + * The reason for (b) is that there may be write locks set on the + * syscall path to put_lockmeter_info() from user space. If we do + * not do this check, then we can deadlock. A similar problem would + * occur if the lock was read locked by the current CPU. At the + * moment this does not appear to happen. + */ + +/* + * Main control structure for lockstat. Used to turn statistics on/off + * and to maintain directory info. + */ +typedef struct { + int state; + spinlock_t control_lock; /* used to serialize turning statistics on/off */ + spinlock_t directory_lock; /* for serialize adding entries to directory */ + volatile int next_free_dir_index;/* next free entry in the directory */ + /* FIXME not all of these fields are used / needed .............. */ + /* the following fields represent data since */ + /* first "lstat on" or most recent "lstat reset" */ + TIME_T first_started_time; /* time when measurement first enabled */ + TIME_T started_time; /* time when measurement last started */ + TIME_T ending_time; /* time when measurement last disabled */ + uint64_t started_cycles64; /* cycles when measurement last started */ + uint64_t ending_cycles64; /* cycles when measurement last disabled */ + uint64_t enabled_cycles64; /* total cycles with measurement enabled */ + int intervals; /* number of measurement intervals recorded */ + /* i. e. number of times did lstat on;lstat off */ + lstat_directory_entry_t *dir; /* directory */ + int dir_overflow; /* count of times ran out of space in directory */ + int rwlock_overflow; /* count of times we couldn't allocate a rw block*/ + ushort *hashtab; /* hash table for quick dir scans */ + lstat_cpu_counts_t *counts[NR_CPUS]; /* Array of pointers to per-cpu stats */ + int next_free_read_lock_index; /* next rwlock reader (global) stats block */ + lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats */ +} lstat_control_t; + +#endif /* defined(__KERNEL__) || defined(USER_MODE_TESTING) */ + +typedef struct { + short lstat_version; /* version of the data */ + short state; /* the current state is returned */ + int maxcpus; /* Number of cpus present */ + int next_free_dir_index; /* index of the next free directory entry */ + TIME_T first_started_time; /* when measurement enabled for first time */ + TIME_T started_time; /* time in secs since 1969 when stats last turned on */ + TIME_T ending_time; /* time in secs since 1969 when stats last turned off */ + uint32_t cycleval; /* cycles per second */ +#ifdef notyet + void *kernel_magic_addr; /* address of kernel_magic */ + void *kernel_end_addr; /* contents of kernel magic (points to "end") */ +#endif + int next_free_read_lock_index; /* index of next (global) read lock stats struct */ + uint64_t started_cycles64; /* cycles when measurement last started */ + uint64_t ending_cycles64; /* cycles when stats last turned off */ + uint64_t enabled_cycles64; /* total cycles with measurement enabled */ + int intervals; /* number of measurement intervals recorded */ + /* i.e. number of times we did lstat on;lstat off*/ + int dir_overflow; /* number of times we wanted more space in directory */ + int rwlock_overflow; /* # of times we wanted more space in read_locks_count */ + struct new_utsname uts; /* info about machine where stats are measured */ + /* -T option of lockstat allows data to be */ + /* moved to another machine. ................. */ +} lstat_user_request_t; + +#endif /* _LINUX_LOCKMETER_H */ --- linux-2.6.1-rc1/include/linux/loop.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/loop.h 2003-12-30 22:49:51.000000000 -0800 @@ -34,8 +34,9 @@ struct loop_device { loff_t lo_sizelimit; int lo_flags; int (*transfer)(struct loop_device *, int cmd, - char *raw_buf, char *loop_buf, int size, - sector_t real_block); + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t real_block); char lo_file_name[LO_NAME_SIZE]; char lo_crypt_name[LO_NAME_SIZE]; char lo_encrypt_key[LO_KEY_SIZE]; @@ -128,8 +129,10 @@ struct loop_info64 { /* Support for loadable transfer modules */ struct loop_func_table { int number; /* filter type */ - int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t real_block); + int (*transfer)(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t real_block); int (*init)(struct loop_device *, const struct loop_info64 *); /* release is called from loop_unregister_transfer or clr_fd */ int (*release)(struct loop_device *); --- linux-2.6.1-rc1/include/linux/miscdevice.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/linux/miscdevice.h 2003-12-30 22:50:06.000000000 -0800 @@ -36,12 +36,15 @@ #define TUN_MINOR 200 +struct device; + struct miscdevice { int minor; const char *name; struct file_operations *fops; struct list_head list; + struct device *dev; char devfs_name[64]; }; --- linux-2.6.1-rc1/include/linux/netdevice.h 2003-11-23 19:03:02.000000000 -0800 +++ 25/include/linux/netdevice.h 2003-12-30 22:49:20.000000000 -0800 @@ -452,6 +452,12 @@ struct net_device unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); +#ifdef CONFIG_NETPOLL_RX + int netpoll_rx; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); +#endif /* bridge stuff */ struct net_bridge_port *br_port; @@ -470,8 +476,15 @@ struct net_device /* class/net/name entry */ struct class_device class_dev; struct net_device_stats* (*last_stats)(struct net_device *); + /* how much padding had been added by alloc_netdev() */ + int padded; }; +static inline void *netdev_priv(struct net_device *dev) +{ + return (char *)dev + ((sizeof(struct net_device) + 31) & ~31); +} + #define SET_MODULE_OWNER(dev) do { } while (0) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. @@ -496,6 +509,7 @@ extern rwlock_t dev_base_lock; /* De extern int netdev_boot_setup_add(char *name, struct ifmap *map); extern int netdev_boot_setup_check(struct net_device *dev); +extern unsigned long netdev_boot_base(const char *prefix, int unit); extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); extern struct net_device *__dev_getfirstbyhwtype(unsigned short type); extern struct net_device *dev_getfirstbyhwtype(unsigned short type); @@ -533,6 +547,9 @@ extern int dev_new_index(void); extern struct net_device *dev_get_by_index(int ifindex); extern struct net_device *__dev_get_by_index(int ifindex); extern int dev_restart(struct net_device *dev); +#ifdef CONFIG_NETPOLL_TRAP +extern int netpoll_trap(void); +#endif typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); @@ -591,12 +608,20 @@ static inline void netif_start_queue(str static inline void netif_wake_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } static inline void netif_stop_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif set_bit(__LINK_STATE_XOFF, &dev->state); } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/linux/netpoll.h 2003-12-30 22:49:20.000000000 -0800 @@ -0,0 +1,38 @@ +/* + * Common code for low-level network console, dump, and debugger code + * + * Derived from netconsole, kgdb-over-ethernet, and netdump patches + */ + +#ifndef _LINUX_NETPOLL_H +#define _LINUX_NETPOLL_H + +#include +#include +#include +#include + +struct netpoll; + +struct netpoll { + struct net_device *dev; + char dev_name[16], *name; + void (*rx_hook)(struct netpoll *, int, char *, int); + u32 local_ip, remote_ip; + u16 local_port, remote_port; + unsigned char local_mac[6], remote_mac[6]; + struct list_head rx_list; +}; + +void netpoll_poll(struct netpoll *np); +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb); +void netpoll_send_udp(struct netpoll *np, const char *msg, int len); +int netpoll_parse_options(struct netpoll *np, char *opt); +int netpoll_setup(struct netpoll *np); +int netpoll_trap(void); +void netpoll_set_trap(int trap); +void netpoll_cleanup(struct netpoll *np); +int netpoll_rx(struct sk_buff *skb); + + +#endif --- linux-2.6.1-rc1/include/linux/pagemap.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/pagemap.h 2003-12-30 22:50:25.000000000 -0800 @@ -70,7 +70,7 @@ extern struct page * find_trylock_page(s extern struct page * find_or_create_page(struct address_space *mapping, unsigned long index, unsigned int gfp_mask); extern unsigned int find_get_pages(struct address_space *mapping, - pgoff_t start, unsigned int nr_pages, + pgoff_t *next, unsigned int nr_pages, struct page **pages); /* @@ -152,17 +152,27 @@ static inline void ___add_to_page_cache( extern void FASTCALL(__lock_page(struct page *page)); extern void FASTCALL(unlock_page(struct page *page)); -static inline void lock_page(struct page *page) + +extern int FASTCALL(__lock_page_wq(struct page *page, wait_queue_t *wait)); +static inline int lock_page_wq(struct page *page, wait_queue_t *wait) { if (TestSetPageLocked(page)) - __lock_page(page); + return __lock_page_wq(page, wait); + else + return 0; +} + +static inline void lock_page(struct page *page) +{ + lock_page_wq(page, NULL); } /* * This is exported only for wait_on_page_locked/wait_on_page_writeback. * Never use this directly! */ -extern void FASTCALL(wait_on_page_bit(struct page *page, int bit_nr)); +extern int FASTCALL(wait_on_page_bit_wq(struct page *page, int bit_nr, + wait_queue_t *wait)); /* * Wait for a page to be unlocked. @@ -171,19 +181,33 @@ extern void FASTCALL(wait_on_page_bit(st * ie with increased "page->count" so that the page won't * go away during the wait.. */ -static inline void wait_on_page_locked(struct page *page) +static inline int wait_on_page_locked_wq(struct page *page, wait_queue_t *wait) { if (PageLocked(page)) - wait_on_page_bit(page, PG_locked); + return wait_on_page_bit_wq(page, PG_locked, wait); + return 0; +} + +static inline int wait_on_page_writeback_wq(struct page *page, + wait_queue_t *wait) +{ + if (PageWriteback(page)) + return wait_on_page_bit_wq(page, PG_writeback, wait); + return 0; +} + +static inline void wait_on_page_locked(struct page *page) +{ + wait_on_page_locked_wq(page, NULL); } /* * Wait for a page to complete writeback */ + static inline void wait_on_page_writeback(struct page *page) { - if (PageWriteback(page)) - wait_on_page_bit(page, PG_writeback); + wait_on_page_writeback_wq(page, NULL); } extern void end_page_writeback(struct page *page); --- linux-2.6.1-rc1/include/linux/pagevec.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/pagevec.h 2003-12-30 22:50:25.000000000 -0800 @@ -23,7 +23,7 @@ void __pagevec_lru_add(struct pagevec *p void __pagevec_lru_add_active(struct pagevec *pvec); void pagevec_strip(struct pagevec *pvec); unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, - pgoff_t start, unsigned int nr_pages); + pgoff_t *next, unsigned int nr_pages); static inline void pagevec_init(struct pagevec *pvec, int cold) { --- linux-2.6.1-rc1/include/linux/pci_ids.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/pci_ids.h 2003-12-30 22:50:12.000000000 -0800 @@ -630,6 +630,8 @@ #define PCI_DEVICE_ID_HP_TACHLITE 0x1029 #define PCI_DEVICE_ID_HP_J2585A 0x1030 #define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_DEVICE_ID_HP_J2973A 0x1040 +#define PCI_DEVICE_ID_HP_J2970A 0x1042 #define PCI_DEVICE_ID_HP_DIVA 0x1048 #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A @@ -882,6 +884,7 @@ #define PCI_DEVICE_ID_SII_680 0x0680 #define PCI_DEVICE_ID_SII_3112 0x3112 +#define PCI_DEVICE_ID_SII_3114 0x3114 #define PCI_DEVICE_ID_SII_1210SA 0x0240 #define PCI_VENDOR_ID_VISION 0x1098 @@ -1785,11 +1788,13 @@ #define PCI_DEVICE_ID_TIGON3_5702 0x1646 #define PCI_DEVICE_ID_TIGON3_5703 0x1647 #define PCI_DEVICE_ID_TIGON3_5704 0x1648 +#define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649 #define PCI_DEVICE_ID_TIGON3_5702FE 0x164d #define PCI_DEVICE_ID_TIGON3_5705 0x1653 #define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 #define PCI_DEVICE_ID_TIGON3_5705M 0x165d #define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e +#define PCI_DEVICE_ID_TIGON3_5705F 0x166e #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5788 0x169c #define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 --- linux-2.6.1-rc1/include/linux/sched.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/sched.h 2003-12-30 22:50:20.000000000 -0800 @@ -151,6 +151,7 @@ extern void init_idle(task_t *idle, int extern void show_state(void); extern void show_regs(struct pt_regs *); +extern void show_trace_task(task_t *tsk); /* * TASK is a pointer to the task whose backtrace we want to see (or NULL for current @@ -463,6 +464,13 @@ struct task_struct { unsigned long ptrace_message; siginfo_t *last_siginfo; /* For ptrace use. */ +/* + * current io wait handle: wait queue entry to use for io waits + * If this thread is processing aio, this points at the waitqueue + * inside the currently handled kiocb. It may be NULL (i.e. default + * to a stack based synchronous wait) if its doing sync IO. + */ + wait_queue_t *io_wait; }; static inline pid_t process_group(struct task_struct *tsk) @@ -579,6 +587,7 @@ extern int FASTCALL(wake_up_process(stru static inline void kick_process(struct task_struct *tsk) { } #endif extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk)); +extern void FASTCALL(sched_fork(task_t * p)); extern void FASTCALL(sched_exit(task_t * p)); asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); --- linux-2.6.1-rc1/include/linux/serial_core.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/serial_core.h 2003-12-30 22:49:25.000000000 -0800 @@ -158,7 +158,9 @@ struct uart_port { unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ unsigned char iotype; /* io access style */ - +#ifdef CONFIG_KGDB + int kgdb; /* in use by kgdb */ +#endif #define UPIO_PORT (0) #define UPIO_HUB6 (1) #define UPIO_MEM (2) --- linux-2.6.1-rc1/include/linux/smp.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/linux/smp.h 2003-12-30 22:50:14.000000000 -0800 @@ -103,7 +103,6 @@ void smp_prepare_boot_cpu(void); #define on_each_cpu(func,info,retry,wait) ({ func(info); 0; }) static inline void smp_send_reschedule(int cpu) { } #define num_booting_cpus() 1 -#define cpu_possible(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define smp_prepare_boot_cpu() do {} while (0) #endif /* !SMP */ --- linux-2.6.1-rc1/include/linux/spinlock.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/spinlock.h 2003-12-30 22:50:17.000000000 -0800 @@ -15,6 +15,12 @@ #include /* for cpu relax */ #include +#ifdef CONFIG_KGDB +#include +#define SET_WHO(x, him) (x)->who = him; +#else +#define SET_WHO(x, him) +#endif /* * Must define these before including other files, inline functions need them @@ -55,6 +61,9 @@ typedef struct { const char *module; char *owner; int oline; +#ifdef CONFIG_KGDB + struct task_struct *who; +#endif } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0} @@ -66,6 +75,7 @@ typedef struct { (x)->module = __FILE__; \ (x)->owner = NULL; \ (x)->oline = 0; \ + SET_WHO(x, NULL) \ } while (0) #define CHECK_LOCK(x) \ @@ -88,6 +98,7 @@ typedef struct { (x)->lock = 1; \ (x)->owner = __FILE__; \ (x)->oline = __LINE__; \ + SET_WHO(x, current) \ } while (0) /* without debugging, spin_is_locked on UP always says @@ -118,6 +129,7 @@ typedef struct { (x)->lock = 1; \ (x)->owner = __FILE__; \ (x)->oline = __LINE__; \ + SET_WHO(x, current) \ 1; \ }) @@ -184,6 +196,17 @@ typedef struct { #endif /* !SMP */ +#ifdef CONFIG_LOCKMETER +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock (spinlock_t *lock); +extern int _metered_spin_trylock(spinlock_t *lock); +extern void _metered_read_lock (rwlock_t *lock); +extern void _metered_read_unlock (rwlock_t *lock); +extern void _metered_write_lock (rwlock_t *lock); +extern void _metered_write_unlock (rwlock_t *lock); +extern int _metered_write_trylock(rwlock_t *lock); +#endif + /* * Define the various spin_lock and rw_lock methods. Note we define these * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various @@ -389,6 +412,141 @@ do { \ _raw_spin_trylock(lock) ? 1 : \ ({preempt_enable(); local_bh_enable(); 0;});}) +#ifdef CONFIG_LOCKMETER +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#undef spin_lock_irqsave +#undef spin_lock_irq +#undef spin_lock_bh +#undef read_lock +#undef read_unlock +#undef write_lock +#undef write_unlock +#undef write_trylock +#undef spin_unlock_bh +#undef read_lock_irqsave +#undef read_lock_irq +#undef read_lock_bh +#undef read_unlock_bh +#undef write_lock_irqsave +#undef write_lock_irq +#undef write_lock_bh +#undef write_unlock_bh + +#define spin_lock(lock) \ +do { \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while(0) + +#define spin_trylock(lock) ({preempt_disable(); _metered_spin_trylock(lock) ? \ + 1 : ({preempt_enable(); 0;});}) +#define spin_unlock(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable(); \ +} while (0) + +#define spin_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_unlock_bh(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + + +#define read_lock(lock) ({preempt_disable(); _metered_read_lock(lock);}) +#define read_unlock(lock) ({_metered_read_unlock(lock); preempt_enable();}) +#define write_lock(lock) ({preempt_disable(); _metered_write_lock(lock);}) +#define write_unlock(lock) ({_metered_write_unlock(lock); preempt_enable();}) +#define write_trylock(lock) ({preempt_disable();_metered_write_trylock(lock) ? \ + 1 : ({preempt_enable(); 0;});}) +#define spin_unlock_no_resched(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable_no_resched(); \ +} while (0) + +#define read_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_unlock_bh(lock) \ +do { \ + _metered_read_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + +#define write_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_unlock_bh(lock) \ +do { \ + _metered_write_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + +#endif /* !CONFIG_LOCKMETER */ + /* "lock on reference count zero" */ #ifndef ATOMIC_DEC_AND_LOCK #include --- linux-2.6.1-rc1/include/linux/swap.h 2003-10-08 15:07:10.000000000 -0700 +++ 25/include/linux/swap.h 2003-12-30 22:50:01.000000000 -0800 @@ -173,7 +173,7 @@ extern int rotate_reclaimable_page(struc extern void swap_setup(void); /* linux/mm/vmscan.c */ -extern int try_to_free_pages(struct zone *, unsigned int, unsigned int); +extern int try_to_free_pages(struct zone **, unsigned int, unsigned int); extern int shrink_all_memory(int); extern int vm_swappiness; --- linux-2.6.1-rc1/include/linux/sysctl.h 2003-12-30 22:37:22.000000000 -0800 +++ 25/include/linux/sysctl.h 2003-12-30 22:50:20.000000000 -0800 @@ -609,6 +609,8 @@ enum FS_LEASE_TIME=15, /* int: maximum time to wait for a lease break */ FS_DQSTATS=16, /* disc quota usage statistics */ FS_XFS=17, /* struct: control xfs parameters */ + FS_AIO_NR=18, /* current system-wide number of aio requests */ + FS_AIO_MAX_NR=19, /* system-wide maximum number of aio requests */ }; /* /proc/sys/fs/quota/ */ @@ -734,6 +736,8 @@ extern int proc_dointvec_minmax(ctl_tabl void __user *, size_t *); extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, void __user *, size_t *); +extern int proc_dointvec_userhz_jiffies(ctl_table *, int, struct file *, + void __user *, size_t *); extern int proc_doulongvec_minmax(ctl_table *, int, struct file *, void __user *, size_t *); extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int, --- linux-2.6.1-rc1/include/linux/sysfs.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/sysfs.h 2003-12-30 22:49:49.000000000 -0800 @@ -18,6 +18,12 @@ struct attribute { mode_t mode; }; +struct attribute_group { + char * name; + struct attribute ** attrs; +}; + + struct bin_attribute { struct attribute attr; size_t size; @@ -25,14 +31,13 @@ struct bin_attribute { ssize_t (*write)(struct kobject *, char *, loff_t, size_t); }; -int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr); -int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); - struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *,char *); ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); }; +#ifdef CONFIG_SYSFS + extern int sysfs_create_dir(struct kobject *); @@ -57,13 +62,75 @@ sysfs_create_link(struct kobject * kobj, extern void sysfs_remove_link(struct kobject *, char * name); - -struct attribute_group { - char * name; - struct attribute ** attrs; -}; +int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr); +int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); int sysfs_create_group(struct kobject *, const struct attribute_group *); void sysfs_remove_group(struct kobject *, const struct attribute_group *); +#else /* CONFIG_SYSFS */ + +static inline int sysfs_create_dir(struct kobject * k) +{ + return 0; +} + +static inline void sysfs_remove_dir(struct kobject * k) +{ + ; +} + +static inline void sysfs_rename_dir(struct kobject * k, const char *new_name) +{ + ; +} + +static inline int sysfs_create_file(struct kobject * k, const struct attribute * a) +{ + return 0; +} + +static inline int sysfs_update_file(struct kobject * k, const struct attribute * a) +{ + return 0; +} + +static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a) +{ + ; +} + +static inline int sysfs_create_link(struct kobject * k, struct kobject * t, char * n) +{ + return 0; +} + +static inline void sysfs_remove_link(struct kobject * k, char * name) +{ + ; +} + + +static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a) +{ + return 0; +} + +static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a) +{ + return 0; +} + +static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g) +{ + return 0; +} + +static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g) +{ + ; +} + +#endif /* CONFIG_SYSFS */ + #endif /* _SYSFS_H_ */ --- linux-2.6.1-rc1/include/linux/wait.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/wait.h 2003-12-30 22:50:20.000000000 -0800 @@ -80,6 +80,15 @@ static inline int waitqueue_active(wait_ return !list_empty(&q->task_list); } +/* + * Used to distinguish between sync and async io wait context: + * sync i/o typically specifies a NULL wait queue entry or a wait + * queue entry bound to a task (current task) to wake up. + * aio specifies a wait queue entry with an async notification + * callback routine, not associated with any task. + */ +#define is_sync_wait(wait) (!(wait) || ((wait)->task)) + extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); --- linux-2.6.1-rc1/include/linux/writeback.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/writeback.h 2003-12-30 22:50:24.000000000 -0800 @@ -84,9 +84,13 @@ int dirty_writeback_centisecs_handler(st void __user *, size_t *); void page_writeback_init(void); -void balance_dirty_pages_ratelimited(struct address_space *mapping); +int balance_dirty_pages_ratelimited(struct address_space *mapping); int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); int do_writepages(struct address_space *mapping, struct writeback_control *wbc); +ssize_t sync_page_range(struct inode *inode, struct address_space *mapping, + loff_t pos, size_t count); +ssize_t sync_page_range_nolock(struct inode *inode, struct address_space + *mapping, loff_t pos, size_t count); /* pdflush.c */ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl --- linux-2.6.1-rc1/include/net/atmclip.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/net/atmclip.h 2003-12-30 22:49:20.000000000 -0800 @@ -44,7 +44,7 @@ struct atmarp_entry { }; -#define PRIV(dev) ((struct clip_priv *) ((struct net_device *) (dev)+1)) +#define PRIV(dev) ((struct clip_priv *) netdev_priv(dev)) struct clip_priv { --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/include/pcmcia/compat.h 2003-12-30 22:50:04.000000000 -0800 @@ -0,0 +1,27 @@ +/* + * include/pcmcia/pcmcia_compat.c - compatibility layer for 2.4. PCMCIA drivers + * + * + * Copyright (C) 2003 Dominik Brodowski + * + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _LINUX_PCMCIA_COMPAT_H +#define _LINUX_PCMCIA_COMPAT_H + +#ifndef IN_CARD_SERVICES /* avoids "deprecated" messages on EXPORT_SYMBOL */ + +extern int __deprecated CardServices(int func, ...); + +#endif + +#endif /* _LINUX_PCMCIA_COMPAT_H */ --- linux-2.6.1-rc1/include/pcmcia/cs.h 2003-10-08 15:07:10.000000000 -0700 +++ 25/include/pcmcia/cs.h 2003-12-30 22:50:04.000000000 -0800 @@ -30,6 +30,8 @@ #ifndef _LINUX_CS_H #define _LINUX_CS_H +#include + /* For AccessConfigurationRegister */ typedef struct conf_reg_t { u_char Function; @@ -421,12 +423,6 @@ enum service { GetFirstWindow, GetNextWindow, GetMemPage }; -#ifdef IN_CARD_SERVICES -extern int CardServices(int func, void *a1, void *a2, void *a3); -#else -extern int CardServices(int func, ...); -#endif - int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg); int pcmcia_bind_device(bind_req_t *req); int pcmcia_bind_mtd(mtd_bind_t *req); --- linux-2.6.1-rc1/include/sound/i2c.h 2003-06-14 12:18:00.000000000 -0700 +++ 25/include/sound/i2c.h 2003-12-30 22:49:57.000000000 -0800 @@ -58,7 +58,7 @@ struct _snd_i2c_bus { snd_card_t *card; /* card which I2C belongs to */ char name[32]; /* some useful label */ - spinlock_t lock; + struct semaphore lock_mutex; snd_i2c_bus_t *master; /* master bus when SCK/SCL is shared */ struct list_head buses; /* master: slave buses sharing SCK/SCL, slave: link list */ @@ -84,15 +84,15 @@ int snd_i2c_device_free(snd_i2c_device_t static inline void snd_i2c_lock(snd_i2c_bus_t *bus) { if (bus->master) - spin_lock(&bus->master->lock); + down(&bus->master->lock_mutex); else - spin_lock(&bus->lock); + down(&bus->lock_mutex); } static inline void snd_i2c_unlock(snd_i2c_bus_t *bus) { if (bus->master) - spin_unlock(&bus->master->lock); + up(&bus->master->lock_mutex); else - spin_unlock(&bus->lock); + up(&bus->lock_mutex); } int snd_i2c_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count); --- linux-2.6.1-rc1/init/do_mounts.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/init/do_mounts.c 2003-12-30 22:49:49.000000000 -0800 @@ -141,9 +141,11 @@ dev_t __init name_to_dev_t(char *name) dev_t res = 0; int part; +#ifdef CONFIG_SYSFS sys_mkdir("/sys", 0700); if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0) goto out; +#endif if (strncmp(name, "/dev/", 5) != 0) { unsigned maj, min; --- linux-2.6.1-rc1/init/Kconfig 2003-12-30 22:37:22.000000000 -0800 +++ 25/init/Kconfig 2003-12-30 22:49:49.000000000 -0800 @@ -43,7 +43,7 @@ config CLEAN_COMPILE config STANDALONE bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL - default y + default n help Select this option if you don't have magic firmware for drivers that need it. --- linux-2.6.1-rc1/kernel/fork.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/kernel/fork.c 2003-12-30 22:50:20.000000000 -0800 @@ -60,10 +60,9 @@ int nr_processes(void) int cpu; int total = 0; - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (cpu_online(cpu)) - total += per_cpu(process_counts, cpu); - } + for_each_cpu(cpu) + total += per_cpu(process_counts, cpu); + return total; } @@ -146,7 +145,12 @@ void prepare_to_wait(wait_queue_head_t * spin_lock_irqsave(&q->lock, flags); if (list_empty(&wait->task_list)) __add_wait_queue(q, wait); - set_current_state(state); + /* + * don't alter the task state if this is just going to + * queue an async wait queue callback + */ + if (is_sync_wait(wait)) + set_current_state(state); spin_unlock_irqrestore(&q->lock, flags); } @@ -161,7 +165,12 @@ prepare_to_wait_exclusive(wait_queue_hea spin_lock_irqsave(&q->lock, flags); if (list_empty(&wait->task_list)) __add_wait_queue_tail(q, wait); - set_current_state(state); + /* + * don't alter the task state if this is just going to + * queue an async wait queue callback + */ + if (is_sync_wait(wait)) + set_current_state(state); spin_unlock_irqrestore(&q->lock, flags); } @@ -316,9 +325,9 @@ static inline int dup_mmap(struct mm_str atomic_dec(&inode->i_writecount); /* insert tmp into the share list, just after mpnt */ - down(&inode->i_mapping->i_shared_sem); + down(&file->f_mapping->i_shared_sem); list_add_tail(&tmp->shared, &mpnt->shared); - up(&inode->i_mapping->i_shared_sem); + up(&file->f_mapping->i_shared_sem); } /* @@ -910,15 +919,7 @@ struct task_struct *copy_process(unsigne if (p->binfmt && !try_module_get(p->binfmt->module)) goto bad_fork_cleanup_put_domain; -#ifdef CONFIG_PREEMPT - /* - * schedule_tail drops this_rq()->lock so we compensate with a count - * of 1. Also, we want to start with kernel preemption disabled. - */ - p->thread_info->preempt_count = 1; -#endif p->did_exec = 0; - p->state = TASK_UNINTERRUPTIBLE; copy_flags(clone_flags, p); if (clone_flags & CLONE_IDLETASK) @@ -935,15 +936,12 @@ struct task_struct *copy_process(unsigne p->proc_dentry = NULL; - INIT_LIST_HEAD(&p->run_list); - INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); INIT_LIST_HEAD(&p->posix_timers); init_waitqueue_head(&p->wait_chldexit); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); - spin_lock_init(&p->switch_lock); spin_lock_init(&p->proc_lock); clear_tsk_thread_flag(p, TIF_SIGPENDING); @@ -958,11 +956,11 @@ struct task_struct *copy_process(unsigne p->tty_old_pgrp = 0; p->utime = p->stime = 0; p->cutime = p->cstime = 0; - p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ p->start_time = get_jiffies_64(); p->security = NULL; p->io_context = NULL; + p->io_wait = NULL; retval = -ENOMEM; if ((retval = security_task_alloc(p))) @@ -1007,38 +1005,12 @@ struct task_struct *copy_process(unsigne p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); p->pdeath_signal = 0; + /* Perform scheduler related setup */ + sched_fork(p); + /* - * Share the timeslice between parent and child, thus the - * total amount of pending timeslices in the system doesn't change, - * resulting in more scheduling fairness. - */ - local_irq_disable(); - p->time_slice = (current->time_slice + 1) >> 1; - /* - * The remainder of the first timeslice might be recovered by - * the parent if the child exits early enough. - */ - p->first_time_slice = 1; - current->time_slice >>= 1; - p->timestamp = sched_clock(); - if (!current->time_slice) { - /* - * This case is rare, it happens when the parent has only - * a single jiffy left from its timeslice. Taking the - * runqueue lock is not a problem. - */ - current->time_slice = 1; - preempt_disable(); - scheduler_tick(0, 0); - local_irq_enable(); - preempt_enable(); - } else - local_irq_enable(); - /* - * Ok, add it to the run-queues and make it - * visible to the rest of the system. - * - * Let it rip! + * Ok, make it visible to the rest of the system. + * We dont wake it up yet. */ p->tgid = p->pid; p->group_leader = p; --- linux-2.6.1-rc1/kernel/futex.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/kernel/futex.c 2003-12-30 22:49:34.000000000 -0800 @@ -577,6 +577,7 @@ static int futex_fd(unsigned long uaddr, filp->f_op = &futex_fops; filp->f_vfsmnt = mntget(futex_mnt); filp->f_dentry = dget(futex_mnt->mnt_root); + filp->f_mapping = filp->f_dentry->d_inode->i_mapping; if (signal) { int err; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/kernel/lockmeter.c 2003-12-30 22:50:17.000000000 -0800 @@ -0,0 +1,1178 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.c by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks + * Added support for hold time statistics for read and write + * locks. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ASSERT(cond) +#define bzero(loc,size) memset(loc,0,size) + +/*<---------------------------------------------------*/ +/* lockmeter.c */ +/*>---------------------------------------------------*/ + +static lstat_control_t lstat_control __cacheline_aligned = + { LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, + 19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 }; + +static ushort lstat_make_dir_entry(void *, void *); + +/* + * lstat_lookup + * + * Given a RA, locate the directory entry for the lock. + */ +static ushort +lstat_lookup(void *lock_ptr, void *caller_ra) +{ + ushort index; + lstat_directory_entry_t *dirp; + + dirp = lstat_control.dir; + + index = lstat_control.hashtab[DIRHASH(caller_ra)]; + while (dirp[index].caller_ra != caller_ra) { + if (index == 0) { + return lstat_make_dir_entry(lock_ptr, caller_ra); + } + index = dirp[index].next_stat_index; + } + + if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) { + dirp[index].lock_ptr = NULL; + } + + return index; +} + +/* + * lstat_make_dir_entry + * Called to add a new lock to the lock directory. + */ +static ushort +lstat_make_dir_entry(void *lock_ptr, void *caller_ra) +{ + lstat_directory_entry_t *dirp; + ushort index, hindex; + unsigned long flags; + + /* lock the table without recursively reentering this metering code */ + local_irq_save(flags); + _raw_spin_lock(&lstat_control.directory_lock); + + hindex = DIRHASH(caller_ra); + index = lstat_control.hashtab[hindex]; + dirp = lstat_control.dir; + while (index && dirp[index].caller_ra != caller_ra) + index = dirp[index].next_stat_index; + + if (index == 0) { + if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) { + index = lstat_control.next_free_dir_index++; + lstat_control.dir[index].caller_ra = caller_ra; + lstat_control.dir[index].lock_ptr = lock_ptr; + lstat_control.dir[index].next_stat_index = + lstat_control.hashtab[hindex]; + lstat_control.hashtab[hindex] = index; + } else { + lstat_control.dir_overflow++; + } + } + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); + return index; +} + +int +lstat_update(void *lock_ptr, void *caller_ra, int action) +{ + int index; + int cpu; + + ASSERT(action < LSTAT_ACT_MAX_VALUES); + + if (lstat_control.state == LSTAT_OFF) + return 0; + + index = lstat_lookup(lock_ptr, caller_ra); + cpu = THIS_CPU_NUMBER; + (*lstat_control.counts[cpu])[index].count[action]++; + (*lstat_control.counts[cpu])[index].acquire_time = get_cycles(); + + return index; +} + +int +lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks) +{ + ushort index; + int cpu; + + ASSERT(action < LSTAT_ACT_MAX_VALUES); + + if (lstat_control.state == LSTAT_OFF) + return 0; + + index = lstat_lookup(lock_ptr, caller_ra); + cpu = THIS_CPU_NUMBER; + (*lstat_control.counts[cpu])[index].count[action]++; + (*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks; + if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks) + (*lstat_control.counts[cpu])[index].max_wait_ticks = ticks; + + (*lstat_control.counts[cpu])[index].acquire_time = get_cycles(); + + return index; +} + +void +_metered_spin_lock(spinlock_t * lock_ptr) +{ + if (lstat_control.state == LSTAT_OFF) { + _raw_spin_lock(lock_ptr); /* do the real lock */ + PUT_INDEX(lock_ptr, 0); /* clean index in case lockmetering */ + /* gets turned on before unlock */ + } else { + void *this_pc = LSTAT_RA(LSTAT_RA_SPIN); + int index; + + if (_raw_spin_trylock(lock_ptr)) { + index = lstat_update(lock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + } else { + uint32_t start_cycles = get_cycles(); + _raw_spin_lock(lock_ptr); /* do the real lock */ + index = lstat_update_time(lock_ptr, this_pc, + LSTAT_ACT_SPIN, get_cycles() - start_cycles); + } + /* save the index in the lock itself for use in spin unlock */ + PUT_INDEX(lock_ptr, index); + } +} + +int +_metered_spin_trylock(spinlock_t * lock_ptr) +{ + if (lstat_control.state == LSTAT_OFF) { + return _raw_spin_trylock(lock_ptr); + } else { + int retval; + void *this_pc = LSTAT_RA(LSTAT_RA_SPIN); + + if ((retval = _raw_spin_trylock(lock_ptr))) { + int index = lstat_update(lock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* + * save the index in the lock itself for use in spin + * unlock + */ + PUT_INDEX(lock_ptr, index); + } else { + lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT); + } + + return retval; + } +} + +void +_metered_spin_unlock(spinlock_t * lock_ptr) +{ + int index = -1; + + if (lstat_control.state != LSTAT_OFF) { + index = GET_INDEX(lock_ptr); + /* + * If statistics were turned off when we set the lock, + * then the index can be zero. If that is the case, + * then collect no stats on this call. + */ + if (index > 0) { + uint32_t hold_time; + int cpu = THIS_CPU_NUMBER; + hold_time = get_cycles() - + (*lstat_control.counts[cpu])[index].acquire_time; + (*lstat_control.counts[cpu])[index].cum_hold_ticks += + (uint64_t) hold_time; + if ((*lstat_control.counts[cpu])[index].max_hold_ticks < + hold_time) + (*lstat_control.counts[cpu])[index]. + max_hold_ticks = hold_time; + } + } + + /* make sure we don't have a stale index value saved */ + PUT_INDEX(lock_ptr, 0); + _raw_spin_unlock(lock_ptr); /* do the real unlock */ +} + +/* + * allocate the next global read lock structure and store its index + * in the rwlock at "lock_ptr". + */ +uint32_t +alloc_rwlock_struct(rwlock_t * rwlock_ptr) +{ + int index; + unsigned long flags; + int cpu = THIS_CPU_NUMBER; + + /* If we've already overflowed, then do a quick exit */ + if (lstat_control.next_free_read_lock_index > + LSTAT_MAX_READ_LOCK_INDEX) { + lstat_control.rwlock_overflow++; + return 0; + } + + local_irq_save(flags); + _raw_spin_lock(&lstat_control.directory_lock); + + /* It is possible this changed while we were waiting for the directory_lock */ + if (lstat_control.state == LSTAT_OFF) { + index = 0; + goto unlock; + } + + /* It is possible someone else got here first and set the index */ + if ((index = GET_RWINDEX(rwlock_ptr)) == 0) { + /* + * we can't turn on read stats for this lock while there are + * readers (this would mess up the running hold time sum at + * unlock time) + */ + if (RWLOCK_READERS(rwlock_ptr) != 0) { + index = 0; + goto unlock; + } + + /* + * if stats are turned on after being off, we may need to + * return an old index from when the statistics were on last + * time. + */ + for (index = 1; index < lstat_control.next_free_read_lock_index; + index++) + if ((*lstat_control.read_lock_counts[cpu])[index]. + lock_ptr == rwlock_ptr) + goto put_index_and_unlock; + + /* allocate the next global read lock structure */ + if (lstat_control.next_free_read_lock_index >= + LSTAT_MAX_READ_LOCK_INDEX) { + lstat_control.rwlock_overflow++; + index = 0; + goto unlock; + } + index = lstat_control.next_free_read_lock_index++; + + /* + * initialize the global read stats data structure for each + * cpu + */ + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + (*lstat_control.read_lock_counts[cpu])[index].lock_ptr = + rwlock_ptr; + } +put_index_and_unlock: + /* store the index for the read lock structure into the lock */ + PUT_RWINDEX(rwlock_ptr, index); + } + +unlock: + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); + return index; +} + +void +_metered_read_lock(rwlock_t * rwlock_ptr) +{ + void *this_pc; + uint32_t start_cycles; + int index; + int cpu; + unsigned long flags; + int readers_before, readers_after; + uint64_t cycles64; + + if (lstat_control.state == LSTAT_OFF) { + _raw_read_lock(rwlock_ptr); + /* clean index in case lockmetering turns on before an unlock */ + PUT_RWINDEX(rwlock_ptr, 0); + return; + } + + this_pc = LSTAT_RA(LSTAT_RA_READ); + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* allocate the global stats entry for this lock, if needed */ + if (index == 0) + index = alloc_rwlock_struct(rwlock_ptr); + + readers_before = RWLOCK_READERS(rwlock_ptr); + if (_raw_read_trylock(rwlock_ptr)) { + /* + * We have decremented the lock to count a new reader, + * and have confirmed that no writer has it locked. + */ + /* update statistics if enabled */ + if (index > 0) { + local_irq_save(flags); + lstat_update((void *) rwlock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* preserve value of TSC so cum_hold_ticks and start_busy use same value */ + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index]. + cum_hold_ticks -= cycles64; + + /* record time and cpu of start of busy period */ + /* this is not perfect (some race conditions are possible) */ + if (readers_before == 0) { + (*lstat_control.read_lock_counts[cpu])[index]. + start_busy = cycles64; + PUT_RW_CPU(rwlock_ptr, cpu); + } + readers_after = RWLOCK_READERS(rwlock_ptr); + if (readers_after > + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers) + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers = readers_after; + local_irq_restore(flags); + } + + return; + } + /* If we get here, then we could not quickly grab the read lock */ + + start_cycles = get_cycles(); /* start counting the wait time */ + + /* Now spin until read_lock is successful */ + _raw_read_lock(rwlock_ptr); + + lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN, + get_cycles() - start_cycles); + + /* update statistics if they are enabled for this lock */ + if (index > 0) { + local_irq_save(flags); + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -= + cycles64; + + /* this is not perfect (some race conditions are possible) */ + if (readers_before == 0) { + (*lstat_control.read_lock_counts[cpu])[index]. + start_busy = cycles64; + PUT_RW_CPU(rwlock_ptr, cpu); + } + readers_after = RWLOCK_READERS(rwlock_ptr); + if (readers_after > + (*lstat_control.read_lock_counts[cpu])[index].max_readers) + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers = readers_after; + local_irq_restore(flags); + } +} + +void +_metered_read_unlock(rwlock_t * rwlock_ptr) +{ + int index; + int cpu; + unsigned long flags; + uint64_t busy_length; + uint64_t cycles64; + + if (lstat_control.state == LSTAT_OFF) { + _raw_read_unlock(rwlock_ptr); + return; + } + + index = GET_RWINDEX(rwlock_ptr); + cpu = THIS_CPU_NUMBER; + + if (index > 0) { + local_irq_save(flags); + /* + * preserve value of TSC so cum_hold_ticks and busy_ticks are + * consistent. + */ + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks += + cycles64; + (*lstat_control.read_lock_counts[cpu])[index].read_lock_count++; + + /* + * once again, this is not perfect (some race conditions are + * possible) + */ + if (RWLOCK_READERS(rwlock_ptr) == 1) { + int cpu1 = GET_RW_CPU(rwlock_ptr); + uint64_t last_start_busy = + (*lstat_control.read_lock_counts[cpu1])[index]. + start_busy; + (*lstat_control.read_lock_counts[cpu])[index]. + busy_periods++; + if (cycles64 > last_start_busy) { + busy_length = cycles64 - last_start_busy; + (*lstat_control.read_lock_counts[cpu])[index]. + busy_ticks += busy_length; + if (busy_length > + (*lstat_control. + read_lock_counts[cpu])[index]. + max_busy) + (*lstat_control. + read_lock_counts[cpu])[index]. + max_busy = busy_length; + } + } + local_irq_restore(flags); + } + _raw_read_unlock(rwlock_ptr); +} + +void +_metered_write_lock(rwlock_t * rwlock_ptr) +{ + uint32_t start_cycles; + void *this_pc; + uint32_t spin_ticks = 0; /* in anticipation of a potential wait */ + int index; + int write_index = 0; + int cpu; + enum { + writer_writer_conflict, + writer_reader_conflict + } why_wait = writer_writer_conflict; + + if (lstat_control.state == LSTAT_OFF) { + _raw_write_lock(rwlock_ptr); + /* clean index in case lockmetering turns on before an unlock */ + PUT_RWINDEX(rwlock_ptr, 0); + return; + } + + this_pc = LSTAT_RA(LSTAT_RA_WRITE); + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* allocate the global stats entry for this lock, if needed */ + if (index == 0) { + index = alloc_rwlock_struct(rwlock_ptr); + } + + if (_raw_write_trylock(rwlock_ptr)) { + /* We acquired the lock on the first try */ + write_index = lstat_update((void *) rwlock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* save the write_index for use in unlock if stats enabled */ + if (index > 0) + (*lstat_control.read_lock_counts[cpu])[index]. + write_index = write_index; + return; + } + + /* If we get here, then we could not quickly grab the write lock */ + start_cycles = get_cycles(); /* start counting the wait time */ + + why_wait = RWLOCK_READERS(rwlock_ptr) ? + writer_reader_conflict : writer_writer_conflict; + + /* Now set the lock and wait for conflicts to disappear */ + _raw_write_lock(rwlock_ptr); + + spin_ticks = get_cycles() - start_cycles; + + /* update stats -- if enabled */ + if (index > 0 && spin_ticks) { + if (why_wait == writer_reader_conflict) { + /* waited due to a reader holding the lock */ + write_index = lstat_update_time((void *)rwlock_ptr, + this_pc, LSTAT_ACT_SPIN, spin_ticks); + } else { + /* + * waited due to another writer holding the lock + */ + write_index = lstat_update_time((void *)rwlock_ptr, + this_pc, LSTAT_ACT_WW_SPIN, spin_ticks); + (*lstat_control.counts[cpu])[write_index]. + cum_wait_ww_ticks += spin_ticks; + if (spin_ticks > + (*lstat_control.counts[cpu])[write_index]. + max_wait_ww_ticks) { + (*lstat_control.counts[cpu])[write_index]. + max_wait_ww_ticks = spin_ticks; + } + } + + /* save the directory index for use on write_unlock */ + (*lstat_control.read_lock_counts[cpu])[index]. + write_index = write_index; + } +} + +void +_metered_write_unlock(rwlock_t * rwlock_ptr) +{ + int index; + int cpu; + int write_index; + uint32_t hold_time; + + if (lstat_control.state == LSTAT_OFF) { + _raw_write_unlock(rwlock_ptr); + return; + } + + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* update statistics if stats enabled for this lock */ + if (index > 0) { + write_index = + (*lstat_control.read_lock_counts[cpu])[index].write_index; + + hold_time = get_cycles() - + (*lstat_control.counts[cpu])[write_index].acquire_time; + (*lstat_control.counts[cpu])[write_index].cum_hold_ticks += + (uint64_t) hold_time; + if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks < + hold_time) + (*lstat_control.counts[cpu])[write_index]. + max_hold_ticks = hold_time; + } + _raw_write_unlock(rwlock_ptr); +} + +int +_metered_write_trylock(rwlock_t * rwlock_ptr) +{ + int retval; + void *this_pc = LSTAT_RA(LSTAT_RA_WRITE); + + if ((retval = _raw_write_trylock(rwlock_ptr))) { + lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT); + } else { + lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT); + } + + return retval; +} + +static void +init_control_space(void) +{ + /* Set all control space pointers to null and indices to "empty" */ + int cpu; + + /* + * Access CPU_CYCLE_FREQUENCY at the outset, which in some + * architectures may trigger a runtime calculation that uses a + * spinlock. Let's do this before lockmetering is turned on. + */ + if (CPU_CYCLE_FREQUENCY == 0) + BUG(); + + lstat_control.hashtab = NULL; + lstat_control.dir = NULL; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + lstat_control.counts[cpu] = NULL; + lstat_control.read_lock_counts[cpu] = NULL; + } +} + +static int +reset_lstat_data(void) +{ + int cpu, flags; + + flags = 0; + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + lstat_control.next_free_read_lock_index = 1; + lstat_control.dir_overflow = 0; + lstat_control.rwlock_overflow = 0; + + lstat_control.started_cycles64 = 0; + lstat_control.ending_cycles64 = 0; + lstat_control.enabled_cycles64 = 0; + lstat_control.first_started_time = 0; + lstat_control.started_time = 0; + lstat_control.ending_time = 0; + lstat_control.intervals = 0; + + /* + * paranoia -- in case someone does a "lockstat reset" before + * "lockstat on" + */ + if (lstat_control.hashtab) { + bzero(lstat_control.hashtab, + LSTAT_HASH_TABLE_SIZE * sizeof (short)); + bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t)); + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + bzero(lstat_control.counts[cpu], + sizeof (lstat_cpu_counts_t)); + bzero(lstat_control.read_lock_counts[cpu], + sizeof (lstat_read_lock_cpu_counts_t)); + } + } +#ifdef NOTDEF + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); +#endif + return 1; +} + +static void +release_control_space(void) +{ + /* + * Called when either (1) allocation of kmem + * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter. + * Assume that all pointers have been initialized to zero, + * i.e., nonzero pointers are valid addresses. + */ + int cpu; + + if (lstat_control.hashtab) { + kfree(lstat_control.hashtab); + lstat_control.hashtab = NULL; + } + + if (lstat_control.dir) { + vfree(lstat_control.dir); + lstat_control.dir = NULL; + } + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (lstat_control.counts[cpu]) { + vfree(lstat_control.counts[cpu]); + lstat_control.counts[cpu] = NULL; + } + if (lstat_control.read_lock_counts[cpu]) { + kfree(lstat_control.read_lock_counts[cpu]); + lstat_control.read_lock_counts[cpu] = NULL; + } + } +} + +int +get_lockmeter_info_size(void) +{ + return sizeof (lstat_user_request_t) + + num_online_cpus() * sizeof (lstat_cpu_counts_t) + + num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t) + + (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t)); +} + +ssize_t +get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index) +{ + lstat_user_request_t req; + struct timeval tv; + ssize_t next_ret_bcount; + ssize_t actual_ret_bcount = 0; + int cpu; + + *last_index = 0; /* a one-shot read */ + + req.lstat_version = LSTAT_VERSION; + req.state = lstat_control.state; + req.maxcpus = num_online_cpus(); + req.cycleval = CPU_CYCLE_FREQUENCY; +#ifdef notyet + req.kernel_magic_addr = (void *) &_etext; + req.kernel_end_addr = (void *) &_etext; +#endif + req.uts = system_utsname; + req.intervals = lstat_control.intervals; + + req.first_started_time = lstat_control.first_started_time; + req.started_time = lstat_control.started_time; + req.started_cycles64 = lstat_control.started_cycles64; + + req.next_free_dir_index = lstat_control.next_free_dir_index; + req.next_free_read_lock_index = lstat_control.next_free_read_lock_index; + req.dir_overflow = lstat_control.dir_overflow; + req.rwlock_overflow = lstat_control.rwlock_overflow; + + if (lstat_control.state == LSTAT_OFF) { + if (req.intervals == 0) { + /* mesasurement is off and no valid data present */ + next_ret_bcount = sizeof (lstat_user_request_t); + req.enabled_cycles64 = 0; + + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; + + copy_to_user(buffer, (void *) &req, next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + return actual_ret_bcount; + } else { + /* + * measurement is off but valid data present + * fetch time info from lstat_control + */ + req.ending_time = lstat_control.ending_time; + req.ending_cycles64 = lstat_control.ending_cycles64; + req.enabled_cycles64 = lstat_control.enabled_cycles64; + } + } else { + /* + * this must be a read while data active--use current time, + * etc + */ + do_gettimeofday(&tv); + req.ending_time = tv.tv_sec; + req.ending_cycles64 = get_cycles64(); + req.enabled_cycles64 = req.ending_cycles64 - + req.started_cycles64 + lstat_control.enabled_cycles64; + } + + next_ret_bcount = sizeof (lstat_user_request_t); + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; + + copy_to_user(buffer, (void *) &req, next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + + if (!lstat_control.counts[0]) /* not initialized? */ + return actual_ret_bcount; + + next_ret_bcount = sizeof (lstat_cpu_counts_t); + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; /* leave early */ + copy_to_user(buffer + actual_ret_bcount, + lstat_control.counts[cpu], next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + } + + next_ret_bcount = LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t); + if (((actual_ret_bcount + next_ret_bcount) > max_len) + || !lstat_control.dir) + return actual_ret_bcount; /* leave early */ + + copy_to_user(buffer + actual_ret_bcount, lstat_control.dir, + next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + + next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t); + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + if (actual_ret_bcount + next_ret_bcount > max_len) + return actual_ret_bcount; + copy_to_user(buffer + actual_ret_bcount, + lstat_control.read_lock_counts[cpu], + next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + } + + return actual_ret_bcount; +} + +/* + * Writing to the /proc lockmeter node enables or disables metering. + * based upon the first byte of the "written" data. + * The following values are defined: + * LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement + * subsequent calls just turn on measurement + * LSTAT_OFF: turns off measurement + * LSTAT_RESET: resets statistics + * LSTAT_RELEASE: releases statistics storage + * + * This allows one to accumulate statistics over several lockstat runs: + * + * lockstat on + * lockstat off + * ...repeat above as desired... + * lockstat get + * ...now start a new set of measurements... + * lockstat reset + * lockstat on + * ... + * + */ +ssize_t +put_lockmeter_info(const char *buffer, size_t len) +{ + int error = 0; + int dirsize, countsize, read_lock_countsize, hashsize; + int cpu; + char put_char; + int i, read_lock_blocks; + unsigned long flags; + rwlock_t *lock_ptr; + struct timeval tv; + + if (len <= 0) + return -EINVAL; + + _raw_spin_lock(&lstat_control.control_lock); + + get_user(put_char, buffer); + switch (put_char) { + + case LSTAT_OFF: + if (lstat_control.state != LSTAT_OFF) { + /* + * To avoid seeing read lock hold times in an + * inconsisent state, we have to follow this protocol + * to turn off statistics + */ + local_irq_save(flags); + /* + * getting this lock will stop any read lock block + * allocations + */ + _raw_spin_lock(&lstat_control.directory_lock); + /* + * keep any more read lock blocks from being + * allocated + */ + lstat_control.state = LSTAT_OFF; + /* record how may read lock blocks there are */ + read_lock_blocks = + lstat_control.next_free_read_lock_index; + _raw_spin_unlock(&lstat_control.directory_lock); + /* now go through the list of read locks */ + cpu = THIS_CPU_NUMBER; + for (i = 1; i < read_lock_blocks; i++) { + lock_ptr = + (*lstat_control.read_lock_counts[cpu])[i]. + lock_ptr; + /* is this saved lock address still valid? */ + if (GET_RWINDEX(lock_ptr) == i) { + /* + * lock address appears to still be + * valid because we only hold one lock + * at a time, this can't cause a + * deadlock unless this is a lock held + * as part of the current system call + * path. At the moment there + * are no READ mode locks held to get + * here from user space, so we solve + * this by skipping locks held in + * write mode. + */ + if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) { + PUT_RWINDEX(lock_ptr, 0); + continue; + } + /* + * now we know there are no read + * holders of this lock! stop + * statistics collection for this + * lock + */ + _raw_write_lock(lock_ptr); + PUT_RWINDEX(lock_ptr, 0); + _raw_write_unlock(lock_ptr); + } + /* + * it may still be possible for the hold time + * sum to be negative e.g. if a lock is + * reallocated while "busy" we will have to fix + * this up in the data reduction program. + */ + } + local_irq_restore(flags); + lstat_control.intervals++; + lstat_control.ending_cycles64 = get_cycles64(); + lstat_control.enabled_cycles64 += + lstat_control.ending_cycles64 - + lstat_control.started_cycles64; + do_gettimeofday(&tv); + lstat_control.ending_time = tv.tv_sec; + /* + * don't deallocate the structures -- we may do a + * lockstat on to add to the data that is already + * there. Use LSTAT_RELEASE to release storage + */ + } else { + error = -EBUSY; /* already OFF */ + } + break; + + case LSTAT_ON: + if (lstat_control.state == LSTAT_OFF) { +#ifdef DEBUG_LOCKMETER + printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n", + THIS_CPU_NUMBER); +#endif + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + + dirsize = LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t); + hashsize = + (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort); + countsize = sizeof (lstat_cpu_counts_t); + read_lock_countsize = + sizeof (lstat_read_lock_cpu_counts_t); +#ifdef DEBUG_LOCKMETER + printk(" dirsize:%d", dirsize); + printk(" hashsize:%d", hashsize); + printk(" countsize:%d", countsize); + printk(" read_lock_countsize:%d\n", + read_lock_countsize); +#endif +#ifdef DEBUG_LOCKMETER + { + int secs; + unsigned long cycles; + uint64_t cycles64; + + do_gettimeofday(&tv); + secs = tv.tv_sec; + do { + do_gettimeofday(&tv); + } while (secs == tv.tv_sec); + cycles = get_cycles(); + cycles64 = get_cycles64(); + secs = tv.tv_sec; + do { + do_gettimeofday(&tv); + } while (secs == tv.tv_sec); + cycles = get_cycles() - cycles; + cycles64 = get_cycles64() - cycles; + printk("lockmeter: cycleFrequency:%d " + "cycles:%d cycles64:%d\n", + CPU_CYCLE_FREQUENCY, cycles, cycles64); + } +#endif + + /* + * if this is the first call, allocate storage and + * initialize + */ + if (!lstat_control.hashtab) { + + spin_lock_init(&lstat_control.directory_lock); + + /* guarantee all pointers at zero */ + init_control_space(); + + lstat_control.hashtab = + kmalloc(hashsize, GFP_KERNEL); + if (!lstat_control.hashtab) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of hashtab\n"); +#endif + } + lstat_control.dir = vmalloc(dirsize); + if (!lstat_control.dir) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of dir\n"); +#endif + } + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + lstat_control.counts[cpu] = + vmalloc(countsize); + if (!lstat_control.counts[cpu]) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error vmalloc of " + "counts[%d]\n", cpu); +#endif + } + lstat_control.read_lock_counts[cpu] = + (lstat_read_lock_cpu_counts_t *) + kmalloc(read_lock_countsize, + GFP_KERNEL); + if (!lstat_control. + read_lock_counts[cpu]) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of " + "read_lock_counts[%d]\n", + cpu); +#endif + } + } + } + + if (error) { + /* + * One or more kmalloc failures -- free + * everything + */ + release_control_space(); + } else { + + if (!reset_lstat_data()) { + error = -EINVAL; + break; + }; + + /* + * record starting and ending times and the + * like + */ + if (lstat_control.intervals == 0) { + do_gettimeofday(&tv); + lstat_control.first_started_time = + tv.tv_sec; + } + lstat_control.started_cycles64 = get_cycles64(); + do_gettimeofday(&tv); + lstat_control.started_time = tv.tv_sec; + + lstat_control.state = LSTAT_ON; + } + } else { + error = -EBUSY; /* already ON */ + } + break; + + case LSTAT_RESET: + if (lstat_control.state == LSTAT_OFF) { + if (!reset_lstat_data()) + error = -EINVAL; + } else { + error = -EBUSY; /* still on; can't reset */ + } + break; + + case LSTAT_RELEASE: + if (lstat_control.state == LSTAT_OFF) { + release_control_space(); + lstat_control.intervals = 0; + lstat_control.enabled_cycles64 = 0; + } else { + error = -EBUSY; + } + break; + + default: + error = -EINVAL; + } /* switch */ + + _raw_spin_unlock(&lstat_control.control_lock); + return error ? error : len; +} + +#ifdef USER_MODE_TESTING +/* following used for user mode testing */ +void +lockmeter_init() +{ + int dirsize, hashsize, countsize, read_lock_countsize, cpu; + + printf("lstat_control is at %x size=%d\n", &lstat_control, + sizeof (lstat_control)); + printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t)); + lstat_control.state = LSTAT_ON; + + lstat_control.directory_lock = SPIN_LOCK_UNLOCKED; + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + lstat_control.next_free_read_lock_index = 1; + + dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t); + hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort); + countsize = sizeof (lstat_cpu_counts_t); + read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t); + + lstat_control.hashtab = (ushort *) malloc(hashsize); + + if (lstat_control.hashtab == 0) { + printf("malloc failure for at line %d in lockmeter.c\n", + __LINE__); + exit(0); + } + + lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize); + + if (lstat_control.dir == 0) { + printf("malloc failure for at line %d in lockmeter.c\n", cpu, + __LINE__); + exit(0); + } + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + int j, k; + j = (int) (lstat_control.counts[cpu] = + (lstat_cpu_counts_t *) malloc(countsize)); + k = (int) (lstat_control.read_lock_counts[cpu] = + (lstat_read_lock_cpu_counts_t *) + malloc(read_lock_countsize)); + if (j * k == 0) { + printf("malloc failure for cpu=%d at line %d in " + "lockmeter.c\n", cpu, __LINE__); + exit(0); + } + } + + memset(lstat_control.hashtab, 0, hashsize); + memset(lstat_control.dir, 0, dirsize); + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + memset(lstat_control.counts[cpu], 0, countsize); + memset(lstat_control.read_lock_counts[cpu], 0, + read_lock_countsize); + } +} + +asm(" \ +.align 4 \ +.globl __write_lock_failed \ +__write_lock_failed: \ + " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) \ +1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) \ + jne 1b \ +\ + " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) \ + jnz __write_lock_failed \ + ret \ +\ +\ +.align 4 \ +.globl __read_lock_failed \ +__read_lock_failed: \ + lock ; incl (%eax) \ +1: cmpl $1,(%eax) \ + js 1b \ +\ + lock ; decl (%eax) \ + js __read_lock_failed \ + ret \ +"); +#endif + +EXPORT_SYMBOL(_metered_spin_lock); +EXPORT_SYMBOL(_metered_spin_unlock); +EXPORT_SYMBOL(_metered_spin_trylock); +EXPORT_SYMBOL(_metered_read_lock); +EXPORT_SYMBOL(_metered_read_unlock); +EXPORT_SYMBOL(_metered_write_lock); +EXPORT_SYMBOL(_metered_write_unlock); --- linux-2.6.1-rc1/kernel/Makefile 2003-11-09 16:45:05.000000000 -0800 +++ 25/kernel/Makefile 2003-12-30 22:50:17.000000000 -0800 @@ -11,6 +11,7 @@ obj-y = sched.o fork.o exec_domain.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o +obj-$(CONFIG_LOCKMETER) += lockmeter.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o --- linux-2.6.1-rc1/kernel/pid.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/kernel/pid.c 2003-12-30 22:49:25.000000000 -0800 @@ -268,6 +268,9 @@ void switch_exec_pids(task_t *leader, ta * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or * more. */ +#ifdef CONFIG_KGDB +int kgdb_pid_init_done; /* so we don't call prior to... */ +#endif void __init pidhash_init(void) { int i, j, pidhash_size; @@ -289,6 +292,9 @@ void __init pidhash_init(void) for (j = 0; j < pidhash_size; j++) INIT_LIST_HEAD(&pid_hash[i][j]); } +#ifdef CONFIG_KGDB + kgdb_pid_init_done++; +#endif } void __init pidmap_init(void) --- linux-2.6.1-rc1/kernel/printk.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/kernel/printk.c 2003-12-30 22:50:17.000000000 -0800 @@ -479,9 +479,13 @@ asmlinkage int printk(const char *fmt, . char *p; static char printk_buf[1024]; static int log_level_unknown = 1; + static int printk_cpu = -1; - if (oops_in_progress) { - /* If a crash is occurring, make sure we can't deadlock */ + if (oops_in_progress && printk_cpu == smp_processor_id()) { + /* + * If a crash is occurring during printk() on this CPU, make + * sure we can't deadlock + */ spin_lock_init(&logbuf_lock); /* And make sure that we print immediately */ init_MUTEX(&console_sem); @@ -489,6 +493,7 @@ asmlinkage int printk(const char *fmt, . /* This stops the holder of console_sem just where we want him */ spin_lock_irqsave(&logbuf_lock, flags); + printk_cpu = smp_processor_id(); /* Emit the output into the temporary buffer */ va_start(args, fmt); --- linux-2.6.1-rc1/kernel/sched.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/kernel/sched.c 2003-12-30 22:50:16.000000000 -0800 @@ -79,13 +79,13 @@ */ #define MIN_TIMESLICE ( 10 * HZ / 1000) #define MAX_TIMESLICE (200 * HZ / 1000) -#define ON_RUNQUEUE_WEIGHT 30 -#define CHILD_PENALTY 95 +#define ON_RUNQUEUE_WEIGHT 30 +#define CHILD_PENALTY 95 #define PARENT_PENALTY 100 -#define EXIT_WEIGHT 3 -#define PRIO_BONUS_RATIO 25 +#define EXIT_WEIGHT 3 +#define PRIO_BONUS_RATIO 25 #define MAX_BONUS (MAX_USER_PRIO * PRIO_BONUS_RATIO / 100) -#define INTERACTIVE_DELTA 2 +#define INTERACTIVE_DELTA 2 #define MAX_SLEEP_AVG (AVG_TIMESLICE * MAX_BONUS) #define STARVATION_LIMIT (MAX_SLEEP_AVG) #define NS_MAX_SLEEP_AVG (JIFFIES_TO_NS(MAX_SLEEP_AVG)) @@ -143,7 +143,7 @@ #define TASK_INTERACTIVE(p) \ ((p)->prio <= (p)->static_prio - DELTA(p)) -#define JUST_INTERACTIVE_SLEEP(p) \ +#define INTERACTIVE_SLEEP(p) \ (JIFFIES_TO_NS(MAX_SLEEP_AVG * \ (MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1)) @@ -168,7 +168,8 @@ */ #define BASE_TIMESLICE(p) (MIN_TIMESLICE + \ - ((MAX_TIMESLICE - MIN_TIMESLICE) * (MAX_PRIO-1-(p)->static_prio)/(MAX_USER_PRIO - 1))) + ((MAX_TIMESLICE - MIN_TIMESLICE) * \ + (MAX_PRIO-1 - (p)->static_prio) / (MAX_USER_PRIO-1))) static inline unsigned int task_timeslice(task_t *p) { @@ -199,11 +200,11 @@ struct prio_array { struct runqueue { spinlock_t lock; unsigned long nr_running, nr_switches, expired_timestamp, - nr_uninterruptible; + nr_uninterruptible, timestamp_last_tick; task_t *curr, *idle; struct mm_struct *prev_mm; prio_array_t *active, *expired, arrays[2]; - int prev_cpu_load[NR_CPUS]; + int best_expired_prio, prev_cpu_load[NR_CPUS]; #ifdef CONFIG_NUMA atomic_t *node_nr_running; int prev_node_load[MAX_NUMNODES]; @@ -225,7 +226,7 @@ static DEFINE_PER_CPU(struct runqueue, r * Default context-switch locking: */ #ifndef prepare_arch_switch -# define prepare_arch_switch(rq, next) do { } while(0) +# define prepare_arch_switch(rq, next) do { } while (0) # define finish_arch_switch(rq, next) spin_unlock_irq(&(rq)->lock) # define task_running(rq, p) ((rq)->curr == (p)) #endif @@ -269,9 +270,9 @@ __init void node_nr_running_init(void) #else /* !CONFIG_NUMA */ -# define nr_running_init(rq) do { } while (0) -# define nr_running_inc(rq) do { (rq)->nr_running++; } while (0) -# define nr_running_dec(rq) do { (rq)->nr_running--; } while (0) +# define nr_running_init(rq) do { } while (0) +# define nr_running_inc(rq) do { (rq)->nr_running++; } while (0) +# define nr_running_dec(rq) do { (rq)->nr_running--; } while (0) #endif /* CONFIG_NUMA */ @@ -396,7 +397,7 @@ static void recalc_task_prio(task_t *p, * other processes. */ if (p->mm && p->activated != -1 && - sleep_time > JUST_INTERACTIVE_SLEEP(p)){ + sleep_time > INTERACTIVE_SLEEP(p)) { p->sleep_avg = JIFFIES_TO_NS(MAX_SLEEP_AVG - AVG_TIMESLICE); if (!HIGH_CREDIT(p)) @@ -413,37 +414,35 @@ static void recalc_task_prio(task_t *p, * one timeslice worth of sleep avg bonus. */ if (LOW_CREDIT(p) && - sleep_time > JIFFIES_TO_NS(task_timeslice(p))) - sleep_time = - JIFFIES_TO_NS(task_timeslice(p)); + sleep_time > JIFFIES_TO_NS(task_timeslice(p))) + sleep_time = JIFFIES_TO_NS(task_timeslice(p)); /* * Non high_credit tasks waking from uninterruptible * sleep are limited in their sleep_avg rise as they * are likely to be cpu hogs waiting on I/O */ - if (p->activated == -1 && !HIGH_CREDIT(p) && p->mm){ - if (p->sleep_avg >= JUST_INTERACTIVE_SLEEP(p)) + if (p->activated == -1 && !HIGH_CREDIT(p) && p->mm) { + if (p->sleep_avg >= INTERACTIVE_SLEEP(p)) sleep_time = 0; else if (p->sleep_avg + sleep_time >= - JUST_INTERACTIVE_SLEEP(p)){ - p->sleep_avg = - JUST_INTERACTIVE_SLEEP(p); - sleep_time = 0; - } + INTERACTIVE_SLEEP(p)) { + p->sleep_avg = INTERACTIVE_SLEEP(p); + sleep_time = 0; + } } /* * This code gives a bonus to interactive tasks. * * The boost works by updating the 'average sleep time' - * value here, based on ->timestamp. The more time a task - * spends sleeping, the higher the average gets - and the - * higher the priority boost gets as well. + * value here, based on ->timestamp. The more time a + * task spends sleeping, the higher the average gets - + * and the higher the priority boost gets as well. */ p->sleep_avg += sleep_time; - if (p->sleep_avg > NS_MAX_SLEEP_AVG){ + if (p->sleep_avg > NS_MAX_SLEEP_AVG) { p->sleep_avg = NS_MAX_SLEEP_AVG; if (!HIGH_CREDIT(p)) p->interactive_credit++; @@ -470,7 +469,7 @@ static inline void activate_task(task_t * This checks to make sure it's not an uninterruptible task * that is now waking up. */ - if (!p->activated){ + if (!p->activated) { /* * Tasks which were woken up by interrupts (ie. hw events) * are most likely of interactive nature. So we give them @@ -480,13 +479,14 @@ static inline void activate_task(task_t */ if (in_interrupt()) p->activated = 2; - else - /* - * Normal first-time wakeups get a credit too for on-runqueue - * time, but it will be weighted down: - */ + else { + /* + * Normal first-time wakeups get a credit too for + * on-runqueue time, but it will be weighted down: + */ p->activated = 1; } + } p->timestamp = now; __activate_task(p, rq); @@ -632,13 +632,14 @@ repeat_lock_task: */ if (unlikely(sync && !task_running(rq, p) && (task_cpu(p) != smp_processor_id()) && - cpu_isset(smp_processor_id(), p->cpus_allowed))) { + cpu_isset(smp_processor_id(), + p->cpus_allowed))) { set_task_cpu(p, smp_processor_id()); task_rq_unlock(rq, &flags); goto repeat_lock_task; } - if (old_state == TASK_UNINTERRUPTIBLE){ + if (old_state == TASK_UNINTERRUPTIBLE) { rq->nr_uninterruptible--; /* * Tasks on involuntary sleep don't earn @@ -663,7 +664,8 @@ repeat_lock_task: } int wake_up_process(task_t * p) { - return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0); + return try_to_wake_up(p, TASK_STOPPED | + TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0); } EXPORT_SYMBOL(wake_up_process); @@ -674,6 +676,54 @@ int wake_up_state(task_t *p, unsigned in } /* + * Perform scheduler related setup for a newly forked process p. + * p is forked by current. + */ +void sched_fork(task_t *p) +{ + p->state = TASK_UNINTERRUPTIBLE; + INIT_LIST_HEAD(&p->run_list); + p->array = NULL; + spin_lock_init(&p->switch_lock); +#ifdef CONFIG_PREEMPT + /* + * During context-switch we hold precisely one spinlock, which + * schedule_tail drops. (in the common case it's this_rq()->lock, + * but it also can be p->switch_lock.) So we compensate with a count + * of 1. Also, we want to start with kernel preemption disabled. + */ + p->thread_info->preempt_count = 1; +#endif + /* + * Share the timeslice between parent and child, thus the + * total amount of pending timeslices in the system doesn't change, + * resulting in more scheduling fairness. + */ + local_irq_disable(); + p->time_slice = (current->time_slice + 1) >> 1; + /* + * The remainder of the first timeslice might be recovered by + * the parent if the child exits early enough. + */ + p->first_time_slice = 1; + current->time_slice >>= 1; + p->timestamp = sched_clock(); + if (!current->time_slice) { + /* + * This case is rare, it happens when the parent has only + * a single jiffy left from its timeslice. Taking the + * runqueue lock is not a problem. + */ + current->time_slice = 1; + preempt_disable(); + scheduler_tick(0, 0); + local_irq_enable(); + preempt_enable(); + } else + local_irq_enable(); +} + +/* * wake_up_forked_process - wake up a freshly forked process. * * This function will do some initial scheduler statistics housekeeping @@ -799,7 +849,8 @@ asmlinkage void schedule_tail(task_t *pr * context_switch - switch to the new MM and the new * thread's register state. */ -static inline task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next) +static inline +task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next) { struct mm_struct *mm = next->mm; struct mm_struct *oldmm = prev->active_mm; @@ -844,11 +895,9 @@ unsigned long nr_uninterruptible(void) { unsigned long i, sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) - continue; + for_each_cpu(i) sum += cpu_rq(i)->nr_uninterruptible; - } + return sum; } @@ -856,11 +905,9 @@ unsigned long nr_context_switches(void) { unsigned long i, sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) - continue; + for_each_cpu(i) sum += cpu_rq(i)->nr_switches; - } + return sum; } @@ -868,11 +915,9 @@ unsigned long nr_iowait(void) { unsigned long i, sum = 0; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_online(i)) - continue; + for_each_cpu(i) sum += atomic_read(&cpu_rq(i)->nr_iowait); - } + return sum; } @@ -947,10 +992,10 @@ static int sched_best_cpu(struct task_st minload = 10000000; for_each_node_with_cpus(i) { /* - * Node load is always divided by nr_cpus_node to normalise + * Node load is always divided by nr_cpus_node to normalise * load values in case cpu count differs from node to node. * We first multiply node_nr_running by 10 to get a little - * better resolution. + * better resolution. */ load = 10 * atomic_read(&node_nr_running[i]) / nr_cpus_node(i); if (load < minload) { @@ -989,7 +1034,7 @@ void sched_balance_exec(void) * load_{t} = load_{t-1}/2 + nr_node_running_{t} * This way sudden load peaks are flattened out a bit. * Node load is divided by nr_cpus_node() in order to compare nodes - * of different cpu count but also [first] multiplied by 10 to + * of different cpu count but also [first] multiplied by 10 to * provide better resolution. */ static int find_busiest_node(int this_node) @@ -1027,8 +1072,10 @@ static int find_busiest_node(int this_no * this_rq is locked already. Recalculate nr_running if we have to * drop the runqueue lock. */ -static inline unsigned int double_lock_balance(runqueue_t *this_rq, - runqueue_t *busiest, int this_cpu, int idle, unsigned int nr_running) +static inline +unsigned int double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest, + int this_cpu, int idle, + unsigned int nr_running) { if (unlikely(!spin_trylock(&busiest->lock))) { if (busiest < this_rq) { @@ -1036,7 +1083,8 @@ static inline unsigned int double_lock_b spin_lock(&busiest->lock); spin_lock(&this_rq->lock); /* Need to recalculate nr_running */ - if (idle || (this_rq->nr_running > this_rq->prev_cpu_load[this_cpu])) + if (idle || (this_rq->nr_running > + this_rq->prev_cpu_load[this_cpu])) nr_running = this_rq->nr_running; else nr_running = this_rq->prev_cpu_load[this_cpu]; @@ -1049,7 +1097,9 @@ static inline unsigned int double_lock_b /* * find_busiest_queue - find the busiest runqueue among the cpus in cpumask. */ -static inline runqueue_t *find_busiest_queue(runqueue_t *this_rq, int this_cpu, int idle, int *imbalance, cpumask_t cpumask) +static inline +runqueue_t *find_busiest_queue(runqueue_t *this_rq, int this_cpu, int idle, + int *imbalance, cpumask_t cpumask) { int nr_running, load, max_load, i; runqueue_t *busiest, *rq_src; @@ -1112,7 +1162,8 @@ static inline runqueue_t *find_busiest_q goto out; } - nr_running = double_lock_balance(this_rq, busiest, this_cpu, idle, nr_running); + nr_running = double_lock_balance(this_rq, busiest, this_cpu, + idle, nr_running); /* * Make sure nothing changed since we checked the * runqueue length. @@ -1129,13 +1180,17 @@ out: * pull_task - move a task from a remote runqueue to the local runqueue. * Both runqueues must be locked. */ -static inline void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p, runqueue_t *this_rq, int this_cpu) +static inline +void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p, + runqueue_t *this_rq, int this_cpu) { dequeue_task(p, src_array); nr_running_dec(src_rq); set_task_cpu(p, this_cpu); nr_running_inc(this_rq); enqueue_task(p, this_rq->active); + p->timestamp = sched_clock() - + (src_rq->timestamp_last_tick - p->timestamp); /* * Note that idle threads have a prio of MAX_PRIO, for this test * to be always true for them. @@ -1145,25 +1200,25 @@ static inline void pull_task(runqueue_t } /* - * Previously: - * - * #define CAN_MIGRATE_TASK(p,rq,this_cpu) \ - * ((!idle || (NS_TO_JIFFIES(now - (p)->timestamp) > \ - * cache_decay_ticks)) && !task_running(rq, p) && \ - * cpu_isset(this_cpu, (p)->cpus_allowed)) + * can_migrate_task - may task p from runqueue rq be migrated to this_cpu? */ - -static inline int -can_migrate_task(task_t *tsk, runqueue_t *rq, int this_cpu, int idle) +static inline +int can_migrate_task(task_t *tsk, runqueue_t *rq, int this_cpu, int idle) { - unsigned long delta = sched_clock() - tsk->timestamp; + unsigned long delta = rq->timestamp_last_tick - tsk->timestamp; - if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks))) - return 0; + /* + * We do not migrate tasks that are: + * 1) running (obviously), or + * 2) cannot be migrated to this CPU due to cpus_allowed, or + * 3) are cache-hot on their current CPU. + */ if (task_running(rq, tsk)) return 0; if (!cpu_isset(this_cpu, tsk->cpus_allowed)) return 0; + if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks))) + return 0; return 1; } @@ -1183,7 +1238,8 @@ static void load_balance(runqueue_t *thi struct list_head *head, *curr; task_t *tmp; - busiest = find_busiest_queue(this_rq, this_cpu, idle, &imbalance, cpumask); + busiest = find_busiest_queue(this_rq, this_cpu, idle, + &imbalance, cpumask); if (!busiest) goto out; @@ -1225,13 +1281,6 @@ skip_bitmap: skip_queue: tmp = list_entry(curr, task_t, run_list); - /* - * We do not migrate tasks that are: - * 1) running (obviously), or - * 2) cannot be migrated to this CPU due to cpus_allowed, or - * 3) are cache-hot on their current CPU. - */ - curr = curr->prev; if (!can_migrate_task(tmp, busiest, this_cpu, idle)) { @@ -1241,6 +1290,8 @@ skip_queue: goto skip_bitmap; } pull_task(busiest, array, tmp, this_rq, this_cpu); + + /* Only migrate one task if we are idle */ if (!idle && --imbalance) { if (curr != head) goto skip_queue; @@ -1330,7 +1381,7 @@ static inline void rebalance_tick(runque } #endif -DEFINE_PER_CPU(struct kernel_stat, kstat) = { { 0 } }; +DEFINE_PER_CPU(struct kernel_stat, kstat); EXPORT_PER_CPU_SYMBOL(kstat); @@ -1341,12 +1392,14 @@ EXPORT_PER_CPU_SYMBOL(kstat); * interactivity of a task if the first expired task had to wait more * than a 'reasonable' amount of time. This deadline timeout is * load-dependent, as the frequency of array switched decreases with - * increasing number of running tasks: + * increasing number of running tasks. We also ignore the interactivity + * if a better static_prio task has expired: */ #define EXPIRED_STARVING(rq) \ - (STARVATION_LIMIT && ((rq)->expired_timestamp && \ + ((STARVATION_LIMIT && ((rq)->expired_timestamp && \ (jiffies - (rq)->expired_timestamp >= \ - STARVATION_LIMIT * ((rq)->nr_running) + 1))) + STARVATION_LIMIT * ((rq)->nr_running) + 1))) || \ + ((rq)->curr->static_prio > (rq)->best_expired_prio)) /* * This function gets called by the timer code, with HZ frequency. @@ -1362,6 +1415,8 @@ void scheduler_tick(int user_ticks, int runqueue_t *rq = this_rq(); task_t *p = current; + rq->timestamp_last_tick = sched_clock(); + if (rcu_pending(cpu)) rcu_check_callbacks(cpu, user_ticks); @@ -1428,6 +1483,8 @@ void scheduler_tick(int user_ticks, int rq->expired_timestamp = jiffies; if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) { enqueue_task(p, rq->expired); + if (p->static_prio < rq->best_expired_prio) + rq->best_expired_prio = p->static_prio; } else enqueue_task(p, rq->active); } else { @@ -1548,6 +1605,7 @@ need_resched: rq->expired = array; array = rq->active; rq->expired_timestamp = 0; + rq->best_expired_prio = MAX_PRIO; } idx = sched_find_first_bit(array->bitmap); @@ -1572,7 +1630,7 @@ switch_tasks: RCU_qsctr(task_cpu(prev))++; prev->sleep_avg -= run_time; - if ((long)prev->sleep_avg <= 0){ + if ((long)prev->sleep_avg <= 0) { prev->sleep_avg = 0; if (!(HIGH_CREDIT(prev) || LOW_CREDIT(prev))) prev->interactive_credit--; @@ -1649,7 +1707,8 @@ EXPORT_SYMBOL(default_wake_function); * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns * zero in this (rare) case, and we handle it by continuing to scan the queue. */ -static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int sync) +static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, + int nr_exclusive, int sync) { struct list_head *tmp, *next; @@ -1726,7 +1785,8 @@ void complete(struct completion *x) spin_lock_irqsave(&x->wait.lock, flags); x->done++; - __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, 0); + __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, + 1, 0); spin_unlock_irqrestore(&x->wait.lock, flags); } @@ -1738,7 +1798,8 @@ void complete_all(struct completion *x) spin_lock_irqsave(&x->wait.lock, flags); x->done += UINT_MAX/2; - __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, 0); + __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, + 0, 0); spin_unlock_irqrestore(&x->wait.lock, flags); } @@ -1765,9 +1826,9 @@ void wait_for_completion(struct completi EXPORT_SYMBOL(wait_for_completion); -#define SLEEP_ON_VAR \ - unsigned long flags; \ - wait_queue_t wait; \ +#define SLEEP_ON_VAR \ + unsigned long flags; \ + wait_queue_t wait; \ init_waitqueue_entry(&wait, current); #define SLEEP_ON_HEAD \ @@ -1775,9 +1836,9 @@ EXPORT_SYMBOL(wait_for_completion); __add_wait_queue(q, &wait); \ spin_unlock(&q->lock); -#define SLEEP_ON_TAIL \ - spin_lock_irq(&q->lock); \ - __remove_wait_queue(q, &wait); \ +#define SLEEP_ON_TAIL \ + spin_lock_irq(&q->lock); \ + __remove_wait_queue(q, &wait); \ spin_unlock_irqrestore(&q->lock, flags); void interruptible_sleep_on(wait_queue_head_t *q) @@ -1887,6 +1948,13 @@ out_unlock: EXPORT_SYMBOL(set_user_nice); +#if defined( CONFIG_KGDB) +struct task_struct * kgdb_get_idle(int this_cpu) +{ + return cpu_rq(this_cpu)->idle; +} +#endif + #ifndef __alpha__ /* @@ -1902,9 +1970,9 @@ asmlinkage long sys_nice(int increment) long nice; /* - * Setpriority might change our priority at the same moment. - * We don't have to worry. Conceptually one call occurs first - * and we have a single winner. + * Setpriority might change our priority at the same moment. + * We don't have to worry. Conceptually one call occurs first + * and we have a single winner. */ if (increment < 0) { if (!capable(CAP_SYS_NICE)) @@ -2084,7 +2152,7 @@ out_nounlock: * @param: structure containing the new RT priority. */ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, - struct sched_param __user *param) + struct sched_param __user *param) { return setscheduler(pid, policy, param); } @@ -2391,7 +2459,8 @@ asmlinkage long sys_sched_get_priority_m * this syscall writes the default timeslice value of a given process * into the user-space timespec buffer. A value of '0' means infinity. */ -asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval) +asmlinkage +long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval) { int retval = -EINVAL; struct timespec t; @@ -2441,17 +2510,16 @@ static inline struct task_struct *younge static void show_task(task_t * p) { - unsigned long free = 0; task_t *relative; - int state; - static const char * stat_nam[] = { "R", "S", "D", "T", "Z", "W" }; + unsigned state; + static const char *stat_nam[] = { "R", "S", "D", "T", "Z", "W" }; printk("%-13.13s ", p->comm); state = p->state ? __ffs(p->state) + 1 : 0; - if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *)) + if (state < ARRAY_SIZE(stat_nam)) printk(stat_nam[state]); else - printk(" "); + printk("?"); #if (BITS_PER_LONG == 32) if (p == current) printk(" current "); @@ -2463,13 +2531,7 @@ static void show_task(task_t * p) else printk(" %016lx ", thread_saved_pc(p)); #endif - { - unsigned long * n = (unsigned long *) (p->thread_info+1); - while (!*n) - n++; - free = (unsigned long) n - (unsigned long)(p->thread_info+1); - } - printk("%5lu %5d %6d ", free, p->pid, p->parent->pid); + printk("%5d %6d ", p->pid, p->parent->pid); if ((relative = eldest_child(p))) printk("%5d ", relative->pid); else @@ -2496,12 +2558,12 @@ void show_state(void) #if (BITS_PER_LONG == 32) printk("\n" - " free sibling\n"); - printk(" task PC stack pid father child younger older\n"); + " sibling\n"); + printk(" task PC pid father child younger older\n"); #else printk("\n" - " free sibling\n"); - printk(" task PC stack pid father child younger older\n"); + " sibling\n"); + printk(" task PC pid father child younger older\n"); #endif read_lock(&tasklist_lock); do_each_thread(g, p) { @@ -2635,7 +2697,9 @@ static void move_task_away(struct task_s if (p->prio < rq_dest->curr->prio) resched_task(rq_dest->curr); } - out: + p->timestamp = rq_dest->timestamp_last_tick; + +out: double_rq_unlock(this_rq(), rq_dest); local_irq_restore(flags); } @@ -2704,11 +2768,10 @@ static int migration_thread(void * data) * migration_call - callback that gets triggered when a CPU is added. * Here we can start up the necessary migration thread for the new CPU. */ -static int migration_call(struct notifier_block *nfb, - unsigned long action, +static int migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) { - long cpu = (long) hcpu; + long cpu = (long)hcpu; migration_startup_t startup; switch (action) { @@ -2737,7 +2800,8 @@ static int migration_call(struct notifie return NOTIFY_OK; } -static struct notifier_block migration_notifier = { &migration_call, NULL, 0 }; +static struct notifier_block migration_notifier + = { .notifier_call = &migration_call }; __init int migration_init(void) { @@ -2773,7 +2837,7 @@ static void kstat_init_cpu(int cpu) } static int __devinit kstat_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) + unsigned long action, void *hcpu) { int cpu = (unsigned long)hcpu; switch(action) { @@ -2787,13 +2851,14 @@ static int __devinit kstat_cpu_notify(st } static struct notifier_block __devinitdata kstat_nb = { - .notifier_call = kstat_cpu_notify, - .next = NULL, + .notifier_call = kstat_cpu_notify, + .next = NULL, }; -__init static void init_kstat(void) { +__init static void init_kstat(void) +{ kstat_cpu_notify(&kstat_nb, (unsigned long)CPU_UP_PREPARE, - (void *)(long)smp_processor_id()); + (void *)(long)smp_processor_id()); register_cpu_notifier(&kstat_nb); } @@ -2810,6 +2875,8 @@ void __init sched_init(void) rq = cpu_rq(i); rq->active = rq->arrays; rq->expired = rq->arrays + 1; + rq->best_expired_prio = MAX_PRIO; + spin_lock_init(&rq->lock); INIT_LIST_HEAD(&rq->migration_queue); atomic_set(&rq->nr_iowait, 0); @@ -2857,7 +2924,7 @@ void __might_sleep(char *file, int line) printk(KERN_ERR "Debug: sleeping function called from invalid" " context at %s:%d\n", file, line); printk("in_atomic():%d, irqs_disabled():%d\n", - in_atomic(), irqs_disabled()); + in_atomic(), irqs_disabled()); dump_stack(); } #endif --- linux-2.6.1-rc1/kernel/softirq.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/kernel/softirq.c 2003-12-30 22:49:54.000000000 -0800 @@ -117,11 +117,22 @@ EXPORT_SYMBOL(do_softirq); void local_bh_enable(void) { + if (in_irq()) { + printk("local_bh_enable() was called in hard irq context. " + "This is probably a bug\n"); + dump_stack(); + } + __local_bh_enable(); - WARN_ON(irqs_disabled()); - if (unlikely(!in_interrupt() && - local_softirq_pending())) + if (unlikely(!in_interrupt() && local_softirq_pending())) { + if (irqs_disabled()) { + printk("local_bh_enable() was called with local " + "interrupts disabled. This is probably a" + " bug\n"); + dump_stack(); + } invoke_softirq(); + } preempt_check_resched(); } EXPORT_SYMBOL(local_bh_enable); --- linux-2.6.1-rc1/kernel/sysctl.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/kernel/sysctl.c 2003-12-30 22:50:20.000000000 -0800 @@ -37,6 +37,7 @@ #include #include #include +#include #include #ifdef CONFIG_ROOT_NFS @@ -794,6 +795,22 @@ static ctl_table fs_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = FS_AIO_NR, + .procname = "aio-nr", + .data = &aio_nr, + .maxlen = sizeof(aio_nr), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_AIO_MAX_NR, + .procname = "aio-max-nr", + .data = &aio_max_nr, + .maxlen = sizeof(aio_max_nr), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; @@ -1050,8 +1067,8 @@ int do_sysctl_strategy (ctl_table *table * cover common cases - * * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(), - * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(), - * proc_doulongvec_minmax() + * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(), + * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax() * * It is the handler's job to read the input buffer from user memory * and process it. The handler should return 0 on success. @@ -1322,19 +1339,36 @@ static int proc_doutsstring(ctl_table *t return r; } -#define OP_SET 0 -#define OP_AND 1 -#define OP_OR 2 -#define OP_MAX 3 -#define OP_MIN 4 +static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +{ + if (write) { + *valp = *negp ? -*lvalp : *lvalp; + } else { + int val = *valp; + if (val < 0) { + *negp = -1; + *lvalp = (unsigned long)-val; + } else { + *negp = 0; + *lvalp = (unsigned long)val; + } + } + return 0; +} static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, int conv, int op) + void __user *buffer, size_t *lenp, + int (*conv)(int *negp, unsigned long *lvalp, int *valp, + int write, void *data), + void *data) { +#define TMPBUFLEN 20 int *i, vleft, first=1, neg, val; + unsigned long lval; size_t left, len; - #define TMPBUFLEN 20 char buf[TMPBUFLEN], *p; if (!table->data || !table->maxlen || !*lenp || @@ -1344,9 +1378,12 @@ static int do_proc_dointvec(ctl_table *t } i = (int *) table->data; - vleft = table->maxlen / sizeof(int); + vleft = table->maxlen / sizeof(*i); left = *lenp; - + + if (!conv) + conv = do_proc_dointvec_conv; + for (; left && vleft--; i++, first=0) { if (write) { while (left) { @@ -1362,8 +1399,8 @@ static int do_proc_dointvec(ctl_table *t break; neg = 0; len = left; - if (len > TMPBUFLEN-1) - len = TMPBUFLEN-1; + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; if(copy_from_user(buf, buffer, len)) return -EFAULT; buf[len] = 0; @@ -1374,7 +1411,9 @@ static int do_proc_dointvec(ctl_table *t } if (*p < '0' || *p > '9') break; - val = simple_strtoul(p, &p, 0) * conv; + + lval = simple_strtoul(p, &p, 0); + len = p-buf; if ((len < left) && *p && !isspace(*p)) break; @@ -1382,22 +1421,18 @@ static int do_proc_dointvec(ctl_table *t val = -val; buffer += len; left -= len; - switch(op) { - case OP_SET: *i = val; break; - case OP_AND: *i &= val; break; - case OP_OR: *i |= val; break; - case OP_MAX: if(*i < val) - *i = val; - break; - case OP_MIN: if(*i > val) - *i = val; - break; - } + + if (conv(&neg, &lval, i, 1, data)) + break; } else { p = buf; if (!first) *p++ = '\t'; - sprintf(p, "%d", (*i) / conv); + + if (conv(&neg, &lval, i, 0, data)) + break; + + sprintf(p, "%s%lu", neg ? "-" : "", lval); len = strlen(buf); if (len > left) len = left; @@ -1429,6 +1464,7 @@ static int do_proc_dointvec(ctl_table *t *lenp -= left; filp->f_pos += *lenp; return 0; +#undef TMPBUFLEN } /** @@ -1447,7 +1483,45 @@ static int do_proc_dointvec(ctl_table *t int proc_dointvec(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp) { - return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); + return do_proc_dointvec(table,write,filp,buffer,lenp, + NULL,NULL); +} + +#define OP_SET 0 +#define OP_AND 1 +#define OP_OR 2 +#define OP_MAX 3 +#define OP_MIN 4 + +static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +{ + int op = *(int *)data; + if (write) { + int val = *negp ? -*lvalp : *lvalp; + switch(op) { + case OP_SET: *valp = val; break; + case OP_AND: *valp &= val; break; + case OP_OR: *valp |= val; break; + case OP_MAX: if(*valp < val) + *valp = val; + break; + case OP_MIN: if(*valp > val) + *valp = val; + break; + } + } else { + int val = *valp; + if (val < 0) { + *negp = -1; + *lvalp = (unsigned long)-val; + } else { + *negp = 0; + *lvalp = (unsigned long)val; + } + } + return 0; } /* @@ -1457,11 +1531,44 @@ int proc_dointvec(ctl_table *table, int int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp) { + int op; + if (!capable(CAP_SYS_MODULE)) { return -EPERM; } - return do_proc_dointvec(table,write,filp,buffer,lenp,1, - (current->pid == 1) ? OP_SET : OP_AND); + + op = (current->pid == 1) ? OP_SET : OP_AND; + return do_proc_dointvec(table,write,filp,buffer,lenp, + do_proc_dointvec_bset_conv,&op); +} + +struct do_proc_dointvec_minmax_conv_param { + int *min; + int *max; +}; + +static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +{ + struct do_proc_dointvec_minmax_conv_param *param = data; + if (write) { + int val = *negp ? -*lvalp : *lvalp; + if ((param->min && *param->min > val) || + (param->max && *param->max < val)) + return -EINVAL; + *valp = val; + } else { + int val = *valp; + if (val < 0) { + *negp = -1; + *lvalp = (unsigned long)-val; + } else { + *negp = 0; + *lvalp = (unsigned long)val; + } + } + return 0; } /** @@ -1483,98 +1590,12 @@ int proc_dointvec_bset(ctl_table *table, int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp) { - int *i, *min, *max, vleft, first=1, neg, val; - size_t len, left; - #define TMPBUFLEN 20 - char buf[TMPBUFLEN], *p; - - if (!table->data || !table->maxlen || !*lenp || - (filp->f_pos && !write)) { - *lenp = 0; - return 0; - } - - i = (int *) table->data; - min = (int *) table->extra1; - max = (int *) table->extra2; - vleft = table->maxlen / sizeof(int); - left = *lenp; - - for (; left && vleft--; i++, min++, max++, first=0) { - if (write) { - while (left) { - char c; - if(get_user(c, (char *) buffer)) - return -EFAULT; - if (!isspace(c)) - break; - left--; - buffer++; - } - if (!left) - break; - neg = 0; - len = left; - if (len > TMPBUFLEN-1) - len = TMPBUFLEN-1; - if(copy_from_user(buf, buffer, len)) - return -EFAULT; - buf[len] = 0; - p = buf; - if (*p == '-' && left > 1) { - neg = 1; - left--, p++; - } - if (*p < '0' || *p > '9') - break; - val = simple_strtoul(p, &p, 0); - len = p-buf; - if ((len < left) && *p && !isspace(*p)) - break; - if (neg) - val = -val; - buffer += len; - left -= len; - - if ((min && val < *min) || (max && val > *max)) - continue; - *i = val; - } else { - p = buf; - if (!first) - *p++ = '\t'; - sprintf(p, "%d", *i); - len = strlen(buf); - if (len > left) - len = left; - if(copy_to_user(buffer, buf, len)) - return -EFAULT; - left -= len; - buffer += len; - } - } - - if (!write && !first && left) { - if(put_user('\n', (char *) buffer)) - return -EFAULT; - left--, buffer++; - } - if (write) { - p = (char *) buffer; - while (left) { - char c; - if(get_user(c, p++)) - return -EFAULT; - if (!isspace(c)) - break; - left--; - } - } - if (write && first) - return -EINVAL; - *lenp -= left; - filp->f_pos += *lenp; - return 0; + struct do_proc_dointvec_minmax_conv_param param = { + .min = (int *) table->extra1, + .max = (int *) table->extra2, + }; + return do_proc_dointvec(table, write, filp, buffer, lenp, + do_proc_dointvec_minmax_conv, ¶m); } static int do_proc_doulongvec_minmax(ctl_table *table, int write, @@ -1729,6 +1750,48 @@ int proc_doulongvec_ms_jiffies_minmax(ct } +static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +{ + if (write) { + *valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ); + } else { + int val = *valp; + unsigned long lval; + if (val < 0) { + *negp = -1; + lval = (unsigned long)-val; + } else { + *negp = 0; + lval = (unsigned long)val; + } + *lvalp = lval / HZ; + } + return 0; +} + +static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +{ + if (write) { + *valp = clock_t_to_jiffies(*negp ? -*lvalp : *lvalp); + } else { + int val = *valp; + unsigned long lval; + if (val < 0) { + *negp = -1; + lval = (unsigned long)-val; + } else { + *negp = 0; + lval = (unsigned long)val; + } + *lvalp = jiffies_to_clock_t(lval); + } + return 0; +} + /** * proc_dointvec_jiffies - read a vector of integers as seconds * @table: the sysctl table @@ -1747,7 +1810,30 @@ int proc_doulongvec_ms_jiffies_minmax(ct int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp) { - return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET); + return do_proc_dointvec(table,write,filp,buffer,lenp, + do_proc_dointvec_jiffies_conv,NULL); +} + +/** + * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds + * @table: the sysctl table + * @write: %TRUE if this is a write to the sysctl file + * @filp: the file structure + * @buffer: the user buffer + * @lenp: the size of the user buffer + * + * Reads/writes up to table->maxlen/sizeof(unsigned int) integer + * values from/to the user buffer, treated as an ASCII string. + * The values read are assumed to be in 1/USER_HZ seconds, and + * are converted into jiffies. + * + * Returns 0 on success. + */ +int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp) +{ + return do_proc_dointvec(table,write,filp,buffer,lenp, + do_proc_dointvec_userhz_jiffies_conv,NULL); } #else /* CONFIG_PROC_FS */ @@ -1788,6 +1874,12 @@ int proc_dointvec_jiffies(ctl_table *tab return -ENOSYS; } +int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { @@ -1975,6 +2067,12 @@ int proc_dointvec_jiffies(ctl_table *tab return -ENOSYS; } +int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp) { @@ -2007,6 +2105,7 @@ void unregister_sysctl_table(struct ctl_ EXPORT_SYMBOL(proc_dointvec); EXPORT_SYMBOL(proc_dointvec_jiffies); EXPORT_SYMBOL(proc_dointvec_minmax); +EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); EXPORT_SYMBOL(proc_dostring); EXPORT_SYMBOL(proc_doulongvec_minmax); EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); --- linux-2.6.1-rc1/kernel/timer.c 2003-11-23 19:03:02.000000000 -0800 +++ 25/kernel/timer.c 2003-12-30 22:50:15.000000000 -0800 @@ -332,10 +332,7 @@ int del_timer_sync(struct timer_list *ti del_again: ret += del_timer(timer); - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) - continue; - + for_each_cpu(i) { base = &per_cpu(tvec_bases, i); if (base->running_timer == timer) { while (base->running_timer == timer) { --- linux-2.6.1-rc1/kernel/workqueue.c 2003-08-22 19:23:42.000000000 -0700 +++ 25/kernel/workqueue.c 2003-12-30 22:50:15.000000000 -0800 @@ -366,9 +366,7 @@ int current_is_keventd(void) BUG_ON(!keventd_wq); - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; + for_each_cpu(cpu) { cwq = keventd_wq->cpu_wq + cpu; if (current == cwq->thread) return 1; --- linux-2.6.1-rc1/MAINTAINERS 2003-12-30 22:37:20.000000000 -0800 +++ 25/MAINTAINERS 2003-12-30 22:49:25.000000000 -0800 @@ -1158,6 +1158,12 @@ W: http://sf.net/projects/kernel-janitor W: http://developer.osdl.org/rddunlap/kj-patches/ S: Maintained +KGDB FOR I386 PLATFORM +P: George Anzinger +M: george@mvista.com +L: linux-net@vger.kernel.org +S: Supported + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au --- linux-2.6.1-rc1/Makefile 2003-12-30 22:37:20.000000000 -0800 +++ 25/Makefile 2003-12-30 22:49:14.000000000 -0800 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 1 -EXTRAVERSION =-rc1 +EXTRAVERSION =-rc1-mm1 # *DOCUMENTATION* # To see a list of typical targets execute "make help" --- linux-2.6.1-rc1/mm/fadvise.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/fadvise.c 2003-12-30 22:49:36.000000000 -0800 @@ -23,7 +23,6 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) { struct file *file = fget(fd); - struct inode *inode; struct address_space *mapping; struct backing_dev_info *bdi; pgoff_t start_index; @@ -33,8 +32,7 @@ asmlinkage long sys_fadvise64_64(int fd, if (!file) return -EBADF; - inode = file->f_dentry->d_inode; - mapping = inode->i_mapping; + mapping = file->f_mapping; if (!mapping) { ret = -EINVAL; goto out; --- linux-2.6.1-rc1/mm/filemap.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/filemap.c 2003-12-30 22:50:26.000000000 -0800 @@ -73,6 +73,9 @@ * ->mmap_sem * ->i_sem (msync) * + * ->i_sem + * ->i_alloc_sem (various) + * * ->inode_lock * ->sb_lock (fs/fs-writeback.c) * ->mapping->page_lock (__sync_single_inode) @@ -226,6 +229,18 @@ restart: EXPORT_SYMBOL(filemap_fdatawait); +int filemap_write_and_wait(struct address_space *mapping) +{ + int retval = 0; + + if (mapping->nrpages) { + retval = filemap_fdatawrite(mapping); + if (retval == 0) + retval = filemap_fdatawait(mapping); + } + return retval; +} + /* * This adds a page to the page cache, starting out as locked, unreferenced, * not uptodate and with no errors. @@ -292,22 +307,42 @@ static wait_queue_head_t *page_waitqueue return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)]; } -void wait_on_page_bit(struct page *page, int bit_nr) +/* + * wait for the specified page bit to be cleared + * this could be a synchronous wait or could just queue an async + * notification callback depending on the wait queue entry parameter + * + * A NULL wait queue parameter defaults to sync behaviour + */ +int wait_on_page_bit_wq(struct page *page, int bit_nr, wait_queue_t *wait) { wait_queue_head_t *waitqueue = page_waitqueue(page); - DEFINE_WAIT(wait); + DEFINE_WAIT(local_wait); + + if (!wait) + wait = &local_wait; /* default to a sync wait entry */ do { - prepare_to_wait(waitqueue, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(waitqueue, wait, TASK_UNINTERRUPTIBLE); if (test_bit(bit_nr, &page->flags)) { sync_page(page); + if (!is_sync_wait(wait)) { + /* + * if we've queued an async wait queue + * callback do not block; just tell the + * caller to return and retry later when + * the callback is notified + */ + return -EIOCBRETRY; + } io_schedule(); } } while (test_bit(bit_nr, &page->flags)); - finish_wait(waitqueue, &wait); -} + finish_wait(waitqueue, wait); -EXPORT_SYMBOL(wait_on_page_bit); + return 0; +} +EXPORT_SYMBOL(wait_on_page_bit_wq); /** * unlock_page() - unlock a locked page @@ -317,7 +352,9 @@ EXPORT_SYMBOL(wait_on_page_bit); * Unlocks the page and wakes up sleepers in ___wait_on_page_locked(). * Also wakes sleepers in wait_on_page_writeback() because the wakeup * mechananism between PageLocked pages and PageWriteback pages is shared. - * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep. + * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep, + * or in case the wakeup notifies async wait queue entries, as in the case + * of aio, retries would be triggered and may re-queue their callbacks. * * The first mb is necessary to safely close the critical section opened by the * TestSetPageLocked(), the second mb is necessary to enforce ordering between @@ -358,26 +395,51 @@ void end_page_writeback(struct page *pag EXPORT_SYMBOL(end_page_writeback); /* - * Get a lock on the page, assuming we need to sleep to get it. + * Get a lock on the page, assuming we need to either sleep to get it + * or to queue an async notification callback to try again when its + * available. + * + * A NULL wait queue parameter defaults to sync behaviour. Otherwise + * it specifies the wait queue entry to be used for async notification + * or waiting. * * Ugly: running sync_page() in state TASK_UNINTERRUPTIBLE is scary. If some * random driver's requestfn sets TASK_RUNNING, we could busywait. However * 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) +int __lock_page_wq(struct page *page, wait_queue_t *wait) { wait_queue_head_t *wqh = page_waitqueue(page); - DEFINE_WAIT(wait); + DEFINE_WAIT(local_wait); + + if (!wait) + wait = &local_wait; while (TestSetPageLocked(page)) { - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(wqh, wait, TASK_UNINTERRUPTIBLE); if (PageLocked(page)) { sync_page(page); + if (!is_sync_wait(wait)) { + /* + * if we've queued an async wait queue + * callback do not block; just tell the + * caller to return and retry later when + * the callback is notified + */ + return -EIOCBRETRY; + } io_schedule(); } } - finish_wait(wqh, &wait); + finish_wait(wqh, wait); + return 0; +} +EXPORT_SYMBOL(__lock_page_wq); + +void __lock_page(struct page *page) +{ + __lock_page_wq(page, NULL); } EXPORT_SYMBOL(__lock_page); @@ -432,8 +494,8 @@ EXPORT_SYMBOL(find_trylock_page); * * Returns zero if the page was not present. find_lock_page() may sleep. */ -struct page *find_lock_page(struct address_space *mapping, - unsigned long offset) +struct page *find_lock_page_wq(struct address_space *mapping, + unsigned long offset, wait_queue_t *wait) { struct page *page; @@ -444,7 +506,10 @@ repeat: page_cache_get(page); if (TestSetPageLocked(page)) { spin_unlock(&mapping->page_lock); - lock_page(page); + if (-EIOCBRETRY == lock_page_wq(page, wait)) { + page_cache_release(page); + return ERR_PTR(-EIOCBRETRY); + } spin_lock(&mapping->page_lock); /* Has the page been truncated while we slept? */ @@ -461,6 +526,12 @@ repeat: EXPORT_SYMBOL(find_lock_page); +struct page *find_lock_page(struct address_space *mapping, + unsigned long offset) +{ + return find_lock_page_wq(mapping, offset, NULL); +} + /** * find_or_create_page - locate or add a pagecache page * @@ -521,9 +592,12 @@ EXPORT_SYMBOL(find_or_create_page); * The search returns a group of mapping-contiguous pages with ascending * indexes. There may be holes in the indices due to not-present pages. * - * find_get_pages() returns the number of pages which were found. + * find_get_pages() returns the number of pages which were found + * and also atomically sets the next offset to continue looking up + * mapping contiguous pages from (useful when doing a range of + * pagevec lookups in chunks of PAGEVEC_SIZE). */ -unsigned int find_get_pages(struct address_space *mapping, pgoff_t start, +unsigned int find_get_pages(struct address_space *mapping, pgoff_t *next, unsigned int nr_pages, struct page **pages) { unsigned int i; @@ -531,9 +605,12 @@ unsigned int find_get_pages(struct addre spin_lock(&mapping->page_lock); ret = radix_tree_gang_lookup(&mapping->page_tree, - (void **)pages, start, nr_pages); + (void **)pages, *next, nr_pages); for (i = 0; i < ret; i++) page_cache_get(pages[i]); + if (ret) + *next = pages[ret - 1]->index + 1; + spin_unlock(&mapping->page_lock); return ret; } @@ -587,30 +664,46 @@ void do_generic_mapping_read(struct addr read_actor_t actor) { struct inode *inode = mapping->host; - unsigned long index, offset, last; + unsigned long index, offset, first, last, end_index; + loff_t isize = i_size_read(inode); struct page *cached_page; int error; cached_page = NULL; - index = *ppos >> PAGE_CACHE_SHIFT; + first = *ppos >> PAGE_CACHE_SHIFT; offset = *ppos & ~PAGE_CACHE_MASK; last = (*ppos + desc->count) >> PAGE_CACHE_SHIFT; + end_index = isize >> PAGE_CACHE_SHIFT; + if (last > end_index) + last = end_index; + + /* Don't repeat the readahead if we are executing aio retries */ + if (in_aio()) { + if (is_retried_kiocb(io_wait_to_kiocb(current->io_wait))) + goto done_readahead; + } /* * Let the readahead logic know upfront about all * the pages we'll need to satisfy this request */ - for (; index < last; index++) + for (index = first; index < last; index++) page_cache_readahead(mapping, ra, filp, index); - index = *ppos >> PAGE_CACHE_SHIFT; + if (ra->next_size == -1UL) { + /* the readahead window was maximally shrunk */ + /* explicitly readahead at least what is needed now */ + for (index = first; index < last; index++) + handle_ra_miss(mapping, ra, index); + do_page_cache_readahead(mapping, filp, first, last - first); + } + +done_readahead: + index = first; for (;;) { struct page *page; - unsigned long end_index, nr, ret; - loff_t isize = i_size_read(inode); + unsigned long nr, ret; - end_index = isize >> PAGE_CACHE_SHIFT; - if (index > end_index) break; nr = PAGE_CACHE_SIZE; @@ -670,7 +763,12 @@ page_not_up_to_date: goto page_ok; /* Get exclusive access to the page ... */ - lock_page(page); + + if (lock_page_wq(page, current->io_wait)) { + pr_debug("queued lock page \n"); + error = -EIOCBRETRY; + goto sync_error; + } /* Did it get unhashed before we got the lock? */ if (!page->mapping) { @@ -692,13 +790,23 @@ readpage: if (!error) { if (PageUptodate(page)) goto page_ok; - wait_on_page_locked(page); + if (wait_on_page_locked_wq(page, current->io_wait)) { + pr_debug("queued wait_on_page \n"); + error = -EIOCBRETRY; + goto sync_error; + } + if (PageUptodate(page)) goto page_ok; error = -EIO; } - /* UHHUH! A synchronous read error occurred. Report it */ +sync_error: + /* We don't have uptodate data in the page yet */ + /* Could be due to an error or because we need to + * retry when we get an async i/o notification. + * Report the reason. + */ desc->error = error; page_cache_release(page); break; @@ -812,7 +920,7 @@ __generic_file_aio_read(struct kiocb *io struct address_space *mapping; struct inode *inode; - mapping = filp->f_dentry->d_inode->i_mapping; + mapping = filp->f_mapping; inode = mapping->host; retval = 0; if (!count) @@ -852,22 +960,19 @@ __generic_file_aio_read(struct kiocb *io out: return retval; } - EXPORT_SYMBOL(__generic_file_aio_read); -ssize_t -generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) +ssize_t generic_file_aio_read(struct kiocb *iocb, char __user *buf, + size_t count, loff_t pos) { struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - BUG_ON(iocb->ki_pos != pos); return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); } - EXPORT_SYMBOL(generic_file_aio_read); -ssize_t -generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) +ssize_t generic_file_read(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) { struct iovec local_iov = { .iov_base = buf, .iov_len = count }; struct kiocb kiocb; @@ -879,10 +984,10 @@ generic_file_read(struct file *filp, cha ret = wait_on_sync_kiocb(&kiocb); return ret; } - EXPORT_SYMBOL(generic_file_read); -int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) +int file_send_actor(read_descriptor_t * desc, struct page *page, + unsigned long offset, unsigned long size) { ssize_t written; unsigned long count = desc->count; @@ -944,7 +1049,7 @@ asmlinkage ssize_t sys_readahead(int fd, file = fget(fd); if (file) { if (file->f_mode & FMODE_READ) { - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; unsigned long start = offset >> PAGE_CACHE_SHIFT; unsigned long end = (offset + count - 1) >> PAGE_CACHE_SHIFT; unsigned long len = end - start + 1; @@ -963,7 +1068,7 @@ asmlinkage ssize_t sys_readahead(int fd, static int FASTCALL(page_cache_read(struct file * file, unsigned long offset)); static int page_cache_read(struct file * file, unsigned long offset) { - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; struct page *page; int error; @@ -1002,7 +1107,7 @@ struct page * filemap_nopage(struct vm_a { int error; struct file *file = area->vm_file; - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; struct file_ra_state *ra = &file->f_ra; struct inode *inode = mapping->host; struct page *page; @@ -1187,7 +1292,7 @@ EXPORT_SYMBOL(filemap_nopage); static struct page * filemap_getpage(struct file *file, unsigned long pgoff, int nonblock) { - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; struct page *page; int error; @@ -1299,7 +1404,7 @@ static int filemap_populate(struct vm_ar int nonblock) { struct file *file = vma->vm_file; - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; unsigned long size; struct mm_struct *mm = vma->vm_mm; @@ -1358,7 +1463,7 @@ static struct vm_operations_struct gener int generic_file_mmap(struct file * file, struct vm_area_struct * vma) { - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; if (!mapping->a_ops->readpage) @@ -1481,7 +1586,9 @@ __grab_cache_page(struct address_space * int err; struct page *page; repeat: - page = find_lock_page(mapping, index); + page = find_lock_page_wq(mapping, index, current->io_wait); + if (IS_ERR(page)) + return page; if (!page) { if (!*cached_page) { *cached_page = page_cache_alloc(mapping); @@ -1626,9 +1733,9 @@ filemap_set_next_iovec(const struct iove * Returns appropriate error code that caller should return or * zero in case that write should be allowed. */ -inline int generic_write_checks(struct inode *inode, - struct file *file, loff_t *pos, size_t *count, int isblk) +inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk) { + struct inode *inode = file->f_mapping->host; unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; if (unlikely(*pos < 0)) @@ -1690,7 +1797,7 @@ inline int generic_write_checks(struct i *count = inode->i_sb->s_maxbytes - *pos; } else { loff_t isize; - if (bdev_read_only(inode->i_bdev)) + if (bdev_read_only(I_BDEV(inode))) return -EPERM; isize = i_size_read(inode); if (*pos >= isize) { @@ -1708,6 +1815,7 @@ EXPORT_SYMBOL(generic_write_checks); /* * Write to a file through the page cache. + * Called under i_sem for S_ISREG files. * * We put everything into the page cache prior to writing it. This is not a * problem when writing full pages. With partial pages, however, we first have @@ -1716,11 +1824,11 @@ EXPORT_SYMBOL(generic_write_checks); * okir@monad.swb.de */ ssize_t -generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, +__generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { struct file *file = iocb->ki_filp; - struct address_space * mapping = file->f_dentry->d_inode->i_mapping; + struct address_space * mapping = file->f_mapping; struct address_space_operations *a_ops = mapping->a_ops; size_t ocount; /* original count */ size_t count; /* after file limit checks */ @@ -1767,11 +1875,10 @@ generic_file_aio_write_nolock(struct kio current->backing_dev_info = mapping->backing_dev_info; written = 0; - err = generic_write_checks(inode, file, &pos, &count, isblk); + err = generic_write_checks(file, &pos, &count, isblk); if (err) goto out; - if (count == 0) goto out; @@ -1796,12 +1903,19 @@ generic_file_aio_write_nolock(struct kio /* * Sync the fs metadata but not the minor inode changes and * of course not the data as we did direct DMA for the IO. + * i_sem is held, which protects generic_osync_inode() from + * livelocking. */ if (written >= 0 && file->f_flags & O_SYNC) - status = generic_osync_inode(inode, OSYNC_METADATA); + status = generic_osync_inode(inode, mapping, OSYNC_METADATA); if (written >= 0 && !is_sync_kiocb(iocb)) written = -EIOCBQUEUED; - goto out_status; + if (written != -ENOTBLK) + goto out_status; + /* + * direct-io write to a hole: fall through to buffered I/O + */ + written = 0; } buf = iov->iov_base; @@ -1825,6 +1939,10 @@ generic_file_aio_write_nolock(struct kio fault_in_pages_readable(buf, bytes); page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); + if (IS_ERR(page)) { + status = PTR_ERR(page); + break; + } if (!page) { status = -ENOMEM; break; @@ -1873,7 +1991,11 @@ generic_file_aio_write_nolock(struct kio page_cache_release(page); if (status < 0) break; - balance_dirty_pages_ratelimited(mapping); + status = balance_dirty_pages_ratelimited(mapping); + if (status < 0) { + pr_debug("async balance_dirty_pages\n"); + break; + } cond_resched(); } while (count); *ppos = pos; @@ -1884,12 +2006,22 @@ generic_file_aio_write_nolock(struct kio /* * For now, when the user asks for O_SYNC, we'll actually give O_DSYNC */ - if (status >= 0) { - if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) - status = generic_osync_inode(inode, - OSYNC_METADATA|OSYNC_DATA); - } + if (likely(status >= 0)) { + if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + if (!a_ops->writepage) + status = generic_osync_inode(inode, mapping, + OSYNC_METADATA|OSYNC_DATA); + } + } + /* + * If we get here for O_DIRECT writes then we must have fallen through + * to buffered writes (block instantiation inside i_size). So we sync + * the file data here, to try to honour O_DIRECT expectations. + */ + if (unlikely(file->f_flags & O_DIRECT) && written) + status = filemap_write_and_wait(mapping); + out_status: err = written ? written : status; out: @@ -1901,6 +2033,55 @@ out: EXPORT_SYMBOL(generic_file_aio_write_nolock); ssize_t +generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + loff_t pos = *ppos; + + if (!iov->iov_base && !is_sync_kiocb(iocb)) { + /* nothing to transfer, may just need to sync data */ + ret = iov->iov_len; /* vector AIO not supported yet */ + goto osync; + } + + ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos); + + /* + * Avoid doing a sync in parts for aio - its more efficient to + * call in again after all the data has been copied + */ + if (!is_sync_kiocb(iocb)) + return ret; + +osync: + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + ret = sync_page_range_nolock(inode, mapping, pos, ret); + if (ret >= 0) + *ppos = pos + ret; + } + return ret; +} + + +ssize_t +__generic_file_write_nolock(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) +{ + struct kiocb kiocb; + ssize_t ret; + + init_sync_kiocb(&kiocb, file); + ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&kiocb); + return ret; +} + +ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { @@ -1920,36 +2101,62 @@ ssize_t generic_file_aio_write(struct ki size_t count, loff_t pos) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; - ssize_t err; - struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + struct iovec local_iov = { .iov_base = (void __user *)buf, + .iov_len = count }; - BUG_ON(iocb->ki_pos != pos); + if (!buf && !is_sync_kiocb(iocb)) { + /* nothing to transfer, may just need to sync data */ + ret = count; + goto osync; + } down(&inode->i_sem); - err = generic_file_aio_write_nolock(iocb, &local_iov, 1, + ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); up(&inode->i_sem); - return err; -} + /* + * Avoid doing a sync in parts for aio - its more efficient to + * call in again after all the data has been copied + */ + if (!is_sync_kiocb(iocb)) + return ret; +osync: + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + ret = sync_page_range(inode, mapping, pos, ret); + if (ret >= 0) + iocb->ki_pos = pos + ret; + } + return ret; +} EXPORT_SYMBOL(generic_file_aio_write); ssize_t generic_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode->i_mapping->host; - ssize_t err; - struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + struct iovec local_iov = { .iov_base = (void __user *)buf, + .iov_len = count }; down(&inode->i_sem); - err = generic_file_write_nolock(file, &local_iov, 1, ppos); + ret = __generic_file_write_nolock(file, &local_iov, 1, ppos); up(&inode->i_sem); - return err; -} + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + ssize_t err; + err = sync_page_range(inode, mapping, *ppos - ret, ret); + if (err < 0) + ret = err; + } + return ret; +} EXPORT_SYMBOL(generic_file_write); ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, @@ -1968,39 +2175,46 @@ ssize_t generic_file_readv(struct file * EXPORT_SYMBOL(generic_file_readv); ssize_t generic_file_writev(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t * ppos) + unsigned long nr_segs, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; ssize_t ret; down(&inode->i_sem); - ret = generic_file_write_nolock(file, iov, nr_segs, ppos); + ret = __generic_file_write_nolock(file, iov, nr_segs, ppos); up(&inode->i_sem); + + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + ssize_t err; + + err = sync_page_range(inode, mapping, *ppos - ret, ret); + if (err < 0) + ret = err; + } return ret; } EXPORT_SYMBOL(generic_file_writev); +/* + * Called under i_sem for writes to S_ISREG files + */ ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_mapping; ssize_t retval; - if (mapping->nrpages) { - retval = filemap_fdatawrite(mapping); - if (retval == 0) - retval = filemap_fdatawait(mapping); - if (retval) - goto out; + retval = filemap_write_and_wait(mapping); + if (retval == 0) { + retval = mapping->a_ops->direct_IO(rw, iocb, iov, + offset, nr_segs); + if (rw == WRITE && mapping->nrpages) + invalidate_inode_pages2(mapping); } - - retval = mapping->a_ops->direct_IO(rw, iocb, iov, offset, nr_segs); - if (rw == WRITE && mapping->nrpages) - invalidate_inode_pages2(mapping); -out: return retval; } --- linux-2.6.1-rc1/mm/madvise.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/madvise.c 2003-12-30 22:49:35.000000000 -0800 @@ -65,7 +65,7 @@ static long madvise_willneed(struct vm_a end = vma->vm_end; end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - force_page_cache_readahead(file->f_dentry->d_inode->i_mapping, + force_page_cache_readahead(file->f_mapping, file, start, max_sane_readahead(end - start)); return 0; } --- linux-2.6.1-rc1/mm/Makefile 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/Makefile 2003-12-30 22:50:18.000000000 -0800 @@ -12,3 +12,6 @@ obj-y := bootmem.o filemap.o mempool.o slab.o swap.o truncate.o vmscan.o $(mmu-y) obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o + +obj-$(CONFIG_X86_4G) += usercopy.o + --- linux-2.6.1-rc1/mm/memory.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/memory.c 2003-12-30 22:50:18.000000000 -0800 @@ -107,7 +107,8 @@ static inline void free_one_pmd(struct m pte_free_tlb(tlb, page); } -static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir) +static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir, + int pgd_idx) { int j; pmd_t * pmd; @@ -121,8 +122,11 @@ static inline void free_one_pgd(struct m } pmd = pmd_offset(dir, 0); pgd_clear(dir); - for (j = 0; j < PTRS_PER_PMD ; j++) + for (j = 0; j < PTRS_PER_PMD ; j++) { + if (pgd_idx * PGDIR_SIZE + j * PMD_SIZE >= TASK_SIZE) + break; free_one_pmd(tlb, pmd+j); + } pmd_free_tlb(tlb, pmd); } @@ -135,11 +139,13 @@ static inline void free_one_pgd(struct m void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr) { pgd_t * page_dir = tlb->mm->pgd; + int pgd_idx = first; page_dir += first; do { - free_one_pgd(tlb, page_dir); + free_one_pgd(tlb, page_dir, pgd_idx); page_dir++; + pgd_idx++; } while (--nr); } @@ -437,7 +443,7 @@ zap_pmd_range(struct mmu_gather *tlb, pg unsigned long address, unsigned long size) { pmd_t * pmd; - unsigned long end; + unsigned long end, pgd_boundary; if (pgd_none(*dir)) return; @@ -448,8 +454,9 @@ zap_pmd_range(struct mmu_gather *tlb, pg } pmd = pmd_offset(dir, address); end = address + size; - if (end > ((address + PGDIR_SIZE) & PGDIR_MASK)) - end = ((address + PGDIR_SIZE) & PGDIR_MASK); + pgd_boundary = ((address + PGDIR_SIZE) & PGDIR_MASK); + if (pgd_boundary && (end > pgd_boundary)) + end = pgd_boundary; do { zap_pte_range(tlb, pmd, address, end - address); address = (address + PMD_SIZE) & PMD_MASK; @@ -603,6 +610,11 @@ void zap_page_range(struct vm_area_struc might_sleep(); if (is_vm_hugetlb_page(vma)) { + static int x; + if (x < 10) { + x++; + dump_stack(); + } zap_hugepage_range(vma, address, size); return; } @@ -685,6 +697,7 @@ int get_user_pages(struct task_struct *t struct page **pages, struct vm_area_struct **vmas) { int i; + int vm_io; unsigned int flags; /* @@ -741,8 +754,10 @@ int get_user_pages(struct task_struct *t } #endif - if (!vma || (pages && (vma->vm_flags & VM_IO)) - || !(flags & vma->vm_flags)) + if (!vma) + return i ? : -EFAULT; + vm_io = vma->vm_flags & VM_IO; + if ((pages && vm_io) || !(flags & vma->vm_flags)) return i ? : -EFAULT; if (is_vm_hugetlb_page(vma)) { @@ -750,9 +765,17 @@ int get_user_pages(struct task_struct *t &start, &len, i); continue; } + spin_lock(&mm->page_table_lock); do { - struct page *map; + struct page *map = NULL; + + /* + * We don't follow pagetables for VM_IO regions - they + * may have no pageframes. + */ + if (vm_io) + goto no_follow; while (!(map = follow_page(mm, start, write))) { spin_unlock(&mm->page_table_lock); switch (handle_mm_fault(mm,vma,start,write)) { @@ -784,6 +807,7 @@ int get_user_pages(struct task_struct *t if (!PageReserved(pages[i])) page_cache_get(pages[i]); } +no_follow: if (vmas) vmas[i] = vma; i++; @@ -1147,7 +1171,7 @@ void invalidate_mmap_range(struct addres invalidate_mmap_range_list(&mapping->i_mmap_shared, hba, hlen); up(&mapping->i_shared_sem); } -EXPORT_SYMBOL_GPL(invalidate_mmap_range); +EXPORT_SYMBOL(invalidate_mmap_range); /* * Handle all mappings that got truncated by a "truncate()" @@ -1409,7 +1433,7 @@ do_no_page(struct mm_struct *mm, struct spin_unlock(&mm->page_table_lock); if (vma->vm_file) { - mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + mapping = vma->vm_file->f_mapping; sequence = atomic_read(&mapping->truncate_count); } smp_rmb(); /* Prevent CPU from reordering lock-free ->nopage() */ --- linux-2.6.1-rc1/mm/mincore.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/mincore.c 2003-12-30 22:49:35.000000000 -0800 @@ -26,7 +26,7 @@ static unsigned char mincore_page(struct unsigned long pgoff) { unsigned char present = 0; - struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping; + struct address_space * as = vma->vm_file->f_mapping; struct page * page; page = find_get_page(as, pgoff); --- linux-2.6.1-rc1/mm/mmap.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/mmap.c 2003-12-30 22:49:36.000000000 -0800 @@ -80,11 +80,10 @@ static void remove_shared_vm_struct(stru struct file *file = vma->vm_file; if (file) { - struct inode *inode = file->f_dentry->d_inode; - - down(&inode->i_mapping->i_shared_sem); - __remove_shared_vm_struct(vma, inode); - up(&inode->i_mapping->i_shared_sem); + struct address_space *mapping = file->f_mapping; + down(&mapping->i_shared_sem); + __remove_shared_vm_struct(vma, file->f_dentry->d_inode); + up(&mapping->i_shared_sem); } } @@ -235,11 +234,10 @@ static inline void __vma_link_file(struc file = vma->vm_file; if (file) { - struct inode * inode = file->f_dentry->d_inode; - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = file->f_mapping; if (vma->vm_flags & VM_DENYWRITE) - atomic_dec(&inode->i_writecount); + atomic_dec(&file->f_dentry->d_inode->i_writecount); if (vma->vm_flags & VM_SHARED) list_add_tail(&vma->shared, &mapping->i_mmap_shared); @@ -265,7 +263,7 @@ static void vma_link(struct mm_struct *m struct address_space *mapping = NULL; if (vma->vm_file) - mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + mapping = vma->vm_file->f_mapping; if (mapping) down(&mapping->i_shared_sem); @@ -383,7 +381,7 @@ static int vma_merge(struct mm_struct *m if (vm_flags & VM_SPECIAL) return 0; - i_shared_sem = file ? &inode->i_mapping->i_shared_sem : NULL; + i_shared_sem = file ? &file->f_mapping->i_shared_sem : NULL; if (!prev) { prev = rb_entry(rb_parent, struct vm_area_struct, vm_rb); @@ -1207,7 +1205,7 @@ int split_vma(struct mm_struct * mm, str new->vm_ops->open(new); if (vma->vm_file) - mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + mapping = vma->vm_file->f_mapping; if (mapping) down(&mapping->i_shared_sem); --- linux-2.6.1-rc1/mm/msync.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/msync.c 2003-12-30 22:49:35.000000000 -0800 @@ -146,20 +146,20 @@ static int msync_interval(struct vm_area ret = filemap_sync(vma, start, end-start, flags); if (!ret && (flags & MS_SYNC)) { - struct inode *inode = file->f_dentry->d_inode; + struct address_space *mapping = file->f_mapping; int err; - down(&inode->i_sem); - ret = filemap_fdatawrite(inode->i_mapping); + down(&mapping->host->i_sem); + ret = filemap_fdatawrite(mapping); if (file->f_op && file->f_op->fsync) { err = file->f_op->fsync(file,file->f_dentry,1); if (err && !ret) ret = err; } - err = filemap_fdatawait(inode->i_mapping); + err = filemap_fdatawait(mapping); if (!ret) ret = err; - up(&inode->i_sem); + up(&mapping->host->i_sem); } } return ret; --- linux-2.6.1-rc1/mm/page_alloc.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/page_alloc.c 2003-12-30 22:50:15.000000000 -0800 @@ -539,7 +539,7 @@ __alloc_pages(unsigned int gfp_mask, uns { const int wait = gfp_mask & __GFP_WAIT; unsigned long min; - struct zone **zones, *classzone; + struct zone **zones; struct page *page; struct reclaim_state reclaim_state; struct task_struct *p = current; @@ -554,8 +554,7 @@ __alloc_pages(unsigned int gfp_mask, uns cold = 1; zones = zonelist->zones; /* the list of zones suitable for gfp_mask */ - classzone = zones[0]; - if (classzone == NULL) /* no zones in the zonelist */ + if (zones[0] == NULL) /* no zones in the zonelist */ return NULL; /* Go through the zonelist once, looking for a zone with enough free */ @@ -630,7 +629,7 @@ rebalance: reclaim_state.reclaimed_slab = 0; p->reclaim_state = &reclaim_state; - try_to_free_pages(classzone, gfp_mask, order); + try_to_free_pages(zones, gfp_mask, order); p->reclaim_state = NULL; p->flags &= ~PF_MEMALLOC; @@ -674,6 +673,7 @@ nopage: printk("%s: page allocation failure." " order:%d, mode:0x%x\n", p->comm, order, gfp_mask); + dump_stack(); } return NULL; got_pg: @@ -869,14 +869,14 @@ void __get_page_state(struct page_state while (cpu < NR_CPUS) { unsigned long *in, *out, off; - if (!cpu_online(cpu)) { + if (!cpu_possible(cpu)) { cpu++; continue; } in = (unsigned long *)&per_cpu(page_states, cpu); cpu++; - if (cpu < NR_CPUS && cpu_online(cpu)) + if (cpu < NR_CPUS && cpu_possible(cpu)) prefetch(&per_cpu(page_states, cpu)); out = (unsigned long *)ret; for (off = 0; off < nr; off++) --- linux-2.6.1-rc1/mm/page-writeback.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/page-writeback.c 2003-12-30 22:50:26.000000000 -0800 @@ -28,6 +28,7 @@ #include #include #include +#include /* * The maximum number of pages to writeout in a single bdflush/kupdate @@ -146,7 +147,7 @@ get_dirty_limits(struct page_state *ps, * If we're over `background_thresh' then pdflush is woken to perform some * writeout. */ -static void balance_dirty_pages(struct address_space *mapping) +static int balance_dirty_pages(struct address_space *mapping) { struct page_state ps; long nr_reclaimable; @@ -163,6 +164,7 @@ static void balance_dirty_pages(struct a .sync_mode = WB_SYNC_NONE, .older_than_this = NULL, .nr_to_write = write_chunk, + .nonblocking = !is_sync_wait(current->io_wait) }; get_dirty_limits(&ps, &background_thresh, &dirty_thresh); @@ -189,7 +191,11 @@ static void balance_dirty_pages(struct a if (pages_written >= write_chunk) break; /* We've done our duty */ } - blk_congestion_wait(WRITE, HZ/10); + if (-EIOCBRETRY == blk_congestion_wait_wq(WRITE, HZ/10, + current->io_wait)) { + pr_debug("async blk congestion wait\n"); + return -EIOCBRETRY; + } } if (nr_reclaimable + ps.nr_writeback <= dirty_thresh) @@ -197,6 +203,8 @@ static void balance_dirty_pages(struct a if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh) pdflush_operation(background_writeout, 0); + + return 0; } /** @@ -212,7 +220,7 @@ static void balance_dirty_pages(struct a * decrease the ratelimiting by a lot, to prevent individual processes from * overshooting the limit by (ratelimit_pages) each. */ -void balance_dirty_pages_ratelimited(struct address_space *mapping) +int balance_dirty_pages_ratelimited(struct address_space *mapping) { static DEFINE_PER_CPU(int, ratelimits) = 0; long ratelimit; @@ -228,10 +236,10 @@ void balance_dirty_pages_ratelimited(str if (get_cpu_var(ratelimits)++ >= ratelimit) { __get_cpu_var(ratelimits) = 0; put_cpu_var(ratelimits); - balance_dirty_pages(mapping); - return; + return balance_dirty_pages(mapping); } put_cpu_var(ratelimits); + return 0; } /* @@ -567,3 +575,152 @@ int test_clear_page_dirty(struct page *p return 0; } EXPORT_SYMBOL(test_clear_page_dirty); + + +static ssize_t operate_on_page_range(struct address_space *mapping, + loff_t pos, size_t count, int (*operator)(struct page *)) +{ + pgoff_t first = pos >> PAGE_CACHE_SHIFT; + pgoff_t last = (pos + count - 1) >> PAGE_CACHE_SHIFT; /* inclusive */ + pgoff_t next = first, curr = first; + struct pagevec pvec; + ssize_t ret = 0, bytes = 0; + int i, nr; + + if (count == 0) + return 0; + + pagevec_init(&pvec, 0); + while ((nr = pagevec_lookup(&pvec, mapping, &next, + min((pgoff_t)PAGEVEC_SIZE, last - next + 1)))) { + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; + + curr = page->index; + if (page->mapping != mapping) /* truncated ?*/ { + curr = next; + break; + } else { + ret = (*operator)(page); + if (ret == -EIOCBRETRY) + break; + if (PageError(page)) { + if (!ret) + ret = -EIO; + } else + curr++; + } + } + pagevec_release(&pvec); + if ((ret == -EIOCBRETRY) || (next > last)) + break; + } + if (!nr) + curr = last + 1; + + bytes = (curr << PAGE_CACHE_SHIFT) - pos; + if (bytes > count) + bytes = count; + return (bytes && (!ret || (ret == -EIOCBRETRY))) ? bytes : ret; +} + +static int page_waiter(struct page *page) +{ + return wait_on_page_writeback_wq(page, current->io_wait); +} + +static size_t +wait_on_page_range(struct address_space *mapping, loff_t pos, size_t count) +{ + return operate_on_page_range(mapping, pos, count, page_waiter); +} + +static int page_writer(struct page *page) +{ + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 1, + }; + + lock_page(page); + if (!page->mapping) { /* truncated */ + unlock_page(page); + return 0; + } + if (!test_clear_page_dirty(page)) { + unlock_page(page); + return 0; + } + wait_on_page_writeback(page); + return page->mapping->a_ops->writepage(page, &wbc); +} + +static ssize_t +write_out_page_range(struct address_space *mapping, loff_t pos, size_t count) +{ + return operate_on_page_range(mapping, pos, count, page_writer); +} + +/* + * Write and wait upon all the pages in the passed range. This is a "data + * integrity" operation. It waits upon in-flight writeout before starting and + * waiting upon new writeout. If there was an IO error, return it. + * + * We need to re-take i_sem during the generic_osync_inode list walk because + * it is otherwise livelockable. + */ +ssize_t sync_page_range(struct inode *inode, struct address_space *mapping, + loff_t pos, size_t count) +{ + int ret = 0; + + if (in_aio()) { + /* Already issued writeouts for this iocb ? */ + if (kiocbTrySync(io_wait_to_kiocb(current->io_wait))) + goto do_wait; /* just need to check if done */ + } + if (!mapping->a_ops->writepage) + return 0; + if (mapping->backing_dev_info->memory_backed) + return 0; + ret = write_out_page_range(mapping, pos, count); + if (ret >= 0) { + down(&inode->i_sem); + ret = generic_osync_inode(inode, mapping, OSYNC_METADATA); + up(&inode->i_sem); + } +do_wait: + if (ret >= 0) + ret = wait_on_page_range(mapping, pos, count); + return ret; +} + +/* + * It is really better to use sync_page_range, rather than call + * sync_page_range_nolock while holding i_sem, if you don't + * want to block parallel O_SYNC writes until the pages in this + * range are written out. + */ +ssize_t sync_page_range_nolock(struct inode *inode, struct address_space + *mapping, loff_t pos, size_t count) +{ + ssize_t ret = 0; + + if (in_aio()) { + /* Already issued writeouts for this iocb ? */ + if (kiocbTrySync(io_wait_to_kiocb(current->io_wait))) + goto do_wait; /* just need to check if done */ + } + if (!mapping->a_ops->writepage) + return 0; + if (mapping->backing_dev_info->memory_backed) + return 0; + ret = write_out_page_range(mapping, pos, count); + if (ret >= 0) { + ret = generic_osync_inode(inode, mapping, OSYNC_METADATA); + } +do_wait: + if (ret >= 0) + ret = wait_on_page_range(mapping, pos, count); + return ret; +} --- linux-2.6.1-rc1/mm/pdflush.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/pdflush.c 2003-12-30 22:49:47.000000000 -0800 @@ -84,6 +84,8 @@ struct pdflush_work { unsigned long when_i_went_to_sleep; }; +static int wakeup_count = 100; + static int __pdflush(struct pdflush_work *my_work) { daemonize("pdflush"); @@ -112,7 +114,10 @@ static int __pdflush(struct pdflush_work spin_lock_irq(&pdflush_lock); if (!list_empty(&my_work->list)) { - printk("pdflush: bogus wakeup!\n"); + if (wakeup_count > 0) { + wakeup_count--; + printk("pdflush: bogus wakeup!\n"); + } my_work->fn = NULL; continue; } @@ -182,6 +187,7 @@ int pdflush_operation(void (*fn)(unsigne { unsigned long flags; int ret = 0; + static int poke_count = 0; if (fn == NULL) BUG(); /* Hard to diagnose if it's deferred */ @@ -190,9 +196,19 @@ int pdflush_operation(void (*fn)(unsigne if (list_empty(&pdflush_list)) { spin_unlock_irqrestore(&pdflush_lock, flags); ret = -1; + if (wakeup_count < 100 && poke_count < 10) { + printk("%s: no threads\n", __FUNCTION__); + dump_stack(); + poke_count++; + } } else { struct pdflush_work *pdf; + if (wakeup_count < 100 && poke_count < 10) { + printk("%s: found a thread\n", __FUNCTION__); + dump_stack(); + poke_count++; + } pdf = list_entry(pdflush_list.next, struct pdflush_work, list); list_del_init(&pdf->list); if (list_empty(&pdflush_list)) --- linux-2.6.1-rc1/mm/shmem.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/shmem.c 2003-12-30 22:49:37.000000000 -0800 @@ -1186,7 +1186,7 @@ shmem_file_write(struct file *file, cons pos = *ppos; written = 0; - err = generic_write_checks(inode, file, &pos, &count, 0); + err = generic_write_checks(file, &pos, &count, 0); if (err || !count) goto out; @@ -1978,6 +1978,7 @@ struct file *shmem_file_setup(char *name inode->i_nlink = 0; /* It is unlinked */ file->f_vfsmnt = mntget(shm_mnt); file->f_dentry = dentry; + file->f_mapping = inode->i_mapping; file->f_op = &shmem_file_operations; file->f_mode = FMODE_WRITE | FMODE_READ; return(file); --- linux-2.6.1-rc1/mm/slab.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/slab.c 2003-12-30 22:50:18.000000000 -0800 @@ -1181,7 +1181,8 @@ next: cachep = NULL; goto opps; } - slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab)); + slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t) + + sizeof(struct slab)); /* * If the slab has been placed off-slab, and we have enough space then @@ -1225,10 +1226,13 @@ next: * the cache that's used by kmalloc(24), otherwise * the creation of further caches will BUG(). */ - cachep->array[smp_processor_id()] = &initarray_generic.cache; + cachep->array[smp_processor_id()] = + &initarray_generic.cache; g_cpucache_up = PARTIAL; } else { - cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init),GFP_KERNEL); + cachep->array[smp_processor_id()] = + kmalloc(sizeof(struct arraycache_init), + GFP_KERNEL); } BUG_ON(!ac_data(cachep)); ac_data(cachep)->avail = 0; @@ -1242,7 +1246,7 @@ next: } cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; /* Need the semaphore to access the chain. */ down(&cache_chain_sem); @@ -1255,16 +1259,24 @@ next: list_for_each(p, &cache_chain) { kmem_cache_t *pc = list_entry(p, kmem_cache_t, next); char tmp; - /* This happens when the module gets unloaded and doesn't - destroy its slab cache and noone else reuses the vmalloc - area of the module. Print a warning. */ - if (__get_user(tmp,pc->name)) { - printk("SLAB: cache with size %d has lost its name\n", - pc->objsize); + + /* + * This happens when the module gets unloaded and + * doesn't destroy its slab cache and noone else reuses + * the vmalloc area of the module. Print a warning. + */ +#ifdef CONFIG_X86_UACCESS_INDIRECT + if (__direct_get_user(tmp,pc->name)) { +#else + if (__get_user(tmp,pc->name)) { +#endif + printk("SLAB: cache with size %d has lost its " + "name\n", pc->objsize); continue; } if (!strcmp(pc->name,name)) { - printk("kmem_cache_create: duplicate cache %s\n",name); + printk("kmem_cache_create: duplicate " + "cache %s\n",name); up(&cache_chain_sem); BUG(); } @@ -1890,6 +1902,15 @@ cache_alloc_debugcheck_after(kmem_cache_ *dbg_redzone1(cachep, objp) = RED_ACTIVE; *dbg_redzone2(cachep, objp) = RED_ACTIVE; } + { + int objnr; + struct slab *slabp; + + slabp = GET_PAGE_SLAB(virt_to_page(objp)); + + objnr = (objp - slabp->s_mem) / cachep->objsize; + slab_bufctl(slabp)[objnr] = (int)caller; + } objp += obj_dbghead(cachep); if (cachep->ctor && cachep->flags & SLAB_POISON) { unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR; @@ -1951,12 +1972,14 @@ static void free_block(kmem_cache_t *cac objnr = (objp - slabp->s_mem) / cachep->objsize; check_slabp(cachep, slabp); #if DEBUG +#if 0 if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) { printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n", cachep->name, objp); BUG(); } #endif +#endif slab_bufctl(slabp)[objnr] = slabp->free; slabp->free = objnr; STATS_DEC_ACTIVE(cachep); @@ -2693,6 +2716,29 @@ struct seq_operations slabinfo_op = { .show = s_show, }; +static void do_dump_slabp(kmem_cache_t *cachep) +{ +#if DEBUG + struct list_head *q; + + check_irq_on(); + spin_lock_irq(&cachep->spinlock); + list_for_each(q,&cachep->lists.slabs_full) { + struct slab *slabp; + int i; + slabp = list_entry(q, struct slab, list); + for (i = 0; i < cachep->num; i++) { + unsigned long sym = slab_bufctl(slabp)[i]; + + printk("obj %p/%d: %p", slabp, i, (void *)sym); + print_symbol(" <%s>", sym); + printk("\n"); + } + } + spin_unlock_irq(&cachep->spinlock); +#endif +} + #define MAX_SLABINFO_WRITE 128 /** * slabinfo_write - Tuning for the slab allocator @@ -2733,9 +2779,11 @@ ssize_t slabinfo_write(struct file *file batchcount < 1 || batchcount > limit || shared < 0) { - res = -EINVAL; + do_dump_slabp(cachep); + res = 0; } else { - res = do_tune_cpucache(cachep, limit, batchcount, shared); + res = do_tune_cpucache(cachep, limit, + batchcount, shared); } break; } --- linux-2.6.1-rc1/mm/swap.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/swap.c 2003-12-30 22:50:25.000000000 -0800 @@ -348,12 +348,15 @@ void pagevec_strip(struct pagevec *pvec) * The search returns a group of mapping-contiguous pages with ascending * indexes. There may be holes in the indices due to not-present pages. * - * pagevec_lookup() returns the number of pages which were found. + * pagevec_lookup() returns the number of pages which were found + * and also atomically sets the next offset to continue looking up + * mapping contiguous pages from (useful when doing a range of + * pagevec lookups in chunks of PAGEVEC_SIZE). */ unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, - pgoff_t start, unsigned int nr_pages) + pgoff_t *next, unsigned int nr_pages) { - pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages); + pvec->nr = find_get_pages(mapping, next, nr_pages, pvec->pages); return pagevec_count(pvec); } --- linux-2.6.1-rc1/mm/swapfile.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/swapfile.c 2003-12-30 22:49:38.000000000 -0800 @@ -912,7 +912,7 @@ static int setup_swap_extents(struct swa sector_t last_block; int ret; - inode = sis->swap_file->f_dentry->d_inode; + inode = sis->swap_file->f_mapping->host; if (S_ISBLK(inode->i_mode)) { ret = add_swap_extent(sis, 0, sis->max, 0); goto done; @@ -1031,13 +1031,13 @@ asmlinkage long sys_swapoff(const char _ if (IS_ERR(victim)) goto out; - mapping = victim->f_dentry->d_inode->i_mapping; + mapping = victim->f_mapping; prev = -1; swap_list_lock(); for (type = swap_list.head; type >= 0; type = swap_info[type].next) { p = swap_info + type; if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) { - if (p->swap_file->f_dentry->d_inode->i_mapping==mapping) + if (p->swap_file->f_mapping == mapping) break; } prev = type; @@ -1099,13 +1099,12 @@ asmlinkage long sys_swapoff(const char _ swap_device_unlock(p); swap_list_unlock(); vfree(swap_map); - if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) { - struct block_device *bdev; - bdev = swap_file->f_dentry->d_inode->i_bdev; + if (S_ISBLK(mapping->host->i_mode)) { + struct block_device *bdev = I_BDEV(mapping->host); set_blocksize(bdev, p->old_block_size); bd_release(bdev); } else { - up(&swap_file->f_dentry->d_inode->i_mapping->host->i_sem); + up(&mapping->host->i_sem); } filp_close(swap_file, NULL); err = 0; @@ -1231,8 +1230,8 @@ asmlinkage long sys_swapon(const char __ int swapfilesize; unsigned short *swap_map; struct page *page = NULL; - struct inode *inode; - struct inode *downed_inode = NULL; + struct inode *inode = NULL; + int did_down = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1279,8 +1278,8 @@ asmlinkage long sys_swapon(const char __ } p->swap_file = swap_file; - inode = swap_file->f_dentry->d_inode; - mapping = swap_file->f_dentry->d_inode->i_mapping; + mapping = swap_file->f_mapping; + inode = mapping->host; error = -EBUSY; for (i = 0; i < nr_swapfiles; i++) { @@ -1288,32 +1287,32 @@ asmlinkage long sys_swapon(const char __ if (i == type || !q->swap_file) continue; - if (mapping == q->swap_file->f_dentry->d_inode->i_mapping) + if (mapping == q->swap_file->f_mapping) goto bad_swap; } error = -EINVAL; if (S_ISBLK(inode->i_mode)) { - bdev = inode->i_bdev; + bdev = I_BDEV(inode); error = bd_claim(bdev, sys_swapon); if (error < 0) { bdev = NULL; goto bad_swap; } p->old_block_size = block_size(bdev); - error = set_blocksize(inode->i_bdev, PAGE_SIZE); + error = set_blocksize(bdev, PAGE_SIZE); if (error < 0) goto bad_swap; p->bdev = bdev; } else if (S_ISREG(inode->i_mode)) { p->bdev = inode->i_sb->s_bdev; - downed_inode = mapping->host; - down(&downed_inode->i_sem); + down(&inode->i_sem); + did_down = 1; } else { goto bad_swap; } - swapfilesize = i_size_read(mapping->host) >> PAGE_SHIFT; + swapfilesize = i_size_read(inode) >> PAGE_SHIFT; /* * Read the swap header. @@ -1465,8 +1464,8 @@ out: } if (name) putname(name); - if (error && downed_inode) - up(&downed_inode->i_sem); + if (error && did_down) + up(&inode->i_sem); return error; } --- linux-2.6.1-rc1/mm/truncate.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/mm/truncate.c 2003-12-30 22:50:25.000000000 -0800 @@ -122,14 +122,10 @@ void truncate_inode_pages(struct address pagevec_init(&pvec, 0); next = start; - while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + while (pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) { for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; - pgoff_t page_index = page->index; - if (page_index > next) - next = page_index; - next++; if (TestSetPageLocked(page)) continue; if (PageWriteback(page)) { @@ -155,7 +151,7 @@ void truncate_inode_pages(struct address next = start; for ( ; ; ) { - if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + if (!pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) { if (next == start) break; next = start; @@ -166,14 +162,19 @@ void truncate_inode_pages(struct address lock_page(page); wait_on_page_writeback(page); - if (page->index > next) - next = page->index; - next++; truncate_complete_page(mapping, page); unlock_page(page); } pagevec_release(&pvec); } + + if (lstart == 0) { + WARN_ON(mapping->nrpages); + WARN_ON(!list_empty(&mapping->clean_pages)); + WARN_ON(!list_empty(&mapping->dirty_pages)); + WARN_ON(!list_empty(&mapping->locked_pages)); + WARN_ON(!list_empty(&mapping->io_pages)); + } } EXPORT_SYMBOL(truncate_inode_pages); @@ -201,17 +202,13 @@ unsigned long invalidate_mapping_pages(s pagevec_init(&pvec, 0); while (next <= end && - pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) { for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; if (TestSetPageLocked(page)) { - next++; continue; } - if (page->index > next) - next = page->index; - next++; if (PageDirty(page) || PageWriteback(page)) goto unlock; if (page_mapped(page)) @@ -250,14 +247,13 @@ void invalidate_inode_pages2(struct addr int i; pagevec_init(&pvec, 0); - while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + while (pagevec_lookup(&pvec, mapping, &next, PAGEVEC_SIZE)) { for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; lock_page(page); if (page->mapping == mapping) { /* truncate race? */ wait_on_page_writeback(page); - next = page->index + 1; if (page_mapped(page)) clear_page_dirty(page); else --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/mm/usercopy.c 2003-12-30 22:50:19.000000000 -0800 @@ -0,0 +1,291 @@ +/* + * linux/mm/usercopy.c + * + * (C) Copyright 2003 Ingo Molnar + * + * Generic implementation of all the user-VM access functions, without + * relying on being able to access the VM directly. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Get kernel address of the user page and pin it. + */ +static inline struct page *pin_page(unsigned long addr, int write) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + struct page *page = NULL; + int ret; + + /* + * Do a quick atomic lookup first - this is the fastpath. + */ +retry: + page = follow_page(mm, addr, write); + if (likely(page != NULL)) { + if (!PageReserved(page)) + get_page(page); + return page; + } + + /* + * No luck - bad address or need to fault in the page: + */ + + /* Release the lock so get_user_pages can sleep */ + spin_unlock(&mm->page_table_lock); + + /* + * In the context of filemap_copy_from_user(), we are not allowed + * to sleep. We must fail this usercopy attempt and allow + * filemap_copy_from_user() to recover: drop its atomic kmap and use + * a sleeping kmap instead. + */ + if (in_atomic()) { + spin_lock(&mm->page_table_lock); + return NULL; + } + + down_read(&mm->mmap_sem); + ret = get_user_pages(current, mm, addr, 1, write, 0, NULL, NULL); + up_read(&mm->mmap_sem); + spin_lock(&mm->page_table_lock); + + if (ret <= 0) + return NULL; + + /* + * Go try the follow_page again. + */ + goto retry; +} + +static inline void unpin_page(struct page *page) +{ + put_page(page); +} + +/* + * Access another process' address space. + * Source/target buffer must be kernel space, + * Do not walk the page table directly, use get_user_pages + */ +static int rw_vm(unsigned long addr, void *buf, int len, int write) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + + if (!len) + return 0; + + spin_lock(&mm->page_table_lock); + + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + struct page *page = NULL; + int bytes, offset; + void *maddr; + + page = pin_page(addr, write); + if (!page) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap_atomic(page, KM_USER_COPY); + +#define HANDLE_TYPE(type) \ + case sizeof(type): *(type *)(maddr+offset) = *(type *)(buf); break; + + if (write) { + switch (bytes) { + HANDLE_TYPE(char); + HANDLE_TYPE(int); + HANDLE_TYPE(long long); + default: + memcpy(maddr + offset, buf, bytes); + } + } else { +#undef HANDLE_TYPE +#define HANDLE_TYPE(type) \ + case sizeof(type): *(type *)(buf) = *(type *)(maddr+offset); break; + switch (bytes) { + HANDLE_TYPE(char); + HANDLE_TYPE(int); + HANDLE_TYPE(long long); + default: + memcpy(buf, maddr + offset, bytes); + } +#undef HANDLE_TYPE + } + kunmap_atomic(maddr, KM_USER_COPY); + unpin_page(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + spin_unlock(&mm->page_table_lock); + + return len; +} + +static int str_vm(unsigned long addr, void *buf0, int len, int copy) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + struct page *page; + void *buf = buf0; + + if (!len) + return len; + + spin_lock(&mm->page_table_lock); + + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, offset, left, copied; + char *maddr; + + page = pin_page(addr, copy == 2); + if (!page) { + spin_unlock(&mm->page_table_lock); + return -EFAULT; + } + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap_atomic(page, KM_USER_COPY); + if (copy == 2) { + memset(maddr + offset, 0, bytes); + copied = bytes; + left = 0; + } else if (copy == 1) { + left = strncpy_count(buf, maddr + offset, bytes); + copied = bytes - left; + } else { + copied = strnlen(maddr + offset, bytes); + left = bytes - copied; + } + BUG_ON(bytes < 0 || copied < 0); + kunmap_atomic(maddr, KM_USER_COPY); + unpin_page(page); + len -= copied; + buf += copied; + addr += copied; + if (left) + break; + } + spin_unlock(&mm->page_table_lock); + + return len; +} + +/* + * Copies memory from userspace (ptr) into kernelspace (val). + * + * returns # of bytes not copied. + */ +int get_user_size(unsigned int size, void *val, const void *ptr) +{ + int ret; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + ret = __direct_copy_from_user(val, ptr, size); + else + ret = rw_vm((unsigned long)ptr, val, size, 0); + if (ret) + /* + * Zero the rest: + */ + memset(val + size - ret, 0, ret); + return ret; +} + +/* + * Copies memory from kernelspace (val) into userspace (ptr). + * + * returns # of bytes not copied. + */ +int put_user_size(unsigned int size, const void *val, void *ptr) +{ + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return __direct_copy_to_user(ptr, val, size); + else + return rw_vm((unsigned long)ptr, (void *)val, size, 1); +} + +int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr) +{ + int copied, left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + left = strncpy_count(val, ptr, size); + copied = size - left; + BUG_ON(copied < 0); + + return copied; + } + left = str_vm((unsigned long)ptr, val, size, 1); + if (left < 0) + return left; + copied = size - left; + BUG_ON(copied < 0); + + return copied; +} + +int strlen_fromuser_size(unsigned int size, const void *ptr) +{ + int copied, left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + copied = strnlen(ptr, size) + 1; + BUG_ON(copied < 0); + + return copied; + } + left = str_vm((unsigned long)ptr, NULL, size, 0); + if (left < 0) + return 0; + copied = size - left + 1; + BUG_ON(copied < 0); + + return copied; +} + +int zero_user_size(unsigned int size, void *ptr) +{ + int left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + memset(ptr, 0, size); + return 0; + } + left = str_vm((unsigned long)ptr, NULL, size, 2); + if (left < 0) + return size; + return left; +} + +EXPORT_SYMBOL(get_user_size); +EXPORT_SYMBOL(put_user_size); +EXPORT_SYMBOL(zero_user_size); +EXPORT_SYMBOL(copy_str_fromuser_size); +EXPORT_SYMBOL(strlen_fromuser_size); + --- linux-2.6.1-rc1/mm/vmscan.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/mm/vmscan.c 2003-12-30 22:50:01.000000000 -0800 @@ -803,16 +803,15 @@ shrink_zone(struct zone *zone, int max_s * scan then give up on it. */ static int -shrink_caches(struct zone *classzone, int priority, int *total_scanned, +shrink_caches(struct zone **zones, int priority, int *total_scanned, int gfp_mask, int nr_pages, struct page_state *ps) { - struct zone *first_classzone; - struct zone *zone; int ret = 0; + int i; - first_classzone = classzone->zone_pgdat->node_zones; - for (zone = classzone; zone >= first_classzone; zone--) { + for (i = 0; zones[i] != NULL; i++) { int to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX); + struct zone *zone = zones[i]; int nr_mapped = 0; int max_scan; @@ -855,27 +854,27 @@ shrink_caches(struct zone *classzone, in * excessive rotation of the inactive list, which is _supposed_ to be an LRU, * yes? */ -int try_to_free_pages(struct zone *cz, +int try_to_free_pages(struct zone **zones, unsigned int gfp_mask, unsigned int order) { int priority; int ret = 0; const int nr_pages = SWAP_CLUSTER_MAX; int nr_reclaimed = 0; - struct zone *zone; struct reclaim_state *reclaim_state = current->reclaim_state; + int i; inc_page_state(allocstall); - for (zone = cz; zone >= cz->zone_pgdat->node_zones; --zone) - zone->temp_priority = DEF_PRIORITY; + for (i = 0; zones[i] != 0; i++) + zones[i]->temp_priority = DEF_PRIORITY; for (priority = DEF_PRIORITY; priority >= 0; priority--) { int total_scanned = 0; struct page_state ps; get_page_state(&ps); - nr_reclaimed += shrink_caches(cz, priority, &total_scanned, + nr_reclaimed += shrink_caches(zones, priority, &total_scanned, gfp_mask, nr_pages, &ps); if (nr_reclaimed >= nr_pages) { ret = 1; @@ -892,7 +891,7 @@ int try_to_free_pages(struct zone *cz, /* Take a nap, wait for some writeback to complete */ blk_congestion_wait(WRITE, HZ/10); - if (cz - cz->zone_pgdat->node_zones < ZONE_HIGHMEM) { + if (zones[0] - zones[0]->zone_pgdat->node_zones < ZONE_HIGHMEM) { shrink_slab(total_scanned, gfp_mask); if (reclaim_state) { nr_reclaimed += reclaim_state->reclaimed_slab; @@ -903,8 +902,8 @@ int try_to_free_pages(struct zone *cz, if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) out_of_memory(); out: - for (zone = cz; zone >= cz->zone_pgdat->node_zones; --zone) - zone->prev_priority = zone->temp_priority; + for (i = 0; zones[i] != 0; i++) + zones[i]->prev_priority = zones[i]->temp_priority; return ret; } --- linux-2.6.1-rc1/net/atm/clip.c 2003-10-17 15:58:05.000000000 -0700 +++ 25/net/atm/clip.c 2003-12-30 22:49:20.000000000 -0800 @@ -563,32 +563,20 @@ static int clip_setentry(struct atm_vcc } -static int clip_init(struct net_device *dev) +static void clip_setup(struct net_device *dev) { - DPRINTK("clip_init %s\n",dev->name); dev->hard_start_xmit = clip_start_xmit; /* sg_xmit ... */ - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->hard_header_parse = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; - dev->change_mtu = NULL; - dev->do_ioctl = NULL; dev->get_stats = clip_get_stats; dev->type = ARPHRD_ATM; dev->hard_header_len = RFC1483LLC_LEN; dev->mtu = RFC1626_MTU; - dev->addr_len = 0; dev->tx_queue_len = 100; /* "normal" queue (packets) */ /* When using a "real" qdisc, the qdisc determines the queue */ /* length. tx_queue_len is only used for the default case, */ /* without any more elaborate queuing. 100 is a reasonable */ /* compromise between decent burst-tolerance and protection */ /* against memory hogs. */ - dev->flags = 0; - return 0; } @@ -608,18 +596,16 @@ static int clip_create(int number) if (PRIV(dev)->number >= number) number = PRIV(dev)->number+1; } - dev = kmalloc(sizeof(struct net_device)+sizeof(struct clip_priv), - GFP_KERNEL); - if (!dev) return -ENOMEM; - memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv)); + dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup); + if (!dev) + return -ENOMEM; clip_priv = PRIV(dev); sprintf(dev->name,"atm%d",number); - dev->init = clip_init; spin_lock_init(&clip_priv->xoff_lock); clip_priv->number = number; error = register_netdev(dev); if (error) { - kfree(dev); + free_netdev(dev); return error; } clip_priv->next = clip_devs; @@ -634,7 +620,7 @@ static int clip_device_event(struct noti { /* ignore non-CLIP devices */ if (((struct net_device *) dev)->type != ARPHRD_ATM || - ((struct net_device *) dev)->init != clip_init) + ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit) return NOTIFY_DONE; switch (event) { case NETDEV_UP: --- linux-2.6.1-rc1/net/bridge/br_if.c 2003-07-27 12:14:40.000000000 -0700 +++ 25/net/bridge/br_if.c 2003-12-30 22:49:20.000000000 -0800 @@ -172,7 +172,7 @@ int br_add_bridge(const char *name) ret = register_netdev(br->dev); if (ret) - kfree(br->dev); + free_netdev(br->dev); return ret; } --- linux-2.6.1-rc1/net/core/dev.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/net/core/dev.c 2003-12-30 22:49:27.000000000 -0800 @@ -105,6 +105,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ #include @@ -371,6 +372,30 @@ int netdev_boot_setup_check(struct net_d return 0; } + +/** + * netdev_boot_base - get address from boot time settings + * @prefix: prefix for network device + * @unit: id for network device + * + * Check boot time settings for the base address of device. + * The found settings are set for the device to be used + * later in the device probing. + * Returns 0 if no settings found. + */ +unsigned long netdev_boot_base(const char *prefix, int unit) +{ + const struct netdev_boot_setup *s = dev_boot_setup; + char name[IFNAMSIZ]; + int i; + + sprintf(name, "%s%d", prefix, unit); + for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) + if (!strcmp(name, s[i].name)) + return s[i].map.base_addr; + return 0; +} + /* * Saves at boot time configured settings for any netdevice. */ @@ -1380,7 +1405,6 @@ static void sample_queue(unsigned long d } #endif - /** * netif_rx - post buffer to the network code * @skb: buffer to post @@ -1405,6 +1429,13 @@ int netif_rx(struct sk_buff *skb) struct softnet_data *queue; unsigned long flags; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1560,6 +1591,13 @@ int netif_receive_skb(struct sk_buff *sk int ret = NET_RX_DROP; unsigned short type = skb->protocol; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1684,7 +1722,6 @@ static void net_rx_action(struct softirq unsigned long start_time = jiffies; int budget = netdev_max_backlog; - preempt_disable(); local_irq_disable(); @@ -1711,6 +1748,10 @@ static void net_rx_action(struct softirq dev_put(dev); local_irq_disable(); } + +#ifdef CONFIG_KGDBOE + kgdb_process_breakpoint(); +#endif } out: local_irq_enable(); @@ -2875,7 +2916,7 @@ void free_netdev(struct net_device *dev) { /* Compatiablity with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { - kfree(dev); + kfree((char *)dev - dev->padded); return; } --- linux-2.6.1-rc1/net/core/Makefile 2003-09-08 13:58:59.000000000 -0700 +++ 25/net/core/Makefile 2003-12-30 22:49:20.000000000 -0800 @@ -13,3 +13,4 @@ obj-$(CONFIG_NETFILTER) += netfilter.o obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NET_RADIO) += wireless.o +obj-$(CONFIG_NETPOLL) += netpoll.o --- linux-2.6.1-rc1/net/core/neighbour.c 2003-12-30 22:37:22.000000000 -0800 +++ 25/net/core/neighbour.c 2003-12-30 22:49:38.000000000 -0800 @@ -24,6 +24,7 @@ #ifdef CONFIG_SYSCTL #include #endif +#include #include #include #include @@ -1510,7 +1511,7 @@ struct neigh_sysctl_table { .procname = "retrans_time", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_REACHABLE_TIME, @@ -1555,21 +1556,21 @@ struct neigh_sysctl_table { .procname = "anycast_delay", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_PROXY_DELAY, .procname = "proxy_delay", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_LOCKTIME, .procname = "locktime", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_GC_INTERVAL, --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/net/core/netpoll.c 2003-12-30 22:49:20.000000000 -0800 @@ -0,0 +1,642 @@ +/* + * Common framework for low-level network console, dump, and debugger code + * + * Sep 8 2003 Matt Mackall + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * We maintain a small pool of fully-sized skbs, to make sure the + * message gets out even in extreme OOM situations. + */ + +#define MAX_SKBS 32 +#define MAX_UDP_CHUNK 1460 + +static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED; +static int nr_skbs; +static struct sk_buff *skbs; + +static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(rx_list); + +static int trapped; + +#define MAX_SKB_SIZE \ + (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ + sizeof(struct iphdr) + sizeof(struct ethhdr)) + +static void zap_completion_queue(void); + +static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, + unsigned short ulen, u32 saddr, u32 daddr) +{ + if (uh->check == 0) + return 0; + + if (skb->ip_summed == CHECKSUM_HW) + return csum_tcpudp_magic( + saddr, daddr, ulen, IPPROTO_UDP, skb->csum); + + skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + + return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); +} + +void netpoll_poll(struct netpoll *np) +{ + int budget = 1; + + if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller) + return; + + /* Process pending work on NIC */ + np->dev->poll_controller(np->dev); + + /* If scheduling is stopped, tickle NAPI bits */ + if(trapped && np->dev->poll && + test_bit(__LINK_STATE_RX_SCHED, &np->dev->state)) + np->dev->poll(np->dev, &budget); + zap_completion_queue(); +} + +static void refill_skbs(void) +{ + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&skb_list_lock, flags); + while (nr_skbs < MAX_SKBS) { + skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC); + if (!skb) + break; + + skb->next = skbs; + skbs = skb; + nr_skbs++; + } + spin_unlock_irqrestore(&skb_list_lock, flags); +} + +static void zap_completion_queue(void) +{ + unsigned long flags; + struct softnet_data *sd = &get_cpu_var(softnet_data); + + if (sd->completion_queue) { + struct sk_buff *clist; + + local_irq_save(flags); + clist = sd->completion_queue; + sd->completion_queue = NULL; + local_irq_restore(flags); + + while (clist != NULL) { + struct sk_buff *skb = clist; + clist = clist->next; + __kfree_skb(skb); + } + } + + put_cpu_var(softnet_data); +} + +static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve) +{ + int once = 1, count = 0; + unsigned long flags; + struct sk_buff *skb = NULL; + + zap_completion_queue(); +repeat: + if (nr_skbs < MAX_SKBS) + refill_skbs(); + + skb = alloc_skb(len, GFP_ATOMIC); + + if (!skb) { + spin_lock_irqsave(&skb_list_lock, flags); + skb = skbs; + if (skb) + skbs = skb->next; + skb->next = NULL; + nr_skbs--; + spin_unlock_irqrestore(&skb_list_lock, flags); + } + + if(!skb) { + count++; + if (once && (count == 1000000)) { + printk("out of netpoll skbs!\n"); + once = 0; + } + netpoll_poll(np); + goto repeat; + } + + atomic_set(&skb->users, 1); + skb_reserve(skb, reserve); + return skb; +} + +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) +{ + int status; + +repeat: + if(!np || !np->dev || !netif_running(np->dev)) { + __kfree_skb(skb); + return; + } + + spin_lock(&np->dev->xmit_lock); + np->dev->xmit_lock_owner = smp_processor_id(); + + if (netif_queue_stopped(np->dev)) { + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + netpoll_poll(np); + goto repeat; + } + + status = np->dev->hard_start_xmit(skb, np->dev); + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + /* transmit busy */ + if(status) + goto repeat; +} + +void netpoll_send_udp(struct netpoll *np, const char *msg, int len) +{ + int total_len, eth_len, ip_len, udp_len; + struct sk_buff *skb; + struct udphdr *udph; + struct iphdr *iph; + struct ethhdr *eth; + + udp_len = len + sizeof(*udph); + ip_len = eth_len = udp_len + sizeof(*iph); + total_len = eth_len + ETH_HLEN; + + skb = find_skb(np, total_len, total_len - len); + if (!skb) + return; + + memcpy(skb->data, msg, len); + skb->len += len; + + udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); + udph->source = htons(np->local_port); + udph->dest = htons(np->remote_port); + udph->len = htons(udp_len); + udph->check = 0; + + iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); + + iph->version = 4; + iph->ihl = 5; + iph->tos = 0; + iph->tot_len = htons(ip_len); + iph->id = 0; + iph->frag_off = 0; + iph->ttl = 64; + iph->protocol = IPPROTO_UDP; + iph->check = 0; + iph->saddr = htonl(np->local_ip); + iph->daddr = htonl(np->remote_ip); + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); + + eth->h_proto = htons(ETH_P_IP); + memcpy(eth->h_source, np->local_mac, 6); + memcpy(eth->h_dest, np->remote_mac, 6); + + netpoll_send_skb(np, skb); +} + +static void arp_reply(struct sk_buff *skb) +{ + struct in_device *in_dev = (struct in_device *) skb->dev->ip_ptr; + struct arphdr *arp; + unsigned char *arp_ptr, *sha, *tha; + int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; + u32 sip, tip; + struct sk_buff *send_skb; + unsigned long flags; + struct list_head *p; + struct netpoll *np = 0; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if ( np->dev == skb->dev ) + break; + np = 0; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (!np) return; + + /* No arp on this interface */ + if (!in_dev || skb->dev->flags & IFF_NOARP) + return; + + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * skb->dev->addr_len) + + (2 * sizeof(u32))))) + return; + + skb->h.raw = skb->nh.raw = skb->data; + arp = skb->nh.arph; + + if ((arp->ar_hrd != htons(ARPHRD_ETHER) && + arp->ar_hrd != htons(ARPHRD_IEEE802)) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr= (unsigned char *)(arp+1); + sha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4; + tha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + /* Should we ignore arp? */ + if (tip != in_dev->ifa_list->ifa_address || + LOOPBACK(tip) || MULTICAST(tip)) + return; + + + size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4); + send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev), + LL_RESERVED_SPACE(np->dev)); + + if (!send_skb) + return; + + send_skb->nh.raw = send_skb->data; + arp = (struct arphdr *) skb_put(send_skb, size); + send_skb->dev = skb->dev; + send_skb->protocol = htons(ETH_P_ARP); + + /* Fill the device header for the ARP frame */ + + if (np->dev->hard_header && + np->dev->hard_header(send_skb, skb->dev, ptype, + np->remote_mac, np->local_mac, + send_skb->len) < 0) { + kfree_skb(send_skb); + return; + } + + /* + * Fill out the arp protocol part. + * + * we only support ethernet device type, + * which (according to RFC 1390) should always equal 1 (Ethernet). + */ + + arp->ar_hrd = htons(np->dev->type); + arp->ar_pro = htons(ETH_P_IP); + arp->ar_hln = np->dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr=(unsigned char *)(arp + 1); + memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &tip, 4); + arp_ptr += 4; + memcpy(arp_ptr, np->local_mac, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &sip, 4); + + netpoll_send_skb(np, send_skb); +} + +int netpoll_rx(struct sk_buff *skb) +{ + int proto, len, ulen; + struct iphdr *iph; + struct udphdr *uh; + struct netpoll *np; + struct list_head *p; + unsigned long flags; + + if (skb->dev->type != ARPHRD_ETHER) + goto out; + + /* check if netpoll clients need ARP */ + if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) { + arp_reply(skb); + return 1; + } + + proto = ntohs(skb->mac.ethernet->h_proto); + if (proto != ETH_P_IP) + goto out; + if (skb->pkt_type == PACKET_OTHERHOST) + goto out; + if (skb_shared(skb)) + goto out; + + iph = (struct iphdr *)skb->data; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + if (iph->ihl < 5 || iph->version != 4) + goto out; + if (!pskb_may_pull(skb, iph->ihl*4)) + goto out; + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) + goto out; + + len = ntohs(iph->tot_len); + if (skb->len < len || len < iph->ihl*4) + goto out; + + if (iph->protocol != IPPROTO_UDP) + goto out; + + len -= iph->ihl*4; + uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); + ulen = ntohs(uh->len); + + if (ulen != len) + goto out; + if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0) + goto out; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if (np->dev && np->dev != skb->dev) + continue; + if (np->local_ip && np->local_ip != ntohl(iph->daddr)) + continue; + if (np->remote_ip && np->remote_ip != ntohl(iph->saddr)) + continue; + if (np->local_port && np->local_port != ntohs(uh->dest)) + continue; + + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (np->rx_hook) + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), ulen-sizeof(uh)-4); + + return 1; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + +out: + return trapped; +} + +int netpoll_parse_options(struct netpoll *np, char *opt) +{ + char *cur=opt, *delim; + + if(*cur != '@') { + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->local_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); + + if(*cur != '/') { + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->local_ip=ntohl(in_aton(cur)); + cur=delim; + + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + cur++; + + if ( *cur != ',') { + /* parse out dev name */ + if ((delim = strchr(cur, ',')) == NULL) + goto parse_failed; + *delim=0; + strlcpy(np->dev_name, cur, sizeof(np->dev_name)); + cur=delim; + } + cur++; + + printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); + + if ( *cur != '@' ) { + /* dst port */ + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->remote_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); + + /* dst ip */ + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->remote_ip=ntohl(in_aton(cur)); + cur=delim+1; + + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + + if( *cur != 0 ) + { + /* MAC address */ + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[0]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[1]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[2]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[3]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[4]=simple_strtol(cur, 0, 16); + cur=delim+1; + np->remote_mac[5]=simple_strtol(cur, 0, 16); + } + + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); + + return 0; + + parse_failed: + printk(KERN_INFO "%s: couldn't parse config at %s!\n", + np->name, cur); + return -1; +} + +int netpoll_setup(struct netpoll *np) +{ + struct net_device *ndev = NULL; + struct in_device *in_dev; + + if (np->dev_name) + ndev = dev_get_by_name(np->dev_name); + if (!ndev) { + printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", + np->name, np->dev_name); + goto release; + } + if (!ndev->poll_controller) { + printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", + np->name, np->dev_name); + goto release; + } + + if (!(ndev->flags & IFF_UP)) { + unsigned short oflags; + unsigned long jiff; + + printk(KERN_INFO "%s: device %s not up yet, forcing it\n", + np->name, np->dev_name); + + oflags = ndev->flags; + + rtnl_shlock(); + if (dev_change_flags(ndev, oflags | IFF_UP) < 0) { + printk(KERN_ERR "%s: failed to open %s\n", + np->name, np->dev_name); + rtnl_shunlock(); + goto release; + } + rtnl_shunlock(); + + jiff = jiffies + 6*HZ; + while(!netif_carrier_ok(ndev)) { + if (!time_before(jiffies, jiff)) { + printk(KERN_NOTICE + "%s: timeout waiting for carrier\n", + np->name); + break; + } + cond_resched(); + } + + } + + if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr) + memcpy(np->local_mac, ndev->dev_addr, 6); + + if (!np->local_ip) { + in_dev = in_dev_get(ndev); + + if (!in_dev) { + printk(KERN_ERR "%s: no IP address for %s, aborting\n", + np->name, np->dev_name); + goto release; + } + + np->local_ip = ntohl(in_dev->ifa_list->ifa_local); + in_dev_put(in_dev); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + + np->dev = ndev; + + if(np->rx_hook) { + unsigned long flags; + +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 1; +#endif + + spin_lock_irqsave(&rx_list_lock, flags); + list_add(&np->rx_list, &rx_list); + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + return 0; + release: + dev_put(ndev); + return -1; +} + +void netpoll_cleanup(struct netpoll *np) +{ + if(np->rx_hook) { + unsigned long flags; + + spin_lock_irqsave(&rx_list_lock, flags); + list_del(&np->rx_list); +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 0; +#endif + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + dev_put(np->dev); + np->dev = 0; +} + +int netpoll_trap() +{ + return trapped; +} + +void netpoll_set_trap(int trap) +{ + trapped = trap; +} + +EXPORT_SYMBOL(netpoll_set_trap); +EXPORT_SYMBOL(netpoll_trap); +EXPORT_SYMBOL(netpoll_parse_options); +EXPORT_SYMBOL(netpoll_setup); +EXPORT_SYMBOL(netpoll_cleanup); +EXPORT_SYMBOL(netpoll_send_skb); +EXPORT_SYMBOL(netpoll_send_udp); +EXPORT_SYMBOL(netpoll_poll); --- linux-2.6.1-rc1/net/core/net-sysfs.c 2003-10-25 14:45:46.000000000 -0700 +++ 25/net/core/net-sysfs.c 2003-12-30 22:49:20.000000000 -0800 @@ -372,7 +372,7 @@ static void netdev_release(struct class_ BUG_ON(dev->reg_state != NETREG_RELEASED); - kfree(dev); + kfree((char *)dev - dev->padded); } static struct class net_class = { --- linux-2.6.1-rc1/net/ipv4/route.c 2003-11-23 19:03:03.000000000 -0800 +++ 25/net/ipv4/route.c 2003-12-30 22:50:15.000000000 -0800 @@ -2703,12 +2703,9 @@ static int ip_rt_acct_read(char *buffer, memcpy(dst, src, length); /* Add the other cpus in, one int at a time */ - for (i = 1; i < NR_CPUS; i++) { + for_each_cpu(i) { unsigned int j; - if (!cpu_online(i)) - continue; - src = ((u32 *) IP_RT_ACCT_CPU(i)) + offset; for (j = 0; j < length/4; j++) --- linux-2.6.1-rc1/net/Kconfig 2003-11-23 19:03:02.000000000 -0800 +++ 25/net/Kconfig 2003-12-30 22:49:27.000000000 -0800 @@ -664,4 +664,19 @@ source "net/irda/Kconfig" source "net/bluetooth/Kconfig" +config KGDBOE + def_bool X86 && KGDB + +config NETPOLL + def_bool NETCONSOLE || KGDBOE + +config NETPOLL_RX + def_bool KGDBOE + +config NETPOLL_TRAP + def_bool KGDBOE + +config NET_POLL_CONTROLLER + def_bool NETPOLL + endmenu --- linux-2.6.1-rc1/net/socket.c 2003-11-23 19:03:03.000000000 -0800 +++ 25/net/socket.c 2003-12-30 22:49:34.000000000 -0800 @@ -394,6 +394,7 @@ int sock_map_fd(struct socket *sock) file->f_dentry->d_op = &sockfs_dentry_operations; d_add(file->f_dentry, SOCK_INODE(sock)); file->f_vfsmnt = mntget(sock_mnt); + file->f_mapping = file->f_dentry->d_inode->i_mapping; sock->file = file; file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops; --- linux-2.6.1-rc1/net/wanrouter/wanmain.c 2003-09-27 18:57:47.000000000 -0700 +++ 25/net/wanrouter/wanmain.c 2003-12-30 22:49:20.000000000 -0800 @@ -726,8 +726,6 @@ static int wanrouter_device_new_if(struc if (dev->name == NULL) { err = -EINVAL; - } else if (dev_get(dev->name)) { - err = -EEXIST; /* name already exists */ } else { #ifdef WANDEBUG --- linux-2.6.1-rc1/sound/i2c/i2c.c 2003-06-14 12:18:09.000000000 -0700 +++ 25/sound/i2c/i2c.c 2003-12-30 22:49:57.000000000 -0800 @@ -84,7 +84,7 @@ int snd_i2c_bus_create(snd_card_t *card, bus = (snd_i2c_bus_t *)snd_magic_kcalloc(snd_i2c_bus_t, 0, GFP_KERNEL); if (bus == NULL) return -ENOMEM; - spin_lock_init(&bus->lock); + init_MUTEX(&bus->lock_mutex); INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->buses); bus->card = card; --- linux-2.6.1-rc1/sound/isa/gus/gus_pcm.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/sound/isa/gus/gus_pcm.c 2003-12-30 22:50:00.000000000 -0800 @@ -334,9 +334,11 @@ static int snd_gf1_pcm_poke_block(snd_gu snd_gf1_poke(gus, pos++, *buf++ ^ invert); } } - schedule_timeout(1); - if (signal_pending(current)) - return -EAGAIN; + if (count > 0 && !in_interrupt()) { + schedule_timeout(1); + if (signal_pending(current)) + return -EAGAIN; + } } return 0; } --- linux-2.6.1-rc1/sound/oss/trident.c 2003-10-17 15:58:05.000000000 -0700 +++ 25/sound/oss/trident.c 2003-12-30 22:50:09.000000000 -0800 @@ -1,5 +1,5 @@ /* - * OSS driver for Linux 2.4.x for + * OSS driver for Linux 2.[46].x for * * Trident 4D-Wave * SiS 7018 @@ -21,7 +21,6 @@ * Peter Wächtler CyberPro5050 support * Muli Ben-Yehuda * - * * 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 @@ -37,6 +36,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.14.10i + * December 29 2003 Muli Ben-Yehuda + * major cleanup for 2.6, fix a few error patch buglets + * with returning without properly cleaning up first, + * get rid of lock_kernel(). * v0.14.10h * Sept 10 2002 Pascal Schmidt * added support for ALi 5451 joystick port @@ -218,36 +222,37 @@ #include "trident.h" -#define DRIVER_VERSION "0.14.10h-2.5" +#define DRIVER_VERSION "0.14.10i-2.6" /* magic numbers to protect our data structures */ -#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ -#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ +#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ +#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ -#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */ -#define ALI_DMA_MASK 0x7fffffff /* ALI Tridents have 31-bit DMA. Wow. */ +#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */ +#define ALI_DMA_MASK 0x7fffffff /* ALI Tridents have 31-bit DMA. Wow. */ #define NR_HW_CH 32 /* maximum number of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only have 2 SDATA_IN lines (currently) */ -#define NR_AC97 2 +#define NR_AC97 2 /* minor number of /dev/swmodem (temporary, experimental) */ #define SND_DEV_SWMODEM 7 -static const unsigned ali_multi_channels_5_1[] = { - /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/ - ALI_CENTER_CHANNEL, - ALI_LEF_CHANNEL, - ALI_SURR_LEFT_CHANNEL, +static const unsigned ali_multi_channels_5_1[] = { + /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL, */ + ALI_CENTER_CHANNEL, + ALI_LEF_CHANNEL, + ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL }; static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; -static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n"; +static const char invalid_magic[] = + KERN_CRIT "trident: invalid magic value in %s\n"; enum { TRIDENT_4D_DX = 0, @@ -257,7 +262,7 @@ enum { CYBER5050 }; -static char * card_names[] = { +static char *card_names[] = { "Trident 4DWave DX", "Trident 4DWave NX", "SiS 7018 PCI Audio", @@ -265,7 +270,7 @@ static char * card_names[] = { "Tvia/IGST CyberPro 5050" }; -static struct pci_device_id trident_pci_tbl [] = { +static struct pci_device_id trident_pci_tbl[] = { {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX}, {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, @@ -274,12 +279,12 @@ static struct pci_device_id trident_pci_ PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018}, {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI_5451}, - { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5050, + {PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CYBER5050}, {0,} }; -MODULE_DEVICE_TABLE (pci, trident_pci_tbl); +MODULE_DEVICE_TABLE(pci, trident_pci_tbl); /* "software" or virtual channel, an instance of opened /dev/dsp */ struct trident_state { @@ -308,12 +313,12 @@ struct trident_state { unsigned fragshift; /* our buffer acts like a circular ring */ - unsigned hwptr; /* where dma last started, updated by update_ptr */ - unsigned swptr; /* where driver last clear/filled, updated by read/write */ - int count; /* bytes to be comsumed or been generated by dma machine */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ + unsigned swptr; /* where driver last clear/filled, updated by read/write */ + int count; /* bytes to be comsumed or been generated by dma machine */ unsigned total_bytes; /* total bytes dmaed by hardware */ - unsigned error; /* number of over/underruns */ + unsigned error; /* number of over/underruns */ wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ /* redundant, but makes calculations easier */ @@ -329,14 +334,14 @@ struct trident_state { unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; - + } dmabuf; - /* 5.1 channels */ + /* 5.1 channels */ struct trident_state *other_states[4]; int multi_channels_adjust_count; unsigned chans_num; - unsigned fmt_flag:1; + unsigned long fmt_flag; /* Guard against mmap/write/read races */ struct semaphore sem; @@ -344,13 +349,13 @@ struct trident_state { /* hardware channels */ struct trident_channel { - int num; /* channel number */ - u32 lba; /* Loop Begine Address, where dma buffer starts */ - u32 eso; /* End Sample Offset, wehre dma buffer ends (in the unit of samples) */ - u32 delta; /* delta value, sample rate / 48k for playback, 48k/sample rate for recording */ - u16 attribute; /* control where PCM data go and come */ + int num; /* channel number */ + u32 lba; /* Loop Begine Address, where dma buffer starts */ + u32 eso; /* End Sample Offset, wehre dma buffer ends (in the unit of samples) */ + u32 delta; /* delta value, sample rate / 48k for playback, 48k/sample rate for recording */ + u16 attribute; /* control where PCM data go and come */ u16 fm_vol; - u32 control; /* signed/unsigned, 8/16 bits, mono/stereo */ + u32 control; /* signed/unsigned, 8/16 bits, mono/stereo */ }; struct trident_pcm_bank_address { @@ -360,16 +365,14 @@ struct trident_pcm_bank_address { u32 aint_en; }; -static struct trident_pcm_bank_address bank_a_addrs = -{ +static struct trident_pcm_bank_address bank_a_addrs = { T4D_START_A, T4D_STOP_A, T4D_AINT_A, T4D_AINTEN_A }; -static struct trident_pcm_bank_address bank_b_addrs = -{ +static struct trident_pcm_bank_address bank_b_addrs = { T4D_START_B, T4D_STOP_B, T4D_AINT_B, @@ -380,7 +383,7 @@ struct trident_pcm_bank { /* register addresses to control bank operations */ struct trident_pcm_bank_address *addresses; /* each bank has 32 channels */ - u32 bitmap; /* channel allocation bitmap */ + u32 bitmap; /* channel allocation bitmap */ struct trident_channel channels[32]; }; @@ -396,16 +399,16 @@ struct trident_card { /* The trident has a certain amount of cross channel interaction so we use a single per card lock */ spinlock_t lock; - + /* PCI device stuff */ - struct pci_dev * pci_dev; + struct pci_dev *pci_dev; u16 pci_id; u8 revision; /* soundcore stuff */ int dev_audio; - /* structures for abstraction of hardware facilities, codecs, banks and channels*/ + /* structures for abstraction of hardware facilities, codecs, banks and channels */ struct ac97_codec *ac97_codec[NR_AC97]; struct trident_pcm_bank banks[NR_BANKS]; struct trident_state *states[NR_HW_CH]; @@ -413,13 +416,14 @@ struct trident_card { /* hardware resources */ unsigned long iobase; u32 irq; - + /* Function support */ - struct trident_channel *(*alloc_pcm_channel)(struct trident_card *); - struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *); - void (*free_pcm_channel)(struct trident_card *, unsigned int chan); - void (*address_interrupt)(struct trident_card *); - + struct trident_channel *(*alloc_pcm_channel) (struct trident_card *); + struct trident_channel *(*alloc_rec_pcm_channel) (struct trident_card + *); + void (*free_pcm_channel) (struct trident_card *, unsigned int chan); + void (*address_interrupt) (struct trident_card *); + /* Added by Matt Wu 01-05-2001 for spdif in */ int multi_channel_use_count; int rec_channel_use_count; @@ -434,16 +438,20 @@ struct trident_card { struct gameport gameport; }; +enum dmabuf_mode { + DM_PLAYBACK = 0, + DM_RECORD +}; + /* table to map from CHANNELMASK to channel attribute for SiS 7018 */ -static u16 mask2attr [] = -{ +static u16 mask2attr[] = { PCM_LR, PCM_LR, SURR_LR, CENTER_LFE, HSET, MIC, MODEM_LINE1, MODEM_LINE2, I2S_LR, SPDIF_LR }; /* table to map from channel attribute to CHANNELMASK for SiS 7018 */ -static int attr2mask [] = { +static int attr2mask[] = { DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET, DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF }; @@ -462,20 +470,24 @@ static void trident_ac97_set(struct ac97 static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg); static int trident_open_mixdev(struct inode *inode, struct file *file); -static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg); +static int trident_ioctl_mixdev(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); -static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val); +static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, + u16 val); static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg); -static void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate); +static void ali_set_spdif_out_rate(struct trident_card *card, + unsigned int rate); static void ali_enable_special_channel(struct trident_state *stat); -static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card); +static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card + *card); static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card); static void ali_restore_regs(struct trident_card *card); static void ali_save_regs(struct trident_card *card); static int trident_suspend(struct pci_dev *dev, u32 unused); static int trident_resume(struct pci_dev *dev); -static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel); +static void ali_free_pcm_channel(struct trident_card *card, + unsigned int channel); static int ali_setup_multi_channels(struct trident_card *card, int chan_nums); static unsigned int ali_get_spdif_in_rate(struct trident_card *card); static void ali_setup_spdif_in(struct trident_card *card); @@ -483,13 +495,12 @@ static void ali_disable_spdif_in(struct static void ali_disable_special_channel(struct trident_card *card, int ch); static void ali_setup_spdif_out(struct trident_card *card, int flag); static int ali_write_5_1(struct trident_state *state, const char *buffer, - int cnt_for_multi_channel, unsigned int *copy_count, + int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt); -static int ali_allocate_other_states_resources(struct trident_state *state, +static int ali_allocate_other_states_resources(struct trident_state *state, int chan_nums); static void ali_free_other_states_resources(struct trident_state *state); - /* save registers for ALi Power Management */ static struct ali_saved_registers { unsigned long global_regs[ALI_GLOBAL_REGS]; @@ -497,40 +508,37 @@ static struct ali_saved_registers { unsigned mixer_regs[ALI_MIXER_REGS]; } ali_registers; -#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) do { \ - (dma_ptr) += (offset); \ - (buffer) += (offset); \ - (cnt) -= (offset); \ - (copy_count) += (offset); \ +#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) \ +do { \ + (dma_ptr) += (offset); \ + (buffer) += (offset); \ + (cnt) -= (offset); \ + (copy_count) += (offset); \ } while (0) - -#define lock_set_fmt(state) do { \ - spin_lock_irqsave(&state->card->lock, flags); \ - if (state->fmt_flag) { \ - spin_unlock_irqrestore(&state->card->lock, flags); \ - return -EFAULT; \ - } \ - state->fmt_flag = 1; \ - spin_unlock_irqrestore(&state->card->lock, flags); \ -} while (0) - -#define unlock_set_fmt(state) do { \ - spin_lock_irqsave(&state->card->lock, flags); \ - state->fmt_flag = 0; \ - spin_unlock_irqrestore(&state->card->lock, flags); \ -} while (0) +static inline int lock_set_fmt(struct trident_state* state) +{ + if (test_and_set_bit(0, &state->fmt_flag)) + return -EFAULT; -static int trident_enable_loop_interrupts(struct trident_card * card) + return 0; +} + +static inline void unlock_set_fmt(struct trident_state* state) +{ + clear_bit(0, &state->fmt_flag); +} + +static int +trident_enable_loop_interrupts(struct trident_card *card) { u32 global_control; global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR)); - switch (card->pci_id) - { + switch (card->pci_id) { case PCI_DEVICE_ID_SI_7018: - global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN); + global_control |= (ENDLP_IE | MIDLP_IE | BANK_B_EN); break; case PCI_DEVICE_ID_ALI_5451: case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: @@ -539,7 +547,7 @@ static int trident_enable_loop_interrupt global_control |= (ENDLP_IE | MIDLP_IE); break; default: - return FALSE; + return 0; } outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR)); @@ -547,10 +555,11 @@ static int trident_enable_loop_interrupt TRDBG("trident: Enable Loop Interrupts, globctl = 0x%08X\n", inl(TRID_REG(card, T4D_LFO_GC_CIR))); - return (TRUE); + return 1; } -static int trident_disable_loop_interrupts(struct trident_card * card) +static int +trident_disable_loop_interrupts(struct trident_card *card) { u32 global_control; @@ -561,10 +570,11 @@ static int trident_disable_loop_interrup TRDBG("trident: Disabled Loop Interrupts, globctl = 0x%08X\n", global_control); - return (TRUE); + return 1; } -static void trident_enable_voice_irq(struct trident_card * card, unsigned int channel) +static void +trident_enable_voice_irq(struct trident_card *card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; @@ -577,31 +587,35 @@ static void trident_enable_voice_irq(str #ifdef DEBUG reg = inl(TRID_REG(card, addr)); TRDBG("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n", - channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr); -#endif /* DEBUG */ + channel, addr == T4D_AINTEN_B ? "AINTEN_B" : "AINTEN_A", reg, + addr); +#endif /* DEBUG */ } -static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel) +static void +trident_disable_voice_irq(struct trident_card *card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; u32 reg, addr = bank->addresses->aint_en; - + reg = inl(TRID_REG(card, addr)); reg &= ~mask; outl(reg, TRID_REG(card, addr)); - + /* Ack the channel in case the interrupt was set before we disable it. */ outl(mask, TRID_REG(card, bank->addresses->aint)); #ifdef DEBUG reg = inl(TRID_REG(card, addr)); TRDBG("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n", - channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr); + channel, addr == T4D_AINTEN_B ? "AINTEN_B" : "AINTEN_A", reg, + addr); #endif /* DEBUG */ } -static void trident_start_voice(struct trident_card * card, unsigned int channel) +static void +trident_start_voice(struct trident_card *card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; @@ -613,14 +627,15 @@ static void trident_start_voice(struct t outl(mask, TRID_REG(card, addr)); -#ifdef DEBUG +#ifdef DEBUG reg = inl(TRID_REG(card, addr)); TRDBG("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n", - channel, addr==T4D_START_B? "START_B":"START_A",reg,addr); + channel, addr == T4D_START_B ? "START_B" : "START_A", reg, addr); #endif /* DEBUG */ } -static void trident_stop_voice(struct trident_card * card, unsigned int channel) +static void +trident_stop_voice(struct trident_card *card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; @@ -635,31 +650,34 @@ static void trident_stop_voice(struct tr #ifdef DEBUG reg = inl(TRID_REG(card, addr)); TRDBG("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n", - channel, addr==T4D_STOP_B? "STOP_B":"STOP_A",reg,addr); + channel, addr == T4D_STOP_B ? "STOP_B" : "STOP_A", reg, addr); #endif /* DEBUG */ } -static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel) +static u32 +trident_get_interrupt_mask(struct trident_card *card, unsigned int channel) { struct trident_pcm_bank *bank = &card->banks[channel]; u32 addr = bank->addresses->aint; return inl(TRID_REG(card, addr)); } -static int trident_check_channel_interrupt(struct trident_card * card, unsigned int channel) +static int +trident_check_channel_interrupt(struct trident_card *card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); - u32 reg = trident_get_interrupt_mask (card, channel >> 5); + u32 reg = trident_get_interrupt_mask(card, channel >> 5); #ifdef DEBUG if (reg & mask) TRDBG("trident: channel %d has interrupt, %s = 0x%08x\n", - channel,reg==T4D_AINT_B? "AINT_B":"AINT_A", reg); + channel, reg == T4D_AINT_B ? "AINT_B" : "AINT_A", reg); #endif /* DEBUG */ - return (reg & mask) ? TRUE : FALSE; + return (reg & mask) ? 1 : 0; } -static void trident_ack_channel_interrupt(struct trident_card * card, unsigned int channel) +static void +trident_ack_channel_interrupt(struct trident_card *card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; @@ -676,7 +694,8 @@ static void trident_ack_channel_interrup #endif /* DEBUG */ } -static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card) +static struct trident_channel * +trident_alloc_pcm_channel(struct trident_card *card) { struct trident_pcm_bank *bank; int idx; @@ -697,28 +716,30 @@ static struct trident_channel * trident_ return NULL; } -static void trident_free_pcm_channel(struct trident_card *card, unsigned int channel) +static void +trident_free_pcm_channel(struct trident_card *card, unsigned int channel) { int bank; - unsigned char b; + unsigned char b; if (channel < 31 || channel > 63) return; if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX || - card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) { - b = inb (TRID_REG(card, T4D_REC_CH)); - if ((b & ~0x80) == channel) - outb(0x0, TRID_REG(card, T4D_REC_CH)); - } - + card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) { + b = inb(TRID_REG(card, T4D_REC_CH)); + if ((b & ~0x80) == channel) + outb(0x0, TRID_REG(card, T4D_REC_CH)); + } + bank = channel >> 5; channel = channel & 0x1f; - + card->banks[bank].bitmap &= ~(1 << (channel)); } -static struct trident_channel * cyber_alloc_pcm_channel(struct trident_card *card) +static struct trident_channel * +cyber_alloc_pcm_channel(struct trident_card *card) { struct trident_pcm_bank *bank; int idx; @@ -739,30 +760,35 @@ static struct trident_channel * cyber_al } /* no more free channels available */ - printk(KERN_ERR "cyberpro5050: no more channels available on Bank A.\n"); + printk(KERN_ERR + "cyberpro5050: no more channels available on Bank A.\n"); return NULL; } -static void cyber_free_pcm_channel(struct trident_card *card, unsigned int channel) +static void +cyber_free_pcm_channel(struct trident_card *card, unsigned int channel) { if (channel > 31) return; card->banks[BANK_A].bitmap &= ~(1 << (channel)); } -static inline void cyber_outidx(int port,int idx,int data) +static inline void +cyber_outidx(int port, int idx, int data) { - outb(idx,port); - outb(data,port+1); + outb(idx, port); + outb(data, port + 1); } -static inline int cyber_inidx(int port,int idx) +static inline int +cyber_inidx(int port, int idx) { - outb(idx,port); - return inb(port+1); + outb(idx, port); + return inb(port + 1); } -static int cyber_init_ritual(struct trident_card *card) +static int +cyber_init_ritual(struct trident_card *card) { /* some black magic, taken from SDK samples */ /* remove this and nothing will work */ @@ -771,47 +797,47 @@ static int cyber_init_ritual(struct trid unsigned long flags; /* - * Keep interrupts off for the configure - we don't want to - * clash with another cyberpro config event - */ - - spin_lock_irqsave(&card->lock, flags); + * Keep interrupts off for the configure - we don't want to + * clash with another cyberpro config event + */ + + spin_lock_irqsave(&card->lock, flags); portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE); /* enable, if it was disabled */ - if( (portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE ) { - printk(KERN_INFO "cyberpro5050: enabling audio controller\n" ); - cyber_outidx( CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE, - portDat | CYBER_BMSK_AUENZ_ENABLE ); + if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) { + printk(KERN_INFO "cyberpro5050: enabling audio controller\n"); + cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE, + portDat | CYBER_BMSK_AUENZ_ENABLE); /* check again if hardware is enabled now */ portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE); } - if( (portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE ) - { - printk(KERN_ERR "cyberpro5050: initAudioAccess: no success\n" ); + if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) { + printk(KERN_ERR "cyberpro5050: initAudioAccess: no success\n"); ret = -1; + } else { + cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE, + CYBER_BMSK_AUDIO_INT_ENABLE); + cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x01); + cyber_outidx(CYBER_PORT_AUDIO, 0xba, 0x20); + cyber_outidx(CYBER_PORT_AUDIO, 0xbb, 0x08); + cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x02); + cyber_outidx(CYBER_PORT_AUDIO, 0xb3, 0x06); + cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x00); } - else - { - cyber_outidx( CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE, CYBER_BMSK_AUDIO_INT_ENABLE ); - cyber_outidx( CYBER_PORT_AUDIO, 0xbf, 0x01 ); - cyber_outidx( CYBER_PORT_AUDIO, 0xba, 0x20 ); - cyber_outidx( CYBER_PORT_AUDIO, 0xbb, 0x08 ); - cyber_outidx( CYBER_PORT_AUDIO, 0xbf, 0x02 ); - cyber_outidx( CYBER_PORT_AUDIO, 0xb3, 0x06 ); - cyber_outidx( CYBER_PORT_AUDIO, 0xbf, 0x00 ); - } - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); return ret; } /* called with spin lock held */ -static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel) +static int +trident_load_channel_registers(struct trident_card *card, u32 * data, + unsigned int channel) { int i; if (channel > 63) - return FALSE; + return 0; /* select hardware channel to write */ outb(channel, TRID_REG(card, T4D_LFO_GC_CIR)); @@ -821,18 +847,19 @@ static int trident_load_channel_register for (i = 0; i < CHANNEL_REGS; i++) { if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451) continue; - outl(data[i], TRID_REG(card, CHANNEL_START + 4*i)); + outl(data[i], TRID_REG(card, CHANNEL_START + 4 * i)); } if (card->pci_id == PCI_DEVICE_ID_ALI_5451 || - card->pci_id == PCI_DEVICE_ID_INTERG_5050) { + card->pci_id == PCI_DEVICE_ID_INTERG_5050) { outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF1)); outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF2)); } - return TRUE; + return 1; } /* called with spin lock held */ -static int trident_write_voice_regs(struct trident_state *state) +static int +trident_write_voice_regs(struct trident_state *state) { unsigned int data[CHANNEL_REGS + 1]; struct trident_channel *channel; @@ -842,37 +869,38 @@ static int trident_write_voice_regs(stru data[1] = channel->lba; data[4] = channel->control; - switch (state->card->pci_id) - { + switch (state->card->pci_id) { case PCI_DEVICE_ID_ALI_5451: - data[0] = 0; /* Current Sample Offset */ + data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); data[3] = 0; - break; + break; case PCI_DEVICE_ID_SI_7018: case PCI_DEVICE_ID_INTERG_5050: - data[0] = 0; /* Current Sample Offset */ + data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - data[0] = 0; /* Current Sample Offset */ + data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); data[3] = channel->fm_vol & 0xffff; break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: data[0] = (channel->delta << 24); - data[2] = ((channel->delta << 16) & 0xff000000) | (channel->eso & 0x00ffffff); + data[2] = ((channel->delta << 16) & 0xff000000) | + (channel->eso & 0x00ffffff); data[3] = channel->fm_vol & 0xffff; break; default: - return FALSE; + return 0; } return trident_load_channel_registers(state->card, data, channel->num); } -static int compute_rate_play(u32 rate) +static int +compute_rate_play(u32 rate) { int delta; /* We special case 44100 and 8000 since rounding with the equation @@ -890,7 +918,8 @@ static int compute_rate_play(u32 rate) return delta; } -static int compute_rate_rec(u32 rate) +static int +compute_rate_rec(u32 rate) { int delta; @@ -905,9 +934,11 @@ static int compute_rate_rec(u32 rate) return delta; } + /* set playback sample rate */ -static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate) -{ +static unsigned int +trident_set_dac_rate(struct trident_state *state, unsigned int rate) +{ struct dmabuf *dmabuf = &state->dmabuf; if (rate > 48000) @@ -926,7 +957,8 @@ static unsigned int trident_set_dac_rate } /* set recording sample rate */ -static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate) +static unsigned int +trident_set_adc_rate(struct trident_state *state, unsigned int rate) { struct dmabuf *dmabuf = &state->dmabuf; @@ -945,8 +977,9 @@ static unsigned int trident_set_adc_rate return rate; } -/* prepare channel attributes for playback */ -static void trident_play_setup(struct trident_state *state) +/* prepare channel attributes for playback */ +static void +trident_play_setup(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; @@ -960,19 +993,22 @@ static void trident_play_setup(struct tr if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) { channel->attribute = 0; if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) { - if ((channel->num == ALI_SPDIF_IN_CHANNEL) || (channel->num == ALI_PCM_IN_CHANNEL)) - ali_disable_special_channel(state->card, channel->num); - else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE) - && (channel->num == ALI_SPDIF_OUT_CHANNEL)) - { - ali_set_spdif_out_rate(state->card, state->dmabuf.rate); + if ((channel->num == ALI_SPDIF_IN_CHANNEL) + || (channel->num == ALI_PCM_IN_CHANNEL)) + ali_disable_special_channel(state->card, + channel->num); + else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL)) + & ALI_SPDIF_OUT_CH_ENABLE) + && (channel->num == ALI_SPDIF_OUT_CHANNEL)) { + ali_set_spdif_out_rate(state->card, + state->dmabuf.rate); state->dmabuf.channel->delta = 0x1000; } } } channel->fm_vol = 0x0; - + channel->control = CHANNEL_LOOP; if (dmabuf->fmt & TRIDENT_FMT_16BIT) { /* 16-bits */ @@ -992,10 +1028,11 @@ static void trident_play_setup(struct tr } /* prepare channel attributes for recording */ -static void trident_rec_setup(struct trident_state *state) +static void +trident_rec_setup(struct trident_state *state) { u16 w; - u8 bval; + u8 bval; struct trident_card *card = state->card; struct dmabuf *dmabuf = &state->dmabuf; @@ -1003,8 +1040,7 @@ static void trident_rec_setup(struct tri unsigned int rate; /* Enable AC-97 ADC (capture) */ - switch (card->pci_id) - { + switch (card->pci_id) { case PCI_DEVICE_ID_ALI_5451: ali_enable_special_channel(state); break; @@ -1032,24 +1068,25 @@ static void trident_rec_setup(struct tri channel->lba = dmabuf->dma_handle; channel->delta = compute_rate_rec(dmabuf->rate); - if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) && (channel->num == ALI_SPDIF_IN_CHANNEL)) { + if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) + && (channel->num == ALI_SPDIF_IN_CHANNEL)) { rate = ali_get_spdif_in_rate(card); - if (rate == 0) - { - printk(KERN_WARNING "trident: ALi 5451 S/PDIF input setup error!\n"); + if (rate == 0) { + printk(KERN_WARNING "trident: ALi 5451 S/PDIF input " + "setup error!\n"); rate = 48000; } - bval = inb(TRID_REG(card,ALI_SPDIF_CTRL)); - if (bval & 0x10) - { - outb(bval,TRID_REG(card,ALI_SPDIF_CTRL)); - printk(KERN_WARNING "trident: cleared ALi 5451 S/PDIF parity error flag.\n"); + bval = inb(TRID_REG(card, ALI_SPDIF_CTRL)); + if (bval & 0x10) { + outb(bval, TRID_REG(card, ALI_SPDIF_CTRL)); + printk(KERN_WARNING "trident: cleared ALi 5451 S/PDIF " + "parity error flag.\n"); } if (rate != 48000) channel->delta = ((rate << 12) / dmabuf->rate) & 0x0000ffff; } - + channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; channel->eso -= 1; @@ -1058,7 +1095,7 @@ static void trident_rec_setup(struct tri } channel->fm_vol = 0x0; - + channel->control = CHANNEL_LOOP; if (dmabuf->fmt & TRIDENT_FMT_16BIT) { /* 16-bits */ @@ -1069,7 +1106,7 @@ static void trident_rec_setup(struct tri if (dmabuf->fmt & TRIDENT_FMT_STEREO) /* stereo */ channel->control |= CHANNEL_STEREO; - + TRDBG("trident: trident_rec_setup, LBA = 0x%08x, " "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", channel->lba, channel->delta, channel->eso, channel->control); @@ -1079,7 +1116,8 @@ static void trident_rec_setup(struct tri /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -static inline unsigned trident_get_dma_addr(struct trident_state *state) +static inline unsigned +trident_get_dma_addr(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; u32 cso; @@ -1089,8 +1127,7 @@ static inline unsigned trident_get_dma_a outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR)); - switch (state->card->pci_id) - { + switch (state->card->pci_id) { case PCI_DEVICE_ID_ALI_5451: case PCI_DEVICE_ID_SI_7018: case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: @@ -1106,7 +1143,6 @@ static inline unsigned trident_get_dma_a return 0; } - TRDBG("trident: trident_get_dma_addr: chip reported channel: %d, " "cso = 0x%04x\n", dmabuf->channel->num, cso); @@ -1117,7 +1153,8 @@ static inline unsigned trident_get_dma_a } /* Stop recording (lock held) */ -static inline void __stop_adc(struct trident_state *state) +static inline void +__stop_adc(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; @@ -1128,7 +1165,8 @@ static inline void __stop_adc(struct tri trident_disable_voice_irq(card, chan_num); } -static void stop_adc(struct trident_state *state) +static void +stop_adc(struct trident_state *state) { struct trident_card *card = state->card; unsigned long flags; @@ -1138,7 +1176,8 @@ static void stop_adc(struct trident_stat spin_unlock_irqrestore(&card->lock, flags); } -static void start_adc(struct trident_state *state) +static void +start_adc(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; @@ -1146,7 +1185,8 @@ static void start_adc(struct trident_sta unsigned long flags; spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + if ((dmabuf->mapped || dmabuf->count < (signed) dmabuf->dmasize) + && dmabuf->ready) { dmabuf->enable |= ADC_RUNNING; trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); @@ -1155,7 +1195,8 @@ static void start_adc(struct trident_sta } /* stop playback (lock held) */ -static inline void __stop_dac(struct trident_state *state) +static inline void +__stop_dac(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; @@ -1172,7 +1213,8 @@ static inline void __stop_dac(struct tri trident_disable_voice_irq(card, chan_num); } -static void stop_dac(struct trident_state *state) +static void +stop_dac(struct trident_state *state) { struct trident_card *card = state->card; unsigned long flags; @@ -1180,9 +1222,10 @@ static void stop_dac(struct trident_stat spin_lock_irqsave(&card->lock, flags); __stop_dac(state); spin_unlock_irqrestore(&card->lock, flags); -} +} -static void start_dac(struct trident_state *state) +static void +start_dac(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; @@ -1195,10 +1238,14 @@ static void start_dac(struct trident_sta trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); if (state->chans_num == 6) { - trident_start_voice(card, state->other_states[0]->dmabuf.channel->num); - trident_start_voice(card, state->other_states[1]->dmabuf.channel->num); - trident_start_voice(card, state->other_states[2]->dmabuf.channel->num); - trident_start_voice(card, state->other_states[3]->dmabuf.channel->num); + trident_start_voice(card, state->other_states[0]->dmabuf. + channel->num); + trident_start_voice(card, state->other_states[1]->dmabuf. + channel->num); + trident_start_voice(card, state->other_states[2]->dmabuf. + channel->num); + trident_start_voice(card, state->other_states[3]->dmabuf. + channel->num); } } spin_unlock_irqrestore(&card->lock, flags); @@ -1207,8 +1254,9 @@ static void start_dac(struct trident_sta #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) #define DMABUF_MINORDER 1 -/* alloc a DMA buffer of with a buffer of this order */ -static int alloc_dmabuf(struct dmabuf* dmabuf, struct pci_dev* pci_dev, int order) +/* alloc a DMA buffer of with a buffer of this order */ +static int +alloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev, int order) { void *rawbuf = NULL; struct page *page, *pend; @@ -1220,11 +1268,12 @@ static int alloc_dmabuf(struct dmabuf* d TRDBG("trident: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf); - dmabuf->ready = dmabuf->mapped = 0; + dmabuf->ready = dmabuf->mapped = 0; dmabuf->rawbuf = rawbuf; dmabuf->buforder = order; - - /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + + /* now mark the pages as reserved; otherwise */ + /* remap_page_range doesn't do what we want */ pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); for (page = virt_to_page(rawbuf); page <= pend; page++) SetPageReserved(page); @@ -1232,31 +1281,35 @@ static int alloc_dmabuf(struct dmabuf* d return 0; } -/* allocate the main DMA buffer, playback and recording buffer should be */ +/* allocate the main DMA buffer, playback and recording buffer should be */ /* allocated separately */ -static int alloc_main_dmabuf(struct trident_state *state) +static int +alloc_main_dmabuf(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; int order; - int ret = -ENOMEM; + int ret = -ENOMEM; /* alloc as big a chunk as we can, FIXME: is this necessary ?? */ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { if (!(ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order))) - return 0; - /* else try again */ + return 0; + /* else try again */ } - return ret; + return ret; } -/* deallocate a DMA buffer */ -static void dealloc_dmabuf(struct dmabuf* dmabuf, struct pci_dev* pci_dev) +/* deallocate a DMA buffer */ +static void +dealloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev) { struct page *page, *pend; - + if (dmabuf->rawbuf) { /* undo marking the pages as reserved */ - pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); + pend = + virt_to_page(dmabuf->rawbuf + + (PAGE_SIZE << dmabuf->buforder) - 1); for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) ClearPageReserved(page); pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder, @@ -1266,21 +1319,24 @@ static void dealloc_dmabuf(struct dmabuf dmabuf->mapped = dmabuf->ready = 0; } -static int prog_dmabuf(struct trident_state *state, unsigned rec) +static int +prog_dmabuf(struct trident_state *state, enum dmabuf_mode rec) { struct dmabuf *dmabuf = &state->dmabuf; unsigned bytepersec; struct trident_state *s = state; unsigned bufsize, dma_nums; unsigned long flags; - int ret, i, order; - - lock_set_fmt(state); + int ret, i, order; + + if ((ret = lock_set_fmt(state)) < 0) + return ret; + if (state->chans_num == 6) dma_nums = 5; - else + else dma_nums = 1; - + for (i = 0; i < dma_nums; i++) { if (i > 0) { s = state->other_states[i - 1]; @@ -1302,19 +1358,23 @@ static int prog_dmabuf(struct trident_st return ret; } } else { - ret = -ENOMEM; - if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) { - ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order); + ret = -ENOMEM; + order = state->dmabuf.buforder - 1; + if (order >= DMABUF_MINORDER) { + ret = alloc_dmabuf(dmabuf, + state->card->pci_dev, + order); } if (ret) { - /* release the main DMA buffer */ - dealloc_dmabuf(&state->dmabuf, state->card->pci_dev); - /* release the auxiliary DMA buffers */ - for (i-=2; i >= 0; i--) - dealloc_dmabuf(&state->other_states[i]->dmabuf, - state->card->pci_dev); + /* release the main DMA buffer */ + dealloc_dmabuf(&state->dmabuf, + state->card->pci_dev); + /* release the auxiliary DMA buffers */ + for (i -= 2; i >= 0; i--) + dealloc_dmabuf(&state->other_states[i]->dmabuf, + state->card->pci_dev); unlock_set_fmt(state); - return ret; + return ret; } } } @@ -1323,12 +1383,12 @@ static int prog_dmabuf(struct trident_st bufsize = PAGE_SIZE << dmabuf->buforder; if (dmabuf->ossfragshift) { if ((1000 << dmabuf->ossfragshift) < bytepersec) - dmabuf->fragshift = ld2(bytepersec/1000); + dmabuf->fragshift = ld2(bytepersec / 1000); else dmabuf->fragshift = dmabuf->ossfragshift; } else { /* lets hand out reasonable big ass buffers by default */ - dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2); } dmabuf->numfrag = bufsize >> dmabuf->fragshift; while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { @@ -1336,34 +1396,48 @@ static int prog_dmabuf(struct trident_st dmabuf->numfrag = bufsize >> dmabuf->fragshift; } dmabuf->fragsize = 1 << dmabuf->fragshift; - if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) + if (dmabuf->ossmaxfrags >= 4 + && dmabuf->ossmaxfrags < dmabuf->numfrag) dmabuf->numfrag = dmabuf->ossmaxfrags; - dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; + dmabuf->fragsamples = + dmabuf->fragsize >> sample_shift[dmabuf->fmt]; dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, + memset(dmabuf->rawbuf, + (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, dmabuf->dmasize); spin_lock_irqsave(&s->card->lock, flags); - if (rec) + if (rec == DM_RECORD) trident_rec_setup(s); - else + else /* DM_PLAYBACK */ trident_play_setup(s); - + spin_unlock_irqrestore(&s->card->lock, flags); /* set the ready flag for the dma buffer */ dmabuf->ready = 1; - TRDBG("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, " - "fragsize = %d dmasize = %d\n", - dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, - dmabuf->fragsize, dmabuf->dmasize); + TRDBG("trident: prog_dmabuf(%d), sample rate = %d, format = %d, " + "numfrag = %d, fragsize = %d dmasize = %d\n", + dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, + dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize); } unlock_set_fmt(state); return 0; } + +static inline int prog_dmabuf_record(struct trident_state* state) +{ + return prog_dmabuf(state, DM_RECORD); +} + +static inline int prog_dmabuf_playback(struct trident_state* state) +{ + return prog_dmabuf(state, DM_PLAYBACK); +} + /* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e. |------------|------------| or |xxxxxxxxxxxx|------------| or |xxxxxxxxxxxx|xxxxxxxxxxxx| but we almost always get this @@ -1371,7 +1445,8 @@ static int prog_dmabuf(struct trident_st so we have to clear the tail space to "silence" |xxxxxx000000|------------| or |xxxxxxxxxxxx|xxxxxx000000| */ -static void trident_clear_tail(struct trident_state *state) +static void +trident_clear_tail(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; unsigned swptr; @@ -1383,17 +1458,17 @@ static void trident_clear_tail(struct tr swptr = dmabuf->swptr; spin_unlock_irqrestore(&state->card->lock, flags); - if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize) + if (swptr == 0 || swptr == dmabuf->dmasize / 2 + || swptr == dmabuf->dmasize) return; - if (swptr < dmabuf->dmasize/2) - len = dmabuf->dmasize/2 - swptr; + if (swptr < dmabuf->dmasize / 2) + len = dmabuf->dmasize / 2 - swptr; else len = dmabuf->dmasize - swptr; memset(dmabuf->rawbuf + swptr, silence, len); - if(state->card->pci_id != PCI_DEVICE_ID_ALI_5451) - { + if (state->card->pci_id != PCI_DEVICE_ID_ALI_5451) { spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr += len; dmabuf->count += len; @@ -1404,7 +1479,8 @@ static void trident_clear_tail(struct tr start_dac(state); } -static int drain_dac(struct trident_state *state, int nonblock) +static int +drain_dac(struct trident_state *state, int nonblock) { DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf = &state->dmabuf; @@ -1418,8 +1494,9 @@ static int drain_dac(struct trident_stat add_wait_queue(&dmabuf->wait, &wait); for (;;) { - /* It seems that we have to set the current state to TASK_INTERRUPTIBLE - every time to make the process really go to sleep */ + /* It seems that we have to set the current */ + /* state to TASK_INTERRUPTIBLE every time to make */ + /* the process really go to sleep */ set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&state->card->lock, flags); @@ -1440,19 +1517,16 @@ static int drain_dac(struct trident_stat /* No matter how much data is left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ - if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451 || - state->card->pci_id == PCI_DEVICE_ID_INTERG_5050) - { - diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize ; + if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451 || + state->card->pci_id == PCI_DEVICE_ID_INTERG_5050) { + diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize; diff = diff % (dmabuf->dmasize); - tmo = (diff * HZ) / dmabuf->rate; - } - else - { + tmo = (diff * HZ) / dmabuf->rate; + } else { tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; } tmo >>= sample_shift[dmabuf->fmt]; - if (!schedule_timeout(tmo ? tmo : 1) && tmo){ + if (!schedule_timeout(tmo ? tmo : 1) && tmo) { break; } } @@ -1464,8 +1538,10 @@ static int drain_dac(struct trident_stat return 0; } -/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void trident_update_ptr(struct trident_state *state) +/* update buffer manangement pointers, especially, */ +/* dmabuf->count and dmabuf->hwptr */ +static void +trident_update_ptr(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; unsigned hwptr, swptr; @@ -1484,19 +1560,20 @@ static void trident_update_ptr(struct tr if (dmabuf->enable == ADC_RUNNING) { if (dmabuf->mapped) { dmabuf->count -= diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (dmabuf->count >= (signed) dmabuf->fragsize) wake_up(&dmabuf->wait); } else { dmabuf->count += diff; - if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + if (dmabuf->count < 0 + || dmabuf->count > dmabuf->dmasize) { /* buffer underrun or buffer overrun, we have no way to recover it here, just stop the machine and let the process force hwptr and swptr to sync */ __stop_adc(state); dmabuf->error++; } - if (dmabuf->count < (signed)dmabuf->dmasize/2) + if (dmabuf->count < (signed) dmabuf->dmasize / 2) wake_up(&dmabuf->wait); } } @@ -1505,7 +1582,7 @@ static void trident_update_ptr(struct tr if (dmabuf->enable == DAC_RUNNING) { if (dmabuf->mapped) { dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (dmabuf->count >= (signed) dmabuf->fragsize) wake_up(&dmabuf->wait); } else { dmabuf->count -= diff; @@ -1516,8 +1593,7 @@ static void trident_update_ptr(struct tr and swptr to sync */ __stop_dac(state); dmabuf->error++; - } - else if (!dmabuf->endcleared) { + } else if (!dmabuf->endcleared) { swptr = dmabuf->swptr; silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80); if (dmabuf->update_flag & ALI_ADDRESS_INT_UPDATE) { @@ -1525,26 +1601,25 @@ static void trident_update_ptr(struct tr According to 1/2 algorithm of Address Engine Interrupt, check the validation of the data of half dmasize. */ half_dmasize = dmabuf->dmasize / 2; - if ((diff = hwptr - half_dmasize) < 0 ) + if ((diff = hwptr - half_dmasize) < 0) diff = hwptr; if ((dmabuf->count + diff) < half_dmasize) { //there is invalid data in the end of half buffer if ((clear_cnt = half_dmasize - swptr) < 0) clear_cnt += half_dmasize; //clear the invalid data - memset (dmabuf->rawbuf + swptr, - silence, clear_cnt); + memset(dmabuf->rawbuf + swptr, silence, clear_cnt); if (state->chans_num == 6) { - clear_cnt = clear_cnt / 2; - swptr = swptr / 2; - memset (state->other_states[0]->dmabuf.rawbuf + swptr, - silence, clear_cnt); - memset (state->other_states[1]->dmabuf.rawbuf + swptr, - silence, clear_cnt); - memset (state->other_states[2]->dmabuf.rawbuf + swptr, - silence, clear_cnt); - memset (state->other_states[3]->dmabuf.rawbuf + swptr, - silence, clear_cnt); + clear_cnt = clear_cnt / 2; + swptr = swptr / 2; + memset(state->other_states[0]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset(state->other_states[1]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset(state->other_states[2]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset(state->other_states[3]->dmabuf.rawbuf + swptr, + silence, clear_cnt); } dmabuf->endcleared = 1; } @@ -1552,18 +1627,18 @@ static void trident_update_ptr(struct tr clear_cnt = dmabuf->fragsize; if ((swptr + clear_cnt) > dmabuf->dmasize) clear_cnt = dmabuf->dmasize - swptr; - memset (dmabuf->rawbuf + swptr, silence, clear_cnt); + memset(dmabuf->rawbuf + swptr, silence, clear_cnt); if (state->chans_num == 6) { clear_cnt = clear_cnt / 2; swptr = swptr / 2; - memset (state->other_states[0]->dmabuf.rawbuf + swptr, - silence, clear_cnt); - memset (state->other_states[1]->dmabuf.rawbuf + swptr, - silence, clear_cnt); - memset (state->other_states[2]->dmabuf.rawbuf + swptr, - silence, clear_cnt); - memset (state->other_states[3]->dmabuf.rawbuf + swptr, - silence, clear_cnt); + memset(state->other_states[0]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset(state->other_states[1]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset(state->other_states[2]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset(state->other_states[3]->dmabuf.rawbuf + swptr, + silence, clear_cnt); } dmabuf->endcleared = 1; } @@ -1571,23 +1646,24 @@ static void trident_update_ptr(struct tr /* trident_update_ptr is called by interrupt handler or by process via ioctl/poll, we only wake up the waiting process when we have more than 1/2 buffer free (always true for interrupt handler) */ - if (dmabuf->count < (signed)dmabuf->dmasize/2) + if (dmabuf->count < (signed) dmabuf->dmasize / 2) wake_up(&dmabuf->wait); } } dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE; } -static void trident_address_interrupt(struct trident_card *card) +static void +trident_address_interrupt(struct trident_card *card) { int i; struct trident_state *state; - unsigned int channel; - + unsigned int channel; + /* Update the pointers for all channels we are running. */ /* FIXME: should read interrupt status only once */ for (i = 0; i < NR_HW_CH; i++) { - channel = 63 - i; + channel = 63 - i; if (trident_check_channel_interrupt(card, channel)) { trident_ack_channel_interrupt(card, channel); if ((state = card->states[i]) != NULL) { @@ -1602,7 +1678,8 @@ static void trident_address_interrupt(st } } -static void ali_hwvol_control(struct trident_card *card, int opt) +static void +ali_hwvol_control(struct trident_card *card, int opt) { u16 dwTemp, volume[2], mute, diff, *pVol[2]; @@ -1610,7 +1687,7 @@ static void ali_hwvol_control(struct tri mute = dwTemp & 0x8000; volume[0] = dwTemp & 0x001f; volume[1] = (dwTemp & 0x1f00) >> 8; - if (volume[0] < volume [1]) { + if (volume[0] < volume[1]) { pVol[0] = &volume[0]; pVol[1] = &volume[1]; } else { @@ -1619,10 +1696,10 @@ static void ali_hwvol_control(struct tri } diff = *(pVol[1]) - *(pVol[0]); - if (opt == 1) { // MUTE + if (opt == 1) { // MUTE dwTemp ^= 0x8000; ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp); - } else if (opt == 2) { // Down + } else if (opt == 2) { // Down if (mute) return; if (*(pVol[1]) < 0x001f) { @@ -1632,21 +1709,21 @@ static void ali_hwvol_control(struct tri dwTemp &= 0xe0e0; dwTemp |= (volume[0]) | (volume[1] << 8); ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp); - card->ac97_codec[0]->mixer_state[0] = ((32-volume[0])*25/8) | (((32-volume[1])*25/8) << 8); - } else if (opt == 4) { // Up + card->ac97_codec[0]->mixer_state[0] = + ((32 - volume[0]) * 25 / 8) | (((32 - volume[1]) * 25 / 8) << 8); + } else if (opt == 4) { // Up if (mute) return; - if (*(pVol[0]) >0) { + if (*(pVol[0]) > 0) { (*pVol[0])--; *(pVol[1]) = *(pVol[0]) + diff; } dwTemp &= 0xe0e0; dwTemp |= (volume[0]) | (volume[1] << 8); ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp); - card->ac97_codec[0]->mixer_state[0] = ((32-volume[0])*25/8) | (((32-volume[1])*25/8) << 8); - } - else - { + card->ac97_codec[0]->mixer_state[0] = + ((32 - volume[0]) * 25 / 8) | (((32 - volume[1]) * 25 / 8) << 8); + } else { /* Nothing needs doing */ } } @@ -1655,12 +1732,13 @@ static void ali_hwvol_control(struct tri * Re-enable reporting of vol change after 0.1 seconds */ -static void ali_timeout(unsigned long ptr) +static void +ali_timeout(unsigned long ptr) { - struct trident_card *card = (struct trident_card *)ptr; + struct trident_card *card = (struct trident_card *) ptr; u16 temp = 0; - /* Enable GPIO IRQ (MISCINT bit 18h)*/ + /* Enable GPIO IRQ (MISCINT bit 18h) */ temp = inw(TRID_REG(card, T4D_MISCINT + 2)); temp |= 0x0004; outw(temp, TRID_REG(card, T4D_MISCINT + 2)); @@ -1669,62 +1747,65 @@ static void ali_timeout(unsigned long pt /* * Set up the timer to clear the vol change notification */ - -static void ali_set_timer(struct trident_card *card) + +static void +ali_set_timer(struct trident_card *card) { /* Add Timer Routine to Enable GPIO IRQ */ del_timer(&card->timer); /* Never queue twice */ card->timer.function = ali_timeout; card->timer.data = (unsigned long) card; - card->timer.expires = jiffies + HZ/10; + card->timer.expires = jiffies + HZ / 10; add_timer(&card->timer); } /* * Process a GPIO event */ - -static void ali_queue_task(struct trident_card *card, int opt) + +static void +ali_queue_task(struct trident_card *card, int opt) { u16 temp; - /* Disable GPIO IRQ (MISCINT bit 18h)*/ + /* Disable GPIO IRQ (MISCINT bit 18h) */ temp = inw(TRID_REG(card, T4D_MISCINT + 2)); - temp &= (u16)(~0x0004); + temp &= (u16) (~0x0004); outw(temp, TRID_REG(card, T4D_MISCINT + 2)); /* Adjust the volume */ ali_hwvol_control(card, opt); - + /* Set the timer for 1/10th sec */ ali_set_timer(card); } -static void cyber_address_interrupt(struct trident_card *card) +static void +cyber_address_interrupt(struct trident_card *card) { - int i,irq_status; + int i, irq_status; struct trident_state *state; - unsigned int channel; + unsigned int channel; /* Update the pointers for all channels we are running. */ /* FIXED: read interrupt status only once */ - irq_status=inl(TRID_REG(card, T4D_AINT_A) ); + irq_status = inl(TRID_REG(card, T4D_AINT_A)); - TRDBG("cyber_address_interrupt: irq_status 0x%X\n",irq_status); + TRDBG("cyber_address_interrupt: irq_status 0x%X\n", irq_status); for (i = 0; i < NR_HW_CH; i++) { - channel = 31 - i; - if (irq_status & ( 1 << channel) ) { - /* clear bit by writing a 1, zeroes are ignored */ - outl( (1 << channel), TRID_REG(card, T4D_AINT_A)); - + channel = 31 - i; + if (irq_status & (1 << channel)) { + /* clear bit by writing a 1, zeroes are ignored */ + outl((1 << channel), TRID_REG(card, T4D_AINT_A)); + TRDBG("cyber_interrupt: channel %d\n", channel); if ((state = card->states[i]) != NULL) { trident_update_ptr(state); } else { printk(KERN_WARNING "cyber5050: spurious " - "channel irq %d.\n", channel); + "channel irq %d.\n", channel); trident_stop_voice(card, channel); trident_disable_voice_irq(card, channel); } @@ -1732,9 +1813,10 @@ static void cyber_address_interrupt(stru } } -static irqreturn_t trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t +trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct trident_card *card = (struct trident_card *)dev_id; + struct trident_card *card = (struct trident_card *) dev_id; u32 event; u32 gpio; @@ -1747,17 +1829,18 @@ static irqreturn_t trident_interrupt(int card->address_interrupt(card); } - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) - { + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { /* GPIO IRQ (H/W Volume Control) */ event = inl(TRID_REG(card, T4D_MISCINT)); - if (event & (1<<25)) { + if (event & (1 << 25)) { gpio = inl(TRID_REG(card, ALI_GPIO)); - if (!timer_pending(&card->timer)) - ali_queue_task(card, gpio&0x07); + if (!timer_pending(&card->timer)) + ali_queue_task(card, gpio & 0x07); } event = inl(TRID_REG(card, T4D_MISCINT)); - outl(event | (ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(card, T4D_MISCINT)); + outl(event | + (ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), + TRID_REG(card, T4D_MISCINT)); spin_unlock(&card->lock); return IRQ_HANDLED; } @@ -1771,9 +1854,11 @@ static irqreturn_t trident_interrupt(int /* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to the user's buffer. it is filled by the dma machine and drained by this loop. */ -static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t +trident_read(struct file *file, char *buffer, size_t count, loff_t * ppos) { - struct trident_state *state = (struct trident_state *)file->private_data; + struct trident_state *state = + (struct trident_state *) file->private_data; struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret = 0; unsigned long flags; @@ -1783,16 +1868,17 @@ static ssize_t trident_read(struct file TRDBG("trident: trident_read called, count = %d\n", count); VALIDATE_STATE(state); + if (ppos != &file->f_pos) return -ESPIPE; - + if (dmabuf->mapped) return -ENXIO; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - + down(&state->sem); - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + if (!dmabuf->ready && (ret = prog_dmabuf_record(state))) goto out; while (count > 0) { @@ -1817,10 +1903,11 @@ static ssize_t trident_read(struct file recorded */ start_adc(state); if (file->f_flags & O_NONBLOCK) { - if (!ret) ret = -EAGAIN; + if (!ret) + ret = -EAGAIN; goto out; } - + up(&state->sem); /* No matter how much space left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ @@ -1834,22 +1921,24 @@ static ssize_t trident_read(struct file which results in a (potential) buffer overrun. And worse, there is NOTHING we can do to prevent it. */ if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { - TRDBG(KERN_ERR "trident: recording schedule timeout, " + TRDBG(KERN_ERR + "trident: recording schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, - dmabuf->hwptr, dmabuf->swptr); + dmabuf->dmasize, dmabuf->fragsize, + dmabuf->count, dmabuf->hwptr, + dmabuf->swptr); /* a buffer overrun, we delay the recovery until next time the while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { - if(!ret) ret = -ERESTARTSYS; + if (!ret) + ret = -ERESTARTSYS; goto out; } down(&state->sem); - if(dmabuf->mapped) - { - if(!ret) + if (dmabuf->mapped) { + if (!ret) ret = -ENXIO; goto out; } @@ -1857,7 +1946,8 @@ static ssize_t trident_read(struct file } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { - if (!ret) ret = -EFAULT; + if (!ret) + ret = -EFAULT; goto out; } @@ -1873,7 +1963,7 @@ static ssize_t trident_read(struct file ret += cnt; start_adc(state); } -out: + out: up(&state->sem); return ret; } @@ -1881,9 +1971,11 @@ out: /* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to the soundcard. it is drained by the dma machine and filled by this loop. */ -static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t +trident_write(struct file *file, const char *buffer, size_t count, + loff_t * ppos) { - struct trident_state *state = (struct trident_state *)file->private_data; + struct trident_state* state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; @@ -1891,33 +1983,32 @@ static ssize_t trident_write(struct file int cnt; unsigned int state_cnt; unsigned int copy_count; + int lret; /* for lock_set_fmt */ TRDBG("trident: trident_write called, count = %d\n", count); VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; - + /* - * Guard against an mmap or ioctl while writing - */ - + * Guard against an mmap or ioctl while writing + */ + down(&state->sem); - - if (dmabuf->mapped) - { + + if (dmabuf->mapped) { ret = -ENXIO; goto out; } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + if (!dmabuf->ready && (ret = prog_dmabuf_playback(state))) goto out; - if (!access_ok(VERIFY_READ, buffer, count)) - { - ret= -EFAULT; + if (!access_ok(VERIFY_READ, buffer, count)) { + ret = -EFAULT; goto out; } - + ret = 0; while (count > 0) { @@ -1942,17 +2033,22 @@ static ssize_t trident_write(struct file played */ start_dac(state); if (file->f_flags & O_NONBLOCK) { - if (!ret) ret = -EAGAIN; + if (!ret) + ret = -EAGAIN; goto out; } /* No matter how much data left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ - lock_set_fmt(state); + if ((lret = lock_set_fmt(state)) < 0) { + ret = lret; + goto out; + } + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); tmo >>= sample_shift[dmabuf->fmt]; unlock_set_fmt(state); up(&state->sem); - + /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1963,31 +2059,37 @@ static ssize_t trident_write(struct file if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { TRDBG(KERN_ERR "trident: playback schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, - dmabuf->hwptr, dmabuf->swptr); + dmabuf->dmasize, dmabuf->fragsize, + dmabuf->count, dmabuf->hwptr, + dmabuf->swptr); /* a buffer underrun, we delay the recovery until next time the while loop begin and we REALLY have data to play */ } if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - goto out; + if (!ret) + ret = -ERESTARTSYS; + goto out_nolock; } down(&state->sem); - if(dmabuf->mapped) - { - if(!ret) + if (dmabuf->mapped) { + if (!ret) ret = -ENXIO; goto out; } continue; } - lock_set_fmt(state); + if ((lret = lock_set_fmt(state)) < 0) { + ret = lret; + goto out; + } + if (state->chans_num == 6) { copy_count = 0; state_cnt = 0; - if (ali_write_5_1(state, buffer, cnt, ©_count, &state_cnt) == -EFAULT) { - if (state_cnt){ + if (ali_write_5_1(state, buffer, cnt, ©_count, + &state_cnt) == -EFAULT) { + if (state_cnt) { swptr = (swptr + state_cnt) % dmabuf->dmasize; spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; @@ -1996,23 +2098,24 @@ static ssize_t trident_write(struct file spin_unlock_irqrestore(&state->card->lock, flags); } ret += copy_count; - if (!ret) ret = -EFAULT; + if (!ret) + ret = -EFAULT; unlock_set_fmt(state); goto out; } - } - else { + } else { if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { - if (!ret) ret = -EFAULT; + if (!ret) + ret = -EFAULT; unlock_set_fmt(state); goto out; } state_cnt = cnt; } unlock_set_fmt(state); - - swptr = (swptr + state_cnt) % dmabuf->dmasize; - + + swptr = (swptr + state_cnt) % dmabuf->dmasize; + spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; dmabuf->count += state_cnt; @@ -2020,18 +2123,19 @@ static ssize_t trident_write(struct file spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; - buffer += cnt; + buffer += cnt; ret += cnt; start_dac(state); } out: up(&state->sem); +out_nolock: return ret; } - /* No kernel lock - we have our own spinlock */ -static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait) +static unsigned int +trident_poll(struct file *file, struct poll_table_struct *wait) { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; @@ -2041,23 +2145,21 @@ static unsigned int trident_poll(struct VALIDATE_STATE(state); /* - * Guard against a parallel poll and write causing multiple - * prog_dmabuf events + * Guard against a parallel poll and write causing multiple + * prog_dmabuf events */ - + down(&state->sem); if (file->f_mode & FMODE_WRITE) { - if (!dmabuf->ready && prog_dmabuf(state, 0)) - { + if (!dmabuf->ready && prog_dmabuf_playback(state)) { up(&state->sem); return 0; } poll_wait(file, &dmabuf->wait, wait); } if (file->f_mode & FMODE_READ) { - if (!dmabuf->ready && prog_dmabuf(state, 1)) - { + if (!dmabuf->ready && prog_dmabuf_record(state)) { up(&state->sem); return 0; } @@ -2065,19 +2167,20 @@ static unsigned int trident_poll(struct } up(&state->sem); - + spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); if (file->f_mode & FMODE_READ) { - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (dmabuf->count >= (signed) dmabuf->fragsize) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { if (dmabuf->mapped) { - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (dmabuf->count >= (signed) dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) + if ((signed) dmabuf->dmasize >= + dmabuf->count + (signed) dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } } @@ -2086,7 +2189,8 @@ static unsigned int trident_poll(struct return mask; } -static int trident_mmap(struct file *file, struct vm_area_struct *vma) +static int +trident_mmap(struct file *file, struct vm_area_struct *vma) { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; @@ -2094,20 +2198,19 @@ static int trident_mmap(struct file *fil unsigned long size; VALIDATE_STATE(state); - lock_kernel(); - + /* - * Lock against poll read write or mmap creating buffers. Also lock - * a read or write against an mmap. + * Lock against poll read write or mmap creating buffers. Also lock + * a read or write against an mmap. */ - + down(&state->sem); - + if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(state, 0)) != 0) + if ((ret = prog_dmabuf_playback(state)) != 0) goto out; } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(state, 1)) != 0) + if ((ret = prog_dmabuf_record(state)) != 0) goto out; } else goto out; @@ -2124,13 +2227,14 @@ static int trident_mmap(struct file *fil goto out; dmabuf->mapped = 1; ret = 0; -out: + out: up(&state->sem); - unlock_kernel(); return ret; } -static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int +trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; @@ -2142,17 +2246,18 @@ static int trident_ioctl(struct inode *i struct trident_card *card = state->card; VALIDATE_STATE(state); - mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || - ((file->f_mode & FMODE_READ) && dmabuf->mapped); + + + mapped = ((file->f_mode & (FMODE_WRITE | FMODE_READ)) && dmabuf->mapped); + TRDBG("trident: trident_ioctl, command = %2d, arg = 0x%08x\n", - _IOC_NR(cmd), arg ? *(int *)arg : 0); + _IOC_NR(cmd), arg ? *(int *) arg : 0); - switch (cmd) - { + switch (cmd) { case OSS_GETVERSION: - ret = put_user(SOUND_VERSION, (int *)arg); + ret = put_user(SOUND_VERSION, (int *) arg); break; - + case SNDCTL_DSP_RESET: /* FIXME: spin_lock ? */ if (file->f_mode & FMODE_WRITE) { @@ -2176,9 +2281,8 @@ static int trident_ioctl(struct inode *i ret = drain_dac(state, file->f_flags & O_NONBLOCK); break; - case SNDCTL_DSP_SPEED: /* set smaple rate */ - if (get_user(val, (int *)arg)) - { + case SNDCTL_DSP_SPEED: /* set smaple rate */ + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2188,26 +2292,29 @@ static int trident_ioctl(struct inode *i dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); trident_set_dac_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); + spin_unlock_irqrestore(&state->card->lock, + flags); } if (file->f_mode & FMODE_READ) { stop_adc(state); dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); trident_set_adc_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); + spin_unlock_irqrestore(&state->card->lock, + flags); } } - ret = put_user(dmabuf->rate, (int *)arg); + ret = put_user(dmabuf->rate, (int *) arg); break; - case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ - if (get_user(val, (int *)arg)) - { + case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } - lock_set_fmt(state); + if ((ret = lock_set_fmt(state)) < 0) + return ret; + if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; @@ -2229,31 +2336,36 @@ static int trident_ioctl(struct inode *i case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(state, 0))) + if ((val = prog_dmabuf_playback(state))) ret = val; else - ret = put_user(dmabuf->fragsize, (int *)arg); + ret = put_user(dmabuf->fragsize, (int *) arg); break; } if (file->f_mode & FMODE_READ) { - if ((val = prog_dmabuf(state, 1))) + if ((val = prog_dmabuf_record(state))) ret = val; else - ret = put_user(dmabuf->fragsize, (int *)arg); + ret = put_user(dmabuf->fragsize, (int *) arg); break; } + /* neither READ nor WRITE? is this even possible? */ + ret = -EINVAL; + break; - case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ - ret = put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */ + ret = put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | AFMT_U8, + (int *) arg); break; - case SNDCTL_DSP_SETFMT: /* Select sample format */ - if (get_user(val, (int *)arg)) - { + case SNDCTL_DSP_SETFMT: /* Select sample format */ + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } - lock_set_fmt(state); + if ((ret = lock_set_fmt(state)) < 0) + return ret; + if (val != AFMT_QUERY) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -2274,38 +2386,36 @@ static int trident_ioctl(struct inode *i } unlock_set_fmt(state); ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); + AFMT_S16_LE : AFMT_U8, (int *) arg); break; case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } if (val != 0) { - lock_set_fmt(state); + if ((ret = lock_set_fmt(state)) < 0) + return ret; + if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; - + //prevent from memory leak - if ((state->chans_num > 2) && (state->chans_num != val)) { + if ((state->chans_num > 2) + && (state->chans_num != val)) { ali_free_other_states_resources(state); state->chans_num = 1; } - - if (val >= 2) - { + if (val >= 2) { dmabuf->fmt |= TRIDENT_FMT_STEREO; if ((val == 6) && (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)) { - - if( card->rec_channel_use_count > 0 ) - { + if (card->rec_channel_use_count > 0) { printk(KERN_ERR "trident: Record is working on the card!\n"); ret = -EBUSY; - unlock_set_fmt(state); + unlock_set_fmt(state); break; } @@ -2321,12 +2431,11 @@ static int trident_ioctl(struct inode *i unlock_set_fmt(state); break; } - state->card->multi_channel_use_count ++; + state->card->multi_channel_use_count++; up(&state->card->open_sem); - } - else val = 2; /*yield to 2-channels*/ - } - else + } else + val = 2; /*yield to 2-channels */ + } else dmabuf->fmt &= ~TRIDENT_FMT_STEREO; state->chans_num = val; } @@ -2337,14 +2446,13 @@ static int trident_ioctl(struct inode *i if (!((file->f_mode & FMODE_WRITE) && (val == 6))) val = 2; dmabuf->fmt |= TRIDENT_FMT_STEREO; - } - else + } else dmabuf->fmt &= ~TRIDENT_FMT_STEREO; state->chans_num = val; } unlock_set_fmt(state); } - ret = put_user(val, (int *)arg); + ret = put_user(val, (int *) arg); break; case SNDCTL_DSP_POST: @@ -2352,18 +2460,15 @@ static int trident_ioctl(struct inode *i break; case SNDCTL_DSP_SUBDIVIDE: - if (dmabuf->subdivision) - { + if (dmabuf->subdivision) { ret = -EINVAL; break; } - if (get_user(val, (int *)arg)) - { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } - if (val != 1 && val != 2 && val != 4) - { + if (val != 1 && val != 2 && val != 4) { ret = -EINVAL; break; } @@ -2371,8 +2476,7 @@ static int trident_ioctl(struct inode *i break; case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *)arg)) - { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2389,13 +2493,11 @@ static int trident_ioctl(struct inode *i break; case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - { + if (!(file->f_mode & FMODE_WRITE)) { ret = -EINVAL; break; } - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - { + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) { ret = val; break; } @@ -2406,17 +2508,16 @@ static int trident_ioctl(struct inode *i abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + ret = copy_to_user((void *) arg, &abinfo, + sizeof (abinfo)) ? -EFAULT : 0; break; case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - { + if (!(file->f_mode & FMODE_READ)) { ret = -EINVAL; break; } - if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - { + if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) { ret = val; break; } @@ -2427,7 +2528,8 @@ static int trident_ioctl(struct inode *i abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + ret = copy_to_user((void *) arg, &abinfo, + sizeof (abinfo)) ? -EFAULT : 0; break; case SNDCTL_DSP_NONBLOCK: @@ -2435,8 +2537,8 @@ static int trident_ioctl(struct inode *i break; case SNDCTL_DSP_GETCAPS: - ret = put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, - (int *)arg); + ret = put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | + DSP_CAP_BIND, (int *) arg); break; case SNDCTL_DSP_GETTRIGGER: @@ -2445,18 +2547,18 @@ static int trident_ioctl(struct inode *i val |= PCM_ENABLE_INPUT; if ((file->f_mode & FMODE_WRITE) && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; - ret = put_user(val, (int *)arg); + ret = put_user(val, (int *) arg); break; case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *)arg)) - { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + if (!dmabuf->ready + && (ret = prog_dmabuf(state, 1))) break; start_adc(state); } else @@ -2464,7 +2566,8 @@ static int trident_ioctl(struct inode *i } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + if (!dmabuf->ready + && (ret = prog_dmabuf(state, 0))) break; start_dac(state); } else @@ -2473,13 +2576,11 @@ static int trident_ioctl(struct inode *i break; case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - { + if (!(file->f_mode & FMODE_READ)) { ret = -EINVAL; break; } - if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - { + if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) { ret = val; break; } @@ -2489,32 +2590,32 @@ static int trident_ioctl(struct inode *i cinfo.blocks = dmabuf->count >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr; if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; + dmabuf->count &= dmabuf->fragsize - 1; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user((void *)arg, &cinfo, sizeof(cinfo))?-EFAULT:0; + ret = copy_to_user((void *) arg, &cinfo, + sizeof (cinfo)) ? -EFAULT : 0; break; case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - { + if (!(file->f_mode & FMODE_WRITE)) { ret = -EINVAL; break; } - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - { + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) { ret = val; break; } - + spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); cinfo.bytes = dmabuf->total_bytes; cinfo.blocks = dmabuf->count >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr; if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; + dmabuf->count &= dmabuf->fragsize - 1; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user((void *)arg, &cinfo, sizeof(cinfo))?-EFAULT:0; + ret = copy_to_user((void *) arg, &cinfo, + sizeof (cinfo)) ? -EFAULT : 0; break; case SNDCTL_DSP_SETDUPLEX: @@ -2522,13 +2623,11 @@ static int trident_ioctl(struct inode *i break; case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - { + if (!(file->f_mode & FMODE_WRITE)) { ret = -EINVAL; break; } - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - { + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) { ret = val; break; } @@ -2536,37 +2635,35 @@ static int trident_ioctl(struct inode *i trident_update_ptr(state); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); - ret = put_user(val, (int *)arg); + ret = put_user(val, (int *) arg); break; case SOUND_PCM_READ_RATE: - ret = put_user(dmabuf->rate, (int *)arg); + ret = put_user(dmabuf->rate, (int *) arg); break; case SOUND_PCM_READ_CHANNELS: ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); + (int *) arg); break; case SOUND_PCM_READ_BITS: ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); + AFMT_S16_LE : AFMT_U8, (int *) arg); break; case SNDCTL_DSP_GETCHANNELMASK: - ret = put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE, - (int *)arg); + ret = put_user(DSP_BIND_FRONT | DSP_BIND_SURR | + DSP_BIND_CENTER_LFE, (int *) arg); break; case SNDCTL_DSP_BIND_CHANNEL: - if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) - { + if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) { ret = -EINVAL; break; } - if (get_user(val, (int *)arg)) - { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2576,12 +2673,14 @@ static int trident_ioctl(struct inode *i } else { dmabuf->ready = 0; if (file->f_mode & FMODE_READ) - dmabuf->channel->attribute = (CHANNEL_REC|SRC_ENABLE); + dmabuf->channel->attribute = + (CHANNEL_REC | SRC_ENABLE); if (file->f_mode & FMODE_WRITE) - dmabuf->channel->attribute = (CHANNEL_SPC_PB|SRC_ENABLE); + dmabuf->channel->attribute = + (CHANNEL_SPC_PB | SRC_ENABLE); dmabuf->channel->attribute |= mask2attr[ffs(val)]; } - ret = put_user(val, (int *)arg); + ret = put_user(val, (int *) arg); break; case SNDCTL_DSP_MAPINBUF: @@ -2592,23 +2691,27 @@ static int trident_ioctl(struct inode *i default: ret = -EINVAL; break; - + } return ret; } -static int trident_open(struct inode *inode, struct file *file) +static int +trident_open(struct inode *inode, struct file *file) { int i = 0; int minor = iminor(inode); struct trident_card *card = devs; struct trident_state *state = NULL; struct dmabuf *dmabuf = NULL; - + /* Added by Matt Wu 01-05-2001 */ - if(file->f_mode & FMODE_READ) - { - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + /* TODO: there's some redundacy here wrt the check below */ + /* for multi_use_count > 0. Should we return -EBUSY or find */ + /* a different card? for now, don't break current behaviour */ + /* -- mulix */ + if (file->f_mode & FMODE_READ) { + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { if (card->multi_channel_use_count > 0) return -EBUSY; } @@ -2617,11 +2720,9 @@ static int trident_open(struct inode *in /* find an available virtual channel (instance of /dev/dsp) */ while (card != NULL) { down(&card->open_sem); - if(file->f_mode & FMODE_READ) - { + if (file->f_mode & FMODE_READ) { /* Skip opens on cards that are in 6 channel mode */ - if (card->multi_channel_use_count > 0) - { + if (card->multi_channel_use_count > 0) { up(&card->open_sem); card = card->next; continue; @@ -2629,12 +2730,12 @@ static int trident_open(struct inode *in } for (i = 0; i < NR_HW_CH; i++) { if (card->states[i] == NULL) { - state = card->states[i] = (struct trident_state *) - kmalloc(sizeof(struct trident_state), GFP_KERNEL); + state = card->states[i] = kmalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) { + up(&card->open_sem); return -ENOMEM; } - memset(state, 0, sizeof(struct trident_state)); + memset(state, 0, sizeof(*state)); init_MUTEX(&state->sem); dmabuf = &state->dmabuf; goto found_virt; @@ -2647,15 +2748,15 @@ static int trident_open(struct inode *in if (!state) { return -ENODEV; } - found_virt: +found_virt: /* found a free virtual channel, allocate hardware channels */ - if(file->f_mode & FMODE_READ) + if (file->f_mode & FMODE_READ) dmabuf->channel = card->alloc_rec_pcm_channel(card); else dmabuf->channel = card->alloc_pcm_channel(card); - + if (dmabuf->channel == NULL) { - kfree (card->states[i]); + kfree(card->states[i]); card->states[i] = NULL; return -ENODEV; } @@ -2675,8 +2776,8 @@ static int trident_open(struct inode *in if ((minor & 0x0f) == SND_DEV_DSP16) dmabuf->fmt |= TRIDENT_FMT_16BIT; dmabuf->ossfragshift = 0; - dmabuf->ossmaxfrags = 0; - dmabuf->subdivision = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; if (card->pci_id == PCI_DEVICE_ID_SI_7018) { /* set default channel attribute to normal playback */ dmabuf->channel->attribute = CHANNEL_PB; @@ -2691,47 +2792,47 @@ static int trident_open(struct inode *in if ((minor & 0x0f) == SND_DEV_DSP16) dmabuf->fmt |= TRIDENT_FMT_16BIT; dmabuf->ossfragshift = 0; - dmabuf->ossmaxfrags = 0; - dmabuf->subdivision = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; if (card->pci_id == PCI_DEVICE_ID_SI_7018) { /* set default channel attribute to 0x8a80, record from - PCM L/R FIFO and mono = (left + right + 1)/2*/ - dmabuf->channel->attribute = - (CHANNEL_REC|PCM_LR|MONO_MIX); + PCM L/R FIFO and mono = (left + right + 1)/2 */ + dmabuf->channel->attribute = (CHANNEL_REC | PCM_LR | MONO_MIX); } trident_set_adc_rate(state, 8000); - + /* Added by Matt Wu 01-05-2001 */ - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) - card->rec_channel_use_count ++; + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) + card->rec_channel_use_count++; } state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&card->open_sem); - TRDBG("trident: open virtual channel %d, hard channel %d\n", - state->virt, dmabuf->channel->num); + TRDBG("trident: open virtual channel %d, hard channel %d\n", + state->virt, dmabuf->channel->num); return 0; } -static int trident_release(struct inode *inode, struct file *file) +static int +trident_release(struct inode *inode, struct file *file) { struct trident_state *state = (struct trident_state *)file->private_data; struct trident_card *card; struct dmabuf *dmabuf; - lock_kernel(); + VALIDATE_STATE(state); + card = state->card; dmabuf = &state->dmabuf; - VALIDATE_STATE(state); if (file->f_mode & FMODE_WRITE) { trident_clear_tail(state); drain_dac(state, file->f_flags & O_NONBLOCK); } - TRDBG("trident: closing virtual channel %d, hard channel %d\n", + TRDBG("trident: closing virtual channel %d, hard channel %d\n", state->virt, dmabuf->channel->num); /* stop DMA state machine and free DMA buffers/channels */ @@ -2740,7 +2841,8 @@ static int trident_release(struct inode if (file->f_mode & FMODE_WRITE) { stop_dac(state); dealloc_dmabuf(&state->dmabuf, state->card->pci_dev); - state->card->free_pcm_channel(state->card, dmabuf->channel->num); + state->card->free_pcm_channel(state->card, + dmabuf->channel->num); /* Added by Matt Wu */ if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { @@ -2756,11 +2858,12 @@ static int trident_release(struct inode if (file->f_mode & FMODE_READ) { stop_adc(state); dealloc_dmabuf(&state->dmabuf, state->card->pci_dev); - state->card->free_pcm_channel(state->card, dmabuf->channel->num); + state->card->free_pcm_channel(state->card, + dmabuf->channel->num); /* Added by Matt Wu */ if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { - if( card->rec_channel_use_count-- < 0 ) + if (card->rec_channel_use_count-- < 0) card->rec_channel_use_count = 0; } } @@ -2770,37 +2873,36 @@ static int trident_release(struct inode /* we're covered by the open_sem */ up(&card->open_sem); - unlock_kernel(); return 0; } -static /*const*/ struct file_operations trident_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = trident_read, - .write = trident_write, - .poll = trident_poll, - .ioctl = trident_ioctl, - .mmap = trident_mmap, - .open = trident_open, - .release = trident_release, +static /* const */ struct file_operations trident_audio_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = trident_read, + .write = trident_write, + .poll = trident_poll, + .ioctl = trident_ioctl, + .mmap = trident_mmap, + .open = trident_open, + .release = trident_release, }; /* trident specific AC97 functions */ /* Write AC97 codec registers */ -static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) +static void +trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) { struct trident_card *card = (struct trident_card *)codec->private_data; unsigned int address, mask, busy; - unsigned short count = 0xffff; + unsigned short count = 0xffff; unsigned long flags; u32 data; data = ((u32) val) << 16; - switch (card->pci_id) - { + switch (card->pci_id) { default: case PCI_DEVICE_ID_SI_7018: address = SI_AC97_WRITE; @@ -2834,7 +2936,6 @@ static void trident_ac97_set(struct ac97 break; } while (count--); - data |= (mask | (reg & AC97_REG_ADDR)); if (count == 0) { @@ -2848,16 +2949,16 @@ static void trident_ac97_set(struct ac97 } /* Read AC97 codec registers */ -static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg) +static u16 +trident_ac97_get(struct ac97_codec *codec, u8 reg) { - struct trident_card *card = (struct trident_card *)codec->private_data; + struct trident_card *card = (struct trident_card *) codec->private_data; unsigned int address, mask, busy; unsigned short count = 0xffff; unsigned long flags; u32 data; - switch (card->pci_id) - { + switch (card->pci_id) { default: case PCI_DEVICE_ID_SI_7018: address = SI_AC97_READ; @@ -2905,31 +3006,31 @@ static u16 trident_ac97_get(struct ac97_ } /* rewrite ac97 read and write mixer register by hulei for ALI*/ -static int acquirecodecaccess(struct trident_card *card) +static int +acquirecodecaccess(struct trident_card *card) { - u16 wsemamask=0x6000; /* bit 14..13 */ + u16 wsemamask = 0x6000; /* bit 14..13 */ u16 wsemabits; - u16 wcontrol ; + u16 wcontrol; int block = 0; int ncount = 25; while (1) { - wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE)); + wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE)); wsemabits = wcontrol & wsemamask; - - if (wsemabits==0x4000) - return 1; /* 0x4000 is audio ,then success */ + + if (wsemabits == 0x4000) + return 1; /* 0x4000 is audio ,then success */ if (ncount-- < 0) break; - if (wsemabits == 0) - { - unlock: - outl(((u32)(wcontrol & 0x1eff)|0x00004000), TRID_REG(card, ALI_AC97_WRITE)); + if (wsemabits == 0) { + unlock: + outl(((u32) (wcontrol & 0x1eff) | 0x00004000), + TRID_REG(card, ALI_AC97_WRITE)); continue; } udelay(20); } - if(!block) - { + if (!block) { TRDBG("accesscodecsemaphore: try unlock\n"); block = 1; goto unlock; @@ -2937,24 +3038,26 @@ static int acquirecodecaccess(struct tri return 0; } -static void releasecodecaccess(struct trident_card *card) -{ +static void +releasecodecaccess(struct trident_card *card) +{ unsigned long wcontrol; - wcontrol = inl(TRID_REG(card, ALI_AC97_WRITE)); + wcontrol = inl(TRID_REG(card, ALI_AC97_WRITE)); outl((wcontrol & 0xffff1eff), TRID_REG(card, ALI_AC97_WRITE)); } -static int waitforstimertick(struct trident_card *card) +static int +waitforstimertick(struct trident_card *card) { unsigned long chk1, chk2; unsigned int wcount = 0xffff; - chk1 = inl(TRID_REG(card, ALI_STIMER)); - - while(1) { - chk2 = inl(TRID_REG(card, ALI_STIMER)); - if( (wcount > 0) && chk1 != chk2) + chk1 = inl(TRID_REG(card, ALI_STIMER)); + + while (1) { + chk2 = inl(TRID_REG(card, ALI_STIMER)); + if ((wcount > 0) && chk1 != chk2) return 1; - if(wcount <= 0) + if (wcount <= 0) break; udelay(50); } @@ -2962,16 +3065,17 @@ static int waitforstimertick(struct trid } /* Read AC97 codec registers for ALi*/ -static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg) +static u16 +ali_ac97_get(struct trident_card *card, int secondary, u8 reg) { unsigned int address, mask; unsigned int ncount; - unsigned long aud_reg; + unsigned long aud_reg; u32 data; - u16 wcontrol; - unsigned long flags; + u16 wcontrol; + unsigned long flags; - if(!card) + if (!card) BUG(); address = ALI_AC97_READ; @@ -2981,121 +3085,125 @@ static u16 ali_ac97_get(struct trident_c mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY; if (secondary) mask |= ALI_AC97_SECONDARY; - - spin_lock_irqsave(&card->lock, flags); - + + spin_lock_irqsave(&card->lock, flags); + if (!acquirecodecaccess(card)) printk(KERN_ERR "access codec fail\n"); - + wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE)); wcontrol &= 0xfe00; - wcontrol |= (0x8000|reg); - outw(wcontrol,TRID_REG(card, ALI_AC97_WRITE)); + wcontrol |= (0x8000 | reg); + outw(wcontrol, TRID_REG(card, ALI_AC97_WRITE)); data = (mask | (reg & AC97_REG_ADDR)); - - if(!waitforstimertick(card)) { + + if (!waitforstimertick(card)) { printk(KERN_ERR "ali_ac97_read: BIT_CLOCK is dead\n"); goto releasecodec; } - - udelay(20); - - ncount=10; - - while(1) { - if ((inw(TRID_REG(card,ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ) != 0) + + udelay(20); + + ncount = 10; + + while (1) { + if ((inw(TRID_REG(card, ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ) + != 0) break; - if(ncount <=0) + if (ncount <= 0) break; - if(ncount--==1) { + if (ncount-- == 1) { TRDBG("ali_ac97_read :try clear busy flag\n"); - aud_reg = inl(TRID_REG(card, ALI_AC97_WRITE)); - outl((aud_reg & 0xffff7fff), TRID_REG(card, ALI_AC97_WRITE)); + aud_reg = inl(TRID_REG(card, ALI_AC97_WRITE)); + outl((aud_reg & 0xffff7fff), + TRID_REG(card, ALI_AC97_WRITE)); } udelay(10); } - + data = inl(TRID_REG(card, address)); spin_unlock_irqrestore(&card->lock, flags); - + return ((u16) (data >> 16)); - releasecodec: +releasecodec: releasecodecaccess(card); spin_unlock_irqrestore(&card->lock, flags); printk(KERN_ERR "ali_ac97_read: AC97 CODEC read timed out.\n"); return 0; } - /* Write AC97 codec registers for hulei*/ -static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val) +static void +ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val) { unsigned int address, mask; unsigned int ncount; u32 data; - u16 wcontrol; - unsigned long flags; - + u16 wcontrol; + unsigned long flags; + data = ((u32) val) << 16; - - if(!card) + + if (!card) BUG(); - + address = ALI_AC97_WRITE; mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY; if (secondary) mask |= ALI_AC97_SECONDARY; if (card->revision == ALI_5451_V02) mask |= ALI_AC97_WRITE_MIXER_REGISTER; - + spin_lock_irqsave(&card->lock, flags); - if (!acquirecodecaccess(card)) + if (!acquirecodecaccess(card)) printk(KERN_ERR "ali_ac97_write: access codec fail\n"); - + wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE)); wcontrol &= 0xff00; - wcontrol |= (0x8100|reg);/* bit 8=1: (ali1535 )reserved /ali1535+ write */ - outl(( data |wcontrol), TRID_REG(card,ALI_AC97_WRITE )); + wcontrol |= (0x8100 | reg); /* bit 8=1: (ali1535 )reserved /ali1535+ write */ + outl((data | wcontrol), TRID_REG(card, ALI_AC97_WRITE)); - if(!waitforstimertick(card)) { + if (!waitforstimertick(card)) { printk(KERN_ERR "BIT_CLOCK is dead\n"); goto releasecodec; } - - ncount = 10; - while(1) { + + ncount = 10; + while (1) { wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE)); - if(!(wcontrol & 0x8000)) + if (!(wcontrol & 0x8000)) break; - if(ncount <= 0) + if (ncount <= 0) break; - if(ncount-- == 1) { + if (ncount-- == 1) { TRDBG("ali_ac97_set :try clear busy flag!!\n"); outw(wcontrol & 0x7fff, TRID_REG(card, ALI_AC97_WRITE)); } udelay(10); } - - releasecodec: + +releasecodec: releasecodecaccess(card); spin_unlock_irqrestore(&card->lock, flags); return; } -static void ali_enable_special_channel(struct trident_state *stat) +static void +ali_enable_special_channel(struct trident_state *stat) { struct trident_card *card = stat->card; unsigned long s_channels; - + s_channels = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); - s_channels |= (1<dmabuf.channel->num); + s_channels |= (1 << stat->dmabuf.channel->num); outl(s_channels, TRID_REG(card, ALI_GLOBAL_CONTROL)); } -static u16 ali_ac97_read(struct ac97_codec *codec, u8 reg) +static u16 +ali_ac97_read(struct ac97_codec *codec, u8 reg) { int id; u16 data; @@ -3104,25 +3212,26 @@ static u16 ali_ac97_read(struct ac97_cod /* Added by Matt Wu */ if (!codec) BUG(); - - card = (struct trident_card *)codec->private_data; - if(!card->mixer_regs_ready) + card = (struct trident_card *) codec->private_data; + + if (!card->mixer_regs_ready) return ali_ac97_get(card, codec->id, reg); /* - * FIXME: need to stop this caching some registers + * FIXME: need to stop this caching some registers */ - if(codec->id) + if (codec->id) id = 1; else id = 0; - data = card->mixer_regs[reg/2][id]; + data = card->mixer_regs[reg / 2][id]; return data; } -static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) +static void +ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) { int id; struct trident_card *card; @@ -3130,96 +3239,99 @@ static void ali_ac97_write(struct ac97_c /* Added by Matt Wu */ if (!codec) BUG(); - - card = (struct trident_card *)codec->private_data; - if (!card->mixer_regs_ready) - { + card = (struct trident_card *) codec->private_data; + + if (!card->mixer_regs_ready) { ali_ac97_set(card, codec->id, reg, val); return; } - if(codec->id) + if (codec->id) id = 1; else id = 0; - card->mixer_regs[reg/2][id] = val; + card->mixer_regs[reg / 2][id] = val; ali_ac97_set(card, codec->id, reg, val); } /* -flag: ALI_SPDIF_OUT_TO_SPDIF_OUT - ALI_PCM_TO_SPDIF_OUT + flag: ALI_SPDIF_OUT_TO_SPDIF_OUT + ALI_PCM_TO_SPDIF_OUT */ -static void ali_setup_spdif_out(struct trident_card *card, int flag) +static void +ali_setup_spdif_out(struct trident_card *card, int flag) { unsigned long spdif; unsigned char ch; - char temp; - struct pci_dev *pci_dev = NULL; + char temp; + struct pci_dev *pci_dev = NULL; - pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); - if (pci_dev == NULL) - return; - pci_read_config_byte(pci_dev, 0x61, &temp); - temp |= 0x40; - pci_write_config_byte(pci_dev, 0x61, temp); - pci_read_config_byte(pci_dev, 0x7d, &temp); - temp |= 0x01; - pci_write_config_byte(pci_dev, 0x7d, temp); - pci_read_config_byte(pci_dev, 0x7e, &temp); - temp &= (~0x20); - temp |= 0x10; - pci_write_config_byte(pci_dev, 0x7e, temp); + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); + if (pci_dev == NULL) + return; + pci_read_config_byte(pci_dev, 0x61, &temp); + temp |= 0x40; + pci_write_config_byte(pci_dev, 0x61, temp); + pci_read_config_byte(pci_dev, 0x7d, &temp); + temp |= 0x01; + pci_write_config_byte(pci_dev, 0x7d, temp); + pci_read_config_byte(pci_dev, 0x7e, &temp); + temp &= (~0x20); + temp |= 0x10; + pci_write_config_byte(pci_dev, 0x7e, temp); ch = inb(TRID_REG(card, ALI_SCTRL)); outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL)); ch = inb(TRID_REG(card, ALI_SPDIF_CTRL)); outb(ch & ALI_SPDIF_OUT_CH_STATUS, TRID_REG(card, ALI_SPDIF_CTRL)); - + if (flag & ALI_SPDIF_OUT_TO_SPDIF_OUT) { - spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); - spdif |= ALI_SPDIF_OUT_CH_ENABLE; - spdif &= ALI_SPDIF_OUT_SEL_SPDIF; - outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif |= ALI_SPDIF_OUT_CH_ENABLE; + spdif &= ALI_SPDIF_OUT_SEL_SPDIF; + outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); spdif = inw(TRID_REG(card, ALI_SPDIF_CS)); if (flag & ALI_SPDIF_OUT_NON_PCM) - spdif |= 0x0002; - else spdif &= (~0x0002); - outw(spdif, TRID_REG(card, ALI_SPDIF_CS)); - } - else { - spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); - spdif |= ALI_SPDIF_OUT_SEL_PCM; - outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); - } + spdif |= 0x0002; + else + spdif &= (~0x0002); + outw(spdif, TRID_REG(card, ALI_SPDIF_CS)); + } else { + spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif |= ALI_SPDIF_OUT_SEL_PCM; + outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + } } -static void ali_disable_special_channel(struct trident_card *card, int ch) +static void +ali_disable_special_channel(struct trident_card *card, int ch) { unsigned long sc; - + sc = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); sc &= ~(1 << ch); outl(sc, TRID_REG(card, ALI_GLOBAL_CONTROL)); } -static void ali_disable_spdif_in(struct trident_card *card) +static void +ali_disable_spdif_in(struct trident_card *card) { unsigned long spdif; - + spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); spdif &= (~ALI_SPDIF_IN_SUPPORT); outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); - - ali_disable_special_channel(card, ALI_SPDIF_IN_CHANNEL); + + ali_disable_special_channel(card, ALI_SPDIF_IN_CHANNEL); } -static void ali_setup_spdif_in(struct trident_card *card) -{ +static void +ali_setup_spdif_in(struct trident_card *card) +{ unsigned long spdif; //Set SPDIF IN Supported @@ -3236,99 +3348,98 @@ static void ali_setup_spdif_in(struct tr spdif |= ALI_SPDIF_IN_CH_STATUS; outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); /* - spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); - spdif |= ALI_SPDIF_IN_FUNC_ENABLE; - outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); + spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); + spdif |= ALI_SPDIF_IN_FUNC_ENABLE; + outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); */ } -static void ali_delay(struct trident_card *card,int interval) +static void +ali_delay(struct trident_card *card, int interval) { - unsigned long begintimer,currenttimer; + unsigned long begintimer, currenttimer; - begintimer = inl(TRID_REG(card, ALI_STIMER)); - currenttimer = inl(TRID_REG(card, ALI_STIMER)); + begintimer = inl(TRID_REG(card, ALI_STIMER)); + currenttimer = inl(TRID_REG(card, ALI_STIMER)); while (currenttimer < begintimer + interval) - currenttimer = inl(TRID_REG(card, ALI_STIMER)); + currenttimer = inl(TRID_REG(card, ALI_STIMER)); } -static void ali_detect_spdif_rate(struct trident_card *card) +static void +ali_detect_spdif_rate(struct trident_card *card) { - u16 wval = 0; + u16 wval = 0; u16 count = 0; - u8 bval = 0, R1 = 0, R2 = 0; + u8 bval = 0, R1 = 0, R2 = 0; - bval = inb(TRID_REG(card,ALI_SPDIF_CTRL)); + bval = inb(TRID_REG(card, ALI_SPDIF_CTRL)); bval |= 0x02; - outb(bval,TRID_REG(card,ALI_SPDIF_CTRL)); + outb(bval, TRID_REG(card, ALI_SPDIF_CTRL)); - bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1)); + bval = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); bval |= 0x1F; - outb(bval,TRID_REG(card,ALI_SPDIF_CTRL + 1)); + outb(bval, TRID_REG(card, ALI_SPDIF_CTRL + 1)); - while (((R1 < 0x0B )||(R1 > 0x0E)) && (R1 != 0x12) && count <= 50000) - { - count ++; + while (((R1 < 0x0B) || (R1 > 0x0E)) && (R1 != 0x12) && count <= 50000) { + count++; ali_delay(card, 6); - bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1)); + bval = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); R1 = bval & 0x1F; } - if (count > 50000) - { - printk(KERN_WARNING "trident: Error in ali_detect_spdif_rate!\n"); + if (count > 50000) { + printk(KERN_WARNING + "trident: Error in ali_detect_spdif_rate!\n"); return; } count = 0; - while (count <= 50000) - { - count ++; + while (count <= 50000) { + count++; ali_delay(card, 6); - bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1)); + bval = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); R2 = bval & 0x1F; - if(R2 != R1) + if (R2 != R1) R1 = R2; else break; } - if (count > 50000) - { - printk(KERN_WARNING "trident: Error in ali_detect_spdif_rate!\n"); + if (count > 50000) { + printk(KERN_WARNING + "trident: Error in ali_detect_spdif_rate!\n"); return; } - switch (R2) - { + switch (R2) { case 0x0b: case 0x0c: case 0x0d: case 0x0e: - wval = inw(TRID_REG(card,ALI_SPDIF_CTRL + 2)); + wval = inw(TRID_REG(card, ALI_SPDIF_CTRL + 2)); wval &= 0xE0F0; - wval |= (u16)0x09 << 8 | (u16)0x05; - outw(wval,TRID_REG(card,ALI_SPDIF_CTRL + 2)); + wval |= (u16) 0x09 << 8 | (u16) 0x05; + outw(wval, TRID_REG(card, ALI_SPDIF_CTRL + 2)); - bval = inb(TRID_REG(card,ALI_SPDIF_CS +3)) & 0xF0; - outb(bval|0x02,TRID_REG(card,ALI_SPDIF_CS + 3)); + bval = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xF0; + outb(bval | 0x02, TRID_REG(card, ALI_SPDIF_CS + 3)); break; case 0x12: - wval = inw(TRID_REG(card,ALI_SPDIF_CTRL + 2)); + wval = inw(TRID_REG(card, ALI_SPDIF_CTRL + 2)); wval &= 0xE0F0; - wval |= (u16)0x0E << 8 | (u16)0x08; - outw(wval,TRID_REG(card,ALI_SPDIF_CTRL + 2)); + wval |= (u16) 0x0E << 8 | (u16) 0x08; + outw(wval, TRID_REG(card, ALI_SPDIF_CTRL + 2)); - bval = inb(TRID_REG(card,ALI_SPDIF_CS +3)) & 0xF0; - outb(bval|0x03,TRID_REG(card,ALI_SPDIF_CS + 3)); + bval = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xF0; + outb(bval | 0x03, TRID_REG(card, ALI_SPDIF_CS + 3)); break; default: @@ -3337,23 +3448,23 @@ static void ali_detect_spdif_rate(struct } -static unsigned int ali_get_spdif_in_rate(struct trident_card *card) +static unsigned int +ali_get_spdif_in_rate(struct trident_card *card) { - u32 dwRate = 0; - u8 bval = 0; + u32 dwRate = 0; + u8 bval = 0; ali_detect_spdif_rate(card); - bval = inb(TRID_REG(card,ALI_SPDIF_CTRL)); + bval = inb(TRID_REG(card, ALI_SPDIF_CTRL)); bval &= 0x7F; bval |= 0x40; - outb(bval,TRID_REG(card,ALI_SPDIF_CTRL)); + outb(bval, TRID_REG(card, ALI_SPDIF_CTRL)); - bval = inb(TRID_REG(card,ALI_SPDIF_CS + 3)); + bval = inb(TRID_REG(card, ALI_SPDIF_CS + 3)); bval &= 0x0F; - switch (bval) - { + switch (bval) { case 0: dwRate = 44100; break; @@ -3369,24 +3480,27 @@ static unsigned int ali_get_spdif_in_rat } return dwRate; - + } -static int ali_close_multi_channels(void) +static int +ali_close_multi_channels(void) { char temp = 0; struct pci_dev *pci_dev = NULL; - pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev); - if (pci_dev == NULL) - return -1; + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + pci_dev); + if (pci_dev == NULL) + return -1; pci_read_config_byte(pci_dev, 0x59, &temp); temp &= ~0x80; pci_write_config_byte(pci_dev, 0x59, temp); - - pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev); + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + pci_dev); if (pci_dev == NULL) - return -1; + return -1; pci_read_config_byte(pci_dev, 0xB8, &temp); temp &= ~0x20; @@ -3395,25 +3509,28 @@ static int ali_close_multi_channels(void return 0; } -static int ali_setup_multi_channels(struct trident_card *card, int chan_nums) +static int +ali_setup_multi_channels(struct trident_card *card, int chan_nums) { unsigned long dwValue; char temp = 0; struct pci_dev *pci_dev = NULL; - pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + pci_dev); if (pci_dev == NULL) - return -1; + return -1; pci_read_config_byte(pci_dev, 0x59, &temp); temp |= 0x80; pci_write_config_byte(pci_dev, 0x59, temp); - - pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev); - if (pci_dev == NULL) - return -1; - pci_read_config_byte(pci_dev, (int)0xB8, &temp); + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + pci_dev); + if (pci_dev == NULL) + return -1; + pci_read_config_byte(pci_dev, (int) 0xB8, &temp); temp |= 0x20; - pci_write_config_byte(pci_dev, (int)0xB8,(u8) temp); + pci_write_config_byte(pci_dev, (int) 0xB8, (u8) temp); if (chan_nums == 6) { dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000; outl(dwValue, TRID_REG(card, ALI_SCTRL)); @@ -3424,11 +3541,10 @@ static int ali_setup_multi_channels(stru ali_ac97_write(card->ac97_codec[0], 0x36, 0); ali_ac97_write(card->ac97_codec[0], 0x38, 0); /* - * On a board with a single codec you won't get the - * surround. On other boards configure it. + * On a board with a single codec you won't get the + * surround. On other boards configure it. */ - if(card->ac97_codec[1]!=NULL) - { + if (card->ac97_codec[1] != NULL) { ali_ac97_write(card->ac97_codec[1], 0x36, 0); ali_ac97_write(card->ac97_codec[1], 0x38, 0); ali_ac97_write(card->ac97_codec[1], 0x02, 0x0606); @@ -3441,7 +3557,8 @@ static int ali_setup_multi_channels(stru return -EINVAL; } -static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel) +static void +ali_free_pcm_channel(struct trident_card *card, unsigned int channel) { int bank; @@ -3454,164 +3571,179 @@ static void ali_free_pcm_channel(struct card->banks[bank].bitmap &= ~(1 << (channel)); } -static int ali_allocate_other_states_resources(struct trident_state *state, int chan_nums) +static int +ali_allocate_other_states_resources(struct trident_state *state, int chan_nums) { struct trident_card *card = state->card; struct trident_state *s; int i, state_count = 0; struct trident_pcm_bank *bank; struct trident_channel *channel; - + unsigned long num; + bank = &card->banks[BANK_A]; - - if (chan_nums == 6) { - for(i = 0;(i < ALI_CHANNELS) && (state_count != 4); i++) { - if (!card->states[i]) { - if (!(bank->bitmap & (1 << ali_multi_channels_5_1[state_count]))) { - bank->bitmap |= (1 << ali_multi_channels_5_1[state_count]); - channel = &bank->channels[ali_multi_channels_5_1[state_count]]; - channel->num = ali_multi_channels_5_1[state_count]; - } - else { - state_count--; - for (; state_count >= 0; state_count--) { - kfree(state->other_states[state_count]); - ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]); - } - return -EBUSY; - } - s = card->states[i] = (struct trident_state *) - kmalloc(sizeof(struct trident_state), GFP_KERNEL); - if (!s) { - ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]); - state_count--; - for (; state_count >= 0; state_count--) { - ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]); - kfree(state->other_states[state_count]); - } - return -ENOMEM; - } - memset(s, 0, sizeof(struct trident_state)); - - s->dmabuf.channel = channel; - s->dmabuf.ossfragshift = s->dmabuf.ossmaxfrags = s->dmabuf.subdivision = 0; - init_waitqueue_head(&s->dmabuf.wait); - s->magic = card->magic; - s->card = card; - s->virt = i; - ali_enable_special_channel(s); - state->other_states[state_count++] = s; + + if (chan_nums != 6) + return 0; + + for (i = 0; (i < ALI_CHANNELS) && (state_count != 4); i++) { + if (card->states[i]) + continue; + + num = ali_multi_channels_5_1[state_count]; + if (!(bank->bitmap & (1 << num))) { + bank->bitmap |= 1 << num; + channel = &bank->channels[num]; + channel->num = num; + } else { + state_count--; + for (; state_count >= 0; state_count--) { + kfree(state->other_states[state_count]); + num = ali_multi_channels_5_1[state_count]; + ali_free_pcm_channel(card, num); } + return -EBUSY; } - - if (state_count != 4) { + s = card->states[i] = kmalloc(sizeof(*state), GFP_KERNEL); + if (!s) { + num = ali_multi_channels_5_1[state_count]; + ali_free_pcm_channel(card, num); state_count--; for (; state_count >= 0; state_count--) { + num = ali_multi_channels_5_1[state_count]; + ali_free_pcm_channel(card, num); kfree(state->other_states[state_count]); - ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]); } - return -EBUSY; + return -ENOMEM; + } + memset(s, 0, sizeof(*state)); + + s->dmabuf.channel = channel; + s->dmabuf.ossfragshift = s->dmabuf.ossmaxfrags = + s->dmabuf.subdivision = 0; + init_waitqueue_head(&s->dmabuf.wait); + s->magic = card->magic; + s->card = card; + s->virt = i; + ali_enable_special_channel(s); + state->other_states[state_count++] = s; + } + + if (state_count != 4) { + state_count--; + for (; state_count >= 0; state_count--) { + kfree(state->other_states[state_count]); + num = ali_multi_channels_5_1[state_count]; + ali_free_pcm_channel(card, num); } + return -EBUSY; } return 0; } -static void ali_save_regs(struct trident_card *card) +static void +ali_save_regs(struct trident_card *card) { unsigned long flags; int i, j; - spin_lock_irqsave(&card->lock, flags); + spin_lock_irqsave(&card->lock, flags); - ali_registers.global_regs[0x2c] = inl(TRID_REG(card,T4D_MISCINT)); - //ali_registers.global_regs[0x20] = inl(TRID_REG(card,T4D_START_A)); - ali_registers.global_regs[0x21] = inl(TRID_REG(card,T4D_STOP_A)); - - //disable all IRQ bits + ali_registers.global_regs[0x2c] = inl(TRID_REG(card, T4D_MISCINT)); +#if 0 + ali_registers.global_regs[0x20] = inl(TRID_REG(card,T4D_START_A)); +#endif /* 0 */ + ali_registers.global_regs[0x21] = inl(TRID_REG(card, T4D_STOP_A)); + + /* disable all IRQ bits */ outl(ALI_DISABLE_ALL_IRQ, TRID_REG(card, T4D_MISCINT)); - + for (i = 1; i < ALI_MIXER_REGS; i++) - ali_registers.mixer_regs[i] = ali_ac97_read (card->ac97_codec[0], i*2); - - for (i = 0; i < ALI_GLOBAL_REGS; i++) - { - if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A)) + ali_registers.mixer_regs[i] = ali_ac97_read(card->ac97_codec[0], i * 2); + + for (i = 0; i < ALI_GLOBAL_REGS; i++) { + if ((i * 4 == T4D_MISCINT) || (i * 4 == T4D_STOP_A)) continue; - ali_registers.global_regs[i] = inl(TRID_REG(card, i*4)); + ali_registers.global_regs[i] = inl(TRID_REG(card, i * 4)); } - - for (i = 0; i < ALI_CHANNELS; i++) - { - outb(i,TRID_REG(card, T4D_LFO_GC_CIR)); - for (j = 0; j < ALI_CHANNEL_REGS; j++) - ali_registers.channel_regs[i][j] = inl(TRID_REG(card, j*4 + 0xe0)); + + for (i = 0; i < ALI_CHANNELS; i++) { + outb(i, TRID_REG(card, T4D_LFO_GC_CIR)); + for (j = 0; j < ALI_CHANNEL_REGS; j++) + ali_registers.channel_regs[i][j] = + inl(TRID_REG(card, j * 4 + 0xe0)); } - //Stop all HW channel + /* Stop all HW channel */ outl(ALI_STOP_ALL_CHANNELS, TRID_REG(card, T4D_STOP_A)); - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); } -static void ali_restore_regs(struct trident_card *card) +static void +ali_restore_regs(struct trident_card *card) { unsigned long flags; int i, j; - spin_lock_irqsave(&card->lock, flags); - + spin_lock_irqsave(&card->lock, flags); + for (i = 1; i < ALI_MIXER_REGS; i++) - ali_ac97_write(card->ac97_codec[0], i*2, ali_registers.mixer_regs[i]); - - for (i = 0; i < ALI_CHANNELS; i++) - { - outb(i,TRID_REG(card, T4D_LFO_GC_CIR)); - for (j = 0; j < ALI_CHANNEL_REGS; j++) - outl(ali_registers.channel_regs[i][j], TRID_REG(card, j*4 + 0xe0)); + ali_ac97_write(card->ac97_codec[0], i * 2, + ali_registers.mixer_regs[i]); + + for (i = 0; i < ALI_CHANNELS; i++) { + outb(i, TRID_REG(card, T4D_LFO_GC_CIR)); + for (j = 0; j < ALI_CHANNEL_REGS; j++) + outl(ali_registers.channel_regs[i][j], + TRID_REG(card, j * 4 + 0xe0)); } - - for (i = 0; i < ALI_GLOBAL_REGS; i++) - { - if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A) || (i*4 == T4D_START_A)) + + for (i = 0; i < ALI_GLOBAL_REGS; i++) { + if ((i * 4 == T4D_MISCINT) || (i * 4 == T4D_STOP_A) + || (i * 4 == T4D_START_A)) continue; - outl(ali_registers.global_regs[i], TRID_REG(card, i*4)); + outl(ali_registers.global_regs[i], TRID_REG(card, i * 4)); } - - //start HW channel - outl(ali_registers.global_regs[0x20], TRID_REG(card,T4D_START_A)); - //restore IRQ enable bits - outl(ali_registers.global_regs[0x2c], TRID_REG(card,T4D_MISCINT)); - spin_unlock_irqrestore(&card->lock, flags); + /* start HW channel */ + outl(ali_registers.global_regs[0x20], TRID_REG(card, T4D_START_A)); + /* restore IRQ enable bits */ + outl(ali_registers.global_regs[0x2c], TRID_REG(card, T4D_MISCINT)); + + spin_unlock_irqrestore(&card->lock, flags); } -static int trident_suspend(struct pci_dev *dev, u32 unused) +static int +trident_suspend(struct pci_dev *dev, u32 unused) { - struct trident_card *card = pci_get_drvdata(dev); + struct trident_card *card = pci_get_drvdata(dev); - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { ali_save_regs(card); } return 0; } -static int trident_resume(struct pci_dev *dev) +static int +trident_resume(struct pci_dev *dev) { - struct trident_card *card = pci_get_drvdata(dev); + struct trident_card *card = pci_get_drvdata(dev); - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { ali_restore_regs(card); } return 0; } -static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card) +static struct trident_channel * +ali_alloc_pcm_channel(struct trident_card *card) { struct trident_pcm_bank *bank; int idx; bank = &card->banks[BANK_A]; - + if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) & (ALI_SPDIF_OUT_CH_ENABLE)) { idx = ALI_SPDIF_OUT_CHANNEL; if (!(bank->bitmap & (1 << idx))) { @@ -3621,8 +3753,9 @@ static struct trident_channel *ali_alloc return channel; } } - - for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST ; idx++) { + + for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST; + idx++) { if (!(bank->bitmap & (1 << idx))) { struct trident_channel *channel = &bank->channels[idx]; bank->bitmap |= 1 << idx; @@ -3632,39 +3765,46 @@ static struct trident_channel *ali_alloc } /* no more free channels avaliable */ -// printk(KERN_ERR "ali: no more channels available on Bank A.\n"); +#if 0 + printk(KERN_ERR "ali: no more channels available on Bank A.\n"); +#endif /* 0 */ return NULL; } -static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card) +static struct trident_channel * +ali_alloc_rec_pcm_channel(struct trident_card *card) { struct trident_pcm_bank *bank; int idx; - + if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_IN_SUPPORT) idx = ALI_SPDIF_IN_CHANNEL; - else idx = ALI_PCM_IN_CHANNEL; + else + idx = ALI_PCM_IN_CHANNEL; bank = &card->banks[BANK_A]; - + if (!(bank->bitmap & (1 << idx))) { struct trident_channel *channel = &bank->channels[idx]; bank->bitmap |= 1 << idx; channel->num = idx; return channel; } - + /* no free recordable channels avaliable */ -// printk(KERN_ERR "ali: no recordable channels available on Bank A.\n"); +#if 0 + printk(KERN_ERR "ali: no recordable channels available on Bank A.\n"); +#endif /* 0 */ return NULL; } -static void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate) +static void +ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate) { unsigned char ch_st_sel; unsigned short status_rate; - - switch(rate) { + + switch (rate) { case 44100: status_rate = 0; break; @@ -3676,28 +3816,30 @@ static void ali_set_spdif_out_rate(struc status_rate = 0x200; break; } - - ch_st_sel = inb(TRID_REG(card, ALI_SPDIF_CTRL)) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out - + + /* select spdif_out */ + ch_st_sel = inb(TRID_REG(card, ALI_SPDIF_CTRL)) & ALI_SPDIF_OUT_CH_STATUS; + ch_st_sel |= 0x80; //select right outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL)); outb(status_rate | 0x20, TRID_REG(card, ALI_SPDIF_CS + 2)); - + ch_st_sel &= (~0x80); //select left outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL)); outw(status_rate | 0x10, TRID_REG(card, ALI_SPDIF_CS + 2)); } -static void ali_address_interrupt(struct trident_card *card) +static void +ali_address_interrupt(struct trident_card *card) { int i, channel; struct trident_state *state; u32 mask, channel_mask; - - mask = trident_get_interrupt_mask (card, 0); + + mask = trident_get_interrupt_mask(card, 0); for (i = 0; i < NR_HW_CH; i++) { if ((state = card->states[i]) == NULL) - continue; + continue; channel = state->dmabuf.channel->num; if ((channel_mask = 1 << channel) & mask) { mask &= ~channel_mask; @@ -3719,23 +3861,22 @@ static void ali_address_interrupt(struct } } -/* Updating the values of counters of other_states' DMAs without lock -protection is no harm because all DMAs of multi-channels and interrupt -depend on a master state's DMA, and changing the counters of the master -state DMA is protected by a spinlock. -*/ -static int ali_write_5_1(struct trident_state *state, - const char *buf, int cnt_for_multi_channel, - unsigned int *copy_count, - unsigned int *state_cnt) +/* Updating the values of counters of other_states' DMAs without lock */ +/* protection is no harm because all DMAs of multi-channels and interrupt */ +/* depend on a master state's DMA, and changing the counters of the master */ +/* state DMA is protected by a spinlock. */ +static int +ali_write_5_1(struct trident_state *state, + const char *buf, int cnt_for_multi_channel, + unsigned int *copy_count, unsigned int *state_cnt) { - + struct dmabuf *dmabuf = &state->dmabuf; struct dmabuf *dmabuf_temp; const char *buffer = buf; unsigned swptr, other_dma_nums, sample_s; unsigned int i, loop; - + other_dma_nums = 4; sample_s = sample_size[dmabuf->fmt] >> 1; swptr = dmabuf->swptr; @@ -3744,17 +3885,21 @@ static int ali_write_5_1(struct trident_ if (i == 1) { if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s)) return -EFAULT; - seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); + seek_offset(swptr, buffer, cnt_for_multi_channel, + sample_s, *copy_count); i--; (*state_cnt) += sample_s; state->multi_channels_adjust_count++; - } - else i = i - (state->chans_num - other_dma_nums); + } else + i = i - (state->chans_num - other_dma_nums); for (; (i < other_dma_nums) && (cnt_for_multi_channel > 0); i++) { dmabuf_temp = &state->other_states[i]->dmabuf; - if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s)) + if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, + buffer, sample_s)) return -EFAULT; - seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); + seek_offset(dmabuf_temp->swptr, buffer, + cnt_for_multi_channel, sample_s, + *copy_count); } if (cnt_for_multi_channel == 0) state->multi_channels_adjust_count += i; @@ -3764,56 +3909,78 @@ static int ali_write_5_1(struct trident_ for (i = 0; i < loop; i++) { if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s * 2)) return -EFAULT; - seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s * 2, *copy_count); + seek_offset(swptr, buffer, cnt_for_multi_channel, + sample_s * 2, *copy_count); (*state_cnt) += (sample_s * 2); - + dmabuf_temp = &state->other_states[0]->dmabuf; - if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s)) + if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, + buffer, sample_s)) return -EFAULT; - seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); - + seek_offset(dmabuf_temp->swptr, buffer, + cnt_for_multi_channel, sample_s, + *copy_count); + dmabuf_temp = &state->other_states[1]->dmabuf; - if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s)) + if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, + buffer, sample_s)) return -EFAULT; - seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); - + seek_offset(dmabuf_temp->swptr, buffer, + cnt_for_multi_channel, sample_s, + *copy_count); + dmabuf_temp = &state->other_states[2]->dmabuf; - if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s)) + if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, + buffer, sample_s)) return -EFAULT; - seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); - + seek_offset(dmabuf_temp->swptr, buffer, + cnt_for_multi_channel, sample_s, + *copy_count); + dmabuf_temp = &state->other_states[3]->dmabuf; - if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s)) + if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, + buffer, sample_s)) return -EFAULT; - seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); + seek_offset(dmabuf_temp->swptr, buffer, + cnt_for_multi_channel, sample_s, + *copy_count); } - + if (cnt_for_multi_channel > 0) { state->multi_channels_adjust_count = cnt_for_multi_channel / sample_s; - + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s)) return -EFAULT; - seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); + seek_offset(swptr, buffer, cnt_for_multi_channel, + sample_s, *copy_count); (*state_cnt) += sample_s; - + if (cnt_for_multi_channel > 0) { if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s)) return -EFAULT; - seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); + seek_offset(swptr, buffer, + cnt_for_multi_channel, sample_s, + *copy_count); (*state_cnt) += sample_s; - + if (cnt_for_multi_channel > 0) { - loop = state->multi_channels_adjust_count - (state->chans_num - other_dma_nums); + int diff = state->chans_num - other_dma_nums; + loop = state->multi_channels_adjust_count - diff; for (i = 0; i < loop; i++) { dmabuf_temp = &state->other_states[i]->dmabuf; - if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s)) + if (copy_from_user(dmabuf_temp->rawbuf + + dmabuf_temp->swptr, buffer, + sample_s)) return -EFAULT; - seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count); + seek_offset(dmabuf_temp->swptr, + buffer, + cnt_for_multi_channel, + sample_s, + *copy_count); } } } - } - else + } else state->multi_channels_adjust_count = 0; } for (i = 0; i < other_dma_nums; i++) { @@ -3823,15 +3990,16 @@ static int ali_write_5_1(struct trident_ return *state_cnt; } -static void ali_free_other_states_resources(struct trident_state *state) +static void +ali_free_other_states_resources(struct trident_state *state) { int i; struct trident_card *card = state->card; struct trident_state *s; unsigned other_states_count; - - other_states_count = state->chans_num - 2; /* except PCM L/R channels*/ - for ( i = 0; i < other_states_count; i++) { + + other_states_count = state->chans_num - 2; /* except PCM L/R channels */ + for (i = 0; i < other_states_count; i++) { s = state->other_states[i]; dealloc_dmabuf(&s->dmabuf, card->pci_dev); ali_disable_special_channel(s->card, s->dmabuf.channel->num); @@ -3842,35 +4010,42 @@ static void ali_free_other_states_resour } struct proc_dir_entry *res; -static int ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +static int +ali_write_proc(struct file *file, const char *buffer, unsigned long count, + void *data) { - struct trident_card *card = (struct trident_card *)data; + struct trident_card *card = (struct trident_card *) data; unsigned long flags; char c; - if (count<0) + if (count < 0) return -EINVAL; if (count == 0) return 0; if (get_user(c, buffer)) return -EFAULT; - + spin_lock_irqsave(&card->lock, flags); switch (c) { - case '0': + case '0': ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); break; - case '1': - ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT|ALI_SPDIF_OUT_PCM); - break; - case '2': - ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT|ALI_SPDIF_OUT_NON_PCM); - break; - case '3': - ali_disable_spdif_in(card); //default + case '1': + ali_setup_spdif_out(card, + ALI_SPDIF_OUT_TO_SPDIF_OUT | + ALI_SPDIF_OUT_PCM); + break; + case '2': + ali_setup_spdif_out(card, + ALI_SPDIF_OUT_TO_SPDIF_OUT | + ALI_SPDIF_OUT_NON_PCM); + break; + case '3': + /* default */ + ali_disable_spdif_in(card); break; - case '4': + case '4': ali_setup_spdif_in(card); break; } @@ -3880,7 +4055,8 @@ static int ali_write_proc(struct file *f } /* OSS /dev/mixer file operation methods */ -static int trident_open_mixdev(struct inode *inode, struct file *file) +static int +trident_open_mixdev(struct inode *inode, struct file *file) { int i = 0; int minor = iminor(inode); @@ -3895,38 +4071,39 @@ static int trident_open_mixdev(struct in if (!card) { return -ENODEV; } - match: +match: file->private_data = card->ac97_codec[i]; - return 0; } -static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int +trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) { - struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + struct ac97_codec *codec = (struct ac97_codec *) file->private_data; return codec->mixer_ioctl(codec, cmd, arg); } -static /*const*/ struct file_operations trident_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = trident_ioctl_mixdev, - .open = trident_open_mixdev, +static /* const */ struct file_operations trident_mixer_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = trident_ioctl_mixdev, + .open = trident_open_mixdev, }; -static int ali_reset_5451(struct trident_card *card) +static int +ali_reset_5451(struct trident_card *card) { struct pci_dev *pci_dev = NULL; - unsigned int dwVal; + unsigned int dwVal; unsigned short wCount, wReg; - pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); + pci_dev =pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); if (pci_dev == NULL) return -1; - + pci_read_config_dword(pci_dev, 0x7c, &dwVal); pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000); udelay(5000); @@ -3945,45 +4122,46 @@ static int ali_reset_5451(struct trident pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff); udelay(5000); + /* TODO: recognize if we have a PM capable codec and only do this */ + /* if the codec is PM capable */ wCount = 2000; - while(wCount--) { + while (wCount--) { wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL); - if((wReg & 0x000f) == 0x000f) + if ((wReg & 0x000f) == 0x000f) return 0; udelay(5000); } + /* This is non fatal if you have a non PM capable codec.. */ return 0; } /* AC97 codec initialisation. */ -static int __devinit trident_ac97_init(struct trident_card *card) +static int __devinit +trident_ac97_init(struct trident_card *card) { int num_ac97 = 0; unsigned long ready_2nd = 0; struct ac97_codec *codec; int i = 0; - /* initialize controller side of AC link, and find out if secondary codes really exist */ - switch (card->pci_id) - { + switch (card->pci_id) { case PCI_DEVICE_ID_ALI_5451: - if (ali_reset_5451(card)) - { + if (ali_reset_5451(card)) { printk(KERN_ERR "trident_ac97_init: error resetting 5451.\n"); return -1; } - outl(0x80000001,TRID_REG(card, ALI_GLOBAL_CONTROL)); - outl(0x00000000,TRID_REG(card, T4D_AINTEN_A)); - outl(0xffffffff,TRID_REG(card, T4D_AINT_A)); - outl(0x00000000,TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); - outb(0x10, TRID_REG(card, ALI_MPUR2)); + outl(0x80000001, TRID_REG(card, ALI_GLOBAL_CONTROL)); + outl(0x00000000, TRID_REG(card, T4D_AINTEN_A)); + outl(0xffffffff, TRID_REG(card, T4D_AINT_A)); + outl(0x00000000, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); + outb(0x10, TRID_REG(card, ALI_MPUR2)); ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); ready_2nd &= 0x3fff; outl(ready_2nd | PCMOUT | 0x8000, TRID_REG(card, ALI_SCTRL)); - ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); + ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); ready_2nd &= SI_AC97_SECONDARY_READY; if (card->revision < ALI_5451_V02) ready_2nd = 0; @@ -3992,7 +4170,7 @@ static int __devinit trident_ac97_init(s /* disable AC97 GPIO interrupt */ outl(0x00, TRID_REG(card, SI_AC97_GPIO)); /* when power up the AC link is in cold reset mode so stop it */ - outl(PCMOUT|SURROUT|CENTEROUT|LFEOUT|SECONDARY_ID, + outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT | SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL)); /* it take a long time to recover from a cold reset (especially when you have more than one codec) */ @@ -4014,7 +4192,7 @@ static int __devinit trident_ac97_init(s /* disable AC97 GPIO interrupt */ outl(0x00, TRID_REG(card, SI_AC97_GPIO)); /* when power up, the AC link is in cold reset mode, so stop it */ - outl(PCMOUT|SURROUT|CENTEROUT|LFEOUT, + outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT, TRID_REG(card, SI_SERIAL_INTF_CTRL)); /* it take a long time to recover from a cold reset (especially when you have more than one codec) */ @@ -4036,16 +4214,16 @@ static int __devinit trident_ac97_init(s if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { codec->codec_read = ali_ac97_read; codec->codec_write = ali_ac97_write; - } - else { + } else { codec->codec_read = trident_ac97_get; codec->codec_write = trident_ac97_set; } - + if (ac97_probe_codec(codec) == 0) break; - if ((codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) { + codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1); + if (codec->dev_mixer < 0) { printk(KERN_ERR "trident: couldn't register mixer!\n"); ac97_release_codec(codec); break; @@ -4062,65 +4240,73 @@ static int __devinit trident_ac97_init(s for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { if (card->ac97_codec[num_ac97] == NULL) break; - for (i=0; i<64;i++) - card->mixer_regs[i][num_ac97] = ali_ac97_get(card, num_ac97,i*2); + for (i = 0; i < 64; i++) { + u16 reg = ali_ac97_get(card, num_ac97, i * 2); + card->mixer_regs[i][num_ac97] = reg; + } } } - return num_ac97+1; + return num_ac97 + 1; } /* Gameport functions for the cards ADC gameport */ -static unsigned char trident_game_read(struct gameport *gameport) +static unsigned char +trident_game_read(struct gameport *gameport) { struct trident_card *card = gameport->driver; return inb(TRID_REG(card, T4D_GAME_LEG)); } -static void trident_game_trigger(struct gameport *gameport) +static void +trident_game_trigger(struct gameport *gameport) { struct trident_card *card = gameport->driver; outb(0xff, TRID_REG(card, T4D_GAME_LEG)); } -static int trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons) +static int +trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons) { - struct trident_card *card = gameport->driver; + struct trident_card *card = gameport->driver; int i; *buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf; for (i = 0; i < 4; i++) { - axes[i] = inw(TRID_REG(card, T4D_GAME_AXD) + i * sizeof(u16)); - if (axes[i] == 0xffff) axes[i] = -1; + axes[i] = inw(TRID_REG(card, T4D_GAME_AXD) + i * sizeof (u16)); + if (axes[i] == 0xffff) + axes[i] = -1; } - - return 0; + + return 0; } -static int trident_game_open(struct gameport *gameport, int mode) +static int +trident_game_open(struct gameport *gameport, int mode) { struct trident_card *card = gameport->driver; switch (mode) { - case GAMEPORT_MODE_COOKED: - outb(0x80, TRID_REG(card, T4D_GAME_CR)); - wait_ms(20); - return 0; - case GAMEPORT_MODE_RAW: - outb(0x00, TRID_REG(card, T4D_GAME_CR)); - return 0; - default: - return -1; + case GAMEPORT_MODE_COOKED: + outb(0x80, TRID_REG(card, T4D_GAME_CR)); + wait_ms(20); + return 0; + case GAMEPORT_MODE_RAW: + outb(0x00, TRID_REG(card, T4D_GAME_CR)); + return 0; + default: + return -1; } return 0; } - -/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ -static int __devinit trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) +/* install the driver, we do not allocate hardware channel nor DMA */ +/* buffer now, they are defered until "ACCESS" time (in prog_dmabuf */ +/* called by open/read/write/ioctl/mmap) */ +static int __devinit +trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { unsigned long iobase; struct trident_card *card; @@ -4139,11 +4325,12 @@ static int __devinit trident_probe(struc dma_mask = ALI_DMA_MASK; else dma_mask = TRIDENT_DMA_MASK; + if (pci_set_dma_mask(pci_dev, dma_mask)) { printk(KERN_ERR "trident: architecture does not support" " %s PCI busmaster DMA\n", pci_dev->device == PCI_DEVICE_ID_ALI_5451 ? - "32-bit" : "30-bit"); + "32-bit" : "31-bit"); goto out; } pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); @@ -4154,17 +4341,18 @@ static int __devinit trident_probe(struc iobase = pci_resource_start(pci_dev, 0); if (!request_region(iobase, 256, card_names[pci_id->driver_data])) { - printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n", + printk(KERN_ERR + "trident: can't allocate I/O space at 0x%4.4lx\n", iobase); goto out; } rc = -ENOMEM; - if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) { + if ((card = kmalloc(sizeof(*card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); goto out_release_region; } - memset(card, 0, sizeof(*card)); + memset (card, 0, sizeof(*card)); init_timer(&card->timer); card->iobase = iobase; @@ -4197,12 +4385,12 @@ static int __devinit trident_probe(struc printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->iobase, card->irq); - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { - /* ALi channel Management */ + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + /* ALi channel Management */ card->alloc_pcm_channel = ali_alloc_pcm_channel; card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; card->free_pcm_channel = ali_free_pcm_channel; - + card->address_interrupt = ali_address_interrupt; /* Added by Matt Wu 01-05-2001 for spdif in */ @@ -4210,8 +4398,8 @@ static int __devinit trident_probe(struc card->rec_channel_use_count = 0; /* ALi SPDIF OUT function */ - if(card->revision == ALI_5451_V02) { - ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); + if (card->revision == ALI_5451_V02) { + ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); res = create_proc_entry("ALi5451", 0, NULL); if (res) { res->write_proc = ali_write_proc; @@ -4221,32 +4409,28 @@ static int __devinit trident_probe(struc /* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */ card->hwvolctl = 0; - pci_dev_m1533 = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev_m1533); + pci_dev_m1533 = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + pci_dev_m1533); rc = -ENODEV; if (pci_dev_m1533 == NULL) goto out_proc_fs; pci_read_config_byte(pci_dev_m1533, 0x63, &bits); - if (bits & (1<<5)) + if (bits & (1 << 5)) card->hwvolctl = 1; - if (card->hwvolctl) - { + if (card->hwvolctl) { /* Clear m1533 pci cfg 78h bit 30 to zero, which makes GPIO11/12/13 work as ACGP_UP/DOWN/MUTE. */ pci_read_config_byte(pci_dev_m1533, 0x7b, &bits); - bits &= 0xbf; /*clear bit 6 */ + bits &= 0xbf; /*clear bit 6 */ pci_write_config_byte(pci_dev_m1533, 0x7b, bits); } - } - else if(card->pci_id == PCI_DEVICE_ID_INTERG_5050) - { + } else if (card->pci_id == PCI_DEVICE_ID_INTERG_5050) { card->alloc_pcm_channel = cyber_alloc_pcm_channel; card->alloc_rec_pcm_channel = cyber_alloc_pcm_channel; card->free_pcm_channel = cyber_free_pcm_channel; card->address_interrupt = cyber_address_interrupt; cyber_init_ritual(card); - } - else - { + } else { card->alloc_pcm_channel = trident_alloc_pcm_channel; card->alloc_rec_pcm_channel = trident_alloc_pcm_channel; card->free_pcm_channel = trident_free_pcm_channel; @@ -4257,22 +4441,26 @@ static int __devinit trident_probe(struc rc = -ENODEV; if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) { - printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq); + printk(KERN_ERR "trident: unable to allocate irq %d\n", + card->irq); goto out_proc_fs; } + /* register /dev/dsp */ if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) { printk(KERN_ERR "trident: couldn't register DSP device!\n"); goto out_free_irq; } card->mixer_regs_ready = 0; + /* initialize AC97 codec and register /dev/mixer */ if (trident_ac97_init(card) <= 0) { /* unregister audio devices */ for (i = 0; i < NR_AC97; i++) { if (card->ac97_codec[i] != NULL) { - unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); - ac97_release_codec(card->ac97_codec[i]); + struct ac97_codec* codec = card->ac97_codec[i]; + unregister_sound_mixer(codec->dev_mixer); + ac97_release_codec(codec); } } goto out_unregister_sound_dsp; @@ -4282,35 +4470,36 @@ static int __devinit trident_probe(struc if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { /* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */ - if(card->hwvolctl) - { - /* Enable GPIO IRQ (MISCINT bit 18h)*/ + if (card->hwvolctl) { + /* Enable GPIO IRQ (MISCINT bit 18h) */ temp = inw(TRID_REG(card, T4D_MISCINT + 2)); temp |= 0x0004; outw(temp, TRID_REG(card, T4D_MISCINT + 2)); - /* Enable H/W Volume Control GLOVAL CONTROL bit 0*/ + /* Enable H/W Volume Control GLOVAL CONTROL bit 0 */ temp = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); temp |= 0x0001; outw(temp, TRID_REG(card, ALI_GLOBAL_CONTROL)); } - if(card->revision == ALI_5451_V02) + if (card->revision == ALI_5451_V02) ali_close_multi_channels(); /* edited by HMSEO for GT sound */ #if defined(CONFIG_ALPHA_NAUTILUS) || defined(CONFIG_ALPHA_GENERIC) { u16 ac97_data; extern struct hwrpb_struct *hwrpb; - + if ((hwrpb->sys_type) == 201) { - printk(KERN_INFO "trident: Running on Alpha system type Nautilus\n"); + printk(KERN_INFO "trident: Running on Alpha system " + "type Nautilus\n"); ac97_data = ali_ac97_get(card, 0, AC97_POWER_CONTROL); - ali_ac97_set(card, 0, AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN); + ali_ac97_set(card, 0, AC97_POWER_CONTROL, + ac97_data | ALI_EAPD_POWER_DOWN); } } -#endif /* CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC */ - /* edited by HMSEO for GT sound*/ +#endif /* CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC */ + /* edited by HMSEO for GT sound */ } rc = 0; pci_set_drvdata(pci_dev, card); @@ -4320,8 +4509,8 @@ static int __devinit trident_probe(struc /* Register gameport */ gameport_register_port(&card->gameport); + goto out; -out: return rc; out_unregister_sound_dsp: unregister_sound_dsp(card->dev_audio); out_free_irq: @@ -4335,26 +4524,28 @@ out_proc_fs: devs = NULL; out_release_region: release_region(iobase, 256); - goto out; +out: + return rc; } -static void __devexit trident_remove(struct pci_dev *pci_dev) +static void __devexit +trident_remove(struct pci_dev *pci_dev) { int i; struct trident_card *card = pci_get_drvdata(pci_dev); /* - * Kill running timers before unload. We can't have them - * going off after rmmod! - */ - if(card->hwvolctl) + * Kill running timers before unload. We can't have them + * going off after rmmod! + */ + if (card->hwvolctl) del_timer_sync(&card->timer); - + /* ALi S/PDIF and Power Management */ - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); - ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); - ali_disable_spdif_in(card); + ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); + ali_disable_spdif_in(card); remove_proc_entry("ALi5451", NULL); } @@ -4381,36 +4572,38 @@ static void __devexit trident_remove(str pci_set_drvdata(pci_dev, NULL); } -MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee"); -MODULE_DESCRIPTION("Trident 4DWave/SiS 7018/ALi 5451 and Tvia/IGST CyberPro5050 PCI Audio Driver"); +MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee, Muli Ben-Yehuda"); +MODULE_DESCRIPTION("Trident 4DWave/SiS 7018/ALi 5451 and Tvia/IGST CyberPro5050 PCI " + "Audio Driver"); MODULE_LICENSE("GPL"); - #define TRIDENT_MODULE_NAME "trident" static struct pci_driver trident_pci_driver = { - .name = TRIDENT_MODULE_NAME, - .id_table = trident_pci_tbl, - .probe = trident_probe, - .remove = __devexit_p(trident_remove), - .suspend = trident_suspend, - .resume = trident_resume + .name = TRIDENT_MODULE_NAME, + .id_table = trident_pci_tbl, + .probe = trident_probe, + .remove = __devexit_p(trident_remove), + .suspend = trident_suspend, + .resume = trident_resume }; -static int __init trident_init_module (void) +static int __init +trident_init_module(void) { printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro " - "5050 PCI Audio, version " DRIVER_VERSION ", " + "5050 PCI Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&trident_pci_driver)) { pci_unregister_driver(&trident_pci_driver); - return -ENODEV; + return -ENODEV; } return 0; } -static void __exit trident_cleanup_module (void) +static void __exit +trident_cleanup_module(void) { pci_unregister_driver(&trident_pci_driver); } --- linux-2.6.1-rc1/sound/oss/trident.h 2003-07-13 21:44:35.000000000 -0700 +++ 25/sound/oss/trident.h 2003-12-30 22:50:09.000000000 -0800 @@ -56,11 +56,6 @@ #define PCI_DEVICE_ID_ALI_1533 0x1533 #endif -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif - #define CHANNEL_REGS 5 #define CHANNEL_START 0xe0 // The first bytes of the contiguous register space. @@ -363,7 +358,7 @@ static inline unsigned ld2(unsigned int #ifdef DEBUG #define TRDBG(msg, args...) do { \ - printk(KERN_DEBUG msg , ##args ); \ + printk(DEBUG msg , ##args ); \ } while (0) #else /* !defined(DEBUG) */ --- linux-2.6.1-rc1/sound/pci/intel8x0.c 2003-11-09 16:45:06.000000000 -0800 +++ 25/sound/pci/intel8x0.c 2003-12-30 22:49:47.000000000 -0800 @@ -2271,10 +2271,8 @@ static void __devinit intel8x0_measure_a t = stop_time.tv_sec - start_time.tv_sec; t *= 1000000; - if (stop_time.tv_usec < start_time.tv_usec) - t -= start_time.tv_usec - stop_time.tv_usec; - else - t += stop_time.tv_usec - start_time.tv_usec; + t += stop_time.tv_usec - start_time.tv_usec; + printk(KERN_INFO "%s: measured %lu usecs\n", __FUNCTION__, t); if (t == 0) { snd_printk(KERN_ERR "?? calculation error..\n"); return; --- linux-2.6.1-rc1/sound/pcmcia/vx/vx_entry.c 2003-09-27 18:57:48.000000000 -0700 +++ 25/sound/pcmcia/vx/vx_entry.c 2003-12-30 22:50:04.000000000 -0800 @@ -38,9 +38,9 @@ static void vxpocket_release(dev_link_t { if (link->state & DEV_CONFIG) { /* release cs resources */ - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } } @@ -58,7 +58,7 @@ static int snd_vxpocket_free(vx_core_t * /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); hw = vxp->hw_entry; if (hw) @@ -170,7 +170,7 @@ dev_link_t *snd_vxpocket_attach(struct s client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); snd_vxpocket_detach(hw, link); @@ -253,8 +253,8 @@ void snd_vxpocket_detach_all(struct snd_ * configuration callback */ -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void vxpocket_config(dev_link_t *link) { @@ -274,21 +274,21 @@ static void vxpocket_config(dev_link_t * tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.ConfigIndex = 1; - CS_CHECK(GetConfigurationInfo, handle, &conf); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* Configure card */ link->state |= DEV_CONFIG; - CS_CHECK(RequestIO, handle, &link->io); - CS_CHECK(RequestIRQ, link->handle, &link->irq); - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; @@ -300,9 +300,9 @@ static void vxpocket_config(dev_link_t * cs_failed: cs_error(link->handle, last_fn, last_ret); failed: - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); } @@ -339,7 +339,7 @@ static int vxpocket_event(event_t event, case CS_EVENT_RESET_PHYSICAL: snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: snd_printdd(KERN_DEBUG "RESUME\n"); @@ -350,7 +350,7 @@ static int vxpocket_event(event_t event, if (DEV_OK(link)) { //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; snd_printdd(KERN_DEBUG "requestconfig...\n"); - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (chip) { snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); snd_vx_resume(chip);