diff -Nurb linux-2.6.24.3/arch/x86/kernel/cobalt.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/cobalt.c --- linux-2.6.24.3/arch/x86/kernel/cobalt.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/cobalt.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,279 @@ +/* $Id: cobalt.c,v 1.34 2002/11/04 17:54:14 thockin Exp $ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NMI_PS 10 + +static u8 last_err; +static u32 last_address; +static unsigned long nmi_repeats; +static struct timer_list nmi_timer; +static int timer_added; +static unsigned long nmi_count; +static spinlock_t nmi_state_lock = SPIN_LOCK_UNLOCKED; + +static inline void +ledonoff(unsigned long on, unsigned long off) +{ +#ifdef CONFIG_COBALT_LED + unsigned long start; + int haltok = current_cpu_data.hlt_works_ok; + + if (on) { + start = jiffies; + cobalt_led_set(cobalt_led_get() | LED_SHUTDOWN); + while (jiffies < start + on) { + if (haltok) __asm__("hlt"); + } + } + + if (off) { + start = jiffies; + cobalt_led_set(cobalt_led_get() & ~LED_SHUTDOWN); + while (jiffies < start + off) { + if (haltok) __asm__("hlt"); + } + } +#endif +} + +/* clla this holding nmi_state_lock */ +static inline void +do_repeats(void) +{ + if (nmi_repeats) { + printk("NMI: last error repeated %lu times\n", nmi_repeats); + nmi_repeats = 0; + } +} + +static void +nmi_throttle_fn(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&nmi_state_lock, flags); + + /* clear any repeated NMIs */ + do_repeats(); + + /* have we had a lot of errors this second */ + if (nmi_count > MAX_NMI_PS) { + printk("NMI: %lu messages were throttled\n", + nmi_count - MAX_NMI_PS); + nmi_count = 0; + } + + /* de-activate the timer - will be reactivated by an NMI */ + del_timer(&nmi_timer); + timer_added = 0; + + spin_unlock_irqrestore(&nmi_state_lock, flags); +} + +void +cobalt_nmi(unsigned char reason, struct pt_regs *regs) +{ + if (cobt_is_5k()) { + static struct pci_dev *cnb_dev; + u8 err; + u32 address = 0; + unsigned long flags; + + /* find our memory controller */ + if (!cnb_dev) { + cnb_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_LE, NULL); + } + if (!cnb_dev) { + EPRINTK("can't find north bridge for NMI status\n"); + return; + } + + /* read the error number */ + pci_read_config_byte(cnb_dev, 0x47, &err); + + /* if a memory error was detected, where? */ + if (err & 0x06) { + pci_read_config_dword(cnb_dev, 0x94, &address); + } + + spin_lock_irqsave(&nmi_state_lock, flags); + + /* set up the timer, if it isn't set to go already */ + if (!timer_added) { + init_timer(&nmi_timer); + nmi_timer.expires = jiffies + HZ; + nmi_timer.function = nmi_throttle_fn; + add_timer(&nmi_timer); + timer_added = 1; + } + + /* if we already printed this error */ + if (last_err && err == last_err && address == last_address) { + nmi_repeats++; + spin_unlock_irqrestore(&nmi_state_lock, flags); + } else { + unsigned long nmi_now; + + /* different error - show repeats */ + do_repeats(); + + /* we only want to do a few messages per second */ + nmi_now = nmi_count++; + + spin_unlock_irqrestore(&nmi_state_lock, flags); + + /* generate a new message */ + if (nmi_now < MAX_NMI_PS) { + /* only remember NMIs that we can print */ + last_err = err; + last_address = address; + + printk("NMI:"); + if (err & 0x40) + printk(" (PCI tx data error)"); + if (err & 0x20) + printk(" (PCI rx data error)"); + if (err & 0x10) + printk(" (PCI address error)"); + if (err & 0x04) + printk(" (DRAM uncorrectable error)"); + if (err & 0x02) + printk(" (DRAM correctable error)"); + if (err & 0x01) + printk(" (Shutdown cycle detected)"); + + if (err & 0x06) { + u8 row, dimm, ecc; + + row = (address >> 29) & 0x7; + pci_read_config_byte(cnb_dev, + 0x7c + (row >> 1), &dimm); + dimm = ((row & 1) ? + (dimm >> 4) : dimm) & 0xf; + pci_read_config_byte(cnb_dev, 0xe8, + &ecc); + + printk(" [memory row %d, DIMM type %d, " + "col=0x%x, row=0x%x, ECC=0x%x]", + row, dimm, + (address >> 15) & 0x3fff, + address & 0x7fff, ecc); + } + printk("\n"); + } + } + + /* clear errors */ + pci_write_config_byte(cnb_dev, 0x47, err); + } else { + /* TODO: make throttling generic, handle GP NMIs */ + printk("NMI: unknown error\n"); + } +} + +void +cobalt_restart(void) +{ + if (cobt_is_3k()) { + /* kick watchdog */ + cobalt_wdt_trigger_reboot(); + } else if (cobt_is_5k()) { + /* set "Enable Hard Reset" bit to 1 */ + outb(0x02, 0x0cf9); + + /* 0-to-1 transition of bit 2 will cause reset of processor */ + outb(0x06, 0x0cf9); + } + mdelay(3000); + + /* we should not get here unless there is a BAD error */ + EPRINTK("can not restart - halting\n"); + machine_halt(); +} + +void +cobalt_halt(void) +{ + int haltok = current_cpu_data.hlt_works_ok; + + if (cobt_is_5k()) { + /* we have soft power-off */ + machine_power_off(); + } + + /* + * we want to do cpu_idle, but we don't actually want to + * call cpu_idle. bleah. + */ + while (1) { + ledonoff(HZ >> 1, HZ >> 1); + if (haltok) { + __asm__("hlt"); + } + } +} + +void +cobalt_power_off(void) +{ + u16 addr; + + if (cobt_is_monterey()) { + u8 val; + /* use card control reg. 7 to select logical device 2 (APC) */ + addr = superio_ldev_base(PC87317_DEV_RTC); + + /* set up bank 2 */ + outb(PC87317_RTC_CRA, addr); + val = inb(addr + 1) & 0x8f; + outb(val | PC87317_RTC_BANK_2, addr + 1); + + /* power off the machine with APCR1 */ + outb(PC87317_APCR1, addr); + val = inb(addr + 1); + outb(0x20 | val, addr + 1); + } else if (cobt_is_alpine()) { + int i; + /* clear status bits, base addr 3 */ + addr = superio_ldev_base_n(PC87417_DEV_SWC, 3); + for (i = 0; i < 4; i++) { + /* + * if we have an event while running, + * we can't halt unless we clear these + * */ + outb(0xff, addr+i); + } + + /* set sleep state, base addr 2 */ + addr = superio_ldev_base_n(PC87417_DEV_SWC, 2); + /* PM1b_CNT_HIGH @offset 1 - set state to S5 */ + outb(0x34, addr+1); + } + mdelay(3000); + EPRINTK("can not power off\n"); +} + +/* put arch specific stuff to run at init time here */ +static int __init +cobalt_arch_init(void) +{ + return 0; +} +module_init(cobalt_arch_init); diff -Nurb linux-2.6.24.3/arch/x86/kernel/Makefile_32 linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32 --- linux-2.6.24.3/arch/x86/kernel/Makefile_32 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32 2008-03-02 14:55:48.000000000 -0800 @@ -58,6 +58,7 @@ targets += vsyscall-note_32.o vsyscall_32.lds # The DSO images are built using a special linker script. +obj-$(CONFIG_COBALT_RAQ) += cobalt.o quiet_cmd_syscall = SYSCALL $@ cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \ -Wl,-T,$(filter-out FORCE,$^) -o $@ diff -Nurb linux-2.6.24.3/arch/x86/kernel/Makefile_32.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32.orig --- linux-2.6.24.3/arch/x86/kernel/Makefile_32.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,89 @@ +# +# Makefile for the linux kernel. +# + +extra-y := head_32.o init_task.o vmlinux.lds +CPPFLAGS_vmlinux.lds += -Ui386 + +obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ + ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ + pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ + quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o + +obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-y += cpu/ +obj-y += acpi/ +obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o +obj-$(CONFIG_MCA) += mca_32.o +obj-$(CONFIG_X86_MSR) += msr.o +obj-$(CONFIG_X86_CPUID) += cpuid.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_PCI) += early-quirks.o +apm-y := apm_32.o +obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o +obj-$(CONFIG_SMP) += smpcommon_32.o +obj-$(CONFIG_X86_TRAMPOLINE) += trampoline_32.o +obj-$(CONFIG_X86_MPPARSE) += mpparse_32.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o +obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o +obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o +obj-$(CONFIG_KEXEC) += machine_kexec_32.o relocate_kernel_32.o crash.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump_32.o +obj-$(CONFIG_X86_NUMAQ) += numaq_32.o +obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o +obj-$(CONFIG_KPROBES) += kprobes_32.o +obj-$(CONFIG_MODULES) += module_32.o +obj-y += sysenter_32.o vsyscall_32.o +obj-$(CONFIG_ACPI_SRAT) += srat_32.o +obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o +obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o +obj-$(CONFIG_VM86) += vm86_32.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_HPET_TIMER) += hpet.o +obj-$(CONFIG_K8_NB) += k8.o +obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o + +obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o +obj-$(CONFIG_PARAVIRT) += paravirt_32.o +obj-y += pcspeaker.o + +obj-$(CONFIG_SCx200) += scx200_32.o + +# vsyscall_32.o contains the vsyscall DSO images as __initdata. +# We must build both images before we can assemble it. +# Note: kbuild does not track this dependency due to usage of .incbin +$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so +targets += $(foreach F,int80 sysenter,vsyscall-$F_32.o vsyscall-$F_32.so) +targets += vsyscall-note_32.o vsyscall_32.lds + +# The DSO images are built using a special linker script. +quiet_cmd_syscall = SYSCALL $@ + cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \ + -Wl,-T,$(filter-out FORCE,$^) -o $@ + +export CPPFLAGS_vsyscall_32.lds += -P -C -Ui386 + +vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ + $(call ld-option, -Wl$(comma)--hash-style=sysv) +SYSCFLAGS_vsyscall-sysenter_32.so = $(vsyscall-flags) +SYSCFLAGS_vsyscall-int80_32.so = $(vsyscall-flags) + +$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so: \ +$(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ + $(obj)/vsyscall-%.o $(obj)/vsyscall-note_32.o FORCE + $(call if_changed,syscall) + +# We also create a special relocatable object that should mirror the symbol +# table and layout of the linked DSO. With ld -R we can then refer to +# these symbols in the kernel code rather than hand-coded addresses. +extra-y += vsyscall-syms.o +$(obj)/built-in.o: $(obj)/vsyscall-syms.o +$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o + +SYSCFLAGS_vsyscall-syms.o = -r +$(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ + $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note_32.o FORCE + $(call if_changed,syscall) + + diff -Nurb linux-2.6.24.3/arch/x86/kernel/process_32.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c --- linux-2.6.24.3/arch/x86/kernel/process_32.c 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c 2008-03-02 14:55:48.000000000 -0800 @@ -51,6 +51,11 @@ #include #endif +#ifdef CONFIG_COBALT_RAQ +#include +#include +#endif + #include #include @@ -531,6 +536,12 @@ { int i; +#ifdef CONFIG_COBALT_RAQ + wait_for_flush(); + cobalt_restart(); +#endif + + /* changed the size calculations - should hopefully work better. lbt */ dump->magic = CMAGIC; dump->start_code = 0; diff -Nurb linux-2.6.24.3/arch/x86/kernel/process_32.c.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c.orig --- linux-2.6.24.3/arch/x86/kernel/process_32.c.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,984 @@ +/* + * Copyright (C) 1995 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MATH_EMULATION +#include +#endif + +#include + +#include +#include + +asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +static int hlt_counter; + +unsigned long boot_option_idle_override = 0; +EXPORT_SYMBOL(boot_option_idle_override); + +DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; +EXPORT_PER_CPU_SYMBOL(current_task); + +DEFINE_PER_CPU(int, cpu_number); +EXPORT_PER_CPU_SYMBOL(cpu_number); + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + return ((unsigned long *)tsk->thread.esp)[3]; +} + +/* + * Powermanagement idle function, if any.. + */ +void (*pm_idle)(void); +EXPORT_SYMBOL(pm_idle); +static DEFINE_PER_CPU(unsigned int, cpu_idle_state); + +void disable_hlt(void) +{ + hlt_counter++; +} + +EXPORT_SYMBOL(disable_hlt); + +void enable_hlt(void) +{ + hlt_counter--; +} + +EXPORT_SYMBOL(enable_hlt); + +/* + * We use this if we don't have any better + * idle routine.. + */ +void default_idle(void) +{ + if (!hlt_counter && boot_cpu_data.hlt_works_ok) { + current_thread_info()->status &= ~TS_POLLING; + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); + + local_irq_disable(); + if (!need_resched()) + safe_halt(); /* enables interrupts racelessly */ + else + local_irq_enable(); + current_thread_info()->status |= TS_POLLING; + } else { + /* loop is done by the caller */ + cpu_relax(); + } +} +#ifdef CONFIG_APM_MODULE +EXPORT_SYMBOL(default_idle); +#endif + +/* + * On SMP it's slightly faster (but much more power-consuming!) + * to poll the ->work.need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +static void poll_idle (void) +{ + cpu_relax(); +} + +#ifdef CONFIG_HOTPLUG_CPU +#include +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void play_dead(void) +{ + /* This must be done before dead CPU ack */ + cpu_exit_clear(); + wbinvd(); + mb(); + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + /* + * With physical CPU hotplug, we should halt the cpu + */ + local_irq_disable(); + while (1) + halt(); +} +#else +static inline void play_dead(void) +{ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + int cpu = smp_processor_id(); + + current_thread_info()->status |= TS_POLLING; + + /* endless idle loop with no priority at all */ + while (1) { + tick_nohz_stop_sched_tick(); + while (!need_resched()) { + void (*idle)(void); + + if (__get_cpu_var(cpu_idle_state)) + __get_cpu_var(cpu_idle_state) = 0; + + check_pgt_cache(); + rmb(); + idle = pm_idle; + + if (!idle) + idle = default_idle; + + if (cpu_is_offline(cpu)) + play_dead(); + + __get_cpu_var(irq_stat).idle_timestamp = jiffies; + idle(); + } + tick_nohz_restart_sched_tick(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +static void do_nothing(void *unused) +{ +} + +void cpu_idle_wait(void) +{ + unsigned int cpu, this_cpu = get_cpu(); + cpumask_t map, tmp = current->cpus_allowed; + + set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); + put_cpu(); + + cpus_clear(map); + for_each_online_cpu(cpu) { + per_cpu(cpu_idle_state, cpu) = 1; + cpu_set(cpu, map); + } + + __get_cpu_var(cpu_idle_state) = 0; + + wmb(); + do { + ssleep(1); + for_each_online_cpu(cpu) { + if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) + cpu_clear(cpu, map); + } + cpus_and(map, map, cpu_online_map); + /* + * We waited 1 sec, if a CPU still did not call idle + * it may be because it is in idle and not waking up + * because it has nothing to do. + * Give all the remaining CPUS a kick. + */ + smp_call_function_mask(map, do_nothing, 0, 0); + } while (!cpus_empty(map)); + + set_cpus_allowed(current, tmp); +} +EXPORT_SYMBOL_GPL(cpu_idle_wait); + +/* + * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, + * which can obviate IPI to trigger checking of need_resched. + * We execute MONITOR against need_resched and enter optimized wait state + * through MWAIT. Whenever someone changes need_resched, we would be woken + * up from MWAIT (without an IPI). + * + * New with Core Duo processors, MWAIT can take some hints based on CPU + * capability. + */ +void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) +{ + if (!need_resched()) { + __monitor((void *)¤t_thread_info()->flags, 0, 0); + smp_mb(); + if (!need_resched()) + __mwait(eax, ecx); + } +} + +/* Default MONITOR/MWAIT with no hints, used for default C1 state */ +static void mwait_idle(void) +{ + local_irq_enable(); + mwait_idle_with_hints(0, 0); +} + +void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_MWAIT)) { + printk("monitor/mwait feature present.\n"); + /* + * Skip, if setup has overridden idle. + * One CPU supports mwait => All CPUs supports mwait + */ + if (!pm_idle) { + printk("using mwait in idle threads.\n"); + pm_idle = mwait_idle; + } + } +} + +static int __init idle_setup(char *str) +{ + if (!strcmp(str, "poll")) { + printk("using polling idle threads.\n"); + pm_idle = poll_idle; +#ifdef CONFIG_X86_SMP + if (smp_num_siblings > 1) + printk("WARNING: polling idle and HT enabled, performance may degrade.\n"); +#endif + } else if (!strcmp(str, "mwait")) + force_mwait = 1; + else + return -1; + + boot_option_idle_override = 1; + return 0; +} +early_param("idle", idle_setup); + +void __show_registers(struct pt_regs *regs, int all) +{ + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + unsigned long d0, d1, d2, d3, d6, d7; + unsigned long esp; + unsigned short ss, gs; + + if (user_mode_vm(regs)) { + esp = regs->esp; + ss = regs->xss & 0xffff; + savesegment(gs, gs); + } else { + esp = (unsigned long) (®s->esp); + savesegment(ss, ss); + savesegment(gs, gs); + } + + printk("\n"); + printk("Pid: %d, comm: %s %s (%s %.*s)\n", + task_pid_nr(current), current->comm, + print_tainted(), init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); + + printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", + 0xffff & regs->xcs, regs->eip, regs->eflags, + smp_processor_id()); + print_symbol("EIP is at %s\n", regs->eip); + + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); + printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, + regs->xfs & 0xffff, gs, ss); + + if (!all) + return; + + cr0 = read_cr0(); + cr2 = read_cr2(); + cr3 = read_cr3(); + cr4 = read_cr4_safe(); + printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", + cr0, cr2, cr3, cr4); + + get_debugreg(d0, 0); + get_debugreg(d1, 1); + get_debugreg(d2, 2); + get_debugreg(d3, 3); + printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", + d0, d1, d2, d3); + + get_debugreg(d6, 6); + get_debugreg(d7, 7); + printk("DR6: %08lx DR7: %08lx\n", + d6, d7); +} + +void show_regs(struct pt_regs *regs) +{ + __show_registers(regs, 1); + show_trace(NULL, regs, ®s->esp); +} + +/* + * This gets run with %ebx containing the + * function to call, and %edx containing + * the "args". + */ +extern void kernel_thread_helper(void); + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + regs.ebx = (unsigned long) fn; + regs.edx = (unsigned long) arg; + + regs.xds = __USER_DS; + regs.xes = __USER_DS; + regs.xfs = __KERNEL_PERCPU; + regs.orig_eax = -1; + regs.eip = (unsigned long) kernel_thread_helper; + regs.xcs = __KERNEL_CS | get_kernel_rpl(); + regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; + + /* Ok, create the new process.. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); +} +EXPORT_SYMBOL(kernel_thread); + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* The process may have allocated an io port bitmap... nuke it. */ + if (unlikely(test_thread_flag(TIF_IO_BITMAP))) { + struct task_struct *tsk = current; + struct thread_struct *t = &tsk->thread; + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; + clear_thread_flag(TIF_IO_BITMAP); + /* + * Careful, clear this in the TSS too: + */ + memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); + t->io_bitmap_max = 0; + tss->io_bitmap_owner = NULL; + tss->io_bitmap_max = 0; + tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + put_cpu(); + } +} + +void flush_thread(void) +{ + struct task_struct *tsk = current; + + memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); + memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); + clear_tsk_thread_flag(tsk, TIF_DEBUG); + /* + * Forget coprocessor state.. + */ + clear_fpu(tsk); + clear_used_math(); +} + +void release_thread(struct task_struct *dead_task) +{ + BUG_ON(dead_task->mm); + release_vm86_irqs(dead_task); +} + +/* + * This gets called before we allocate a new thread and copy + * the current task into it. + */ +void prepare_to_copy(struct task_struct *tsk) +{ + unlazy_fpu(tsk); +} + +int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct task_struct *tsk; + int err; + + childregs = task_pt_regs(p); + *childregs = *regs; + childregs->eax = 0; + childregs->esp = esp; + + p->thread.esp = (unsigned long) childregs; + p->thread.esp0 = (unsigned long) (childregs+1); + + p->thread.eip = (unsigned long) ret_from_fork; + + savesegment(gs,p->thread.gs); + + tsk = current; + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { + p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, + IO_BITMAP_BYTES, GFP_KERNEL); + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; + return -ENOMEM; + } + set_tsk_thread_flag(p, TIF_IO_BITMAP); + } + + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) { + struct desc_struct *desc; + struct user_desc info; + int idx; + + err = -EFAULT; + if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) + goto out; + err = -EINVAL; + if (LDT_empty(&info)) + goto out; + + idx = info.entry_number; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + goto out; + + desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } + + err = 0; + out: + if (err && p->thread.io_bitmap_ptr) { + kfree(p->thread.io_bitmap_ptr); + p->thread.io_bitmap_max = 0; + } + return err; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + int i; + +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + for (i = 0; i < 8; i++) + dump->u_debugreg[i] = current->thread.debugreg[i]; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->regs.ebx = regs->ebx; + dump->regs.ecx = regs->ecx; + dump->regs.edx = regs->edx; + dump->regs.esi = regs->esi; + dump->regs.edi = regs->edi; + dump->regs.ebp = regs->ebp; + dump->regs.eax = regs->eax; + dump->regs.ds = regs->xds; + dump->regs.es = regs->xes; + dump->regs.fs = regs->xfs; + savesegment(gs,dump->regs.gs); + dump->regs.orig_eax = regs->orig_eax; + dump->regs.eip = regs->eip; + dump->regs.cs = regs->xcs; + dump->regs.eflags = regs->eflags; + dump->regs.esp = regs->esp; + dump->regs.ss = regs->xss; + + dump->u_fpvalid = dump_fpu (regs, &dump->i387); +} +EXPORT_SYMBOL(dump_thread); + +/* + * Capture the user space registers if the task is not running (in user space) + */ +int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +{ + struct pt_regs ptregs = *task_pt_regs(tsk); + ptregs.xcs &= 0xffff; + ptregs.xds &= 0xffff; + ptregs.xes &= 0xffff; + ptregs.xss &= 0xffff; + + elf_core_copy_regs(regs, &ptregs); + + return 1; +} + +#ifdef CONFIG_SECCOMP +void hard_disable_TSC(void) +{ + write_cr4(read_cr4() | X86_CR4_TSD); +} +void disable_TSC(void) +{ + preempt_disable(); + if (!test_and_set_thread_flag(TIF_NOTSC)) + /* + * Must flip the CPU state synchronously with + * TIF_NOTSC in the current running context. + */ + hard_disable_TSC(); + preempt_enable(); +} +void hard_enable_TSC(void) +{ + write_cr4(read_cr4() & ~X86_CR4_TSD); +} +#endif /* CONFIG_SECCOMP */ + +static noinline void +__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, + struct tss_struct *tss) +{ + struct thread_struct *next; + + next = &next_p->thread; + + if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { + set_debugreg(next->debugreg[0], 0); + set_debugreg(next->debugreg[1], 1); + set_debugreg(next->debugreg[2], 2); + set_debugreg(next->debugreg[3], 3); + /* no 4 and 5 */ + set_debugreg(next->debugreg[6], 6); + set_debugreg(next->debugreg[7], 7); + } + +#ifdef CONFIG_SECCOMP + if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ + test_tsk_thread_flag(next_p, TIF_NOTSC)) { + /* prev and next are different */ + if (test_tsk_thread_flag(next_p, TIF_NOTSC)) + hard_disable_TSC(); + else + hard_enable_TSC(); + } +#endif + + if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { + /* + * Disable the bitmap via an invalid offset. We still cache + * the previous bitmap owner and the IO bitmap contents: + */ + tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + return; + } + + if (likely(next == tss->io_bitmap_owner)) { + /* + * Previous owner of the bitmap (hence the bitmap content) + * matches the next task, we dont have to do anything but + * to set a valid offset in the TSS: + */ + tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; + return; + } + /* + * Lazy TSS's I/O bitmap copy. We set an invalid offset here + * and we let the task to get a GPF in case an I/O instruction + * is performed. The handler of the GPF will verify that the + * faulting task has a valid I/O bitmap and, it true, does the + * real copy and restart the instruction. This will save us + * redundant copies when the currently switched task does not + * perform any I/O during its timeslice. + */ + tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; +} + +/* + * switch_to(x,yn) should switch tasks from x to y. + * + * We fsave/fwait so that an exception goes off at the right time + * (as a call from the fsave or fwait in effect) rather than to + * the wrong process. Lazy FP saving no longer makes any sense + * with modern CPU's, and this simplifies a lot of things (SMP + * and UP become the same). + * + * NOTE! We used to use the x86 hardware context switching. The + * reason for not using it any more becomes apparent when you + * try to recover gracefully from saved state that is no longer + * valid (stale segment register values in particular). With the + * hardware task-switch, there is no way to fix up bad state in + * a reasonable manner. + * + * The fact that Intel documents the hardware task-switching to + * be slow is a fairly red herring - this code is not noticeably + * faster. However, there _is_ some room for improvement here, + * so the performance issues may eventually be a valid point. + * More important, however, is the fact that this allows us much + * more flexibility. + * + * The return value (in %eax) will be the "prev" task after + * the task-switch, and shows up in ret_from_fork in entry.S, + * for example. + */ +struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +{ + struct thread_struct *prev = &prev_p->thread, + *next = &next_p->thread; + int cpu = smp_processor_id(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + + /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ + + __unlazy_fpu(prev_p); + + + /* we're going to use this soon, after a few expensive things */ + if (next_p->fpu_counter > 5) + prefetch(&next->i387.fxsave); + + /* + * Reload esp0. + */ + load_esp0(tss, next); + + /* + * Save away %gs. No need to save %fs, as it was saved on the + * stack on entry. No need to save %es and %ds, as those are + * always kernel segments while inside the kernel. Doing this + * before setting the new TLS descriptors avoids the situation + * where we temporarily have non-reloadable segments in %fs + * and %gs. This could be an issue if the NMI handler ever + * used %fs or %gs (it does not today), or if the kernel is + * running inside of a hypervisor layer. + */ + savesegment(gs, prev->gs); + + /* + * Load the per-thread Thread-Local Storage descriptor. + */ + load_TLS(next, cpu); + + /* + * Restore IOPL if needed. In normal use, the flags restore + * in the switch assembly will handle this. But if the kernel + * is running virtualized at a non-zero CPL, the popf will + * not restore flags, so it must be done in a separate step. + */ + if (get_kernel_rpl() && unlikely(prev->iopl != next->iopl)) + set_iopl_mask(next->iopl); + + /* + * Now maybe handle debug registers and/or IO bitmaps + */ + if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV || + task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT)) + __switch_to_xtra(prev_p, next_p, tss); + + /* + * Leave lazy mode, flushing any hypercalls made here. + * This must be done before restoring TLS segments so + * the GDT and LDT are properly updated, and must be + * done before math_state_restore, so the TS bit is up + * to date. + */ + arch_leave_lazy_cpu_mode(); + + /* If the task has used fpu the last 5 timeslices, just do a full + * restore of the math state immediately to avoid the trap; the + * chances of needing FPU soon are obviously high now + */ + if (next_p->fpu_counter > 5) + math_state_restore(); + + /* + * Restore %gs if needed (which is common) + */ + if (prev->gs | next->gs) + loadsegment(gs, next->gs); + + x86_write_percpu(current_task, next_p); + + return prev_p; +} + +asmlinkage int sys_fork(struct pt_regs regs) +{ + return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL); +} + +asmlinkage int sys_clone(struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + clone_flags = regs.ebx; + newsp = regs.ecx; + parent_tidptr = (int __user *)regs.edx; + child_tidptr = (int __user *)regs.edi; + if (!newsp) + newsp = regs.esp; + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(struct pt_regs regs) +{ + int error; + char * filename; + + filename = getname((char __user *) regs.ebx); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, + (char __user * __user *) regs.ecx, + (char __user * __user *) regs.edx, + ®s); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + /* Make sure we don't return using sysenter.. */ + set_thread_flag(TIF_IRET); + } + putname(filename); +out: + return error; +} + +#define top_esp (THREAD_SIZE - sizeof(unsigned long)) +#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long)) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)task_stack_page(p); + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > top_esp+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > top_ebp+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (!in_sched_functions(eip)) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + return 0; +} + +/* + * sys_alloc_thread_area: get a yet unused TLS descriptor index. + */ +static int get_free_idx(void) +{ + struct thread_struct *t = ¤t->thread; + int idx; + + for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) + if (desc_empty(t->tls_array + idx)) + return idx + GDT_ENTRY_TLS_MIN; + return -ESRCH; +} + +/* + * Set a given TLS descriptor: + */ +asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) +{ + struct thread_struct *t = ¤t->thread; + struct user_desc info; + struct desc_struct *desc; + int cpu, idx; + + if (copy_from_user(&info, u_info, sizeof(info))) + return -EFAULT; + idx = info.entry_number; + + /* + * index -1 means the kernel should try to find and + * allocate an empty descriptor: + */ + if (idx == -1) { + idx = get_free_idx(); + if (idx < 0) + return idx; + if (put_user(idx, &u_info->entry_number)) + return -EFAULT; + } + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; + + /* + * We must not get preempted while modifying the TLS. + */ + cpu = get_cpu(); + + if (LDT_empty(&info)) { + desc->a = 0; + desc->b = 0; + } else { + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } + load_TLS(t, cpu); + + put_cpu(); + + return 0; +} + +/* + * Get the current Thread-Local Storage area: + */ + +#define GET_BASE(desc) ( \ + (((desc)->a >> 16) & 0x0000ffff) | \ + (((desc)->b << 16) & 0x00ff0000) | \ + ( (desc)->b & 0xff000000) ) + +#define GET_LIMIT(desc) ( \ + ((desc)->a & 0x0ffff) | \ + ((desc)->b & 0xf0000) ) + +#define GET_32BIT(desc) (((desc)->b >> 22) & 1) +#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) +#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) +#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) +#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) +#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) + +asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) +{ + struct user_desc info; + struct desc_struct *desc; + int idx; + + if (get_user(idx, &u_info->entry_number)) + return -EFAULT; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + memset(&info, 0, sizeof(info)); + + desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; + + info.entry_number = idx; + info.base_addr = GET_BASE(desc); + info.limit = GET_LIMIT(desc); + info.seg_32bit = GET_32BIT(desc); + info.contents = GET_CONTENTS(desc); + info.read_exec_only = !GET_WRITABLE(desc); + info.limit_in_pages = GET_LIMIT_PAGES(desc); + info.seg_not_present = !GET_PRESENT(desc); + info.useable = GET_USEABLE(desc); + + if (copy_to_user(u_info, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +unsigned long arch_align_stack(unsigned long sp) +{ + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; +} diff -Nurb linux-2.6.24.3/arch/x86/kernel/reboot_32.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c --- linux-2.6.24.3/arch/x86/kernel/reboot_32.c 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c 2008-03-02 14:55:48.000000000 -0800 @@ -17,6 +17,11 @@ #include #include +#ifdef CONFIG_COBALT_RAQ +#include +#include +#endif + /* * Power off function, if any */ @@ -297,7 +302,13 @@ { #ifdef CONFIG_SMP int reboot_cpu_id; - +#endif +#ifdef CONFIG_COBALT_RAQ + wait_for_flush(); + //cobalt_halt(); + cobalt_lcd_print("It is now safe", "to remove power"); +#endif +#ifdef CONFIG_SMP /* The boot cpu is always logical cpu 0 */ reboot_cpu_id = 0; @@ -338,6 +349,9 @@ static void native_machine_emergency_restart(void) { +#ifdef CONFIG_COBALT_RAQ + cobalt_restart(); +#endif if (!reboot_thru_bios) { if (efi_enabled) { efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); @@ -360,8 +374,35 @@ machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); } +/* kill some time at halt/reboot to allow drives with large cache to sync */ +void wait_for_flush(void) +{ + int i; + static int flushed; + + if (flushed) + return; + flushed = 1; + + printk("waiting for devices to flush"); + for (i = 0 ; i < 10; i++) { + printk("."); + mdelay(500); +#ifdef CONFIG_COBALT_LCD + if (i == 8) + cobalt_lcd_off(); +#endif + } + printk("done\n"); +} + static void native_machine_restart(char * __unused) { +#ifdef CONFIG_COBALT_RAQ + wait_for_flush(); + cobalt_restart(); +#endif + machine_shutdown(); machine_emergency_restart(); } diff -Nurb linux-2.6.24.3/arch/x86/kernel/reboot_32.c.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c.orig --- linux-2.6.24.3/arch/x86/kernel/reboot_32.c.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,413 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mach_reboot.h" +#include +#include + +/* + * Power off function, if any + */ +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); + +static int reboot_mode; +static int reboot_thru_bios; + +#ifdef CONFIG_SMP +static int reboot_cpu = -1; +#endif +static int __init reboot_setup(char *str) +{ + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': /* "bios" reboot by jumping through the BIOS */ + reboot_thru_bios = 1; + break; + case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ + reboot_thru_bios = 0; + break; +#ifdef CONFIG_SMP + case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ + if (isdigit(*(str+1))) { + reboot_cpu = (int) (*(str+1) - '0'); + if (isdigit(*(str+2))) + reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); + } + /* we will leave sorting out the final value + when we are ready to reboot, since we might not + have set up boot_cpu_id or smp_num_cpu */ + break; +#endif + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } + return 1; +} + +__setup("reboot=", reboot_setup); + +/* + * Reboot options and system auto-detection code provided by + * Dell Inc. so their systems "just work". :-) + */ + +/* + * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. + */ +static int __init set_bios_reboot(const struct dmi_system_id *d) +{ + if (!reboot_thru_bios) { + reboot_thru_bios = 1; + printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); + } + return 0; +} + +static struct dmi_system_id __initdata reboot_dmi_table[] = { + { /* Handle problems with rebooting on Dell E520's */ + .callback = set_bios_reboot, + .ident = "Dell E520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), + }, + }, + { /* Handle problems with rebooting on Dell 1300's */ + .callback = set_bios_reboot, + .ident = "Dell PowerEdge 1300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), + }, + }, + { /* Handle problems with rebooting on Dell 300's */ + .callback = set_bios_reboot, + .ident = "Dell PowerEdge 300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), + }, + }, + { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/ + .callback = set_bios_reboot, + .ident = "Dell OptiPlex 745", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), + DMI_MATCH(DMI_BOARD_NAME, "0WF810"), + }, + }, + { /* Handle problems with rebooting on Dell 2400's */ + .callback = set_bios_reboot, + .ident = "Dell PowerEdge 2400", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), + }, + }, + { /* Handle problems with rebooting on HP laptops */ + .callback = set_bios_reboot, + .ident = "HP Compaq Laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), + }, + }, + { } +}; + +static int __init reboot_init(void) +{ + dmi_check_system(reboot_dmi_table); + return 0; +} + +core_initcall(reboot_init); + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +static struct Xgt_desc_struct +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }, +no_idt = { 0, 0 }; + + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSs don't assume much. */ + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x09, /* wbinvd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_bios [] = +{ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; + +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ +void machine_real_restart(unsigned char *code, int length) +{ + local_irq_disable(); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) + */ + + spin_lock(&rtc_lock); + CMOS_WRITE(0x00, 0x8f); + spin_unlock(&rtc_lock); + + /* 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); + + /* + * Use `swapper_pg_dir' as our page directory. + */ + load_cr3(swapper_pg_dir); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = reboot_mode; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), code, length); + + /* Set up the IDT for real mode. */ + + load_idt(&real_mode_idt); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + load_gdt(&real_mode_gdt); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} +#ifdef CONFIG_APM_MODULE +EXPORT_SYMBOL(machine_real_restart); +#endif + +static void native_machine_shutdown(void) +{ +#ifdef CONFIG_SMP + int reboot_cpu_id; + + /* The boot cpu is always logical cpu 0 */ + reboot_cpu_id = 0; + + /* See if there has been given a command line override */ + if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && + cpu_isset(reboot_cpu, cpu_online_map)) { + reboot_cpu_id = reboot_cpu; + } + + /* Make certain the cpu I'm rebooting on is online */ + if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { + reboot_cpu_id = smp_processor_id(); + } + + /* Make certain I only run on the appropriate processor */ + set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); + + /* O.K. Now that I'm on the appropriate processor, stop + * all of the others, and disable their local APICs. + */ + + smp_send_stop(); +#endif /* CONFIG_SMP */ + + lapic_shutdown(); + +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif +#ifdef CONFIG_HPET_TIMER + hpet_disable(); +#endif +} + +void __attribute__((weak)) mach_reboot_fixups(void) +{ +} + +static void native_machine_emergency_restart(void) +{ + if (!reboot_thru_bios) { + if (efi_enabled) { + efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); + load_idt(&no_idt); + __asm__ __volatile__("int3"); + } + /* rebooting needs to touch the page at absolute addr 0 */ + *((unsigned short *)__va(0x472)) = reboot_mode; + for (;;) { + mach_reboot_fixups(); /* for board specific fixups */ + mach_reboot(); + /* That didn't work - force a triple fault.. */ + load_idt(&no_idt); + __asm__ __volatile__("int3"); + } + } + if (efi_enabled) + efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL); + + machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); +} + +static void native_machine_restart(char * __unused) +{ + machine_shutdown(); + machine_emergency_restart(); +} + +static void native_machine_halt(void) +{ +} + +static void native_machine_power_off(void) +{ + if (pm_power_off) { + machine_shutdown(); + pm_power_off(); + } +} + + +struct machine_ops machine_ops = { + .power_off = native_machine_power_off, + .shutdown = native_machine_shutdown, + .emergency_restart = native_machine_emergency_restart, + .restart = native_machine_restart, + .halt = native_machine_halt, +}; + +void machine_power_off(void) +{ + machine_ops.power_off(); +} + +void machine_shutdown(void) +{ + machine_ops.shutdown(); +} + +void machine_emergency_restart(void) +{ + machine_ops.emergency_restart(); +} + +void machine_restart(char *cmd) +{ + machine_ops.restart(cmd); +} + +void machine_halt(void) +{ + machine_ops.halt(); +} diff -Nurb linux-2.6.24.3/arch/x86/kernel/traps_32.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c --- linux-2.6.24.3/arch/x86/kernel/traps_32.c 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c 2008-03-02 14:55:48.000000000 -0800 @@ -66,6 +66,10 @@ DECLARE_BITMAP(used_vectors, NR_VECTORS); EXPORT_SYMBOL_GPL(used_vectors); +#ifdef CONFIG_COBALT_RAQ +#include +#endif + asmlinkage int system_call(void); /* Do we ignore FPU interrupts ? */ @@ -633,9 +637,13 @@ static __kprobes void mem_parity_error(unsigned char reason, struct pt_regs * regs) { +#ifdef CONFIG_COBALT_RAQ + cobalt_nmi(reason, regs); +#else printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " "CPU %d.\n", reason, smp_processor_id()); printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); +#endif #if defined(CONFIG_EDAC) if(edac_handler_set()) { diff -Nurb linux-2.6.24.3/arch/x86/kernel/traps_32.c.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c.orig --- linux-2.6.24.3/arch/x86/kernel/traps_32.c.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,1224 @@ +/* + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_EISA +#include +#include +#endif + +#ifdef CONFIG_MCA +#include +#endif + +#if defined(CONFIG_EDAC) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mach_traps.h" + +int panic_on_unrecovered_nmi; + +DECLARE_BITMAP(used_vectors, NR_VECTORS); +EXPORT_SYMBOL_GPL(used_vectors); + +asmlinkage int system_call(void); + +/* Do we ignore FPU interrupts ? */ +char ignore_fpu_irq = 0; + +/* + * The IDT has to be page-aligned to simplify the Pentium + * F0 0F bug workaround.. We have a special link segment + * for this. + */ +struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; + +asmlinkage void divide_error(void); +asmlinkage void debug(void); +asmlinkage void nmi(void); +asmlinkage void int3(void); +asmlinkage void overflow(void); +asmlinkage void bounds(void); +asmlinkage void invalid_op(void); +asmlinkage void device_not_available(void); +asmlinkage void coprocessor_segment_overrun(void); +asmlinkage void invalid_TSS(void); +asmlinkage void segment_not_present(void); +asmlinkage void stack_segment(void); +asmlinkage void general_protection(void); +asmlinkage void page_fault(void); +asmlinkage void coprocessor_error(void); +asmlinkage void simd_coprocessor_error(void); +asmlinkage void alignment_check(void); +asmlinkage void spurious_interrupt_bug(void); +asmlinkage void machine_check(void); + +int kstack_depth_to_print = 24; +static unsigned int code_bytes = 64; + +static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size) +{ + return p > (void *)tinfo && + p <= (void *)tinfo + THREAD_SIZE - size; +} + +/* The form of the top of the frame on the stack */ +struct stack_frame { + struct stack_frame *next_frame; + unsigned long return_address; +}; + +static inline unsigned long print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long ebp, + const struct stacktrace_ops *ops, void *data) +{ +#ifdef CONFIG_FRAME_POINTER + struct stack_frame *frame = (struct stack_frame *)ebp; + while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) { + struct stack_frame *next; + unsigned long addr; + + addr = frame->return_address; + ops->address(data, addr); + /* + * break out of recursive entries (such as + * end_of_stack_stop_unwind_function). Also, + * we can never allow a frame pointer to + * move downwards! + */ + next = frame->next_frame; + if (next <= frame) + break; + frame = next; + } +#else + while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { + unsigned long addr; + + addr = *stack++; + if (__kernel_text_address(addr)) + ops->address(data, addr); + } +#endif + return ebp; +} + +#define MSG(msg) ops->warning(data, msg) + +void dump_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, + const struct stacktrace_ops *ops, void *data) +{ + unsigned long ebp = 0; + + if (!task) + task = current; + + if (!stack) { + unsigned long dummy; + stack = &dummy; + if (task != current) + stack = (unsigned long *)task->thread.esp; + } + +#ifdef CONFIG_FRAME_POINTER + if (!ebp) { + if (task == current) { + /* Grab ebp right from our regs */ + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + } else { + /* ebp is the last reg pushed by switch_to */ + ebp = *(unsigned long *) task->thread.esp; + } + } +#endif + + while (1) { + struct thread_info *context; + context = (struct thread_info *) + ((unsigned long)stack & (~(THREAD_SIZE - 1))); + ebp = print_context_stack(context, stack, ebp, ops, data); + /* Should be after the line below, but somewhere + in early boot context comes out corrupted and we + can't reference it -AK */ + if (ops->stack(data, "IRQ") < 0) + break; + stack = (unsigned long*)context->previous_esp; + if (!stack) + break; + touch_nmi_watchdog(); + } +} +EXPORT_SYMBOL(dump_trace); + +static void +print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) +{ + printk(data); + print_symbol(msg, symbol); + printk("\n"); +} + +static void print_trace_warning(void *data, char *msg) +{ + printk("%s%s\n", (char *)data, msg); +} + +static int print_trace_stack(void *data, char *name) +{ + return 0; +} + +/* + * Print one address/symbol entries per line. + */ +static void print_trace_address(void *data, unsigned long addr) +{ + printk("%s [<%08lx>] ", (char *)data, addr); + print_symbol("%s\n", addr); + touch_nmi_watchdog(); +} + +static const struct stacktrace_ops print_trace_ops = { + .warning = print_trace_warning, + .warning_symbol = print_trace_warning_symbol, + .stack = print_trace_stack, + .address = print_trace_address, +}; + +static void +show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long * stack, char *log_lvl) +{ + dump_trace(task, regs, stack, &print_trace_ops, log_lvl); + printk("%s =======================\n", log_lvl); +} + +void show_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long * stack) +{ + show_trace_log_lvl(task, regs, stack, ""); +} + +static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *esp, char *log_lvl) +{ + unsigned long *stack; + int i; + + if (esp == NULL) { + if (task) + esp = (unsigned long*)task->thread.esp; + else + esp = (unsigned long *)&esp; + } + + stack = esp; + for(i = 0; i < kstack_depth_to_print; i++) { + if (kstack_end(stack)) + break; + if (i && ((i % 8) == 0)) + printk("\n%s ", log_lvl); + printk("%08lx ", *stack++); + } + printk("\n%sCall Trace:\n", log_lvl); + show_trace_log_lvl(task, regs, esp, log_lvl); +} + +void show_stack(struct task_struct *task, unsigned long *esp) +{ + printk(" "); + show_stack_log_lvl(task, NULL, esp, ""); +} + +/* + * The architecture-independent dump_stack generator + */ +void dump_stack(void) +{ + unsigned long stack; + + printk("Pid: %d, comm: %.20s %s %s %.*s\n", + current->pid, current->comm, print_tainted(), + init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); + show_trace(current, NULL, &stack); +} + +EXPORT_SYMBOL(dump_stack); + +void show_registers(struct pt_regs *regs) +{ + int i; + + print_modules(); + __show_registers(regs, 0); + printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", + TASK_COMM_LEN, current->comm, task_pid_nr(current), + current_thread_info(), current, task_thread_info(current)); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (!user_mode_vm(regs)) { + u8 *eip; + unsigned int code_prologue = code_bytes * 43 / 64; + unsigned int code_len = code_bytes; + unsigned char c; + + printk("\n" KERN_EMERG "Stack: "); + show_stack_log_lvl(NULL, regs, ®s->esp, KERN_EMERG); + + printk(KERN_EMERG "Code: "); + + eip = (u8 *)regs->eip - code_prologue; + if (eip < (u8 *)PAGE_OFFSET || + probe_kernel_address(eip, c)) { + /* try starting at EIP */ + eip = (u8 *)regs->eip; + code_len = code_len - code_prologue + 1; + } + for (i = 0; i < code_len; i++, eip++) { + if (eip < (u8 *)PAGE_OFFSET || + probe_kernel_address(eip, c)) { + printk(" Bad EIP value."); + break; + } + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); + } + } + printk("\n"); +} + +int is_valid_bugaddr(unsigned long eip) +{ + unsigned short ud2; + + if (eip < PAGE_OFFSET) + return 0; + if (probe_kernel_address((unsigned short *)eip, ud2)) + return 0; + + return ud2 == 0x0b0f; +} + +/* + * This is gone through when something in the kernel has done something bad and + * is about to be terminated. + */ +void die(const char * str, struct pt_regs * regs, long err) +{ + static struct { + raw_spinlock_t lock; + u32 lock_owner; + int lock_owner_depth; + } die = { + .lock = __RAW_SPIN_LOCK_UNLOCKED, + .lock_owner = -1, + .lock_owner_depth = 0 + }; + static int die_counter; + unsigned long flags; + + oops_enter(); + + if (die.lock_owner != raw_smp_processor_id()) { + console_verbose(); + raw_local_irq_save(flags); + __raw_spin_lock(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); + } else + raw_local_irq_save(flags); + + if (++die.lock_owner_depth < 3) { + unsigned long esp; + unsigned short ss; + + report_bug(regs->eip, regs); + + printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, + ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); +#endif +#ifdef CONFIG_SMP + printk("SMP "); +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); +#endif + printk("\n"); + + if (notify_die(DIE_OOPS, str, regs, err, + current->thread.trap_no, SIGSEGV) != + NOTIFY_STOP) { + show_registers(regs); + /* Executive summary in case the oops scrolled away */ + esp = (unsigned long) (®s->esp); + savesegment(ss, ss); + if (user_mode(regs)) { + esp = regs->esp; + ss = regs->xss & 0xffff; + } + printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip); + print_symbol("%s", regs->eip); + printk(" SS:ESP %04x:%08lx\n", ss, esp); + } + else + regs = NULL; + } else + printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); + + bust_spinlocks(0); + die.lock_owner = -1; + add_taint(TAINT_DIE); + __raw_spin_unlock(&die.lock); + raw_local_irq_restore(flags); + + if (!regs) + return; + + if (kexec_should_crash(current)) + crash_kexec(regs); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) + panic("Fatal exception"); + + oops_exit(); + do_exit(SIGSEGV); +} + +static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!user_mode_vm(regs)) + die(str, regs, err); +} + +static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, + struct pt_regs * regs, long error_code, + siginfo_t *info) +{ + struct task_struct *tsk = current; + + if (regs->eflags & VM_MASK) { + if (vm86) + goto vm86_trap; + goto trap_signal; + } + + if (!user_mode(regs)) + goto kernel_trap; + + trap_signal: { + /* + * We want error_code and trap_no set for userspace faults and + * kernelspace faults which result in die(), but not + * kernelspace faults which are fixed up. die() gives the + * process no chance to handle the signal and notice the + * kernel fault information, so that won't result in polluting + * the information about previously queued, but not yet + * delivered, faults. See also do_general_protection below. + */ + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); + return; + } + + kernel_trap: { + if (!fixup_exception(regs)) { + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + die(str, regs, error_code); + } + return; + } + + vm86_trap: { + int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); + if (ret) goto trap_signal; + return; + } +} + +#define DO_ERROR(trapnr, signr, str, name) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ +} + +#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + if (irq) \ + local_irq_enable(); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ +} + +#define DO_VM86_ERROR(trapnr, signr, str, name) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ +} + +#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ + trace_hardirqs_fixup(); \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ +} + +DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +#ifndef CONFIG_KPROBES +DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +#endif +DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) +DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) +DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0) +DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) +DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) +DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) +DO_ERROR(12, SIGBUS, "stack segment", stack_segment) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) +DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1) + +fastcall void __kprobes do_general_protection(struct pt_regs * regs, + long error_code) +{ + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct thread_struct *thread = ¤t->thread; + + /* + * Perform the lazy TSS's I/O bitmap copy. If the TSS has an + * invalid offset set (the LAZY one) and the faulting thread has + * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS + * and we set the offset field correctly. Then we let the CPU to + * restart the faulting instruction. + */ + if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && + thread->io_bitmap_ptr) { + memcpy(tss->io_bitmap, thread->io_bitmap_ptr, + thread->io_bitmap_max); + /* + * If the previously set map was extending to higher ports + * than the current one, pad extra space with 0xff (no access). + */ + if (thread->io_bitmap_max < tss->io_bitmap_max) + memset((char *) tss->io_bitmap + + thread->io_bitmap_max, 0xff, + tss->io_bitmap_max - thread->io_bitmap_max); + tss->io_bitmap_max = thread->io_bitmap_max; + tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; + tss->io_bitmap_owner = thread; + put_cpu(); + return; + } + put_cpu(); + + if (regs->eflags & VM_MASK) + goto gp_in_vm86; + + if (!user_mode(regs)) + goto gp_in_kernel; + + current->thread.error_code = error_code; + current->thread.trap_no = 13; + if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) && + printk_ratelimit()) + printk(KERN_INFO + "%s[%d] general protection eip:%lx esp:%lx error:%lx\n", + current->comm, task_pid_nr(current), + regs->eip, regs->esp, error_code); + + force_sig(SIGSEGV, current); + return; + +gp_in_vm86: + local_irq_enable(); + handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + return; + +gp_in_kernel: + if (!fixup_exception(regs)) { + current->thread.error_code = error_code; + current->thread.trap_no = 13; + if (notify_die(DIE_GPF, "general protection fault", regs, + error_code, 13, SIGSEGV) == NOTIFY_STOP) + return; + die("general protection fault", regs, error_code); + } +} + +static __kprobes void +mem_parity_error(unsigned char reason, struct pt_regs * regs) +{ + printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " + "CPU %d.\n", reason, smp_processor_id()); + printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); + +#if defined(CONFIG_EDAC) + if(edac_handler_set()) { + edac_atomic_assert_error(); + return; + } +#endif + + if (panic_on_unrecovered_nmi) + panic("NMI: Not continuing"); + + printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + + /* Clear and disable the memory parity error line. */ + clear_mem_error(reason); +} + +static __kprobes void +io_check_error(unsigned char reason, struct pt_regs * regs) +{ + unsigned long i; + + printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + + /* Re-enable the IOCK line, wait for a few seconds */ + reason = (reason & 0xf) | 8; + outb(reason, 0x61); + i = 2000; + while (--i) udelay(1000); + reason &= ~8; + outb(reason, 0x61); +} + +static __kprobes void +unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +{ +#ifdef CONFIG_MCA + /* Might actually be able to figure out what the guilty party + * is. */ + if( MCA_bus ) { + mca_handle_nmi(); + return; + } +#endif + printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " + "CPU %d.\n", reason, smp_processor_id()); + printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); + if (panic_on_unrecovered_nmi) + panic("NMI: Not continuing"); + + printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); +} + +static DEFINE_SPINLOCK(nmi_print_lock); + +void __kprobes die_nmi(struct pt_regs *regs, const char *msg) +{ + if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == + NOTIFY_STOP) + return; + + spin_lock(&nmi_print_lock); + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + bust_spinlocks(1); + printk(KERN_EMERG "%s", msg); + printk(" on CPU%d, eip %08lx, registers:\n", + smp_processor_id(), regs->eip); + show_registers(regs); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); + + /* If we are in kernel we are probably nested up pretty bad + * and might aswell get out now while we still can. + */ + if (!user_mode_vm(regs)) { + current->thread.trap_no = 2; + crash_kexec(regs); + } + + do_exit(SIGSEGV); +} + +static __kprobes void default_do_nmi(struct pt_regs * regs) +{ + unsigned char reason = 0; + + /* Only the BSP gets external NMIs from the system. */ + if (!smp_processor_id()) + reason = get_nmi_reason(); + + if (!(reason & 0xc0)) { + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) + return; +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ + if (nmi_watchdog_tick(regs, reason)) + return; + if (!do_nmi_callback(regs, smp_processor_id())) +#endif + unknown_nmi_error(reason, regs); + + return; + } + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) + return; + if (reason & 0x80) + mem_parity_error(reason, regs); + if (reason & 0x40) + io_check_error(reason, regs); + /* + * Reassert NMI in case it became active meanwhile + * as it's edge-triggered. + */ + reassert_nmi(); +} + +static int ignore_nmis; + +fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) +{ + int cpu; + + nmi_enter(); + + cpu = smp_processor_id(); + + ++nmi_count(cpu); + + if (!ignore_nmis) + default_do_nmi(regs); + + nmi_exit(); +} + +void stop_nmi(void) +{ + acpi_nmi_disable(); + ignore_nmis++; +} + +void restart_nmi(void) +{ + ignore_nmis--; + acpi_nmi_enable(); +} + +#ifdef CONFIG_KPROBES +fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) +{ + trace_hardirqs_fixup(); + + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return; + /* This is an interrupt gate, because kprobes wants interrupts + disabled. Normal trap handlers don't. */ + restore_interrupts(regs); + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); +} +#endif + +/* + * Our handling of the processor debug registers is non-trivial. + * We do not clear them on entry and exit from the kernel. Therefore + * it is possible to get a watchpoint trap here from inside the kernel. + * However, the code in ./ptrace.c has ensured that the user can + * only set watchpoints on userspace addresses. Therefore the in-kernel + * watchpoint trap can only occur in code which is reading/writing + * from user space. Such code must not hold kernel locks (since it + * can equally take a page fault), therefore it is safe to call + * force_sig_info even though that claims and releases locks. + * + * Code in ./signal.c ensures that the debug control register + * is restored before we deliver any signal, and therefore that + * user code runs with the correct debug control register even though + * we clear it here. + * + * Being careful here means that we don't have to be as careful in a + * lot of more complicated places (task switching can be a bit lazy + * about restoring all the debug state, and ptrace doesn't have to + * find every occurrence of the TF bit that could be saved away even + * by user code) + */ +fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code) +{ + unsigned int condition; + struct task_struct *tsk = current; + + trace_hardirqs_fixup(); + + get_debugreg(condition, 6); + + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, + SIGTRAP) == NOTIFY_STOP) + return; + /* It's safe to allow irq's after DR6 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + + /* Mask out spurious debug traps due to lazy DR7 setting */ + if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { + if (!tsk->thread.debugreg[7]) + goto clear_dr7; + } + + if (regs->eflags & VM_MASK) + goto debug_vm86; + + /* Save debug status register where ptrace can see it */ + tsk->thread.debugreg[6] = condition; + + /* + * Single-stepping through TF: make sure we ignore any events in + * kernel space (but re-enable TF when returning to user mode). + */ + if (condition & DR_STEP) { + /* + * We already checked v86 mode above, so we can + * check for kernel mode by just checking the CPL + * of CS. + */ + if (!user_mode(regs)) + goto clear_TF_reenable; + } + + /* Ok, finally something we can handle */ + send_sigtrap(tsk, regs, error_code); + + /* Disable additional traps. They'll be re-enabled when + * the signal is delivered. + */ +clear_dr7: + set_debugreg(0, 7); + return; + +debug_vm86: + handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + return; + +clear_TF_reenable: + set_tsk_thread_flag(tsk, TIF_SINGLESTEP); + regs->eflags &= ~TF_MASK; + return; +} + +/* + * Note that we play around with the 'TS' bit in an attempt to get + * the correct behaviour even in the presence of the asynchronous + * IRQ13 behaviour + */ +void math_error(void __user *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short cwd, swd; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + task->thread.trap_no = 16; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + cwd = get_fpu_cwd(task); + swd = get_fpu_swd(task); + switch (swd & ~cwd & 0x3f) { + case 0x000: /* No unmasked exception */ + return; + default: /* Multiple exceptions */ + break; + case 0x001: /* Invalid Op */ + /* + * swd & 0x240 == 0x040: Stack Underflow + * swd & 0x240 == 0x240: Stack Overflow + * User must clear the SF bit (0x40) if set + */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code) +{ + ignore_fpu_irq = 1; + math_error((void __user *)regs->eip); +} + +static void simd_math_error(void __user *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short mxcsr; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + task->thread.trap_no = 19; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * The SIMD FPU exceptions are handled a little differently, as there + * is only a single status/control register. Thus, to determine which + * unmasked exception was caught we must mask the exception mask bits + * at 0x1f80, and then use these to mask the exception bits at 0x3f. + */ + mxcsr = get_fpu_mxcsr(task); + switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +fastcall void do_simd_coprocessor_error(struct pt_regs * regs, + long error_code) +{ + if (cpu_has_xmm) { + /* Handle SIMD FPU exceptions on PIII+ processors. */ + ignore_fpu_irq = 1; + simd_math_error((void __user *)regs->eip); + } else { + /* + * Handle strange cache flush from user space exception + * in all other cases. This is undocumented behaviour. + */ + if (regs->eflags & VM_MASK) { + handle_vm86_fault((struct kernel_vm86_regs *)regs, + error_code); + return; + } + current->thread.trap_no = 19; + current->thread.error_code = error_code; + die_if_kernel("cache flush denied", regs, error_code); + force_sig(SIGSEGV, current); + } +} + +fastcall void do_spurious_interrupt_bug(struct pt_regs * regs, + long error_code) +{ +#if 0 + /* No need to warn about this any longer. */ + printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); +#endif +} + +fastcall unsigned long patch_espfix_desc(unsigned long uesp, + unsigned long kesp) +{ + struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; + unsigned long base = (kesp - uesp) & -THREAD_SIZE; + unsigned long new_kesp = kesp - base; + unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; + __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; + /* Set up base for espfix segment */ + desc &= 0x00f0ff0000000000ULL; + desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | + ((((__u64)base) << 32) & 0xff00000000000000ULL) | + ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | + (lim_pages & 0xffff); + *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; + return new_kesp; +} + +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + * + * Careful.. There are problems with IBM-designed IRQ13 behaviour. + * Don't touch unless you *really* know how it works. + * + * Must be called with kernel preemption disabled (in this case, + * local interrupts are disabled at the call-site in entry.S). + */ +asmlinkage void math_state_restore(void) +{ + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = thread->task; + + clts(); /* Allow maths ops (or we recurse) */ + if (!tsk_used_math(tsk)) + init_fpu(tsk); + restore_fpu(tsk); + thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ + tsk->fpu_counter++; +} +EXPORT_SYMBOL_GPL(math_state_restore); + +#ifndef CONFIG_MATH_EMULATION + +asmlinkage void math_emulate(long arg) +{ + printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n"); + printk(KERN_EMERG "killing %s.\n",current->comm); + force_sig(SIGFPE,current); + schedule(); +} + +#endif /* CONFIG_MATH_EMULATION */ + +/* + * This needs to use 'idt_table' rather than 'idt', and + * thus use the _nonmapped_ version of the IDT, as the + * Pentium F0 0F bugfix can have resulted in the mapped + * IDT being write-protected. + */ +void set_intr_gate(unsigned int n, void *addr) +{ + _set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS); +} + +/* + * This routine sets up an interrupt gate at directory privilege level 3. + */ +static inline void set_system_intr_gate(unsigned int n, void *addr) +{ + _set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, addr, __KERNEL_CS); +} + +static void __init set_trap_gate(unsigned int n, void *addr) +{ + _set_gate(n, DESCTYPE_TRAP, addr, __KERNEL_CS); +} + +static void __init set_system_gate(unsigned int n, void *addr) +{ + _set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS); +} + +static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) +{ + _set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3)); +} + + +void __init trap_init(void) +{ + int i; + +#ifdef CONFIG_EISA + void __iomem *p = ioremap(0x0FFFD9, 4); + if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) { + EISA_bus = 1; + } + iounmap(p); +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); +#endif + + set_trap_gate(0,÷_error); + set_intr_gate(1,&debug); + set_intr_gate(2,&nmi); + set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ + set_system_gate(4,&overflow); + set_trap_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_intr_gate(14,&page_fault); + set_trap_gate(15,&spurious_interrupt_bug); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); +#ifdef CONFIG_X86_MCE + set_trap_gate(18,&machine_check); +#endif + set_trap_gate(19,&simd_coprocessor_error); + + if (cpu_has_fxsr) { + /* + * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. + * Generates a compile-time "error: zero width for bit-field" if + * the alignment is wrong. + */ + struct fxsrAlignAssert { + int _:!(offsetof(struct task_struct, + thread.i387.fxsave) & 15); + }; + + printk(KERN_INFO "Enabling fast FPU save and restore... "); + set_in_cr4(X86_CR4_OSFXSR); + printk("done.\n"); + } + if (cpu_has_xmm) { + printk(KERN_INFO "Enabling unmasked SIMD FPU exception " + "support... "); + set_in_cr4(X86_CR4_OSXMMEXCPT); + printk("done.\n"); + } + + set_system_gate(SYSCALL_VECTOR,&system_call); + + /* Reserve all the builtin and the syscall vector. */ + for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) + set_bit(i, used_vectors); + set_bit(SYSCALL_VECTOR, used_vectors); + + /* + * Should be a barrier for any external CPU state. + */ + cpu_init(); + + trap_init_hook(); +} + +static int __init kstack_setup(char *s) +{ + kstack_depth_to_print = simple_strtoul(s, NULL, 0); + return 1; +} +__setup("kstack=", kstack_setup); + +static int __init code_bytes_setup(char *s) +{ + code_bytes = simple_strtoul(s, NULL, 0); + if (code_bytes > 8192) + code_bytes = 8192; + + return 1; +} +__setup("code_bytes=", code_bytes_setup); diff -Nurb linux-2.6.24.3/drivers/char/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig --- linux-2.6.24.3/drivers/char/Kconfig 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig 2008-03-02 14:55:48.000000000 -0800 @@ -813,7 +813,7 @@ will get access to the real time clock (or hardware clock) built into your computer. -config COBALT_LCD +config COBALT_MIPS_LCD bool "Support for Cobalt LCD" depends on MIPS_COBALT help diff -Nurb linux-2.6.24.3/drivers/char/Kconfig.orig linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig.orig --- linux-2.6.24.3/drivers/char/Kconfig.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,1044 @@ +# +# Character device configuration +# + +menu "Character devices" + +config VT + bool "Virtual terminal" if EMBEDDED + depends on !S390 + select INPUT + default y if !VIOCONS + ---help--- + If you say Y here, you will get support for terminal devices with + display and keyboard devices. These are called "virtual" because you + can run several virtual terminals (also called virtual consoles) on + one physical terminal. This is rather useful, for example one + virtual terminal can collect system messages and warnings, another + one can be used for a text-mode user session, and a third could run + an X session, all in parallel. Switching between virtual terminals + is done with certain key combinations, usually Alt-. + + The setterm command ("man setterm") can be used to change the + properties (such as colors or beeping) of a virtual terminal. The + man page console_codes(4) ("man console_codes") contains the special + character sequences that can be used to change those properties + directly. The fonts used on virtual terminals can be changed with + the setfont ("man setfont") command and the key bindings are defined + with the loadkeys ("man loadkeys") command. + + You need at least one virtual terminal device in order to make use + of your keyboard and monitor. Therefore, only people configuring an + embedded system would want to say N here in order to save some + memory; the only way to log into such a system is then via a serial + or network connection. + + If unsure, say Y, or else you won't be able to do much with your new + shiny Linux system :-) + +config VT_CONSOLE + bool "Support for console on virtual terminal" if EMBEDDED + depends on VT + default y + ---help--- + The system console is the device which receives all kernel messages + and warnings and which allows logins in single user mode. If you + answer Y here, a virtual terminal (the device used to interact with + a physical terminal) can be used as system console. This is the most + common mode of operations, so you should say Y here unless you want + the kernel messages be output only to a serial port (in which case + you should say Y to "Console on serial port", below). + + If you do say Y here, by default the currently visible virtual + terminal (/dev/tty0) will be used as system console. You can change + that with a kernel command line option such as "console=tty3" which + would use the third virtual terminal as system console. (Try "man + bootparam" or see the documentation of your boot loader (lilo or + loadlin) about how to pass options to the kernel at boot time.) + + If unsure, say Y. + +config HW_CONSOLE + bool + depends on VT && !S390 && !UML + default y + +config VT_HW_CONSOLE_BINDING + bool "Support for binding and unbinding console drivers" + depends on HW_CONSOLE + default n + ---help--- + The virtual terminal is the device that interacts with the physical + terminal through console drivers. On these systems, at least one + console driver is loaded. In other configurations, additional console + drivers may be enabled, such as the framebuffer console. If more than + 1 console driver is enabled, setting this to 'y' will allow you to + select the console driver that will serve as the backend for the + virtual terminals. + + See for more + information. For framebuffer console users, please refer to + . + +config SERIAL_NONSTANDARD + bool "Non-standard serial port support" + depends on HAS_IOMEM + ---help--- + Say Y here if you have any non-standard serial boards -- boards + which aren't supported using the standard "dumb" serial driver. + This includes intelligent serial boards such as Cyclades, + Digiboards, etc. These are usually used for systems that need many + serial ports because they serve many terminals or dial-in + connections. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about non-standard serial boards. + + Most people can say N here. + +config COMPUTONE + tristate "Computone IntelliPort Plus serial support" + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) + ---help--- + This driver supports the entire family of Intelliport II/Plus + controllers with the exception of the MicroChannel controllers and + products previous to the Intelliport II. These are multiport cards, + which give you many serial ports. You would need something like this + to connect more than two modems to your Linux box, for instance in + order to become a dial-in server. If you have a card like that, say + Y here and read . + + To compile this driver as modules, choose M here: the + modules will be called ip2 and ip2main. + +config ROCKETPORT + tristate "Comtrol RocketPort support" + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) + help + This driver supports Comtrol RocketPort and RocketModem PCI boards. + These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or + modems. For information about the RocketPort/RocketModem boards + and this driver read . + + To compile this driver as a module, choose M here: the + module will be called rocket. + + If you want to compile this driver into the kernel, say Y here. If + you don't have a Comtrol RocketPort/RocketModem card installed, say N. + +config CYCLADES + tristate "Cyclades async mux support" + depends on SERIAL_NONSTANDARD && (PCI || ISA) + select FW_LOADER + ---help--- + This driver supports Cyclades Z and Y multiserial boards. + You would need something like this to connect more than two modems to + your Linux box, for instance in order to become a dial-in server. + + For information about the Cyclades-Z card, read + . + + To compile this driver as a module, choose M here: the + module will be called cyclades. + + If you haven't heard about it, it's safe to say N. + +config CYZ_INTR + bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)" + depends on EXPERIMENTAL && CYCLADES + help + The Cyclades-Z family of multiport cards allows 2 (two) driver op + modes: polling and interrupt. In polling mode, the driver will check + the status of the Cyclades-Z ports every certain amount of time + (which is called polling cycle and is configurable). In interrupt + mode, it will use an interrupt line (IRQ) in order to check the + status of the Cyclades-Z ports. The default op mode is polling. If + unsure, say N. + +config DIGIEPCA + tristate "Digiboard Intelligent Async Support" + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) + ---help--- + This is a driver for Digi International's Xx, Xeve, and Xem series + of cards which provide multiple serial ports. You would need + something like this to connect more than two modems to your Linux + box, for instance in order to become a dial-in server. This driver + supports the original PC (ISA) boards as well as PCI, and EISA. If + you have a card like this, say Y here and read the file + . + + To compile this driver as a module, choose M here: the + module will be called epca. + +config ESPSERIAL + tristate "Hayes ESP serial port support" + depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API + help + This is a driver which supports Hayes ESP serial ports. Both single + port cards and multiport cards are supported. Make sure to read + . + + To compile this driver as a module, choose M here: the + module will be called esp. + + If unsure, say N. + +config MOXA_INTELLIO + tristate "Moxa Intellio support" + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) + help + Say Y here if you have a Moxa Intellio multiport serial card. + + To compile this driver as a module, choose M here: the + module will be called moxa. + +config MOXA_SMARTIO + tristate "Moxa SmartIO support (OBSOLETE)" + depends on SERIAL_NONSTANDARD + help + Say Y here if you have a Moxa SmartIO multiport serial card. + + This driver can also be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mxser. If you want to do that, say M + here. + +config MOXA_SMARTIO_NEW + tristate "Moxa SmartIO support v. 2.0" + depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) + help + Say Y here if you have a Moxa SmartIO multiport serial card and/or + want to help develop a new version of this driver. + + This is upgraded (1.9.1) driver from original Moxa drivers with + changes finally resulting in PCI probing. + + This driver can also be built as a module. The module will be called + mxser_new. If you want to do that, say M here. + +config ISI + tristate "Multi-Tech multiport card support (EXPERIMENTAL)" + depends on SERIAL_NONSTANDARD && PCI + select FW_LOADER + help + This is a driver for the Multi-Tech cards which provide several + serial ports. The driver is experimental and can currently only be + built as a module. The module will be called isicom. + If you want to do that, choose M here. + +config SYNCLINK + tristate "Microgate SyncLink card support" + depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API + help + Provides support for the SyncLink ISA and PCI multiprotocol serial + adapters. These adapters support asynchronous and HDLC bit + synchronous communication up to 10Mbps (PCI adapter). + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclink. If you want to do that, say M + here. + +config SYNCLINKMP + tristate "SyncLink Multiport support" + depends on SERIAL_NONSTANDARD && PCI + help + Enable support for the SyncLink Multiport (2 or 4 ports) + serial adapter, running asynchronous and HDLC communications up + to 2.048Mbps. Each ports is independently selectable for + RS-232, V.35, RS-449, RS-530, and X.21 + + This driver may be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclinkmp. If you want to do that, say M + here. + +config SYNCLINK_GT + tristate "SyncLink GT/AC support" + depends on SERIAL_NONSTANDARD && PCI + help + Support for SyncLink GT and SyncLink AC families of + synchronous and asynchronous serial adapters + manufactured by Microgate Systems, Ltd. (www.microgate.com) + +config N_HDLC + tristate "HDLC line discipline support" + depends on SERIAL_NONSTANDARD + help + Allows synchronous HDLC communications with tty device drivers that + support synchronous HDLC such as the Microgate SyncLink adapter. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called n_hdlc. If you want to do that, say M + here. + +config RISCOM8 + tristate "SDL RISCom/8 card support" + depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + help + This is a driver for the SDL Communications RISCom/8 multiport card, + which gives you many serial ports. You would need something like + this to connect more than two modems to your Linux box, for instance + in order to become a dial-in server. If you have a card like that, + say Y here and read the file . + + Also it's possible to say M here and compile this driver as kernel + loadable module; the module will be called riscom8. + +config SPECIALIX + tristate "Specialix IO8+ card support" + depends on SERIAL_NONSTANDARD + help + This is a driver for the Specialix IO8+ multiport card (both the + ISA and the PCI version) which gives you many serial ports. You + would need something like this to connect more than two modems to + your Linux box, for instance in order to become a dial-in server. + + If you have a card like that, say Y here and read the file + . Also it's possible to say M here + and compile this driver as kernel loadable module which will be + called specialix. + +config SPECIALIX_RTSCTS + bool "Specialix DTR/RTS pin is RTS" + depends on SPECIALIX + help + The Specialix IO8+ card can only support either RTS or DTR. If you + say N here, the driver will use the pin as "DTR" when the tty is in + software handshake mode. If you say Y here or hardware handshake is + on, it will always be RTS. Read the file + for more information. + +config SX + tristate "Specialix SX (and SI) card support" + depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) + help + This is a driver for the SX and SI multiport serial cards. + Please read the file for details. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sx. If you want to do that, say M here. + +config RIO + tristate "Specialix RIO system support" + depends on SERIAL_NONSTANDARD + help + This is a driver for the Specialix RIO, a smart serial card which + drives an outboard box that can support up to 128 ports. Product + information is at . + There are both ISA and PCI versions. + +config RIO_OLDPCI + bool "Support really old RIO/PCI cards" + depends on RIO + help + Older RIO PCI cards need some initialization-time configuration to + determine the IRQ and some control addresses. If you have a RIO and + this doesn't seem to work, try setting this to Y. + +config STALDRV + bool "Stallion multiport serial support" + depends on SERIAL_NONSTANDARD + help + Stallion cards give you many serial ports. You would need something + like this to connect more than two modems to your Linux box, for + instance in order to become a dial-in server. If you say Y here, + you will be asked for your specific card model in the next + questions. Make sure to read in + this case. If you have never heard about all this, it's safe to + say N. + +config STALLION + tristate "Stallion EasyIO or EC8/32 support" + depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) + help + If you have an EasyIO or EasyConnection 8/32 multiport Stallion + card, then this is for you; say Y. Make sure to read + . + + To compile this driver as a module, choose M here: the + module will be called stallion. + +config ISTALLION + tristate "Stallion EC8/64, ONboard, Brumby support" + depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) + help + If you have an EasyConnection 8/64, ONboard, Brumby or Stallion + serial multiport card, say Y here. Make sure to read + . + + To compile this driver as a module, choose M here: the + module will be called istallion. + +config A2232 + tristate "Commodore A2232 serial support (EXPERIMENTAL)" + depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP + ---help--- + This option supports the 2232 7-port serial card shipped with the + Amiga 2000 and other Zorro-bus machines, dating from 1989. At + a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip + each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The + ports were connected with 8 pin DIN connectors on the card bracket, + for which 8 pin to DB25 adapters were supplied. The card also had + jumpers internally to toggle various pinning configurations. + + This driver can be built as a module; but then "generic_serial" + will also be built as a module. This has to be loaded before + "ser_a2232". If you want to do this, answer M here. + +config SGI_SNSC + bool "SGI Altix system controller communication support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) + help + If you have an SGI Altix and you want to enable system + controller communication from user space (you want this!), + say Y. Otherwise, say N. + +config SGI_TIOCX + bool "SGI TIO CX driver support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) + help + If you have an SGI Altix and you have fpga devices attached + to your TIO, say Y here, otherwise say N. + +config SGI_MBCS + tristate "SGI FPGA Core Services driver support" + depends on SGI_TIOCX + help + If you have an SGI Altix with an attached SABrick + say Y or M here, otherwise say N. + +source "drivers/serial/Kconfig" + +config UNIX98_PTYS + bool "Unix98 PTY support" if EMBEDDED + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + All modern Linux systems use the Unix98 ptys. Say Y unless + you're on an embedded system and want to conserve memory. + +config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS + range 0 256 + default "256" + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. + + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. + +config BRIQ_PANEL + tristate 'Total Impact briQ front panel driver' + depends on PPC_CHRP + ---help--- + The briQ is a small footprint CHRP computer with a frontpanel VFD, a + tristate led and two switches. It is the size of a CDROM drive. + + If you have such one and want anything showing on the VFD then you + must answer Y here. + + To compile this driver as a module, choose M here: the + module will be called briq_panel. + + It's safe to say N here. + +config PRINTER + tristate "Parallel printer support" + depends on PARPORT + ---help--- + If you intend to attach a printer to the parallel port of your Linux + box (as opposed to using a serial printer; if the connector at the + printer has 9 or 25 holes ["female"], then it's serial), say Y. + Also read the Printing-HOWTO, available from + . + + It is possible to share one parallel port among several devices + (e.g. printer and ZIP drive) and it is safe to compile the + corresponding drivers into the kernel. + + To compile this driver as a module, choose M here and read + . The module will be called lp. + + If you have several parallel ports, you can specify which ports to + use with the "lp" kernel command line option. (Try "man bootparam" + or see the documentation of your boot loader (lilo or loadlin) about + how to pass options to the kernel at boot time.) The syntax of the + "lp" command line option can be found in . + + If you have more than 8 printers, you need to increase the LP_NO + macro in lp.c and the PARPORT_MAX macro in parport.h. + +config LP_CONSOLE + bool "Support for console on line printer" + depends on PRINTER + ---help--- + If you want kernel messages to be printed out as they occur, you + can have a console on the printer. This option adds support for + doing that; to actually get it to happen you need to pass the + option "console=lp0" to the kernel at boot time. + + If the printer is out of paper (or off, or unplugged, or too + busy..) the kernel will stall until the printer is ready again. + By defining CONSOLE_LP_STRICT to 0 (at your own risk) you + can make the kernel continue when this happens, + but it'll lose the kernel messages. + + If unsure, say N. + +config PPDEV + tristate "Support for user-space parallel port device drivers" + depends on PARPORT + ---help--- + Saying Y to this adds support for /dev/parport device nodes. This + is needed for programs that want portable access to the parallel + port, for instance deviceid (which displays Plug-and-Play device + IDs). + + This is the parallel port equivalent of SCSI generic support (sg). + It is safe to say N to this -- it is not needed for normal printing + or parallel port CD-ROM/disk support. + + To compile this driver as a module, choose M here: the + module will be called ppdev. + + If unsure, say N. + +config HVC_DRIVER + bool + help + Generic "hypervisor virtual console" infrastructure for various + hypervisors (pSeries, iSeries, Xen, lguest). + It will automatically be selected if one of the back-end console drivers + is selected. + + +config HVC_CONSOLE + bool "pSeries Hypervisor Virtual Console support" + depends on PPC_PSERIES + select HVC_DRIVER + help + pSeries machines when partitioned support a hypervisor virtual + console. This driver allows each pSeries partition to have a console + which is accessed via the HMC. + +config HVC_ISERIES + bool "iSeries Hypervisor Virtual Console support" + depends on PPC_ISERIES + default y + select HVC_DRIVER + help + iSeries machines support a hypervisor virtual console. + +config HVC_RTAS + bool "IBM RTAS Console support" + depends on PPC_RTAS + select HVC_DRIVER + help + IBM Console device driver which makes use of RTAS + +config HVC_BEAT + bool "Toshiba's Beat Hypervisor Console support" + depends on PPC_CELLEB + select HVC_DRIVER + help + Toshiba's Cell Reference Set Beat Console device driver + +config HVC_XEN + bool "Xen Hypervisor Console support" + depends on XEN + select HVC_DRIVER + default y + help + Xen virtual console device driver + +config VIRTIO_CONSOLE + bool + select HVC_DRIVER + +config HVCS + tristate "IBM Hypervisor Virtual Console Server support" + depends on PPC_PSERIES + help + Partitionable IBM Power5 ppc64 machines allow hosting of + firmware virtual consoles from one Linux partition by + another Linux partition. This driver allows console data + from Linux partitions to be accessed through TTY device + interfaces in the device tree of a Linux partition running + this driver. + + To compile this driver as a module, choose M here: the + module will be called hvcs.ko. Additionally, this module + will depend on arch specific APIs exported from hvcserver.ko + which will also be compiled when this driver is built as a + module. + +source "drivers/char/ipmi/Kconfig" + +config DS1620 + tristate "NetWinder thermometer support" + depends on ARCH_NETWINDER + help + Say Y here to include support for the thermal management hardware + found in the NetWinder. This driver allows the user to control the + temperature set points and to read the current temperature. + + It is also possible to say M here to build it as a module (ds1620) + It is recommended to be used on a NetWinder, but it is not a + necessity. + +config NWBUTTON + tristate "NetWinder Button" + depends on ARCH_NETWINDER + ---help--- + If you say Y here and create a character device node /dev/nwbutton + with major and minor numbers 10 and 158 ("man mknod"), then every + time the orange button is pressed a number of times, the number of + times the button was pressed will be written to that device. + + This is most useful for applications, as yet unwritten, which + perform actions based on how many times the button is pressed in a + row. + + Do not hold the button down for too long, as the driver does not + alter the behaviour of the hardware reset circuitry attached to the + button; it will still execute a hard reset if the button is held + down for longer than approximately five seconds. + + To compile this driver as a module, choose M here: the + module will be called nwbutton. + + Most people will answer Y to this question and "Reboot Using Button" + below to be able to initiate a system shutdown from the button. + +config NWBUTTON_REBOOT + bool "Reboot Using Button" + depends on NWBUTTON + help + If you say Y here, then you will be able to initiate a system + shutdown and reboot by pressing the orange button a number of times. + The number of presses to initiate the shutdown is two by default, + but this can be altered by modifying the value of NUM_PRESSES_REBOOT + in nwbutton.h and recompiling the driver or, if you compile the + driver as a module, you can specify the number of presses at load + time with "insmod button reboot_count=". + +config NWFLASH + tristate "NetWinder flash support" + depends on ARCH_NETWINDER + ---help--- + If you say Y here and create a character device /dev/flash with + major 10 and minor 160 you can manipulate the flash ROM containing + the NetWinder firmware. Be careful as accidentally overwriting the + flash contents can render your computer unbootable. On no account + allow random users access to this device. :-) + + To compile this driver as a module, choose M here: the + module will be called nwflash. + + If you're not sure, say N. + +source "drivers/char/hw_random/Kconfig" + +config NVRAM + tristate "/dev/nvram support" + depends on ATARI || X86 || ARM || GENERIC_NVRAM + ---help--- + If you say Y here and create a character special file /dev/nvram + with major number 10 and minor number 144 using mknod ("man mknod"), + you get read and write access to the extra bytes of non-volatile + memory in the real time clock (RTC), which is contained in every PC + and most Ataris. The actual number of bytes varies, depending on the + nvram in the system, but is usually 114 (128-14 for the RTC). + + This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" + on Ataris. /dev/nvram may be used to view settings there, or to + change them (with some utility). It could also be used to frequently + save a few bits of very important data that may not be lost over + power-off and for which writing to disk is too insecure. Note + however that most NVRAM space in a PC belongs to the BIOS and you + should NEVER idly tamper with it. See Ralf Brown's interrupt list + for a guide to the use of CMOS bytes by your BIOS. + + On Atari machines, /dev/nvram is always configured and does not need + to be selected. + + To compile this driver as a module, choose M here: the + module will be called nvram. + +config RTC + tristate "Enhanced Real Time Clock Support" + depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + into your computer. + + Every PC has such a clock built in. It can be used to generate + signals from as low as 1Hz up to 8192Hz, and can also be used + as a 24 hour alarm. It reports status information via the file + /proc/driver/rtc and its behaviour is set by various ioctls on + /dev/rtc. + + If you run Linux on a multiprocessor machine and said Y to + "Symmetric Multi Processing" above, you should say Y here to read + and set the RTC in an SMP compatible fashion. + + If you think you have a use for such a device (such as periodic data + sampling), then say Y here, and read + for details. + + To compile this driver as a module, choose M here: the + module will be called rtc. + +config JS_RTC + tristate "Enhanced Real Time Clock Support" + depends on SPARC32 && PCI + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + into your computer. + + Every PC has such a clock built in. It can be used to generate + signals from as low as 1Hz up to 8192Hz, and can also be used + as a 24 hour alarm. It reports status information via the file + /proc/driver/rtc and its behaviour is set by various ioctls on + /dev/rtc. + + If you think you have a use for such a device (such as periodic data + sampling), then say Y here, and read + for details. + + To compile this driver as a module, choose M here: the + module will be called js-rtc. + +config SGI_DS1286 + tristate "SGI DS1286 RTC support" + depends on SGI_IP22 + help + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock built into your computer. + Every SGI has such a clock built in. It reports status information + via the file /proc/rtc and its behaviour is set by various ioctls on + /dev/rtc. + +config SGI_IP27_RTC + bool "SGI M48T35 RTC support" + depends on SGI_IP27 + help + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock built into your computer. + Every SGI has such a clock built in. It reports status information + via the file /proc/rtc and its behaviour is set by various ioctls on + /dev/rtc. + +config GEN_RTC + tristate "Generic /dev/rtc emulation" + depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + into your computer. + + It reports status information via the file /proc/driver/rtc and its + behaviour is set by various ioctls on /dev/rtc. If you enable the + "extended RTC operation" below it will also provide an emulation + for RTC_UIE which is required by some programs and may improve + precision in some cases. + + To compile this driver as a module, choose M here: the + module will be called genrtc. + +config GEN_RTC_X + bool "Extended RTC operation" + depends on GEN_RTC + help + Provides an emulation for RTC_UIE which is required by some programs + and may improve precision of the generic RTC support in some cases. + +config EFI_RTC + bool "EFI Real Time Clock Services" + depends on IA64 + +config DS1302 + tristate "DS1302 RTC support" + depends on M32R && (PLAT_M32700UT || PLAT_OPSPUT) + help + If you say Y here and create a character special file /dev/rtc with + major number 121 and minor number 0 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + into your computer. + +config COBALT_LCD + bool "Support for Cobalt LCD" + depends on MIPS_COBALT + help + This option enables support for the LCD display and buttons found + on Cobalt systems through a misc device. + +config DTLK + tristate "Double Talk PC internal speech card support" + depends on ISA + help + This driver is for the DoubleTalk PC, a speech synthesizer + manufactured by RC Systems (). It is also + called the `internal DoubleTalk'. + + To compile this driver as a module, choose M here: the + module will be called dtlk. + +config R3964 + tristate "Siemens R3964 line discipline" + ---help--- + This driver allows synchronous communication with devices using the + Siemens R3964 packet protocol. Unless you are dealing with special + hardware like PLCs, you are unlikely to need this. + + To compile this driver as a module, choose M here: the + module will be called n_r3964. + + If unsure, say N. + +config APPLICOM + tristate "Applicom intelligent fieldbus card support" + depends on PCI + ---help--- + This driver provides the kernel-side support for the intelligent + fieldbus cards made by Applicom International. More information + about these cards can be found on the WWW at the address + , or by email from David Woodhouse + . + + To compile this driver as a module, choose M here: the + module will be called applicom. + + If unsure, say N. + +config SONYPI + tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)" + depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT + ---help--- + This driver enables access to the Sony Programmable I/O Control + Device which can be found in many (all ?) Sony Vaio laptops. + + If you have one of those laptops, read + , and say Y or M here. + + To compile this driver as a module, choose M here: the + module will be called sonypi. + +config GPIO_TB0219 + tristate "TANBAC TB0219 GPIO support" + depends on TANBAC_TB022X + select GPIO_VR41XX + +source "drivers/char/pcmcia/Kconfig" + +config MWAVE + tristate "ACP Modem (Mwave) support" + depends on X86 + select SERIAL_8250 + ---help--- + The ACP modem (Mwave) for Linux is a WinModem. It is composed of a + kernel driver and a user level application. Together these components + support direct attachment to public switched telephone networks (PSTNs) + and support selected world wide countries. + + This version of the ACP Modem driver supports the IBM Thinkpad 600E, + 600, and 770 that include on board ACP modem hardware. + + The modem also supports the standard communications port interface + (ttySx) and is compatible with the Hayes AT Command Set. + + The user level application needed to use this driver can be found at + the IBM Linux Technology Center (LTC) web site: + . + + If you own one of the above IBM Thinkpads which has the Mwave chipset + in it, say Y. + + To compile this driver as a module, choose M here: the + module will be called mwave. + +config SCx200_GPIO + tristate "NatSemi SCx200 GPIO Support" + depends on SCx200 + select NSC_GPIO + help + Give userspace access to the GPIO pins on the National + Semiconductor SCx200 processors. + + If compiled as a module, it will be called scx200_gpio. + +config PC8736x_GPIO + tristate "NatSemi PC8736x GPIO Support" + depends on X86 + default SCx200_GPIO # mostly N + select NSC_GPIO # needed for support routines + help + Give userspace access to the GPIO pins on the National + Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip + has multiple functional units, inc several managed by + hwmon/pc87360 driver. Tested with PC-87366 + + If compiled as a module, it will be called pc8736x_gpio. + +config NSC_GPIO + tristate "NatSemi Base GPIO Support" + depends on X86_32 + # selected by SCx200_GPIO and PC8736x_GPIO + # what about 2 selectors differing: m != y + help + Common support used (and needed) by scx200_gpio and + pc8736x_gpio drivers. If those drivers are built as + modules, this one will be too, named nsc_gpio + +config CS5535_GPIO + tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" + depends on X86_32 + help + Give userspace access to the GPIO pins on the AMD CS5535 and + CS5536 Geode companion devices. + + If compiled as a module, it will be called cs5535_gpio. + +config GPIO_VR41XX + tristate "NEC VR4100 series General-purpose I/O Unit support" + depends on CPU_VR41XX + +config RAW_DRIVER + tristate "RAW driver (/dev/raw/rawN)" + depends on BLOCK + help + The raw driver permits block devices to be bound to /dev/raw/rawN. + Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. + See the raw(8) manpage for more details. + + Applications should preferably open the device (eg /dev/hda1) + with the O_DIRECT flag. + +config MAX_RAW_DEVS + int "Maximum number of RAW devices to support (1-8192)" + depends on RAW_DRIVER + default "256" + help + The maximum number of RAW devices that are supported. + Default is 256. Increase this number in case you need lots of + raw devices. + +config HPET + bool "HPET - High Precision Event Timer" if (X86 || IA64) + default n + depends on ACPI + help + If you say Y here, you will have a miscdevice named "/dev/hpet/". Each + open selects one of the timers supported by the HPET. The timers are + non-periodic and/or periodic. + +config HPET_RTC_IRQ + bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC + default n + depends on HPET + help + If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It + is assumed the platform called hpet_alloc with the RTC IRQ values for + the HPET timers. + +config HPET_MMAP + bool "Allow mmap of HPET" + default y + depends on HPET + help + If you say Y here, user applications will be able to mmap + the HPET registers. + + In some hardware implementations, the page containing HPET + registers may also contain other things that shouldn't be + exposed to the user. If this applies to your hardware, + say N here. + +config HANGCHECK_TIMER + tristate "Hangcheck timer" + depends on X86 || IA64 || PPC64 || S390 + help + The hangcheck-timer module detects when the system has gone + out to lunch past a certain margin. It can reboot the system + or merely print a warning. + +config MMTIMER + tristate "MMTIMER Memory mapped RTC for SGI Altix" + depends on IA64_GENERIC || IA64_SGI_SN2 + default y + help + The mmtimer device allows direct userspace access to the + Altix system timer. + +source "drivers/char/tpm/Kconfig" + +config TELCLOCK + tristate "Telecom clock driver for ATCA SBC" + depends on EXPERIMENTAL && X86 + default n + help + The telecom clock device is specific to the MPCBL0010 and MPCBL0050 + ATCA computers and allows direct userspace access to the + configuration of the telecom clock configuration settings. This + device is used for hardware synchronization across the ATCA backplane + fabric. Upon loading, the driver exports a sysfs directory, + /sys/devices/platform/telco_clock, with a number of files for + controlling the behavior of this hardware. + +config DEVPORT + bool + depends on !M68K + depends on ISA || PCI + default y + +source "drivers/s390/char/Kconfig" + +endmenu + diff -Nurb linux-2.6.24.3/drivers/char/Makefile linux-2.6.24.3-cobalt3-tw/drivers/char/Makefile --- linux-2.6.24.3/drivers/char/Makefile 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/char/Makefile 2008-03-02 14:55:48.000000000 -0800 @@ -85,7 +85,7 @@ obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_HW_RANDOM) += hw_random/ -obj-$(CONFIG_COBALT_LCD) += lcd.o +obj-$(CONFIG_COBALT_MIPS_LCD) += lcd.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o diff -Nurb linux-2.6.24.3/drivers/char/misc.c linux-2.6.24.3-cobalt3-tw/drivers/char/misc.c --- linux-2.6.24.3/drivers/char/misc.c 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/char/misc.c 2008-03-02 14:55:48.000000000 -0800 @@ -50,6 +50,17 @@ #include #include +#ifdef CONFIG_COBALT_RAQ +#include +#include +#include +#include +#include +#include +#include +#endif + + /* * Head entry for the doubly linked miscdevice list */ @@ -64,6 +75,13 @@ extern int pmu_device_init(void); +#ifdef CONFIG_COBALT_RAQ +extern int cobalt_init(void); +#endif +#ifdef CONFIG_COBALT_MIPS_LCD +extern int lcd_init(void); +#endif + #ifdef CONFIG_PROC_FS static void *misc_seq_start(struct seq_file *seq, loff_t *pos) { @@ -273,7 +291,9 @@ misc_class = class_create(THIS_MODULE, "misc"); if (IS_ERR(misc_class)) return PTR_ERR(misc_class); - +#ifdef CONFIG_COBALT_MIPS_LCD + lcd_init(); +#endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); diff -Nurb linux-2.6.24.3/drivers/char/nvram.c linux-2.6.24.3-cobalt3-tw/drivers/char/nvram.c --- linux-2.6.24.3/drivers/char/nvram.c 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/char/nvram.c 2008-03-02 14:55:48.000000000 -0800 @@ -42,12 +42,18 @@ #define PC 1 #define ATARI 2 +#define COBALT 3 /* select machine configuration */ #if defined(CONFIG_ATARI) # define MACH ATARI #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */ +# if defined(CONFIG_COBALT_RAQ) +# include +# define MACH COBALT +# else # define MACH PC +# endif #else # error Cannot build nvram driver for this machine configuration. #endif @@ -69,6 +75,18 @@ #endif +#if MACH == COBALT + +#define CHECK_DRIVER_INIT() 1 + +#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) + +#define mach_check_checksum cobalt_check_checksum +#define mach_set_checksum cobalt_set_checksum +#define mach_proc_infos cobalt_proc_infos + +#endif + #if MACH == ATARI /* Special parameters for RTC in Atari machines */ @@ -585,6 +603,177 @@ #endif /* MACH == PC */ +#if MACH == COBALT + +/* the cobalt CMOS has a wider range of its checksum */ +static int cobalt_check_checksum(void) +{ + int i; + unsigned short sum = 0; + unsigned short expect; + + for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { + if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) + continue; + + sum += __nvram_read_byte(i); + } + expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 | + __nvram_read_byte(COBT_CMOS_CHECKSUM+1); + return ((sum & 0xffff) == expect); +} + +static void cobalt_set_checksum(void) +{ + int i; + unsigned short sum = 0; + + for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { + if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) + continue; + + sum += __nvram_read_byte(i); + } + + __nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM); + __nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1); +} + +#ifdef CONFIG_PROC_FS + +static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + int i; + unsigned int checksum; + unsigned int flags; + char sernum[14]; + char *key = "cNoEbTaWlOtR!"; + unsigned char bto_csum; + + spin_lock_irq(&rtc_lock); + checksum = __nvram_check_checksum(); + spin_unlock_irq(&rtc_lock); + + PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); + + flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8 + | nvram[COBT_CMOS_FLAG_BYTE_1]; + + PRINT_PROC("Console: %s\n", + flags & COBT_CMOS_CONSOLE_FLAG ? "on": "off"); + + PRINT_PROC("Firmware Debug Messages: %s\n", + flags & COBT_CMOS_DEBUG_FLAG ? "on": "off"); + + PRINT_PROC("Auto Prompt: %s\n", + flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off"); + + PRINT_PROC("Shutdown Status: %s\n", + flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty"); + + PRINT_PROC("Hardware Probe: %s\n", + flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full"); + + PRINT_PROC("System Fault: %sdetected\n", + flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not "); + + PRINT_PROC("Panic on OOPS: %s\n", + flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no"); + + PRINT_PROC("Delayed Cache Initialization: %s\n", + flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no"); + + PRINT_PROC("Show Logo at Boot: %s\n", + flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes"); + + PRINT_PROC("Boot Method: "); + switch (nvram[COBT_CMOS_BOOT_METHOD]) { + case COBT_CMOS_BOOT_METHOD_DISK: + PRINT_PROC("disk\n"); + break; + + case COBT_CMOS_BOOT_METHOD_ROM: + PRINT_PROC("rom\n"); + break; + + case COBT_CMOS_BOOT_METHOD_NET: + PRINT_PROC("net\n"); + break; + + default: + PRINT_PROC("unknown\n"); + break; + } + + PRINT_PROC("Primary Boot Device: %d:%d\n", + nvram[COBT_CMOS_BOOT_DEV0_MAJ], + nvram[COBT_CMOS_BOOT_DEV0_MIN] ); + PRINT_PROC("Secondary Boot Device: %d:%d\n", + nvram[COBT_CMOS_BOOT_DEV1_MAJ], + nvram[COBT_CMOS_BOOT_DEV1_MIN] ); + PRINT_PROC("Tertiary Boot Device: %d:%d\n", + nvram[COBT_CMOS_BOOT_DEV2_MAJ], + nvram[COBT_CMOS_BOOT_DEV2_MIN] ); + + PRINT_PROC("Uptime: %d\n", + nvram[COBT_CMOS_UPTIME_0] << 24 | + nvram[COBT_CMOS_UPTIME_1] << 16 | + nvram[COBT_CMOS_UPTIME_2] << 8 | + nvram[COBT_CMOS_UPTIME_3]); + + PRINT_PROC("Boot Count: %d\n", + nvram[COBT_CMOS_BOOTCOUNT_0] << 24 | + nvram[COBT_CMOS_BOOTCOUNT_1] << 16 | + nvram[COBT_CMOS_BOOTCOUNT_2] << 8 | + nvram[COBT_CMOS_BOOTCOUNT_3]); + + /* 13 bytes of serial num */ + for (i=0 ; i<13 ; i++) { + sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i]; + } + sernum[13] = '\0'; + + checksum = 0; + for (i=0 ; i<13 ; i++) { + checksum += sernum[i] ^ key[i]; + } + checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff; + + PRINT_PROC("Serial Number: %s", sernum); + if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) { + PRINT_PROC(" (invalid checksum)"); + } + PRINT_PROC("\n"); + + PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ], + nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]); + + PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0], + nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2], + nvram[COBT_CMOS_BTO_IP_3]); + bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1] + + nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3]; + if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) { + PRINT_PROC(" (invalid checksum)"); + } + PRINT_PROC("\n"); + + if (flags & COBT_CMOS_VERSION_FLAG + && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) { + PRINT_PROC("BTO Code: 0x%x\n", + nvram[COBT_CMOS_BTO_CODE_0] << 24 | + nvram[COBT_CMOS_BTO_CODE_1] << 16 | + nvram[COBT_CMOS_BTO_CODE_2] << 8 | + nvram[COBT_CMOS_BTO_CODE_3]); + } + + return 1; +} +#endif /* CONFIG_PROC_FS */ + +#endif /* MACH == COBALT */ + #if MACH == ATARI static int diff -Nurb linux-2.6.24.3/drivers/cobalt/acpi.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/acpi.c --- linux-2.6.24.3/drivers/cobalt/acpi.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/acpi.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,1993 @@ + /* + * cobalt acpi driver + * Copyright (c) 2000, Cobalt Networks, Inc. + * Copyright (c) 2001, Sun Microsystems, Inc. + * $Id: acpi.c,v 1.32 2002/06/26 19:08:54 duncan Exp $ + * + * author: asun@cobalt.com, thockin@sun.com + * modified by: jeff@404ster.com + * + * this driver just sets stuff up for ACPI interrupts + * + * if acpi support really existed in the kernel, we would read + * data from the ACPI tables. however, it doesn't. as a result, + * we use some hardcoded values. + * + * This should be SMP safe. The only data that needs protection is the acpi + * handler list. It gets scanned at timer-interrupts, must use + * irqsave/restore locks. Read/write locks would be useful if there were any + * other times that the list was read but never written. --TPH + * + * /proc/acpi emulation emulates the /proc/acpi/events interface supplied by + * the INTEL acpi drivers. A lot of the code to handle it has been adapted + * from there. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ACPI_DRIVER "Cobalt Networks ACPI driver" +#define ACPI_DRIVER_VMAJ 1 +#define ACPI_DRIVER_VMIN 0 + +#define POWER_BUTTON_SHUTDOWN 0 + +#define ACPI_IRQ 10 /* XXX: hardcoded interrupt */ +#define ACPI_NAME "sci" +#define ACPI_MAGIC 0xc0b7ac21 + +#define SUPERIO_EVENT 0xff +#define OSB4_EVENT 0x40 +#define OSB4_INDEX_PORT SERVERWORKS_ACPI_INDEX_PORT +#define OSB4_DATA_PORT SERVERWORKS_ACPI_DATA_PORT + +#define GEN_ACPI_TMR_STS (0x1 << 0) +#define GEN_ACPI_BM_STS (0x1 << 4) +#define GEN_ACPI_GBL_STS (0x1 << 5) +#define GEN_ACPI_PWRBTN_STS (0x1 << 8) +#define GEN_ACPI_SLPBTN_STS (0x1 << 9) +#define GEN_ACPI_RTC_STS (0x1 << 10) +#define GEN_ACPI_WAK_STS (0x1 << 15) + +#ifdef CONFIG_COBALT_EMU_ACPI +static int cobalt_acpi_setup_proc(void); +static int cobalt_acpi_open_event(struct inode *inode, struct file *file); +static int cobalt_acpi_close_event(struct inode *inode, struct file *file); +static ssize_t cobalt_acpi_read_event(struct file *file, char *buf, + size_t count, loff_t *ppos); +static unsigned int cobalt_acpi_poll_event(struct file *file, poll_table *wait); +#endif + + + +typedef struct +{ + u16 hw_type; + cobalt_acpi_hw_handler hw_handler; + cobalt_acpi_enable_handler en_handler; + void *data; + struct list_head link; +} hw_handler_datum; + +typedef struct +{ + u16 hw_type; + u16 table_len; + u16 *table; + struct list_head link; +} trans_table_datum; + +typedef struct +{ + cobalt_acpi_evt_handler handler; + u16 ev_type; + void *data; + struct list_head link; +} evt_handler_datum; + +typedef struct +{ + cobalt_acpi_evt evt; + struct list_head link; +} evt_list_datum; + +static LIST_HEAD( hw_handler_list ); +static spinlock_t hw_handler_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD( trans_table_list ); +static spinlock_t trans_table_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD( evt_handler_list ); +static spinlock_t evt_handler_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD( dispatch_queue ); +static spinlock_t dispatch_queue_lock = SPIN_LOCK_UNLOCKED; + +typedef struct +{ + u16 hw_type; + + /* block lengths */ + u16 pm1_evt_len; + u16 pm1_cnt_len; + u16 pm2_cnt_len; + u16 pm_tmr_len; + u16 gpe0_len; + u16 gpe1_len; + + /* block I/O locations */ + u16 pm1a_evt_blk; + u16 pm1b_evt_blk; + u16 pm1a_cnt_blk; + u16 pm1b_cnt_blk; + u16 pm2_cnt_blk; + u16 pm_tmr_blk; + u16 p_blk; + u16 gpe0_blk; + u16 gpe1_blk; + + /* ponters to strings for the io names */ + char *pm1a_evt_nam; + char *pm1b_evt_nam; + char *pm1a_cnt_nam; + char *pm1b_cnt_nam; + char *pm2_cnt_nam; + char *pm_tmr_nam; + char *p_nam; + char *gpe0_nam; + char *gpe1_nam; + + /* reference counts for events */ + atomic_t tmr_ref_cnt; + atomic_t bm_ref_cnt; + atomic_t gbl_ref_cnt; + atomic_t pwrbtn_ref_cnt; + atomic_t slpbtn_ref_cnt; + atomic_t rtc_ref_cnt; + atomic_t wak_ref_cnt; + atomic_t *gpe_ref_cnt; + + +} generic_acpi_regions; + + +static void cobalt_acpi_enable_event( u16 ev_type, int en ); +static void cobalt_acpi_run_enable_handler( u16 hw_type, u16 ev_type, + u16 ev_data, int en); +static int cobalt_acpi_apply_evt_handlers( evt_list_datum *d ); +static int cobalt_acpi_run_dispatch_queue( void ); +static irqreturn_t acpi_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void cobalt_acpi_cleanup( void ); + +static int register_acpi_regions( generic_acpi_regions *regions, char * subsys_name ); +static int unregister_acpi_regions( generic_acpi_regions *regions ); +static void cobalt_acpi_handle_pm1_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ); +static void cobalt_acpi_handle_gpe_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ); +static int cobalt_acpi_generic_hw_handler( int irq, void *dev_id, + struct pt_regs *regs, void * data ); + +static int cobalt_acpi_osb4_init( void ); +static int cobalt_acpi_osb4_cleanup( void ); +static int get_osb4_regions( generic_acpi_regions *regions); + +static int cobalt_acpi_csb5_init( void ); +static int cobalt_acpi_csb5_cleanup( void ); +static int get_csb5_regions( generic_acpi_regions *regions); + +static int cobalt_acpi_pc8731x_init( void ); +static int cobalt_acpi_pc8731x_cleanup( void ); +static int get_pc8731x_regions( generic_acpi_regions *regions ); + +static int cobalt_acpi_pc8741x_init( void ); +static int cobalt_acpi_pc8741x_cleanup( void ); +static int get_pc8741x_regions( generic_acpi_regions *regions ); + +static int cobalt_acpi_monterey_init( void ); +static int cobalt_acpi_monterey_cleanup( void ); + +static int cobalt_acpi_alpine_init( void ); +static int cobalt_acpi_alpine_cleanup( void ); + +static __inline__ struct list_head *list_pop( struct list_head *head ) +{ + struct list_head *e; + + if( list_empty( head ) ) + return NULL; + + e = head->next; + list_del( e ); + return e; +} + +static __inline__ u16 get_reg(u16 index, u16 data, u8 port) +{ + u16 reg; + + outb(port, index); + reg = inb(data); + outb(port + 1, index); + reg |= inb(data) << 8; + return reg; +} + +/* + * + * Main ACPI Subsystem Code + * + */ + +extern int cobalt_acpi_register_hw_handler( u16 hw_type, + cobalt_acpi_hw_handler hw_handler, + cobalt_acpi_enable_handler en_handler, + void *data ) +{ + hw_handler_datum *d; + unsigned long flags; + + if( ! (d = (hw_handler_datum *) kmalloc( sizeof( hw_handler_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + d->hw_type = hw_type; + d->hw_handler = hw_handler; + d->en_handler = en_handler; + d->data = data; + + spin_lock_irqsave( &hw_handler_list_lock, flags ); + list_add( &(d->link), &hw_handler_list ); + spin_unlock_irqrestore( &hw_handler_list_lock, flags ); + + return 0; +} + +extern int cobalt_acpi_unregister_hw_handler( cobalt_acpi_hw_handler handler ) +{ + struct list_head *pos; + unsigned long flags; + + spin_lock_irqsave( &hw_handler_list_lock, flags ); + list_for_each( pos, &hw_handler_list ) + { + if( list_entry( pos, hw_handler_datum, link )->hw_handler == handler ) + { + list_del( pos ); + spin_unlock_irqrestore( &hw_handler_list_lock, flags ); + + kfree( list_entry( pos, hw_handler_datum, link ) ); + return 0; + } + + }; + + spin_unlock_irqrestore( &hw_handler_list_lock, flags ); + return -1; +} + +extern int cobalt_acpi_register_trans_table( u16 hw_type, u16 table_len, u16 *table ) +{ + trans_table_datum *d; + unsigned long flags; + + if( ! (d = (trans_table_datum *) kmalloc( sizeof( trans_table_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + d->hw_type = hw_type; + d->table_len = table_len; + d->table = table; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_add( &(d->link), &trans_table_list ); + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + + return 0; +} + +extern int cobalt_acpi_unregister_trans_table( u16 hw_type ) +{ + struct list_head *pos; + unsigned long flags; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_for_each( pos, &trans_table_list ) + { + if( list_entry( pos, trans_table_datum, link )->hw_type == hw_type ) + { + list_del( pos ); + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + + kfree( list_entry( pos, trans_table_datum, link ) ); + return 0; + } + + }; + + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + return -1; +} + +extern int cobalt_acpi_register_evt_handler( cobalt_acpi_evt_handler handler, + u16 ev_type, + void *data ) +{ + evt_handler_datum *d; + unsigned long flags; + + if( ! (d = (evt_handler_datum *) kmalloc( sizeof( evt_handler_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + d->handler = handler; + d->data = data; + d->ev_type = ev_type; + + spin_lock_irqsave( &evt_handler_list_lock, flags ); + list_add( &(d->link), &evt_handler_list ); + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + + cobalt_acpi_enable_event( ev_type, 1 ); + + return 0; +} + +extern int cobalt_acpi_unregister_evt_handler( cobalt_acpi_evt_handler handler ) +{ + struct list_head *pos; + unsigned long flags; + + + spin_lock_irqsave( &evt_handler_list_lock, flags ); + list_for_each( pos, &evt_handler_list ) + { + if( list_entry( pos, evt_handler_datum, link )->handler == handler ) + { + list_del( pos ); + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + + cobalt_acpi_enable_event( list_entry( pos, + evt_handler_datum, + link )->ev_type, 0 ); + + kfree( list_entry( pos, evt_handler_datum, link ) ); + return 0; + } + + }; + + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + return -EINVAL; +} + +static void cobalt_acpi_enable_event( u16 ev_type, int en ) +{ + if( ev_type >= 0x8000 ) + { + struct list_head *pos; + trans_table_datum *d; + int i; + unsigned long flags; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_for_each( pos, &trans_table_list ) + { + d = list_entry( pos, trans_table_datum, link ); + for( i=0 ; itable_len ; i++ ) + { + if( d->table[i] == ev_type ) + { + cobalt_acpi_run_enable_handler( d->hw_type, + COBALT_ACPI_EVT_GPE, + i, en ); + } + } + } + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + } + else + cobalt_acpi_run_enable_handler( COBALT_ACPI_HW_ANY, ev_type, 0, en); +} + +static void cobalt_acpi_run_enable_handler( u16 hw_type, u16 ev_type, + u16 ev_data, int en) +{ + struct list_head *pos; + unsigned long flags; + hw_handler_datum *d; + + spin_lock_irqsave(&hw_handler_list_lock, flags); + list_for_each( pos, &hw_handler_list ) + { + d = list_entry( pos, hw_handler_datum, link ); + if( (!hw_type) || (d->hw_type == hw_type) ) + d->en_handler( ev_type, ev_data, en, d->data ); + } + spin_unlock_irqrestore(&hw_handler_list_lock, flags); + +} + +static int cobalt_acpi_translate_event( cobalt_acpi_evt *evt ) +{ + struct list_head *pos; + unsigned long flags; + trans_table_datum *d; + + if( evt->ev_type != COBALT_ACPI_EVT_GPE ) + return 0; + + spin_lock_irqsave( &trans_table_list_lock, flags ); + list_for_each( pos, &trans_table_list ) + { + d = list_entry( pos, trans_table_datum, link ); + if( d->hw_type == evt->hw_type ) + { + if( evt->ev_data >= d->table_len ) + goto err_out; + + if( d->table[ evt->ev_data ] != COBALT_ACPI_EVT_NONE ) + { + evt->ev_type = d->table[ evt->ev_data ]; + evt->ev_data = 0; + } + + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + return 0; + } + } + + err_out: + spin_unlock_irqrestore( &trans_table_list_lock, flags ); + return -1; +} + +extern int cobalt_acpi_post_event( cobalt_acpi_evt evt ) +{ + evt_list_datum *d; + unsigned long flags; + + if( ! (d = (evt_list_datum *) kmalloc( sizeof( evt_handler_datum ), GFP_ATOMIC )) ) + return -ENOMEM; + + + cobalt_acpi_translate_event( &evt ); + + memcpy( &(d->evt), &evt, sizeof(evt) ); + + spin_lock_irqsave( &dispatch_queue_lock, flags ); + list_add_tail( &(d->link), &dispatch_queue ); + spin_unlock_irqrestore( &dispatch_queue_lock, flags ); + + return 0; +} + +static int cobalt_acpi_apply_evt_handlers( evt_list_datum *d ) +{ + struct list_head *pos; + evt_handler_datum *evt_h; + int ret,err = 0; + unsigned long flags; + + spin_lock_irqsave( &evt_handler_list_lock, flags ); + list_for_each( pos, &evt_handler_list ) + { + evt_h = list_entry( pos, evt_handler_datum, link ); + if( (! evt_h->ev_type) || (evt_h->ev_type == d->evt.ev_type) ) + { + if( (ret = evt_h->handler( &d->evt, evt_h->data )) < 0 ) + err = ret; + } + } + spin_unlock_irqrestore( &evt_handler_list_lock, flags ); + + return err; +} + +static int cobalt_acpi_run_dispatch_queue( void ) +{ + struct list_head *pos; + int ret; + int err=0; + evt_list_datum *d; + unsigned long flags; + + spin_lock_irqsave( &dispatch_queue_lock, flags ); + while( (pos = list_pop( &dispatch_queue )) ) + { + d = list_entry( pos, evt_list_datum, link ); + if( (ret = cobalt_acpi_apply_evt_handlers( d )) < 0 ) + err = ret; +#ifdef CONFIG_COBALT_EMU_ACPI + cobalt_acpi_generate_proc_evt( &d->evt ); +#endif + kfree( d ); + } + spin_unlock_irqrestore( &dispatch_queue_lock, flags ); + + return err; +} + +static irqreturn_t acpi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct list_head *pos; + hw_handler_datum *d; + int ret=0, err=0; + unsigned long flags; + + spin_lock_irqsave(&hw_handler_list_lock, flags); + list_for_each( pos, &hw_handler_list ) + { + d = list_entry( pos, hw_handler_datum, link ); + if( (ret = d->hw_handler( irq, dev_id, regs, d->data )) < 0 ) + err = ret; + + } + spin_unlock_irqrestore(&hw_handler_list_lock, flags); + + if( (err = cobalt_acpi_run_dispatch_queue()) < 0 ) + err = ret; + + if( err ) + EPRINTK( "error at interrupt time of type %d.\n", err ); + + return IRQ_HANDLED; +} + + + + +int __init cobalt_acpi_init(void) +{ + int err; + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", ACPI_DRIVER,ACPI_DRIVER_VMAJ,ACPI_DRIVER_VMIN); + + if( cobt_is_monterey() ) + cobalt_acpi_monterey_init(); + else if( cobt_is_alpine() ) + cobalt_acpi_alpine_init(); + + if( cobt_is_5k() ) + { + if( pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL ) ) + { + if( (err = cobalt_acpi_osb4_init()) < 0 ) + { + goto cleanup; + } + } + + if( pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL ) ) + { + if( (err = cobalt_acpi_csb5_init()) < 0 ) + { + goto cleanup; + } + } + + switch( superio_type() ) + { + case SIO_TYPE_PC8731X: + if( (err = cobalt_acpi_pc8731x_init()) ) + { + goto cleanup; + } + break; + + case SIO_TYPE_PC8741X: + if( (err = cobalt_acpi_pc8741x_init()) ) + { + goto cleanup; + } + break; + + case SIO_TYPE_UNKNOWN: + EPRINTK("unknown superio type\n"); + break; + } + + /* setup an interrupt handler for an ACPI SCI */ + err = request_irq(ACPI_IRQ, acpi_interrupt, + SA_SHIRQ, ACPI_NAME, (void *)ACPI_MAGIC); + if (err) { + EPRINTK("can't assign ACPI IRQ (%d)\n", ACPI_IRQ); + return err; + } + +#ifdef CONFIG_COBALT_EMU_ACPI + cobalt_acpi_setup_proc(); +#endif + } + + /* enable some events we may want */ + cobalt_acpi_enable_event( COBALT_ACPI_EVT_PWRBTN, 1 ); + + return 0; + + cleanup: + cobalt_acpi_cleanup(); + return err; +} + +static void cobalt_acpi_cleanup( void ) +{ + cobalt_acpi_osb4_cleanup(); + cobalt_acpi_csb5_cleanup(); + cobalt_acpi_pc8731x_cleanup(); + cobalt_acpi_pc8741x_cleanup(); + + if( cobt_is_monterey() ) + cobalt_acpi_monterey_cleanup(); + if( cobt_is_alpine() ) + cobalt_acpi_alpine_cleanup(); +} + +/* + * + * Generic ACPI HW Support + * + */ + +static __inline__ char *region_name( char * subsys_name, char * blk_name ) +{ + char * new_name; + + if( !( new_name = (char *) kmalloc( strlen(subsys_name) + strlen(blk_name) + 14, + GFP_ATOMIC)) ) + return NULL; + + sprintf( new_name, "%s (%s)", subsys_name, blk_name ); + return new_name; +} + +static void free_region_names( generic_acpi_regions *regions ) +{ + if( regions->pm1a_evt_nam ) + kfree( regions->pm1a_evt_nam ); + + if( regions->pm1b_evt_nam ) + kfree( regions->pm1b_evt_nam ); + + if( regions->pm1a_cnt_nam ) + kfree( regions->pm1a_cnt_nam ); + + if( regions->pm1b_cnt_nam ) + kfree( regions->pm1b_cnt_nam ); + + if( regions->pm2_cnt_nam ) + kfree( regions->pm2_cnt_nam ); + + if( regions->pm_tmr_nam ) + kfree( regions->pm_tmr_nam ); + + if( regions->p_nam ) + kfree( regions->p_nam ); + + if( regions->gpe0_nam ) + kfree( regions->gpe0_nam ); + + if( regions->gpe1_nam ) + kfree( regions->gpe1_nam ); +} + +static int register_acpi_regions( generic_acpi_regions *regions, char * subsys_name ) +{ + int i; + + if( regions->pm1a_evt_blk && regions->pm1_evt_len ) + { + if( !(regions->pm1a_evt_nam = region_name( subsys_name, "pm1a_evt_blk" )) ) + goto cleanup0; + + if( !request_region( regions->pm1a_evt_blk, regions->pm1_evt_len, + regions->pm1a_evt_nam ) ) + goto cleanup0; + } + + if( regions->pm1b_evt_blk && regions->pm1_evt_len ) + { + if( !(regions->pm1b_evt_nam = region_name( subsys_name, "pm1b_evt_blk" )) ) + goto cleanup0; + + if( !request_region( regions->pm1b_evt_blk, regions->pm1_evt_len, + regions->pm1b_evt_nam) ) + goto cleanup1; + } + + if( regions->pm1a_cnt_blk && regions->pm1_cnt_len ) + { + if( !(regions->pm1a_cnt_nam = region_name( subsys_name, "pm1a_cnt_blk" )) ) + goto cleanup1; + + if( !request_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len, + regions->pm1a_cnt_nam ) ) + goto cleanup2; + } + + if( regions->pm1b_cnt_blk && regions->pm1_cnt_len ) + { + if( !(regions->pm1b_cnt_nam = region_name( subsys_name, "pm1b_cnt_blk" )) ) + goto cleanup2; + + if( !request_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len, + regions->pm1b_cnt_nam ) ) + goto cleanup3; + } + + if( regions->pm2_cnt_blk && regions->pm2_cnt_len ) + { + if( !(regions->pm2_cnt_nam = region_name( subsys_name, "pm2_cnt_blk" )) ) + goto cleanup3; + + if( !request_region( regions->pm2_cnt_blk, regions->pm2_cnt_len, + regions->pm2_cnt_nam ) ) + goto cleanup4; + } + + if( regions->pm_tmr_blk && regions->pm_tmr_len ) + { + if( !(regions->pm_tmr_nam = region_name( subsys_name, "pm_tmp_blk" )) ) + goto cleanup4; + + if( !request_region( regions->pm_tmr_blk, regions->pm_tmr_len, + regions->pm_tmr_nam ) ) + goto cleanup5; + } + + if( regions->p_blk ) + { + if( !(regions->p_nam = region_name( subsys_name, "p_blk" )) ) + goto cleanup5; + + if( !request_region( regions->p_blk, 6, regions->p_nam ) ) + goto cleanup6; + } + + if( regions->gpe0_blk && regions->gpe0_len ) + { + if( !(regions->gpe0_nam = region_name( subsys_name, "gpe0_blk" )) ) + goto cleanup6; + + if( !request_region( regions->gpe0_blk, regions->gpe0_len, + regions->gpe0_nam ) ) + goto cleanup7; + } + + if( regions->gpe1_blk && regions->gpe1_len ) + { + if( !(regions->gpe1_nam = region_name( subsys_name, "gpe1_blk" )) ) + goto cleanup7; + + if( !request_region( regions->gpe1_blk, regions->gpe1_len, + regions->gpe1_nam ) ) + goto cleanup8; + } + + if( (regions->gpe_ref_cnt = (atomic_t *) kmalloc( sizeof( atomic_t ) * + regions->gpe0_len * 8, + GFP_ATOMIC)) == NULL ) + goto cleanup9; + + memset( regions->gpe_ref_cnt, 0x0, sizeof( atomic_t ) * regions->gpe0_len * 8 ); + + /* disable all events and ack them */ + if( regions->pm1a_evt_blk ) + { + outw( 0x0000, regions->pm1a_evt_blk + regions->pm1_evt_len/2 ); + outw( 0xffff, regions->pm1a_evt_blk ); + } + + if( regions->pm1b_evt_blk ) + { + outw( 0x0000, regions->pm1b_evt_blk + regions->pm1_evt_len/2 ); + outw( 0xffff, regions->pm1b_evt_blk ); + } + + if( regions->gpe0_blk ) + { + for( i=0 ; i<(regions->gpe0_len/2) ; i++ ) + { + outb( 0x00, regions->gpe0_blk + regions->gpe0_len/2 + i ); + outb( 0xff, regions->gpe0_blk + i ); + } + } + + if( regions->gpe1_blk ) + { + for( i=0 ; i<(regions->gpe1_len/2) ; i++ ) + { + outb( 0x00, regions->gpe1_blk + regions->gpe1_len/2 + i ); + outb( 0xff, regions->gpe1_blk + i ); + } + } + + return 0; + + cleanup9: + if( regions->gpe1_blk ) + { + release_region( regions->gpe1_blk, regions->gpe1_len ); + regions->gpe1_blk = 0; + } + + cleanup8: + if( regions->gpe0_blk ) + { + release_region( regions->gpe0_blk, regions->gpe0_len ); + regions->gpe0_blk = 0; + } + + cleanup7: + if( regions->p_blk ) + { + release_region( regions->p_blk, 6 ); + regions->p_blk = 0; + } + + cleanup6: + if( regions->pm_tmr_blk ) + { + release_region( regions->pm_tmr_blk, regions->pm_tmr_len ); + regions->pm_tmr_blk = 0; + } + + cleanup5: + if( regions->pm2_cnt_blk ) + { + release_region( regions->pm2_cnt_blk, regions->pm2_cnt_len ); + regions->pm2_cnt_blk = 0; + } + + cleanup4: + if( regions->pm1b_cnt_blk ) + { + release_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len ); + regions->pm1b_cnt_blk = 0; + } + + cleanup3: + if( regions->pm1a_cnt_blk ) + { + release_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len ); + regions->pm1a_cnt_blk = 0; + } + + cleanup2: + if( regions->pm1b_evt_blk ) + { + release_region( regions->pm1b_evt_blk, regions->pm1_evt_len ); + regions->pm1b_evt_blk = 0; + } + + cleanup1: + if( regions->pm1a_evt_blk ) + { + release_region( regions->pm1a_evt_blk, regions->pm1_evt_len ); + regions->pm1a_evt_blk = 0; + } + + cleanup0: + free_region_names( regions ); + + return -EBUSY; +} + +static int unregister_acpi_regions( generic_acpi_regions *regions ) +{ + if( regions->pm1a_evt_blk && regions->pm1_evt_len ) + { + release_region( regions->pm1a_evt_blk, regions->pm1_evt_len ); + regions->pm1a_evt_blk = 0; + } + + if( regions->pm1b_evt_blk && regions->pm1_evt_len ) + { + release_region( regions->pm1b_evt_blk, regions->pm1_evt_len ); + regions->pm1b_evt_blk = 0; + } + + if( regions->pm1a_cnt_blk && regions->pm1_cnt_len ) + { + release_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len ); + regions->pm1a_cnt_blk = 0; + } + + if( regions->pm1b_cnt_blk && regions->pm1_cnt_len ) + { + release_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len ); + regions->pm1b_cnt_blk = 0; + } + + if( regions->pm2_cnt_blk && regions->pm2_cnt_len ) + { + release_region( regions->pm2_cnt_blk, regions->pm2_cnt_len ); + regions->pm2_cnt_blk = 0; + } + + if( regions->pm_tmr_blk && regions->pm_tmr_len ) + { + release_region( regions->pm_tmr_blk, regions->pm_tmr_len ); + regions->pm_tmr_blk = 0; + } + + if( regions->p_blk ) + { + release_region( regions->p_blk, 6 ); + regions->p_blk = 0; + } + + if( regions->gpe0_blk && regions->gpe0_len ) + { + release_region( regions->gpe0_blk, regions->gpe0_len ); + regions->gpe0_blk = 0; + } + + if( regions->gpe1_blk && regions->gpe1_len ) + { + release_region( regions->gpe1_blk, regions->gpe1_len ); + regions->gpe1_blk = 0; + } + + if( regions->gpe_ref_cnt ) + kfree( regions->gpe_ref_cnt ); + + free_region_names( regions ); + + return 0; +} + +static void cobalt_acpi_handle_pm1_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ) +{ + cobalt_acpi_evt evt; + u16 sts, en; + + evt.hw_type = regions->hw_type; + + if( (sts = inw( io_addr )) && + (en = inw( io_addr + len/2 )) ) + { + + + /* clear status bits */ + outw( sts, io_addr); + + if( (en & GEN_ACPI_TMR_STS) && + (sts & GEN_ACPI_TMR_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_TMR; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_BM_STS) && + (sts & GEN_ACPI_BM_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_BM; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_GBL_STS) && + (sts & GEN_ACPI_GBL_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_GBL; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_PWRBTN_STS) && + (sts & GEN_ACPI_PWRBTN_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_PWRBTN; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_SLPBTN_STS) && + (sts & GEN_ACPI_SLPBTN_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_SLPBTN; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (en & GEN_ACPI_RTC_STS) && + (sts & GEN_ACPI_RTC_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_RTC; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + if( (sts & GEN_ACPI_WAK_STS) ) + { + evt.ev_type = COBALT_ACPI_EVT_WAK; + evt.ev_data = 0x0; + cobalt_acpi_post_event( evt ); + } + } +} + +static void cobalt_acpi_handle_gpe_blk( u16 io_addr, u16 len, + generic_acpi_regions * regions ) +{ + cobalt_acpi_evt evt; + int i,j; + u8 sts, en; + + evt.hw_type = regions->hw_type; + evt.ev_type = COBALT_ACPI_EVT_GPE; + + for( i=0 ; i<(len/2) ; i++ ) + { + sts = inb( io_addr + i ); + en = inb( io_addr + len/2 + i ); + + /* clear status bits */ + outb( sts, io_addr); + + for( j=0 ; j<8 ; j++ ) + { + if( (en & 0x1) && + (sts & 0x1) ) + { + evt.ev_data = i*8 + j; + cobalt_acpi_post_event( evt ); + } + en >>= 1; + sts >>= 1; + } + } +} + +static int cobalt_acpi_generic_hw_handler( int irq, void *dev_id, + struct pt_regs *regs, void * data ) +{ + generic_acpi_regions * regions = (generic_acpi_regions *) data; + cobalt_acpi_evt evt; + + evt.hw_type = regions->hw_type; + + /* various PM events */ + if( regions->pm1a_evt_blk ) + cobalt_acpi_handle_pm1_blk( regions->pm1a_evt_blk, regions->pm1_evt_len, regions ); + + if( regions->pm1b_evt_blk ) + cobalt_acpi_handle_pm1_blk( regions->pm1b_evt_blk, regions->pm1_evt_len, regions ); + + if( regions->gpe0_blk ) + cobalt_acpi_handle_gpe_blk( regions->gpe0_blk, regions->gpe0_len, regions ); + + if( regions->gpe1_blk ) + cobalt_acpi_handle_gpe_blk( regions->gpe1_blk, regions->gpe1_len, regions ); + + + return 0; +} + +static int cobalt_acpi_generic_en_handler( u16 ev_type, u16 ev_data, int en, void *data ) +{ + generic_acpi_regions * regions = (generic_acpi_regions *) data; + int block, offset; + u8 data8; + u16 data16; + + switch( ev_type ) + { + case COBALT_ACPI_EVT_TMR: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_TMR_STS; + atomic_inc( ®ions->tmr_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->tmr_ref_cnt ) ) + data16 &= ~GEN_ACPI_TMR_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_BM: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_BM_STS; + atomic_inc( ®ions->bm_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->bm_ref_cnt ) ) + data16 &= ~GEN_ACPI_BM_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_GBL: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_GBL_STS; + atomic_inc( ®ions->gbl_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->gbl_ref_cnt ) ) + data16 &= ~GEN_ACPI_GBL_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_PWRBTN: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_PWRBTN_STS; + atomic_inc( ®ions->pwrbtn_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->pwrbtn_ref_cnt ) ) + data16 &= ~GEN_ACPI_PWRBTN_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_SLPBTN: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_SLPBTN_STS; + atomic_inc( ®ions->slpbtn_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->slpbtn_ref_cnt ) ) + data16 &= ~GEN_ACPI_SLPBTN_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_RTC: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_RTC_STS; + atomic_inc( ®ions->rtc_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->rtc_ref_cnt ) ) + data16 &= ~GEN_ACPI_RTC_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_WAK: + data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + + if( en ) + { + data16 |= GEN_ACPI_WAK_STS; + atomic_inc( ®ions->wak_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->wak_ref_cnt ) ) + data16 &= ~GEN_ACPI_WAK_STS; + } + outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) ); + break; + + case COBALT_ACPI_EVT_GPE: + if( (ev_data/8) >= (regions->gpe0_len / 2) ) + return -EINVAL; + + block = ev_data / 8; + offset = ev_data % 8; + + data8 = inb( regions->gpe0_blk + (regions->gpe0_len / 2) + block ); + + if( en ) + { + data8 |= 0x1 << offset; + atomic_inc( ®ions->gpe_ref_cnt[ev_data] ); + } + else + { + if( atomic_dec_and_test( ®ions->gpe_ref_cnt[ev_data] ) ) + data8 &= ~( 0x1 << offset ); + } + + outb( data8, regions->gpe0_blk + (regions->gpe0_len / 2) + block ); + + break; + + default: + return -EINVAL; + + } + + return 0; +} + +/* + * + * Generic ServerWorks region code + * + */ + +static int get_serverworks_regions( generic_acpi_regions *regions, u16 type ) +{ + int reg; + + memset( regions, 0x0, sizeof( *regions ) ); + + regions->hw_type = type; + + regions->pm1_evt_len = 4; + regions->pm1_cnt_len = 2; + regions->pm_tmr_len = 4; + regions->gpe0_len = 8; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x20)) ) + regions->pm1a_evt_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x22)) ) + regions->pm1a_cnt_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x24)) ) + regions->pm_tmr_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x26)) ) + regions->p_blk = (u16) reg; + + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x28)) ) + regions->gpe0_blk = (u16) reg; + + if( type == COBALT_ACPI_HW_OSB4 ) + { + regions->pm2_cnt_len = 1; + if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x2E)) ) + regions->pm2_cnt_blk = (u16) reg; + } + + switch( type ) + { + case COBALT_ACPI_HW_OSB4: + return register_acpi_regions( regions, "OSB4" ); + + case COBALT_ACPI_HW_CSB5: + return register_acpi_regions( regions, "CSB5" ); + } + + return -EINVAL; + +} + +/* + * + * ServerWorks OSB4 + * + */ + +static generic_acpi_regions osb4_regions; + +static int cobalt_acpi_osb4_init( void ) +{ + int err; + + if( (err = get_osb4_regions( &osb4_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_OSB4, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &osb4_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_osb4_cleanup( void ) +{ + unregister_acpi_regions( &osb4_regions ); + return 0; +} + +static int get_osb4_regions( generic_acpi_regions *regions) +{ + return get_serverworks_regions( regions, COBALT_ACPI_HW_OSB4 ); +} + +/* + * + * ServerWorks CSB5 + * + */ + +/* static generic_acpi_regions csb5_regions; */ + +static generic_acpi_regions csb5_regions; + +static int cobalt_acpi_csb5_init( void ) +{ + int err; + + if( (err = get_csb5_regions( &csb5_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_CSB5, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &csb5_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_csb5_cleanup( void ) +{ + unregister_acpi_regions( &csb5_regions ); + return 0; +} + +static int get_csb5_regions( generic_acpi_regions *regions) +{ + return get_serverworks_regions( regions, COBALT_ACPI_HW_CSB5 ); +} + +/* + * + * NatSemi PC8731x + * + */ +static generic_acpi_regions pc8731x_regions; + +static int cobalt_acpi_pc8731x_init( void ) +{ + int err; + + if( (err = get_pc8731x_regions( &pc8731x_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_PC8731X, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &pc8731x_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_pc8731x_cleanup( void ) +{ + unregister_acpi_regions( &pc8731x_regions ); + return 0; +} + +static int get_pc8731x_regions( generic_acpi_regions *regions ) +{ + int reg; + u16 addr; + + memset( regions, 0x0, sizeof( *regions ) ); + + regions->hw_type = COBALT_ACPI_HW_PC8731X; + + regions->pm1_evt_len = 4; + regions->pm1_cnt_len = 2; + regions->pm_tmr_len = 4; + regions->gpe0_len = 4; + + /* superi/o -- select pm logical device and get base address */ + addr = superio_ldev_base(PC87317_DEV_PM); + if( addr ) + { + /* get registers */ + if( (reg = get_reg(addr, addr + 1, 0x08)) ) + regions->pm1a_evt_blk = reg; + + if( (reg = get_reg(addr, addr + 1, 0x0a)) ) + regions->pm_tmr_blk = reg; + + if( (reg = get_reg(addr, addr + 1, 0x0c)) ) + regions->pm1a_cnt_blk = reg; + + if( (reg = get_reg(addr, addr + 1, 0x0e)) ) + regions->gpe0_blk = reg; + } + + return register_acpi_regions( regions, "pc8731x" ); +} + +/* + * + * NatSemi PC8741x + * + */ + +static generic_acpi_regions pc8741x_regions; + +static int cobalt_acpi_pc8741x_init( void ) +{ + int err; + + if( (err = get_pc8741x_regions( &pc8741x_regions )) < 0 ) + return err; + + if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_PC8741X, + cobalt_acpi_generic_hw_handler, + cobalt_acpi_generic_en_handler, + &pc8741x_regions )) < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_pc8741x_cleanup( void ) +{ + unregister_acpi_regions( &pc8741x_regions ); + return 0; +} + +static int get_pc8741x_regions( generic_acpi_regions *regions ) +{ + int reg; + + memset( regions, 0x0, sizeof( *regions ) ); + + regions->hw_type = COBALT_ACPI_HW_PC8741X; + + regions->pm1_evt_len = 4; + regions->pm1_cnt_len = 2; + regions->pm_tmr_len = 4; + regions->gpe0_len = 8; + + /* get registers */ + if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 1)) ) + regions->pm1a_evt_blk = reg; + + if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 2)) ) + regions->pm1a_cnt_blk = reg; + + if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 3)) ) + regions->gpe0_blk = reg; + + return register_acpi_regions( regions, "pc8741x" ); +} + +/* + * + * Platform support + * + */ + +/* + * + * Monterey + * + */ + +static u16 cobalt_acpi_monterey_osb4_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_NONE, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_NONE, +/* GPE 6 */ COBALT_ACPI_EVT_SLED, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE }; + +static u16 cobalt_acpi_monterey_superio_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_NONE, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_NONE, +/* GPE 6 */ COBALT_ACPI_EVT_NONE, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE, +/* GPE 16 */ COBALT_ACPI_EVT_NONE, +/* GPE 17 */ COBALT_ACPI_EVT_NONE, +/* GPE 18 */ COBALT_ACPI_EVT_NONE, +/* GPE 19 */ COBALT_ACPI_EVT_NONE, +/* GPE 20 */ COBALT_ACPI_EVT_NONE, +/* GPE 21 */ COBALT_ACPI_EVT_NONE, +/* GPE 22 */ COBALT_ACPI_EVT_NONE, +/* GPE 23 */ COBALT_ACPI_EVT_NONE, +/* GPE 24 */ COBALT_ACPI_EVT_NONE, +/* GPE 25 */ COBALT_ACPI_EVT_NONE, +/* GPE 26 */ COBALT_ACPI_EVT_NONE, +/* GPE 27 */ COBALT_ACPI_EVT_NONE, +/* GPE 28 */ COBALT_ACPI_EVT_NONE, +/* GPE 29 */ COBALT_ACPI_EVT_NONE, +/* GPE 30 */ COBALT_ACPI_EVT_NONE, +/* GPE 31 */ COBALT_ACPI_EVT_NONE }; + +static int cobalt_acpi_monterey_init( void ) +{ + int err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_OSB4, + sizeof( cobalt_acpi_monterey_osb4_table )/sizeof( u16 ), + cobalt_acpi_monterey_osb4_table ); + if( err < 0 ) + return err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_PC8731X, + sizeof( cobalt_acpi_monterey_superio_table )/sizeof( u16 ), + cobalt_acpi_monterey_superio_table ); + if( err < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_monterey_cleanup( void ) +{ + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_OSB4 ); + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_PC8731X ); + + return 0; +} + +/* + * + * Alpine + * + */ + +static u16 cobalt_acpi_alpine_csb5_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_FAN, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_SM_INT, +/* GPE 6 */ COBALT_ACPI_EVT_THERM, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE }; + +static u16 cobalt_acpi_alpine_superio_table[] = { +/* GPE 0 */ COBALT_ACPI_EVT_NONE, +/* GPE 1 */ COBALT_ACPI_EVT_NONE, +/* GPE 2 */ COBALT_ACPI_EVT_NONE, +/* GPE 3 */ COBALT_ACPI_EVT_NONE, +/* GPE 4 */ COBALT_ACPI_EVT_NONE, +/* GPE 5 */ COBALT_ACPI_EVT_NONE, +/* GPE 6 */ COBALT_ACPI_EVT_NONE, +/* GPE 7 */ COBALT_ACPI_EVT_NONE, +/* GPE 8 */ COBALT_ACPI_EVT_NONE, +/* GPE 9 */ COBALT_ACPI_EVT_NONE, +/* GPE 10 */ COBALT_ACPI_EVT_NONE, +/* GPE 11 */ COBALT_ACPI_EVT_NONE, +/* GPE 12 */ COBALT_ACPI_EVT_NONE, +/* GPE 13 */ COBALT_ACPI_EVT_NONE, +/* GPE 14 */ COBALT_ACPI_EVT_NONE, +/* GPE 15 */ COBALT_ACPI_EVT_NONE, +/* GPE 16 */ COBALT_ACPI_EVT_NONE, +/* GPE 17 */ COBALT_ACPI_EVT_NONE, +/* GPE 18 */ COBALT_ACPI_EVT_NONE, +/* GPE 19 */ COBALT_ACPI_EVT_NONE, +/* GPE 20 */ COBALT_ACPI_EVT_NONE, +/* GPE 21 */ COBALT_ACPI_EVT_NONE, +/* GPE 22 */ COBALT_ACPI_EVT_NONE, +/* GPE 23 */ COBALT_ACPI_EVT_NONE, +/* GPE 24 */ COBALT_ACPI_EVT_NONE, +/* GPE 25 */ COBALT_ACPI_EVT_NONE, +/* GPE 26 */ COBALT_ACPI_EVT_NONE, +/* GPE 27 */ COBALT_ACPI_EVT_NONE, +/* GPE 28 */ COBALT_ACPI_EVT_NONE, +/* GPE 29 */ COBALT_ACPI_EVT_NONE, +/* GPE 30 */ COBALT_ACPI_EVT_NONE, +/* GPE 31 */ COBALT_ACPI_EVT_NONE }; + +static int cobalt_acpi_alpine_init( void ) +{ + int err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_CSB5, + sizeof( cobalt_acpi_alpine_csb5_table )/sizeof( u16 ), + cobalt_acpi_alpine_csb5_table ); + if( err < 0 ) + return err; + + err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_PC8741X, + sizeof( cobalt_acpi_alpine_superio_table )/sizeof( u16 ), + cobalt_acpi_alpine_superio_table ); + if( err < 0 ) + return err; + + return 0; +} + +static int cobalt_acpi_alpine_cleanup( void ) +{ + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_CSB5 ); + cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_PC8741X ); + + return 0; +} + +/* + * end platform support + */ +#ifdef CONFIG_COBALT_EMU_ACPI +/* + * This is all necessary because we don't have BIOS support for ACPI yet. + * We can fake it here, and when full support is ready just yank this. + */ +typedef struct { + char *device_type; + char *device_instance; + u32 event_type; + u32 event_data; + struct list_head list; +} cobalt_acpi_event_t; + +#define COBALT_ACPI_MAX_STRING_LENGTH 80 + +static LIST_HEAD(cobalt_acpi_event_list); +static DECLARE_WAIT_QUEUE_HEAD(cobalt_acpi_event_wait_queue); +static int event_is_open = 0; +static spinlock_t cobalt_acpi_event_lock = SPIN_LOCK_UNLOCKED; + +static struct proc_dir_entry *cobalt_acpi_proc_root; +static struct proc_dir_entry *cobalt_acpi_proc_event; + +static struct file_operations proc_event_ops = { + open: cobalt_acpi_open_event, + read: cobalt_acpi_read_event, + release: cobalt_acpi_close_event, + poll: cobalt_acpi_poll_event, +}; + +static int +cobalt_acpi_setup_proc(void) +{ + cobalt_acpi_proc_root = proc_mkdir("acpi", NULL); + if (!cobalt_acpi_proc_root) { + return -ENOMEM; + } + + cobalt_acpi_proc_event = create_proc_entry("event", S_IRUSR, + cobalt_acpi_proc_root); + if (!cobalt_acpi_proc_event) { + return -ENOMEM; + } + + cobalt_acpi_proc_event->proc_fops = &proc_event_ops; + + return 0; +} + + +int +cobalt_acpi_generate_proc_evt( cobalt_acpi_evt * evt ) +{ + cobalt_acpi_event_t *event = NULL, *tmp; + unsigned long flags = 0; + char *dev_type; + char *dev_instance; + u32 event_type; + u32 event_data; + struct list_head *pos; + + /* drop event on the floor if no one's listening */ + if (!event_is_open) + return 0; + + event_type = (evt->ev_type << 0x10) | + evt->hw_type; + event_data = evt->ev_data; + + + /* + * Check to see if an event of this type is already + * pending + */ + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + list_for_each( pos, &cobalt_acpi_event_list ) + { + tmp = list_entry(pos, cobalt_acpi_event_t, list); + if( (tmp->event_type == event_type) && + (tmp->event_data == event_data) ) + { + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return 0; + } + + + } + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + + + /* parse the event struct */ + switch( evt->ev_type ) + { + case COBALT_ACPI_EVT_TMR: + dev_type = "generic"; + dev_instance = "timer"; + break; + + case COBALT_ACPI_EVT_BM: + dev_type = "generic"; + dev_instance = "bus-master"; + break; + + case COBALT_ACPI_EVT_GBL: + dev_type = "generic"; + dev_instance = "global"; + break; + + case COBALT_ACPI_EVT_PWRBTN: + dev_type = "button"; + dev_instance = "power"; + break; + + case COBALT_ACPI_EVT_SLPBTN: + dev_type = "button"; + dev_instance = "sleep"; + break; + + case COBALT_ACPI_EVT_RTC: + dev_type = "generic"; + dev_instance = "rtc"; + break; + + case COBALT_ACPI_EVT_WAK: + dev_type = "generic"; + dev_instance = "wake"; + break; + + case COBALT_ACPI_EVT_GPE: + dev_type = "generic"; + dev_instance = "gpe"; + break; + + case COBALT_ACPI_EVT_SLED: + dev_type = "cobalt"; + dev_instance = "sled"; + break; + + case COBALT_ACPI_EVT_THERM: + dev_type = "cobalt"; + dev_instance = "therm_trip"; + break; + + case COBALT_ACPI_EVT_FAN: + dev_type = "cobalt"; + dev_instance = "fan"; + break; + + case COBALT_ACPI_EVT_SM_INT: + dev_type = "cobalt"; + dev_instance = "sm_int"; + break; + + case COBALT_ACPI_EVT_VOLT: + dev_type = "cobalt"; + dev_instance = "volt_trip"; + break; + + default: + dev_type = "unknown"; + dev_instance = "unknown"; + break; + } + + + /* + * Allocate a new event structure. + */ + event = kmalloc(sizeof(*event), GFP_ATOMIC); + if (!event) + goto alloc_error; + + event->device_type=NULL; + event->device_instance=NULL; + + event->device_type = kmalloc(strlen(dev_type) + sizeof(char), + GFP_ATOMIC); + if (!event->device_type) + goto alloc_error; + + event->device_instance = kmalloc(strlen(dev_instance) + sizeof(char), + GFP_ATOMIC ); + if (!event->device_instance) + goto alloc_error; + + /* + * Set event data. + */ + strcpy(event->device_type, dev_type); + strcpy(event->device_instance, dev_instance); + event->event_type = event_type; + event->event_data = event_data; + + /* + * Add to the end of our event list. + */ + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + list_add_tail(&event->list, &cobalt_acpi_event_list); + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + + /* + * Signal waiting threads (if any). + */ + wake_up_interruptible(&cobalt_acpi_event_wait_queue); + + return 0; + +alloc_error: + if(event) + { + if (event->device_instance) + kfree(event->device_instance); + + if (event->device_type) + kfree(event->device_type); + + kfree(event); + } + + return -ENOMEM; +} + + +static int +cobalt_acpi_open_event(struct inode *inode, struct file *file) +{ + unsigned long flags; + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + + if (event_is_open) + goto out_busy; + + event_is_open = 1; + + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return 0; + +out_busy: + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return -EBUSY; +} + + +static int +cobalt_acpi_close_event(struct inode *inode, struct file *file) +{ + unsigned long flags; + struct list_head *pos; + cobalt_acpi_event_t *tmp; + + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + + while( (pos = list_pop( &cobalt_acpi_event_list )) ) + { + tmp = list_entry(pos, cobalt_acpi_event_t, list); + if (tmp->device_instance) + kfree(tmp->device_instance); + + if (tmp->device_type) + kfree(tmp->device_type); + + kfree( tmp ); + } + event_is_open = 0; + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + return 0; +} + +#define ACPI_MAX_STRING_LENGTH 80 +static ssize_t +cobalt_acpi_read_event(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + cobalt_acpi_event_t *event = NULL; + unsigned long flags = 0; + static char str[ACPI_MAX_STRING_LENGTH]; + static int strsize; + static char *ptr; + + if (!strsize) { + DECLARE_WAITQUEUE(wait, current); + + if (list_empty(&cobalt_acpi_event_list)) { + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&cobalt_acpi_event_wait_queue, &wait); + + if (list_empty(&cobalt_acpi_event_list)) { + schedule(); + } + + remove_wait_queue(&cobalt_acpi_event_wait_queue, &wait); + set_current_state(TASK_RUNNING); + + if (signal_pending(current)) { + return -ERESTARTSYS; + } + } + + spin_lock_irqsave(&cobalt_acpi_event_lock, flags); + event = list_entry(cobalt_acpi_event_list.next, + cobalt_acpi_event_t, list); + list_del(&event->list); + spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags); + + strsize = sprintf(str, "%s %s %08x %08x\n", + event->device_type, event->device_instance, + event->event_type, event->event_data); + ptr = str; + + kfree(event->device_type); + kfree(event->device_instance); + kfree(event); + } + if (strsize < count) + count = strsize; + + if (copy_to_user(buf, ptr, count)) + return -EFAULT; + + *ppos += count; + strsize -= count; + ptr += count; + + return count; +} + +static unsigned int +cobalt_acpi_poll_event(struct file *file, poll_table *wait) +{ + poll_wait(file, &cobalt_acpi_event_wait_queue, wait); + if (!list_empty(&cobalt_acpi_event_list)) + return POLLIN | POLLRDNORM; + return 0; +} + +#endif /* CONFIG_COBALT_EMU_ACPI */ diff -Nurb linux-2.6.24.3/drivers/cobalt/fans.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/fans.c --- linux-2.6.24.3/drivers/cobalt/fans.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/fans.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,418 @@ +/* $Id: fans.c,v 1.18 2002/03/16 21:33:02 duncan Exp $ + * Copyright (c) 2000-2001 Sun Microsystems, Inc + * + * This should be SMP safe. The critical data (the info list) and the + * critical code (inb()/outb() calls) are protected by fan_lock. It is + * locked at the only external access points - the proc read()/write() + * methods. --TPH + */ +#if defined(CONFIG_COBALT_FANS) || defined(CONFIG_COBALT_FANS_MODULE) + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define FAN_DRIVER "Cobalt Networks Fan driver" +#define FAN_DRIVER_VMAJ 1 +#define FAN_DRIVER_VMIN 0 + +/* GPIO base is assigned by BIOS, perhaps we should probe it */ +#define GPIO_BASE 0x600 +#define FAN_GPIO_MAX 8 +#define FAN_RPM(fn,ms) ((fn).hcyl * (60000000 / (fn).poles) / (ms)) +#define FAN_VALID(f) ((f)->mask && (f)->poles) +#define FAN_CACHE_TIME 2 /* seconds */ +#define FAN_SAMPLE_LEN 50 /* milliseconds */ + +/* + * fans are attached to GPIO pins + * each pin is part of a port, multiple fans are controlled by a port + */ +struct fan_info { + int id; /* fan number */ + uint8_t mask; /* mask within the port */ + int poles; /* # of magnetic poles (divisor) */ + int hcyl; /* # of half cycles */ + unsigned rpm; /* calculated fan speed */ + char *type; /* FAN description */ +}; + +struct fan_gpio { + int port; /* GPIO Port */ + uint16_t base; /* GPDI (data in) base address */ + uint8_t latch; /* latched 'data in' value */ + long tcache; /* latched 'epoch' value */ + struct fan_info fan[FAN_GPIO_MAX]; +}; + +/* the current fanlist */ +static struct fan_gpio *sys_fanlist; +static spinlock_t fan_lock = SPIN_LOCK_UNLOCKED; + +static struct fan_gpio fan_gpio_raqxtr[] = { + { + port: 1, + base: GPIO_BASE, + fan: { + { mask: 0x2, poles: 4, type: "processor" }, + { mask: 0x4, poles: 4, type: "processor" }, + { mask: 0 }, + }, + }, + { + port: 2, + base: GPIO_BASE+4, + fan: { + { mask: 0x10, poles: 4 }, + { mask: 0x20, poles: 4 }, + { mask: 0x40, poles: 4 }, + { mask: 0x80, poles: 4 }, + { mask: 0 }, + }, + }, + { port: -1 } +}; + +static struct fan_gpio fan_gpio_alpine[] = { + { + port: 2, + base: GPIO_BASE+7, + fan: { + { mask: 0x4, poles: 4 }, + { mask: 0x8, poles: 4 }, + { mask: 0x10, poles: 4 }, + { mask: 0x20, poles: 4, type: "power supply" }, + { mask: 0x40, poles: 4, type: "processor" }, + { mask: 0 }, + }, + }, + { port: -1 } +}; + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC +static struct proc_dir_entry *proc_faninfo; +#endif /* CONFIG_COBALT_OLDPROC */ +static struct proc_dir_entry *proc_cfaninfo; +#endif /* CONFIG_PROC_FS */ + +static struct fan_info *fan_info_find(int id); +static int fan_control(struct fan_info *fi, int todo); +static int fan_info_print(char *buffer); +static int fan_read_proc(char *buf, char **start, off_t pos, + int len, int *eof, void *x); +static int fan_write_proc(struct file *file, const char *buf, + unsigned long len, void *x); + +int __init +cobalt_fan_init(void) +{ + if (cobt_is_monterey()) { + sys_fanlist = (struct fan_gpio *)fan_gpio_raqxtr; + } else if (cobt_is_alpine()) { + sys_fanlist = (struct fan_gpio *)fan_gpio_alpine; + } else { + sys_fanlist = NULL; + return -ENOSYS; + } + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", FAN_DRIVER,FAN_DRIVER_VMAJ,FAN_DRIVER_VMIN); + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + proc_faninfo = create_proc_entry("faninfo", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, NULL); + if (!proc_faninfo) { + EPRINTK("can't create /proc/faninfo\n"); + return -ENOENT; + } + proc_faninfo->owner = THIS_MODULE; + proc_faninfo->read_proc = fan_read_proc; + proc_faninfo->write_proc = fan_write_proc; +#endif /* CONFIG_COBALT_OLDPROC */ + proc_cfaninfo = create_proc_entry("faninfo", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt); + if (!proc_cfaninfo) { + EPRINTK("can't create /proc/cobalt/faninfo\n"); + return -ENOENT; + } + proc_cfaninfo->owner = THIS_MODULE; + proc_cfaninfo->read_proc = fan_read_proc; + proc_cfaninfo->write_proc = fan_write_proc; +#endif /* CONFIG_PROC_FS */ + + return 0; +} + +static void __exit +cobalt_fan_exit(void) +{ +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + if (proc_faninfo) { + remove_proc_entry("faninfo", NULL); + } +#endif /* CONFIG_COBALT_OLDPROC */ + if (proc_cfaninfo) { + remove_proc_entry("faninfo", proc_cobalt); + } +#endif /* CONFIG_PROC_FS */ + + sys_fanlist = NULL; +} + +/* + * Samples fan tachometer square wave to calculate and report RPM + */ +static int +get_faninfo(char *buffer) +{ + struct fan_gpio *fg; + struct timeval utime; + unsigned long elapsed, start; + int i, val, len; + + if (!sys_fanlist || !cobt_is_5k()) { + /* software is keyed off this string - do not change it ! */ + return sprintf(buffer, "Fan monitoring not supported.\n"); + } + + /* save start timestamp */ + do_gettimeofday(&utime); + start = utime.tv_usec; + + /* initialize 'previous' values. we do edge detection by + * looking for transitions from previous values */ + for (fg = sys_fanlist; fg->port >= 0; fg++) { + if (fg->tcache && utime.tv_sec < fg->tcache+FAN_CACHE_TIME) { + return fan_info_print(buffer); + } + fg->tcache = utime.tv_sec; + fg->latch = inb(fg->base); + for (i = 0; i < FAN_GPIO_MAX; i++) { + fg->fan[i].hcyl = 0; + fg->fan[i].rpm = 0; + } + } + + /* We are counting the number of halfcycles in a square wave + * that pass in a given amount of time to determine frequency */ + do { + for (fg=sys_fanlist; fg->port>=0; fg++) { + val = inb(fg->base); + for (i=0; ifan[i]; + if (FAN_VALID(p)) { + if ((val ^ fg->latch) & p->mask) { + p->hcyl++; + } + } + } + fg->latch = val; + } + + do_gettimeofday(&utime); + if (utime.tv_usec > start) { + elapsed = utime.tv_usec - start; + } else { + elapsed = utime.tv_usec + 1000001 - start; + } + + } while (elapsed < (FAN_SAMPLE_LEN) * 1000); + + /* Fan rpm = 60 / ( t * poles ) + * where t is 1/2 the period and poles are the number of + * magnetic poles for the fan. + * + * For the Sunon KDE1204PKBX fans on Raq XTR, poles = 4 + * So, in terms of cycles, + * + * rpm = 60 s/m halfcycles + * ------ * -------------- * 1,000,000 us/s * 2 + * 4 2 * elapsed us + * + * = (60,000,000 / 4 poles) * halfcycles / elapsed + * = 15,000,000 * halfcycles / elapsed + * + * Note, by this method and sampling for 50ms, our accuracy + * is +/- 300 rpm. The fans are spec'ed for +/- 1000 rpm + */ + for (val=len=0, fg=sys_fanlist; fg->port>=0; fg++) { + for (i=0; ifan[i]; + if (FAN_VALID(p)) { + p->id = val++; + p->rpm = FAN_RPM(fg->fan[i], elapsed); + len += sprintf(buffer+len, "fan %d : %u\n", + p->id, p->rpm); + } + } + } + + return len; +} + +static int +fan_info_print(char *buffer) +{ + struct fan_gpio *fg; + int i, len=0; + + if (!sys_fanlist) { + return -1; + } + + for (fg=sys_fanlist; fg->port>=0; fg++) { + for (i=0; ifan[i]; + if (FAN_VALID(p)) { + len += sprintf(buffer+len, "fan %d : %u\n", + p->id, p->rpm); + } + } + } + + return len; +} + +/* FIXME: generify */ +static int +fan_control(struct fan_info *fi, int todo) +{ + if (fi && cobt_is_alpine()) { + switch (fi->id) { + case 4: { + /* CPU FAN */ + uint8_t gpdo = inb(GPIO_BASE+6); + + if (todo) { + gpdo &= ~fi->mask; /* 0 = on */ + } else { + gpdo |= fi->mask; /* 1 = off */ + } + outb(gpdo, GPIO_BASE+6); + return 0; + } + default: + return -ENODEV; + } + } + + return -ENOSYS; +} + +static struct fan_info * +fan_info_find(int id) +{ + struct fan_gpio *fg; + int i; + + if (!sys_fanlist) { + return NULL; + } + + for (fg=sys_fanlist; fg->port>=0; fg++) { + for (i=0; ifan[i])) { + if (fg->fan[i].id == id) { + return &fg->fan[i]; + } + } + } + } + + return NULL; +} + +#ifdef CONFIG_PROC_FS +static int +fan_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + int plen; + + //MOD_INC_USE_COUNT; + + spin_lock(&fan_lock); + plen = get_faninfo(buf); + spin_unlock(&fan_lock); + + //MOD_DEC_USE_COUNT; + + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +static int +fan_write_proc(struct file *file, const char *buf, unsigned long len, void *x) +{ + char *page; + int retval = -EINVAL; + + //MOD_INC_USE_COUNT; + + if (len > PAGE_SIZE) { + //MOD_DEC_USE_COUNT; + return -EOVERFLOW; + } + + page = (char *)__get_free_page(GFP_KERNEL); + if (!page) { + //MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + if (copy_from_user(page, buf, len)) { + free_page((unsigned long)page); + //MOD_DEC_USE_COUNT; + return -EFAULT; + } + page[len] = '\0'; + + /* format: `fan ID COMMAND' */ + if (len>5 && !strncmp("fan ", page, 4)) { + if (*(page+4) != '\0') { + struct fan_info *finf; + char *nextpg = NULL; + + spin_lock(&fan_lock); + finf = fan_info_find(simple_strtoul(page+4,&nextpg,0)); + if (!finf) { + retval = -ENOENT; + } else if (nextpg != '\0') { + if (!strncmp("on", nextpg+1, 2)) { + retval = fan_control(finf, 1); + } + else if (!strncmp("off", nextpg+1, 3)) { + retval = fan_control(finf, 0); + } + } + spin_unlock(&fan_lock); + } + } + + free_page((unsigned long)page); + //MOD_DEC_USE_COUNT; + + return (retval < 0) ? retval : len; +} +#endif /* CONFIG_PROC_FS */ + +#if defined(CONFIG_COBALT_FANS_MODULE) +module_init(cobalt_fan_init); +module_exit(cobalt_fan_exit); + +MODULE_AUTHOR("Sun Cobalt"); +MODULE_DESCRIPTION("Sun Cobalt fan tachometers"); +#endif + +#endif /* CONFIG_COBALT_FANS || CONFIG_COBALT_FANS_MODULE */ diff -Nurb linux-2.6.24.3/drivers/cobalt/i2c.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/i2c.c --- linux-2.6.24.3/drivers/cobalt/i2c.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/i2c.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,518 @@ +/* + * $Id: i2c.c,v 1.19 2002/09/17 23:41:29 sparker Exp $ + * i2c.c : Cobalt I2C driver support + * + * Copyright (C) 2000 Cobalt Networks, Inc. + * Copyright (C) 2001 Sun Microsystems, Inc. + * + * Modified By: jeff@404ster.com + * + * This should be SMP safe. All the exported functions lock on enter and + * unlock on exit. These exported functions may be called at interupt time, + * so we have to use the IRQ safe locks. NOTE: no function herein may call + * any exported function herein. --TPH + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define I2C_3K_STATUS 0x00 +#define I2C_3K_CMD 0x01 +#define I2C_3K_START 0x02 +#define I2C_3K_ADDR 0x03 +#define I2C_3K_LOW_DATA 0x04 +#define I2C_3K_HIGH_DATA 0x05 +#define I2C_3K_BLOCK_DATA 0x06 +#define I2C_3K_INDEX 0x07 +#define I2C_3K_STATUS_IDLE 0x04 +#define I2C_3K_CMD_RW_BYTE 0x20 +#define I2C_3K_CMD_RW_WORD 0x30 +#define I2C_3K_CMD_RW_BLOCK 0xC0 +#define I2C_3K_CMD_RESET_PTR 0x80 + +#define I2C_5K_HOST_STATUS 0x00 +#define I2C_5K_SLAVE_STATUS 0x01 +#define I2C_5K_HOST_CONTROL 0x02 +#define I2C_5K_HOST_COMMAND 0x03 +#define I2C_5K_HOST_ADDR 0x04 +#define I2C_5K_DATA_0 0x05 +#define I2C_5K_DATA_1 0x06 +#define I2C_5K_BLOCK_DATA 0x07 +#define I2C_5K_SLAVE_CONTROL 0x08 +#define I2C_5K_SHADOW_COMMAND 0x09 +#define I2C_5K_SLAVE_EVENT 0x0a +#define I2C_5K_SLAVE_DATA 0x0c +#define I2C_5K_HOST_STATUS_BUSY 0x01 +#define I2C_5K_HOST_CMD_START 0x40 +#define I2C_5K_HOST_CMD_QUICK_RW (0 << 2) +#define I2C_5K_HOST_CMD_BYTE_RW (1 << 2) +#define I2C_5K_HOST_CMD_BYTE_DATA_RW (2 << 2) +#define I2C_5K_HOST_CMD_WORD_DATA_RW (3 << 2) +#define I2C_5K_HOST_CMD_BLOCK_DATA_RW (5 << 2) + +#define I2C_WRITE 0 +#define I2C_READ 1 + +/* this delay was determined empirically */ +#define I2C_WRITE_UDELAY 1000 + +struct cobalt_i2c_data { + const unsigned char status; + const unsigned char addr; + const unsigned char index; + const unsigned char data_low; + const unsigned char data_high; + const unsigned char data_block; + const unsigned char rw_byte; + const unsigned char rw_word; + const unsigned char rw_block; + unsigned int io_port; +}; + +struct cobalt_i2c_data cobalt_i2c_3k = { + I2C_3K_STATUS, + I2C_3K_ADDR, + I2C_3K_INDEX, + I2C_3K_LOW_DATA, + I2C_3K_HIGH_DATA, + I2C_3K_BLOCK_DATA, + I2C_3K_CMD_RW_BYTE, + I2C_3K_CMD_RW_WORD, + I2C_3K_CMD_RW_BLOCK, + 0L +}; + +struct cobalt_i2c_data cobalt_i2c_5k = { + I2C_5K_HOST_STATUS, + I2C_5K_HOST_ADDR, + I2C_5K_HOST_COMMAND, + I2C_5K_DATA_0, + I2C_5K_DATA_1, + I2C_5K_BLOCK_DATA, + I2C_5K_HOST_CMD_BYTE_DATA_RW, + I2C_5K_HOST_CMD_WORD_DATA_RW, + I2C_5K_HOST_CMD_BLOCK_DATA_RW, + 0L +}; + +/* a global pointer for our i2c data */ +struct cobalt_i2c_data *i2c_data; + +#define I2C_REG(r) (i2c_data->io_port + i2c_data->r) +#define I2C_CMD(c) (i2c_data->c) + +#define I2C_LOCK (1 << 0) +#define I2C_DEAD (1 << 1) +static unsigned long i2c_state; + +static int initialized; + +static inline int +do_i2c_lock(void) +{ + int i = 0; + + if (test_bit(I2C_DEAD, &i2c_state)) + return -1; + + while (test_and_set_bit(I2C_LOCK, &i2c_state)) { + if (i++ > 5) + return -1; + udelay(10); + } + udelay(1); + return 0; +} + +static inline void +do_i2c_unlock(void) +{ + clear_bit(I2C_LOCK, &i2c_state); +} + +/* do a little squelching */ +#define NOISE_RATE (5*HZ) +static int +i2c_noisy(void) +{ + static unsigned long last_time; + static unsigned int messages; + + if ((long) (jiffies - last_time) > NOISE_RATE) { + last_time = jiffies; + if (messages) { + WPRINTK("skipped %u kernel messages\n", messages); + messages = 0; + } + return 0; + } + messages++; + return 1; +} + +static int +i2c_wait_for_smi(void) +{ + static unsigned int shutup = 0; + int timeout=10; + int status; + + while (timeout--) { + udelay(100); /* wait */ + status = inb_p(I2C_REG(status)); + + if (cobt_is_3k()) { + if (status & I2C_3K_STATUS_IDLE) { + return 0; + } + } else if (cobt_is_5k()) { + if (!(status & I2C_5K_HOST_STATUS_BUSY)) { + return 0; + } + } + outb_p(status, I2C_REG(status)); + } + + /* still busy - complain */ + if (!i2c_noisy()) { + if (++shutup > 2) { + EPRINTK("i2c seems to be dead - sorry\n"); + set_bit(I2C_DEAD, &i2c_state); + } else { + WPRINTK("i2c timeout: status busy (0x%x), resetting\n", + status); + } + } + + /* punch the abort bit */ + if (cobt_is_3k()) { + outb_p(4, i2c_data->io_port + I2C_3K_CMD); + } else if (cobt_is_5k()) { + outb_p(2, i2c_data->io_port + I2C_5K_HOST_CONTROL); + outb_p(1, i2c_data->io_port + I2C_5K_HOST_CONTROL); + } + + return -1; +} + +static inline int +i2c_setup(const int dev, const int index, const int r) +{ + if (i2c_wait_for_smi() < 0) + return -1; + + /* clear status */ + outb_p(0xff, I2C_REG(status)); + + /* device address */ + outb_p((dev|r) & 0xff, I2C_REG(addr)); + + /* I2C index */ + outb_p(index & 0xff, I2C_REG(index)); + + return 0; +} + +static inline int +i2c_cmd(const unsigned char command) +{ + if (cobt_is_3k()) { + outb_p(command, i2c_data->io_port + I2C_3K_CMD); + outb_p(0xff, i2c_data->io_port + I2C_3K_START); + } else if (cobt_is_5k()) { + outb_p(I2C_5K_HOST_CMD_START | command, + i2c_data->io_port + I2C_5K_HOST_CONTROL); + } + + if (i2c_wait_for_smi() < 0) + return -1; + + return 0; +} + +int +cobalt_i2c_init(void) +{ + struct pci_dev *i2cdev = NULL; + + if( ! initialized ) { + if (cobt_is_3k()) { + i2c_data = &cobalt_i2c_3k; + i2cdev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!i2cdev) { + EPRINTK("can't find PMU for i2c access\n"); + return -1; + } + pci_read_config_dword(i2cdev, 0x14, &i2c_data->io_port); + } else if (cobt_is_5k()) { + i2c_data = &cobalt_i2c_5k; + i2cdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, i2cdev); + if (!i2cdev) { + i2cdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, i2cdev); + if (!i2cdev) { + EPRINTK("can't find OSB4 or CSB5 for i2c access\n"); + return -1; + } + } + pci_read_config_dword(i2cdev, 0x90, &i2c_data->io_port); + } + + i2c_data->io_port &= 0xfff0; + if (!i2c_data->io_port) { + EPRINTK("i2c IO port not found\n"); + } + initialized = 1; + } + + return 0; +} + +int +cobalt_i2c_reset(void) +{ + int r; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (cobt_is_3k()) { + /* clear status */ + outb_p(0xff, i2c_data->io_port + I2C_3K_STATUS); + /* reset SMB devs */ + outb_p(0x08, i2c_data->io_port + I2C_3K_CMD); + /* start command */ + outb_p(0xff, i2c_data->io_port + I2C_3K_START); + } else if (cobt_is_5k()) { + /* clear status */ + outb_p(0x2, i2c_data->io_port + I2C_5K_HOST_CONTROL); + outb_p(0x1, i2c_data->io_port + I2C_5K_HOST_CONTROL); + outb_p(0xff, i2c_data->io_port + I2C_5K_HOST_STATUS); + outb_p(I2C_5K_HOST_CMD_START | 0x08, + i2c_data->io_port + I2C_5K_HOST_CONTROL); + } + + r = i2c_wait_for_smi(); + + do_i2c_unlock(); + + return r; +} + +int +cobalt_i2c_read_byte(const int dev, const int index) +{ + int val = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_READ) < 0 + || i2c_cmd(I2C_CMD(rw_byte)) < 0) { + val = -1; + } + + if (val == 0) { + val = inb_p(I2C_REG(data_low)); + } + + do_i2c_unlock(); + + return val; +} + +int +cobalt_i2c_read_word(const int dev, const int index) +{ + int val = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_READ) < 0 + || i2c_cmd(I2C_CMD(rw_word)) < 0) { + val = -1; + } + + if (val == 0) { + val = inb_p(I2C_REG(data_low)); + val += inb_p(I2C_REG(data_high)) << 8; + } + + do_i2c_unlock(); + + return val; +} + +int +cobalt_i2c_read_block(const int dev, const int index, + unsigned char *data, int count) +{ + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_READ) < 0) { + do_i2c_unlock(); + return -1; + } + + outb_p(count & 0xff, I2C_REG(data_low)); + outb_p(count & 0xff, I2C_REG(data_high)); + + if (i2c_cmd(I2C_CMD(rw_block)) < 0) { + do_i2c_unlock(); + return -1; + } + + while (count) { + /* read a byte of block data */ + *data = inb_p(I2C_REG(data_block)); + data++; + count--; + } + + do_i2c_unlock(); + + return 0; +} + +int +cobalt_i2c_write_byte(const int dev, const int index, const u8 val) +{ + int r = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_WRITE) < 0) { + r = -1; + } + + if (r == 0) { + outb_p(val & 0xff, I2C_REG(data_low)); + + if (i2c_cmd(I2C_CMD(rw_byte)) < 0) { + r = -1; + } + } + + udelay(I2C_WRITE_UDELAY); + + do_i2c_unlock(); + + return r; +} + +int +cobalt_i2c_write_word(const int dev, const int index, const u16 val) +{ + int r = 0; + + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_WRITE) < 0) { + r = -1; + } + + if (r == 0) { + outb_p(val & 0xff, I2C_REG(data_low)); + outb_p((val >> 8) & 0xff, I2C_REG(data_high)); + + if (i2c_cmd(I2C_CMD(rw_word)) < 0) { + r = -1; + } + } + + udelay(I2C_WRITE_UDELAY); + + do_i2c_unlock(); + + return r; +} + +int +cobalt_i2c_write_block(int dev, int index, unsigned char *data, int count) +{ + if( !initialized ) { + if( cobalt_i2c_init() < 0 ) + return -1; + } + + if (do_i2c_lock() < 0) + return -1; + + if (i2c_setup(dev, index, I2C_WRITE) < 0) { + do_i2c_unlock(); + return -1; + } + + outb_p(count & 0xff, I2C_REG(data_low)); + outb_p(count & 0xff, I2C_REG(data_high)); + + if (i2c_cmd(I2C_CMD(rw_block)) < 0) { + do_i2c_unlock(); + return -1; + } + + while (count) { + /* write a byte of block data */ + outb_p(*data, I2C_REG(data_block)); + data++; + count--; + } + + udelay(I2C_WRITE_UDELAY); + + do_i2c_unlock(); + + return 0; +} + +EXPORT_SYMBOL(cobalt_i2c_reset); +EXPORT_SYMBOL(cobalt_i2c_read_byte); +EXPORT_SYMBOL(cobalt_i2c_read_word); +EXPORT_SYMBOL(cobalt_i2c_read_block); +EXPORT_SYMBOL(cobalt_i2c_write_byte); +EXPORT_SYMBOL(cobalt_i2c_write_word); +EXPORT_SYMBOL(cobalt_i2c_write_block); diff -Nurb linux-2.6.24.3/drivers/cobalt/init.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/init.c --- linux-2.6.24.3/drivers/cobalt/init.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/init.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,117 @@ +/* $Id: init.c,v 1.22 2002/11/04 17:54:15 thockin Exp $ */ +/* + * Copyright (c) 2001 Sun Microsystems + * Generic initialization, to reduce pollution of other files + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static int cobalt_proc_init(void); +extern int cobalt_i2c_init(void); +extern int cobalt_net_init(void); +extern int cobalt_systype_init(void); +extern void cobalt_boardrev_init(void); +extern int cobalt_led_init(void); +extern int cobalt_lcd_init(void); +extern int cobalt_serialnum_init(void); +extern int cobalt_wdt_init(void); +extern int cobalt_sensors_init(void); +extern int cobalt_fan_init(void); +extern int cobalt_acpi_init(void); +extern int cobalt_ruler_init(void); +extern int cobalt_raminfo_init(void); + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_cobalt; +EXPORT_SYMBOL(proc_cobalt); +#endif +spinlock_t cobalt_superio_lock = SPIN_LOCK_UNLOCKED; + +/* initialize all the cobalt specific stuff */ +int __init +cobalt_init(void) +{ + cobalt_proc_init(); + cobalt_systype_init(); +#ifdef CONFIG_COBALT_RAQ + /* we might keep the boardrev on an i2c chip */ + cobalt_i2c_init(); +#endif + cobalt_boardrev_init(); +#ifdef CONFIG_COBALT_ACPI + cobalt_acpi_init(); +#endif +#ifdef CONFIG_COBALT_LED + cobalt_net_init(); + cobalt_led_init(); +#endif +#ifdef CONFIG_COBALT_LCD + cobalt_lcd_init(); +#endif +#ifdef CONFIG_COBALT_RULER + cobalt_ruler_init(); +#endif +#ifdef CONFIG_COBALT_SERNUM + cobalt_serialnum_init(); +#endif +#ifdef CONFIG_COBALT_RAQ + /* some systems use WDT it for reboot */ + cobalt_wdt_init(); +#endif +#ifdef CONFIG_COBALT_SENSORS + cobalt_sensors_init(); +#endif +#ifdef CONFIG_COBALT_FANS + cobalt_fan_init(); +#endif +#ifdef CONFIG_COBALT_RAMINFO + cobalt_raminfo_init(); +#endif +#ifdef CONFIG_COBALT_POWERMODE + cobalt_powermode_init(); +#endif + return 0; +} + +static int __init +cobalt_proc_init(void) +{ +#ifdef CONFIG_PROC_FS + proc_cobalt = proc_mkdir("cobalt", 0); + if (!proc_cobalt) { + EPRINTK("can't create /proc/cobalt\n"); + return -1; + } +#endif + + return 0; +} + +/* a function that handles the blah stuff in a simple proc read function */ +int +cobalt_gen_proc_read(char *buf, int plen, char **start, off_t pos, + int len, int *eof) +{ + /* trying to read a bad offset? */ + if (pos >= plen) { + *eof = 1; + return 0; + } + + /* did we write everything we wanted to? */ + if (len >= (plen-pos)) { + *eof = 1; + } + + *start = buf + pos; + plen -= pos; + + return (len > plen) ? plen : len; +} +EXPORT_SYMBOL(cobalt_gen_proc_read); diff -Nurb linux-2.6.24.3/drivers/cobalt/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Kconfig --- linux-2.6.24.3/drivers/cobalt/Kconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Kconfig 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,156 @@ +# +# Cobalt Drivers +# + +menu "Cobalt RaQ/Qube Hardware" + +config COBALT_RAQ + bool "Cobalt RaQ/Qube Hardware Support" + select INPUT + default n + ---help--- + NOTE: This support is for x86 Cobalts, not MIPS versions + + If you have a Gen III or Gen V Cobalt RaQ/Qube machine, it's probably + a good idea to say Y here and choose from the options below. + +config COBALT_GEN_III + bool "Gen III (3000 series) system support" + depends on COBALT_RAQ + default y + ---help--- + If you have one of the following Gen III Cobalt systems, say Y here. + Otherwise, it's best to say N. + + - RaQ 3 + - RaQ 4 + - Qube3 + +config COBALT_GEN_V + bool "Gen V (5000 series) system support" + depends on COBALT_RAQ + default n + ---help--- + If you have one of the following Gen V Cobalt systems, say Y here. + Otherwise, it's best to say N. + + - RaQ XTR + - RaQ550 + +config COBALT_OLDPROC + bool "Create legacy /proc files" + depends on COBALT_RAQ + depends on PROC_FS + default y + ---help--- + Creates entries in /proc/cobalt which provide useful information about + your RaQ/Qube. Best to say Y here. + +#config COBALT_BOOTLOADER +# bool "Cobalt Bootloader Support" +# depends on COBALT_RAQ +# default n +# ---help--- +# If you are going to being burning this kernel to the RaQ/Qube's ROM to +# act as a loader kernel, this is required to load the system kernel and +# hand off control to it. It is recommended you say N here unless you +# know what you're getting yourself into. +# +menu "Cobalt Hardware Options" + depends on COBALT_RAQ + + config COBALT_LCD + bool "Front panel LCD support" + default y + ---help--- + Handles support for the front panel LCD screen and buttons. + + config COBALT_LCD_TWIDDLE + bool "Twiddle LCD on boot" + depends on COBALT_LCD + default y + ---help--- + Gives you a nice little twiddle on the LCD while booting. + + config COBALT_LED + bool "Software controlled LED support" + default y + ---help--- + Allows software to play with the LEDs on the front of the + system. + + config COBALT_SERNUM + tristate "Serial number support" + depends on COBALT_OLDPROC + default y + ---help--- + Allows you to retrieve the system's serial number via a /proc + entry. + + config COBALT_WDT + bool "Watchdog timer support" + depends on WATCHDOG + default y + ---help--- + w00f? + + config COBALT_POWERMODE + bool "Powermode Restore support" + depends on COBALT_OLDPROC + depends on COBALT_GEN_V + default y + ---help--- + On GenV RaQs you can specify what action to take should a + power failure occur. This code allows you to set that action + via /proc/cobalt/powermode. Your options are "on", "off", and + "same", except on Monterey hardware (XTR's) where there is no + support for "on". + + config COBALT_SENSORS + bool "System sensors support" + depends on COBALT_OLDPROC + default y + ---help--- + Allows you to retrieve system temperatures via /proc entries. + + config COBALT_FANS + tristate "Fan tachometer support" + depends on COBALT_OLDPROC + depends on COBALT_GEN_V + default y + ---help--- + Allows you to retrieve fan speeds via /proc entries. + + config COBALT_RAMINFO + tristate "Memory information support" + depends on COBALT_OLDPROC + default y + ---help--- + Got DIMMs? This will tell you how much and in which slot via a + /proc entry. + + config COBALT_RULER + bool "Disk drive ruler support" + depends on COBALT_OLDPROC + depends on COBALT_GEN_V + default y + ---help--- + Not sure what this does... A purple tape measure maybe? + + config COBALT_ACPI + bool "Cobalt ACPI support" + depends on COBALT_GEN_V + default y + ---help--- + ACPI support for the Generation V Cobalts. + + config COBALT_EMU_ACPI + bool "/proc/acpi emulation" + depends on COBALT_ACPI + default y + ---help--- + Emulates the /proc/acpi interface. + +endmenu + +endmenu diff -Nurb linux-2.6.24.3/drivers/cobalt/lcd.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/lcd.c --- linux-2.6.24.3/drivers/cobalt/lcd.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/lcd.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,858 @@ +/* + * $Id: lcd.c,v 1.44 2002/05/10 18:44:45 duncan Exp $ + * lcd.c : driver for Cobalt LCD/Buttons + * + * Copyright 1996-2000 Cobalt Networks, Inc. + * Copyright 2001 Sun Microsystems, Inc. + * + * By: Andrew Bose + * Timothy Stonis + * Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * Modified By: jeff@404ster.com + * + * This should be SMP safe. We're hardly performance critical, + * so we lock around lcd_ioctl() and just where needed by other external + * functions. There is a static global waiters variable that is atomic_t, and + * so should be safe. --TPH + */ + +#ifdef CONFIG_COBALT_LCD + +#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 TWIDDLE_HZ (HZ/10) + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define LCD_DRIVER "Cobalt Networks LCD driver" +#define LCD_DRIVER_VMAJ 4 +#define LCD_DRIVER_VMIN 0 + +/* io registers */ +#define LPT 0x0378 +#define LCD_DATA_ADDRESS LPT+0 +#define LCD_CONTROL_ADDRESS LPT+2 + +/* LCD device info */ +#define LCD_Addr 0x80 +#define DD_R00 0x00 +#define DD_R01 0x27 +#define DD_R10 0x40 +#define DD_R11 0x67 + +/* driver functions */ +static int cobalt_lcd_open(struct inode *, struct file *); +static ssize_t cobalt_lcd_read(struct file *, char *, size_t, loff_t *); +static int cobalt_lcd_read_proc(char *, char **, off_t, int, int *, void *); +static char *cobalt_lcddev_read_line(int, char *); +static int cobalt_lcd_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); +static int cobalt_lcd_panic(struct notifier_block *self, unsigned long, void *); + +/* globals used throughout */ +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC +static struct proc_dir_entry *proc_lcd; +#endif +static struct proc_dir_entry *proc_clcd; +#endif +static int lcd_present; +static int has_i2c_lcd; +static spinlock_t lcd_lock = SPIN_LOCK_UNLOCKED; + +/* various file operations we support for this driver */ +static struct file_operations lcd_fops = { + .read = cobalt_lcd_read, + .ioctl = cobalt_lcd_ioctl, + .open = cobalt_lcd_open, +}; + +/* device structure */ +static struct miscdevice lcd_dev = { + MISC_DYNAMIC_MINOR, + "lcd", + &lcd_fops +}; + +static int disable_lcd; +static int __init +lcd_disable_setup(char *str) +{ + disable_lcd = 1; + return 0; +} +__setup("nolcd", lcd_disable_setup); + +/* Read a control instruction from the LCD */ +static inline int +lcddev_read_inst(void) +{ + int a = 0; + + if (cobt_is_5k() && has_i2c_lcd) { + a = cobalt_i2c_read_byte( + COBALT_I2C_DEV_LCD_INST | COBALT_I2C_READ, 0); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x21, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + outb(0x20, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=1 */ + a = inb(LCD_DATA_ADDRESS); + outb(0x21, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + outb(0x01, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + } + + /* small delay */ + udelay(100); + + return a; +} + +#define LCD_MAX_POLL 10000 +static inline void +lcddev_poll_wait(void) +{ + int i=0; + + while (i++ < LCD_MAX_POLL) { + int r = lcddev_read_inst(); + if (r < 0 || !(r & 0x80)) + break; + } +} + +/* Write a control instruction to the LCD */ +static inline void +lcddev_write_inst(unsigned char data) +{ + lcddev_poll_wait(); + + if (cobt_is_5k() && has_i2c_lcd) { + cobalt_i2c_write_byte( + COBALT_I2C_DEV_LCD_INST | COBALT_I2C_WRITE, 0, data); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x03, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=0 */ + outb(data, LCD_DATA_ADDRESS); + outb(0x02, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=1 */ + outb(0x03, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=0 */ + outb(0x01, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */ + } + + /* small delay */ + udelay(100); +} + +/* Write one byte of data to the LCD */ +static inline void +lcddev_write_data(unsigned char data) +{ + lcddev_poll_wait(); + + if (cobt_is_5k() && has_i2c_lcd) { + cobalt_i2c_write_byte( + COBALT_I2C_DEV_LCD_DATA | COBALT_I2C_WRITE, 0, data); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x07, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=0 */ + outb(data, LCD_DATA_ADDRESS); + outb(0x06, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=1 */ + outb(0x07, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=0 */ + outb(0x05, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + } + /* small delay */ + udelay(100); +} + +/* Read one byte of data from the LCD */ +static inline unsigned char +lcddev_read_data(void) +{ + unsigned char a = 0; + + lcddev_poll_wait(); + + if (cobt_is_5k() && has_i2c_lcd) { + a = cobalt_i2c_read_byte( + COBALT_I2C_DEV_LCD_DATA | COBALT_I2C_READ, 0); + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x25, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + outb(0x24, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=1 */ + a = inb(LCD_DATA_ADDRESS); + outb(0x25, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + outb(0x01, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */ + } + + /* small delay */ + udelay(100); + + return a; +} + +static inline void +lcddev_init(void) +{ + lcddev_write_inst(0x38); + lcddev_write_inst(0x38); + lcddev_write_inst(0x38); + lcddev_write_inst(0x06); + lcddev_write_inst(0x0c); +} + +static inline char +read_buttons(void) +{ + char r = 0; + + if (cobt_is_5k() && has_i2c_lcd) { + unsigned char inst; + inst = cobalt_i2c_read_byte(COBALT_I2C_DEV_FP_BUTTONS, 0); + switch (inst) { + case 0x3e: r = BUTTON_Next_B; break; + case 0x3d: r = BUTTON_Enter_B; break; + case 0x1f: r = BUTTON_Left_B; break; + case 0x3b: r = BUTTON_Right_B; break; + case 0x2f: r = BUTTON_Up_B; break; + case 0x37: r = BUTTON_Down_B; break; + case 0x3f: + default: r = BUTTON_NONE_B; + } + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + outb(0x29, LCD_CONTROL_ADDRESS); /* Sel=0, Bi=1 */ + r = inb(LCD_DATA_ADDRESS) & BUTTON_MASK; + } + + return r; +} + +static inline int +button_pressed(void) +{ + unsigned char b; + unsigned long flags; + + spin_lock_irqsave(&lcd_lock, flags); + b = read_buttons(); + spin_unlock_irqrestore(&lcd_lock, flags); + + switch (b) { + case BUTTON_Next: + case BUTTON_Next_B: + case BUTTON_Reset_B: + return b; + default: + break; + } + + return 0; +} + +/* this could be protected by CAP_RAW_IO here, or by the FS permissions */ +static int +cobalt_lcd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct lcd_display button_display, display; + unsigned long address, a; + int index; + int dlen = sizeof(struct lcd_display); + int r = 0; + unsigned long flags; + +#ifdef CONFIG_COBALT_LCD_TWIDDLE + cobalt_lcd_stop_twiddle(); +#endif + switch (cmd) { + /* Turn the LCD on */ + case LCD_On: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0F); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn the LCD off */ + case LCD_Off: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x08); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Reset the LCD */ + case LCD_Reset: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x3F); + lcddev_write_inst(0x01); + lcddev_write_inst(0x06); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Clear the LCD */ + case LCD_Clear: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x01); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Move the cursor one position to the left */ + case LCD_Cursor_Left: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x10); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Move the cursor one position to the right */ + case LCD_Cursor_Right: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x14); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn the cursor off */ + case LCD_Cursor_Off: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0C); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn the cursor on */ + case LCD_Cursor_On: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0F); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Turn blinking off? I don't know what this does - TJS */ + case LCD_Blink_Off: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x0E); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Get the current cursor position */ + case LCD_Get_Cursor_Pos: + spin_lock_irqsave(&lcd_lock, flags); + display.cursor_address = (unsigned char)lcddev_read_inst(); + display.cursor_address = display.cursor_address & 0x07F; + spin_unlock_irqrestore(&lcd_lock, flags); + if (copy_to_user((struct lcd_display *)arg, &display, dlen)) { + r = -EFAULT; + } + break; + + /* Set the cursor position */ + case LCD_Set_Cursor_Pos: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + a = display.cursor_address | LCD_Addr; + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(a); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Get the value at the current cursor position? - TJS */ + case LCD_Get_Cursor: + spin_lock_irqsave(&lcd_lock, flags); + display.character = lcddev_read_data(); + lcddev_write_inst(0x10); + spin_unlock_irqrestore(&lcd_lock, flags); + if (copy_to_user((struct lcd_display *)arg, &display, dlen)) { + r = -EFAULT; + } + break; + + /* Set the character at the cursor position? - TJS */ + case LCD_Set_Cursor: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_data(display.character); + lcddev_write_inst(0x10); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Dunno what this does - TJS */ + case LCD_Disp_Left: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x18); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Dunno what this does - TJS */ + case LCD_Disp_Right: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x1C); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Dunno what this does - TJS */ + case LCD_Home: + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x02); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Write a string to the LCD */ + case LCD_Write: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + + spin_lock_irqsave(&lcd_lock, flags); + + display.size1 = display.size1 > 0 ? + min(display.size1, (int) sizeof(display.line1)) : 0; + display.size2 = display.size2 > 0 ? + min(display.size2, (int) sizeof(display.line2)) : 0; + + /* First line */ + lcddev_write_inst(0x80); + for (index = 0; index < display.size1; index++) + lcddev_write_data(display.line1[index]); + for (index = display.size1; index < sizeof(display.line1); index++) + lcddev_write_data(' '); + + /* Second line */ + lcddev_write_inst(0xC0); + for (index = 0; index < display.size2; index++) + lcddev_write_data(display.line2[index]); + for (index = display.size2; index < sizeof(display.line2); index++) + lcddev_write_data(' '); + + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + /* Read what's on the LCD */ + case LCD_Read: + spin_lock_irqsave(&lcd_lock, flags); + + for (address = DD_R00; address <= DD_R01; address++) { + lcddev_write_inst(address | LCD_Addr); + display.line1[address] = lcddev_read_data(); + } + for (address = DD_R10; address <= DD_R11; address++) { + lcddev_write_inst(address | LCD_Addr); + display.line2[address - DD_R10] = lcddev_read_data(); + } + + spin_unlock_irqrestore(&lcd_lock, flags); + + display.line1[DD_R01] = '\0'; + display.line2[DD_R01] = '\0'; + + if (copy_to_user((struct lcd_display *)arg, &display, dlen)) { + r = -EFAULT; + } + break; + + case LCD_Raw_Inst: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(display.character); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + case LCD_Raw_Data: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_data(display.character); + spin_unlock_irqrestore(&lcd_lock, flags); + break; + + case LCD_Type: + if (cobt_is_5k() && has_i2c_lcd) { + if (put_user(LCD_TYPE_I2C, (int *)arg)) { + r = -EFAULT; + } + } else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) { + if (put_user(LCD_TYPE_PARALLEL_B, (int *)arg)) { + r = -EFAULT; + } + } + break; + + /* Read the buttons */ + case BUTTON_Read: + spin_lock_irqsave(&lcd_lock, flags); + button_display.buttons = read_buttons(); + spin_unlock_irqrestore(&lcd_lock, flags); + if (copy_to_user((struct lcd_display *)arg, + &button_display, dlen)) { + r = -EFAULT; + } + break; + +#ifdef CONFIG_COBALT_LED + /* a slightly different api that allows you to set 32 leds */ + case LED32_Set: + cobalt_led_set_lazy(arg); + break; + + case LED32_Bit_Set: + cobalt_led_set_bits_lazy(arg); + break; + + case LED32_Bit_Clear: + cobalt_led_clear_bits_lazy(arg); + break; + + case LED32_Get: + *(unsigned int *)arg = cobalt_led_get(); + break; + + /* set all the leds */ + case LED_Set: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + cobalt_led_set_lazy(display.leds); + break; + + /* set a single led */ + case LED_Bit_Set: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + cobalt_led_set_bits_lazy(display.leds); + break; + + /* clear an led */ + case LED_Bit_Clear: + if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) { + r = -EFAULT; + break; + } + cobalt_led_clear_bits_lazy(display.leds); + break; +#endif + + default: + break; + } + + return r; +} + +static int +cobalt_lcd_open(struct inode *inode, struct file *file) +{ + if (!lcd_present) { + return -ENXIO; + } else { + return 0; + } +} + +/* LCD daemon sits on this, we wake it up once a key is pressed */ +static ssize_t +cobalt_lcd_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + int bnow; + static unsigned long lcd_waiters; + + if (test_and_set_bit(0, &lcd_waiters)) { + return -EINVAL; + } + + while (((bnow = button_pressed()) == 0) && !(signal_pending(current))) { + if (file->f_flags & O_NONBLOCK) { + lcd_waiters = 0; + return -EAGAIN; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2 * HZ); + } + lcd_waiters = 0; + + if (signal_pending(current)) { + return -ERESTARTSYS; + } + + return bnow; +} + +/* read a single line from the LCD into a string */ +static char * +cobalt_lcddev_read_line(int lineno, char *line) +{ + unsigned long addr, min, max; + unsigned long flags; + + switch (lineno) { + case 0: + min = DD_R00; + max = DD_R01; + break; + case 1: + min = DD_R10; + max = DD_R11; + break; + default: + min = 1; + max = 0; + } + + spin_lock_irqsave(&lcd_lock, flags); + for (addr = min; addr <= max; addr++) { + lcddev_write_inst(addr | LCD_Addr); + udelay(150); + line[addr-min] = lcddev_read_data(); + udelay(150); + } + spin_unlock_irqrestore(&lcd_lock, flags); + line[addr-min] = '\0'; + + return line; +} + +#ifdef CONFIG_PROC_FS +static int +cobalt_lcd_read_proc(char *buf, char **start, off_t pos, + int len, int *eof, void *private) +{ + int plen = 0; + char line[COBALT_LCD_LINELEN+1]; + + /* first line */ + cobalt_lcddev_read_line(0, line); + plen += sprintf(buf+plen, "%s\n", line); + + /* second line */ + cobalt_lcddev_read_line(1, line); + plen += sprintf(buf+plen, "%s\n", line); + + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} +#endif + +void cobalt_lcd_print(char * line1, char * line2) +{ + int i; + int len; + + if( !lcd_present ) + return; + +#ifdef CONFIG_COBALT_LCD_TWIDDLE + cobalt_lcd_stop_twiddle(); +#endif + + lcddev_write_inst( (DD_R00) | LCD_Addr); + len = strlen( line1 ); + for( i=0 ; i<16 ; i++ ) + lcddev_write_data( (i 11) { + state = -1; + pos = 10; + } + + lcddev_write_inst((DD_R10+4+pos) | LCD_Addr); + lcddev_write_data(0xff); + + spin_unlock_irqrestore(&lcd_lock, flags); + + mod_timer(&twiddle_timer, jiffies + TWIDDLE_HZ); +} + +void +cobalt_lcd_start_twiddle(void) +{ + init_timer(&twiddle_timer); + twiddle_timer.expires = jiffies + TWIDDLE_HZ; + twiddle_timer.data = 0; + twiddle_timer.function = &twiddle_timer_func; + add_timer(&twiddle_timer); + twiddling=1; +} + +void +cobalt_lcd_stop_twiddle(void) +{ + unsigned long flags; + + spin_lock_irqsave(&lcd_lock, flags); + if (twiddling) { + del_timer_sync(&twiddle_timer); + twiddling = 0; + } + spin_unlock_irqrestore(&lcd_lock, flags); +} +#endif /* CONFIG_COBALT_LCD_TWIDDLE */ + +/* stop the lcd */ +void cobalt_lcd_off(void) +{ + unsigned long flags; + + spin_lock_irqsave(&lcd_lock, flags); + lcddev_write_inst(0x01); /* clear */ + lcddev_write_inst(0x08); /* off */ + spin_unlock_irqrestore(&lcd_lock, flags); +} + +static int initialized; +static struct notifier_block lcd_nb; + +int __init +cobalt_lcd_init(void) +{ + int retval; + + if (initialized) + return 0; + + initialized=1; + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", LCD_DRIVER,LCD_DRIVER_VMAJ,LCD_DRIVER_VMIN); + + if (disable_lcd) { + printk(KERN_INFO "%s DISABLED\n", LCD_DRIVER); + return 0; + } + + retval = misc_register(&lcd_dev); + + if (cobt_is_monterey() + && (cobalt_i2c_read_byte(COBALT_I2C_DEV_LCD_INST, 0) != 0xff)) { + printk(KERN_INFO " - LCD is an I2C device\n"); + has_i2c_lcd = 1; + } else { + has_i2c_lcd = 0; + } + + /* flag ourselves as present */ + lcd_present = 1; + + /* initialize the device */ + lcddev_init(); + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + /* create /proc/lcd */ + proc_lcd = create_proc_read_entry("lcd", S_IRUSR, NULL, + cobalt_lcd_read_proc, NULL); + if (!proc_lcd) { + EPRINTK("can't create /proc/lcd\n"); + } +#endif + proc_clcd = create_proc_read_entry("lcd", S_IRUSR, proc_cobalt, + cobalt_lcd_read_proc, NULL); + if (!proc_clcd) { + EPRINTK("can't create /proc/cobalt/lcd\n"); + } +#endif + +#ifdef CONFIG_COBALT_LCD_TWIDDLE + cobalt_lcd_start_twiddle(); +#endif + + /* register panic notifier */ + lcd_nb.notifier_call = cobalt_lcd_panic; + lcd_nb.next = NULL; + lcd_nb.priority = 0; + + atomic_notifier_chain_register( &panic_notifier_list, &lcd_nb ); + + return 0; +} + +#endif /* CONFIG_COBALT_LCD */ diff -Nurb linux-2.6.24.3/drivers/cobalt/led.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/led.c --- linux-2.6.24.3/drivers/cobalt/led.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/led.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,502 @@ + /* + * $Id: led.c,v 1.36 2002/05/10 18:44:45 duncan Exp $ + * led.c : driver for Cobalt LEDs + * + * Copyright 1996-2000 Cobalt Networks, Inc. + * Copyright 2001 Sun Microsystems, Inc. + * + * By: Andrew Bose + * Timothy Stonis + * Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * Modified By: jeff@404ster.com + * + * This should be SMP safe. There is one definite critical region: the + * handler list (led_handler_lock). The led_state is protected by led_lock, + * so should be safe against simultaneous writes. Bit banging of lights is + * currently also a protected region (led_lock, rather than add a new lock). + */ + +#ifdef CONFIG_COBALT_LED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LED_DRIVER "Cobalt Networks LED driver" +#define LED_DRIVER_VMAJ 1 +#define LED_DRIVER_VMIN 0 + +/* the rate at which software controlled frontpanel LEDs blink */ +#define FPLED_DEFAULT_HZ (HZ/20) + +/* + * This is the abstracted state of active LEDs - see the defines for LED_* + * LED masks are always 'unsigned int'. You must hold led_lock to muck with + * these. + */ +static unsigned int led_state; +static unsigned int led_blips; + +/* leds are PCI on genIII */ +static struct pci_dev *led_dev; +/* on XTR the front panel LEDs are software controlled */ +struct led_handler { + unsigned int (*function)(void *); + void *data; + struct led_handler *next; + struct led_handler *prev; +}; +struct led_handler *led_handler_list; +static spinlock_t led_handler_lock = SPIN_LOCK_UNLOCKED; +static struct timer_list timer; + +static spinlock_t led_lock = SPIN_LOCK_UNLOCKED; + +/* + * RaQ 3 + * RaQ 4 + * Qube 3 + */ +#define RAQ3_SHUTLOGO_ADDR 0x7e +#define RAQ3_SHUTDOWN_OFF 0x40 /* reverse polarity */ +#define RAQ3_COBALTLOGO_ON 0x80 +#define QUBE3_LIGHTBAR_ON 0xc0 /* direct polarity */ +#define RAQ3_WEBLIGHT_ADDR 0xb8 +#define RAQ3_WEBLIGHT_ON 0x80 + +/* + * RaQ XTR + */ +#define MONTEREY_FPLED00 0x8000 +#define MONTEREY_FPLED01 0x4000 +#define MONTEREY_FPLED02 0x2000 +#define MONTEREY_FPLED03 0x0200 +#define MONTEREY_FPLED04 0x0080 +#define MONTEREY_FPLED05 0x0040 +#define MONTEREY_FPLED10 0x1000 +#define MONTEREY_FPLED11 0x0800 +#define MONTEREY_FPLED12 0x0400 +#define MONTEREY_FPLED13 0x0100 +#define MONTEREY_FPLED14 0x0020 +#define MONTEREY_FPLED15 0x0010 +#define MONTEREY_FPLED_ETH0_TXRX MONTEREY_FPLED00 +#define MONTEREY_FPLED_ETH0_LINK MONTEREY_FPLED10 +#define MONTEREY_FPLED_ETH1_TXRX MONTEREY_FPLED01 +#define MONTEREY_FPLED_ETH1_LINK MONTEREY_FPLED11 +#define MONTEREY_FPLED_DISK0 MONTEREY_FPLED02 +#define MONTEREY_FPLED_DISK1 MONTEREY_FPLED03 +#define MONTEREY_FPLED_DISK2 MONTEREY_FPLED04 +#define MONTEREY_FPLED_DISK3 MONTEREY_FPLED05 +#define MONTEREY_FPLED_WEB MONTEREY_FPLED12 +#define MONTEREY_LOGOLED_BIT 0x40 +#define MONTEREY_SYSFAULTLED_BIT 0x80 +#define MONTEREY_SLED0 (1<<3) +#define MONTEREY_SLED1 (1<<2) +#define MONTEREY_SLED2 (1<<1) +#define MONTEREY_SLED3 (1<<0) + +/* + * Alpine + */ +#define ALPINE_WEBLED_PORT 0x60e +#define ALPINE_WEBLED_BIT 0x20 +#define ALPINE_POWERLED_PORT 0x50b +#define ALPINE_POWERLED_CFG 0x23 +#define ALPINE_LOGOLED_BIT 0x02 +#define ALPINE_SYSFAULTLED_BIT 0x07 + +/* + * actually set the leds (icky details hidden within) + * this must be protected against itself with led_lock + * */ +static void +__set_led_hw(const unsigned int newstate) +{ + if (cobt_is_pacifica() && led_dev) { + unsigned char tmp; + /* RaQ 3, RaQ 4 + * - shutdown light + * - logo light + * - web light + */ + + /* read the current state of shutdown/logo lights */ + pci_read_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, &tmp); + + /* reverse polarity for shutdown light */ + if (newstate & LED_SHUTDOWN) + tmp &= ~RAQ3_SHUTDOWN_OFF; + else + tmp |= RAQ3_SHUTDOWN_OFF; + + /* logo light is straight forward */ + if (newstate & LED_COBALTLOGO) + tmp |= RAQ3_COBALTLOGO_ON; + else + tmp &= ~RAQ3_COBALTLOGO_ON; + + /* write new shutdown/logo light state */ + pci_write_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, tmp); + + /* read web light state */ + pci_read_config_byte(led_dev, RAQ3_WEBLIGHT_ADDR, &tmp); + if (newstate & LED_WEBLIGHT) { + tmp |= RAQ3_WEBLIGHT_ON; + } else { + tmp &= ~RAQ3_WEBLIGHT_ON; + } + + /* write new web light state */ + pci_write_config_byte(led_dev, RAQ3_WEBLIGHT_ADDR, tmp); + } else if (cobt_is_carmel() && led_dev) { + unsigned char tmp; + /* Qube 3 + * - no shutdown light + * - lightbar instead of logo + * - no web led (wired to 2nd IDE reset for staggered startup) + */ + + /* read the current state of lightbar */ + pci_read_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, &tmp); + if (newstate & LED_COBALTLOGO) { + tmp |= QUBE3_LIGHTBAR_ON; + } else { + tmp &= ~QUBE3_LIGHTBAR_ON; + } + + /* write new lightbar state */ + pci_write_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, tmp); + } else if (cobt_is_monterey()) { + unsigned int tmp = 0; + u8 val; + unsigned long flags; + + if (newstate & LED_WEBLIGHT) { + tmp |= MONTEREY_FPLED_WEB; + } + if (newstate & LED_ETH0_TXRX) { + tmp |= MONTEREY_FPLED_ETH0_TXRX; + } + if (newstate & LED_ETH0_LINK) { + tmp |= MONTEREY_FPLED_ETH0_LINK; + } + if (newstate & LED_ETH1_TXRX) { + tmp |= MONTEREY_FPLED_ETH1_TXRX; + } + if (newstate & LED_ETH1_LINK) { + tmp |= MONTEREY_FPLED_ETH1_LINK; + } + if (newstate & LED_DISK0) { + tmp |= MONTEREY_FPLED_DISK0; + } + if (newstate & LED_DISK1) { + tmp |= MONTEREY_FPLED_DISK1; + } + if (newstate & LED_DISK2) { + tmp |= MONTEREY_FPLED_DISK2; + } + if (newstate & LED_DISK3) { + tmp |= MONTEREY_FPLED_DISK3; + } + /* 3 LED's are unused on Monterey, but we support them */ + if (newstate & LED_MONTEREY_UNUSED0) { + tmp |= MONTEREY_FPLED13; + } + if (newstate & LED_MONTEREY_UNUSED1) { + tmp |= MONTEREY_FPLED14; + } + if (newstate & LED_MONTEREY_UNUSED2) { + tmp |= MONTEREY_FPLED15; + } + /* I2C controlled front-panel lights */ + cobalt_i2c_write_byte(COBALT_I2C_DEV_LED_I, 0, tmp & 0xff); + cobalt_i2c_write_byte(COBALT_I2C_DEV_LED_II, 0, tmp >> 8); + + /* drive sled LEDs are on a different i2c device */ + tmp = 0xf0; /* high nibble means something else */ + if (newstate * LED_SLED0) + tmp |= MONTEREY_SLED0; + if (newstate * LED_SLED1) + tmp |= MONTEREY_SLED1; + if (newstate * LED_SLED2) + tmp |= MONTEREY_SLED2; + if (newstate * LED_SLED3) + tmp |= MONTEREY_SLED3; + cobalt_i2c_write_byte(COBALT_I2C_DEV_RULER, 0, tmp); + + /* sysfault and logo are in APC page of nvram */ + spin_lock_irqsave(&rtc_lock, flags); + superio_set_rtc_bank(PC87317_RTC_BANK_APC); + val = CMOS_READ(PC87317_APCR4); + + /* reverse polarity */ + if (newstate & LED_COBALTLOGO) { + val &= ~MONTEREY_LOGOLED_BIT; /* logo is on */ + } else { + val |= MONTEREY_LOGOLED_BIT; /* logo is off */ + } + + if (newstate & LED_SYSFAULT) { + val |= MONTEREY_SYSFAULTLED_BIT; + } else { + val &= ~MONTEREY_SYSFAULTLED_BIT; + } + + CMOS_WRITE(val, PC87317_APCR4); + superio_set_rtc_bank(PC87317_RTC_BANK_MAIN); + spin_unlock_irqrestore(&rtc_lock, flags); + } else if (cobt_is_alpine()) { + unsigned char val; + + /* web LED is reverse polarity */ + val = inb(ALPINE_WEBLED_PORT); + if (newstate & LED_WEBLIGHT) { + val &= ~ALPINE_WEBLED_BIT; + } else { + val |= ALPINE_WEBLED_BIT; + } + outb(val, ALPINE_WEBLED_PORT); + + /* + * the power led is controled by switching the pin between + * a GPIO pin (on) and a LED pin (off) + */ + + outb( ALPINE_POWERLED_CFG, 0x2e ); + val = inb( 0x2f ); + if (newstate & LED_COBALTLOGO) { + val &= ~ALPINE_LOGOLED_BIT; + } else { + val |= ALPINE_LOGOLED_BIT; + } + outb( val, 0x2f ); + + if (newstate & LED_SYSFAULT) { + val = ALPINE_SYSFAULTLED_BIT; + } else { + val = 0; + } + + outb(val, ALPINE_POWERLED_PORT); + } +} + +/* blip the front panel leds */ +static void +led_timer_func(unsigned long data) +{ + unsigned int leds = 0; + struct led_handler *p; + unsigned long flags; + + /* call all registered callbacks */ + spin_lock_irqsave(&led_handler_lock, flags); + for (p = led_handler_list; p; p = p->next) { + leds |= p->function(p->data); + } + spin_unlock_irqrestore(&led_handler_lock, flags); + + /* set the led hardware */ + spin_lock_irqsave(&led_lock, flags); + __set_led_hw(led_state | leds | led_blips); + led_blips = 0; + spin_unlock_irqrestore(&led_lock, flags); + + /* re-arm ourself */ + mod_timer(&timer, jiffies + FPLED_DEFAULT_HZ); +} + +static void +__cobalt_led_set(const unsigned int leds) +{ + led_state = leds; + __set_led_hw(leds); +} + +void +cobalt_led_set(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set(leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_set_bits(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set(led_state | leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_clear_bits(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set(led_state & ~leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +static void +__cobalt_led_set_lazy(const unsigned int leds) +{ + /* the next led timer run will catch these changes */ + led_state = leds; + /* remember lights that were 'blipped' to force an edge */ + led_blips |= leds; +} + +void +cobalt_led_set_lazy(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set_lazy(leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_set_bits_lazy(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set_lazy(led_state | leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +void +cobalt_led_clear_bits_lazy(const unsigned int leds) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + __cobalt_led_set_lazy(led_state & ~leds); + spin_unlock_irqrestore(&led_lock, flags); +} + +unsigned int +cobalt_led_get(void) +{ + unsigned int r; + unsigned long flags; + + spin_lock_irqsave(&led_lock, flags); + r = led_state; + spin_unlock_irqrestore(&led_lock, flags); + + return r; +} + +int +cobalt_fpled_register(unsigned int (*function)(void *), void *data) +{ + struct led_handler *newh; + unsigned long flags; + + newh = kmalloc(sizeof(*newh), GFP_ATOMIC); + if (!newh) { + EPRINTK("can't allocate memory for handler %p(%p)\n", + function, data); + return -1; + } + + spin_lock_irqsave(&led_handler_lock, flags); + + /* head insert */ + newh->function = function; + newh->data = data; + newh->next = led_handler_list; + newh->prev = NULL; + if (led_handler_list) { + led_handler_list->prev = newh; + } + led_handler_list = newh; + + spin_unlock_irqrestore(&led_handler_lock, flags); + + return 0; +} + +int +cobalt_fpled_unregister(unsigned int (*function)(void *), void *data) +{ + int r = -1; + struct led_handler *p; + unsigned long flags; + + spin_lock_irqsave(&led_handler_lock, flags); + + for (p = led_handler_list; p; p = p->next) { + if (p->function == function && p->data == data) { + if (p->prev) { + p->prev->next = p->next; + } + if (p->next) { + p->next->prev = p->prev; + } + r = 0; + break; + } + } + + spin_unlock_irqrestore(&led_handler_lock, flags); + + return r; +} + +int __init +cobalt_led_init(void) +{ + unsigned int leds = LED_SHUTDOWN | LED_COBALTLOGO; + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", LED_DRIVER,LED_DRIVER_VMAJ,LED_DRIVER_VMIN); + + if (cobt_is_3k()) { + /* LEDs for RaQ3/4 and Qube3 are on the PMU */ + led_dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!led_dev) { + EPRINTK("can't find PMU for LED control\n"); + return -1; + } + } + + /* setup up timer for fp leds */ + init_timer(&timer); + timer.expires = jiffies + FPLED_DEFAULT_HZ; + timer.data = 0; + timer.function = &led_timer_func; + add_timer(&timer); + + /* set the initial state */ + leds |= cobalt_cmos_read_flag(COBT_CMOS_SYSFAULT_FLAG) ? + LED_SYSFAULT : 0; + led_state = leds; + __set_led_hw(leds); + + return 0; +} + +#endif /* CONFIG_COBALT_LED */ diff -Nurb linux-2.6.24.3/drivers/cobalt/Makefile linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Makefile --- linux-2.6.24.3/drivers/cobalt/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Makefile 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,18 @@ +# +# Makefile for the Sun/Cobalt device drivers +# + +#O_TARGET := cobalt.o + +#export-objs := init.o systype.o wdt.o i2c.o + +obj-$(CONFIG_COBALT_RAQ) += init.o systype.o i2c.o wdt.o +obj-$(CONFIG_COBALT_ACPI) += acpi.o +obj-$(CONFIG_COBALT_SERNUM) += serialnum.o +obj-$(CONFIG_COBALT_LCD) += lcd.o +obj-$(CONFIG_COBALT_LED) += net.o led.o +obj-$(CONFIG_COBALT_SENSORS) += sensors.o +obj-$(CONFIG_COBALT_FANS) += fans.o +obj-$(CONFIG_COBALT_RAMINFO) += raminfo.o +obj-$(CONFIG_COBALT_RULER) += ruler.o +obj-$(CONFIG_COBALT_POWERMODE) += powermode.o diff -Nurb linux-2.6.24.3/drivers/cobalt/net.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/net.c --- linux-2.6.24.3/drivers/cobalt/net.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/net.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,132 @@ +/* + * cobalt net wrappers + * Copyright (c) 2000, Cobalt Networks, Inc. + * Copyright (c) 2001, Sun Microsystems, Inc. + * $Id: net.c,v 1.11 2001/10/27 00:40:24 thockin Exp $ + * author: thockin@sun.com + * + * This should be SMP safe. The only critical data is the list of devices. + * The LED handler runs at timer-interrupt, so we must use the IRQ safe forms + * of the locks. --TPH + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_COBT_NETDEVS 2 +static struct net_device *netdevs[MAX_COBT_NETDEVS]; +static int n_netdevs; +static spinlock_t cobaltnet_lock = SPIN_LOCK_UNLOCKED; + +#if defined(CONFIG_COBALT_LED) +static unsigned int +net_led_handler(void *data) +{ + int i; + unsigned int leds = 0; + static int txrxmap[MAX_COBT_NETDEVS] = {LED_ETH0_TXRX, LED_ETH1_TXRX}; + static int linkmap[MAX_COBT_NETDEVS] = {LED_ETH0_LINK, LED_ETH1_LINK}; + unsigned long flags; + static unsigned long net_old[MAX_COBT_NETDEVS]; + + spin_lock_irqsave(&cobaltnet_lock, flags); + + for (i = 0; i < n_netdevs; i++) { + unsigned long txrxstate; + struct net_device *dev = netdevs[i]; + if (!dev) { + continue; + } + /* check for link */ + if (netif_running(dev) && netif_carrier_ok(dev)) { + leds |= linkmap[i]; + } + /* check for tx/rx */ + txrxstate = dev->trans_start ^ dev->last_rx; + if (txrxstate != net_old[i]) { + leds |= txrxmap[i]; + net_old[i] = txrxstate; + } + } + + spin_unlock_irqrestore(&cobaltnet_lock, flags); + + return leds; +} +#endif + +/* + * We try to be VERY explicit here. Fine for now, may eventually break down. + */ +void +cobalt_net_register(struct net_device *ndev) +{ + unsigned long flags; + int i; + + if (!ndev) { + return; + } + + /* we'll track the first MAX_COBT_NETDEVS NICs */ + if (n_netdevs >= MAX_COBT_NETDEVS) { + return; + } + + spin_lock_irqsave(&cobaltnet_lock, flags); + + /* find a free slot */ + for (i = 0; i < MAX_COBT_NETDEVS; i++) { + if (!netdevs[i]) { + netdevs[i] = ndev; + n_netdevs++; + break; + } + } + + spin_unlock_irqrestore(&cobaltnet_lock, flags); +} + +void +cobalt_net_unregister(struct net_device *ndev) +{ + int i; + unsigned long flags; + + if (!ndev) { + return; + } + + spin_lock_irqsave(&cobaltnet_lock, flags); + + /* try to remove it from the list */ + for (i = 0; i < MAX_COBT_NETDEVS; i++) { + if (netdevs[i] == ndev) { + netdevs[i] = NULL; + n_netdevs--; + break; + } + } + + spin_unlock_irqrestore(&cobaltnet_lock, flags); +} + +int __init +cobalt_net_init(void) +{ +#if defined(CONFIG_COBALT_LED) + /* register an LED handler */ + cobalt_fpled_register(net_led_handler, NULL); +#endif + + return 0; +} diff -Nurb linux-2.6.24.3/drivers/cobalt/powermode.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/powermode.c --- linux-2.6.24.3/drivers/cobalt/powermode.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/powermode.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,279 @@ +/* + * $Id: powermode.c,v 1.17 2007/02/20 23:14:23 illogical Exp $ + * + * Copyright (c) 2001, Sun Microsystems, Inc. + * All Rights Reserved + * + * Port of powermode functionality from sysctl.c + */ + +#if defined (CONFIG_COBALT_POWERMODE) || defined (MODULE) + +//#include +//#include +#include +#include +//#include + +#include +#include +#include +//#include +#include +#include +#include + +static int cobalt_powermode_status; + +static int set_powermode (void); +static void get_powermode (void); +static int cobalt_powermode_fail (const int set, const int val); +static int cobalt_powermode_apply (const int set, const int val); + +#define POWERMODE_DRIVER "Cobalt Networks Powermode driver" +#define POWERMODE_DRIVER_VMAJ 1 +#define POWERMODE_DRIVER_VMIN 0 + +struct proc_dir_entry *cobalt_powermode_proc; + +int __init cobalt_powermode_init (void) { + printk (KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", POWERMODE_DRIVER, POWERMODE_DRIVER_VMAJ, POWERMODE_DRIVER_VMIN); + if (cobt_is_monterey ()) { + printk (KERN_INFO " NOTE: Monterey systems do not support the powermode \"on\"\n"); + } else if (cobt_is_3k ()) { + EPRINTK ("No support for GenIII systems!\n"); + return -ENOENT; + } + + cobalt_powermode_proc = create_proc_entry ("powermode", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt); + if (! cobalt_powermode_proc) { + EPRINTK ("Cannot create /proc/cobalt/powermode\n"); + return -ENOENT; + } + cobalt_powermode_proc->owner = THIS_MODULE; + cobalt_powermode_proc->write_proc = cobalt_powermode_write_proc; + cobalt_powermode_proc->read_proc = cobalt_powermode_read_proc; + return 0; +} + +void __exit cobalt_powermode_exit (void) { + if (cobalt_powermode_proc) { + remove_proc_entry ("powermode", proc_cobalt); + cobalt_powermode_proc = NULL; + } +} + +int cobalt_powermode_read_proc (char *buf, char **st, off_t off, int len, int *eof, void *x) { + int rlen; + + get_powermode (); + + rlen = 0; + if (cobalt_powermode_status == COBALT_POWER_ON) { + rlen += sprintf(buf + rlen, "on\n"); + } else if (cobalt_powermode_status == COBALT_POWER_OFF) { + rlen += sprintf(buf + rlen, "off\n"); + } else if (cobalt_powermode_status == COBALT_POWER_SAME) { + rlen += sprintf(buf + rlen, "same\n"); + } else { + rlen += sprintf(buf + rlen, "uknown\n"); + } + return cobalt_gen_proc_read(buf, rlen, st, off, len, eof); +} + +int cobalt_powermode_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { + int len, set_ret; + char *p; + char buf [9]; + enum cobalt_powermode val; + + if (count > 8) + len = 8; + else + len = count; + + if (copy_from_user (buf, buffer, len)) { + return -EFAULT; + } + buf [len] = '\0'; + + val = simple_strtol(buf, &p, 0); + if (p != buf) { + if ((val < 1) || (val > 3)) { + return -EINVAL; + } + cobalt_powermode_status = val; + } else { + if (buf [len - 1] == '\n') + buf [len - 1] = '\0'; + if (! strcmp (buf, "on")) { + cobalt_powermode_status = COBALT_POWER_ON; + } else if (! strcmp (buf, "off")) { + cobalt_powermode_status = COBALT_POWER_OFF; + } else if (! strcmp (buf, "same")) { + cobalt_powermode_status = COBALT_POWER_SAME; + } else { + return -EINVAL; + } + } + set_ret = set_powermode (); + if (set_ret != 0) { + return set_ret; + } + return len; +} + +static int set_powermode (void) { + int r0,r1; + int fail, apply; + + r0 = 0; r1 = 0; + + fail = cobalt_powermode_fail (0, 0); + apply = cobalt_powermode_apply (0, 0); + + switch (cobalt_powermode_status) { + case COBALT_POWER_ON: + r0 = cobalt_powermode_fail (1, 1); + r1 = cobalt_powermode_apply (1, 1); + break; + case COBALT_POWER_OFF: + r0 = cobalt_powermode_fail (1, 0); + r1 = cobalt_powermode_apply (1, 0); + break; + case COBALT_POWER_SAME: + r0 = cobalt_powermode_fail (1, 1); + r1 = cobalt_powermode_apply (1, 0); + break; + } + + if (r0 < 0 || r1 < 0) { + cobalt_powermode_fail (1, fail); + cobalt_powermode_apply (1, apply); + return -EINVAL; + } + return 0; +} + +static void get_powermode (void) { + int fail, apply; + + fail = cobalt_powermode_fail (0, 0); + apply = cobalt_powermode_apply (0, 0); + + if (fail && apply) { + cobalt_powermode_status = COBALT_POWER_ON; + } else if (! fail && ! apply) { + cobalt_powermode_status = COBALT_POWER_OFF; + } else if (fail && ! apply) { + cobalt_powermode_status = COBALT_POWER_SAME; + } else { + + } +} + +static int cobalt_powermode_fail (const int set, const int val) { + int r = 0; + if (cobt_is_monterey ()) { + u8 reg; + unsigned long flags; + + spin_lock_irqsave (&rtc_lock, flags); + superio_set_rtc_bank (PC87317_RTC_BANK_APC); + reg = CMOS_READ (PC87317_APCR6); + r = reg & 0x80 ? 0 : 1; + if (set) { + if (val) { + reg &= ~0xc0; + } else { + reg |= 0x80; + } + CMOS_WRITE (reg, PC87317_APCR6); + } + superio_set_rtc_bank (PC87317_RTC_BANK_MAIN); + spin_unlock_irqrestore (&rtc_lock, flags); + } else if (cobt_is_alpine ()) { + u16 addr; + u8 reg; + + addr = superio_ldev_base (PC87417_DEV_SWC); + reg = inb (addr + PC87417_SWC_PWONCTL); + r = reg & 0x20 ? 1 : 0; + if (set) { + if (val) { + reg |= 0x20; + } else { + reg &= ~0x20; + } + outb (reg, addr + PC87417_SWC_PWONCTL); + } + } + return r; +} + +#define NS_GP1_EN0_PME2_E 0x02 +#define NS_EVENT_WAKEUP_S345 0x03 +static int cobalt_powermode_apply (const int set, const int val) { + int r = 0; + if (cobt_is_monterey ()) { +#if 0 /* not supported on monterey hardware */ + u8 reg; + u16 pmaddr; + u16 gpeaddr; + + /* figure out the PM base address */ + pmaddr = superio_ldev_base (PC87317_DEV_PM); + /* figure out the GPE base address */ + outb (PC87317_PMDEV_GPELO, pmaddr); + gpeaddr = inb (pmaddr + 1); + outb (PC87317_PMDEV_GPEHI, pmaddr); + gpeaddr |= inb (pmaddr + 1) << 8; + + reg = inb (gpeaddr + PC87317_GPE_GP1_EN0); + r = (reg & NS_GP1_EN0_PME2_E) ? 1 : 0; + if (set) { + if (val) { + reg |= NS_GP1_EN0_PME2_E; + } else { + reg &= ~NS_GP1_EN0_PME2_E; + } + outb (reg, gpeaddr + PC87317_GPE_GP1_EN0); + } +#endif + if (set && val) { + return -1; + } else { + return 0; + } + } else if (cobt_is_alpine ()) { + u16 pmaddr; + u8 reg; + + /* power event is attached to GPIOE42 */ + pmaddr = superio_ldev_base (PC87417_DEV_SWC); + outb (PC87417_SWCWKEVENT_GPIOE42, pmaddr + PC87417_SWC_WKEVENT); + reg = inb (pmaddr + PC87417_SWC_WKSTATE); + r = reg & NS_EVENT_WAKEUP_S345 ? 1 : 0; + if (set) { + if (val) { + reg |= NS_EVENT_WAKEUP_S345; + } else { + /* disable wakeup */ + reg &= ~NS_EVENT_WAKEUP_S345; + } + outb (reg, pmaddr + PC87417_SWC_WKSTATE); + } + } + return r; +} + +//#ifdef MODULE +//module_init (cobalt_powermode_init); +//module_exit (cobalt_powermode_exit); +//#endif + +//MODULE_AUTHOR ("Sun Cobalt"); +//MODULE_DESCRIPTION ("Power State Storage"); +//MODULE_LICENSE ("GPL"); + +#endif diff -Nurb linux-2.6.24.3/drivers/cobalt/raminfo.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/raminfo.c --- linux-2.6.24.3/drivers/cobalt/raminfo.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/raminfo.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,318 @@ +/* $Id: raminfo.c,v 1.7 2001/10/29 22:21:36 thockin Exp $ + * + * Copyright (c) 2000-2001 Sun Microsystems, Inc. + * All Rights Reserved. + * + * This is SMP safe - the init runs once on load, and the rest is just + * printing information. --TPH + */ +#if defined(CONFIG_COBALT_RAMINFO) || defined(CONFIG_COBALT_RAMINFO_MODULE) + +#include +#include +#include +#include + +#include +#include + +#define RAM_DRIVER "Cobalt Networks RAM Info driver" +#define RAM_DRIVER_VMAJ 1 +#define RAM_DRIVER_VMIN 0 + +#define MAX_DIMM_SLOTS 4 + +enum dimm_t { + DIMM_TYPE_FPM_DRAM, + DIMM_TYPE_EDO_DRAM, + DIMM_TYPE_REG_SDRAM, + DIMM_TYPE_SDRAM +}; + +static char *dimm_desc[] = { + "Fast-page Mode DRAM", + "EDO DRAM", + "Registered SDRAM", + "SDRAM", +}; + +struct dimm_slot { + int num; + enum dimm_t type; + uint16_t size; + int ecc; +}; + +struct raminfo { + int total; + int (*query)(struct dimm_slot *); + struct pci_dev *dev; + struct dimm_slot *dimm; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc; +#endif /* CONFIG_PROC_FS */ +}; + +/*########################################################################*/ + +static int serverworks_le_dimm_info(struct dimm_slot *); +static int ali_1541_dimm_info(struct dimm_slot *); +static int raminfo_read_proc(char*, char**, off_t, int, int*, void*); + +/* RaQ-3, RaQ-4, Qube-3 + * - uses ALI M1541 for memory controller + * - has 2 dimm slots */ +static struct raminfo gen3_raminfo = { + total: 2, + query: ali_1541_dimm_info +}; +/* RaQ-XTR (Monterey) + * - uses ServerWorks CNB30LE for Memory Controller + * - has 4 dimm slots */ +static struct raminfo gen5_monterey_raminfo = { + total: 4, + query: serverworks_le_dimm_info +}; +/* RaQ (Alpine) + * - uses ServerWorks CNB30LE for Memory Controller + * - has 2 dimm slots */ +static struct raminfo gen5_alpine_raminfo = { + total: 2, + query: serverworks_le_dimm_info +}; + +static struct raminfo *sys_raminfo; + +/*########################################################################*/ + +#define SERVERWORKS_DRAM_MRPR (0x90) +#define SERVERWORKS_DRAM_MRAR(slot) (0x7c + (slot)) +#define SERVERWORKS_DRAM_ECCR (0xe0) + +static int +serverworks_le_dimm_info(struct dimm_slot *dimm) +{ + int row; + uint8_t rar, active, eccr; + uint16_t ma_map[] = { + 32, 16, 32, 256, 512, 128, 128, 64, 256, 128, 64, 64, 128, + }; + + if (!sys_raminfo || !sys_raminfo->dev || !dimm) + return -ENOSYS; + + pci_read_config_byte(sys_raminfo->dev, + SERVERWORKS_DRAM_MRPR, &active); + pci_read_config_byte(sys_raminfo->dev, + SERVERWORKS_DRAM_MRAR(dimm->num), &rar); + + /* serverworks uses only registered sdram */ + dimm->type = DIMM_TYPE_REG_SDRAM; + dimm->size = 0; + + /* check to see if ECC is enabled (bit 4 of reg 0xE0) */ + pci_read_config_byte(sys_raminfo->dev, + SERVERWORKS_DRAM_ECCR, &eccr); + dimm->ecc = (eccr & (1<<2)) ? 1 : 0; + + /* two rows for each dimm slot */ + for (row=2*dimm->num; row<=(2*dimm->num+1); row++) { + /* each active row will have corresponding bit + * set in the Memory Row Presence Register */ + if (active & (1 << row)) { + /* lookup size ma_map table */ + dimm->size += ma_map[ rar & 0xf ]; + } + /* two rows per RAR register, bits 7-4 and bits 3-0 */ + rar >>= 4; + } + + return 0; +} + +#define ALI_DRAM_CONF_1(row) (0x60 + ((row) * 2)) +#define ALI_DRAM_CONF_2(row) (0x61 + ((row) * 2)) +#define ALI_DIMM_TYPE(d2) (((d2) >> 4) & 0x3) +#define ALI_DIMM_MMAP(d2) (((d2) >> 6) & 0x3) +#define ALI_DIMM_SIZE(d1, d2) (((((d2) & 0xf) << 8) | (d1)) + 1) + +static int +ali_1541_dimm_info(struct dimm_slot *dimm) +{ + int row; + uint8_t dbc1, dbc2; + + if (!sys_raminfo || !sys_raminfo->dev || !dimm) + return -ENOSYS; + + dimm->size = 0; + dimm->ecc = 0; + + /* read two rows per dimm (for double-side) */ + for (row=2*dimm->num; row<=(2*dimm->num + 1); row++) { + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_2(row), &dbc2); + + /* row is empty iff dimm type and ma_map are both 0 */ + if (!ALI_DIMM_TYPE(dbc2) && !ALI_DIMM_MMAP(dbc2)) + continue; + + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_1(row), &dbc1); + + /* type is bits 4-5 of dimm conf reg 2 */ + dimm->type = ALI_DIMM_TYPE(dbc2); + + /* A27-A20 address lines are bits 7-0 of dimm conf reg 1 + * A31-A28 address lines are bits 3-0 of dimm conf reg 2 */ + dimm->size = ALI_DIMM_SIZE(dbc1, dbc2); + } + + /* the M1541 uses "not less than" policy to determine which row a + * memory address resides in. the top address boundary for each + * row is the maximum memory value minus 1. so to determine the + * size of a row you must subtract the size of the previous row. + * (unless this is slot 0 or the first populated slot) */ + if (dimm->num > 0 && dimm->size > 0) { + uint16_t sz; + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_1(2*dimm->num - 1), &dbc1); + pci_read_config_byte(sys_raminfo->dev, + ALI_DRAM_CONF_2(2*dimm->num - 1), &dbc2); + sz = ALI_DIMM_SIZE(dbc1, dbc2); + dimm->size -= (sz > 1) ? sz : 0; + } + + return 0; +} + +int __init +cobalt_raminfo_init(void) +{ + int j; + + /* determine system type and find memory controller pci dev + * so we don't have to do pci lookup for each proc read */ + if (cobt_is_3k()) { + sys_raminfo = &gen3_raminfo; + sys_raminfo->dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M1541, NULL); + } else if (cobt_is_5k()) { + if (cobt_is_monterey()) { + sys_raminfo = &gen5_monterey_raminfo; + } else if (cobt_is_alpine()) { + sys_raminfo = &gen5_alpine_raminfo; + } else { + EPRINTK("unable to identify gen5 board\n"); + return -ENOSYS; + } + sys_raminfo->dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_LE, NULL); + } + + if (!sys_raminfo || !sys_raminfo->dev) { + EPRINTK("unable to identify system type\n"); + return -ENOSYS; + } + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", RAM_DRIVER,RAM_DRIVER_VMAJ,RAM_DRIVER_VMIN); + +#ifdef CONFIG_PROC_FS + /* add entry to /proc filesytem */ + sys_raminfo->proc = create_proc_entry("raminfo", + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt); + if (!sys_raminfo->proc) { + EPRINTK("can't create /proc/cobalt/raminfo\n"); + return -ENOENT; + } + sys_raminfo->proc->owner = THIS_MODULE; + sys_raminfo->proc->write_proc = NULL; + sys_raminfo->proc->read_proc = raminfo_read_proc; +#endif /* CONFIG_PROC_FS */ + + /* create arrary of dimm slots to store info */ + sys_raminfo->dimm = kmalloc( + sys_raminfo->total * sizeof(struct dimm_slot), GFP_ATOMIC); + if (!sys_raminfo->dimm) { + EPRINTK("unable to allocate memory\n"); +#ifdef CONFIG_PROC_FS + if (sys_raminfo->proc) { + remove_proc_entry("raminfo", proc_cobalt); + sys_raminfo->proc = NULL; + } +#endif /* CONFIG_PROC_FS */ + return -ENOMEM; + } + + { + struct dimm_slot *ds = sys_raminfo->dimm; + for (j=0; jtotal; j++, ds++) { + if (!ds) continue; + ds->num = j; + if (sys_raminfo->query(ds) < 0) { + EPRINTK("unable to read dimm %d\n", j); + ds->num = -1; + } + } + } + + return 0; +} + +static void __exit +cobalt_raminfo_exit(void) +{ +#ifdef CONFIG_PROC_FS + if (sys_raminfo->proc) { + remove_proc_entry("raminfo", proc_cobalt); + sys_raminfo->proc = NULL; + } +#endif /* CONFIG_PROC_FS */ + + if (sys_raminfo->dimm) { + kfree(sys_raminfo->dimm); + sys_raminfo->dimm = NULL; + } + + sys_raminfo->dev = NULL; + sys_raminfo = NULL; +} + +#ifdef CONFIG_PROC_FS +static int +raminfo_read_proc(char *buf, char **st, off_t off, int len, int *eof, void *x) +{ + int rlen, i; + struct dimm_slot *ds; + + if (!sys_raminfo) + return -ENOSYS; + + //MOD_INC_USE_COUNT; + + ds = sys_raminfo->dimm; + for (rlen=i=0; itotal; i++, ds++) { + if (!ds || ds->num < 0) + continue; + rlen += sprintf(buf+rlen, "%d [%s%s]: %u MB\n", i, + ds->size ? dimm_desc[ds->type] : "Empty", + ds->size ? ds->ecc ? "+ECC" : "" : "", + ds->size); + } + + //MOD_DEC_USE_COUNT; + + return cobalt_gen_proc_read(buf, rlen, st, off, len, eof); +} +#endif /* CONFIG_PROC_FS */ + +#ifdef CONFIG_COBALT_RAMINFO_MODULE +module_init(cobalt_raminfo_init); +module_exit(cobalt_raminfo_exit); +#endif + +MODULE_AUTHOR("Sun Cobalt"); +MODULE_DESCRIPTION("DIMM Information"); +MODULE_LICENSE("GPL"); + +#endif /* CONFIG_COBALT_RAMINFO || CONFIG_COBALT_RAMINFO_MODULE */ diff -Nurb linux-2.6.24.3/drivers/cobalt/README linux-2.6.24.3-cobalt3-tw/drivers/cobalt/README --- linux-2.6.24.3/drivers/cobalt/README 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/README 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,19 @@ +Notes on Cobalt's drivers: + +You will notice in several places constructs such as this: + + if (cobt_is_3k()) { + foo(); + } else if (cobt_is_5k()) { + bar(); + } + +The goal here is to only compile in code that is needed, but to allow one to +define support for both 3k and 5k (and more?) style systems. The systype +check macros are very simple and clean. They check whether config-time +support for the generation has been enabled, and (if so) whether the current +systype matches the spcified generation. This leaves the code free from +#ifdef cruft, but lets the compiler throw out unsupported generation-specific +code with if (0) detection. + +-- diff -Nurb linux-2.6.24.3/drivers/cobalt/ruler.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/ruler.c --- linux-2.6.24.3/drivers/cobalt/ruler.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/ruler.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,418 @@ +/* + * cobalt ruler driver + * Copyright (c) 2000, Cobalt Networks, Inc. + * Copyright (c) 2001, Sun Microsystems, Inc. + * $Id: ruler.c,v 1.23 2002/08/29 00:33:01 uzi Exp $ + * + * author: asun@cobalt.com, thockin@sun.com + * + * This should be SMP safe. There is one critical piece of data, and thus + * one lock. The ruler_lock protects the arrays of channels(hwifs) and + * busproc function pointers. These are only ever written in the + * register/unregister functions but read in several other places. A + * read/write lock is appropriate. The global switches and sled_leds are + * atomic_t. --TPH + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define RULER_TIMEOUT (HZ >> 1) /* .5s */ +#define MAX_COBT_DRIVES 4 + +#define RULER_DRIVER "Cobalt Networks Disk Ruler driver" +#define RULER_DRIVER_VMAJ 1 +#define RULER_DRIVER_VMIN 0 + +/* all of this is for gen V */ +static struct timer_list cobalt_ruler_timer; +static rwlock_t ruler_lock = RW_LOCK_UNLOCKED; +static ide_drive_t *channels[MAX_COBT_DRIVES]; + +static int (*busprocs[MAX_COBT_DRIVES])(ide_drive_t *, int); + +//static cob_busprocs_t busprocs[MAX_COBT_DRIVES]; + +/* NOTE: switches is a bitmask of DETACHED sleds */ +static atomic_t switches = ATOMIC_INIT(0); +static atomic_t sled_leds = ATOMIC_INIT(0); +static int sled_led_map[] = {LED_SLED0, LED_SLED1, LED_SLED2, LED_SLED3}; +static int ruler_detect; +static int initialized; + +static void ruler_hwif_added(ide_hwif_t *hwif, int idx); + +static inline u8 +read_switches(void) +{ + u8 state = 0; + if (cobt_is_monterey()) { + int tries = 3; + + /* i2c can be busy, and this can read wrong - try a few times */ + while (tries--) { + state = cobalt_i2c_read_byte(COBALT_I2C_DEV_DRV_SWITCH, + 0); + if ((state & 0xf0) != 0xf0) { + break; + } + } + } + + return state; +} + +static inline unsigned int +get_sled_leds(void) +{ + return atomic_read(&sled_leds); +} + +/* + * deal with sled leds: LED on means OK to remove + * NOTE: all the reset lines are kept high. + * NOTE: the reset lines are in the reverse order of the switches. + */ +static void +set_sled_leds(unsigned int leds) +{ + if (cobt_is_monterey()) { + unsigned int offed = get_sled_leds(); + + offed &= ~leds; + atomic_set(&sled_leds, leds); +#ifdef CONFIG_COBALT_LED + cobalt_led_clear_bits_lazy(offed); + cobalt_led_set_bits_lazy(leds); +#endif + } +} + +/* this must be called with the ruler_lock held for read */ +static int +do_busproc(int idx, ide_drive_t *drive, int arg) +{ + if (cobt_is_monterey()) { + /* sed sled LEDs */ + switch (arg) { + case BUSSTATE_ON: + set_sled_leds(get_sled_leds() & + ~sled_led_map[idx]); + break; + case BUSSTATE_OFF: + case BUSSTATE_TRISTATE: + set_sled_leds(get_sled_leds() | + sled_led_map[idx]); + break; + default: + WPRINTK("unknown busproc argument (%d)\n", arg); + } + } + + /* do the real work */ + return busprocs[idx](drive, arg); +} + +static void +ruler_timer_fn(unsigned long data) +{ + if (cobt_is_monterey()) { + u8 state; + int i; + unsigned int now, expected, bit, swcur; + + state = read_switches(); + if ((state & 0xf0) == 0xf0) { + return; + } + swcur = atomic_read(&switches); + + state &= 0xf; + read_lock(&ruler_lock); + for (i = 0; i < MAX_COBT_DRIVES; i++) { + bit = 1 << i; + now = state & bit; + expected = swcur & bit; + if (now == expected) { + /* no changes to worry about */ + continue; + } + + if (now) { + /* a freshly detached drive */ + atomic_set(&switches, swcur | bit); + if (channels[i]) { + printk("disabling ide ruler " + "channel %d\n", i); + do_busproc(i, channels[i], + BUSSTATE_TRISTATE); + } else { + WPRINTK("drive detach on bad " + "channel (%d)\n", i); + } + set_sled_leds(get_sled_leds() | + sled_led_map[i]); + } else { + /* + * do we want to do anything when a re-attach + * is detected? + */ + } + } + read_unlock(&ruler_lock); + } +} + +#ifdef CONFIG_COBALT_ACPI +static int +ruler_interrupt(cobalt_acpi_evt *evt, void * data) +{ + if (cobt_is_monterey() && ruler_detect) { + u8 state; + + state = read_switches(); + if ((state & 0xf0) != 0xf0) { + /* this is protected inside mod_timer */ + mod_timer(&cobalt_ruler_timer, jiffies + RULER_TIMEOUT); + } + + evt->ev_data = state; + /* empirical: delay enough to debounce */ + udelay(10); + } + return 0; +} +#endif /* CONFIG_COBALT_ACPI */ + +#if defined(CONFIG_COBALT_LED) +/* figure which LEDs to blink */ +static unsigned int +ide_led_handler(void *data) +{ + ide_hwif_t *hwif; + unsigned int leds = 0; + + if (cobt_is_monterey()) { + int i; + static int ledmap[MAX_COBT_DRIVES] = { + LED_DISK0, LED_DISK1, LED_DISK2, LED_DISK3 + }; + static unsigned long old[MAX_COBT_DRIVES]; + + read_lock(&ruler_lock); + + for (i = 0; i < MAX_COBT_DRIVES; i++) { + if (channels[i]) + { + hwif = HWIF(channels[i]); + if (hwif->drives[0].present && + hwif->drives[0].service_start != old[i]) { + leds |= ledmap[i]; + old[i] = hwif->drives[0].service_start; + } + } + } + + read_unlock(&ruler_lock); + } + + return leds; +} +#endif + +/* this is essentially an exported function - it is in the hwif structs */ +static int ruler_busproc_fn(ide_drive_t *drive, int arg) +{ + int r = 0; + if (cobt_is_monterey()) { + int idx; + + read_lock(&ruler_lock); + + for (idx = 0; idx < MAX_COBT_DRIVES; idx++) { + if (channels[idx] == drive) { + break; + } + } + + if (idx >= MAX_COBT_DRIVES) { + /* not a hwif we manage? */ + return 0; + } + + r = do_busproc(idx, drive, arg); + read_unlock(&ruler_lock); + } + + return r; +} + +/* + * We try to be VERY explicit here. Fine for now, may eventually break down. + */ +void +cobalt_ruler_register(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + + if (cobt_is_monterey()) { + struct pci_dev *dev; + int idx; + unsigned long flags; + + if (!hwif) { + return; + } + + /* Cobalt rulers only have HPT370 controllers on bus 1 */ + dev = hwif->pci_dev; + if (!dev) + return; + + if (dev->vendor != PCI_VENDOR_ID_TTI + || dev->device != PCI_DEVICE_ID_TTI_HPT366 + || dev->bus->number != 1) { + /* ignore it */ + return; + } + + /* IDE ruler has controllers at dev 3 and 4, ONLY */ + if (dev->devfn == PCI_DEVFN(3,0)) { + idx = hwif->channel; + } else if (dev->devfn == PCI_DEVFN(4,0)) { + idx = 2 + hwif->channel; + } else { + return; + } + + if (idx >= MAX_COBT_DRIVES) { + return; + } + + write_lock_irqsave(&ruler_lock, flags); + + /* save a pointer to the hwif, and trap it's busproc() */ + channels[idx] = drive; + if (hwif->busproc) { + busprocs[idx] = HWIF(drive)->busproc; + hwif->busproc = &ruler_busproc_fn; + } + + write_unlock_irqrestore(&ruler_lock, flags); + + /* now that we have trapped it, do what we need to initialize + * the drive - if we haven't been initialized, we'll call this + * later. + */ + if (initialized) { + ruler_hwif_added(hwif, idx); + } + } +} + +static void +ruler_hwif_added(ide_hwif_t *hwif, int idx) +{ + /* the associated switch should be closed */ + if (hwif->drives[0].present) { + /* set the sled LED off - not safe to remove */ + set_sled_leds(get_sled_leds() & ~sled_led_map[idx]); + } +} + +void cobalt_ruler_unregister(ide_drive_t *drive) +{ + if (cobt_is_monterey()) { + int i; + unsigned long flags; + + write_lock_irqsave(&ruler_lock, flags); + + for (i = 0; i < MAX_COBT_DRIVES; i++) { + if (channels[i] == drive) { + channels[i] = NULL; + HWIF(drive)->busproc = busprocs[i]; + busprocs[i] = NULL; + } + } + + write_unlock_irqrestore(&ruler_lock, flags); + } +} + +int __init +cobalt_ruler_init(void) +{ + if (cobt_is_monterey()) { + int err; + u8 tmp; + int i; + + /* initialize switches */ + tmp = read_switches(); + ruler_detect = ((tmp & 0xf0) == 0xf0) ? 0 : 1; + tmp &= 0xf; + atomic_set(&switches, tmp); + + /* initialize our timer */ + init_timer(&cobalt_ruler_timer); + cobalt_ruler_timer.function = ruler_timer_fn; + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", RULER_DRIVER,RULER_DRIVER_VMAJ,RULER_DRIVER_VMIN); + +#ifdef CONFIG_COBALT_ACPI + err = cobalt_acpi_register_evt_handler(ruler_interrupt, + COBALT_ACPI_EVT_SLED, NULL ); + + if (err) { + EPRINTK("can't register interrupt handler %p\n", + ruler_interrupt); + } +#endif + + /* set initial sled LED state */ + set_sled_leds(LED_SLED0 | LED_SLED1 | LED_SLED2 | LED_SLED3); + + /* run through any devices that were registered before */ + for (i = 0; i < MAX_COBT_DRIVES; i++) { + if (channels[i]) { + ruler_hwif_added(HWIF(channels[i]), i); + } + } + +#if defined(CONFIG_COBALT_LED) + /* register for a blinky LEDs callback */ + err = cobalt_fpled_register(ide_led_handler, NULL); + if (err) { + EPRINTK("can't register LED handler %p\n", + ide_led_handler); + } +#endif + } + + initialized = 1; + + return 0; +} diff -Nurb linux-2.6.24.3/drivers/cobalt/sensors.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/sensors.c --- linux-2.6.24.3/drivers/cobalt/sensors.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/sensors.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,523 @@ +/* $Id: sensors.c,v 1.31 2002/08/29 00:33:01 uzi Exp $ + * Copyright (c) 2000-2001 Sun Microsystems, Inc + * + * This should be SMP safe. There is just one race - the read in /proc. + * It now guards against itself with a semaphore. Note that we don't use a + * spinlock because any of the methods may (and do!) block. + */ +#ifdef CONFIG_COBALT_SENSORS + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define SENS_DRIVER "Cobalt Networks Sensor driver" +#define SENS_DRIVER_VMAJ 1 +#define SENS_DRIVER_VMIN 0 + +/* externals */ +unsigned int cobalt_nthermals; +unsigned int cobalt_nvoltages; + +/* data about a sensor for generic handling */ +/* we could add data about a low/high range, if needed */ +struct sensor { + int sensor; /* sensor #, so maps can be logically ordered */ + char *desc; + int last_val; + unsigned long cache; + unsigned long cache_timeout; + /* pre/post hook - 1 for pre, 0 for post */ + void (*setup)(struct sensor *s, int pre); + /* read as an int, to be passed to format() */ + int (*read)(struct sensor *s); + /* hook for scaling values */ + int (*scale)(struct sensor *s, int val); + /* format the value as a string */ + char *(*format)(struct sensor *s, int val, char *buf, int len); +}; + +/* some stuff for generic formatting */ +#define DEC_SCALAR 100 +static char *decimal_format(struct sensor *s, int val, char *buf, int len); + +static DECLARE_MUTEX(sensor_sem); +static struct sensor *therm_map; +static struct sensor *volt_map; + +#define CACHE_DEF 30 + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_csensors; +static struct proc_dir_entry *proc_therm; +static struct proc_dir_entry *proc_volt; +static int therm_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x); +static int therm_write_proc(struct file *file, const char *buf, + unsigned long len, void *x); +static int volt_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x); +static int volt_write_proc(struct file *file, const char *buf, + unsigned long len, void *x); +#endif + +static int lm77_therm_read(struct sensor *s); +static int adm1029_init(void); +static int adm1029_therm_read(struct sensor *s); +static int adm1029_volt_read(struct sensor *s); +static int alpine_vcore_scale(struct sensor *s, int val); +static void alpine_vbat_switch(struct sensor *s, int pre); +static int alpine_vbat_scale(struct sensor *s, int val); + +/* sensor name mappings */ +static struct sensor gen3_therm_map[] = { + {0, "CPU", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, +}; +static struct sensor monterey_therm_map[] = { + {0, "CPU0", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, + {1, "CPU1", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, + {2, "Case0", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, + {3, "Case1", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format}, +}; +static struct sensor alpine_therm_map[] = { + {1, "CPU", 0, 0, CACHE_DEF, NULL, adm1029_therm_read, NULL, decimal_format}, + {0, "Case", 0, 0, CACHE_DEF, NULL, adm1029_therm_read, NULL, decimal_format}, +}; +static struct sensor alpine_volt_map[] = { + {0, "Vcore", 0, 0, CACHE_DEF, NULL, adm1029_volt_read, + alpine_vcore_scale, decimal_format}, + {1, "Vtt", 0, 0, CACHE_DEF, NULL, adm1029_volt_read, NULL, decimal_format}, + {0, "Vbat", 0, 0, CACHE_DEF<<10, alpine_vbat_switch, adm1029_volt_read, + alpine_vbat_scale, decimal_format}, +}; + +int __init +cobalt_sensors_init(void) +{ + if (cobt_is_3k()) { + cobalt_nthermals = 1; + cobalt_nvoltages = 0; + therm_map = gen3_therm_map; + } else if (cobt_is_monterey()) { + cobalt_nthermals = 4; + cobalt_nvoltages = 0; + therm_map = monterey_therm_map; + } else if (cobt_is_alpine()) { + cobalt_nthermals = 2; + cobalt_nvoltages = 3; + therm_map = alpine_therm_map; + volt_map = alpine_volt_map; + adm1029_init(); + } else { + return -1; + } + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", SENS_DRIVER,SENS_DRIVER_VMAJ,SENS_DRIVER_VMIN); + +#ifdef CONFIG_PROC_FS + /* make files in /proc */ + proc_csensors = proc_mkdir("sensors", proc_cobalt); + if (!proc_csensors) { + EPRINTK("can't create /proc/cobalt/sensors\n"); + return -1; + } + if (cobalt_nthermals) { + proc_therm = create_proc_entry("thermal", + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + proc_csensors); + if (!proc_therm) { + EPRINTK("can't create /proc/cobalt/sensors/thermal\n"); + } + proc_therm->read_proc = therm_read_proc; + proc_therm->write_proc = therm_write_proc; + } + if (cobalt_nvoltages) { + proc_volt = create_proc_entry("voltage", + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + proc_csensors); + if (!proc_volt) { + EPRINTK("can't create /proc/cobalt/sensors/voltage\n"); + } + proc_volt->read_proc = volt_read_proc; + proc_volt->write_proc = volt_write_proc; + + } +#endif + + return 0; +} + +static char * +sensor_read(struct sensor *s, char *buf, int len) +{ + int val; + + if (s->cache && time_after(s->cache_timeout*HZ + s->cache, jiffies)) + val = s->last_val; + else { + if (s->setup) s->setup(s, 1); + val = s->read(s); + s->last_val = val; + s->cache = jiffies; + if (s->setup) s->setup(s, 0); + } + + if (s->scale) val = s->scale(s, val); + return s->format(s, val, buf, len); +} + +/* exported - nicer inline functions in header */ +char * +__cobalt_thermal_read(unsigned int idx, char *buf, int len) +{ + if (idx >= cobalt_nthermals || !buf) { + return NULL; + } + + return sensor_read(&therm_map[idx], buf, len); +} + +/* exported - nicer inline functions in header */ +char * +__cobalt_voltage_read(unsigned int idx, char *buf, int len) +{ + if (idx >= cobalt_nvoltages || !buf) { + return NULL; + } + + return sensor_read(&volt_map[idx], buf, len); +} + +/* generic function for formatting decimal scaled data */ +static char * +decimal_format(struct sensor *s, int val, char *buf, int len) +{ + int plen; + + if (!buf || len <= 0) { + return NULL; + } + + plen = snprintf(buf, len, "%d", val/DEC_SCALAR); + len -= plen; + + if (val % DEC_SCALAR && len > 0) { + snprintf(buf+plen, len, ".%02d", val%DEC_SCALAR); + } + + return buf; +} + +#define LM77_TEMP 0x0 +static int +lm77_therm_read(struct sensor *s) +{ + int sensor = s->sensor; + int tmp; + int val = 0; + int tries = 2; + + /* sometimes it reads as zero... try again */ + while (tries--) { + /* LM77 returns the bytes backwards - */ + /* address = base + deviceid + 1 for read */ + val = cobalt_i2c_read_word(COBALT_I2C_DEV_LM77 + + (sensor<<1) + 1, LM77_TEMP); + if (val < 0) { + /* read failed, return the last known value */ + return s->last_val; + } + + tmp = (val<<8 & 0xff00) + (val>>8 & 0x00ff); + if (tmp) { + val = tmp >> 4; + val *= DEC_SCALAR; + if (tmp & 0x8) { + val += DEC_SCALAR/2; + } + break; + } + } + return val; +} + +#define ADM1029_CTL_CFAULT_OVER 0x01 +#define ADM1029_CTL_ALARM_OVER 0x02 +#define ADM1029_CTL_INT_OVER 0x04 +#define ADM1029_CTL_ALARM_LOW 0x08 +#define ADM1029_CTL_CFAULT_UNDER 0x10 +#define ADM1029_CTL_ALARM_UNDER 0x20 +#define ADM1029_CTL_INT_UNDER 0x40 +#define ADM1029_CTL_LATCH 0x80 + +#define ADM1029_FAN_CTL(i) (0x18 + i) +#define ADM1029_TEMP_CTL(i) (0x40 + i) +#define ADM1029_AIN_CTL(i) (0x50 + i) + +#define ADM1029_TEMP_HIGH(i) (0x90 + i) +#define ADM1029_TEMP_LOW(i) (0x98 + i) +#define ADM1029_AIN_HIGH(i) (0xa8 + i) +#define ADM1029_AIN_LOW(i) (0xb0 + i) + +#define ADM1029_TEMP_VALUE(i) (0xa0 + i) +#define ADM1029_AIN_VALUE(i) (0xb8 + i) + +#ifdef CONFIG_COBALT_ACPI +static int +adm1029_handler(cobalt_acpi_evt *evt, void * data) +{ + int j, k; + + switch (evt->ev_type) { + case COBALT_ACPI_EVT_SM_INT: + evt->ev_data = 0; + evt->ev_type = COBALT_ACPI_EVT_VOLT; + for (j=0; jev_data |= (1 << j); + volt_map[j].cache = 0; + } + } + break; + + case COBALT_ACPI_EVT_THERM: + evt->ev_data = 0; + for (j=0; jev_data |= (1 << j); + therm_map[j].cache = 0; + } + } + break; + + default: + return -1; + } + return 0; +} +#endif /* CONFIG_COBALT_ACPI */ + +static int +adm1029_init(void) +{ + +#ifdef CONFIG_COBALT_ACPI + cobalt_acpi_register_evt_handler(adm1029_handler, + COBALT_ACPI_EVT_THERM, NULL); + cobalt_acpi_register_evt_handler(adm1029_handler, + COBALT_ACPI_EVT_SM_INT, NULL); +#endif + + return 0; +} + +static int +adm1029_therm_read(struct sensor *s) +{ + int sensor = s->sensor; + int val; + + val = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_TEMP_VALUE(sensor)); + if (val < 0) { + /* read failed, return the last known value */ + return s->last_val; + } + if (val & 0x80) { + val -= 256; + } + val *= DEC_SCALAR; + + return val; +} + +static int +adm1029_volt_read(struct sensor *s) +{ + int sensor = s->sensor; + int val; + + val = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_AIN_VALUE(sensor)); + if (val < 0) { + /* read failed, return the last known value */ + return s->last_val; + } + + /* already scaled by 100 */ + val *= DEC_SCALAR/100; + + return val; +} + +static int +alpine_vcore_scale(struct sensor *s, int val) +{ + /* the measured Vbat switch cost is negligable + * due to very low current through the diode */ + return val; +} + +#define VBAT_REG 0x608 +#define VBAT_BIT 0x1 +static void +alpine_vbat_switch(struct sensor *s, int pre) +{ + unsigned char v = inb(VBAT_REG); + unsigned long j = jiffies; + + if (pre) { + v |= VBAT_BIT; + /* + * disable AIN0 INT# assertion before switching to + * Vbat because the input is shared with Vcore and + * their acceptable ranges are very different. + */ + cobalt_i2c_write_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_AIN_CTL(s->sensor), 0x0); + } else { + v &= ~VBAT_BIT; + } + + outb(v, VBAT_REG); + + /* + * wait for the round-robin monitor to complete a cycle + * before _and_ after toggling Vbat switch, otherwise + * stale data in AIN0 will trigger INT# assertion. + */ + while ((jiffies - j) < HZ) { + /* block for ~ 1sec */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } + + if (!pre) { + /* + * now re-enable INT# assertion capability for AIN0 + * (this also clears the AIN0 fault latch at bit 7) + */ + cobalt_i2c_write_byte(COBALT_I2C_DEV_ADM1029, + ADM1029_AIN_CTL(s->sensor), + ADM1029_CTL_INT_OVER | ADM1029_CTL_INT_UNDER); + } +} + +static int +alpine_vbat_scale(struct sensor *s, int val) +{ + /* + * The spec says 2.5V max - but empirically, 3.3V works :) + * The Vbat switch costs 0.3 volts + */ + if (val) val += (3 * DEC_SCALAR)/10; + + return val; +} + +#ifdef CONFIG_PROC_FS +static int +sensor_write_proc(int nsensors, struct sensor *map, + struct file *file, const char *buf, unsigned long len, void *x) +{ + char *pg; + + if (len > PAGE_SIZE) { + return -EOVERFLOW; + } + + pg = (char *)__get_free_page(GFP_KERNEL); + if (!pg) { + return -ENOMEM; + } + + if (copy_from_user(pg, buf, len)) { + free_page((unsigned long)pg); + return -EFAULT; + } + pg[len] = '\0'; + + /* format: `cache_timeout #' in seconds */ + if (len>15 && !strncmp("cache_timeout ", pg, 14) && isdigit(*(pg+14))) { + unsigned long i, sec = simple_strtoul(pg+14, NULL, 0); + for (i=0; i= plen) { + *eof = 1; + up(&sensor_sem); + return 0; + } + + plen = 0; + for (i = 0; i < nsensors; i++) { + char sbuf[32]; + if (sensor_read(&map[i], sbuf, sizeof(sbuf))) + plen += sprintf(buf+plen, "%d [%s]: %s\n", i, map[i].desc, sbuf); + } + + up(&sensor_sem); + + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +static int +therm_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + return sensor_read_proc(cobalt_nthermals, therm_map, + buf, start, pos, len, eof, x); +} +static int +therm_write_proc(struct file *file, const char *buf, unsigned long len, void *x) +{ + return sensor_write_proc(cobalt_nthermals, therm_map, file, buf, len, x); +} + +static int +volt_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + return sensor_read_proc(cobalt_nvoltages, volt_map, + buf, start, pos, len, eof, x); +} +static int +volt_write_proc(struct file *file, const char *buf, unsigned long len, void *x) +{ + return sensor_write_proc(cobalt_nvoltages, volt_map, file, buf, len, x); +} +#endif /* CONFIG_PROC_FS */ + +#endif /* CONFIG_COBALT_SENSORS */ diff -Nurb linux-2.6.24.3/drivers/cobalt/serialnum.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/serialnum.c --- linux-2.6.24.3/drivers/cobalt/serialnum.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/serialnum.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,452 @@ +/* $Id: serialnum.c,v 1.15 2001/10/23 20:15:27 thockin Exp $ */ +/* + * + * Author: Philip Gladstone, Axent Technologies + * modified for Nat Semi PC[89]7317 by asun@cobalt.com + * ported to 2.4.x by thockin@sun.com + * alpine serial eeprom by erik.glling@sun.com + * Copyright (c) 2000 Axent Technologies, Cobalt Networks + * Copyright (c) 2001 Axent Technologies, Sun Microsystems + * + * This module interrogates the DS2401 Silicon Serial Number chip + * that is attached to all x86 Cobalt systems. + * + * It exports /proc/cobalt/hostid which is four bytes generated from of + * the id. It can be linked to /var/adm/hostid or /etc/hostid for the + * hostid command to use. + * + * It exports /proc/cobalt/serialnumber which is the entire 64 bit value + * read back (in ascii). + * + * For the guts of the 1 wire protocol used herein, please see the DS2401 + * specification. + * + * 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 + * + * This driver is SMP safe by nature. --TPH + */ +#if defined (CONFIG_COBALT_SERNUM) || defined(CONFIG_COBALT_SERNUM_MODULE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define SN_DRIVER "Cobalt Networks Serial Number driver" +#define SN_DRIVER_VMAJ 1 +#define SN_DRIVER_VMIN 6 + +/* dependent on systype */ +static unsigned int sn_direction; +static unsigned int sn_output; +static unsigned int sn_input; +static unsigned int sn_mask; + +/* 3k style systems */ +#define III_SN_DIRECTION 0x7d +#define III_SN_OUTPUT 0x7e +#define III_SN_INPUT 0x7f +#define III_SN_MASK 0x08 +static struct pci_dev *id_dev; + +/* 5k style systems */ +#define V_SN_DIRECTION (sn_io_base + 0x01) +#define V_SN_OUTPUT (sn_io_base + 0x00) +#define V_SN_INPUT (sn_io_base + 0x00) +#define V_SN_MASK (sn_io_base + 0x01) +static unsigned int sn_io_base; + +#define SSN_SIZE 8 /* bytes */ +static char ssn_string[SSN_SIZE * 2 + 1]; +static unsigned long hostid; +static int debug; +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC +static struct proc_dir_entry *proc_hostid; +static struct proc_dir_entry *proc_serialnum; +#endif +static struct proc_dir_entry *proc_chostid; +static struct proc_dir_entry *proc_cserialnum; +#endif + +static int +hostid_read(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + int plen = sizeof(hostid); + memcpy(buf, &hostid, sizeof(hostid)); + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +static int +serialnum_read(char *buf, char **start, off_t pos, int len, int *eof, void *x) +{ + int plen = sizeof(ssn_string); + sprintf(buf, "%s\n", ssn_string); + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} + +/* set up the requisite IO bits */ +static int __init +io_init(void) +{ + unsigned char data; + + if (cobt_is_3k()) { + /* The GPIO tied to the ID chip is on the PMU */ + id_dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!id_dev) { + EPRINTK("can't find PMU for serialnumber access\n"); + return -ENXIO; + } + + /* Set input mode on GPIO3 */ + pci_read_config_byte(id_dev, sn_direction, &data); + if (debug > 1) { + WPRINTK("read of register 0x%x = 0x%x\n", + sn_direction, data); + } + if (data & sn_mask) { + pci_write_config_byte(id_dev, sn_direction, + data & ~sn_mask); + } + + /* Set the output value to be 0 */ + pci_read_config_byte(id_dev, sn_output, &data); + if (debug > 1) { + WPRINTK("read of register 0x%x = 0x%x\n", + sn_output, data); + } + if (data & sn_mask) { + pci_write_config_byte(id_dev, sn_output, + data & ~sn_mask); + } + } else if (cobt_is_5k()) { + u16 addr; + + addr = superio_ldev_base(PC87317_DEV_GPIO); + if (addr) { + u8 val; + + sn_io_base = addr; + + /* set output value to 0 */ + val = inb(sn_direction); + outb(val | sn_mask, sn_direction); + data = inb(sn_output); + if (data & sn_mask) { + outb(data & ~sn_mask, sn_output); + } + /* set to input */ + outb(val & ~sn_mask, sn_direction); + } + } else { + return -ENXIO; + } + + /* pick proper variables */ + if (cobt_is_3k()) { + sn_direction = III_SN_DIRECTION; + sn_output = III_SN_OUTPUT; + sn_input = III_SN_INPUT; + sn_mask = III_SN_MASK; + } else if (cobt_is_5k()) { + sn_direction = V_SN_DIRECTION; + sn_output = V_SN_OUTPUT; + sn_input = V_SN_INPUT; + sn_mask = V_SN_MASK; + } else { + return -1; + } + + /* Let things calm down */ + udelay(500); + return 0; +} + +/* write out a bit */ +static void __init +io_write(int delay) +{ + if (cobt_is_3k()) { + unsigned char data; + /* Set output mode on GPIO3 */ + pci_read_config_byte(id_dev, sn_direction, &data); + pci_write_config_byte(id_dev, sn_direction, data | sn_mask); + udelay(delay); + + /* Set input mode */ + pci_write_config_byte(id_dev, sn_direction, data & ~sn_mask); + } else if (cobt_is_5k()) { + unsigned char direction; + + /* change to output and back */ + direction = inb(sn_direction); + outb(direction | sn_mask, sn_direction); + udelay(delay); + outb(direction & ~sn_mask, sn_direction); + } +} + +/* read in a bit */ +static int __init +io_read(void) +{ + unsigned char data = 0; + + /* Get the input value */ + if (cobt_is_3k()) { + pci_read_config_byte(id_dev, sn_input, &data); + } else if (cobt_is_5k()) { + data = inb(sn_input); + } + + return (data & sn_mask) ? 1 : 0; +} + +static void __init +io_write_byte(unsigned char c) +{ + int i; + unsigned long flags; + + local_save_flags(flags); + + for (i = 0; i < 8; i++, c >>= 1) { + local_irq_disable(); + if (c & 1) { + /* Transmit a 1 */ + io_write(5); + udelay(80); + } else { + /* Transmit a 0 */ + io_write(80); + udelay(10); + } + local_irq_restore(flags); + } +} + +static int __init +io_read_byte(void) +{ + int i; + int c = 0; + unsigned long flags; + + local_save_flags(flags); + + for (i = 0; i < 8; i++) { + local_irq_disable(); + io_write(1); /* Start the read */ + udelay(2); + if (io_read()) { + c |= 1 << i; + } + udelay(60); + local_irq_restore(flags); + } + + return c; +} + +static int __init +get_ssn(unsigned char *buf) +{ + int i; + unsigned long flags; + + /* + * Alpine does not have a dallas chip. Instead + * we read from an eprom. + */ + if (cobt_is_alpine()) { + for (i = 0; i < 8; i++) { + buf[i] = cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, + 12 + i); + } + return 0; + } + + /* + * bit-bang the Dallas 2401 + */ + + local_save_flags(flags); + local_irq_disable(); + + /* Master Reset Pulse */ + for (i = 0; i < 600; i += 30) { + if (io_read()) { + break; + } + } + + if (i >= 600) { + if (debug) { + EPRINTK("the data line seems to be held low\n"); + } + local_irq_restore(flags); + return -ENXIO; + } + + io_write(600); + + for (i = 0; i < 300; i += 15) { + udelay(15); + if (io_read() == 0) { + /* We got a presence pulse */ + udelay(600); /* Wait for things to quiet down */ + break; + } + } + local_irq_restore(flags); + + if (i >= 300) { + if (debug) + EPRINTK("no presence pulse detected\n"); + return -ENXIO; + } + + io_write_byte(0x33); + + for (i = 0; i < 8; i++) { + int rc; + + rc = io_read_byte(); + if (rc < 0) { + return rc; + } + + *buf++ = rc; + } + + return 0; +} + +int __init +cobalt_serialnum_init(void) +{ + unsigned char ssn[SSN_SIZE]; + int rc; + int i; + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", SN_DRIVER,SN_DRIVER_VMAJ,SN_DRIVER_VMIN); + /* set up for proper IO */ + rc = io_init(); + if (rc) { + return rc; + } + + /* + * NOTE: the below algorithm CAN NOT be changed. We have many systems + * out there registered with the serial number AS DERIVED by this + * algorithm. + */ + + rc = get_ssn(ssn); + if (rc) { + return rc; + } + + /* Convert to ssn_string */ + for (i = 7; i >= 0; i--) { + sprintf(ssn_string + (7 - i) * 2, "%02x", ssn[i]); + } + + /* get four bytes for a pretty unique (not guaranteed) hostid */ + hostid = *(unsigned long *)ssn ^ *(unsigned long *)(ssn+4); + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + proc_hostid = create_proc_read_entry("hostid", 0, NULL, + hostid_read, NULL); + if (!proc_hostid) { + EPRINTK("can't create /proc/hostid\n"); + } + proc_serialnum = create_proc_read_entry("serialnumber", 0, NULL, + serialnum_read, NULL); + if (!proc_serialnum) { + EPRINTK("can't create /proc/serialnumber\n"); + } +#endif + proc_chostid = create_proc_read_entry("hostid", 0, proc_cobalt, + hostid_read, NULL); + if (!proc_chostid) { + EPRINTK("can't create /proc/cobalt/hostid\n"); + } + proc_cserialnum = create_proc_read_entry("serialnumber", 0, + proc_cobalt, serialnum_read, NULL); + if (!proc_cserialnum) { + EPRINTK("can't create /proc/cobalt/serialnumber\n"); + } +#endif + + return 0; +} + +char * +cobalt_serialnum_get(void) +{ + return ssn_string; +} + +unsigned long +cobalt_hostid_get(void) +{ + return hostid; +} + +#if defined(CONFIG_COBALT_SERNUM_MODULE) +MODULE_PARM(debug, "i"); + +int +init_module(void) +{ + return cobalt_serialnum_init(); +} + +void +cleanup_module(void) +{ +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_COBALT_OLDPROC + remove_proc_entry("hostid", NULL); + remove_proc_entry("serialnumber", NULL); +#endif + remove_proc_entry("hostid", proc_cobalt); + remove_proc_entry("serialnumber", proc_cobalt); +#endif +} + +module_init(init_module); +module_exit(cleanup_module); +#endif /* MODULE */ + +#endif /* CONFIG_COBALT_SERNUM */ diff -Nurb linux-2.6.24.3/drivers/cobalt/systype.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/systype.c --- linux-2.6.24.3/drivers/cobalt/systype.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/systype.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,278 @@ +/* + * $Id: systype.c,v 1.33 2002/11/04 17:54:15 thockin Exp $ + * systype.c : routines for figuring out which Cobalt system this is + * + * Copyright 2001-2002 Sun Microsystems, Inc. + * + * By: Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * This driver is SMP safe by nature. --TPH + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* for easy first-pass analysis */ +#if defined(CONFIG_COBALT_GEN_III) +int COBALT_GENERATION_III_DEFINED; +#endif +#if defined(CONFIG_COBALT_GEN_V) +int COBALT_GENERATION_V_DEFINED; +#endif + +cobt_sys_t cobt_type = COBT_UNINITIALIZED; +EXPORT_SYMBOL(cobt_type); +unsigned long cobt_rev; +EXPORT_SYMBOL(cobt_rev); + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_systype; +#endif +static int systype_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x); +static char *systype_str(cobt_sys_t type); +static unsigned long boardrev_read(void); + +void __init +cobalt_boardrev_init(void) +{ + cobt_rev = boardrev_read(); +} + +int __init +cobalt_systype_init(void) +{ + cobalt_systype_probe(); + +#ifdef CONFIG_PROC_FS + proc_systype = create_proc_read_entry("systype", 0, + proc_cobalt, systype_read_proc, NULL); + if (!proc_systype) { + EPRINTK("can't create /proc/cobalt/systype\n"); + } +#endif + + if (cobt_type == COBT_UNKNOWN) { + printk(KERN_INFO "Cobalt system type is unknown, trouble will ensue (I can vouch for this)\n"); + return -1; + } else { + printk(KERN_INFO "Cobalt system type is %s\n",systype_str(cobt_type)); + return 0; + } +} + +#if defined(CONFIG_COBALT_GEN_III) +static cobt_sys_t +systype_probe_3k(void) +{ + struct pci_dev *pdev; + cobt_sys_t retval = COBT_UNKNOWN; + + /* board identifier for RaQ3/4 vs Qube3 is on the PMU @ 0x7f */ + pdev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL); + if (pdev) { + /* + * check to see what board we are on + * ( RaQ 3, RaQ 4, Qube 3 ) + */ + unsigned char val; + + /* momentarily set DOGB# to input */ + pci_read_config_byte(pdev, 0x7d, &val); + pci_write_config_byte(pdev, 0x7d, val & ~0x20); + + /* read the GPIO register */ + pci_read_config_byte(pdev, 0x7f, &val); + /* RaQ3/4 boards have DOGB (0x20) high, + * Qube3 has DOGB low */ + if (val & 0x20) { + retval = COBT_PACIFICA; + } else { + retval = COBT_CARMEL; + } + + /* change DOGB back to output */ + pci_read_config_byte(pdev, 0x7d, &val); + pci_write_config_byte(pdev, 0x7d, val | 0x20); + } + + /* assign to this, so the compiler shuts up */ + COBALT_GENERATION_III_DEFINED = 1; + + return retval; +} +#else +#define systype_probe_3k() (COBT_UNKNOWN) +#endif + +#if defined(CONFIG_COBALT_GEN_V) +static cobt_sys_t +systype_probe_5k(void) +{ + struct pci_dev *pdev; + cobt_sys_t retval = COBT_UNKNOWN; + + /* is it a gen V ? */ + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); + if (pdev) { + retval = COBT_MONTEREY; + goto out; + } + + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_LE, NULL); + if (pdev) { + retval = COBT_ALPINE; + goto out; + } + } + +out: + /* assign to this, so the compiler shuts up */ + COBALT_GENERATION_V_DEFINED = 1; + + return retval; +} +#else +#define systype_probe_5k() (COBT_UNKNOWN) +#endif + +static cobt_sys_t +systype_probe_gp(void) +{ + struct pci_dev *pdev; + cobt_sys_t retval = COBT_UNKNOWN; + + /* is it a GP system? */ + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HE, NULL); + if (pdev) { + retval = COBT_BIGBEAR; + } + } + + return retval; +} + +cobt_sys_t +cobalt_systype_probe(void) +{ + static int init_done = 0; + + if (init_done) { + return cobt_type; + } + + /* check for 3k family systems */ + + cobt_type = systype_probe_3k(); + if (cobt_type != COBT_UNKNOWN) + goto out; + + /* check for 5k family systems */ + cobt_type = systype_probe_5k(); + if (cobt_type != COBT_UNKNOWN) + goto out; + + /* it's a GP system or unknown */ + cobt_type = systype_probe_gp(); + +out: + if (cobt_type != COBT_UNKNOWN) { + init_done = 1; + } + + return cobt_type; +} +EXPORT_SYMBOL(cobalt_systype_probe); + +#ifdef CONFIG_PROC_FS +static int +systype_read_proc(char *buf, char **start, off_t pos, int len, + int *eof, void *x) +{ + int plen = sprintf(buf, "%s\n", systype_str(cobt_type)); + return cobalt_gen_proc_read(buf, plen, start, pos, len, eof); +} +#endif + +static char * +systype_str(cobt_sys_t type) +{ + switch (type) { + case COBT_PACIFICA: + return "Pacifica"; + break; + case COBT_CARMEL: + return "Carmel"; + break; + case COBT_MONTEREY: + return "Monterey"; + break; + case COBT_ALPINE: + return "Alpine"; + break; + case COBT_BIGBEAR: + return "BigBear"; + break; + case COBT_UNKNOWN: + default: + return "unknown"; + break; + } +} + +static unsigned long +boardrev_read(void) +{ + unsigned long rev; + + switch (cobt_type) { +#ifdef CONFIG_COBALT_RAQ + case COBT_PACIFICA: + case COBT_CARMEL: + /* No usable board rev on these systems */ + return 0; + case COBT_MONTEREY: + /* + * the boardrev on monterey is strapped off of GPM[3:0] + * and is read from port 0xc52 + */ + return inb(0xc52); + case COBT_ALPINE: + /* + * the boardrev on alpine in stored in the i2c eeprom + * location 4 + */ + rev = cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x04); + rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x05) << 8; + rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x06) << 16; + rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x07) << 24; + if (rev == 0xffffffff) + rev = 0; + return rev; +#endif + case COBT_BIGBEAR: + /* No board revs at this time */ + return 0; + case COBT_UNKNOWN: + case COBT_UNINITIALIZED: + return 0; + } + return 0; +} diff -Nurb linux-2.6.24.3/drivers/cobalt/wdt.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/wdt.c --- linux-2.6.24.3/drivers/cobalt/wdt.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/wdt.c 2008-03-02 14:55:48.000000000 -0800 @@ -0,0 +1,421 @@ +/* $Id: wdt.c,v 1.21 2002/07/02 00:38:17 asun Exp $ */ +/* + * Cobalt kernel WDT timer driver + * Tim Hockin + * Adrian Sun + * Chris Johnson + * Copyright (c)1999-2000, Cobalt Networks + * Copyright (c)2001, Sun Microsystems + * + * This should be SMP safe. Every external function (except trigger_reboot) + * grabs the wdt lock. No function in this file may call any exported + * function (excepting trigger_reboot). The disable counter is an atomic, so + * there should be no issues there. --TPH + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DOGB 0x20 +#define ALI_7101_WDT 0x92 +#define ALI_WDT_ARM 0x01 +#define WDT_3K_TIMEOUT (HZ >> 4) /* 1/16 second */ + +#define WDT_SUPERIO_TIMEOUT (0x01) /* 1 minute */ +#define WDT_5K_TIMEOUT (HZ << 3) /* 8 seconds */ + +#define WDT_DRIVER "Cobalt Networks Watchdog Timer driver" +#define WDT_DRIVER_VMAJ 1 +#define WDT_DRIVER_VMIN 0 + +static unsigned long wdt_timeout; +static unsigned long long tsc_per_wdt; +static int initialized; + +#ifdef CONFIG_COBALT_WDT +struct timer_list cobalt_wdt_timer; +static atomic_t cobalt_wdt_disable_count = ATOMIC_INIT(0); +static spinlock_t wdt_lock = SPIN_LOCK_UNLOCKED; +#endif + +/* gen III */ +static struct pci_dev *cobalt_pmu; +static int use_pic; +/* gen V */ +static u16 superio_pm_port; + +#ifdef CONFIG_COBALT_WDT +static void do_refresh(void); +static void do_cleardog(void); +static void do_disable(void); +static void do_reenable(void); +#endif + +static unsigned long __init +chipset_setup(void) +{ + unsigned char tmp; + if (cobt_is_3k()) { + /* + * Set up the PMU for 3k boards. It has a max + * of a 1 second timeout. + */ + struct pci_dev *south; + + /* PMU (1543 ver A1-E) has a built-in WDT. Set it to 1 sec */ + cobalt_pmu = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M7101, NULL); + if (!cobalt_pmu) { + EPRINTK("can't find south bridge for WDT\n"); + return 0; + } + pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, 0x02); + + /* why it is called 1543, but DevId is 1533 I'll never know */ + south = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M1533, NULL); + if (!south) { + EPRINTK("can't find south bridge for WDT\n"); + use_pic = 1; + } else { + /* reversion # is here - must match ???1001?(b) + * else use PIC for WDT */ + pci_read_config_byte(south, 0x5e, &tmp); + use_pic = ((tmp & 0x1e) != 0x12); + } + + if (!use_pic) { + /* set DOGB GPIO pin to OUTPUT - JIC */ + pci_read_config_byte(cobalt_pmu, 0x7d, &tmp); + pci_write_config_byte(cobalt_pmu, 0x7d, tmp | DOGB); + } + return WDT_3K_TIMEOUT; + } else if (cobt_is_monterey()) { + /* + * Set up the Nat. Semi SuperI/O for XTR. It has a + * minimum of a 1 minute timeout. + */ + + /* superi/o -- select pm logical device and get base address */ + superio_pm_port = superio_ldev_base(PC87317_DEV_PM); +#ifdef CONFIG_COBALT_WDT + if (!superio_pm_port) { + return 0; + } + outb(PC87317_PMDEV_WDTO, superio_pm_port); + outb(WDT_SUPERIO_TIMEOUT, superio_pm_port + 1); +#endif + return WDT_5K_TIMEOUT; + } else if (cobt_is_alpine()) { + /* + * Set up the Nat. Semi SuperI/O for Alpine. It has a + * minimum of a 1 minute timeout. + */ + + /* superi/o -- select pm logical device and get base address */ + superio_pm_port = superio_ldev_base(PC87417_DEV_SWC); +#ifdef CONFIG_COBALT_WDT + if (!superio_pm_port) { + return 0; + } + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port+PC87417_SWC_BANK); + /* clear event config... */ + tmp = inb(superio_pm_port+PC87417_WDT_CONFIG); + outb(0, superio_pm_port+PC87417_WDT_CONFIG); + /* ...before mucking with timeout */ + outb(WDT_SUPERIO_TIMEOUT, + superio_pm_port+PC87417_WDT_TIMEOUT); + /* restore the event config */ + outb(tmp, superio_pm_port+PC87417_WDT_CONFIG); + /* enable the counter */ + outb(1, superio_pm_port+PC87417_WDT_CONTROL); +#endif + return WDT_5K_TIMEOUT; + } + + return 0; +} + +void __init +cobalt_wdt_init(void) +{ + unsigned long long start, stop; + + printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", WDT_DRIVER,WDT_DRIVER_VMAJ,WDT_DRIVER_VMIN); + + wdt_timeout = chipset_setup(); + + /* figure out time */ + rdtscll(start); + udelay(100); + rdtscll(stop); + + /* + * (int) (stop - start) * 10 == tsc per msec + * 1000 / HZ == msec per tick + * wdt_timeout == ticks per watchdog rearm + */ + tsc_per_wdt = (int) (stop - start) * 10 * (1000 * wdt_timeout / HZ); + +#ifdef CONFIG_COBALT_WDT + /* set the timer going */ + init_timer(&cobalt_wdt_timer); + cobalt_wdt_timer.function = cobalt_wdt_refresh; + cobalt_wdt_timer.data = 1; + cobalt_wdt_timer.expires = jiffies + wdt_timeout; + add_timer(&cobalt_wdt_timer); + + /* the first timer tick will set it going */ + + if (cobt_is_3k() && use_pic) { + WPRINTK("Cobalt WDT - old board, using PIC controller\n"); + } +#endif /* CONFIG_COBALT_WDT */ + + initialized = 1; +} + +static inline void +hw_disable(void) +{ + if (cobt_is_3k()) { + char tmp; + /* read the value, disable (reset) WDT */ + pci_read_config_byte(cobalt_pmu, ALI_7101_WDT, &tmp); + pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, + (tmp & ~ALI_WDT_ARM)); + } else if (cobt_is_monterey()) { + outb(PC87317_PMDEV_WDTO, superio_pm_port); + outb(0, superio_pm_port + 1); + } else if (cobt_is_alpine()) { + unsigned char tmp; + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK); + /* clear event config before mucking with timeout */ + tmp = inb(superio_pm_port + PC87417_WDT_CONFIG); + outb(0, superio_pm_port + PC87417_WDT_CONFIG); + /* + * Disable it by setting a 0 time-out. + * The spec says 00h is reserved, but NSC confirms this is the + * way to disable the device. + */ + outb(0, superio_pm_port + PC87417_WDT_TIMEOUT); + /* restore the event config */ + outb(tmp, superio_pm_port + PC87417_WDT_CONFIG); + } +} + +static inline void +hw_enable(void) +{ + if (cobt_is_3k()) { + unsigned char tmp; + /* read the value, disable (reset) WDT, enable WDT */ + pci_read_config_byte(cobalt_pmu, ALI_7101_WDT, &tmp); + pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, + (tmp | ALI_WDT_ARM)); + if (use_pic) { + /* transition GPIO 5 (DOGB) to arm/clear timer */ + pci_read_config_byte(cobalt_pmu, 0x7e, &tmp); + pci_write_config_byte(cobalt_pmu, 0x7e, tmp ^ DOGB); + } + } else if (cobt_is_monterey()) { + outb(PC87317_PMDEV_WDTO, superio_pm_port); + outb(WDT_SUPERIO_TIMEOUT, superio_pm_port + 1); + } else if (cobt_is_alpine()) { + unsigned char tmp; + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK); + /* clear event config before mucking with timeout */ + tmp = inb(superio_pm_port + PC87417_WDT_CONFIG); + outb(0, superio_pm_port + PC87417_WDT_CONFIG); + /* enable and refresh the timer */ + outb(WDT_SUPERIO_TIMEOUT, + superio_pm_port + PC87417_WDT_TIMEOUT); + outb(0x80, superio_pm_port + PC87417_WDT_CONTROL); + /* restore event config */ + outb(tmp, superio_pm_port + PC87417_WDT_CONFIG); + } +} + +#ifdef CONFIG_COBALT_WDT +static void +do_refresh(void) +{ + if (!initialized) { + return; + } + + do_cleardog(); + + /* re-arm the timer - this is locked in mod_timer() */ + mod_timer(&cobalt_wdt_timer, jiffies + wdt_timeout); +} +#endif + +EXPORT_SYMBOL(cobalt_wdt_refresh); +void +cobalt_wdt_refresh(unsigned long refresh_timer) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + spin_lock_irqsave(&wdt_lock, flags); + do_refresh(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} + +#ifdef CONFIG_COBALT_WDT +static void +do_cleardog(void) +{ + static unsigned long long last_tsc = 0; + unsigned long long tmp; + + if (!initialized || (atomic_read(&cobalt_wdt_disable_count) > 0)) { + return; + } + + /* only bother if we're due */ + rdtscll(tmp); + if ((int)(tmp - last_tsc) < tsc_per_wdt) { + return; + } + + if (cobt_is_3k() || cobt_is_monterey()) { + /* this is how we re-start the clock */ + hw_disable(); + hw_enable(); + } else if (cobt_is_alpine()) { + /* select the WDT bank of SWC */ + outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK); + /* refresh the timer */ + outb(0x80, superio_pm_port + PC87417_WDT_CONTROL); + } + + rdtscll(last_tsc); +} +#endif + +EXPORT_SYMBOL(cobalt_wdt_cleardog); +void +cobalt_wdt_cleardog(void) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + + spin_lock_irqsave(&wdt_lock, flags); + do_cleardog(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} + +/* + * this is called from machine_restart. it should not be used on + * 5k machines. + */ +EXPORT_SYMBOL(cobalt_wdt_trigger_reboot); +void +cobalt_wdt_trigger_reboot(void) +{ + if (cobt_is_3k()) { + if (!cobalt_pmu) { + WPRINTK("no PMU found!\n"); + WPRINTK("reboot not possible!\n"); + return; + } + +#ifdef CONFIG_COBALT_WDT + /* stop feeding it */ + del_timer_sync(&cobalt_wdt_timer); +#endif + + /* kiss your rear goodbye... */ + initialized = 0; + hw_disable(); + hw_enable(); + } +} + +#ifdef CONFIG_COBALT_WDT +static void +do_disable(void) +{ + if (!initialized) { + return; + } + + if (atomic_read(&cobalt_wdt_disable_count) == 0) { + atomic_inc(&cobalt_wdt_disable_count); + del_timer_sync(&cobalt_wdt_timer); + hw_disable(); + } +} +#endif + +EXPORT_SYMBOL(cobalt_wdt_disable); +void +cobalt_wdt_disable(void) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + + if (cobt_is_3k() && use_pic) { + WPRINTK("in PIC mode - cannot disable\n"); + return; + } + + spin_lock_irqsave(&wdt_lock, flags); + do_disable(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} + +#ifdef CONFIG_COBALT_WDT +static void +do_reenable(void) +{ + int dcnt; + + if (!initialized) { + return; + } + + atomic_dec(&cobalt_wdt_disable_count); + dcnt = atomic_read(&cobalt_wdt_disable_count); + + if (dcnt == 0) { + do_refresh(); + } else if (dcnt < 0) { + WPRINTK("too many enables\n"); + atomic_set(&cobalt_wdt_disable_count, 0); + } +} +#endif + + +EXPORT_SYMBOL(cobalt_wdt_reenable); +void +cobalt_wdt_reenable(void) +{ +#ifdef CONFIG_COBALT_WDT + unsigned long flags; + + spin_lock_irqsave(&wdt_lock, flags); + do_reenable(); + spin_unlock_irqrestore(&wdt_lock, flags); +#endif +} diff -Nurb linux-2.6.24.3/drivers/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/Kconfig --- linux-2.6.24.3/drivers/Kconfig 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/Kconfig 2008-03-02 14:55:48.000000000 -0800 @@ -90,6 +90,8 @@ source "drivers/auxdisplay/Kconfig" +source "drivers/cobalt/Kconfig" + source "drivers/kvm/Kconfig" source "drivers/uio/Kconfig" diff -Nurb linux-2.6.24.3/drivers/Kconfig.orig linux-2.6.24.3-cobalt3-tw/drivers/Kconfig.orig --- linux-2.6.24.3/drivers/Kconfig.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/Kconfig.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,98 @@ +# drivers/Kconfig + +menu "Device Drivers" + +source "drivers/base/Kconfig" + +source "drivers/connector/Kconfig" + +source "drivers/mtd/Kconfig" + +source "drivers/of/Kconfig" + +source "drivers/parport/Kconfig" + +source "drivers/pnp/Kconfig" + +source "drivers/block/Kconfig" + +# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4 + +source "drivers/misc/Kconfig" + +source "drivers/ide/Kconfig" + +source "drivers/scsi/Kconfig" + +source "drivers/ata/Kconfig" + +source "drivers/md/Kconfig" + +source "drivers/message/fusion/Kconfig" + +source "drivers/ieee1394/Kconfig" + +source "drivers/message/i2o/Kconfig" + +source "drivers/macintosh/Kconfig" + +source "drivers/net/Kconfig" + +source "drivers/isdn/Kconfig" + +source "drivers/telephony/Kconfig" + +# input before char - char/joystick depends on it. As does USB. + +source "drivers/input/Kconfig" + +source "drivers/char/Kconfig" + +source "drivers/i2c/Kconfig" + +source "drivers/spi/Kconfig" + +source "drivers/w1/Kconfig" + +source "drivers/power/Kconfig" + +source "drivers/hwmon/Kconfig" + +source "drivers/watchdog/Kconfig" + +source "drivers/ssb/Kconfig" + +source "drivers/mfd/Kconfig" + +source "drivers/media/Kconfig" + +source "drivers/video/Kconfig" + +source "sound/Kconfig" + +source "drivers/hid/Kconfig" + +source "drivers/usb/Kconfig" + +source "drivers/mmc/Kconfig" + +source "drivers/leds/Kconfig" + +source "drivers/infiniband/Kconfig" + +source "drivers/edac/Kconfig" + +source "drivers/rtc/Kconfig" + +source "drivers/dma/Kconfig" + +source "drivers/dca/Kconfig" + +source "drivers/auxdisplay/Kconfig" + +source "drivers/kvm/Kconfig" + +source "drivers/uio/Kconfig" + +source "drivers/virtio/Kconfig" +endmenu diff -Nurb linux-2.6.24.3/drivers/Makefile linux-2.6.24.3-cobalt3-tw/drivers/Makefile --- linux-2.6.24.3/drivers/Makefile 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/Makefile 2008-03-02 14:55:48.000000000 -0800 @@ -68,6 +68,8 @@ obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ +obj-$(CONFIG_COBALT_RAQ) += cobalt/ + obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_EDAC) += edac/ diff -Nurb linux-2.6.24.3/drivers/Makefile.orig linux-2.6.24.3-cobalt3-tw/drivers/Makefile.orig --- linux-2.6.24.3/drivers/Makefile.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/Makefile.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,93 @@ +# +# Makefile for the Linux kernel device drivers. +# +# 15 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# + +obj-$(CONFIG_PCI) += pci/ +obj-$(CONFIG_PARISC) += parisc/ +obj-$(CONFIG_RAPIDIO) += rapidio/ +obj-y += video/ +obj-$(CONFIG_ACPI) += acpi/ +# PnP must come after ACPI since it will eventually need to check if acpi +# was used and do nothing if so +obj-$(CONFIG_PNP) += pnp/ +obj-$(CONFIG_ARM_AMBA) += amba/ + +obj-$(CONFIG_XEN) += xen/ + +# char/ comes before serial/ etc so that the VT console is the boot-time +# default. +obj-y += char/ + +obj-$(CONFIG_CONNECTOR) += connector/ + +# i810fb and intelfb depend on char/agp/ +obj-$(CONFIG_FB_I810) += video/i810/ +obj-$(CONFIG_FB_INTEL) += video/intelfb/ + +obj-y += serial/ +obj-$(CONFIG_PARPORT) += parport/ +obj-y += base/ block/ misc/ mfd/ net/ media/ +obj-$(CONFIG_NUBUS) += nubus/ +obj-$(CONFIG_ATM) += atm/ +obj-y += macintosh/ +obj-$(CONFIG_IDE) += ide/ +obj-$(CONFIG_SCSI) += scsi/ +obj-$(CONFIG_ATA) += ata/ +obj-$(CONFIG_FUSION) += message/ +obj-$(CONFIG_FIREWIRE) += firewire/ +obj-$(CONFIG_IEEE1394) += ieee1394/ +obj-$(CONFIG_UIO) += uio/ +obj-y += cdrom/ +obj-y += auxdisplay/ +obj-$(CONFIG_MTD) += mtd/ +obj-$(CONFIG_SPI) += spi/ +obj-$(CONFIG_PCCARD) += pcmcia/ +obj-$(CONFIG_DIO) += dio/ +obj-$(CONFIG_SBUS) += sbus/ +obj-$(CONFIG_KVM) += kvm/ +obj-$(CONFIG_ZORRO) += zorro/ +obj-$(CONFIG_MAC) += macintosh/ +obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ +obj-$(CONFIG_PARIDE) += block/paride/ +obj-$(CONFIG_TC) += tc/ +obj-$(CONFIG_USB) += usb/ +obj-$(CONFIG_PCI) += usb/ +obj-$(CONFIG_USB_GADGET) += usb/gadget/ +obj-$(CONFIG_SERIO) += input/serio/ +obj-$(CONFIG_GAMEPORT) += input/gameport/ +obj-$(CONFIG_INPUT) += input/ +obj-$(CONFIG_I2O) += message/ +obj-$(CONFIG_RTC_LIB) += rtc/ +obj-y += i2c/ +obj-$(CONFIG_W1) += w1/ +obj-$(CONFIG_POWER_SUPPLY) += power/ +obj-$(CONFIG_HWMON) += hwmon/ +obj-$(CONFIG_WATCHDOG) += watchdog/ +obj-$(CONFIG_PHONE) += telephony/ +obj-$(CONFIG_MD) += md/ +obj-$(CONFIG_BT) += bluetooth/ +obj-$(CONFIG_ISDN) += isdn/ +obj-$(CONFIG_EDAC) += edac/ +obj-$(CONFIG_MCA) += mca/ +obj-$(CONFIG_EISA) += eisa/ +obj-$(CONFIG_LGUEST_GUEST) += lguest/ +obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_CPU_IDLE) += cpuidle/ +obj-$(CONFIG_MMC) += mmc/ +obj-$(CONFIG_NEW_LEDS) += leds/ +obj-$(CONFIG_INFINIBAND) += infiniband/ +obj-$(CONFIG_SGI_SN) += sn/ +obj-y += firmware/ +obj-$(CONFIG_CRYPTO) += crypto/ +obj-$(CONFIG_SUPERH) += sh/ +obj-$(CONFIG_GENERIC_TIME) += clocksource/ +obj-$(CONFIG_DMA_ENGINE) += dma/ +obj-$(CONFIG_DCA) += dca/ +obj-$(CONFIG_HID) += hid/ +obj-$(CONFIG_PPC_PS3) += ps3/ +obj-$(CONFIG_OF) += of/ +obj-$(CONFIG_SSB) += ssb/ +obj-$(CONFIG_VIRTIO) += virtio/ diff -Nurb linux-2.6.24.3/drivers/net/e100.c linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c --- linux-2.6.24.3/drivers/net/e100.c 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c 2008-03-02 14:55:48.000000000 -0800 @@ -163,6 +163,7 @@ #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" #define PFX DRV_NAME ": " +#define DRV_MODIFIED "Modified by to ignore bad EEPROM checksums" #define E100_WATCHDOG_PERIOD (2 * HZ) #define E100_NAPI_WEIGHT 16 @@ -760,9 +761,15 @@ * the sum of words should be 0xBABA */ checksum = le16_to_cpu(0xBABA - checksum); if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { +#if defined(CONFIG_E100_IGNORE_CSUM) + DPRINTK(PROBE, ERR, "EEPROM corrupted, ignoring and moving on\n"); + DPRINTK(PROBE, ERR, " Caclulated Checksum: %X\n",checksum); + DPRINTK(PROBE, ERR, " EEPROM Checksum: %X\n",nic->eeprom[nic->eeprom_wc - 1]); +#else DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); if (!eeprom_bad_csum_allow) return -EAGAIN; +#endif } return 0; @@ -2882,6 +2889,9 @@ 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); +#if defined(CONFIG_E100_IGNORE_CSUM) + printk(KERN_INFO PFX "%s\n", DRV_MODIFIED); +#endif } return pci_register_driver(&e100_driver); } diff -Nurb linux-2.6.24.3/drivers/net/e100.c.orig linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c.orig --- linux-2.6.24.3/drivers/net/e100.c.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,2895 @@ +/******************************************************************************* + + Intel PRO/100 Linux driver + Copyright(c) 1999 - 2006 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + 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. + * 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. A software-generated interrupt + * is generated 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). + * + * MagicPacket(tm) WoL support is enabled/disabled via ethtool. + * + * Thanks to JC (jchapman@katalix.com) for helping with + * testing/troubleshooting the development driver. + * + * TODO: + * o several entry points race with dev->close + * o check for tx-no-resources/stop Q races with tx clean/wake Q + * + * FIXES: + * 2005/12/02 - Michael O'Donnell + * - Stratus87247: protect MDI control register manipulations + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRV_NAME "e100" +#define DRV_EXT "-NAPI" +#define DRV_VERSION "3.5.23-k4"DRV_EXT +#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 1999-2006 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"); +MODULE_VERSION(DRV_VERSION); + +static int debug = 3; +static int eeprom_bad_csum_allow = 0; +static int use_io = 0; +module_param(debug, int, 0); +module_param(eeprom_bad_csum_allow, int, 0); +module_param(use_io, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums"); +MODULE_PARM_DESC(use_io, "Force use of i/o access mode"); +#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(0x1056, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1057, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1059, 0), + 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(0x1091, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1092, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1093, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1094, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1095, 7), + 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), + INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7), + { 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_ek = 0x031002A8, + 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_ready = 0x10, + rus_mask = 0x3C, +}; + +enum ru_state { + RU_SUSPENDED = 0, + RU_RUNNING = 1, + RU_UNINITIALIZED = -1, +}; + +enum scb_stat_ack { + stat_ack_not_ours = 0x00, + 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_not_present = 0xFF, + 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 { + cuc_nop = 0x00, + 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 cuc_dump { + cuc_dump_complete = 0x0000A005, + cuc_dump_reset_complete = 0x0000A007, +}; + +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_cnfg_mdix = 0x03, + eeprom_id = 0x0A, + eeprom_config_asf = 0x0D, + eeprom_smbus_addr = 0x90, +}; + +enum eeprom_cnfg_mdix { + eeprom_mdix_enabled = 0x0080, +}; + +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_nop = 0x0000, + cb_iaaddr = 0x0001, + cb_config = 0x0002, + cb_multi = 0x0003, + cb_tx = 0x0004, + cb_ucode = 0x0005, + 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 { + struct rx *next, *prev; + struct sk_buff *skb; + dma_addr_t dma_addr; +}; + +#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 */ +#define UCODE_SIZE 134 +struct cb { + u16 status; + u16 command; + u32 link; + union { + u8 iaaddr[ETH_ALEN]; + u32 ucode[UCODE_SIZE]; + 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 rx *rxs ____cacheline_aligned; + struct rx *rx_to_use; + struct rx *rx_to_clean; + struct rfd blank_rfd; + enum ru_state ru_running; + + spinlock_t cb_lock ____cacheline_aligned; + spinlock_t cmd_lock; + struct csr __iomem *csr; + enum scb_cmd_lo cuc_cmd; + unsigned int cbs_avail; + struct napi_struct napi; + 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), + ich_10h_workaround = (1 << 4), + } flags ____cacheline_aligned; + + enum mac mac; + enum phy phy; + struct params params; + struct timer_list watchdog; + struct timer_list blink_timer; + struct mii_if_info mii; + struct work_struct tx_timeout_task; + 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; + u32 rx_over_length_errors; + + u16 leds; + u16 eeprom_wc; + u16 eeprom[256]; + spinlock_t mdio_lock; +}; + +static inline void e100_write_flush(struct nic *nic) +{ + /* Flush previous PCI writes through intermediate bridges + * by doing a benign read */ + (void)ioread8(&nic->csr->scb.status); +} + +static void e100_enable_irq(struct nic *nic) +{ + unsigned long flags; + + spin_lock_irqsave(&nic->cmd_lock, flags); + iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + spin_unlock_irqrestore(&nic->cmd_lock, flags); +} + +static void e100_disable_irq(struct nic *nic) +{ + unsigned long flags; + + spin_lock_irqsave(&nic->cmd_lock, flags); + iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + spin_unlock_irqrestore(&nic->cmd_lock, flags); +} + +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 */ + iowrite32(selective_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* Now fully reset device */ + iowrite32(software_reset, &nic->csr->port); + e100_write_flush(nic); udelay(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; + + iowrite32(selftest | dma_addr, &nic->csr->port); + e100_write_flush(nic); + /* Wait 10 msec for self-test to complete */ + msleep(10); + + /* 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) | + cpu_to_le16(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 */ + iowrite8(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; + iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + /* Wait 10 msec for cmd to complete */ + msleep(10); + + /* Chip deselect */ + iowrite8(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 */ + iowrite8(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; + iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + iowrite8(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 = ioread8(&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 */ + iowrite8(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + return le16_to_cpu(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 += cpu_to_le16(nic->eeprom[addr]); + } + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + checksum = le16_to_cpu(0xBABA - checksum); + if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { + DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); + if (!eeprom_bad_csum_allow) + 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 += cpu_to_le16(nic->eeprom[addr]); + nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum); + e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, + nic->eeprom[nic->eeprom_wc - 1]); + + return 0; +} + +#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */ +#define E100_WAIT_SCB_FAST 20 /* delay like the old code */ +static 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(!ioread8(&nic->csr->scb.cmd_lo))) + break; + cpu_relax(); + if(unlikely(i > E100_WAIT_SCB_FAST)) + udelay(5); + } + if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) { + err = -EAGAIN; + goto err_unlock; + } + + if(unlikely(cmd != cuc_resume)) + iowrite32(dma_addr, &nic->csr->scb.gen_ptr); + iowrite8(cmd, &nic->csr->scb.cmd_lo); + +err_unlock: + spin_unlock_irqrestore(&nic->cmd_lock, flags); + + return err; +} + +static 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); + wmb(); + cb->prev->command &= cpu_to_le16(~cb_s); + + while(nic->cb_to_send != nic->cb_to_use) { + if(unlikely(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. */ + if(err == -ENOSPC) { + //request a reset + schedule_work(&nic->tx_timeout_task); + } + 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; + unsigned long flags; + + + /* + * Stratus87247: we shouldn't be writing the MDI control + * register until the Ready bit shows True. Also, since + * manipulation of the MDI control registers is a multi-step + * procedure it should be done under lock. + */ + spin_lock_irqsave(&nic->mdio_lock, flags); + for (i = 100; i; --i) { + if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready) + break; + udelay(20); + } + if (unlikely(!i)) { + printk("e100.mdio_ctrl(%s) won't go Ready\n", + nic->netdev->name ); + spin_unlock_irqrestore(&nic->mdio_lock, flags); + return 0; /* No way to indicate timeout error */ + } + iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); + + for (i = 0; i < 100; i++) { + udelay(20); + if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready) + break; + } + spin_unlock_irqrestore(&nic->mdio_lock, flags); + 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(netdev), addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); +} + +static void e100_get_defaults(struct nic *nic) +{ + struct param_range rfds = { .min = 16, .max = 256, .count = 256 }; + struct param_range cbs = { .min = 64, .max = 256, .count = 128 }; + + /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */ + nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->pdev->revision; + 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; + + /* no interrupt for every tx completion, delay = 256us if not 557*/ + nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf | + ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); + + /* 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 */ + + /* disable WoL when up */ + if(netif_running(nic->netdev) || !(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 */ + /* Enable TCO in extended config */ + if (nic->mac >= mac_82551_10) { + config->byte_count = 0x20; /* extended bytes */ + config->rx_d102_mode = 0x1; /* GMRC for TCO */ + } + } 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]); +} + +/********************************************************/ +/* Micro code for 8086:1229 Rev 8 */ +/********************************************************/ + +/* 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, \ +} + +/********************************************************/ +/* Micro code for 8086:1229 Rev 9 */ +/********************************************************/ + +/* 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 \ +} + +/********************************************************/ +/* Micro code for the 8086:1229 Rev F/10 */ +/********************************************************/ + +/* 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, 0x0EF70E36, 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, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \ +0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +} + +static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ +/* *INDENT-OFF* */ + static struct { + u32 ucode[UCODE_SIZE + 1]; + u8 mac; + u8 timer_dword; + u8 bundle_dword; + u8 min_size_dword; + } ucode_opts[] = { + { D101M_B_RCVBUNDLE_UCODE, + mac_82559_D101M, + D101M_CPUSAVER_TIMER_DWORD, + D101M_CPUSAVER_BUNDLE_DWORD, + D101M_CPUSAVER_MIN_SIZE_DWORD }, + { D101S_RCVBUNDLE_UCODE, + mac_82559_D101S, + D101S_CPUSAVER_TIMER_DWORD, + D101S_CPUSAVER_BUNDLE_DWORD, + D101S_CPUSAVER_MIN_SIZE_DWORD }, + { D102_E_RCVBUNDLE_UCODE, + mac_82551_F, + D102_E_CPUSAVER_TIMER_DWORD, + D102_E_CPUSAVER_BUNDLE_DWORD, + D102_E_CPUSAVER_MIN_SIZE_DWORD }, + { D102_E_RCVBUNDLE_UCODE, + mac_82551_10, + D102_E_CPUSAVER_TIMER_DWORD, + D102_E_CPUSAVER_BUNDLE_DWORD, + D102_E_CPUSAVER_MIN_SIZE_DWORD }, + { {0}, 0, 0, 0, 0} + }, *opts; +/* *INDENT-ON* */ + +/************************************************************************* +* 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 the algorithm. +* +* INTDELAY - This loads the dead-man timer with its initial value. +* When this timer expires the interrupt is asserted, and the +* timer is reset each time a new packet is received. (see +* BUNDLEMAX below to set the limit on number of chained packets) +* The current default is 0x600 or 1536. Experiments show that +* the value should probably stay within the 0x200 - 0x1000. +* +* BUNDLEMAX - +* This 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. +* +* BUNDLESMALL - +* This 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. +*************************************************************************/ + +/* if you wish to disable the ucode functionality, while maintaining the + * workarounds it provides, set the following defines to: + * BUNDLESMALL 0 + * BUNDLEMAX 1 + * INTDELAY 1 + */ +#define BUNDLESMALL 1 +#define BUNDLEMAX (u16)6 +#define INTDELAY (u16)1536 /* 0x600 */ + + /* do not load u-code for ICH devices */ + if (nic->flags & ich) + goto noloaducode; + + /* Search for ucode match against h/w revision */ + for (opts = ucode_opts; opts->mac; opts++) { + int i; + u32 *ucode = opts->ucode; + if (nic->mac != opts->mac) + continue; + + /* Insert user-tunable settings */ + ucode[opts->timer_dword] &= 0xFFFF0000; + ucode[opts->timer_dword] |= INTDELAY; + ucode[opts->bundle_dword] &= 0xFFFF0000; + ucode[opts->bundle_dword] |= BUNDLEMAX; + ucode[opts->min_size_dword] &= 0xFFFF0000; + ucode[opts->min_size_dword] |= (BUNDLESMALL) ? 0xFFFF : 0xFF80; + + for (i = 0; i < UCODE_SIZE; i++) + cb->u.ucode[i] = cpu_to_le32(ucode[i]); + cb->command = cpu_to_le16(cb_ucode | cb_el); + return; + } + +noloaducode: + cb->command = cpu_to_le16(cb_nop | cb_el); +} + +static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +{ + int err = 0, counter = 50; + struct cb *cb = nic->cb_to_clean; + + if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode))) + DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err); + + /* must restart cuc */ + nic->cuc_cmd = cuc_start; + + /* wait for completion */ + e100_write_flush(nic); + udelay(10); + + /* wait for possibly (ouch) 500ms */ + while (!(cb->status & cpu_to_le16(cb_complete))) { + msleep(10); + if (!--counter) break; + } + + /* ack any interrupts, something could have been set */ + iowrite8(~0, &nic->csr->scb.stat_ack); + + /* if the command failed, or is not OK, notify and return */ + if (!counter || !(cb->status & cpu_to_le16(cb_ok))) { + DPRINTK(PROBE,ERR, "ucode load failed\n"); + err = -EPERM; + } + + return err; +} + +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 phys */ +#define NCS_PHY_MODEL_MASK 0xFFF0FFFF + if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) { + /* Disable congestion control */ + cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG); + cong |= NSC_CONG_TXREADY; + cong &= ~NSC_CONG_ENABLE; + mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); + } + + if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && + (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && + !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) { + /* 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_wait(nic, NULL, e100_setup_ucode))) + 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(netdev); + + 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 *dev = nic->netdev; + struct net_device_stats *ns = &dev->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(cuc_dump_reset_complete)) { + *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_length_errors += le32_to_cpu(s->rx_short_frame_errors) + + nic->rx_over_length_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_over_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_missed_errors += le32_to_cpu(s->rx_resource_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); + } + } + } + + + if(e100_exec_cmd(nic, cuc_dump_reset, 0)) + DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n"); +} + +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. + * Unfortunately have to use a spinlock to not re-enable interrupts + * accidentally, due to hardware that shares a register between the + * interrupt mask bit and the SW Interrupt generation bit */ + spin_lock_irq(&nic->cmd_lock); + iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); + e100_write_flush(nic); + spin_unlock_irq(&nic->cmd_lock); + + 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); + + if(nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF) + /* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */ + nic->flags |= ich_10h_workaround; + else + nic->flags &= ~ich_10h_workaround; + + mod_timer(&nic->watchdog, + round_jiffies(jiffies + E100_WATCHDOG_PERIOD)); +} + +static void e100_xmit_prepare(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = nic->tx_command; + /* interrupt every 16 packets regardless of delay */ + if((nic->cbs_avail & ~15) == nic->cbs_avail) + cb->command |= cpu_to_le16(cb_i); + 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)); + /* check for mapping failure? */ + 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(netdev); + int err; + + if(nic->flags & ich_10h_workaround) { + /* SW workaround for ICH[x] 10Mbps/half duplex Tx hang. + Issue a NOP command followed by a 1us delay before + issuing the Tx command. */ + if(e100_exec_cmd(nic, cuc_nop, 0)) + DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n"); + udelay(1); + } + + err = e100_exec_cb(nic, skb, e100_xmit_prepare); + + switch(err) { + case -ENOSPC: + /* We queued the skb, but now we're out of space. */ + DPRINTK(TX_ERR, DEBUG, "No space for CB\n"); + 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 int e100_tx_clean(struct nic *nic) +{ + struct net_device *dev = nic->netdev; + struct cb *cb; + int tx_cleaned = 0; + + spin_lock(&nic->cb_lock); + + /* Clean CBs marked complete */ + for(cb = nic->cb_to_clean; + cb->status & cpu_to_le16(cb_complete); + cb = nic->cb_to_clean = cb->next) { + DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n", + (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)), + cb->status); + + if(likely(cb->skb != NULL)) { + dev->stats.tx_packets++; + dev->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); + cb->skb = NULL; + 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) +{ + if(nic->cbs) { + while(nic->cbs_avail != nic->params.cbs.count) { + 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++; + } + 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)); + cb->skb = NULL; + } + + 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, struct rx *rx) +{ + if(!nic->rxs) return; + if(RU_SUSPENDED != nic->ru_running) return; + + /* handle init time starts */ + if(!rx) rx = nic->rxs; + + /* (Re)start RU if suspended or idle and RFA is non-NULL */ + if(rx->skb) { + e100_exec_cmd(nic, ruc_start, rx->dma_addr); + nic->ru_running = RU_RUNNING; + } +} + +#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) +static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) +{ + if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN))) + return -ENOMEM; + + /* Align, init, and map the RFD. */ + skb_reserve(rx->skb, NET_IP_ALIGN); + skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd)); + rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, + RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); + + if(pci_dma_mapping_error(rx->dma_addr)) { + dev_kfree_skb_any(rx->skb); + rx->skb = NULL; + rx->dma_addr = 0; + return -ENOMEM; + } + + /* Link the RFD to end of RFA by linking previous RFD to + * this one, and clearing EL bit of previous. */ + if(rx->prev->skb) { + struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; + put_unaligned(cpu_to_le32(rx->dma_addr), + (u32 *)&prev_rfd->link); + wmb(); + prev_rfd->command &= ~cpu_to_le16(cb_el); + pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); + } + + return 0; +} + +static int e100_rx_indicate(struct nic *nic, struct rx *rx, + unsigned int *work_done, unsigned int work_to_do) +{ + struct net_device *dev = nic->netdev; + struct sk_buff *skb = rx->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_for_cpu(nic->pdev, rx->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 -ENODATA; + + /* Get actual data size */ + actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; + if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd))) + actual_size = RFD_BUF_LEN - sizeof(struct rfd); + + /* Get data */ + pci_unmap_single(nic->pdev, rx->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + + /* this allows for a fast restart without re-enabling interrupts */ + if(le16_to_cpu(rfd->command) & cb_el) + nic->ru_running = RU_SUSPENDED; + + /* 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))) { + /* Don't indicate if hardware indicates errors */ + dev_kfree_skb_any(skb); + } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) { + /* Don't indicate oversized frames */ + nic->rx_over_length_errors++; + dev_kfree_skb_any(skb); + } else { + dev->stats.rx_packets++; + dev->stats.rx_bytes += actual_size; + nic->netdev->last_rx = jiffies; + netif_receive_skb(skb); + if(work_done) + (*work_done)++; + } + + rx->skb = NULL; + + return 0; +} + +static void e100_rx_clean(struct nic *nic, unsigned int *work_done, + unsigned int work_to_do) +{ + struct rx *rx; + int restart_required = 0; + struct rx *rx_to_start = NULL; + + /* are we already rnr? then pay attention!!! this ensures that + * the state machine progression never allows a start with a + * partially cleaned list, avoiding a race between hardware + * and rx_to_clean when in NAPI mode */ + if(RU_SUSPENDED == nic->ru_running) + restart_required = 1; + + /* Indicate newly arrived packets */ + for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { + int err = e100_rx_indicate(nic, rx, work_done, work_to_do); + if(-EAGAIN == err) { + /* hit quota so have more work to do, restart once + * cleanup is complete */ + restart_required = 0; + break; + } else if(-ENODATA == err) + break; /* No more to clean */ + } + + /* save our starting point as the place we'll restart the receiver */ + if(restart_required) + rx_to_start = nic->rx_to_clean; + + /* Alloc new skbs to refill list */ + for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { + if(unlikely(e100_rx_alloc_skb(nic, rx))) + break; /* Better luck next time (see watchdog) */ + } + + if(restart_required) { + // ack the rnr? + writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); + e100_start_receiver(nic, rx_to_start); + if(work_done) + (*work_done)++; + } +} + +static void e100_rx_clean_list(struct nic *nic) +{ + struct rx *rx; + unsigned int i, count = nic->params.rfds.count; + + nic->ru_running = RU_UNINITIALIZED; + + if(nic->rxs) { + for(rx = nic->rxs, i = 0; i < count; rx++, i++) { + if(rx->skb) { + pci_unmap_single(nic->pdev, rx->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rx->skb); + } + } + kfree(nic->rxs); + nic->rxs = NULL; + } + + nic->rx_to_use = nic->rx_to_clean = NULL; +} + +static int e100_rx_alloc_list(struct nic *nic) +{ + struct rx *rx; + unsigned int i, count = nic->params.rfds.count; + + nic->rx_to_use = nic->rx_to_clean = NULL; + nic->ru_running = RU_UNINITIALIZED; + + if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC))) + return -ENOMEM; + + for(rx = nic->rxs, i = 0; i < count; rx++, i++) { + rx->next = (i + 1 < count) ? rx + 1 : nic->rxs; + rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1; + if(e100_rx_alloc_skb(nic, rx)) { + e100_rx_clean_list(nic); + return -ENOMEM; + } + } + + nic->rx_to_use = nic->rx_to_clean = nic->rxs; + nic->ru_running = RU_SUSPENDED; + + return 0; +} + +static irqreturn_t e100_intr(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct nic *nic = netdev_priv(netdev); + u8 stat_ack = ioread8(&nic->csr->scb.stat_ack); + + DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); + + if(stat_ack == stat_ack_not_ours || /* Not our interrupt */ + stat_ack == stat_ack_not_present) /* Hardware is ejected */ + return IRQ_NONE; + + /* Ack interrupt(s) */ + iowrite8(stat_ack, &nic->csr->scb.stat_ack); + + /* We hit Receive No Resource (RNR); restart RU after cleaning */ + if(stat_ack & stat_ack_rnr) + nic->ru_running = RU_SUSPENDED; + + if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) { + e100_disable_irq(nic); + __netif_rx_schedule(netdev, &nic->napi); + } + + return IRQ_HANDLED; +} + +static int e100_poll(struct napi_struct *napi, int budget) +{ + struct nic *nic = container_of(napi, struct nic, napi); + struct net_device *netdev = nic->netdev; + unsigned int work_done = 0; + + e100_rx_clean(nic, &work_done, budget); + e100_tx_clean(nic); + + /* If budget not fully consumed, exit the polling mode */ + if (work_done < budget) { + netif_rx_complete(netdev, napi); + e100_enable_irq(nic); + } + + return work_done; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void e100_netpoll(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + + e100_disable_irq(nic); + e100_intr(nic->pdev->irq, netdev); + e100_tx_clean(nic); + e100_enable_irq(nic); +} +#endif + +static int e100_set_mac_address(struct net_device *netdev, void *p) +{ + struct nic *nic = netdev_priv(netdev); + 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 <= 0x1057) && + (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, NULL); + mod_timer(&nic->watchdog, jiffies); + if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED, + nic->netdev->name, nic->netdev))) + goto err_no_irq; + netif_wake_queue(nic->netdev); + napi_enable(&nic->napi); + /* enable ints _after_ enabling poll, preventing a race between + * disable ints+schedule */ + e100_enable_irq(nic); + return 0; + +err_no_irq: + del_timer_sync(&nic->watchdog); +err_clean_cbs: + e100_clean_cbs(nic); +err_rx_clean_list: + e100_rx_clean_list(nic); + return err; +} + +static void e100_down(struct nic *nic) +{ + /* wait here for poll to complete */ + napi_disable(&nic->napi); + netif_stop_queue(nic->netdev); + e100_hw_reset(nic); + free_irq(nic->pdev->irq, nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + e100_clean_cbs(nic); + e100_rx_clean_list(nic); +} + +static void e100_tx_timeout(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + + /* Reset outside of interrupt context, to avoid request_irq + * in interrupt context */ + schedule_work(&nic->tx_timeout_task); +} + +static void e100_tx_timeout_task(struct work_struct *work) +{ + struct nic *nic = container_of(work, struct nic, tx_timeout_task); + struct net_device *netdev = nic->netdev; + + DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", + ioread8(&nic->csr->scb.status)); + e100_down(netdev_priv(netdev)); + e100_up(netdev_priv(netdev)); +} + +static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) +{ + int err; + struct sk_buff *skb; + + /* 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, NULL); + + if(!(skb = netdev_alloc_skb(nic->netdev, 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); + + msleep(10); + + pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + + if(memcmp(nic->rx_to_clean->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_clean_cbs(nic); + e100_hw_reset(nic); +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(netdev); + 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(netdev); + 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(netdev); + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, pci_name(nic->pdev)); +} + +#define E100_PHY_REGS 0x1C +static int e100_get_regs_len(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return 1 + E100_PHY_REGS + sizeof(nic->mem->dump_buf); +} + +static void e100_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct nic *nic = netdev_priv(netdev); + u32 *buff = p; + int i; + + regs->version = (1 << 24) | nic->pdev->revision; + buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 | + ioread8(&nic->csr->scb.cmd_lo) << 16 | + ioread16(&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); + msleep(10); + 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(netdev); + 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(netdev); + + if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + return -EOPNOTSUPP; + + if(wol->wolopts) + nic->flags |= wol_magic; + else + nic->flags &= ~wol_magic; + + e100_exec_cb(nic, NULL, e100_configure); + + return 0; +} + +static u32 e100_get_msglevel(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return nic->msg_enable; +} + +static void e100_set_msglevel(struct net_device *netdev, u32 value) +{ + struct nic *nic = netdev_priv(netdev); + nic->msg_enable = value; +} + +static int e100_nway_reset(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return mii_nway_restart(&nic->mii); +} + +static u32 e100_get_link(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return mii_link_ok(&nic->mii); +} + +static int e100_get_eeprom_len(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + 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(netdev); + + 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(netdev); + + 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(netdev); + 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(netdev); + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + 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); + DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n", + rfds->count, cbs->count); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} + +static const 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 void e100_diag_test(struct net_device *netdev, + struct ethtool_test *test, u64 *data) +{ + struct ethtool_cmd cmd; + struct nic *nic = netdev_priv(netdev); + int i, err; + + 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) { + + /* save speed, duplex & autoneg settings */ + err = mii_ethtool_gset(&nic->mii, &cmd); + + 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); + + /* restore speed, duplex & autoneg settings */ + err = mii_ethtool_sset(&nic->mii, &cmd); + + if(netif_running(netdev)) + e100_up(nic); + } + for(i = 0; i < E100_TEST_LEN; i++) + test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0; + + msleep_interruptible(4 * 1000); +} + +static int e100_phys_id(struct net_device *netdev, u32 data) +{ + struct nic *nic = netdev_priv(netdev); + + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + mod_timer(&nic->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&nic->blink_timer); + mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); + + return 0; +} + +static const 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_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_TEST: + return E100_TEST_LEN; + case ETH_SS_STATS: + return E100_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void e100_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct nic *nic = netdev_priv(netdev); + int i; + + for(i = 0; i < E100_NET_STATS_LEN; i++) + data[i] = ((unsigned long *)&netdev->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 const 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 = e100_diag_test, + .get_strings = e100_get_strings, + .phys_id = e100_phys_id, + .get_ethtool_stats = e100_get_ethtool_stats, + .get_sset_count = e100_get_sset_count, +}; + +static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct nic *nic = netdev_priv(netdev); + + return generic_mii_ioctl(&nic->mii, if_mii(ifr), 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(netdev); + 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(netdev)); + 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; + DECLARE_MAC_BUF(mac); + + 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->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_NET_POLL_CONTROLLER + netdev->poll_controller = e100_netpoll; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + nic = netdev_priv(netdev); + netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT); + 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; + } + + if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n"); + goto err_out_free_res; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + if (use_io) + DPRINTK(PROBE, INFO, "using i/o access mode\n"); + + nic->csr = pci_iomap(pdev, (use_io ? 1 : 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; + + e100_get_defaults(nic); + + /* locks must be initialized before calling hw_reset */ + spin_lock_init(&nic->cb_lock); + spin_lock_init(&nic->cmd_lock); + spin_lock_init(&nic->mdio_lock); + + /* Reset the device before pci_set_master() in case device is in some + * funky state and has an interrupt pending - hint: we don't have the + * interrupt handler registered yet. */ + e100_hw_reset(nic); + + pci_set_master(pdev); + + 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; + + INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task); + + if((err = e100_alloc(nic))) { + DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); + goto err_out_iounmap; + } + + if((err = e100_eeprom_load(nic))) + goto err_out_free; + + e100_phy_init(nic); + + memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); + memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); + if (!is_valid_ether_addr(netdev->perm_addr)) { + if (!eeprom_bad_csum_allow) { + DPRINTK(PROBE, ERR, "Invalid MAC address from " + "EEPROM, aborting.\n"); + err = -EAGAIN; + goto err_out_free; + } else { + DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, " + "you MUST configure one.\n"); + } + } + + /* 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; + + /* ack any pending wake events, disable PME */ + err = pci_enable_wake(pdev, 0, 0); + if (err) + DPRINTK(PROBE, ERR, "Error clearing wake event\n"); + + strcpy(netdev->name, "eth%d"); + if((err = register_netdev(netdev))) { + DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); + goto err_out_free; + } + + DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n", + (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), + pdev->irq, print_mac(mac, netdev->dev_addr)); + + return 0; + +err_out_free: + e100_free(nic); +err_out_iounmap: + pci_iounmap(pdev, 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(netdev); + 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, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + if (netif_running(netdev)) + napi_disable(&nic->napi); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + netif_device_detach(netdev); + + pci_save_state(pdev); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + free_irq(pdev->irq, netdev); + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int e100_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, 0, 0); + + netif_device_attach(netdev); + if (netif_running(netdev)) + e100_up(nic); + + return 0; +} +#endif /* CONFIG_PM */ + +static void e100_shutdown(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + if (netif_running(netdev)) + napi_disable(&nic->napi); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + free_irq(pdev->irq, netdev); + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); +} + +/* ------------------ PCI Error Recovery infrastructure -------------- */ +/** + * e100_io_error_detected - called when PCI error is detected. + * @pdev: Pointer to PCI device + * @state: The current pci conneection state + */ +static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + /* Similar to calling e100_down(), but avoids adpater I/O. */ + netdev->stop(netdev); + + /* Detach; put netif into state similar to hotplug unplug. */ + napi_enable(&nic->napi); + netif_device_detach(netdev); + pci_disable_device(pdev); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * e100_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch. + */ +static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + if (pci_enable_device(pdev)) { + printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + /* Only one device per card can do a reset */ + if (0 != PCI_FUNC(pdev->devfn)) + return PCI_ERS_RESULT_RECOVERED; + e100_hw_reset(nic); + e100_phy_init(nic); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * e100_io_resume - resume normal operations + * @pdev: Pointer to PCI device + * + * Resume normal operations after an error recovery + * sequence has been completed. + */ +static void e100_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, 0, 0); + + netif_device_attach(netdev); + if (netif_running(netdev)) { + e100_open(netdev); + mod_timer(&nic->watchdog, jiffies); + } +} + +static struct pci_error_handlers e100_err_handler = { + .error_detected = e100_io_error_detected, + .slot_reset = e100_io_slot_reset, + .resume = e100_io_resume, +}; + +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 + /* Power Management hooks */ + .suspend = e100_suspend, + .resume = e100_resume, +#endif + .shutdown = e100_shutdown, + .err_handler = &e100_err_handler, +}; + +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_register_driver(&e100_driver); +} + +static void __exit e100_cleanup_module(void) +{ + pci_unregister_driver(&e100_driver); +} + +module_init(e100_init_module); +module_exit(e100_cleanup_module); diff -Nurb linux-2.6.24.3/drivers/net/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig --- linux-2.6.24.3/drivers/net/Kconfig 2008-02-25 16:20:20.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig 2008-03-02 14:55:48.000000000 -0800 @@ -1440,6 +1440,16 @@ To compile this driver as a module, choose M here. The module will be called e100. +config E100_IGNORE_CSUM + bool "Ignore bad EEPROM checksum" + depends on E100 && EXPERIMENTAL && !CLEAN_COMPILE + help + This option tells the e100 driver to ignore bad EEPROM checksums. + Usually this is a bad idea, as an incorrect checksum can indicate a + serious issue with the network card. + + If unsure, say N. + config LNE390 tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" depends on NET_PCI && EISA && EXPERIMENTAL diff -Nurb linux-2.6.24.3/drivers/net/Kconfig.orig linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig.orig --- linux-2.6.24.3/drivers/net/Kconfig.orig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig.orig 2008-02-25 16:20:20.000000000 -0800 @@ -0,0 +1,3069 @@ + +# +# Network device configuration +# + +menuconfig NETDEVICES + default y if UML + depends on NET + bool "Network device support" + ---help--- + You can say N here if you don't intend to connect your Linux box to + any other computer at all. + + You'll have to say Y if your computer contains a network card that + you want to use under Linux. If you are going to run SLIP or PPP over + telephone line or null modem cable you need say Y here. Connecting + two machines with parallel ports using PLIP needs this, as well as + AX.25/KISS for sending Internet traffic over amateur radio links. + + See also "The Linux Network Administrator's Guide" by Olaf Kirch and + Terry Dawson. Available at . + + If unsure, say Y. + +# All the following symbols are dependent on NETDEVICES - do not repeat +# that for each of the symbols. +if NETDEVICES + +config NETDEVICES_MULTIQUEUE + bool "Netdevice multiple hardware queue support" + ---help--- + Say Y here if you want to allow the network stack to use multiple + hardware TX queues on an ethernet device. + + Most people will say N here. + +config IFB + tristate "Intermediate Functional Block support" + depends on NET_CLS_ACT + ---help--- + This is an intermediate driver that allows sharing of + resources. + To compile this driver as a module, choose M here: the module + will be called ifb. If you want to use more than one ifb + device at a time, you need to compile this driver as a module. + Instead of 'ifb', the devices will then be called 'ifb0', + 'ifb1' etc. + Look at the iproute2 documentation directory for usage etc + +config DUMMY + tristate "Dummy net driver support" + ---help--- + This is essentially a bit-bucket device (i.e. traffic you send to + this device is consigned into oblivion) with a configurable IP + address. It is most commonly used in order to make your currently + inactive SLIP address seem like a real address for local programs. + If you use SLIP or PPP, you might want to say Y here. Since this + thing often comes in handy, the default is Y. It won't enlarge your + kernel either. What a deal. Read about it in the Network + Administrator's Guide, available from + . + + To compile this driver as a module, choose M here: the module + will be called dummy. If you want to use more than one dummy + device at a time, you need to compile this driver as a module. + Instead of 'dummy', the devices will then be called 'dummy0', + 'dummy1' etc. + +config BONDING + tristate "Bonding driver support" + depends on INET + ---help--- + Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet + Channels together. This is called 'Etherchannel' by Cisco, + 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux. + + The driver supports multiple bonding modes to allow for both high + performance and high availability operation. + + Refer to for more + information. + + To compile this driver as a module, choose M here: the module + will be called bonding. + +config MACVLAN + tristate "MAC-VLAN support (EXPERIMENTAL)" + depends on EXPERIMENTAL + ---help--- + This allows one to create virtual interfaces that map packets to + or from specific MAC addresses to a particular interface. + + To compile this driver as a module, choose M here: the module + will be called macvlan. + +config EQUALIZER + tristate "EQL (serial line load balancing) support" + ---help--- + If you have two serial connections to some other computer (this + usually requires two modems and two telephone lines) and you use + SLIP (the protocol for sending Internet traffic over telephone + lines) or PPP (a better SLIP) on them, you can make them behave like + one double speed connection using this driver. Naturally, this has + to be supported at the other end as well, either with a similar EQL + Linux driver or with a Livingston Portmaster 2e. + + Say Y if you want this and read + . You may also want to read + section 6.2 of the NET-3-HOWTO, available from + . + + To compile this driver as a module, choose M here: the module + will be called eql. If unsure, say N. + +config TUN + tristate "Universal TUN/TAP device driver support" + select CRC32 + ---help--- + TUN/TAP provides packet reception and transmission for user space + programs. It can be viewed as a simple Point-to-Point or Ethernet + device, which instead of receiving packets from a physical media, + receives them from user space program and instead of sending packets + via physical media writes them to the user space program. + + When a program opens /dev/net/tun, driver creates and registers + corresponding net device tunX or tapX. After a program closed above + devices, driver will automatically delete tunXX or tapXX device and + all routes corresponding to it. + + Please read for more + information. + + To compile this driver as a module, choose M here: the module + will be called tun. + + If you don't know what to use this for, you don't need it. + +config VETH + tristate "Virtual ethernet pair device" + ---help--- + This device is a local ethernet tunnel. Devices are created in pairs. + When one end receives the packet it appears on its pair and vice + versa. + +config NET_SB1000 + tristate "General Instruments Surfboard 1000" + depends on PNP + ---help--- + This is a driver for the General Instrument (also known as + NextLevel) SURFboard 1000 internal + cable modem. This is an ISA card which is used by a number of cable + TV companies to provide cable modem access. It's a one-way + downstream-only cable modem, meaning that your upstream net link is + provided by your regular phone modem. + + At present this driver only compiles as a module, so say M here if + you have this card. The module will be called sb1000. Then read + for information on how + to use this module, as it needs special ppp scripts for establishing + a connection. Further documentation and the necessary scripts can be + found at: + + + + + + If you don't have this card, of course say N. + +source "drivers/net/arcnet/Kconfig" + +source "drivers/net/phy/Kconfig" + +# +# Ethernet +# + +menuconfig NET_ETHERNET + bool "Ethernet (10 or 100Mbit)" + depends on !UML + ---help--- + Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common + type of Local Area Network (LAN) in universities and companies. + + Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over + coaxial cable, linking computers in a chain), 10BASE-T or twisted + pair (10 Mbps over twisted pair cable, linking computers to central + hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs), + 100BASE-TX (100 Mbps over two twisted pair cables, using hubs), + 100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair + cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links) + [the 100BASE varieties are also known as Fast Ethernet], and Gigabit + Ethernet (1 Gbps over optical fiber or short copper links). + + If your Linux machine will be connected to an Ethernet and you have + an Ethernet network interface card (NIC) installed in your computer, + say Y here and read the Ethernet-HOWTO, available from + . You will then also have + to say Y to the driver for your particular NIC. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Ethernet network cards. If unsure, say N. + +if NET_ETHERNET + +config MII + tristate "Generic Media Independent Interface device support" + help + Most ethernet controllers have MII transceiver either as an external + or internal device. It is safe to say Y or M here even if your + ethernet card lack MII. + +config MACB + tristate "Atmel MACB support" + depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 + select PHYLIB + help + The Atmel MACB ethernet interface is found on many AT32 and AT91 + parts. Say Y to include support for the MACB chip. + + To compile this driver as a module, choose M here: the module + will be called macb. + +source "drivers/net/arm/Kconfig" + +config AX88796 + tristate "ASIX AX88796 NE2000 clone support" + depends on ARM || MIPS || SUPERH + select CRC32 + select MII + help + AX88796 driver, using platform bus to provide + chip detection and resources + +config AX88796_93CX6 + bool "ASIX AX88796 external 93CX6 eeprom support" + depends on AX88796 + select EEPROM_93CX6 + help + Select this if your platform comes with an external 93CX6 eeprom. + +config MACE + tristate "MACE (Power Mac ethernet) support" + depends on PPC_PMAC && PPC32 + select CRC32 + help + Power Macintoshes and clones with Ethernet built-in on the + motherboard will usually use a MACE (Medium Access Control for + Ethernet) interface. Say Y to include support for the MACE chip. + + To compile this driver as a module, choose M here: the module + will be called mace. + +config MACE_AAUI_PORT + bool "Use AAUI port instead of TP by default" + depends on MACE + help + Some Apple machines (notably the Apple Network Server) which use the + MACE ethernet chip have an Apple AUI port (small 15-pin connector), + instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say + Y here if you have such a machine. If unsure, say N. + The driver will default to AAUI on ANS anyway, and if you use it as + a module, you can provide the port_aaui=0|1 to force the driver. + +config BMAC + tristate "BMAC (G3 ethernet) support" + depends on PPC_PMAC && PPC32 + select CRC32 + help + Say Y for support of BMAC Ethernet interfaces. These are used on G3 + computers. + + To compile this driver as a module, choose M here: the module + will be called bmac. + +config ARIADNE + tristate "Ariadne support" + depends on ZORRO + help + If you have a Village Tronic Ariadne Ethernet adapter, say Y. + Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called ariadne. + +config A2065 + tristate "A2065 support" + depends on ZORRO + select CRC32 + help + If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise, + say N. + + To compile this driver as a module, choose M here: the module + will be called a2065. + +config HYDRA + tristate "Hydra support" + depends on ZORRO + select CRC32 + help + If you have a Hydra Ethernet adapter, say Y. Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called hydra. + +config ZORRO8390 + tristate "Zorro NS8390-based Ethernet support" + depends on ZORRO + select CRC32 + help + This driver is for Zorro Ethernet cards using an NS8390-compatible + chipset, like the Village Tronic Ariadne II and the Individual + Computers X-Surf Ethernet cards. If you have such a card, say Y. + Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called zorro8390. + +config APNE + tristate "PCMCIA NE2000 support" + depends on AMIGA_PCMCIA + select CRC32 + help + If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, + say N. + + To compile this driver as a module, choose M here: the module + will be called apne. + +config APOLLO_ELPLUS + tristate "Apollo 3c505 support" + depends on APOLLO + help + Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card. + If you don't have one made for Apollos, you can use one from a PC, + except that your Apollo won't be able to boot from it (because the + code in the ROM will be for a PC). + +config MAC8390 + bool "Macintosh NS 8390 based ethernet cards" + depends on MAC + select CRC32 + help + If you want to include a driver to support Nubus or LC-PDS + Ethernet cards using an NS8390 chipset or its equivalent, say Y + and read the Ethernet-HOWTO, available from + . + +config MAC89x0 + tristate "Macintosh CS89x0 based ethernet cards" + depends on MAC + ---help--- + Support for CS89x0 chipset based Ethernet cards. If you have a + Nubus or LC-PDS network (Ethernet) card of this type, say Y and + read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. This module will + be called mac89x0. + +config MACSONIC + tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)" + depends on MAC + ---help--- + Support for NatSemi SONIC based Ethernet devices. This includes + the onboard Ethernet in many Quadras as well as some LC-PDS, + a few Nubus and all known Comm Slot Ethernet cards. If you have + one of these say Y and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. This module will + be called macsonic. + +config MACMACE + bool "Macintosh (AV) onboard MACE ethernet" + depends on MAC + select CRC32 + help + Support for the onboard AMD 79C940 MACE Ethernet controller used in + the 660AV and 840AV Macintosh. If you have one of these Macintoshes + say Y and read the Ethernet-HOWTO, available from + . + +config MVME147_NET + tristate "MVME147 (Lance) Ethernet support" + depends on MVME147 + select CRC32 + help + Support for the on-board Ethernet interface on the Motorola MVME147 + single-board computer. Say Y here to include the + driver for this chip in your kernel. + To compile this driver as a module, choose M here. + +config MVME16x_NET + tristate "MVME16x Ethernet support" + depends on MVME16x + help + This is the driver for the Ethernet interface on the Motorola + MVME162, 166, 167, 172 and 177 boards. Say Y here to include the + driver for this chip in your kernel. + To compile this driver as a module, choose M here. + +config BVME6000_NET + tristate "BVME6000 Ethernet support" + depends on BVME6000 + help + This is the driver for the Ethernet interface on BVME4000 and + BVME6000 VME boards. Say Y here to include the driver for this chip + in your kernel. + To compile this driver as a module, choose M here. + +config ATARILANCE + tristate "Atari Lance support" + depends on ATARI + help + Say Y to include support for several Atari Ethernet adapters based + on the AMD Lance chipset: RieblCard (with or without battery), or + PAMCard VME (also the version by Rhotron, with different addresses). + +config SUN3LANCE + tristate "Sun3/Sun3x on-board LANCE support" + depends on SUN3 || SUN3X + help + Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80) + featured an AMD Lance 10Mbit Ethernet controller on board; say Y + here to compile in the Linux driver for this and enable Ethernet. + General Linux information on the Sun 3 and 3x series (now + discontinued) is at + . + + If you're not building a kernel for a Sun 3, say N. + +config SUN3_82586 + bool "Sun3 on-board Intel 82586 support" + depends on SUN3 + help + This driver enables support for the on-board Intel 82586 based + Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note + that this driver does not support 82586-based adapters on additional + VME boards. + +config HPLANCE + bool "HP on-board LANCE support" + depends on DIO + select CRC32 + help + If you want to use the builtin "LANCE" Ethernet controller on an + HP300 machine, say Y here. + +config LASI_82596 + tristate "Lasi ethernet" + depends on GSC + help + Say Y here to support the builtin Intel 82596 ethernet controller + found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet. + +config SNI_82596 + tristate "SNI RM ethernet" + depends on NET_ETHERNET && SNI_RM + help + Say Y here to support the on-board Intel 82596 ethernet controller + built into SNI RM machines. + +config MIPS_JAZZ_SONIC + tristate "MIPS JAZZ onboard SONIC Ethernet support" + depends on MACH_JAZZ + help + This is the driver for the onboard card of MIPS Magnum 4000, + Acer PICA, Olivetti M700-10 and a few other identical OEM systems. + +config MIPS_AU1X00_ENET + bool "MIPS AU1000 Ethernet support" + depends on SOC_AU1X00 + select PHYLIB + select CRC32 + help + If you have an Alchemy Semi AU1X00 based system + say Y. Otherwise, say N. + +config SGI_IOC3_ETH + bool "SGI IOC3 Ethernet" + depends on PCI && SGI_IP27 + select CRC32 + select MII + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + +config MIPS_SIM_NET + tristate "MIPS simulator Network device" + depends on MIPS_SIM + help + The MIPSNET device is a simple Ethernet network device which is + emulated by the MIPS Simulator. + If you are not using a MIPSsim or are unsure, say N. + +config SGI_O2MACE_ETH + tristate "SGI O2 MACE Fast Ethernet support" + depends on SGI_IP32=y + +config STNIC + tristate "National DP83902AV support" + depends on SUPERH + select CRC32 + help + Support for cards based on the National Semiconductor DP83902AV + ST-NIC Serial Network Interface Controller for Twisted Pair. This + is a 10Mbit/sec Ethernet controller. Product overview and specs at + . + + If unsure, say N. + +config SUNLANCE + tristate "Sun LANCE support" + depends on SBUS + select CRC32 + help + This driver supports the "le" interface present on all 32-bit Sparc + systems, on some older Ultra systems and as an Sbus option. These + cards are based on the AMD Lance chipset, which is better known + via the NE2100 cards. + + To compile this driver as a module, choose M here: the module + will be called sunlance. + +config HAPPYMEAL + tristate "Sun Happy Meal 10/100baseT support" + depends on SBUS || PCI + select CRC32 + help + This driver supports the "hme" interface present on most Ultra + systems and as an option on older Sbus systems. This driver supports + both PCI and Sbus devices. This driver also supports the "qfe" quad + 100baseT device available in both PCI and Sbus configurations. + + To compile this driver as a module, choose M here: the module + will be called sunhme. + +config SUNBMAC + tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)" + depends on SBUS && EXPERIMENTAL + select CRC32 + help + This driver supports the "be" interface available as an Sbus option. + This is Sun's older 100baseT Ethernet device. + + To compile this driver as a module, choose M here: the module + will be called sunbmac. + +config SUNQE + tristate "Sun QuadEthernet support" + depends on SBUS + select CRC32 + help + This driver supports the "qe" 10baseT Ethernet device, available as + an Sbus option. Note that this is not the same as Quad FastEthernet + "qfe" which is supported by the Happy Meal driver instead. + + To compile this driver as a module, choose M here: the module + will be called sunqe. + +config SUNGEM + tristate "Sun GEM support" + depends on PCI + select CRC32 + help + Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also + . + +config CASSINI + tristate "Sun Cassini support" + depends on PCI + select CRC32 + help + Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also + + +config SUNVNET + tristate "Sun Virtual Network support" + depends on SUN_LDOMS + help + Support for virtual network devices under Sun Logical Domains. + +config NET_VENDOR_3COM + bool "3COM cards" + depends on ISA || EISA || MCA || PCI + help + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about 3COM cards. If you say Y, you will be asked for + your specific card in the following questions. + +config EL1 + tristate "3c501 \"EtherLink\" support" + depends on NET_VENDOR_3COM && ISA + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . Also, consider buying a + new card, since the 3c501 is slow, broken, and obsolete: you will + have problems. Some people suggest to ping ("man ping") a nearby + machine every minute ("man cron") when using this card. + + To compile this driver as a module, choose M here. The module + will be called 3c501. + +config EL2 + tristate "3c503 \"EtherLink II\" support" + depends on NET_VENDOR_3COM && ISA + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called 3c503. + +config ELPLUS + tristate "3c505 \"EtherLink Plus\" support" + depends on NET_VENDOR_3COM && ISA && ISA_DMA_API + ---help--- + Information about this network (Ethernet) card can be found in + . If you have a card of + this type, say Y and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called 3c505. + +config EL16 + tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)" + depends on NET_VENDOR_3COM && ISA && EXPERIMENTAL + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called 3c507. + +config EL3 + tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support" + depends on NET_VENDOR_3COM && (ISA || EISA || MCA) + ---help--- + If you have a network (Ethernet) card belonging to the 3Com + EtherLinkIII series, say Y and read the Ethernet-HOWTO, available + from . + + If your card is not working you may need to use the DOS + setup disk to disable Plug & Play mode, and to select the default + media type. + + To compile this driver as a module, choose M here. The module + will be called 3c509. + +config 3C515 + tristate "3c515 ISA \"Fast EtherLink\"" + depends on NET_VENDOR_3COM && (ISA || EISA) && ISA_DMA_API + help + If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet + network card, say Y and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called 3c515. + +config ELMC + tristate "3c523 \"EtherLink/MC\" support" + depends on NET_VENDOR_3COM && MCA_LEGACY + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called 3c523. + +config ELMC_II + tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)" + 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 + . + + To compile this driver as a module, choose M here. The module + will be called 3c527. + +config VORTEX + tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support" + depends on NET_VENDOR_3COM && (PCI || EISA) + select MII + ---help--- + This option enables driver support for a large number of 10Mbps and + 10/100Mbps EISA, PCI and PCMCIA 3Com network cards: + + "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI + "Boomerang" (EtherLink XL 3c900 or 3c905) PCI + "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus + "Tornado" (3c905) PCI + "Hurricane" (3c555/3cSOHO) PCI + + If you have such a card, say Y and read the Ethernet-HOWTO, + available from . More + specific information is in + and in the comments at + the beginning of . + + To compile this support as a module, choose M here. + +config TYPHOON + tristate "3cr990 series \"Typhoon\" support" + depends on NET_VENDOR_3COM && PCI + select CRC32 + ---help--- + This option enables driver support for the 3cr990 series of cards: + + 3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97, + 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server, + 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR + + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called typhoon. + +config LANCE + tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" + depends on ISA && ISA_DMA_API + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . Some LinkSys cards are + of this type. + + To compile this driver as a module, choose M here: the module + will be called lance. This is recommended. + +config NET_VENDOR_SMC + bool "Western Digital/SMC cards" + depends on ISA || MCA || EISA || MAC + help + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Western Digital cards. If you say Y, you will be + asked for your specific card in the following questions. + +config WD80x3 + tristate "WD80*3 support" + depends on NET_VENDOR_SMC && ISA + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called wd. + +config ULTRAMCA + tristate "SMC Ultra MCA support" + depends on NET_VENDOR_SMC && MCA + select CRC32 + help + If you have a network (Ethernet) card of this type and are running + an MCA based system (PS/2), say Y and read the Ethernet-HOWTO, + available from . + + To compile this driver as a module, choose M here. The module + will be called smc-mca. + +config ULTRA + tristate "SMC Ultra support" + depends on NET_VENDOR_SMC && ISA + select CRC32 + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + Important: There have been many reports that, with some motherboards + mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, + such as some BusLogic models) causes corruption problems with many + operating systems. The Linux smc-ultra driver has a work-around for + this but keep it in mind if you have such a SCSI card and have + problems. + + To compile this driver as a module, choose M here. The module + will be called smc-ultra. + +config ULTRA32 + tristate "SMC Ultra32 EISA support" + depends on NET_VENDOR_SMC && EISA + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called smc-ultra32. + +config BFIN_MAC + tristate "Blackfin 536/537 on-chip mac support" + depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H) + select CRC32 + select MII + select PHYLIB + select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE + help + This is the driver for blackfin on-chip mac device. Say Y if you want it + compiled into the kernel. This driver is also available as a module + ( = code which can be inserted in and removed from the running kernel + whenever you want). The module will be called bfin_mac. + +config BFIN_MAC_USE_L1 + bool "Use L1 memory for rx/tx packets" + depends on BFIN_MAC && BF537 + default y + help + To get maximum network performance, you should use L1 memory as rx/tx buffers. + Say N here if you want to reserve L1 memory for other uses. + +config BFIN_TX_DESC_NUM + int "Number of transmit buffer packets" + depends on BFIN_MAC + range 6 10 if BFIN_MAC_USE_L1 + range 10 100 + default "10" + help + Set the number of buffer packets used in driver. + +config BFIN_RX_DESC_NUM + int "Number of receive buffer packets" + depends on BFIN_MAC + range 20 100 if BFIN_MAC_USE_L1 + range 20 800 + default "20" + help + Set the number of buffer packets used in driver. + +config BFIN_MAC_RMII + bool "RMII PHY Interface (EXPERIMENTAL)" + depends on BFIN_MAC && EXPERIMENTAL + default n + help + Use Reduced PHY MII Interface + +config SMC9194 + tristate "SMC 9194 support" + depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN) + select CRC32 + ---help--- + This is support for the SMC9xxx based Ethernet cards. Choose this + option if you have a DELL laptop with the docking station, or + another SMC9192/9194 based chipset. Say Y if you want it compiled + into the kernel, and read the file + and the Ethernet-HOWTO, + available from . + + To compile this driver as a module, choose M here. The module + will be called smc9194. + +config SMC91X + tristate "SMC 91C9x/91C1xxx support" + select CRC32 + select MII + depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BLACKFIN + help + This is a driver for SMC's 91x series of Ethernet chipsets, + including the SMC91C94 and the SMC91C111. Say Y if you want it + compiled into the kernel, and read the file + and the Ethernet-HOWTO, + available from . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc91x. If you want to compile it as a + module, say M here and read . + +config NET_NETX + tristate "NetX Ethernet support" + select MII + depends on ARCH_NETX + help + This is support for the Hilscher netX builtin Ethernet ports + + To compile this driver as a module, choose M here. The module + will be called netx-eth. + +config DM9000 + tristate "DM9000 support" + depends on ARM || BLACKFIN || MIPS + select CRC32 + select MII + ---help--- + Support for DM9000 chipset. + + To compile this driver as a module, choose M here. The module + will be called dm9000. + +config SMC911X + tristate "SMSC LAN911[5678] support" + select CRC32 + select MII + depends on ARCH_PXA || SH_MAGIC_PANEL_R2 + help + This is a driver for SMSC's LAN911x series of Ethernet chipsets + including the new LAN9115, LAN9116, LAN9117, and LAN9118. + Say Y if you want it compiled into the kernel, + and read the Ethernet-HOWTO, available from + . + + This driver is also available as a module. The module will be + called smc911x. If you want to compile it as a module, say M + here and read + +config NET_VENDOR_RACAL + bool "Racal-Interlan (Micom) NI cards" + depends on ISA + help + If you have a network (Ethernet) card belonging to this class, such + as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, + available from . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about NI cards. If you say Y, you will be asked for + your specific card in the following questions. + +config NI5010 + tristate "NI5010 support (EXPERIMENTAL)" + depends on NET_VENDOR_RACAL && ISA && EXPERIMENTAL && BROKEN_ON_SMP + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . Note that this is still + experimental code. + + To compile this driver as a module, choose M here. The module + will be called ni5010. + +config NI52 + tristate "NI5210 support" + depends on NET_VENDOR_RACAL && ISA + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called ni52. + +config NI65 + tristate "NI6510 support" + depends on NET_VENDOR_RACAL && ISA && ISA_DMA_API + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called ni65. + +source "drivers/net/tulip/Kconfig" + +config AT1700 + tristate "AT1700/1720 support (EXPERIMENTAL)" + depends on (ISA || MCA_LEGACY) && EXPERIMENTAL + select CRC32 + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called at1700. + +config DEPCA + tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support" + depends on ISA || EISA || MCA + select CRC32 + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + as well as + . + + To compile this driver as a module, choose M here. The module + will be called depca. + +config HP100 + tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support" + depends on ISA || EISA || PCI + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called hp100. + +config NET_ISA + bool "Other ISA cards" + depends on ISA + ---help--- + If your network (Ethernet) card hasn't been mentioned yet and its + bus system (that's the way the cards talks to the other components + of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y. + Make sure you know the name of your card. Read the Ethernet-HOWTO, + available from . + + If unsure, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the remaining ISA network card questions. If you say Y, you will be + asked for your specific card in the following questions. + +config E2100 + tristate "Cabletron E21xx support" + depends on NET_ISA + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called e2100. + +config EWRK3 + tristate "EtherWORKS 3 (DE203, DE204, DE205) support" + depends on NET_ISA + select CRC32 + ---help--- + This driver supports the DE203, DE204 and DE205 network (Ethernet) + cards. If this is for you, say Y and read + in the kernel source as + well as the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called ewrk3. + +config EEXPRESS + tristate "EtherExpress 16 support" + depends on NET_ISA + ---help--- + If you have an EtherExpress16 network (Ethernet) card, say Y and + read the Ethernet-HOWTO, available from + . Note that the Intel + EtherExpress16 card used to be regarded as a very poor choice + because the driver was very unreliable. We now have a new driver + that should do better. + + To compile this driver as a module, choose M here. The module + will be called eexpress. + +config EEXPRESS_PRO + tristate "EtherExpressPro support/EtherExpress 10 (i82595) support" + depends on NET_ISA + ---help--- + If you have a network (Ethernet) card of this type, say Y. This + driver supports Intel i82595{FX,TX} based boards. Note however + that the EtherExpress PRO/100 Ethernet card has its own separate + driver. Please read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called eepro. + +config HPLAN_PLUS + tristate "HP PCLAN+ (27247B and 27252A) support" + depends on NET_ISA + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called hp-plus. + +config HPLAN + tristate "HP PCLAN (27245 and other 27xxx series) support" + depends on NET_ISA + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called hp. + +config LP486E + tristate "LP486E on board Ethernet" + depends on NET_ISA + help + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. + +config ETH16I + tristate "ICL EtherTeam 16i/32 support" + depends on NET_ISA + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called eth16i. + +config NE2000 + tristate "NE2000/NE1000 support" + depends on NET_ISA || (Q40 && m) || M32R || TOSHIBA_RBTX4927 || TOSHIBA_RBTX4938 + select CRC32 + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . Many Ethernet cards + without a specific driver are compatible with NE2000. + + If you have a PCI NE2000 card however, say N here and Y to "PCI + NE2000 and clone support" under "EISA, VLB, PCI and on board + controllers" below. If you have a NE2000 card and are running on + an MCA system (a bus system used on some IBM PS/2 computers and + laptops), say N here and Y to "NE/2 (ne2000 MCA version) support", + below. + + To compile this driver as a module, choose M here. The module + will be called ne. + +config ZNET + tristate "Zenith Z-Note support (EXPERIMENTAL)" + depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API + help + The Zenith Z-Note notebook computer has a built-in network + (Ethernet) card, and this is the Linux driver for it. Note that the + IBM Thinkpad 300 is compatible with the Z-Note and is also supported + by this driver. Read the Ethernet-HOWTO, available from + . + +config SEEQ8005 + tristate "SEEQ8005 support (EXPERIMENTAL)" + depends on NET_ISA && EXPERIMENTAL + help + This is a driver for the SEEQ 8005 network (Ethernet) card. If this + is for you, read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called seeq8005. + +config NE2_MCA + tristate "NE/2 (ne2000 MCA version) support" + depends on MCA_LEGACY + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called ne2. + +config IBMLANA + tristate "IBM LAN Adapter/A support" + depends on MCA && MCA_LEGACY + ---help--- + This is a Micro Channel Ethernet adapter. You need to set + CONFIG_MCA to use this driver. It is both available as an in-kernel + driver and as a module. + + To compile this driver as a module, choose M here. The only + currently supported card is the IBM LAN Adapter/A for Ethernet. It + will both support 16K and 32K memory windows, however a 32K window + gives a better security against packet losses. Usage of multiple + boards with this driver should be possible, but has not been tested + up to now due to lack of hardware. + +config IBMVETH + tristate "IBM LAN Virtual Ethernet support" + depends on PPC_PSERIES + ---help--- + This driver supports virtual ethernet adapters on newer IBM iSeries + and pSeries systems. + + To compile this driver as a module, choose M here. The module will + be called ibmveth. + +source "drivers/net/ibm_emac/Kconfig" +source "drivers/net/ibm_newemac/Kconfig" + +config NET_PCI + bool "EISA, VLB, PCI and on board controllers" + depends on ISA || EISA || PCI + help + This is another class of network cards which attach directly to the + bus. If you have one of those, say Y and read the Ethernet-HOWTO, + available from . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about this class of network cards. If you say Y, you + will be asked for your specific card in the following questions. If + you are unsure, say Y. + +config PCNET32 + tristate "AMD PCnet32 PCI support" + depends on NET_PCI && PCI + select CRC32 + select MII + help + If you have a PCnet32 or PCnetPCI based network (Ethernet) card, + answer Y here and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called pcnet32. + +config PCNET32_NAPI + bool "Use RX polling (NAPI)" + depends on PCNET32 + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config AMD8111_ETH + tristate "AMD 8111 (new PCI lance) support" + depends on NET_PCI && PCI + select CRC32 + select MII + help + If you have an AMD 8111-based PCI lance ethernet card, + answer Y here and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called amd8111e. + +config AMD8111E_NAPI + bool "Use RX polling (NAPI)" + depends on AMD8111_ETH + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config ADAPTEC_STARFIRE + tristate "Adaptec Starfire/DuraLAN support" + depends on NET_PCI && PCI + select CRC32 + select MII + help + Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network + adapter. The DuraLAN chip is used on the 64 bit PCI boards from + Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip + driver. + + To compile this driver as a module, choose M here: the module + will be called starfire. This is recommended. + +config ADAPTEC_STARFIRE_NAPI + bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" + depends on ADAPTEC_STARFIRE && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config AC3200 + tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)" + depends on NET_PCI && (ISA || EISA) && EXPERIMENTAL + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called ac3200. + +config APRICOT + tristate "Apricot Xen-II on board Ethernet" + depends on NET_PCI && ISA + 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. The module + will be called apricot. + +config B44 + tristate "Broadcom 440x/47xx ethernet support" + depends on SSB_POSSIBLE + select SSB + select MII + help + If you have a network (Ethernet) controller of this type, say Y + or M and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called b44. + +# Auto-select SSB PCI-HOST support, if possible +config B44_PCI_AUTOSELECT + bool + depends on B44 && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B44_PCICORE_AUTOSELECT + bool + depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B44_PCI + bool + depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT + default y + +config FORCEDETH + tristate "nForce Ethernet support" + depends on NET_PCI && PCI + 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. The module + will be called forcedeth. + +config FORCEDETH_NAPI + bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" + depends on FORCEDETH && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config CS89x0 + tristate "CS89x0 support" + depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X) + ---help--- + Support for CS89x0 chipset based Ethernet cards. If you have a + network (Ethernet) card of this type, say Y and read the + Ethernet-HOWTO, available from + as well as + . + + To compile this driver as a module, choose M here. The module + will be called cs89x0. + +config TC35815 + tristate "TOSHIBA TC35815 Ethernet support" + depends on NET_PCI && PCI && MIPS + select MII + +config EEPRO100 + tristate "EtherExpressPro/100 support (eepro100, original Becker driver)" + depends on NET_PCI && PCI + select MII + help + If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) + card, say Y and read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called eepro100. + + +config E100 + tristate "Intel(R) PRO/100+ support" + depends on NET_PCI && PCI + select MII + ---help--- + This driver supports Intel(R) PRO/100 family of adapters. + To verify that your adapter is supported, find the board ID number + on the adapter. Look for a label that has a barcode and a number + in the format 123456-001 (six digits hyphen three digits). + + Use the above information and the Adapter & Driver ID Guide at: + + + + to identify the adapter. + + For the latest Intel PRO/100 network driver for Linux, see: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module + will be called e100. + +config LNE390 + tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" + depends on NET_PCI && EISA && EXPERIMENTAL + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called lne390. + +config FEALNX + tristate "Myson MTD-8xx PCI Ethernet support" + depends on NET_PCI && PCI + select CRC32 + select MII + help + Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet + cards. Specifications and data at + . + +config NATSEMI + tristate "National Semiconductor DP8381x series PCI Ethernet support" + depends on NET_PCI && PCI + select CRC32 + help + This driver is for the National Semiconductor DP83810 series, + which is used in cards from PureData, NetGear, Linksys + and others, including the 83815 chip. + More specific information and updates are available from + . + +config NE2K_PCI + tristate "PCI NE2000 and clones support (see help)" + depends on NET_PCI && PCI + select CRC32 + ---help--- + This driver is for NE2000 compatible PCI cards. It will not work + with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 + support" below). If you have a PCI NE2000 network (Ethernet) card, + say Y and read the Ethernet-HOWTO, available from + . + + This driver also works for the following NE2000 clone cards: + RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 + NetVin NV5000SC Via 86C926 SureCom NE34 Winbond + Holtek HT80232 Holtek HT80229 + + To compile this driver as a module, choose M here. The module + will be called ne2k-pci. + +config NE3210 + tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)" + depends on NET_PCI && EISA && EXPERIMENTAL + select CRC32 + ---help--- + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . Note that this driver + will NOT WORK for NE3200 cards as they are completely different. + + To compile this driver as a module, choose M here. The module + will be called ne3210. + +config ES3210 + tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)" + depends on NET_PCI && EISA && EXPERIMENTAL + select CRC32 + help + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module + will be called es3210. + +config 8139CP + tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + select MII + help + This is a driver for the Fast Ethernet PCI network cards based on + the RTL8139C+ chips. If you have one of those, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here: the module + will be called 8139cp. This is recommended. + +config 8139TOO + tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support" + depends on NET_PCI && PCI + select CRC32 + select MII + ---help--- + This is a driver for the Fast Ethernet PCI network cards based on + the RTL 8129/8130/8139 chips. If you have one of those, say Y and + read the Ethernet-HOWTO . + + To compile this driver as a module, choose M here: the module + will be called 8139too. This is recommended. + +config 8139TOO_PIO + bool "Use PIO instead of MMIO" + default y + depends on 8139TOO + help + This instructs the driver to use programmed I/O ports (PIO) instead + of PCI shared memory (MMIO). This can possibly solve some problems + in case your mainboard has memory consistency issues. If unsure, + say N. + +config 8139TOO_TUNE_TWISTER + bool "Support for uncommon RTL-8139 rev. K (automatic channel equalization)" + depends on 8139TOO + help + This implements a function which might come in handy in case you + are using low quality on long cabling. It is required for RealTek + RTL-8139 revision K boards, and totally unused otherwise. It tries + to match the transceiver to the cable characteristics. This is + experimental since hardly documented by the manufacturer. + If unsure, say Y. + +config 8139TOO_8129 + bool "Support for older RTL-8129/8130 boards" + depends on 8139TOO + help + This enables support for the older and uncommon RTL-8129 and + RTL-8130 chips, which support MII via an external transceiver, + instead of an internal one. Disabling this option will save some + memory by making the code size smaller. If unsure, say Y. + +config 8139_OLD_RX_RESET + bool "Use older RX-reset method" + depends on 8139TOO + help + The 8139too driver was recently updated to contain a more rapid + reset sequence, in the face of severe receive errors. This "new" + RX-reset method should be adequate for all boards. But if you + experience problems, you can enable this option to restore the + old RX-reset behavior. If unsure, say N. + +config SIS900 + tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" + depends on NET_PCI && PCI + select CRC32 + select MII + ---help--- + This is a driver for the Fast Ethernet PCI network cards based on + the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in + SiS 630 and SiS 540 chipsets. + + This driver also supports AMD 79C901 HomePNA so that you can use + your phone line as a network cable. + + To compile this driver as a module, choose M here: the module + will be called sis900. This is recommended. + +config EPIC100 + tristate "SMC EtherPower II" + depends on NET_PCI && PCI + select CRC32 + select MII + help + This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, + which is based on the SMC83c17x (EPIC/100). + More specific information and updates are available from + . + +config SUNDANCE + tristate "Sundance Alta support" + depends on NET_PCI && PCI + select CRC32 + select MII + help + This driver is for the Sundance "Alta" chip. + More specific information and updates are available from + . + +config SUNDANCE_MMIO + bool "Use MMIO instead of PIO" + depends on SUNDANCE + help + Enable memory-mapped I/O for interaction with Sundance NIC registers. + Do NOT enable this by default, PIO (enabled when MMIO is disabled) + is known to solve bugs on certain chips. + + If unsure, say N. + +config TLAN + tristate "TI ThunderLAN support" + depends on NET_PCI && (PCI || EISA) && !64BIT + ---help--- + If you have a PCI Ethernet network card based on the ThunderLAN chip + which is supported by this driver, say Y and read the + Ethernet-HOWTO, available from + . + + Devices currently supported by this driver are Compaq Netelligent, + Compaq NetFlex and Olicom cards. Please read the file + for more details. + + To compile this driver as a module, choose M here. The module + will be called tlan. + + Please email feedback to . + +config VIA_RHINE + tristate "VIA Rhine support" + depends on NET_PCI && PCI + select CRC32 + select MII + help + If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A), + Rhine-II (VT6102), or Rhine-III (VT6105)), say Y here. Rhine-type + Ethernet functions can also be found integrated on South Bridges + (e.g. VT8235). + + To compile this driver as a module, choose M here. The module + will be called via-rhine. + +config VIA_RHINE_MMIO + bool "Use MMIO instead of PIO" + depends on VIA_RHINE + help + This instructs the driver to use PCI shared memory (MMIO) instead of + programmed I/O ports (PIO). Enabling this gives an improvement in + processing time in parts of the driver. + + If unsure, say Y. + +config VIA_RHINE_NAPI + bool "Use Rx Polling (NAPI)" + depends on VIA_RHINE + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + +config LAN_SAA9730 + bool "Philips SAA9730 Ethernet support" + depends on NET_PCI && PCI && MIPS_ATLAS + help + The SAA9730 is a combined multimedia and peripheral controller used + in thin clients, Internet access terminals, and diskless + workstations. + See . + +config SC92031 + tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + ---help--- + This is a driver for the Fast Ethernet PCI network cards based on + the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you + have one of these, say Y here. + + To compile this driver as a module, choose M here: the module + will be called sc92031. This is recommended. + +config CPMAC + tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" + depends on NET_ETHERNET && EXPERIMENTAL && AR7 + select PHYLIB + select FIXED_PHY + select FIXED_MII_100_FDX + help + TI AR7 CPMAC Ethernet support + +config NET_POCKET + bool "Pocket and portable adapters" + depends on PARPORT + ---help--- + Cute little network (Ethernet) devices which attach to the parallel + port ("pocket adapters"), commonly used with laptops. If you have + one of those, say Y and read the Ethernet-HOWTO, available from + . + + If you want to plug a network (or some other) card into the PCMCIA + (or PC-card) slot of your laptop instead (PCMCIA is the standard for + credit card size extension cards used by all modern laptops), you + need the pcmcia-cs package (location contained in the file + ) and you can say N here. + + Laptop users should read the Linux Laptop home page at + or + Tuxmobil - Linux on Mobile Computers at . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about this class of network devices. If you say Y, you + will be asked for your specific device in the following questions. + +config ATP + tristate "AT-LAN-TEC/RealTek pocket adapter support" + depends on NET_POCKET && PARPORT && X86 + select CRC32 + ---help--- + This is a network (Ethernet) device which attaches to your parallel + port. Read as well as the Ethernet-HOWTO, + available from , if you + want to use this. If you intend to use this driver, you should have + said N to the "Parallel printer support", because the two drivers + don't like each other. + + To compile this driver as a module, choose M here: the module + will be called atp. + +config DE600 + tristate "D-Link DE600 pocket adapter support" + depends on NET_POCKET && PARPORT + ---help--- + This is a network (Ethernet) device which attaches to your parallel + port. Read as well as the + Ethernet-HOWTO, available from + , if you want to use + this. It is possible to have several devices share a single parallel + port and it is safe to compile the corresponding drivers into the + kernel. + + To compile this driver as a module, choose M here: the module + will be called de600. + +config DE620 + tristate "D-Link DE620 pocket adapter support" + depends on NET_POCKET && PARPORT + ---help--- + This is a network (Ethernet) device which attaches to your parallel + port. Read as well as the + Ethernet-HOWTO, available from + , if you want to use + this. It is possible to have several devices share a single parallel + port and it is safe to compile the corresponding drivers into the + kernel. + + To compile this driver as a module, choose M here: the module + will be called de620. + +config SGISEEQ + tristate "SGI Seeq ethernet controller support" + depends on SGI_IP22 + help + Say Y here if you have an Seeq based Ethernet network card. This is + used in many Silicon Graphics machines. + +config DECLANCE + tristate "DEC LANCE ethernet controller support" + depends on MACH_DECSTATION + select CRC32 + help + This driver is for the series of Ethernet controllers produced by + DEC (now Compaq) based on the AMD Lance chipset, including the + DEPCA series. (This chipset is better known via the NE2100 cards.) + +config 68360_ENET + bool "Motorola 68360 ethernet controller" + depends on M68360 + help + Say Y here if you want to use the built-in ethernet controller of + the Motorola 68360 processor. + +config FEC + bool "FEC ethernet controller (of ColdFire CPUs)" + depends on M523x || M527x || M5272 || M528x || M520x + help + Say Y here if you want to use the built-in 10/100 Fast ethernet + controller on some Motorola ColdFire processors. + +config FEC2 + bool "Second FEC ethernet controller (on some ColdFire CPUs)" + depends on FEC + help + Say Y here if you want to use the second built-in 10/100 Fast + ethernet controller on some Motorola ColdFire processors. + +config FEC_MPC52xx + tristate "MPC52xx FEC driver" + depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC + select CRC32 + select PHYLIB + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller + If compiled as module, it will be called 'fec_mpc52xx.ko'. + +config FEC_MPC52xx_MDIO + bool "MPC52xx FEC MDIO bus driver" + depends on FEC_MPC52xx + default y + ---help--- + The MPC5200's FEC can connect to the Ethernet either with + an external MII PHY chip or 10 Mbps 7-wire interface + (Motorola? industry standard). + If your board uses an external PHY connected to FEC, enable this. + If not sure, enable. + If compiled as module, it will be called 'fec_mpc52xx_phy.ko'. + +config NE_H8300 + tristate "NE2000 compatible support for H8/300" + depends on H8300 + help + Say Y here if you want to use the NE2000 compatible + controller on the Renesas H8/300 processor. + +source "drivers/net/fec_8xx/Kconfig" +source "drivers/net/fs_enet/Kconfig" + +endif # NET_ETHERNET + +# +# Gigabit Ethernet +# + +menuconfig NETDEV_1000 + bool "Ethernet (1000 Mbit)" + depends on !UML + default y + ---help--- + Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common + type of Local Area Network (LAN) in universities and companies. + + Say Y here to get to see options for Gigabit Ethernet drivers. + This option alone does not add any kernel code. + Note that drivers supporting both 100 and 1000 MBit may be listed + under "Ethernet (10 or 100MBit)" instead. + + If you say N, all options in this submenu will be skipped and disabled. + +if NETDEV_1000 + +config ACENIC + tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support" + depends on PCI + ---help--- + Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear + GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet + adapter. The driver allows for using the Jumbo Frame option (9000 + bytes/frame) however it requires that your switches can handle this + as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig + line. + + To compile this driver as a module, choose M here: the + module will be called acenic. + +config ACENIC_OMIT_TIGON_I + bool "Omit support for old Tigon I based AceNICs" + depends on ACENIC + help + Say Y here if you only have Tigon II based AceNICs and want to leave + out support for the older Tigon I based cards which are no longer + being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B + version)). This will reduce the size of the driver object by + app. 100KB. If you are not sure whether your card is a Tigon I or a + Tigon II, say N here. + + The safe and default value for this is N. + +config DL2K + tristate "DL2000/TC902x-based Gigabit Ethernet support" + depends on PCI + select CRC32 + help + This driver supports DL2000/TC902x-based Gigabit ethernet cards, + which includes + D-Link DGE-550T Gigabit Ethernet Adapter. + D-Link DL2000-based Gigabit Ethernet Adapter. + Sundance/Tamarack TC902x Gigabit Ethernet Adapter. + + To compile this driver as a module, choose M here: the + module will be called dl2k. + +config E1000 + tristate "Intel(R) PRO/1000 Gigabit Ethernet support" + depends on PCI + ---help--- + This driver supports Intel(R) PRO/1000 gigabit ethernet family of + adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module + will be called e1000. + +config E1000_NAPI + bool "Use Rx Polling (NAPI)" + depends on E1000 + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config E1000_DISABLE_PACKET_SPLIT + bool "Disable Packet Split for PCI express adapters" + depends on E1000 + help + Say Y here if you want to use the legacy receive path for PCI express + hardware. + + If in doubt, say N. + +config E1000E + tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" + depends on PCI + ---help--- + This driver supports the PCI-Express Intel(R) PRO/1000 gigabit + ethernet family of adapters. For PCI or PCI-X e1000 adapters, + use the regular e1000 driver For more information on how to + identify your adapter, go to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + To compile this driver as a module, choose M here. The module + will be called e1000e. + +config IP1000 + tristate "IP1000 Gigabit Ethernet support" + depends on PCI && EXPERIMENTAL + select MII + ---help--- + This driver supports IP1000 gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called ipg. This is recommended. + +source "drivers/net/ixp2000/Kconfig" + +config MYRI_SBUS + tristate "MyriCOM Gigabit Ethernet support" + depends on SBUS + help + This driver supports MyriCOM Sbus gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called myri_sbus. This is recommended. + +config NS83820 + tristate "National Semiconductor DP83820 support" + depends on PCI + help + This is a driver for the National Semiconductor DP83820 series + of gigabit ethernet MACs. Cards using this chipset include + the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX, + SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of + zero copy. + +config HAMACHI + tristate "Packet Engines Hamachi GNIC-II support" + depends on PCI + select MII + help + If you have a Gigabit Ethernet card of this type, say Y and read + the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. The module will be + called hamachi. + +config YELLOWFIN + tristate "Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + select CRC32 + ---help--- + Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet + adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is + used by the Beowulf Linux cluster project. See + for more + information about this driver in particular and Beowulf in general. + + To compile this driver as a module, choose M here: the module + will be called yellowfin. This is recommended. + +config R8169 + tristate "Realtek 8169 gigabit ethernet support" + depends on PCI + select CRC32 + ---help--- + Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter. + + To compile this driver as a module, choose M here: the module + will be called r8169. This is recommended. + +config R8169_NAPI + bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" + depends on R8169 && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config R8169_VLAN + bool "VLAN support" + depends on R8169 && VLAN_8021Q + ---help--- + Say Y here for the r8169 driver to support the functions required + by the kernel 802.1Q code. + + If in doubt, say Y. + +config SB1250_MAC + tristate "SB1250 Gigabit Ethernet support" + depends on SIBYTE_SB1xxx_SOC + select PHYLIB + ---help--- + This driver supports Gigabit Ethernet interfaces based on the + Broadcom SiByte family of System-On-a-Chip parts. They include + the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455 + and BCM1480 chips. + + To compile this driver as a module, choose M here: the module + will be called sb1250-mac. + +config SIS190 + tristate "SiS190/SiS191 gigabit ethernet support" + depends on PCI + select CRC32 + select MII + ---help--- + Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or + a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to + appear in lan on motherboard designs which are based on SiS 965 + and SiS 966 south bridge. + + To compile this driver as a module, choose M here: the module + will be called sis190. This is recommended. + +config SKGE + tristate "New SysKonnect GigaEthernet support" + depends on PCI + select CRC32 + ---help--- + This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx + and related Gigabit Ethernet adapters. It is a new smaller driver + with better performance and more complete ethtool support. + + It does not support the link failover and network management + features that "portable" vendor supplied sk98lin driver does. + + This driver supports adapters based on the original Yukon chipset: + Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T, + Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872. + + It does not support the newer Yukon2 chipset: a separate driver, + sky2, is provided for Yukon2-based adapters. + + To compile this driver as a module, choose M here: the module + will be called skge. This is recommended. + +config SKGE_DEBUG + bool "Debugging interface" + depends on SKGE && DEBUG_FS + help + This option adds the ability to dump driver state for debugging. + The file debugfs/skge/ethX displays the state of the internal + transmit and receive rings. + + If unsure, say N. + +config SKY2 + tristate "SysKonnect Yukon2 support" + depends on PCI + select CRC32 + ---help--- + This driver supports Gigabit Ethernet adapters based on the + Marvell Yukon 2 chipset: + Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/ + 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21 + + There is companion driver for the older Marvell Yukon and + Genesis based adapters: skge. + + To compile this driver as a module, choose M here: the module + will be called sky2. This is recommended. + +config SKY2_DEBUG + bool "Debugging interface" + depends on SKY2 && DEBUG_FS + help + This option adds the ability to dump driver state for debugging. + The file debugfs/sky2/ethX displays the state of the internal + transmit and receive rings. + + If unsure, say N. + +config SK98LIN + tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)" + depends on PCI + ---help--- + Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx + compliant Gigabit Ethernet Adapter. + + This driver supports the original Yukon chipset. This driver is + deprecated and will be removed from the kernel in the near future, + it has been replaced by the skge driver. skge is cleaner and + seems to work better. + + This driver does not support the newer Yukon2 chipset. A separate + driver, sky2, is provided to support Yukon2-based adapters. + + The following adapters are supported by this driver: + - 3Com 3C940 Gigabit LOM Ethernet Adapter + - 3Com 3C941 Gigabit LOM Ethernet Adapter + - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter + - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter + - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter + - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter + - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter + - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter + - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter + - Allied Telesyn AT-2971T Gigabit Ethernet Adapter + - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45 + - 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 88E8050 Gigabit LOM Ethernet Adapter (Intel) + - Marvell RDK-8001 Adapter + - Marvell RDK-8002 Adapter + - Marvell RDK-8003 Adapter + - Marvell RDK-8004 Adapter + - Marvell RDK-8006 Adapter + - Marvell RDK-8007 Adapter + - Marvell RDK-8008 Adapter + - Marvell RDK-8009 Adapter + - Marvell RDK-8010 Adapter + - Marvell RDK-8011 Adapter + - Marvell RDK-8012 Adapter + - Marvell RDK-8052 Adapter + - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit) + - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit) + - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L) + - SK-9521 10/100/1000Base-T Adapter + - SK-9521 V2.0 10/100/1000Base-T Adapter + - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T) + - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter + - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link) + - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX) + - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter + - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link) + - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX) + - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter + - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link) + - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter + - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition) + - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter + - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link) + - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX) + - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter + - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link) + - SMC EZ Card 1000 (SMC9452TXV.2) + + The adapters support Jumbo Frames. + The dual link adapters support link-failover and dual port features. + Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support + the scatter-gather functionality with sendfile(). Please refer to + for more information about + optional driver parameters. + Questions concerning this driver may be addressed to: + + + 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 . The module will + be called sk98lin. This is recommended. + +config VIA_VELOCITY + tristate "VIA Velocity support" + depends on PCI + select CRC32 + select CRC_CCITT + select MII + help + If you have a VIA "Velocity" based network card say Y here. + + To compile this driver as a module, choose M here. The module + will be called via-velocity. + +config TIGON3 + tristate "Broadcom Tigon3 support" + depends on PCI + help + This driver supports Broadcom Tigon3 based gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called tg3. This is recommended. + +config BNX2 + tristate "Broadcom NetXtremeII support" + depends on PCI + select CRC32 + select ZLIB_INFLATE + help + This driver supports Broadcom NetXtremeII gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called bnx2. This is recommended. + +config SPIDER_NET + tristate "Spider Gigabit Ethernet driver" + depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) + select FW_LOADER + help + This driver supports the Gigabit Ethernet chips present on the + Cell Processor-Based Blades from IBM. + +config TSI108_ETH + tristate "Tundra TSI108 gigabit Ethernet support" + depends on TSI108_BRIDGE + help + This driver supports Tundra TSI108 gigabit Ethernet ports. + To compile this driver as a module, choose M here: the module + will be called tsi108_eth. + +config GELIC_NET + tristate "PS3 Gigabit Ethernet driver" + depends on PPC_PS3 + help + This driver supports the network device on the PS3 game + console. This driver has built-in support for Ethernet. + + To compile this driver as a module, choose M here: the + module will be called ps3_gelic. + +config GIANFAR + tristate "Gianfar Ethernet" + depends on 85xx || 83xx || PPC_86xx + select PHYLIB + select CRC32 + help + This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx, + and MPC86xx family of chips, and the FEC on the 8540. + +config GFAR_NAPI + bool "Use Rx Polling (NAPI)" + depends on GIANFAR + +config UCC_GETH + tristate "Freescale QE Gigabit Ethernet" + depends on QUICC_ENGINE + select PHYLIB + help + This driver supports the Gigabit Ethernet mode of the QUICC Engine, + which is available on some Freescale SOCs. + +config UGETH_NAPI + bool "Use Rx Polling (NAPI)" + depends on UCC_GETH + +config UGETH_MAGIC_PACKET + bool "Magic Packet detection support" + depends on UCC_GETH + +config UGETH_FILTERING + bool "Mac address filtering support" + depends on UCC_GETH + +config UGETH_TX_ON_DEMAND + bool "Transmit on Demand support" + depends on UCC_GETH + +config MV643XX_ETH + tristate "Marvell Discovery (643XX) and Orion ethernet support" + depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION + select MII + help + This driver supports the gigabit ethernet MACs in the + Marvell Discovery PPC/MIPS chipset family (MV643XX) and + in the Marvell Orion ARM SoC family. + + Some boards that use the Discovery chipset are the Momenco + Ocelot C and Jaguar ATX and Pegasos II. + +config QLA3XXX + tristate "QLogic QLA3XXX Network Driver Support" + depends on PCI + help + This driver supports QLogic ISP3XXX gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called qla3xxx. + +config ATL1 + tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + select CRC32 + select MII + help + This driver supports the Attansic L1 gigabit ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl1. + +endif # NETDEV_1000 + +# +# 10 Gigabit Ethernet +# + +menuconfig NETDEV_10000 + bool "Ethernet (10000 Mbit)" + depends on !UML + default y + ---help--- + Say Y here to get to see options for 10 Gigabit Ethernet drivers. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if NETDEV_10000 + +config CHELSIO_T1 + tristate "Chelsio 10Gb Ethernet support" + depends on PCI + select CRC32 + help + This driver supports Chelsio gigabit and 10-gigabit + Ethernet cards. More information about adapter features and + performance tuning is in . + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called cxgb. + +config CHELSIO_T1_1G + bool "Chelsio gigabit Ethernet support" + depends on CHELSIO_T1 + help + Enables support for Chelsio's gigabit Ethernet PCI cards. If you + are using only 10G cards say 'N' here. + +config CHELSIO_T1_NAPI + bool "Use Rx Polling (NAPI)" + depends on CHELSIO_T1 + default y + help + NAPI is a driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. + +config CHELSIO_T3 + tristate "Chelsio Communications T3 10Gb Ethernet support" + depends on PCI + select FW_LOADER + help + This driver supports Chelsio T3-based gigabit and 10Gb Ethernet + adapters. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called cxgb3. + +config EHEA + tristate "eHEA Ethernet support" + depends on IBMEBUS && INET + select INET_LRO + ---help--- + This driver supports the IBM pSeries eHEA ethernet adapter. + + To compile the driver as a module, choose M here. The module + will be called ehea. + +config IXGBE + tristate "Intel(R) 10GbE PCI Express adapters support" + depends on PCI + ---help--- + This driver supports Intel(R) 10GbE PCI Express family of + adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + To compile this driver as a module, choose M here. The module + will be called ixgbe. + +config IXGB + tristate "Intel(R) PRO/10GbE support" + depends on PCI + ---help--- + This driver supports Intel(R) PRO/10GbE family of adapters for + PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver + instead. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module + will be called ixgb. + +config IXGB_NAPI + bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" + depends on IXGB && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config S2IO + tristate "S2IO 10Gbe XFrame NIC" + depends on PCI + ---help--- + This driver supports the 10Gbe XFrame NIC of S2IO. + More specific information on configuring the driver is in + . + +config S2IO_NAPI + bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" + depends on S2IO && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + If in doubt, say N. + +config MYRI10GE + tristate "Myricom Myri-10G Ethernet support" + depends on PCI && INET + select FW_LOADER + select CRC32 + select INET_LRO + ---help--- + This driver supports Myricom Myri-10G Dual Protocol interface in + Ethernet mode. If the eeprom on your board is not recent enough, + you will need a newer firmware image. + You may get this image or more information, at: + + + + To compile this driver as a module, choose M here. The module + will be called myri10ge. + +config NETXEN_NIC + tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC" + depends on PCI + help + This enables the support for NetXen's Gigabit Ethernet card. + +config NIU + tristate "Sun Neptune 10Gbit Ethernet support" + depends on PCI + help + This enables support for cards based upon Sun's + Neptune chipset. + +config PASEMI_MAC + tristate "PA Semi 1/10Gbit MAC" + depends on PPC64 && PCI + select PHYLIB + help + This driver supports the on-chip 1/10Gbit Ethernet controller on + PA Semi's PWRficient line of chips. + +config MLX4_CORE + tristate + depends on PCI + default n + +config MLX4_DEBUG + bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED) + depends on MLX4_CORE + default y + ---help--- + This option causes debugging code to be compiled into the + mlx4_core driver. The output can be turned on via the + debug_level module parameter (which can also be set after + the driver is loaded through sysfs). + +config TEHUTI + tristate "Tehuti Networks 10G Ethernet" + depends on PCI + help + Tehuti Networks 10G Ethernet NIC + +endif # NETDEV_10000 + +source "drivers/net/tokenring/Kconfig" + +source "drivers/net/wireless/Kconfig" + +source "drivers/net/usb/Kconfig" + +source "drivers/net/pcmcia/Kconfig" + +source "drivers/net/wan/Kconfig" + +source "drivers/atm/Kconfig" + +source "drivers/s390/net/Kconfig" + +config XEN_NETDEV_FRONTEND + tristate "Xen network device frontend driver" + depends on XEN + default y + help + The network device frontend driver allows the kernel to + access network devices exported exported by a virtual + machine containing a physical network device driver. The + frontend driver is intended for unprivileged guest domains; + if you are compiling a kernel for a Xen guest, you almost + certainly want to enable this. + +config ISERIES_VETH + tristate "iSeries Virtual Ethernet driver support" + depends on PPC_ISERIES + +config RIONET + tristate "RapidIO Ethernet over messaging driver support" + depends on RAPIDIO + +config RIONET_TX_SIZE + int "Number of outbound queue entries" + depends on RIONET + default "128" + +config RIONET_RX_SIZE + int "Number of inbound queue entries" + depends on RIONET + default "128" + +config FDDI + bool "FDDI driver support" + depends on (PCI || EISA || TC) + help + Fiber Distributed Data Interface is a high speed local area network + design; essentially a replacement for high speed Ethernet. FDDI can + run over copper or fiber. If you are connected to such a network and + want a driver for the FDDI card in your computer, say Y here (and + then also Y to the driver for your FDDI card, below). Most people + will say N. + +config DEFXX + tristate "Digital DEFTA/DEFEA/DEFPA adapter support" + depends on FDDI && (PCI || EISA || TC) + ---help--- + This is support for the DIGITAL series of TURBOchannel (DEFTA), + EISA (DEFEA) and PCI (DEFPA) controllers which can connect you + to a local FDDI network. + + To compile this driver as a module, choose M here: the module + will be called defxx. If unsure, say N. + +config DEFXX_MMIO + bool + prompt "Use MMIO instead of PIO" if PCI || EISA + depends on DEFXX + default n if PCI || EISA + default y + ---help--- + This instructs the driver to use EISA or PCI memory-mapped I/O + (MMIO) as appropriate instead of programmed I/O ports (PIO). + Enabling this gives an improvement in processing time in parts + of the driver, but it may cause problems with EISA (DEFEA) + adapters. TURBOchannel does not have the concept of I/O ports, + so MMIO is always used for these (DEFTA) adapters. + + If unsure, say N. + +config SKFP + tristate "SysKonnect FDDI PCI support" + depends on FDDI && PCI + select BITREVERSE + ---help--- + Say Y here if you have a SysKonnect FDDI PCI adapter. + The following adapters are supported by this driver: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC + + Read for information about + the driver. + + Questions concerning this driver can be addressed to: + + + To compile this driver as a module, choose M here: the module + will be called skfp. This is recommended. + +config HIPPI + bool "HIPPI driver support (EXPERIMENTAL)" + depends on EXPERIMENTAL && INET && PCI + help + HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and + 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI + can run over copper (25m) or fiber (300m on multi-mode or 10km on + single-mode). HIPPI networks are commonly used for clusters and to + connect to super computers. If you are connected to a HIPPI network + and have a HIPPI network card in your computer that you want to use + under Linux, say Y here (you must also remember to enable the driver + for your HIPPI card below). Most people will say N here. + +config ROADRUNNER + tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)" + depends on HIPPI && PCI + help + Say Y here if this is your PCI HIPPI network card. + + To compile this driver as a module, choose M here: the module + will be called rrunner. If unsure, say N. + +config ROADRUNNER_LARGE_RINGS + bool "Use large TX/RX rings (EXPERIMENTAL)" + depends on ROADRUNNER + help + If you say Y here, the RoadRunner driver will preallocate up to 2 MB + of additional memory to allow for fastest operation, both for + transmitting and receiving. This memory cannot be used by any other + kernel code or by user space programs. Say Y here only if you have + the memory. + +config PLIP + tristate "PLIP (parallel port) support" + depends on PARPORT + ---help--- + PLIP (Parallel Line Internet Protocol) is used to create a + reasonably fast mini network consisting of two (or, rarely, more) + local machines. A PLIP link from a Linux box is a popular means to + install a Linux distribution on a machine which doesn't have a + CD-ROM drive (a minimal system has to be transferred with floppies + first). The kernels on both machines need to have this PLIP option + enabled for this to work. + + The PLIP driver has two modes, mode 0 and mode 1. The parallel + ports (the connectors at the computers with 25 holes) are connected + with "null printer" or "Turbo Laplink" cables which can transmit 4 + bits at a time (mode 0) or with special PLIP cables, to be used on + bidirectional parallel ports only, which can transmit 8 bits at a + time (mode 1); you can find the wiring of these cables in + . The cables can be up to + 15m long. Mode 0 works also if one of the machines runs DOS/Windows + and has some PLIP software installed, e.g. the Crynwr PLIP packet + driver () + and winsock or NCSA's telnet. + + If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well + as the NET-3-HOWTO, both available from + . Note that the PLIP + protocol has been changed and this PLIP driver won't work together + with the PLIP support in Linux versions 1.0.x. This option enlarges + your kernel by about 8 KB. + + To compile this driver as a module, choose M here. The module + will be called plip. If unsure, say Y or M, in case you buy + a laptop later. + +config PPP + tristate "PPP (point-to-point protocol) support" + select SLHC + ---help--- + PPP (Point to Point Protocol) is a newer and better SLIP. It serves + the same purpose: sending Internet traffic over telephone (and other + serial) lines. Ask your access provider if they support it, because + otherwise you can't use it; most Internet access providers these + days support PPP rather than SLIP. + + To use PPP, you need an additional program called pppd as described + in the PPP-HOWTO, available at + . Make sure that you have + the version of pppd recommended in . + The PPP option enlarges your kernel by about 16 KB. + + There are actually two versions of PPP: the traditional PPP for + asynchronous lines, such as regular analog phone lines, and + synchronous PPP which can be used over digital ISDN lines for + example. If you want to use PPP over phone lines or other + asynchronous serial lines, you need to say Y (or M) here and also to + the next option, "PPP support for async serial ports". For PPP over + synchronous lines, you should say Y (or M) here and to "Support + synchronous PPP", below. + + If you said Y to "Version information on all symbols" above, then + you cannot compile the PPP driver into the kernel; you can then only + compile it as a module. To compile this driver as a module, choose M + here. The module will be called ppp_generic. + +config PPP_MULTILINK + bool "PPP multilink support (EXPERIMENTAL)" + depends on PPP && EXPERIMENTAL + help + PPP multilink is a protocol (defined in RFC 1990) which allows you + to combine several (logical or physical) lines into one logical PPP + connection, so that you can utilize your full bandwidth. + + This has to be supported at the other end as well and you need a + version of the pppd daemon which understands the multilink protocol. + + If unsure, say N. + +config PPP_FILTER + bool "PPP filtering" + depends on PPP + help + Say Y here if you want to be able to filter the packets passing over + PPP interfaces. This allows you to control which packets count as + activity (i.e. which packets will reset the idle timer or bring up + a demand-dialed link) and which packets are to be dropped entirely. + You need to say Y here if you wish to use the pass-filter and + active-filter options to pppd. + + If unsure, say N. + +config PPP_ASYNC + tristate "PPP support for async serial ports" + depends on PPP + select CRC_CCITT + ---help--- + Say Y (or M) here if you want to be able to use PPP over standard + asynchronous serial ports, such as COM1 or COM2 on a PC. If you use + a modem (not a synchronous or ISDN modem) to contact your ISP, you + need this option. + + To compile this driver as a module, choose M here. + + If unsure, say Y. + +config PPP_SYNC_TTY + tristate "PPP support for sync tty ports" + depends on PPP + help + Say Y (or M) here if you want to be able to use PPP over synchronous + (HDLC) tty devices, such as the SyncLink adapter. These devices + are often used for high-speed leased lines like T1/E1. + + To compile this driver as a module, choose M here. + +config PPP_DEFLATE + tristate "PPP Deflate compression" + depends on PPP + select ZLIB_INFLATE + select ZLIB_DEFLATE + ---help--- + Support for the Deflate compression method for PPP, which uses the + Deflate algorithm (the same algorithm that gzip uses) to compress + each PPP packet before it is sent over the wire. The machine at the + other end of the PPP link (usually your ISP) has to support the + Deflate compression method as well for this to be useful. Even if + they don't support it, it is safe to say Y here. + + To compile this driver as a module, choose M here. + +config PPP_BSDCOMP + tristate "PPP BSD-Compress compression" + depends on PPP + ---help--- + Support for the BSD-Compress compression method for PPP, which uses + the LZW compression method to compress each PPP packet before it is + sent over the wire. The machine at the other end of the PPP link + (usually your ISP) has to support the BSD-Compress compression + method as well for this to be useful. Even if they don't support it, + it is safe to say Y here. + + The PPP Deflate compression method ("PPP Deflate compression", + above) is preferable to BSD-Compress, because it compresses better + and is patent-free. + + Note that the BSD compression code will always be compiled as a + module; it is called bsd_comp and will show up in the directory + modules once you have said "make modules". If unsure, say N. + +config PPP_MPPE + tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" + depends on PPP && EXPERIMENTAL + select CRYPTO + select CRYPTO_SHA1 + select CRYPTO_ARC4 + select CRYPTO_ECB + ---help--- + Support for the MPPE Encryption protocol, as employed by the + Microsoft Point-to-Point Tunneling Protocol. + + See http://pptpclient.sourceforge.net/ for information on + configuring PPTP clients and servers to utilize this method. + +config PPPOE + tristate "PPP over Ethernet (EXPERIMENTAL)" + depends on EXPERIMENTAL && PPP + help + Support for PPP over Ethernet. + + This driver requires the latest version of pppd from the CVS + repository at cvs.samba.org. Alternatively, see the + RoaringPenguin package () + which contains instruction on how to use this driver (under + the heading "Kernel mode PPPoE"). + +config PPPOATM + tristate "PPP over ATM" + depends on ATM && PPP + help + Support PPP (Point to Point Protocol) encapsulated in ATM frames. + This implementation does not yet comply with section 8 of RFC2364, + which can lead to bad results if the ATM peer loses state and + changes its encapsulation unilaterally. + +config PPPOL2TP + tristate "PPP over L2TP (EXPERIMENTAL)" + depends on EXPERIMENTAL && PPP && INET + help + Support for PPP-over-L2TP socket family. L2TP is a protocol + used by ISPs and enterprises to tunnel PPP traffic over UDP + tunnels. L2TP is replacing PPTP for VPN uses. + + This kernel component handles only L2TP data packets: a + userland daemon handles L2TP the control protocol (tunnel + and session setup). One such daemon is OpenL2TP + (http://openl2tp.sourceforge.net/). + +config SLIP + tristate "SLIP (serial line) support" + ---help--- + Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to + connect to your Internet service provider or to connect to some + other local Unix box or if you want to configure your Linux box as a + Slip/CSlip server for other people to dial in. SLIP (Serial Line + Internet Protocol) is a protocol used to send Internet traffic over + serial connections such as telephone lines or null modem cables; + nowadays, the protocol PPP is more commonly used for this same + purpose. + + Normally, your access provider has to support SLIP in order for you + to be able to use it, but there is now a SLIP emulator called SLiRP + around (available from + ) which + allows you to use SLIP over a regular dial up shell connection. If + you plan to use SLiRP, make sure to say Y to CSLIP, below. The + NET-3-HOWTO, available from + , explains how to + configure SLIP. Note that you don't need this option if you just + want to run term (term is a program which gives you almost full + Internet connectivity if you have a regular dial up shell account on + some Internet connected Unix computer. Read + ). SLIP + support will enlarge your kernel by about 4 KB. If unsure, say N. + + To compile this driver as a module, choose M here. The module + will be called slip. + +config SLIP_COMPRESSED + bool "CSLIP compressed headers" + depends on SLIP + select SLHC + ---help--- + This protocol is faster than SLIP because it uses compression on the + TCP/IP headers (not on the data itself), but it has to be supported + on both ends. Ask your access provider if you are not sure and + answer Y, just in case. You will still be able to use plain SLIP. If + you plan to use SLiRP, the SLIP emulator (available from + ) which + allows you to use SLIP over a regular dial up shell connection, you + definitely want to say Y here. The NET-3-HOWTO, available from + , explains how to configure + CSLIP. This won't enlarge your kernel. + +config SLHC + tristate + help + This option enables Van Jacobsen serial line header compression + routines. + +config SLIP_SMART + bool "Keepalive and linefill" + depends on SLIP + help + Adds additional capabilities to the SLIP driver to support the + RELCOM line fill and keepalive monitoring. Ideal on poor quality + analogue lines. + +config SLIP_MODE_SLIP6 + bool "Six bit SLIP encapsulation" + depends on SLIP + help + Just occasionally you may need to run IP over hostile serial + networks that don't pass all control characters or are only seven + bit. Saying Y here adds an extra mode you can use with SLIP: + "slip6". In this mode, SLIP will only send normal ASCII symbols over + the serial device. Naturally, this has to be supported at the other + end of the link as well. It's good enough, for example, to run IP + over the async ports of a Camtec JNT Pad. If unsure, say N. + +config NET_FC + bool "Fibre Channel driver support" + depends on SCSI && PCI + help + Fibre Channel is a high speed serial protocol mainly used to connect + large storage devices to the computer; it is compatible with and + intended to replace SCSI. + + If you intend to use Fibre Channel, you need to have a Fibre channel + adaptor card in your computer; say Y here and to the driver for your + adaptor below. You also should have said Y to "SCSI support" and + "SCSI generic support". + +config SHAPER + tristate "Traffic Shaper (OBSOLETE)" + depends on EXPERIMENTAL + ---help--- + The traffic shaper is a virtual network device that allows you to + limit the rate of outgoing data flow over some other network device. + The traffic that you want to slow down can then be routed through + these virtual devices. See + for more information. + + An alternative to this traffic shaper are traffic schedulers which + you'll get if you say Y to "QoS and/or fair queuing" in + "Networking options". + + 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 EXPERIMENTAL + ---help--- + If you want to log kernel messages over the network, enable this. + See for details. + +config NETCONSOLE_DYNAMIC + bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)" + depends on NETCONSOLE