boards supported by this driver, and for further information
on the use of this driver.
+SCSI tape drive support for Smart Array 5xxx
+CONFIG_CISS_SCSI_TAPE
+ When enabled (Y), this option allows SCSI tape drives and SCSI medium
+ changers (tape robots) to be accessed via a Compaq 5xxx array
+ controller. (See Documentation/cciss.txt for more details.)
+
+ "SCSI support" and "SCSI tape support" must also be enabled for this
+ option to work.
+
+ When this option is disabled (N), the SCSI portion of the driver
+ is not compiled.
+
QuickNet Internet LineJack/PhoneJack support
CONFIG_PHONE_IXJ
Say M if you have a telephony card manufactured by Quicknet
would like kernel messages to be formatted into GDB $O packets so
that GDB prints them as program output, say 'Y'.
+CRC32 functions
+CONFIG_CRC32
+ This option is provided for the case where no in-kernel-tree
+ modules require CRC32 functions, but a module built outside the
+ kernel tree does. Such modules that use library CRC32 functions
+ require M here.
+
#
# A couple of things I keep forgetting:
# capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
--- /dev/null
+
+struct request documentation
+
+Jens Axboe <axboe@suse.de> 070102
+
+1.0
+Index
+
+2.0 Struct request members classification
+
+ 2.1 struct request members explanation
+
+3.0
+
+
+2.0
+Short explanation of request members
+
+Classification flags:
+
+ D driver member
+ B block layer member
+ I I/O scheduler member
+
+Unless an entry contains a D classification, a device driver must not access
+this member. Some members may contain D classifications, but should only be
+access through certain macros or functions (eg ->flags).
+
+<linux/blkdev.h>
+
+2.1
+Member Flag Comment
+------ ---- -------
+
+struct list_head queuelist BI Organization on various internal
+ queues
+
+void *elevator_private I I/O scheduler private data
+
+unsigned char cmd[16] D Driver can use this for setting up
+ a cdb before execution, see
+ blk_queue_prep_rq
+
+unsigned long flags DBI Contains info about data direction,
+ request type, etc.
+
+int rq_status D Request status bits
+
+kdev_t rq_dev DBI Target device
+
+int errors DB Error counts
+
+sector_t sector DBI Target location
+
+unsigned long hard_nr_sectors B Used to keep sector sane
+
+unsigned long nr_sectors DBI Total number of sectors in request
+
+unsigned long hard_nr_sectors B Used to keep nr_sectors sane
+
+unsigned short nr_phys_segments DB Number of physical scatter gather
+ segments in a request
+
+unsigned short nr_hw_segments DB Number of hardware scatter gather
+ segments in a request
+
+unsigned int current_nr_sectors DB Number of sectors in first segment
+ of request
+
+unsigned int hard_cur_sectors B Used to keep current_nr_sectors sane
+
+void *special D Free to be used by driver
+
+char *buffer D Map of first segment, also see
+ section on bouncing SECTION
+
+struct completion *waiting D Can be used by driver to get signalled
+ on request completion
+
+struct bio *bio DBI First bio in request
+
+struct bio *biotail DBI Last bio in request
+
+request_queue_t *q DB Request queue this request belongs to
+
+struct request_list *rl B Request list this request came from
can be informed of changes to the virtual SCSI bus which the driver
presents to it in the usual way. For example:
- echo add-single-device 3 2 1 0 > /proc/scsi/scsi
+ echo scsi add-single-device 3 2 1 0 > /proc/scsi/scsi
to add a device on controller 3, bus 2, target 1, lun 0. Note that
the driver makes an effort to preserve the devices positions
- Defined macros for error and debug messages
- Updated README from master HTML file
+===============================================================================
+Changes for patch v206
+
+- Added support for multiple Compaq cpqarray controllers
+
+- Fixed (rare, old) race in <devfs_lookup>
ICMP ECHO requests sent to it or just those to broadcast/multicast
addresses, respectively.
-icmp_destunreach_rate - INTEGER
-icmp_paramprob_rate - INTEGER
-icmp_timeexceed_rate - INTEGER
-icmp_echoreply_rate - INTEGER (not enabled per default)
- Limit the maximal rates for sending ICMP packets to specific targets.
+icmp_ratelimit - INTEGER
+ Limit the maximal rates for sending ICMP packets whose type matches
+ icmp_ratemask (see below) to specific targets.
0 to disable any limiting, otherwise the maximal rate in jiffies(1)
- See the source for more information.
+ Default: 1
+
+icmp_ratemask - INTEGER
+ Mask made of ICMP types for which rates are being limited.
+ Default: 6168
+ Note: 6168 = 0x1818 = 1<<ICMP_DEST_UNREACH + 1<<ICMP_SOURCE_QUENCH +
+ 1<<ICMP_TIME_EXCEEDED + 1<<ICMP_PARAMETERPROB, which means
+ dest unreachable (3), source quench (4), time exceeded (11)
+ and parameter problem (12) ICMP packets are rate limited
+ (check values in icmp.h)
icmp_ignore_bogus_error_responses - BOOLEAN
Some routers violate RFC 1122 by sending bogus responses to broadcast
Pekka Savola
pekkas@netcore.fi
-$Id: ip-sysctl.txt,v 1.19 2001/05/16 17:11:04 davem Exp $
+$Id: ip-sysctl.txt,v 1.20 2001/12/13 09:00:18 davem Exp $
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 2
-EXTRAVERSION =-pre11
+EXTRAVERSION =
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
NETWORKS =net/network.o
LIBS =$(TOPDIR)/lib/lib.a
-SUBDIRS =kernel drivers mm fs net ipc lib
+SUBDIRS =kernel lib drivers mm fs net ipc
DRIVERS-n :=
DRIVERS-y :=
$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \
--start-group \
$(CORE_FILES) \
+ $(LIBS) \
$(DRIVERS) \
$(NETWORKS) \
- $(LIBS) \
--end-group \
-o vmlinux
$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
fi
endmenu
+
+source lib/Config.in
dep_bool ' Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
dep_bool ' Kernel low-level debugging messages via SA1100 Ser3 (otherwise Ser1)' CONFIG_DEBUG_LL_SER3 $CONFIG_DEBUG_LL $CONFIG_ARCH_SA1100
endmenu
+
+source lib/Config.in
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
endmenu
+
+source lib/Config.in
fi
endmenu
+
+source lib/Config.in
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
printk(KERN_WARNING "Use a PAE enabled kernel.\n");
else
printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+ max_pfn = MAXMEM_PFN;
#else /* !CONFIG_HIGHMEM */
#ifndef CONFIG_X86_PAE
if (max_pfn > MAX_NONPAE_PFN) {
source drivers/usb/Config.in
+source lib/Config.in
+
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
source net/bluetooth/Config.in
fi
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+
+source lib/Config.in
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
endmenu
+
+source lib/Config.in
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
endmenu
+
+source lib/Config.in
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+source lib/Config.in
bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
endmenu
+
+source lib/Config.in
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+source lib/Config.in
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+source lib/Config.in
bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
fi
endmenu
+
+source lib/Config.in
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
+
+source lib/Config.in
#!/bin/sh
case $1 in
-printf)
- sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
+ sed -n -e '/^#/d;/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0 0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0 0x%08x\\n", check_asm_data[i++]);/' >> $4
echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4
;;
-data)
- sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
+ sed -n -e '/^#/d;/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/ ((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)), sizeof(((struct '$2'_struct *)0)->\0),/' >> $4
echo " sizeof(struct $2_struct)," >> $4
;;
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/threads.h>
-#include <linux/config.h>
+#include <linux/string.h>
#include <linux/init.h>
#include <asm/page.h>
-/* $Id: ebus.c,v 1.18 2001/11/08 04:41:33 davem Exp $
+/* $Id: ebus.c,v 1.20 2002/01/05 01:13:43 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* If this is not aligned on a 8k boundry, then you should change code
* in etrap.S which assumes it.
*/
-union task_union init_task_union
- __attribute__((__section__(".text"))) =
+__asm__(".section \".text\",#alloc\n");
+union task_union init_task_union =
{ INIT_TASK(init_task_union.task) };
-/* $Id: irq.c,v 1.113 2001/07/17 16:17:33 anton Exp $
+/* $Id: irq.c,v 1.114 2001/12/11 04:55:51 davem Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
-/* $Id: process.c,v 1.157 2001/11/13 00:57:05 davem Exp $
+/* $Id: process.c,v 1.160 2002/01/11 08:45:38 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
goto out;
/* endless idle loop with no priority at all */
- current->nice = 20;
- init_idle();
-
for (;;) {
if (ARCH_SUN4C_SUN4) {
static int count = HZ;
int cpu_idle(void)
{
/* endless idle loop with no priority at all */
- current->nice = 20;
- init_idle();
-
while(1) {
if(current->need_resched) {
schedule();
show_regwindow((struct reg_window *)regs->u_regs[14]);
}
-#if NOTUSED
-void show_thread(struct thread_struct *thread)
+void show_trace_task(struct task_struct *tsk)
{
- int i;
-
- printk("uwinmask: 0x%08lx kregs: 0x%08lx\n", thread->uwinmask, (unsigned long)thread->kregs);
- show_regs(thread->kregs);
- printk("ksp: 0x%08lx kpc: 0x%08lx\n", thread->ksp, thread->kpc);
- printk("kpsr: 0x%08lx kwim: 0x%08lx\n", thread->kpsr, thread->kwim);
- printk("fork_kpsr: 0x%08lx fork_kwim: 0x%08lx\n", thread->fork_kpsr, thread->fork_kwim);
-
- for (i = 0; i < NSWINS; i++) {
- if (!thread->rwbuf_stkptrs[i])
- continue;
- printk("reg_window[%d]:\n", i);
- printk("stack ptr: 0x%08lx\n", thread->rwbuf_stkptrs[i]);
- show_regwindow(&thread->reg_window[i]);
- }
- printk("w_saved: 0x%08lx\n", thread->w_saved);
-
- /* XXX missing: float_regs */
- printk("fsr: 0x%08lx fpqdepth: 0x%08lx\n", thread->fsr, thread->fpqdepth);
- /* XXX missing: fpqueue */
+ unsigned long pc, fp;
+ unsigned long task_base = (unsigned long) tsk;
+ struct reg_window *rw;
+ int count = 0;
- printk("flags: 0x%08lx current_ds: 0x%08lx\n", thread->flags, thread->current_ds.seg);
-
- show_regwindow((struct reg_window *)thread->ksp);
+ if (!tsk)
+ return;
- /* XXX missing: core_exec */
+ fp = tsk->thread.ksp;
+ do {
+ /* Bogus frame pointer? */
+ if (fp < (task_base + sizeof(struct task_struct)) ||
+ fp >= (task_base + (PAGE_SIZE << 1)))
+ break;
+ rw = (struct reg_window *) fp;
+ pc = rw->ins[7];
+ printk("[%08lx] ", pc);
+ fp = rw->ins[6];
+ } while (++count < 16);
+ printk("\n");
}
-#endif
/*
* Free current thread data structures etc..
-/* $Id: signal.c,v 1.108 2001/01/24 21:05:12 davem Exp $
+/* $Id: signal.c,v 1.109 2001/12/21 01:22:31 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/tty.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-/* $Id: sun4d_irq.c,v 1.28 2001/07/17 16:17:33 anton Exp $
+/* $Id: sun4d_irq.c,v 1.29 2001/12/11 04:55:51 davem Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
while((unsigned long)current_set[cpuid] < PAGE_OFFSET)
barrier();
- while(current_set[cpuid]->processor != cpuid)
+ while(current_set[cpuid]->cpu != cpuid)
barrier();
/* Fix idle thread fields. */
mid_xlate[i] = i;
__cpu_number_map[boot_cpu_id] = 0;
__cpu_logical_map[0] = boot_cpu_id;
- current->processor = boot_cpu_id;
+ current->cpu = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
smp_setup_percpu_timer();
- init_idle();
local_flush_cache_all();
if(linux_num_cpus == 1)
return; /* Not an MP box. */
cpucount++;
p = init_task.prev_task;
- init_tasks[i] = p;
- p->processor = i;
- p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+ p->cpu = i;
current_set[i] = p;
- del_from_runqueue(p);
unhash_process(p);
for (no = 0; no < linux_num_cpus; no++)
mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
__cpu_number_map[boot_cpu_id] = 0;
__cpu_logical_map[0] = boot_cpu_id;
- current->processor = boot_cpu_id;
+ current->cpu = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
set_irq_udt(mid_xlate[boot_cpu_id]);
smp_setup_percpu_timer();
- init_idle();
local_flush_cache_all();
if(linux_num_cpus == 1)
return; /* Not an MP box. */
cpucount++;
p = init_task.prev_task;
- init_tasks[i] = p;
- p->processor = i;
- p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+ p->cpu = i;
current_set[i] = p;
- del_from_runqueue(p);
unhash_process(p);
/* See trampoline.S for details... */
-/* $Id: sys_sunos.c,v 1.135 2001/08/13 14:40:10 davem Exp $
+/* $Id: sys_sunos.c,v 1.136 2002/01/08 16:00:14 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* SunOS is so stupid some times... hmph!
*/
if (file) {
- if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
- MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
+ if(major(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
+ minor(file->f_dentry->d_inode->i_rdev) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
file = 0;
-/* $Id: trampoline.S,v 1.13 1999/08/04 03:19:15 davem Exp $
+/* $Id: trampoline.S,v 1.14 2002/01/11 08:45:38 davem Exp $
* trampoline.S: SMP cpu boot-up trampoline code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
.align 4
smp_do_cpu_idle:
+ call C_LABEL(init_idle)
+ nop
call C_LABEL(cpu_idle)
mov 0, %o0
-/* $Id: unaligned.c,v 1.22 2000/04/29 08:05:21 anton Exp $
+/* $Id: unaligned.c,v 1.23 2001/12/21 00:54:31 davem Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
"or %%l1, %%g7, %%g7\n\t" \
"st %%g7, [%0 + 4]\n" \
"0:\n\n\t" \
- ".section __ex_table\n\t" \
+ ".section __ex_table,#alloc\n\t" \
".word 4b, " #errh "\n\t" \
".word 5b, " #errh "\n\t" \
".word 6b, " #errh "\n\t" \
"16:\t" "stb %%l2, [%0]\n" \
"17:\t" "stb %%l1, [%0 + 1]\n" \
"0:\n\n\t" \
- ".section __ex_table\n\t" \
+ ".section __ex_table,#alloc\n\t" \
".word 4b, " #errh "\n\t" \
".word 5b, " #errh "\n\t" \
".word 6b, " #errh "\n\t" \
static unsigned long
search_one_table(const struct exception_table_entry *start,
- const struct exception_table_entry *last,
+ const struct exception_table_entry *end,
unsigned long value, unsigned long *g2)
{
- const struct exception_table_entry *first = start;
- const struct exception_table_entry *mid;
- long diff = 0;
- while (first <= last) {
- mid = (last - first) / 2 + first;
- diff = mid->insn - value;
- if (diff == 0) {
- if (!mid->fixup) {
- *g2 = 0;
- return (mid + 1)->fixup;
- } else
- return mid->fixup;
- } else if (diff < 0)
- first = mid+1;
- else
- last = mid-1;
- }
- if (last->insn < value && !last->fixup && last[1].insn > value) {
- *g2 = (value - last->insn)/4;
- return last[1].fixup;
- }
- if (first > start && first[-1].insn < value
- && !first[-1].fixup && first->insn < value) {
- *g2 = (value - first[-1].insn)/4;
- return first->fixup;
- }
+ const struct exception_table_entry *walk;
+
+ /* Single insn entries are encoded as:
+ * word 1: insn address
+ * word 2: fixup code address
+ *
+ * Range entries are encoded as:
+ * word 1: first insn address
+ * word 2: 0
+ * word 3: last insn address + 4 bytes
+ * word 4: fixup code address
+ *
+ * See asm/uaccess.h for more details.
+ */
+
+ /* 1. Try to find an exact match. */
+ for (walk = start; walk <= end; walk++) {
+ if (walk->fixup == 0) {
+ /* A range entry, skip both parts. */
+ walk++;
+ continue;
+ }
+
+ if (walk->insn == value)
+ return walk->fixup;
+ }
+
+ /* 2. Try to find a range match. */
+ for (walk = start; walk <= (end - 1); walk++) {
+ if (walk->fixup)
+ continue;
+
+ if (walk[0].insn <= value &&
+ walk[1].insn > value) {
+ *g2 = (value - walk[0].insn) / 4;
+ return walk[1].fixup;
+ }
+ walk++;
+ }
+
return 0;
}
-/* $Id: fault.c,v 1.121 2001/10/30 04:54:22 davem Exp $
+/* $Id: fault.c,v 1.122 2001/11/17 07:19:26 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
unsigned long address)
{
+ struct pt_regs regs;
unsigned long g2;
+ unsigned int insn;
int i;
- unsigned insn;
- struct pt_regs regs;
- i = search_exception_table (ret_pc, &g2);
+ i = search_exception_table(ret_pc, &g2);
switch (i) {
- /* load & store will be handled by fixup */
- case 3: return 3;
- /* store will be handled by fixup, load will bump out */
- /* for _to_ macros */
- case 1: insn = (unsigned)pc; if ((insn >> 21) & 1) return 1; break;
- /* load will be handled by fixup, store will bump out */
- /* for _from_ macros */
- case 2: insn = (unsigned)pc;
- if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2;
+ case 3:
+ /* load & store will be handled by fixup */
+ return 3;
+
+ case 1:
+ /* store will be handled by fixup, load will bump out */
+ /* for _to_ macros */
+ insn = *((unsigned int *) pc);
+ if ((insn >> 21) & 1)
+ return 1;
+ break;
+
+ case 2:
+ /* load will be handled by fixup, store will bump out */
+ /* for _from_ macros */
+ insn = *((unsigned int *) pc);
+ if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
+ return 2;
break;
- default: break;
- }
- memset (®s, 0, sizeof (regs));
+
+ default:
+ break;
+ };
+
+ memset(®s, 0, sizeof (regs));
regs.pc = pc;
regs.npc = pc + 4;
- __asm__ __volatile__ (
+ __asm__ __volatile__(
"rd %%psr, %0\n\t"
"nop\n\t"
"nop\n\t"
"nop\n" : "=r" (regs.psr));
- unhandled_fault (address, current, ®s);
+ unhandled_fault(address, current, ®s);
+
/* Not reached */
return 0;
}
-/* $Id: init.c,v 1.100 2001/09/21 22:51:47 davem Exp $
+/* $Id: init.c,v 1.103 2001/11/19 19:03:08 davem Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
int datapages = 0;
int initpages = 0;
int i;
-#ifdef CONFIG_BLK_DEV_INITRD
- unsigned long addr, last;
-#endif
highmem_start_page = mem_map + highstart_pfn;
-/* $Id: io-unit.c,v 1.23 2001/02/13 01:16:43 davem Exp $
+/* $Id: io-unit.c,v 1.24 2001/12/17 07:05:09 davem Exp $
* io-unit.c: IO-UNIT specific routines for memory management.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
spin_lock_irqsave(&iounit->lock, flags);
for (; sz >= 0; sz--) {
- sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)sg[sz].address, sg[sz].length);
+ sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)page_address(sg[sz].page) + sg[sz].offset, sg[sz].length);
sg[sz].dvma_length = sg[sz].length;
}
spin_unlock_irqrestore(&iounit->lock, flags);
-/* $Id: iommu.c,v 1.21 2001/02/13 01:16:43 davem Exp $
+/* $Id: iommu.c,v 1.22 2001/12/17 07:05:09 davem Exp $
* iommu.c: IOMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
for (; sz >= 0; sz--) {
- sg[sz].dvma_address = (__u32) (sg[sz].address);
+ sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset);
sg[sz].dvma_length = (__u32) (sg[sz].length);
}
}
{
flush_page_for_dma(0);
for (; sz >= 0; sz--) {
- sg[sz].dvma_address = (__u32) (sg[sz].address);
+ sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset);
sg[sz].dvma_length = (__u32) (sg[sz].length);
}
}
unsigned long page, oldpage = 0;
while(sz >= 0) {
- page = ((unsigned long) sg[sz].address) & PAGE_MASK;
+ page = ((unsigned long) sg[sz].offset) & PAGE_MASK;
if (oldpage == page)
page += PAGE_SIZE; /* We flushed that page already */
- while(page < (unsigned long)(sg[sz].address + sg[sz].length)) {
+ while(page < (unsigned long)(page_address(sg[sz].page) + sg[sz].offset + sg[sz].length)) {
flush_page_for_dma(page);
page += PAGE_SIZE;
}
- sg[sz].dvma_address = (__u32) (sg[sz].address);
+ sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset);
sg[sz].dvma_length = (__u32) (sg[sz].length);
sz--;
oldpage = page - PAGE_SIZE;
-/* $Id: ranges.c,v 1.14 1999/10/06 19:28:54 zaitcev Exp $
+/* $Id: ranges.c,v 1.15 2001/12/19 00:29:51 davem Exp $
* ranges.c: Handle ranges in newer proms for obio/sbus.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
int num_obio_ranges;
/* Adjust register values based upon the ranges parameters. */
-void
+static void
prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
struct linux_prom_ranges *rangep, int nranges)
{
int regc, rngc;
- for(regc=0; regc < nregs; regc++) {
- for(rngc=0; rngc < nranges; rngc++)
- if(regp[regc].which_io == rangep[rngc].ot_child_space &&
- regp[regc].phys_addr >= rangep[rngc].ot_child_base &&
- regp[regc].phys_addr + regp[regc].reg_size <= rangep[rngc].ot_child_base + rangep[rngc].or_size)
+ for (regc = 0; regc < nregs; regc++) {
+ for (rngc = 0; rngc < nranges; rngc++)
+ if (regp[regc].which_io == rangep[rngc].ot_child_space)
break; /* Fount it */
- if(rngc==nranges) /* oops */
+ if (rngc == nranges) /* oops */
prom_printf("adjust_regs: Could not find range with matching bus type...\n");
regp[regc].which_io = rangep[rngc].ot_parent_space;
+ regp[regc].phys_addr -= rangep[rngc].ot_child_base;
regp[regc].phys_addr += rangep[rngc].ot_parent_base;
}
}
-void
+static void
prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1,
struct linux_prom_ranges *ranges2, int nranges2)
{
-# $Id: Makefile,v 1.49 2001/10/17 18:26:58 davem Exp $
+# $Id: Makefile,v 1.51 2001/11/17 00:15:27 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
AS := $(AS) --undeclared-regs
endif
-#
-# Uncomment the first CFLAGS if you are doing kgdb source level
-# debugging of the kernel to get the proper debugging information.
-
-#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
ifneq ($(NEW_GCC),y)
CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
-ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
endif
-# Uncomment this to get spinlock/rwlock debugging on SMP.
-# DEBUG_SPINLOCK = 1
-
-ifdef CONFIG_SMP
- ifdef DEBUG_SPINLOCK
- CFLAGS += -DSPIN_LOCK_DEBUG
- AFLAGS += -DSPIN_LOCK_DEBUG
- endif
-endif
-
-# Uncomment this to keep track of how often flush_dcache_page
-# actually flushes the caches, output via /proc/cpuinfo
-#
-# DEBUG_DCACHE_FLUSH = 1
-ifdef DEBUG_DCACHE_FLUSH
- CFLAGS += -DDCFLUSH_DEBUG
- AFLAGS += -DDCFLUSH_DEBUG
-endif
-
LINKFLAGS = -T arch/sparc64/vmlinux.lds
HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
-# $Id: config.in,v 1.152 2001/11/12 10:20:47 davem Exp $
+# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
# Identify this as a Sparc64 build
define_bool CONFIG_SPARC64 y
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
# Global things across all Sun machines.
define_bool CONFIG_HAVE_DEC_LOCK y
define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
mainmenu_option next_comment
comment 'Console drivers'
bool 'PROM console' CONFIG_PROM_CONSOLE
-bool 'Support Frame buffer devices' CONFIG_FB
source drivers/video/Config.in
endmenu
if [ "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then
dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
- fi
- if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
- int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
- int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
- int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
- bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
- if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
- bool ' include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+ if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+ int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+ int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
+ int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
+ bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
+ if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+ bool ' include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+ fi
+ if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
+ bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+ fi
fi
- if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
- bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
- fi
fi
dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
mainmenu_option next_comment
comment 'Kernel hacking'
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+ bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
+ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
+ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+ bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+ bool ' D-cache flush debugging' CONFIG_DEBUG_DCFLUSH
+fi
+
endmenu
+
+source lib/Config.in
CONFIG_VT_CONSOLE=y
CONFIG_SMP=y
CONFIG_SPARC64=y
+CONFIG_HOTPLUG=y
CONFIG_HAVE_DEC_LOCK=y
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# Console drivers
#
CONFIG_PROM_CONSOLE=y
-CONFIG_FB=y
#
# Frame-buffer support
#
# Multi-device support (RAID and LVM)
#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
# CONFIG_MD_RAID5 is not set
# CONFIG_MD_MULTIPATH is not set
# CONFIG_BLK_DEV_LVM is not set
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
CONFIG_NETLINK_DEV=y
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
# CONFIG_BLK_DEV_TIVO is not set
# CONFIG_BLK_DEV_IDECS is not set
CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDETAPE=m
-CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
#
# CONFIG_IDEDMA_IVB is not set
# CONFIG_DMA_NONPCI is not set
CONFIG_BLK_DEV_IDE_MODES=y
-CONFIG_BLK_DEV_ATARAID=m
-CONFIG_BLK_DEV_ATARAID_PDC=m
-CONFIG_BLK_DEV_ATARAID_HPT=m
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
#
# SCSI support
CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
CONFIG_AIC7XXX_OLD_PROC_STATS=y
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=m
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
CONFIG_SCSI_QLOGIC_ISP=m
CONFIG_SCSI_QLOGIC_FC=y
CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
CONFIG_ADAPTEC_STARFIRE=m
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
+CONFIG_DE2104X=m
CONFIG_TULIP=m
# CONFIG_TULIP_MWI is not set
# CONFIG_TULIP_MMIO is not set
CONFIG_SUNDANCE=m
# CONFIG_TLAN is not set
CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
CONFIG_WINBOND_840=m
# CONFIG_NET_POCKET is not set
CONFIG_NET_FC=y
# CONFIG_IPHASE5526 is not set
# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+CONFIG_SHAPER=m
#
# Wan interfaces
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_TMPFS is not set
-CONFIG_RAMFS=m
+CONFIG_RAMFS=y
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
# CONFIG_ZISOFS is not set
# CONFIG_USB_LONG_TIMEOUT is not set
#
-# USB Controllers
+# USB Host Controller Drivers
#
+CONFIG_USB_EHCI_HCD=m
CONFIG_USB_UHCI=y
# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
CONFIG_USB_OV511=m
CONFIG_USB_PWC=m
CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
CONFIG_USB_DSBR=m
CONFIG_USB_DABUSB=m
CONFIG_USB_SERIAL_EMPEG=m
CONFIG_USB_SERIAL_FTDI_SIO=m
CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
# CONFIG_USB_SERIAL_IR is not set
CONFIG_USB_SERIAL_EDGEPORT=m
CONFIG_USB_SERIAL_KEYSPAN_PDA=m
# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_KLSI=m
CONFIG_USB_SERIAL_PL2303=m
CONFIG_USB_SERIAL_CYBERJACK=m
CONFIG_USB_SERIAL_XIRCOM=m
# USB Miscellaneous drivers
#
CONFIG_USB_RIO500=m
+CONFIG_USB_AUERSWALD=m
#
# Bluetooth support
#
# Kernel hacking
#
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_DCFLUSH is not set
-# $Id: Makefile,v 1.67 2001/05/11 04:31:55 davem Exp $
+# $Id: Makefile,v 1.69 2001/11/19 04:09:53 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@echo "#include <linux/config.h>" > tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
@echo "#include <linux/config.h>" >> check_asm_data.c
@echo "#undef CONFIG_SMP" >> check_asm_data.c
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
- @echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h
+ @echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
@echo "#include <linux/config.h>" > tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#define CONFIG_SMP 1" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
@echo "#include <linux/config.h>" >> check_asm_data.c
@echo "#undef CONFIG_SMP" >> check_asm_data.c
$(HOSTCC) -o check_asm check_asm.c
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
- @echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+ @echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
@echo "#include <linux/sched.h>" > tmp.c
- $(CPP) $(CPPFLAGS) -DSPIN_LOCK_DEBUG tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
@echo "#include <linux/config.h>" >> check_asm_data.c
@echo "#undef CONFIG_SMP" >> check_asm_data.c
$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
@echo '};' >> check_asm_data.c
- $(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
+ $(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
$(HOSTCC) -o check_asm check_asm.c
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
- @echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+ @echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
@if test -r $(HPATH)/asm/asm_offsets.h; then \
-/* $Id: central.c,v 1.14 2000/09/21 06:25:14 anton Exp $
+/* $Id: central.c,v 1.15 2001/12/19 00:29:51 davem Exp $
* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
* Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
if (rngc == nranges) /* oops */
prom_printf("adjust_regs: Could not find range with matching bus type...\n");
regp[regc].which_io = rangep[rngc].ot_parent_space;
+ regp[regc].phys_addr -= rangep[rngc].ot_child_base;
regp[regc].phys_addr += rangep[rngc].ot_parent_base;
}
}
#!/bin/sh
case $1 in
-printf)
- sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
+ sed -n -e '/^#/d;/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0 0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0 0x%08x\\n", check_asm_data[i++]);/' >> $4
echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4
;;
-data)
- sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
+ sed -n -e '/^#/d;/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/ ((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)), sizeof(((struct '$2'_struct *)0)->\0),/' >> $4
echo " sizeof(struct $2_struct)," >> $4
;;
-/* $Id: chmc.c,v 1.3 2001/04/03 12:49:47 davem Exp $
+/* $Id: chmc.c,v 1.4 2002/01/08 16:00:14 davem Exp $
* memctrlr.c: Driver for UltraSPARC-III memory controller.
*
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
#include <linux/init.h>
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
-/* $Id: entry.S,v 1.137 2001/10/18 09:06:36 davem Exp $
+/* $Id: entry.S,v 1.141 2001/12/05 23:56:32 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
ldxa [%g7 + %g0] ASI_INTR_R, %g7
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
- jmpl %g3, %g0
+ ba,pt %xcc, 1f
+ nop
+
+ .align 32
+1: jmpl %g3, %g0
nop
do_ivec_spurious:
stx %g5, [%g1 + %lo(pdma_size)]
sethi %hi(auxio_register), %g1
ldx [%g1 + %lo(auxio_register)], %g7
- ldub [%g7], %g5
+ lduba [%g7] ASI_PHYS_BYPASS_EC_E, %g5
or %g5, 0xc2, %g5
- stb %g5, [%g7]
+ stba %g5, [%g7] ASI_PHYS_BYPASS_EC_E
andn %g5, 0x02, %g5
nop; nop; nop; nop; nop; nop;
nop; nop; nop; nop; nop; nop;
- stb %g5, [%g7]
+ stba %g5, [%g7] ASI_PHYS_BYPASS_EC_E
sethi %hi(doing_pdma), %g1
b,pt %xcc, floppy_dosoftint
st %g0, [%g1 + %lo(doing_pdma)]
sethi %hi(irq_action), %g1
or %g1, %lo(irq_action), %g1
ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq]
- ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr
+ ldx [%g3 + 0x08], %g4 ! action->flags>>48==ino
+ sethi %hi(ivector_table), %g3
+ srlx %g4, 48, %g4
+ or %g3, %lo(ivector_table), %g3
+ sllx %g4, 5, %g4
+ ldx [%g3 + %g4], %g4 ! &ivector_table[ino]
ldx [%g4 + 0x10], %g4 ! bucket->iclr
stwa %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE
membar #Sync ! probably not needed...
*
* Note with time_t changes to the timeval type, I must now use
* nucleus atomic quad 128-bit loads.
+ *
+ * If xtime was stored recently, I've seen crap from the
+ * quad load on Cheetah. Putting a membar SYNC before
+ * the quad load seems to make the problem go away. -DaveM
+ * (we should nop out workarounds like this on spitfire)
*/
sethi %hi(timer_tick_offset), %g3
sethi %hi(xtime), %g2
sethi %hi(0x003e0014), %o1
srlx %o2, 32, %o2
or %o1, %lo(0x003e0014), %o1
+ membar #Sync
ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4
cmp %o2, %o1
bne,pt %xcc, 2f
rd %asr24, %o1
2: rd %tick, %o1
3: ldx [%g1], %g7
+ membar #Sync
ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o2
xor %o4, %o2, %o2
xor %o5, %o3, %o3
-/* $Id: ioctl32.c,v 1.132 2001/11/07 05:56:19 davem Exp $
+/* $Id: ioctl32.c,v 1.135 2002/01/11 08:45:38 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
return -ENODEV;
strcpy(ifr32.ifr_name, dev->name);
+ dev_put(dev);
err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
return (err ? -EFAULT : 0);
u32 pv[ABS_MAX_PV + 1];
u32 lv[ABS_MAX_LV + 1];
uint8_t vg_uuid[UUID_LEN+1]; /* volume group UUID */
+ uint8_t dummy1[200];
} vg32_t;
typedef struct {
} lv_status_byindex_req32_t;
typedef struct {
- dev_t dev;
+ __kernel_dev_t32 dev;
u32 lv;
} lv_status_bydev_req32_t;
lv_block_exception32_t *lbe32;
lv_block_exception_t *lbe;
lv32_t *ul = (lv32_t *)A(p);
- lv_t *l = (lv_t *)kmalloc(sizeof(lv_t), GFP_KERNEL);
+ lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
if (!l) {
*errp = -ENOMEM;
return NULL;
if (l->lv_block_exception) {
lbe32 = (lv_block_exception32_t *)A(ptr2);
memset(lbe, 0, size);
- for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
- err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
- err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
- err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
- err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-
+ for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+ err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+ err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+ err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+ err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
}
}
}
static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
- vg_t *v;
+ vg_t *v = NULL;
union {
lv_req_t lv_req;
le_remap_req_t le_remap;
switch (cmd) {
case VG_STATUS:
v = kmalloc(sizeof(vg_t), GFP_KERNEL);
- if (!v) return -ENOMEM;
+ if (!v)
+ return -ENOMEM;
karg = v;
break;
+
+ case VG_CREATE_OLD:
case VG_CREATE:
v = kmalloc(sizeof(vg_t), GFP_KERNEL);
- if (!v) return -ENOMEM;
- if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
- __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+ if (!v)
+ return -ENOMEM;
+ if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
kfree(v);
return -EFAULT;
}
+ /* 'proc' field is unused, just NULL it out. */
+ v->proc = NULL;
if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
kfree(v);
return -EFAULT;
return -EPERM;
for (i = 0; i < v->pv_max; i++) {
err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
- if (err) break;
+ if (err)
+ break;
if (ptr) {
v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
if (!v->pv[i]) {
err = -ENOMEM;
break;
}
- err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+ err = copy_from_user(v->pv[i], (void *)A(ptr),
+ sizeof(pv32_t) - 8 - UUID_LEN+1);
if (err) {
err = -EFAULT;
break;
}
- err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+ err = copy_from_user(v->pv[i]->pv_uuid,
+ ((pv32_t *)A(ptr))->pv_uuid,
+ UUID_LEN+1);
if (err) {
err = -EFAULT;
break;
}
-
- v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+ v->pv[i]->pe = NULL;
+ v->pv[i]->bd = NULL;
}
}
if (!err) {
for (i = 0; i < v->lv_max; i++) {
err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
- if (err) break;
+ if (err)
+ break;
if (ptr) {
v->lv[i] = get_lv_t(ptr, &err);
- if (err) break;
+ if (err)
+ break;
}
}
}
break;
+
case LV_CREATE:
case LV_EXTEND:
case LV_REDUCE:
case LV_RENAME:
case LV_STATUS_BYNAME:
err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
- if (err) return -EFAULT;
+ if (err)
+ return -EFAULT;
if (cmd != LV_REMOVE) {
err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
- if (err) return err;
+ if (err)
+ return err;
u.lv_req.lv = get_lv_t(ptr, &err);
} else
u.lv_req.lv = NULL;
break;
-
case LV_STATUS_BYINDEX:
- err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+ err = get_user(u.lv_byindex.lv_index,
+ &((lv_status_byindex_req32_t *)arg)->lv_index);
err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
- if (err) return err;
+ if (err)
+ return err;
u.lv_byindex.lv = get_lv_t(ptr, &err);
break;
+
case LV_STATUS_BYDEV:
err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+ err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+ if (err)
+ return err;
u.lv_bydev.lv = get_lv_t(ptr, &err);
- if (err) return err;
- u.lv_bydev.lv = &p;
- p.pe = NULL; p.inode = NULL;
- break;
+ break;
+
case VG_EXTEND:
err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
- if (err) return -EFAULT;
+ if (err)
+ return -EFAULT;
err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
- if (err) return -EFAULT;
- p.pe = NULL; p.inode = NULL;
+ if (err)
+ return -EFAULT;
+ p.pe = NULL;
+ p.bd = NULL;
karg = &p;
break;
+
case PV_CHANGE:
case PV_STATUS:
err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
- if (err) return -EFAULT;
+ if (err)
+ return -EFAULT;
err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
- if (err) return err;
+ if (err)
+ return err;
u.pv_status.pv = &p;
if (cmd == PV_CHANGE) {
- err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
- if (err) return -EFAULT;
- p.pe = NULL; p.inode = NULL;
+ err = copy_from_user(&p, (void *)A(ptr),
+ sizeof(pv32_t) - 8 - UUID_LEN+1);
+ if (err)
+ return -EFAULT;
+ p.pe = NULL;
+ p.bd = NULL;
}
break;
- }
+ };
+
old_fs = get_fs(); set_fs (KERNEL_DS);
err = sys_ioctl (fd, cmd, (unsigned long)karg);
set_fs (old_fs);
+
switch (cmd) {
case VG_STATUS:
if (!err) {
}
kfree(v);
break;
+
+ case VG_CREATE_OLD:
case VG_CREATE:
- for (i = 0; i < v->pv_max; i++)
- if (v->pv[i]) kfree(v->pv[i]);
- for (i = 0; i < v->lv_max; i++)
- if (v->lv[i]) put_lv_t(v->lv[i]);
+ for (i = 0; i < v->pv_max; i++) {
+ if (v->pv[i])
+ kfree(v->pv[i]);
+ }
+ for (i = 0; i < v->lv_max; i++) {
+ if (v->lv[i])
+ put_lv_t(v->lv[i]);
+ }
kfree(v);
break;
+
case LV_STATUS_BYNAME:
- if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+ if (!err && u.lv_req.lv)
+ err = copy_lv_t(ptr, u.lv_req.lv);
/* Fall through */
+
case LV_CREATE:
case LV_EXTEND:
case LV_REDUCE:
- if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+ if (u.lv_req.lv)
+ put_lv_t(u.lv_req.lv);
break;
+
case LV_STATUS_BYINDEX:
if (u.lv_byindex.lv) {
- if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+ if (!err)
+ err = copy_lv_t(ptr, u.lv_byindex.lv);
put_lv_t(u.lv_byindex.lv);
}
break;
+
+ case LV_STATUS_BYDEV:
+ if (u.lv_bydev.lv) {
+ if (!err)
+ err = copy_lv_t(ptr, u.lv_bydev.lv);
+ put_lv_t(u.lv_byindex.lv);
+ }
+ break;
+
case PV_STATUS:
if (!err) {
err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
- if (err) return -EFAULT;
+ if (err)
+ return -EFAULT;
err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
- if (err) return -EFAULT;
+ if (err)
+ return -EFAULT;
}
break;
- case LV_STATUS_BYDEV:
- if (!err) {
- if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv);
- put_lv_t(u.lv_byindex.lv);
- }
- break;
- }
+ };
+
return err;
}
#endif
}
struct usbdevfs_ctrltransfer32 {
- __u8 requesttype;
- __u8 request;
- __u16 value;
- __u16 index;
- __u16 length;
+ __u8 bRequestType;
+ __u8 bRequest;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
__u32 timeout; /* in milliseconds */
__u32 data;
};
/* In usbdevice_fs, it limits the control buffer to a page,
* for simplicity so do we.
*/
- if (!uptr || kctrl.length > PAGE_SIZE)
+ if (!uptr || kctrl.wLength > PAGE_SIZE)
return -EINVAL;
kptr = (void *)__get_free_page(GFP_KERNEL);
- if ((kctrl.requesttype & 0x80) == 0) {
+ if ((kctrl.bRequestType & 0x80) == 0) {
err = -EFAULT;
- if (copy_from_user(kptr, uptr, kctrl.length))
+ if (copy_from_user(kptr, uptr, kctrl.wLength))
goto out;
}
set_fs(old_fs);
if (err >= 0 &&
- ((kctrl.requesttype & 0x80) != 0)) {
- if (copy_to_user(uptr, kptr, kctrl.length))
+ ((kctrl.bRequestType & 0x80) != 0)) {
+ if (copy_to_user(uptr, kptr, kctrl.wLength))
err = -EFAULT;
}
HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
#endif /* LVM */
-/* $Id: iommu_common.c,v 1.8 2001/12/11 11:13:06 davem Exp $
+/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $
* iommu_common.c: UltraSparc SBUS/PCI common iommu code.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
daddr = dma_sg->dma_address;
sglen = sg->length;
- sgaddr = (unsigned long) (sg->address ?
- sg->address :
- page_address(sg->page) + sg->offset);
+ sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
while (dlen > 0) {
unsigned long paddr;
sg++;
if (--nents <= 0)
break;
- sgaddr = (unsigned long) (sg->address ?
- sg->address :
- page_address(sg->page) + sg->offset);
+ sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
sglen = sg->length;
}
if (dlen < 0) {
printk("%016lx.\n", sg->dma_address & IO_PAGE_MASK);
for (i = 0; i < nents; i++) {
- printk("sg(%d): address(%p) length(%x) "
+ printk("sg(%d): page_addr(%p) off(%x) length(%x) "
"dma_address[%016lx] dma_length[%016lx]\n",
i,
- sg[i].address, sg[i].length,
+ page_address(sg[i].page), sg[i].offset,
+ sg[i].length,
sg[i].dma_address, sg[i].dma_length);
}
}
unsigned long prev;
u32 dent_addr, dent_len;
- prev = (unsigned long) (sg->address ?
- sg->address :
- page_address(sg->page) + sg->offset);
+ prev = (unsigned long) (page_address(sg->page) + sg->offset);
prev += (unsigned long) (dent_len = sg->length);
- dent_addr = (u32) ((unsigned long)(sg->address ?
- sg->address :
- page_address(sg->page) + sg->offset)
+ dent_addr = (u32) ((unsigned long)(page_address(sg->page) + sg->offset)
& (IO_PAGE_SIZE - 1UL));
while (--nents) {
unsigned long addr;
sg++;
- addr = (unsigned long) (sg->address ?
- sg->address :
- page_address(sg->page) + sg->offset);
+ addr = (unsigned long) (page_address(sg->page) + sg->offset);
if (! VCONTIG(prev, addr)) {
dma_sg->dma_address = dent_addr;
dma_sg->dma_length = dent_len;
-/* $Id: irq.c,v 1.109 2001/11/12 22:22:37 davem Exp $
+/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/kbd_ll.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/softirq.h>
#include <asm/starfire.h>
#include <asm/uaccess.h>
+#include <asm/cache.h>
#ifdef CONFIG_SMP
static void distribute_irqs(void);
* at the same time.
*/
-struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64)));
+struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
#ifndef CONFIG_SMP
-unsigned int __up_workvec[16] __attribute__ ((aligned (64)));
+unsigned int __up_workvec[16] __attribute__ ((aligned (SMP_CACHE_BYTES)));
#define irq_work(__cpu, __pil) &(__up_workvec[(void)(__cpu), (__pil)])
#else
#define irq_work(__cpu, __pil) &(cpu_data[(__cpu)].irq_worklists[(__pil)])
for(i = 0; i < (NR_IRQS + 1); i++) {
if(!(action = *(i + irq_action)))
continue;
- seq_print(p, "%3d: ", i);
+ seq_printf(p, "%3d: ", i);
#ifndef CONFIG_SMP
- seq_print(p, "%10u ", kstat_irqs(i));
+ seq_printf(p, "%10u ", kstat_irqs(i));
#else
for (j = 0; j < smp_num_cpus; j++)
- seq_print(p, "%10u ",
- kstat.irqs[cpu_logical_map(j)][i]);
+ seq_printf(p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
#endif
- seq_print(p, " %s:%lx", action->name,
- get_ino_in_irqaction(action));
+ seq_printf(p, " %s:%lx", action->name,
+ get_ino_in_irqaction(action));
for(action = action->next; action; action = action->next) {
- seq_print(p, ", %s:%lx", action->name,
- get_ino_in_irqaction(action));
+ seq_printf(p, ", %s:%lx", action->name,
+ get_ino_in_irqaction(action));
}
seq_putc(p, '\n');
}
tid = ((tid & UPA_CONFIG_MID) << 9);
tid &= IMAP_TID_UPA;
} else {
- tid = (starfire_translate(imap, current->processor) << 26);
+ tid = (starfire_translate(imap, smp_processor_id()) << 26);
tid &= IMAP_TID_UPA;
}
irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
+#ifdef CONFIG_PCI
+ if (irq == 9)
+ kbd_pt_regs = regs;
+#endif
+
/* Sliiiick... */
#ifndef CONFIG_SMP
bp = ((irq != 0) ?
prom_timers->count0 = 0;
}
+/* Only invoked on boot processor. */
void __init init_IRQ(void)
{
- static int called = 0;
-
- if (called == 0) {
- called = 1;
- map_prom_timers();
- kill_prom_timer();
- memset(&ivector_table[0], 0, sizeof(ivector_table));
+ map_prom_timers();
+ kill_prom_timer();
+ memset(&ivector_table[0], 0, sizeof(ivector_table));
#ifndef CONFIG_SMP
- memset(&__up_workvec[0], 0, sizeof(__up_workvec));
+ memset(&__up_workvec[0], 0, sizeof(__up_workvec));
#endif
- }
/* We need to clear any IRQ's pending in the soft interrupt
* registers, a spurious one could be left around from the
-/* $Id: pci_iommu.c,v 1.16 2001/10/09 02:24:33 davem Exp $
+/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $
* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
}
#define SG_ENT_PHYS_ADDRESS(SG) \
- ((SG)->address ? \
- __pa((SG)->address) : \
- (__pa(page_address((SG)->page)) + (SG)->offset))
+ (__pa(page_address((SG)->page)) + (SG)->offset)
static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
int nused, int nelems, unsigned long iopte_protection)
if (nelems == 1) {
sglist->dma_address =
pci_map_single(pdev,
- (sglist->address ?
- sglist->address :
- (page_address(sglist->page) + sglist->offset)),
+ (page_address(sglist->page) + sglist->offset),
sglist->length, direction);
sglist->dma_length = sglist->length;
return 1;
-/* $Id: pci_psycho.c,v 1.29 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_psycho.c,v 1.31 2002/01/05 07:33:16 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
#include <linux/slab.h>
#include <asm/pbm.h>
+#include <asm/fhc.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
case PCI_BASE_CLASS_MULTIMEDIA:
case PCI_BASE_CLASS_MEMORY:
case PCI_BASE_CLASS_BRIDGE:
+ case PCI_BASE_CLASS_SERIAL:
ret = 10;
break;
{
unsigned int busrange[2];
struct pci_pbm_info *pbm;
- char namebuf[64];
- int err, len;
+ int err;
if (is_pbm_a) {
pbm = &p->pbm_A;
pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A;
} else {
pbm = &p->pbm_B;
- pbm->pci_first_slot = 1;
- len = prom_getproperty(prom_root_node, "name",
- namebuf, sizeof(namebuf));
- if (len > 0) {
- if (!strcmp(namebuf, "SUNW,Ultra-1-Engine"))
- pbm->pci_first_slot = 2;
- }
+ pbm->pci_first_slot = 2;
+ if (central_bus != NULL)
+ pbm->pci_first_slot = 1;
pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B;
pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B;
}
-/* $Id: pci_sabre.c,v 1.40 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
{
int ret;
+ if (pdev &&
+ pdev->vendor == PCI_VENDOR_ID_SUN &&
+ pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+ return 9;
+
ret = sabre_pil_table[ino];
if (ret == 0 && pdev == NULL) {
ret = 1;
case PCI_BASE_CLASS_MULTIMEDIA:
case PCI_BASE_CLASS_MEMORY:
case PCI_BASE_CLASS_BRIDGE:
+ case PCI_BASE_CLASS_SERIAL:
ret = 10;
break;
-/* $Id: pci_schizo.c,v 1.22 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
* pci_schizo.c: SCHIZO specific PCI controller support.
*
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
{
int ret;
+ if (pdev &&
+ pdev->vendor == PCI_VENDOR_ID_SUN &&
+ pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+ return 9;
+
ret = schizo_pil_table[ino];
if (ret == 0 && pdev == NULL) {
ret = 1;
case PCI_BASE_CLASS_MULTIMEDIA:
case PCI_BASE_CLASS_MEMORY:
case PCI_BASE_CLASS_BRIDGE:
+ case PCI_BASE_CLASS_SERIAL:
ret = 10;
break;
-/* $Id: power.c,v 1.9 2001/06/08 02:28:22 davem Exp $
+/* $Id: power.c,v 1.10 2001/12/11 01:57:16 davem Exp $
* power.c: Power management driver.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
sprintf(current->comm, "powerd");
again:
- while(button_pressed == 0) {
+ while (button_pressed == 0) {
spin_lock_irq(¤t->sigmask_lock);
flush_signals(current);
spin_unlock_irq(¤t->sigmask_lock);
found:
power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
printk("power: Control reg at %016lx ... ", power_reg);
- if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
- printk("Failed to start power daemon.\n");
- return;
- }
- printk("powerd running.\n");
- if (edev->irqs[0] != 0) {
+ if (edev->irqs[0] != PCI_IRQ_NONE) {
+ if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
+ printk("Failed to start power daemon.\n");
+ return;
+ }
+ printk("powerd running.\n");
+
if (request_irq(edev->irqs[0],
power_handler, SA_SHIRQ, "power",
(void *) power_reg) < 0)
printk("power: Error, cannot register IRQ handler.\n");
+ } else {
+ printk("not using powerd.\n");
}
}
#endif /* CONFIG_PCI */
-/* $Id: process.c,v 1.122 2001/10/18 09:06:36 davem Exp $
+/* $Id: process.c,v 1.128 2002/01/11 08:45:38 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
return -EPERM;
/* endless idle loop with no priority at all */
- current->nice = 20;
- init_idle();
-
for (;;) {
/* If current->need_resched is zero we should really
* setup for a system wakup event and execute a shutdown
/*
* the idle loop on a UltraMultiPenguin...
*/
-#define idle_me_harder() (cpu_data[current->processor].idle_volume += 1)
-#define unidle_me() (cpu_data[current->processor].idle_volume = 0)
+#define idle_me_harder() (cpu_data[smp_processor_id()].idle_volume += 1)
+#define unidle_me() (cpu_data[smp_processor_id()].idle_volume = 0)
int cpu_idle(void)
{
- current->nice = 20;
- init_idle();
-
while(1) {
if (current->need_resched != 0) {
unidle_me();
#ifdef CONFIG_SMP
unsigned long flags;
- spin_lock_irqsave(®dump_lock, flags);
+ /* Protect against xcall ipis which might lead to livelock on the lock */
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate"
+ : "=r" (flags)
+ : "i" (PSTATE_IE));
+ spin_lock(®dump_lock);
printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n",
smp_processor_id(),
local_irq_count(smp_processor_id()),
regs->u_regs[15]);
show_regwindow(regs);
#ifdef CONFIG_SMP
- spin_unlock_irqrestore(®dump_lock, flags);
+ spin_unlock(®dump_lock);
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (flags));
#endif
}
csp += STACK_BIAS;
psp += STACK_BIAS;
__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
+ fp += STACK_BIAS;
} else
__get_user(fp, &(((struct reg_window32 *)psp)->ins[6]));
struct thread_struct *t = &p->thread;
char *child_trap_frame;
+#ifdef CONFIG_DEBUG_SPINLOCK
+ t->smp_lock_count = 0;
+ t->smp_lock_pc = 0;
+#endif
+
/* Calculate offset to stack_frame & pt_regs */
child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
-/* $Id: rtrap.S,v 1.56 2001/10/13 00:14:34 kanoj Exp $
+/* $Id: rtrap.S,v 1.59 2002/01/11 08:45:38 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#define RTRAP_PSTATE_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
-#if 0
-#define RTRAP_CHECK call rtrap_check; add %sp, (STACK_BIAS+REGWIN_SZ), %o0;
-#else
-#define RTRAP_CHECK
-#endif
+ /* Register %l6 keeps track of whether we are returning
+ * from a system call or not. It is cleared if we call
+ * do_signal, and it must not be otherwise modified until
+ * we fully commit to returning to userspace.
+ */
.text
-
.align 32
__handle_softirq:
call do_softirq
nop
__handle_preemption:
call schedule
- nop
+ wrpr %g0, RTRAP_PSTATE, %pstate
ba,pt %xcc, __handle_preemption_continue
- nop
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+
__handle_user_windows:
- wrpr %g0, RTRAP_PSTATE, %pstate
call fault_in_user_windows
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+ /* Redo sched+sig checks */
+ ldx [%g6 + AOFF_task_need_resched], %l0
+ brz,pt %l0, 1f
nop
- ba,pt %xcc, __handle_user_windows_continue
+ call schedule
+
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+1: lduw [%g6 + AOFF_task_sigpending], %l0
+ brz,pt %l0, __handle_user_windows_continue
nop
+ clr %o0
+ mov %l5, %o2
+ mov %l6, %o3
+
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call do_signal
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+ clr %l6
+ /* Signal delivery can modify pt_regs tstate, so we must
+ * reload it.
+ */
+ ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+ sethi %hi(0xf << 20), %l4
+ and %l1, %l4, %l4
+
+ ba,pt %xcc, __handle_user_windows_continue
+ andn %l1, %l4, %l1
__handle_perfctrs:
- /* Don't forget to preserve user window invariants. */
- wrpr %g0, RTRAP_PSTATE, %pstate
call update_perfctrs
- nop
+ wrpr %g0, RTRAP_PSTATE, %pstate
wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
- brz,pt %o2, __handle_perfctrs_continue
- sethi %hi(TSTATE_PEF), %l6
- wrpr %g0, RTRAP_PSTATE, %pstate
+ brz,pt %o2, 1f
+ nop
+ /* Redo userwin+sched+sig checks */
call fault_in_user_windows
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+1: ldx [%g6 + AOFF_task_need_resched], %l0
+ brz,pt %l0, 1f
nop
+ call schedule
+ wrpr %g0, RTRAP_PSTATE, %pstate
+
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+1: lduw [%g6 + AOFF_task_sigpending], %l0
+ brz,pt %l0, __handle_perfctrs_continue
+ sethi %hi(TSTATE_PEF), %o0
+ clr %o0
+ mov %l5, %o2
+ mov %l6, %o3
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+
+ call do_signal
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+ clr %l6
+ /* Signal delivery can modify pt_regs tstate, so we must
+ * reload it.
+ */
+ ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+ sethi %hi(0xf << 20), %l4
+ and %l1, %l4, %l4
+ andn %l1, %l4, %l1
+
ba,pt %xcc, __handle_perfctrs_continue
- nop
+ sethi %hi(TSTATE_PEF), %o0
__handle_userfpu:
rd %fprs, %l5
andcc %l5, FPRS_FEF, %g0
+ sethi %hi(TSTATE_PEF), %o0
be,a,pn %icc, __handle_userfpu_continue
- andn %l1, %l6, %l1
+ andn %l1, %o0, %l1
ba,a,pt %xcc, __handle_userfpu_continue
+
__handle_signal:
clr %o0
mov %l5, %o2
mov %l6, %o3
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
call do_signal
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
clr %l6
/* Signal delivery can modify pt_regs tstate, so we must
.align 64
.globl rtrap_clr_l6, rtrap, irqsz_patchme
rtrap_clr_l6: clr %l6
-rtrap: lduw [%g6 + AOFF_task_processor], %l0
+rtrap: lduw [%g6 + AOFF_task_cpu], %l0
sethi %hi(irq_stat), %l2 ! &softirq_active
or %l2, %lo(irq_stat), %l2 ! &softirq_active
irqsz_patchme: sllx %l0, 0, %l0
and %l1, %l4, %l4
bne,pn %icc, to_kernel
andn %l1, %l4, %l1
-to_user: ldx [%g6 + AOFF_task_need_resched], %l0
- brnz,pn %l0, __handle_preemption
+ /* We must hold IRQs off and atomically test schedule+signal
+ * state, then hold them off all the way back to userspace.
+ * If we are returning to kernel, none of this matters.
+ *
+ * If we do not do this, there is a window where we would do
+ * the tests, later the signal/resched event arrives but we do
+ * not process it since we are still in kernel mode. It would
+ * take until the next local IRQ before the signal/resched
+ * event would be handled.
+ *
+ * This also means that if we have to deal with performance
+ * counters or user windows, we have to redo all of these
+ * sched+signal checks with IRQs disabled.
+ */
+to_user: wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
__handle_preemption_continue:
+ ldx [%g6 + AOFF_task_need_resched], %l0
+ brnz,pn %l0, __handle_preemption
lduw [%g6 + AOFF_task_sigpending], %l0
brnz,pn %l0, __handle_signal
nop
__handle_signal_continue:
-check_user_wins:
- wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
brnz,pn %o2, __handle_user_windows
- sethi %hi(TSTATE_PEF), %l6
-
+ nop
__handle_user_windows_continue:
- RTRAP_CHECK
ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
andcc %l5, SPARC_FLAG_PERFCTR, %g0
+ sethi %hi(TSTATE_PEF), %o0
bne,pn %xcc, __handle_perfctrs
__handle_perfctrs_continue:
- andcc %l1, %l6, %g0
+ andcc %l1, %o0, %g0
+
+ /* This fpdepth clear is neccessary for non-syscall rtraps only */
bne,pn %xcc, __handle_userfpu
- stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+ stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
__handle_userfpu_continue:
rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
-/* $Id: sbus.c,v 1.17 2001/10/09 02:24:33 davem Exp $
+/* $Id: sbus.c,v 1.18 2001/12/17 07:05:09 davem Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
}
#define SG_ENT_PHYS_ADDRESS(SG) \
- ((SG)->address ? \
- __pa((SG)->address) : \
- (__pa(page_address((SG)->page)) + (SG)->offset))
+ (__pa(page_address((SG)->page)) + (SG)->offset)
static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, unsigned long iopte_bits)
{
if (nents == 1) {
sg->dma_address =
sbus_map_single(sdev,
- (sg->address ?
- sg->address :
- (page_address(sg->page) + sg->offset)),
+ (page_address(sg->page) + sg->offset),
sg->length, dir);
sg->dma_length = sg->length;
return 1;
-/* $Id: semaphore.c,v 1.8 2001/05/18 08:01:35 davem Exp $
+/* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
* semaphore.c: Sparc64 semaphore implementation.
*
* This is basically the PPC semaphore scheme ported to use
" cas [%3], %0, %1\n"
" cmp %0, %1\n"
" bne,pn %%icc, 1b\n"
-" nop\n"
+" membar #StoreLoad | #StoreStore\n"
: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
: "r" (&sem->count), "r" (incr), "m" (sem->count)
: "cc");
-/* $Id: signal.c,v 1.56 2001/03/21 11:46:20 davem Exp $
+/* $Id: signal.c,v 1.57 2001/12/11 04:55:51 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/tty.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
-/* $Id: signal32.c,v 1.70 2001/04/24 01:09:12 davem Exp $
+/* $Id: signal32.c,v 1.71 2001/12/11 04:55:51 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/tty.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- while (!smp_processors_ready)
+ while (!smp_threads_ready)
membar("#LoadLoad");
-}
-
-extern int cpu_idle(void);
-extern void init_IRQ(void);
-void initialize_secondary(void)
-{
-}
-
-int start_secondary(void *unused)
-{
- trap_init();
- init_IRQ();
- smp_callin();
- return cpu_idle();
+ init_idle();
}
void cpu_panic(void)
printk("Entering UltraSMPenguin Mode...\n");
__sti();
smp_store_cpu_info(boot_cpu_id);
- init_idle();
if (linux_num_cpus == 1)
return;
int no;
prom_printf("Starting CPU %d... ", i);
- kernel_thread(start_secondary, NULL, CLONE_PID);
+ kernel_thread(NULL, NULL, CLONE_PID);
cpucount++;
p = init_task.prev_task;
- init_tasks[cpucount] = p;
- p->processor = i;
- p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+ p->cpu = i;
- del_from_runqueue(p);
unhash_process(p);
callin_flag = 0;
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
- if ((stuck & ~(0x5555555555555555UL)) == 0) {
+ if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) {
/* Busy bits will not clear, continue instead
* of freezing up on this cpu.
*/
int wait;
};
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static struct call_data_struct *call_data;
+
extern unsigned long xcall_call_function;
int smp_call_function(void (*func)(void *info), void *info,
{
struct call_data_struct data;
int cpus = smp_num_cpus - 1;
+ long timeout;
if (!cpus)
return 0;
atomic_set(&data.finished, 0);
data.wait = wait;
- smp_cross_call(&xcall_call_function,
- 0, (u64) &data, 0);
+ spin_lock_bh(&call_lock);
+
+ call_data = &data;
+
+ smp_cross_call(&xcall_call_function, 0, 0, 0);
+
/*
* Wait for other cpus to complete function or at
* least snap the call data.
*/
- while (atomic_read(&data.finished) != cpus)
+ timeout = 1000000;
+ while (atomic_read(&data.finished) != cpus) {
+ if (--timeout <= 0)
+ goto out_timeout;
barrier();
+ udelay(1);
+ }
+
+ spin_unlock_bh(&call_lock);
return 0;
+
+out_timeout:
+ spin_unlock_bh(&call_lock);
+ printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n",
+ smp_num_cpus - 1, atomic_read(&data.finished));
+ return 0;
}
-void smp_call_function_client(struct call_data_struct *call_data)
+void smp_call_function_client(void)
{
void (*func) (void *info) = call_data->func;
void *info = call_data->info;
extern unsigned long xcall_flush_dcache_page_cheetah;
extern unsigned long xcall_flush_dcache_page_spitfire;
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
extern atomic_t dcpage_flushes;
extern atomic_t dcpage_flushes_xcall;
#endif
if (smp_processors_ready) {
unsigned long mask = 1UL << cpu;
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
atomic_inc(&dcpage_flushes);
#endif
if (cpu == smp_processor_id()) {
__pa(page->virtual),
0, mask);
}
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
atomic_inc(&dcpage_flushes_xcall);
#endif
}
}
}
+void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
+{
+ if (smp_processors_ready) {
+ unsigned long mask = cpu_present_map & ~(1UL << smp_processor_id());
+ u64 data0;
+
+#ifdef CONFIG_DEBUG_DCFLUSH
+ atomic_inc(&dcpage_flushes);
+#endif
+ if (mask == 0UL)
+ goto flush_self;
+ if (tlb_type == spitfire) {
+ data0 = ((u64)&xcall_flush_dcache_page_spitfire);
+ if (page->mapping != NULL)
+ data0 |= ((u64)1 << 32);
+ spitfire_xcall_deliver(data0,
+ __pa(page->virtual),
+ (u64) page->virtual,
+ mask);
+ } else {
+ data0 = ((u64)&xcall_flush_dcache_page_cheetah);
+ cheetah_xcall_deliver(data0,
+ __pa(page->virtual),
+ 0, mask);
+ }
+#ifdef CONFIG_DEBUG_DCFLUSH
+ atomic_inc(&dcpage_flushes_xcall);
+#endif
+ flush_self:
+ __local_flush_dcache_page(page);
+ }
+}
+
void smp_receive_signal(int cpu)
{
if (smp_processors_ready) {
__cpu_number_map[boot_cpu_id] = 0;
prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node;
__cpu_logical_map[0] = boot_cpu_id;
- current->processor = boot_cpu_id;
prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
}
-/* $Id: sparc64_ksyms.c,v 1.116 2001/10/26 15:49:21 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.120 2001/12/21 04:56:15 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
#ifdef CONFIG_SMP
extern spinlock_t kernel_flag;
extern int smp_num_cpus;
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
extern void _do_spin_lock (spinlock_t *lock, char *str);
extern void _do_spin_unlock (spinlock_t *lock);
extern int _spin_trylock (spinlock_t *lock);
/* used by various drivers */
#ifdef CONFIG_SMP
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
/* Out of line rw-locking implementation. */
EXPORT_SYMBOL(__read_lock);
EXPORT_SYMBOL(__read_unlock);
EXPORT_SYMBOL(__cpu_logical_map);
/* Spinlock debugging library, optional. */
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
EXPORT_SYMBOL(_do_spin_lock);
EXPORT_SYMBOL(_do_spin_unlock);
EXPORT_SYMBOL(_spin_trylock);
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(_clear_page);
-EXPORT_SYMBOL(_copy_page);
EXPORT_SYMBOL(clear_user_page);
EXPORT_SYMBOL(copy_user_page);
EXPORT_SYMBOL(__bzero);
void VISenter(void);
/* RAID code needs this */
-EXPORT_SYMBOL(VISenter);
+EXPORT_SYMBOL_NOVERS(VISenter);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
-/* $Id: sys_sparc.c,v 1.54 2001/10/28 20:49:13 davem Exp $
+/* $Id: sys_sparc.c,v 1.56 2001/12/21 04:56:15 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
return PAGE_SIZE;
}
-#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1))
+#define COLOUR_ALIGN(addr,pgoff) \
+ ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
+ (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct vm_area_struct * vmm;
unsigned long task_size = TASK_SIZE;
+ int do_color_align;
if (flags & MAP_FIXED) {
/* We do not accept a shared mapping if it would violate
if (!addr)
addr = TASK_UNMAPPED_BASE;
- if (flags & MAP_SHARED)
- addr = COLOUR_ALIGN(addr);
+ do_color_align = 0;
+ if (filp || (flags & MAP_SHARED))
+ do_color_align = 1;
+
+ if (do_color_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
else
addr = PAGE_ALIGN(addr);
-
task_size -= len;
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
if (!vmm || addr + len <= vmm->vm_start)
return addr;
addr = vmm->vm_end;
- if (flags & MAP_SHARED)
- addr = COLOUR_ALIGN(addr);
+ if (do_color_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
}
}
asmlinkage int sparc64_personality(unsigned long personality)
{
- unsigned long ret, trying, orig_ret;
-
- trying = ret = personality;
-
- if (current->personality == PER_LINUX32 &&
- trying == PER_LINUX)
- trying = ret = PER_LINUX32;
-
- /* For PER_LINUX32 we want to retain &default_exec_domain. */
- if (trying == PER_LINUX32)
- ret = PER_LINUX;
-
- orig_ret = ret;
- ret = sys_personality(ret);
+ int ret;
- if (orig_ret == PER_LINUX && trying == PER_LINUX32) {
- current->personality = PER_LINUX32;
+ if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+ personality = PER_LINUX32;
+ ret = sys_personality(personality);
+ if (ret == PER_LINUX32)
ret = PER_LINUX;
- }
- return (int) ret;
+ return ret;
}
/* Linux version of mmap */
-/* $Id: sys_sunos32.c,v 1.61 2001/08/13 14:40:07 davem Exp $
+/* $Id: sys_sunos32.c,v 1.62 2002/01/08 16:00:14 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
struct file *file = NULL;
unsigned long retval, ret_type;
- if(flags & MAP_NORESERVE) {
+ if (flags & MAP_NORESERVE) {
static int cnt;
if (cnt++ < 10)
printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
flags &= ~MAP_NORESERVE;
}
retval = -EBADF;
- if(!(flags & MAP_ANONYMOUS)) {
+ if (!(flags & MAP_ANONYMOUS)) {
struct inode * inode;
- if(fd >= SUNOS_NR_OPEN)
+ if (fd >= SUNOS_NR_OPEN)
goto out;
file = fget(fd);
if (!file)
goto out;
inode = file->f_dentry->d_inode;
- if(MAJOR(inode->i_rdev)==MEM_MAJOR && MINOR(inode->i_rdev)==5) {
+ if (minor(inode->i_rdev) == MEM_MAJOR && minor(inode->i_rdev) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
file = NULL;
}
retval = -EINVAL;
- if(!(flags & MAP_FIXED))
+ if (!(flags & MAP_FIXED))
addr = 0;
else if (len > 0xf0000000 || addr > 0xf0000000 - len)
goto out_putf;
(unsigned long) prot, (unsigned long) flags,
(unsigned long) off);
up_write(¤t->mm->mmap_sem);
- if(!ret_type)
+ if (!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
out_putf:
if (file)
-/* $Id: time.c,v 1.40 2001/09/06 02:44:28 davem Exp $
+/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
unsigned long clock;
init_timers(timer_interrupt, &clock);
- timer_tick_offset = clock / HZ;
timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
}
-/* $Id: trampoline.S,v 1.22 2001/09/07 21:04:40 kanoj Exp $
+/* $Id: trampoline.S,v 1.25 2002/01/11 08:45:38 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
wrpr %o1, PSTATE_IG, %pstate
/* Get our UPA MID. */
- lduw [%o2 + AOFF_task_processor], %g1
+ lduw [%o2 + AOFF_task_cpu], %g1
sethi %hi(cpu_data), %g5
or %g5, %lo(cpu_data), %g5
-/* $Id: traps.c,v 1.79 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: traps.c,v 1.83 2002/01/11 08:45:38 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
void bad_trap (struct pt_regs *regs, long lvl)
{
+ char buffer[32];
siginfo_t info;
if (lvl < 0x100) {
- char buffer[24];
-
- sprintf (buffer, "Bad hw trap %lx at tl0\n", lvl);
+ sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
+ die_if_kernel(buffer, regs);
+ }
+
+ lvl -= 0x100;
+ if (regs->tstate & TSTATE_PRIV) {
+ sprintf(buffer, "Kernel bad sw trap %lx", lvl);
die_if_kernel (buffer, regs);
}
- if (regs->tstate & TSTATE_PRIV)
- die_if_kernel ("Kernel bad trap", regs);
if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
regs->tpc &= 0xffffffff;
regs->tnpc &= 0xffffffff;
info.si_errno = 0;
info.si_code = ILL_ILLTRP;
info.si_addr = (void *)regs->tpc;
- info.si_trapno = lvl - 0x100;
+ info.si_trapno = lvl;
force_sig_info(SIGILL, &info, current);
}
die_if_kernel (buffer, regs);
}
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void do_BUG(const char *file, int line)
+{
+ bust_spinlocks(1);
+ printk("kernel BUG at %s:%d!\n", file, line);
+}
+#endif
+
void instruction_access_exception (struct pt_regs *regs,
unsigned long sfsr, unsigned long sfar)
{
__asm__ __volatile__("ldxa [%0] %3, %%g0\n\t"
"ldxa [%1] %3, %%g0\n\t"
"casxa [%2] %3, %%g0, %%g0\n\t"
+ "membar #StoreLoad | #StoreStore\n\t"
"ldxa [%0] %3, %%g0\n\t"
"ldxa [%1] %3, %%g0\n\t"
"membar #Sync"
}
}
+/* Only invoked on boot processor. */
void trap_init(void)
{
- /* Attach to the address space of init_task. */
+ /* Attach to the address space of init_task. On SMP we
+ * do this in smp.c:smp_callin for other cpus.
+ */
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- /* NOTE: Other cpus have this done as they are started
- * up on SMP.
- */
+#ifdef CONFIG_SMP
+ current->cpu = hard_smp_processor_id();
+#endif
}
-/* $Id: ttable.S,v 1.35 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
*
* Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
sparc64_ttable_tl0:
tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
-tl0_iax: TRAP_NOSAVE(__do_instruction_access_exception)
+tl0_iax: membar #Sync
+ TRAP_NOSAVE_7INSNS(__do_instruction_access_exception)
tl0_resv009: BTRAP(0x9)
tl0_iae: TRAP(do_iae)
tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
-tl0_ill: TRAP(do_illegal_instruction)
+tl0_ill: membar #Sync
+ TRAP_7INSNS(do_illegal_instruction)
tl0_privop: TRAP(do_privop)
tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
-/* $Id: atomic.S,v 1.3 2000/03/16 16:44:37 davem Exp $
+/* $Id: atomic.S,v 1.4 2001/11/18 00:12:56 davem Exp $
* atomic.S: These things are too big to do inline.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
cas [%o1], %g5, %g7
cmp %g5, %g7
bne,pn %icc, __atomic_add
- nop
+ membar #StoreLoad | #StoreStore
retl
add %g7, %o0, %o0
cas [%o1], %g5, %g7
cmp %g5, %g7
bne,pn %icc, __atomic_sub
- nop
+ membar #StoreLoad | #StoreStore
retl
sub %g7, %o0, %o0
atomic_impl_end:
-/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $
+/* $Id: bitops.S,v 1.3 2001/11/18 00:12:56 davem Exp $
* bitops.S: Sparc64 atomic bit operations.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
bne,a,pn %xcc, 1b
ldx [%o1], %g7
2: retl
- nop
+ membar #StoreLoad | #StoreStore
.globl ___test_and_clear_bit
___test_and_clear_bit: /* %o0=nr, %o1=addr */
bne,a,pn %xcc, 1b
ldx [%o1], %g7
2: retl
- nop
+ membar #StoreLoad | #StoreStore
.globl ___test_and_change_bit
___test_and_change_bit: /* %o0=nr, %o1=addr */
bne,a,pn %xcc, 1b
ldx [%o1], %g7
2: retl
- nop
+ membar #StoreLoad | #StoreStore
nop
.globl ___test_and_set_le_bit
bne,a,pn %icc, 1b
lduwa [%o1] ASI_PL, %g7
2: retl
- nop
+ membar #StoreLoad | #StoreStore
.globl ___test_and_clear_le_bit
___test_and_clear_le_bit: /* %o0=nr, %o1=addr */
bne,a,pn %icc, 1b
lduwa [%o1] ASI_PL, %g7
2: retl
- nop
+ membar #StoreLoad | #StoreStore
.globl __bitops_end
__bitops_end:
-/* $Id: blockops.S,v 1.36 2001/09/24 21:44:03 davem Exp $
+/* $Id: blockops.S,v 1.41 2001/12/05 06:05:35 davem Exp $
* blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
fmovd %reg4, %f56; fmovd %reg5, %f58; \
fmovd %reg6, %f60; fmovd %reg7, %f62;
-#define TLBTEMP_BASE (8 * 1024 * 1024)
#define DCACHE_SIZE (PAGE_SIZE * 2)
-#define TLBTEMP_ENT1 (61 << 3)
-#define TLBTEMP_ENT2 (62 << 3)
+#define TLBTEMP_ENT1 (60 << 3)
+#define TLBTEMP_ENT2 (61 << 3)
#define TLBTEMP_ENTSZ (1 << 3)
#if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19)
.text
.align 32
- .globl _copy_page
- .type _copy_page,@function
-_copy_page: /* %o0=dest, %o1=src */
- VISEntry
- membar #LoadStore | #StoreStore | #StoreLoad
- ldda [%o1] ASI_BLK_P, %f0
- add %o1, 0x40, %o1
- ldda [%o1] ASI_BLK_P, %f16
- add %o1, 0x40, %o1
- sethi %hi(PAGE_SIZE), %o2
-1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
- ldda [%o1] ASI_BLK_P, %f32
- stda %f48, [%o0] ASI_BLK_P
- add %o1, 0x40, %o1
- sub %o2, 0x40, %o2
- add %o0, 0x40, %o0
- TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
- ldda [%o1] ASI_BLK_P, %f0
- stda %f48, [%o0] ASI_BLK_P
- add %o1, 0x40, %o1
- sub %o2, 0x40, %o2
- add %o0, 0x40, %o0
- TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
- ldda [%o1] ASI_BLK_P, %f16
- stda %f48, [%o0] ASI_BLK_P
- sub %o2, 0x40, %o2
- add %o1, 0x40, %o1
- cmp %o2, PAGE_SIZE_REM
- bne,pt %xcc, 1b
- add %o0, 0x40, %o0
-#if (PAGE_SHIFT == 16) || (PAGE_SHIFT == 22)
- TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
- ldda [%o1] ASI_BLK_P, %f32
- stda %f48, [%o0] ASI_BLK_P
- add %o1, 0x40, %o1
- sub %o2, 0x40, %o2
- add %o0, 0x40, %o0
- TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
- ldda [%o1] ASI_BLK_P, %f0
- stda %f48, [%o0] ASI_BLK_P
- add %o1, 0x40, %o1
- sub %o2, 0x40, %o2
- add %o0, 0x40, %o0
- membar #Sync
- stda %f32, [%o0] ASI_BLK_P
- add %o0, 0x40, %o0
- stda %f0, [%o0] ASI_BLK_P
-#else
- membar #Sync
- stda %f0, [%o0] ASI_BLK_P
- add %o0, 0x40, %o0
- stda %f16, [%o0] ASI_BLK_P
-#endif
- membar #Sync
- VISExit
- retl
- nop
-
.globl copy_user_page
.type copy_user_page,@function
copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
or %g2, %g3, %g2
add %o0, %o3, %o0
add %o0, %o1, %o1
-#define FIX_INSN_1 0x96102068 /* mov (13 << 3), %o3 */
+#define FIX_INSN_1 0x96102060 /* mov (12 << 3), %o3 */
cheetah_patch_1:
mov TLBTEMP_ENT1, %o3
rdpr %pstate, %g3
stxa %g0, [%o5] ASI_DMMU
membar #Sync
+ ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g0
ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5
stxa %o0, [%o2] ASI_DMMU
stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS
stxa %g0, [%g7] ASI_DMMU
membar #Sync
+ ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g0
ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7
stxa %o1, [%o2] ASI_DMMU
stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS
nop
cheetah_copy_user_page:
- mov 121, %o2 ! A0 Group
+ sethi %hi((PAGE_SIZE/64)-7), %o2 ! A0 Group
prefetch [%o1 + 0x000], #one_read ! MS
- prefetch [%o1 + 0x040], #one_read ! MS Group
+ or %o2, %lo((PAGE_SIZE/64)-7), %o2 ! A1 Group
+ prefetch [%o1 + 0x040], #one_read ! MS
prefetch [%o1 + 0x080], #one_read ! MS Group
prefetch [%o1 + 0x0c0], #one_read ! MS Group
ldd [%o1 + 0x000], %f0 ! MS Group
or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
or %g1, %g3, %g1
add %o0, %o3, %o0
-#define FIX_INSN_2 0x96102070 /* mov (14 << 3), %o3 */
+#define FIX_INSN_2 0x96102068 /* mov (13 << 3), %o3 */
cheetah_patch_2:
mov TLBTEMP_ENT2, %o3
rdpr %pstate, %g3
stxa %g0, [%g7] ASI_DMMU
membar #Sync
+ ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g0
ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7
stxa %o0, [%o2] ASI_DMMU
stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS
clear_page_common:
membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
fzero %f0 ! FPA Group
- mov PAGE_SIZE/256, %o1 ! IEU0
+ sethi %hi(PAGE_SIZE/256), %o1 ! IEU0
fzero %f2 ! FPA Group
+ or %o1, %lo(PAGE_SIZE/256), %o1 ! IEU0
faddd %f0, %f2, %f4 ! FPA Group
fmuld %f0, %f2, %f6 ! FPM
faddd %f0, %f2, %f8 ! FPA Group
-/* $Id: debuglocks.c,v 1.6 2001/04/24 01:09:12 davem Exp $
+/* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $
* debuglocks.c: Debugging versions of SMP locking primitives.
*
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
#include <linux/spinlock.h>
#include <asm/system.h>
-#ifdef CONFIG_SMP
-
-/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
-#ifdef SPIN_LOCK_DEBUG
+#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
unsigned long caller, val;
int stuck = INIT_STUCK;
int cpu = smp_processor_id();
+ int shown = 0;
GET_CALLER(caller);
again:
if (val) {
while (lock->lock) {
if (!--stuck) {
- show(str, lock, caller);
+ if (shown++ <= 2)
+ show(str, lock, caller);
stuck = INIT_STUCK;
}
membar("#LoadLoad");
}
lock->owner_pc = ((unsigned int)caller);
lock->owner_cpu = cpu;
+ current->thread.smp_lock_count++;
+ current->thread.smp_lock_pc = ((unsigned int)caller);
}
int _spin_trylock(spinlock_t *lock)
if (!val) {
lock->owner_pc = ((unsigned int)caller);
lock->owner_cpu = cpu;
+ current->thread.smp_lock_count++;
+ current->thread.smp_lock_pc = ((unsigned int)caller);
}
return val == 0;
}
lock->owner_cpu = NO_PROC_ID;
membar("#StoreStore | #LoadStore");
lock->lock = 0;
+ current->thread.smp_lock_count--;
}
/* Keep INIT_STUCK the same... */
unsigned long caller, val;
int stuck = INIT_STUCK;
int cpu = smp_processor_id();
+ int shown = 0;
GET_CALLER(caller);
wlock_again:
/* Wait for any writer to go away. */
while (((long)(rw->lock)) < 0) {
if (!--stuck) {
- show_read(str, rw, caller);
+ if (shown++ <= 2)
+ show_read(str, rw, caller);
stuck = INIT_STUCK;
}
membar("#LoadLoad");
if (val)
goto wlock_again;
rw->reader_pc[cpu] = ((unsigned int)caller);
+ current->thread.smp_lock_count++;
+ current->thread.smp_lock_pc = ((unsigned int)caller);
}
void _do_read_unlock (rwlock_t *rw, char *str)
unsigned long caller, val;
int stuck = INIT_STUCK;
int cpu = smp_processor_id();
+ int shown = 0;
GET_CALLER(caller);
/* Drop our identity _first_. */
rw->reader_pc[cpu] = 0;
+ current->thread.smp_lock_count--;
runlock_again:
/* Spin trying to decrement the counter using casx. */
__asm__ __volatile__(
: "g5", "g7", "memory");
if (val) {
if (!--stuck) {
- show_read(str, rw, caller);
+ if (shown++ <= 2)
+ show_read(str, rw, caller);
stuck = INIT_STUCK;
}
goto runlock_again;
unsigned long caller, val;
int stuck = INIT_STUCK;
int cpu = smp_processor_id();
+ int shown = 0;
GET_CALLER(caller);
wlock_again:
/* Spin while there is another writer. */
while (((long)rw->lock) < 0) {
if (!--stuck) {
- show_write(str, rw, caller);
+ if (shown++ <= 2)
+ show_write(str, rw, caller);
stuck = INIT_STUCK;
}
membar("#LoadLoad");
if (val) {
/* We couldn't get the write bit. */
if (!--stuck) {
- show_write(str, rw, caller);
+ if (shown++ <= 2)
+ show_write(str, rw, caller);
stuck = INIT_STUCK;
}
goto wlock_again;
* lock, spin, and try again.
*/
if (!--stuck) {
- show_write(str, rw, caller);
+ if (shown++ <= 2)
+ show_write(str, rw, caller);
stuck = INIT_STUCK;
}
__asm__ __volatile__(
: "g3", "g5", "g7", "cc", "memory");
while(rw->lock != 0) {
if (!--stuck) {
- show_write(str, rw, caller);
+ if (shown++ <= 2)
+ show_write(str, rw, caller);
stuck = INIT_STUCK;
}
membar("#LoadLoad");
/* We have it, say who we are. */
rw->writer_pc = ((unsigned int)caller);
rw->writer_cpu = cpu;
+ current->thread.smp_lock_count++;
+ current->thread.smp_lock_pc = ((unsigned int)caller);
}
void _do_write_unlock(rwlock_t *rw)
{
unsigned long caller, val;
int stuck = INIT_STUCK;
+ int shown = 0;
GET_CALLER(caller);
/* Drop our identity _first_ */
rw->writer_pc = 0;
rw->writer_cpu = NO_PROC_ID;
+ current->thread.smp_lock_count--;
wlock_again:
__asm__ __volatile__(
" mov 1, %%g3\n"
: "g3", "g5", "g7", "memory");
if (val) {
if (!--stuck) {
- show_write("write_unlock", rw, caller);
+ if (shown++ <= 2)
+ show_write("write_unlock", rw, caller);
stuck = INIT_STUCK;
}
goto wlock_again;
}
}
-#endif /* SPIN_LOCK_DEBUG */
-#endif /* CONFIG_SMP */
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+ spin_lock(lock);
+ if (atomic_dec_and_test(atomic))
+ return 1;
+ spin_unlock(lock);
+ return 0;
+}
+
+#endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */
-/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $
+/* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $
* dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()"
* using cas and ldstub instructions.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
*/
+#include <linux/config.h>
+#ifndef CONFIG_DEBUG_SPINLOCK
.text
.align 64
bne,pn %icc, loop1
mov 0, %g1
-out: retl
+out:
+ membar #StoreLoad | #StoreStore
+ retl
mov %g1, %o0
-to_zero:ldstub [%o1], %g3
+to_zero:
+ ldstub [%o1], %g3
brnz,pn %g3, spin_on_lock
membar #StoreLoad | #StoreStore
loop2: cas [%o0], %g5, %g7 /* ASSERT(g7 == 0) */
- nop
cmp %g5, %g7
be,pt %icc, out
ba,pt %xcc, to_zero
nop
nop
+
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
static unsigned long
search_one_table(const struct exception_table_entry *start,
- const struct exception_table_entry *last,
+ const struct exception_table_entry *end,
unsigned long value, unsigned long *g2)
{
- const struct exception_table_entry *first = start;
- const struct exception_table_entry *mid;
- long diff = 0;
- while (first <= last) {
- mid = (last - first) / 2 + first;
- diff = mid->insn - value;
- if (diff == 0) {
- if (!mid->fixup) {
- *g2 = 0;
- return (mid + 1)->fixup;
- } else
- return mid->fixup;
- } else if (diff < 0)
- first = mid+1;
- else
- last = mid-1;
- }
- if (last->insn < value && !last->fixup && last[1].insn > value) {
- *g2 = (value - last->insn)/4;
- return last[1].fixup;
- }
- if (first > start && first[-1].insn < value
- && !first[-1].fixup && first->insn < value) {
- *g2 = (value - first[-1].insn)/4;
- return first->fixup;
- }
+ const struct exception_table_entry *walk;
+
+ /* Single insn entries are encoded as:
+ * word 1: insn address
+ * word 2: fixup code address
+ *
+ * Range entries are encoded as:
+ * word 1: first insn address
+ * word 2: 0
+ * word 3: last insn address + 4 bytes
+ * word 4: fixup code address
+ *
+ * See asm/uaccess.h for more details.
+ */
+
+ /* 1. Try to find an exact match. */
+ for (walk = start; walk <= end; walk++) {
+ if (walk->fixup == 0) {
+ /* A range entry, skip both parts. */
+ walk++;
+ continue;
+ }
+
+ if (walk->insn == value)
+ return walk->fixup;
+ }
+
+ /* 2. Try to find a range match. */
+ for (walk = start; walk <= (end - 1); walk++) {
+ if (walk->fixup)
+ continue;
+
+ if (walk[0].insn <= value &&
+ walk[1].insn > value) {
+ *g2 = (value - walk[0].insn) / 4;
+ return walk[1].fixup;
+ }
+ walk++;
+ }
+
return 0;
}
extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
atomic_t dcpage_flushes = ATOMIC_INIT(0);
#ifdef CONFIG_SMP
atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0);
__inline__ void flush_dcache_page_impl(struct page *page)
{
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
atomic_inc(&dcpage_flushes);
#endif
"casx [%2], %%g7, %%g5\n\t"
"cmp %%g7, %%g5\n\t"
"bne,pn %%xcc, 1b\n\t"
- " nop"
+ " membar #StoreLoad | #StoreStore"
: /* no outputs */
: "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
: "g5", "g7");
"casx [%2], %%g7, %%g5\n\t"
"cmp %%g7, %%g5\n\t"
"bne,pn %%xcc, 1b\n\t"
- " nop\n"
+ " membar #StoreLoad | #StoreStore\n"
"2:"
: /* no outputs */
: "r" (cpu), "r" (mask), "r" (&page->flags)
else
seq_printf(m, "MMU Type\t: ???\n");
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
seq_printf(m, "DCPageFlushes\t: %d\n",
atomic_read(&dcpage_flushes));
#ifdef CONFIG_SMP
seq_printf(m, "DCPageFlushesXC\t: %d\n",
atomic_read(&dcpage_flushes_xcall));
#endif /* CONFIG_SMP */
-#endif /* DCFLUSH_DEBUG */
+#endif /* CONFIG_DEBUG_DCFLUSH */
}
struct linux_prom_translation {
-/* $Id: ultra.S,v 1.68 2001/11/09 14:59:19 davem Exp $
+/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
wrpr %g1, PSTATE_IE, %pstate
mov TLB_TAG_ACCESS, %g3
/* XXX Spitfire dependency... */
- mov (62 << 3), %g2
+ mov ((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
/* Spitfire Errata #32 workaround. */
mov 0x8, %o4
stx %g0, [%g4 + %lo(errata32_hwbug)]
2: add %g2, 1, %g2
- cmp %g2, 63
+ cmp %g2, SPITFIRE_HIGHEST_LOCKED_TLBENT
ble,pt %icc, 1b
sll %g2, 3, %g3
flush %g6
.globl xcall_call_function
xcall_call_function:
- mov TLB_TAG_ACCESS, %g5 ! wheee...
- stxa %g1, [%g5] ASI_IMMU ! save call_data here for a bit
- membar #Sync
rdpr %pstate, %g2
wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
- mov TLB_TAG_ACCESS, %g2
- ldxa [%g2] ASI_IMMU, %g5
rdpr %pil, %g2
wrpr %g0, 15, %pil
sethi %hi(109f), %g7
b,pt %xcc, etrap_irq
109: or %g7, %lo(109b), %g7
call smp_call_function_client
- mov %l5, %o0
+ nop
b,pt %xcc, rtrap
clr %l6
-/* $Id: fs.c,v 1.25 2001/09/19 00:04:30 davem Exp $
+/* $Id: fs.c,v 1.26 2002/01/08 16:00:21 davem Exp $
* fs.c: fs related syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
__put_user (s.f_files, &ss->f_files) ||
__put_user (s.f_ffree, &ss->f_ffree) ||
__put_user (s.f_ffree, &ss->f_favail) ||
- __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+ __put_user (R4_DEV(kdev_t_to_nr(inode->i_sb->s_dev)), &ss->f_fsid) ||
__copy_to_user (ss->f_basetype,p,j) ||
__put_user (0, (char *)&ss->f_basetype[j]) ||
__put_user (s.f_namelen, &ss->f_namemax) ||
__put_user (s.f_files, &ss->f_files) ||
__put_user (s.f_ffree, &ss->f_ffree) ||
__put_user (s.f_ffree, &ss->f_favail) ||
- __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+ __put_user (R4_DEV(kdev_t_to_nr(inode->i_sb->s_dev)), &ss->f_fsid) ||
__copy_to_user (ss->f_basetype,p,j) ||
__put_user (0, (char *)&ss->f_basetype[j]) ||
__put_user (s.f_namelen, &ss->f_namemax) ||
-/* $Id: misc.c,v 1.33 2001/09/18 22:29:06 davem Exp $
+/* $Id: misc.c,v 1.35 2002/01/08 16:00:21 davem Exp $
* misc.c: Miscelaneous syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#include <linux/mman.h>
#include <linux/file.h>
#include <linux/timex.h>
+#include <linux/major.h>
#include <asm/uaccess.h>
#include <asm/string.h>
goto out;
else {
struct inode * inode = file->f_dentry->d_inode;
- if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
- MINOR(inode->i_rdev) == 5) {
+ if(major(inode->i_rdev) == MEM_MAJOR &&
+ minor(inode->i_rdev) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
file = NULL;
-/* $Id: socksys.c,v 1.18 2001/02/13 01:16:44 davem Exp $
+/* $Id: socksys.c,v 1.20 2002/01/08 16:00:21 davem Exp $
* socksys.c: /dev/inet/ stuff for Solaris emulation.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
(int (*)(int,int,int))SUNOS(97);
struct sol_socket_struct * sock;
- family = ((MINOR(inode->i_rdev) >> 4) & 0xf);
+ family = ((minor(inode->i_rdev) >> 4) & 0xf);
switch (family) {
case AF_UNIX:
type = SOCK_STREAM;
protocol = 0;
break;
case AF_INET:
- protocol = af_inet_protocols[MINOR(inode->i_rdev) & 0xf];
+ protocol = af_inet_protocols[minor(inode->i_rdev) & 0xf];
switch (protocol) {
case IPPROTO_TCP: type = SOCK_STREAM; break;
case IPPROTO_UDP: type = SOCK_DGRAM; break;
-/* $Id: timod.c,v 1.16 2001/09/18 22:29:06 davem Exp $
+/* $Id: timod.c,v 1.18 2002/01/08 16:00:21 davem Exp $
* timod.c: timod emulation.
*
* Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
if (!ino) goto out;
if (!ino->i_sock &&
- (MAJOR(ino->i_rdev) != 30 || MINOR(ino->i_rdev) != 1))
+ (major(ino->i_rdev) != 30 || minor(ino->i_rdev) != 1))
goto out;
ctlptr = (struct strbuf *)A(arg1);
fi
dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI
+dep_mbool ' SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
revalidate: frevalidate_logvol,
};
+#include "cciss_scsi.c" /* For SCSI tape support */
+
/*
* Report information about this controller.
*/
h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG);
pos += size; len += size;
+ cciss_proc_tape_report(ctlr, buffer, &pos, &len);
for(i=0; i<h->num_luns; i++) {
drv = &h->drv[i];
size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
return len;
}
+static int
+cciss_proc_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ unsigned char cmd[80];
+ int len;
+#ifdef CONFIG_CISS_SCSI_TAPE
+ ctlr_info_t *h = (ctlr_info_t *) data;
+ int rc;
+#endif
+
+ if (count > sizeof(cmd)-1) return -EINVAL;
+ if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+ cmd[count] = '\0';
+ len = strlen(cmd); // above 3 lines ensure safety
+ if (cmd[len-1] == '\n')
+ cmd[--len] = '\0';
+# ifdef CONFIG_CISS_SCSI_TAPE
+ if (strcmp("engage scsi", cmd)==0) {
+ rc = cciss_engage_scsi(h->ctlr);
+ if (rc != 0) return -rc;
+ return count;
+ }
+ /* might be nice to have "disengage" too, but it's not
+ safely possible. (only 1 module use count, lock issues.) */
+# endif
+ return -EINVAL;
+}
+
/*
* Get us a file in /proc/cciss that says something about each controller.
* Create /proc/cciss if it doesn't exist yet.
*/
static void __init cciss_procinit(int i)
{
+ struct proc_dir_entry *pde;
+
if (proc_cciss == NULL) {
proc_cciss = proc_mkdir("cciss", proc_root_driver);
if (!proc_cciss)
return;
}
- create_proc_read_entry(hba[i]->devname, 0, proc_cciss,
- cciss_proc_get_info, hba[i]);
+ pde = create_proc_read_entry(hba[i]->devname,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
+ proc_cciss, cciss_proc_get_info, hba[i]);
+ pde->write_proc = cciss_proc_write;
}
#endif /* CONFIG_PROC_FS */
int ctlr,
void *buff,
size_t size,
- unsigned int use_unit_num,
+ unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: periph device address is scsi3addr */
unsigned int log_unit,
- __u8 page_code )
+ __u8 page_code,
+ unsigned char *scsi3addr)
{
CommandList_struct *c;
int i;
to controller so It's a physical command
mode = 0 target = 0.
So we have nothing to write.
- Otherwise
- mode = 1 target = LUNID
+ otherwise, if use_unit_num == 1,
+ mode = 1(volume set addressing) target = LUNID
+ otherwise, if use_unit_num == 2,
+ mode = 0(periph dev addr) target = scsi3addr
*/
- if(use_unit_num != 0)
+ if(use_unit_num == 1)
{
c->Header.LUN.LogDev.VolId=
hba[ctlr]->drv[log_unit].LunID;
c->Header.LUN.LogDev.Mode = 1;
}
+ else if (use_unit_num == 2)
+ {
+ memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+ c->Header.LUN.LogDev.Mode = 0; // phys dev addr
+ }
+
/* are we trying to read a vital product page */
if(page_code != 0)
{
c->Request.CDB[4] = size & 0xFF;
break;
case CISS_REPORT_LOG:
+ case CISS_REPORT_PHYS:
/* Talking to controller so It's a physical command
mode = 00 target = 0.
So we have nothing to write.
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ; // Read
c->Request.Timeout = 0; // Don't time out
- c->Request.CDB[0] = CISS_REPORT_LOG;
+ c->Request.CDB[0] = cmd;
c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0xFF;
ignore it
*/
if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
+ (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
(c->Request.CDB[0] == CISS_INQUIRY)) &&
((c->err_info->CommandStatus ==
CMD_DATA_OVERRUN) ||
} else if (c->cmd_type == CMD_IOCTL_PEND) {
c->cmd_type = CMD_IOCTL_DONE;
}
+# ifdef CONFIG_CISS_SCSI_TAPE
+ else if (c->cmd_type == CMD_SCSI)
+ complete_scsi_command(c, 0, a1);
+# endif
continue;
}
}
}
/* Get the firmware version */
return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
- sizeof(InquiryData_struct), 0, 0 ,0 );
+ sizeof(InquiryData_struct), 0, 0 ,0, NULL );
if (return_code == IO_OK)
{
hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
}
/* Get the number of logical volumes */
return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0 );
+ sizeof(ReportLunData_struct), 0, 0, 0, NULL );
if( return_code == IO_OK)
{
memset(size_buff, 0, sizeof(ReadCapdata_struct));
return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff,
- sizeof( ReadCapdata_struct), 1, i, 0 );
+ sizeof( ReadCapdata_struct), 1, i, 0, NULL );
if (return_code == IO_OK)
{
total_size = (0xff &
/* Execute the command to read the disk geometry */
memset(inq_buff, 0, sizeof(InquiryData_struct));
return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
- sizeof(InquiryData_struct), 1, i ,0xC1 );
+ sizeof(InquiryData_struct), 1, i ,0xC1, NULL );
if (return_code == IO_OK)
{
if(inq_buff->data_byte[8] == 0xFF)
cciss_getgeometry(i);
+ cciss_find_non_disk_devices(i); /* find our tape drives, if any */
+
/* Turn the interrupts on so we can service requests */
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
MAX_PART, &cciss_fops,
hba[i]->drv[j].nr_blocks);
+ cciss_register_scsi(i, 1); /* hook ourself into SCSI subsystem */
+
return(1);
}
free_irq(hba[i]->intr, hba[i]);
pci_set_drvdata(pdev, NULL);
iounmap((void*)hba[i]->vaddr);
+ cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
remove_proc_entry(hba[i]->devname, proc_cciss);
struct hd_struct hd[256];
int sizes[256];
int blocksizes[256];
+#ifdef CONFIG_CISS_SCSI_TAPE
+ void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
+#endif
};
/* Defining the diffent access_menthods */
//STRUCTURES
//###########################################################################
#define CISS_MAX_LUN 16
+#define CISS_MAX_PHYS_LUN 1024
// SCSI-3 Cmmands
#pragma pack(1)
} InquiryData_struct;
#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */
+#define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */
// Data returned
typedef struct _ReportLUNdata_struct
{
#define CMD_RWREQ 0x00
#define CMD_IOCTL_PEND 0x01
#define CMD_IOCTL_DONE 0x02
+#define CMD_SCSI 0x03
+#define CMD_MSG_DONE 0x04
+#define CMD_MSG_TIMEOUT 0x05
typedef struct _CommandList_struct {
CommandListHeader_struct Header;
struct _CommandList_struct *prev;
struct _CommandList_struct *next;
struct request * rq;
+#ifdef CONFIG_CISS_SCSI_TAPE
+ void * scsi_cmd;
+#endif
} CommandList_struct;
//Configuration Table Structure
--- /dev/null
+/*
+ * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
+ * Copyright 2001 Compaq Computer Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ * Author: Stephen M. Cameron
+ */
+#ifdef CONFIG_CISS_SCSI_TAPE
+
+/* Here we have code to present the driver as a scsi driver
+ as it is simultaneously presented as a block driver. The
+ reason for doing this is to allow access to SCSI tape drives
+ through the array controller. Note in particular, neither
+ physical nor logical disks are presented through the scsi layer. */
+
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include <asm/atomic.h>
+#include <linux/timer.h>
+
+#include "cciss_scsi.h"
+
+/* some prototypes... */
+static int sendcmd(
+ __u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: address is in scsi3addr */
+ unsigned int log_unit,
+ __u8 page_code,
+ unsigned char *scsi3addr );
+
+
+int __init cciss_scsi_detect(Scsi_Host_Template *tpnt);
+int cciss_scsi_release(struct Scsi_Host *sh);
+const char *cciss_scsi_info(struct Scsi_Host *sa);
+
+int cciss_scsi_proc_info(
+ char *buffer, /* data buffer */
+ char **start, /* where data in buffer starts */
+ off_t offset, /* offset from start of imaginary file */
+ int length, /* length of data in buffer */
+ int hostnum, /* which host adapter (always zero for me) */
+ int func); /* 0 == read, 1 == write */
+
+int cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *));
+#if 0
+int cciss_scsi_abort(Scsi_Cmnd *cmd);
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+int cciss_scsi_reset(Scsi_Cmnd *cmd, unsigned int reset_flags);
+#else
+int cciss_scsi_reset(Scsi_Cmnd *cmd);
+#endif
+#endif
+
+static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
+ { name: "cciss0", ndevices: 0 },
+ { name: "cciss1", ndevices: 0 },
+ { name: "cciss2", ndevices: 0 },
+ { name: "cciss3", ndevices: 0 },
+ { name: "cciss4", ndevices: 0 },
+ { name: "cciss5", ndevices: 0 },
+ { name: "cciss6", ndevices: 0 },
+ { name: "cciss7", ndevices: 0 },
+};
+
+/* We need one Scsi_Host_Template *per controller* instead of
+ the usual one Scsi_Host_Template per controller *type*. This
+ is so PCI hot plug could have a remote possibility of still
+ working even with the SCSI system. It's so
+ scsi_unregister_host will differentiate the controllers.
+ When register_scsi_module is called, each host template is
+ customized (name change) in cciss_register_scsi()
+ (that's called from cciss.c:cciss_init_one()) */
+
+static
+Scsi_Host_Template driver_template[MAX_CTLR] =
+{
+ CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+ CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+};
+
+#pragma pack(1)
+struct cciss_scsi_cmd_stack_elem_t {
+ CommandList_struct cmd;
+ ErrorInfo_struct Err;
+ __u32 busaddr;
+};
+
+#pragma pack()
+
+#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
+ CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
+ // plus two for init time usage
+
+#pragma pack(1)
+struct cciss_scsi_cmd_stack_t {
+ struct cciss_scsi_cmd_stack_elem_t *pool;
+ struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
+ dma_addr_t cmd_pool_handle;
+ int top;
+};
+#pragma pack()
+
+struct cciss_scsi_adapter_data_t {
+ struct Scsi_Host *scsi_host;
+ struct cciss_scsi_cmd_stack_t cmd_stack;
+ int registered;
+ spinlock_t lock; // to protect ccissscsi[ctlr];
+};
+
+#define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \
+ &(((struct cciss_scsi_adapter_data_t *) \
+ hba[ctlr]->scsi_ctlr)->lock), flags);
+#define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \
+ &(((struct cciss_scsi_adapter_data_t *) \
+ hba[ctlr]->scsi_ctlr)->lock), flags);
+
+static CommandList_struct *
+scsi_cmd_alloc(ctlr_info_t *h)
+{
+ /* assume only one process in here at a time, locking done by caller. */
+ /* use CCISS_LOCK(ctlr) */
+ /* might be better to rewrite how we allocate scsi commands in a way that */
+ /* needs no locking at all. */
+
+ /* take the top memory chunk off the stack and return it, if any. */
+ struct cciss_scsi_cmd_stack_elem_t *c;
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ u64bit temp64;
+
+ sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+ stk = &sa->cmd_stack;
+
+ if (stk->top < 0)
+ return NULL;
+ c = stk->elem[stk->top];
+ /* memset(c, 0, sizeof(*c)); */
+ memset(&c->cmd, 0, sizeof(c->cmd));
+ memset(&c->Err, 0, sizeof(c->Err));
+ /* set physical addr of cmd and addr of scsi parameters */
+ c->cmd.busaddr = c->busaddr;
+ /* (__u32) (stk->cmd_pool_handle +
+ (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
+
+ temp64.val = (__u64) (c->busaddr + sizeof(CommandList_struct));
+ /* (__u64) (stk->cmd_pool_handle +
+ (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top) +
+ sizeof(CommandList_struct)); */
+ stk->top--;
+ c->cmd.ErrDesc.Addr.lower = temp64.val32.lower;
+ c->cmd.ErrDesc.Addr.upper = temp64.val32.upper;
+ c->cmd.ErrDesc.Len = sizeof(ErrorInfo_struct);
+
+ c->cmd.ctlr = h->ctlr;
+ c->cmd.err_info = &c->Err;
+
+ return (CommandList_struct *) c;
+}
+
+static void
+scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
+{
+ /* assume only one process in here at a time, locking done by caller. */
+ /* use CCISS_LOCK(ctlr) */
+ /* drop the free memory chunk on top of the stack. */
+
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+
+ sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+ stk = &sa->cmd_stack;
+ if (stk->top >= CMD_STACK_SIZE) {
+ printk("cciss: scsi_cmd_free called too many times.\n");
+ BUG();
+ }
+ stk->top++;
+ stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
+}
+
+static int
+scsi_cmd_stack_setup(int ctlr)
+{
+ int i;
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ size_t size;
+
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+ size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+
+ // We use NULL as first arg to pci_alloc_consistent so we can be
+ // sure that we get addresses that will fit through the 32 bit
+ // command register, (our DMA mask says we can do 64 bit DMA, which
+ // we, can, just not for commands.)
+
+ stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
+ pci_alloc_consistent(NULL, size, &stk->cmd_pool_handle);
+
+ if (stk->pool == NULL) {
+ printk("stk->pool is null\n");
+ return -1;
+ }
+
+ for (i=0; i<CMD_STACK_SIZE; i++) {
+ stk->elem[i] = &stk->pool[i];
+ stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle +
+ (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
+ }
+ stk->top = CMD_STACK_SIZE-1;
+ return 0;
+}
+
+static void
+scsi_cmd_stack_free(int ctlr)
+{
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ size_t size;
+
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+ if (stk->top != CMD_STACK_SIZE-1) {
+ printk( "cciss: %d scsi commands are still outstanding.\n",
+ CMD_STACK_SIZE - stk->top);
+ // BUG();
+ printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
+ (unsigned int) stk);
+ }
+ size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+
+ // About NULL, see note above near pci_alloc_consistent
+ pci_free_consistent(NULL, size, stk->pool, stk->cmd_pool_handle);
+ stk->pool = NULL;
+}
+
+/* scsi_device_types comes from scsi.h */
+#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
+ "Unknown" : scsi_device_types[n]
+
+#if 0
+static int xmargin=8;
+static int amargin=60;
+
+static void
+print_bytes (unsigned char *c, int len, int hex, int ascii)
+{
+
+ int i;
+ unsigned char *x;
+
+ if (hex)
+ {
+ x = c;
+ for (i=0;i<len;i++)
+ {
+ if ((i % xmargin) == 0 && i>0) printk("\n");
+ if ((i % xmargin) == 0) printk("0x%04x:", i);
+ printk(" %02x", *x);
+ x++;
+ }
+ printk("\n");
+ }
+ if (ascii)
+ {
+ x = c;
+ for (i=0;i<len;i++)
+ {
+ if ((i % amargin) == 0 && i>0) printk("\n");
+ if ((i % amargin) == 0) printk("0x%04x:", i);
+ if (*x > 26 && *x < 128) printk("%c", *x);
+ else printk(".");
+ x++;
+ }
+ printk("\n");
+ }
+}
+
+static void
+print_cmd(CommandList_struct *cp)
+{
+ printk("queue:%d\n", cp->Header.ReplyQueue);
+ printk("sglist:%d\n", cp->Header.SGList);
+ printk("sgtot:%d\n", cp->Header.SGTotal);
+ printk("Tag:0x%08x/0x%08x\n", cp->Header.Tag.upper,
+ cp->Header.Tag.lower);
+ printk("LUN:0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ cp->Header.LUN.LunAddrBytes[0],
+ cp->Header.LUN.LunAddrBytes[1],
+ cp->Header.LUN.LunAddrBytes[2],
+ cp->Header.LUN.LunAddrBytes[3],
+ cp->Header.LUN.LunAddrBytes[4],
+ cp->Header.LUN.LunAddrBytes[5],
+ cp->Header.LUN.LunAddrBytes[6],
+ cp->Header.LUN.LunAddrBytes[7]);
+ printk("CDBLen:%d\n", cp->Request.CDBLen);
+ printk("Type:%d\n",cp->Request.Type.Type);
+ printk("Attr:%d\n",cp->Request.Type.Attribute);
+ printk(" Dir:%d\n",cp->Request.Type.Direction);
+ printk("Timeout:%d\n",cp->Request.Timeout);
+ printk( "CDB: %02x %02x %02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ cp->Request.CDB[0], cp->Request.CDB[1],
+ cp->Request.CDB[2], cp->Request.CDB[3],
+ cp->Request.CDB[4], cp->Request.CDB[5],
+ cp->Request.CDB[6], cp->Request.CDB[7],
+ cp->Request.CDB[8], cp->Request.CDB[9],
+ cp->Request.CDB[10], cp->Request.CDB[11],
+ cp->Request.CDB[12], cp->Request.CDB[13],
+ cp->Request.CDB[14], cp->Request.CDB[15]),
+ printk("edesc.Addr: 0x%08x/0%08x, Len = %d\n",
+ cp->ErrDesc.Addr.upper, cp->ErrDesc.Addr.lower,
+ cp->ErrDesc.Len);
+ printk("sgs..........Errorinfo:\n");
+ printk("scsistatus:%d\n", cp->err_info->ScsiStatus);
+ printk("senselen:%d\n", cp->err_info->SenseLen);
+ printk("cmd status:%d\n", cp->err_info->CommandStatus);
+ printk("resid cnt:%d\n", cp->err_info->ResidualCnt);
+ printk("offense size:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_size);
+ printk("offense byte:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_num);
+ printk("offense value:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+
+}
+
+#endif
+
+static int
+find_bus_target_lun(int ctlr, int *bus, int *target, int *lun)
+{
+ /* finds an unused bus, target, lun for a new device */
+ /* assumes hba[ctlr]->scsi_ctlr->lock is held */
+ int i, found=0;
+ unsigned char target_taken[CCISS_MAX_SCSI_DEVS_PER_HBA];
+
+ memset(&target_taken[0], 0, CCISS_MAX_SCSI_DEVS_PER_HBA);
+
+ target_taken[SELF_SCSI_ID] = 1;
+ for (i=0;i<ccissscsi[ctlr].ndevices;i++)
+ target_taken[ccissscsi[ctlr].dev[i].target] = 1;
+
+ for (i=0;i<CCISS_MAX_SCSI_DEVS_PER_HBA;i++) {
+ if (!target_taken[i]) {
+ *bus = 0; *target=i; *lun = 0; found=1;
+ break;
+ }
+ }
+ return (!found);
+}
+
+static int
+cciss_scsi_add_entry(int ctlr, int hostno,
+ unsigned char *scsi3addr, int devtype)
+{
+ /* assumes hba[ctlr]->scsi_ctlr->lock is held */
+ int n = ccissscsi[ctlr].ndevices;
+ struct cciss_scsi_dev_t *sd;
+
+ if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
+ printk("cciss%d: Too many devices, "
+ "some will be inaccessible.\n", ctlr);
+ return -1;
+ }
+ sd = &ccissscsi[ctlr].dev[n];
+ if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0)
+ return -1;
+ memcpy(&sd->scsi3addr[0], scsi3addr, 8);
+ sd->devtype = devtype;
+ ccissscsi[ctlr].ndevices++;
+
+ /* initially, (before registering with scsi layer) we don't
+ know our hostno and we don't want to print anything first
+ time anyway (the scsi layer's inquiries will show that info) */
+ if (hostno != -1)
+ printk("cciss%d: %s device c%db%dt%dl%d added.\n",
+ ctlr, DEVICETYPE(sd->devtype), hostno,
+ sd->bus, sd->target, sd->lun);
+ return 0;
+}
+
+static void
+cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
+{
+ /* assumes hba[ctlr]->scsi_ctlr->lock is held */
+ int i;
+ struct cciss_scsi_dev_t sd;
+
+ if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return;
+ sd = ccissscsi[ctlr].dev[entry];
+ for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++)
+ ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
+ ccissscsi[ctlr].ndevices--;
+ printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+ ctlr, DEVICETYPE(sd.devtype), hostno,
+ sd.bus, sd.target, sd.lun);
+}
+
+
+#define SCSI3ADDR_EQ(a,b) ( \
+ (a)[7] == (b)[7] && \
+ (a)[6] == (b)[6] && \
+ (a)[5] == (b)[5] && \
+ (a)[4] == (b)[4] && \
+ (a)[3] == (b)[3] && \
+ (a)[2] == (b)[2] && \
+ (a)[1] == (b)[1] && \
+ (a)[0] == (b)[0])
+
+static int
+adjust_cciss_scsi_table(int ctlr, int hostno,
+ struct cciss_scsi_dev_t sd[], int nsds)
+{
+ /* sd contains scsi3 addresses and devtypes, but
+ bus target and lun are not filled in. This funciton
+ takes what's in sd to be the current and adjusts
+ ccissscsi[] to be in line with what's in sd. */
+
+ int i,j, found, changes=0;
+ struct cciss_scsi_dev_t *csd;
+ unsigned long flags;
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+
+ /* find any devices in ccissscsi[] that are not in
+ sd[] and remove them from ccissscsi[] */
+
+ i = 0;
+ while(i<ccissscsi[ctlr].ndevices) {
+ csd = &ccissscsi[ctlr].dev[i];
+ found=0;
+ for (j=0;j<nsds;j++) {
+ if (SCSI3ADDR_EQ(sd[j].scsi3addr,
+ csd->scsi3addr)) {
+ if (sd[j].devtype == csd->devtype)
+ found=2;
+ else
+ found=1;
+ break;
+ }
+ }
+
+ if (found == 0) { /* device no longer present. */
+ changes++;
+ /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+ ctlr, DEVICETYPE(csd->devtype), hostno,
+ csd->bus, csd->target, csd->lun); */
+ cciss_scsi_remove_entry(ctlr, hostno, i);
+ /* note, i not incremented */
+ }
+ else if (found == 1) { /* device is different kind */
+ changes++;
+ printk("cciss%d: device c%db%dt%dl%d type changed "
+ "(device type now %s).\n",
+ ctlr, hostno, csd->bus, csd->target, csd->lun,
+ DEVICETYPE(csd->devtype));
+ csd->devtype = sd[j].devtype;
+ i++; /* so just move along. */
+ } else /* device is same as it ever was, */
+ i++; /* so just move along. */
+ }
+
+ /* Now, make sure every device listed in sd[] is also
+ listed in ccissscsi[], adding them if they aren't found */
+
+ for (i=0;i<nsds;i++) {
+ found=0;
+ for (j=0;j<ccissscsi[ctlr].ndevices;j++) {
+ csd = &ccissscsi[ctlr].dev[j];
+ if (SCSI3ADDR_EQ(sd[i].scsi3addr,
+ csd->scsi3addr)) {
+ if (sd[i].devtype == csd->devtype)
+ found=2; /* found device */
+ else
+ found=1; /* found a bug. */
+ break;
+ }
+ }
+ if (!found) {
+ changes++;
+ if (cciss_scsi_add_entry(ctlr, hostno,
+ &sd[i].scsi3addr[0], sd[i].devtype) != 0)
+ break;
+ } else if (found == 1) {
+ /* should never happen... */
+ changes++;
+ printk("cciss%d: device unexpectedly changed type\n",
+ ctlr);
+ /* but if it does happen, we just ignore that device */
+ }
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+
+ if (!changes)
+ printk("cciss%d: No device changes detected.\n", ctlr);
+
+ return 0;
+}
+
+static int
+lookup_scsi3addr(int ctlr, int bus, int target, int lun, char *scsi3addr)
+{
+ int i;
+ struct cciss_scsi_dev_t *sd;
+ unsigned long flags;
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+ for (i=0;i<ccissscsi[ctlr].ndevices;i++) {
+ sd = &ccissscsi[ctlr].dev[i];
+ if (sd->bus == bus &&
+ sd->target == target &&
+ sd->lun == lun) {
+ memcpy(scsi3addr, &sd->scsi3addr[0], 8);
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return 0;
+ }
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return -1;
+}
+
+
+static void
+cciss_find_non_disk_devices(int cntl_num)
+{
+ ReportLunData_struct *ld_buff;
+ InquiryData_struct *inq_buff;
+ int return_code;
+ int i;
+ int listlength = 0;
+ int num_luns;
+ unsigned char scsi3addr[8];
+ unsigned long flags;
+ int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
+
+ hba[cntl_num]->scsi_ctlr = (void *)
+ kmalloc(sizeof(struct cciss_scsi_adapter_data_t),
+ GFP_KERNEL);
+ if (hba[cntl_num]->scsi_ctlr == NULL)
+ return;
+
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[cntl_num]->scsi_ctlr)->scsi_host = NULL;
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[cntl_num]->scsi_ctlr)->lock = SPIN_LOCK_UNLOCKED;
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[cntl_num]->scsi_ctlr)->registered = 0;
+
+ if (scsi_cmd_stack_setup(cntl_num) != 0) {
+ printk("Trouble, returned non-zero!\n");
+ return;
+ }
+
+ ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+ if (ld_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return;
+ }
+ memset(ld_buff, 0, sizeof(ReportLunData_struct));
+ inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ return;
+ }
+
+ /* Get the physical luns */
+ return_code = sendcmd(CISS_REPORT_PHYS, cntl_num, ld_buff,
+ reportlunsize, 0, 0, 0, NULL );
+
+ if( return_code == IO_OK) {
+ unsigned char *c = &ld_buff->LUNListLength[0];
+ listlength = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+ }
+ else { /* getting report of physical luns failed */
+ printk(KERN_WARNING "cciss: report physical luns"
+ " command failed\n");
+ listlength = 0;
+ }
+
+ CPQ_TAPE_LOCK(cntl_num, flags);
+ ccissscsi[cntl_num].ndevices = 0;
+ num_luns = listlength / 8; // 8 bytes pre entry
+ /* printk("Found %d LUNs\n", num_luns); */
+
+ if (num_luns > CISS_MAX_PHYS_LUN)
+ {
+ printk(KERN_WARNING
+ "cciss: Maximum physical LUNs (%d) exceeded. "
+ "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN,
+ num_luns - CISS_MAX_PHYS_LUN);
+ num_luns = CISS_MAX_PHYS_LUN;
+ }
+
+ for(i=0; i<num_luns; i++) {
+ /* Execute an inquiry to figure the device type */
+ memset(inq_buff, 0, sizeof(InquiryData_struct));
+ memcpy(scsi3addr, ld_buff->LUN[i], 8); /* ugly... */
+ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+ sizeof(InquiryData_struct), 2, 0 ,0, scsi3addr );
+ if (return_code == IO_OK) {
+ if(inq_buff->data_byte[8] == 0xFF)
+ {
+ printk(KERN_WARNING "cciss: inquiry failed\n");
+ } else {
+ int devtype;
+
+ /* printk("Inquiry...\n");
+ print_bytes((unsigned char *) inq_buff, 36, 1, 1); */
+ devtype = (inq_buff->data_byte[0] & 0x1f);
+
+ switch (devtype)
+ {
+ case 0x01: /* sequential access, (tape) */
+ case 0x08: /* medium changer */
+ /* this is the only kind of dev */
+ /* we want to expose here. */
+ if (cciss_scsi_add_entry(cntl_num, -1,
+ (unsigned char *) ld_buff->LUN[i],
+ devtype) != 0)
+ i=num_luns; // leave loop
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+ else printk("cciss: inquiry failed.\n");
+ }
+#if 0
+ for (i=0;i<ccissscsi[cntl_num].ndevices;i++)
+ printk("Tape device presented at c%db%dt%dl%d\n",
+ cntl_num, // <-- this is wrong
+ ccissscsi[cntl_num].dev[i].bus,
+ ccissscsi[cntl_num].dev[i].target,
+ ccissscsi[cntl_num].dev[i].lun);
+#endif
+ CPQ_TAPE_UNLOCK(cntl_num, flags);
+ kfree(ld_buff);
+ kfree(inq_buff);
+ return;
+}
+
+static void
+complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
+{
+ Scsi_Cmnd *cmd;
+ ctlr_info_t *ctlr;
+ u64bit addr64;
+ ErrorInfo_struct *ei;
+
+ ei = cp->err_info;
+
+ /* First, see if it was a message rather than a command */
+ if (cp->Request.Type.Type == TYPE_MSG) {
+ cp->cmd_type = CMD_MSG_DONE;
+ return;
+ }
+
+ cmd = (Scsi_Cmnd *) cp->scsi_cmd;
+ ctlr = hba[cp->ctlr];
+
+ /* undo the DMA mappings */
+
+ if (cmd->use_sg) {
+ pci_unmap_sg(ctlr->pdev,
+ cmd->buffer, cmd->use_sg,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+ else if (cmd->request_bufflen) {
+ addr64.val32.lower = cp->SG[0].Addr.lower;
+ addr64.val32.upper = cp->SG[0].Addr.upper;
+ pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+
+ cmd->result = (DID_OK << 16); /* host byte */
+ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+ /* cmd->result |= (GOOD < 1); */ /* status byte */
+
+ cmd->result |= (ei->ScsiStatus);
+ /* printk("Scsistatus is 0x%02x\n", ei->ScsiStatus); */
+
+ /* copy the sense data whether we need to or not. */
+
+ memcpy(cmd->sense_buffer, ei->SenseInfo,
+ ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
+ SCSI_SENSE_BUFFERSIZE :
+ ei->SenseLen);
+ cmd->resid = ei->ResidualCnt;
+
+ if(ei->CommandStatus != 0)
+ { /* an error has occurred */
+ switch(ei->CommandStatus)
+ {
+ case CMD_TARGET_STATUS:
+ /* Pass it up to the upper layers... */
+ if( ei->ScsiStatus)
+ {
+#if 0
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ cp,
+ ei->ScsiStatus);
+#endif
+ cmd->result |= (ei->ScsiStatus < 1);
+ }
+ else { /* scsi status is zero??? How??? */
+
+ /* Ordinarily, this case should never happen, but there is a bug
+ in some released firmware revisions that allows it to happen
+ if, for example, a 4100 backplane loses power and the tape
+ drive is in it. We assume that it's a fatal error of some
+ kind because we can't show that it wasn't. We will make it
+ look like selection timeout since that is the most common
+ reason for this to occur, and it's severe enough. */
+
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
+ case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+ break;
+ case CMD_DATA_OVERRUN:
+ printk(KERN_WARNING "cciss: cp %p has"
+ " completed with data overrun "
+ "reported\n", cp);
+ break;
+ case CMD_INVALID: {
+ /* print_bytes(cp, sizeof(*cp), 1, 0);
+ print_cmd(cp); */
+ /* We get CMD_INVALID if you address a non-existent tape drive instead
+ of a selection timeout (no response). You will see this if you yank
+ out a tape drive, then try to access it. This is kind of a shame
+ because it means that any other CMD_INVALID (e.g. driver bug) will
+ get interpreted as a missing target. */
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cp %p has "
+ "protocol error \n", cp);
+ break;
+ case CMD_HARDWARE_ERR:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p had "
+ " hardware error\n", cp);
+ break;
+ case CMD_CONNECTION_LOST:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p had "
+ "connection lost\n", cp);
+ break;
+ case CMD_ABORTED:
+ cmd->result = DID_ABORT << 16;
+ printk(KERN_WARNING "cciss: cp %p was "
+ "aborted\n", cp);
+ break;
+ case CMD_ABORT_FAILED:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p reports "
+ "abort failed\n", cp);
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ cmd->result = DID_ABORT << 16;
+ printk(KERN_WARNING "cciss: cp %p aborted "
+ "do to an unsolicited abort\n", cp);
+ break;
+ case CMD_TIMEOUT:
+ cmd->result = DID_TIME_OUT << 16;
+ printk(KERN_WARNING "cciss: cp %p timedout\n",
+ cp);
+ break;
+ default:
+ cmd->result = DID_ERROR << 16;
+ printk(KERN_WARNING "cciss: cp %p returned "
+ "unknown status %x\n", cp,
+ ei->CommandStatus);
+ }
+ }
+ // printk("c:%p:c%db%dt%dl%d ", cmd, ctlr->ctlr, cmd->channel,
+ // cmd->target, cmd->lun);
+ cmd->scsi_done(cmd);
+ scsi_cmd_free(ctlr, cp);
+}
+
+/* cciss_scsi_detect is called from the scsi mid layer.
+ The scsi mid layer (scsi_register_host) is
+ called from cciss.c:cciss_init_one(). */
+
+int __init
+cciss_scsi_detect(Scsi_Host_Template *tpnt)
+{
+ int i;
+ struct Scsi_Host *sh;
+
+ /* Tell the kernel we want to be a SCSI driver... */
+ sh = scsi_register(tpnt, sizeof(struct ctlr_info *));
+ if (sh == NULL) return 0;
+
+ sh->io_port = 0; // good enough? FIXME,
+ sh->n_io_port = 0; // I don't think we use these two...
+
+ sh->this_id = SELF_SCSI_ID;
+
+ /* This is a bit kludgey, using the adapter name to figure out */
+ /* which scsi host template we've got, won't scale beyond 9 ctlrs. */
+ i = tpnt->name[5] - '0';
+
+# if MAX_CTLR > 9
+# error "cciss_scsi.c: MAX_CTLR > 9, code maintenance needed."
+# endif
+
+ if (i<0 || i>=MAX_CTLR || hba[i] == NULL) {
+ /* we didn't find ourself... we shouldn't get here. */
+ printk("cciss_scsi_detect: could not find ourself in hba[]\n");
+ return 0;
+ }
+
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[i]->scsi_ctlr)->scsi_host = (void *) sh;
+ sh->hostdata[0] = (unsigned long) hba[i];
+ sh->irq = hba[i]->intr;
+ sh->unique_id = sh->irq;
+ scsi_set_pci_device(sh, hba[i]->pdev);
+
+ return 1; /* Say we have 1 scsi adapter, this will be */
+ /* called multiple times, once for each adapter */
+ /* from cciss.c:cciss_init_one(). We do it this */
+ /* way for PCI-hot plug reasons. (we don't know how */
+ /* many adapters we have total, so we say we have */
+ /* 1, each of a unique type.) */
+}
+
+static void __exit cleanup_cciss_module(void);
+int
+cciss_scsi_release(struct Scsi_Host *sh)
+{
+ return 0;
+}
+
+static void
+cciss_unmap_one(struct pci_dev *pdev,
+ CommandList_struct *cp,
+ size_t buflen,
+ int data_direction)
+{
+ u64bit addr64;
+
+ addr64.val32.lower = cp->SG[0].Addr.lower;
+ addr64.val32.upper = cp->SG[0].Addr.upper;
+ pci_unmap_single(pdev, (dma_addr_t) addr64.val, buflen, data_direction);
+}
+
+static void
+cciss_map_one(struct pci_dev *pdev,
+ CommandList_struct *cp,
+ unsigned char *buf,
+ size_t buflen,
+ int data_direction)
+{
+ __u64 addr64;
+
+ addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction);
+ cp->SG[0].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Len = buflen;
+ cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */
+}
+
+static int
+cciss_scsi_do_simple_cmd(ctlr_info_t *c,
+ CommandList_struct *cp,
+ unsigned char *scsi3addr,
+ unsigned char *cdb,
+ unsigned char cdblen,
+ unsigned char *buf, int bufsize,
+ int direction)
+{
+ unsigned long flags;
+
+ cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl
+ cp->scsi_cmd = NULL;
+ cp->Header.ReplyQueue = 0; // unused in simple mode
+ memcpy(&cp->Header.LUN, scsi3addr, sizeof(cp->Header.LUN));
+ cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag
+ // Fill in the request block...
+
+ /* printk("Using scsi3addr 0x%02x%0x2%0x2%0x2%0x2%0x2%0x2%0x2\n",
+ scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3],
+ scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); */
+
+ memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
+ memcpy(cp->Request.CDB, cdb, cdblen);
+ cp->Request.Timeout = 1000; // guarantee completion.
+ cp->Request.CDBLen = cdblen;
+ cp->Request.Type.Type = TYPE_CMD;
+ cp->Request.Type.Attribute = ATTR_SIMPLE;
+ cp->Request.Type.Direction = direction;
+
+ /* Fill in the SG list and do dma mapping */
+ cciss_map_one(c->pdev, cp,
+ (unsigned char *) buf, bufsize,
+ scsi_to_pci_dma_dir(SCSI_DATA_READ));
+
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ addQ(&c->reqQ, cp);
+ c->Qdepth++;
+ start_io(c);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+
+ /* Wait for the request to complete */
+ while(cp->cmd_type != CMD_IOCTL_DONE)
+ schedule_timeout(1);
+
+ /* undo the dma mapping */
+ cciss_unmap_one(c->pdev, cp, bufsize,
+ scsi_to_pci_dma_dir(SCSI_DATA_READ));
+
+ return(0);
+}
+
+static void
+cciss_scsi_interpret_error(CommandList_struct *cp)
+{
+ ErrorInfo_struct *ei;
+
+ ei = cp->err_info;
+ switch(ei->CommandStatus)
+ {
+ case CMD_TARGET_STATUS:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "completed with errors\n", cp);
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ cp,
+ ei->ScsiStatus);
+ if (ei->ScsiStatus == 0)
+ printk(KERN_WARNING
+ "cciss:SCSI status is abnormally zero. "
+ "(probably indicates selection timeout "
+ "reported incorrectly due to a known "
+ "firmware bug, circa July, 2001.)\n");
+ break;
+ case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+ printk("UNDERRUN\n");
+ break;
+ case CMD_DATA_OVERRUN:
+ printk(KERN_WARNING "cciss: cp %p has"
+ " completed with data overrun "
+ "reported\n", cp);
+ break;
+ case CMD_INVALID: {
+ /* controller unfortunately reports SCSI passthru's */
+ /* to non-existent targets as invalid commands. */
+ printk(KERN_WARNING "cciss: cp %p is "
+ "reported invalid (probably means "
+ "target device no longer present)\n",
+ cp);
+ /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
+ print_cmd(cp); */
+ }
+ break;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cp %p has "
+ "protocol error \n", cp);
+ break;
+ case CMD_HARDWARE_ERR:
+ /* cmd->result = DID_ERROR << 16; */
+ printk(KERN_WARNING "cciss: cp %p had "
+ " hardware error\n", cp);
+ break;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cp %p had "
+ "connection lost\n", cp);
+ break;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cp %p was "
+ "aborted\n", cp);
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cp %p reports "
+ "abort failed\n", cp);
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING "cciss: cp %p aborted "
+ "do to an unsolicited abort\n", cp);
+ break;
+ case CMD_TIMEOUT:
+ printk(KERN_WARNING "cciss: cp %p timedout\n",
+ cp);
+ break;
+ default:
+ printk(KERN_WARNING "cciss: cp %p returned "
+ "unknown status %x\n", cp,
+ ei->CommandStatus);
+ }
+}
+
+static int
+cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
+ InquiryData_struct *buf)
+{
+ int rc;
+ CommandList_struct *cp;
+ char cdb[6];
+ ErrorInfo_struct *ei;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ cp = scsi_cmd_alloc(c);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ ei = cp->err_info;
+
+ if (cp == NULL) { /* trouble... */
+ printk("cmd_alloc returned NULL!\n");
+ return -1;
+ }
+
+ cdb[0] = CISS_INQUIRY;
+ cdb[1] = 0;
+ cdb[2] = 0;
+ cdb[3] = 0;
+ cdb[4] = sizeof(*buf) & 0xff;
+ cdb[5] = 0;
+ rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb,
+ 6, (unsigned char *) buf,
+ sizeof(*buf), XFER_READ);
+
+ if (rc != 0) return rc; /* something went wrong */
+
+ if (ei->CommandStatus != 0 &&
+ ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ cciss_scsi_interpret_error(cp);
+ rc = -1;
+ }
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ scsi_cmd_free(c, cp);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ return rc;
+}
+
+static int
+cciss_scsi_do_report_phys_luns(ctlr_info_t *c,
+ ReportLunData_struct *buf, int bufsize)
+{
+ int rc;
+ CommandList_struct *cp;
+ unsigned char cdb[12];
+ unsigned char scsi3addr[8];
+ ErrorInfo_struct *ei;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ cp = scsi_cmd_alloc(c);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ if (cp == NULL) { /* trouble... */
+ printk("cmd_alloc returned NULL!\n");
+ return -1;
+ }
+
+ memset(&scsi3addr[0], 0, 8); /* address the controller */
+ cdb[0] = CISS_REPORT_PHYS;
+ cdb[1] = 0;
+ cdb[2] = 0;
+ cdb[3] = 0;
+ cdb[4] = 0;
+ cdb[5] = 0;
+ cdb[6] = (sizeof(*buf) >> 24) & 0xFF; //MSB
+ cdb[7] = (sizeof(*buf) >> 16) & 0xFF;
+ cdb[8] = (sizeof(*buf) >> 8) & 0xFF;
+ cdb[9] = sizeof(*buf) & 0xFF;
+ cdb[10] = 0;
+ cdb[11] = 0;
+
+ rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr,
+ cdb, 12,
+ (unsigned char *) buf,
+ bufsize, XFER_READ);
+
+ if (rc != 0) return rc; /* something went wrong */
+
+ ei = cp->err_info;
+ if (ei->CommandStatus != 0 &&
+ ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ cciss_scsi_interpret_error(cp);
+ rc = -1;
+ }
+ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+ scsi_cmd_free(c, cp);
+ spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+ return rc;
+}
+
+static void
+cciss_update_non_disk_devices(int cntl_num, int hostno)
+{
+ /* the idea here is we could get notified from /proc
+ that some devices have changed, so we do a report
+ physical luns cmd, and adjust our list of devices
+ accordingly. (We can't rely on the scsi-mid layer just
+ doing inquiries, because the "busses" that the scsi
+ mid-layer probes are totally fabricated by this driver,
+ so new devices wouldn't show up.
+
+ the scsi3addr's of devices won't change so long as the
+ adapter is not reset. That means we can rescan and
+ tell which devices we already know about, vs. new
+ devices, vs. disappearing devices.
+
+ Also, if you yank out a tape drive, then put in a disk
+ in it's place, (say, a configured volume from another
+ array controller for instance) _don't_ poke this driver
+ (so it thinks it's still a tape, but _do_ poke the scsi
+ mid layer, so it does an inquiry... the scsi mid layer
+ will see the physical disk. This would be bad. Need to
+ think about how to prevent that. One idea would be to
+ snoop all scsi responses and if an inquiry repsonse comes
+ back that reports a disk, chuck it an return selection
+ timeout instead and adjust our table... Not sure i like
+ that though.
+
+ */
+
+ ReportLunData_struct *ld_buff;
+ InquiryData_struct *inq_buff;
+ unsigned char scsi3addr[8];
+ ctlr_info_t *c;
+ __u32 num_luns=0;
+ unsigned char *ch;
+ /* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */
+ struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
+ int ncurrent=0;
+ int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
+ int i;
+
+ c = (ctlr_info_t *) hba[cntl_num];
+ ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+ if (ld_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return;
+ }
+ memset(ld_buff, 0, reportlunsize);
+ inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ return;
+ }
+
+ if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {
+ ch = &ld_buff->LUNListLength[0];
+ num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;
+ if (num_luns > CISS_MAX_PHYS_LUN) {
+ printk(KERN_WARNING
+ "cciss: Maximum physical LUNs (%d) exceeded. "
+ "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN,
+ num_luns - CISS_MAX_PHYS_LUN);
+ num_luns = CISS_MAX_PHYS_LUN;
+ }
+ }
+ else {
+ printk(KERN_ERR "cciss: Report physical LUNs failed.\n");
+ return;
+ }
+
+
+ /* adjust our table of devices */
+ for(i=0; i<num_luns; i++)
+ {
+ int devtype;
+
+ /* for each physical lun, do an inquiry */
+ memset(inq_buff, 0, sizeof(InquiryData_struct));
+ memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
+
+ if (cciss_scsi_do_inquiry(hba[cntl_num],
+ scsi3addr, inq_buff) != 0)
+ {
+ /* Inquiry failed (msg printed already) */
+ devtype = 0; /* so we will skip this device. */
+ } else /* what kind of device is this? */
+ devtype = (inq_buff->data_byte[0] & 0x1f);
+
+ switch (devtype)
+ {
+ case 0x01: /* sequential access, (tape) */
+ case 0x08: /* medium changer */
+ memcpy(¤tsd[ncurrent].scsi3addr[0],
+ &scsi3addr[0], 8);
+ currentsd[ncurrent].devtype = devtype;
+ currentsd[ncurrent].bus = -1;
+ currentsd[ncurrent].target = -1;
+ currentsd[ncurrent].lun = -1;
+ ncurrent++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent);
+
+ kfree(inq_buff);
+ kfree(ld_buff);
+ return;
+}
+
+static int
+is_keyword(char *ptr, int len, char *verb) // Thanks to ncr53c8xx.c
+{
+ int verb_len = strlen(verb);
+ if (len >= verb_len && !memcmp(verb,ptr,verb_len))
+ return verb_len;
+ else
+ return 0;
+}
+
+static int
+cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length)
+{
+ int arg_len;
+
+ if ((arg_len = is_keyword(buffer, length, "rescan")) != 0)
+ cciss_update_non_disk_devices(ctlr, hostno);
+ else
+ return -EINVAL;
+ return length;
+}
+
+/* It's a pity that we need this, but, we do... */
+extern struct Scsi_Host *scsi_hostlist; /* from ../scsi/hosts.c */
+
+int
+cciss_scsi_proc_info(char *buffer, /* data buffer */
+ char **start, /* where data in buffer starts */
+ off_t offset, /* offset from start of imaginary file */
+ int length, /* length of data in buffer */
+ int hostnum, /* which host adapter (always zero for me) */
+ int func) /* 0 == read, 1 == write */
+{
+
+ int buflen, datalen;
+ struct Scsi_Host *sh;
+ int found;
+ ctlr_info_t *ci;
+ int cntl_num;
+
+ /* Lets see if we can find our Scsi_Host...
+ this might be kind of "bad", searching scis_hostlist this way
+ but how else can we find the scsi host? I think I've seen
+ this coded both ways, (circular list and null terminated list)
+ I coded it to work either way, since I wasn't sure. */
+
+ sh = scsi_hostlist;
+ found=0;
+ do {
+ if (sh == NULL) break;
+ if (sh->host_no == hostnum) {
+ found++;
+ break;
+ }
+ sh = sh->next;
+ } while (sh != scsi_hostlist && sh != NULL);
+
+ if (sh == NULL || found == 0) /* This really shouldn't ever happen. */
+ return -EINVAL;
+
+ ci = (ctlr_info_t *) sh->hostdata[0];
+ if (ci == NULL) /* This really shouldn't ever happen. */
+ return -EINVAL;
+
+ cntl_num = ci->ctlr; /* Get our index into the hba[] array */
+
+ if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */
+ buflen = sprintf(buffer, "hostnum=%d\n", hostnum);
+
+ datalen = buflen - offset;
+ if (datalen < 0) { /* they're reading past EOF. */
+ datalen = 0;
+ *start = buffer+buflen;
+ } else
+ *start = buffer + offset;
+ return(datalen);
+ } else /* User is writing to /proc/scsi/cciss*?/?* ... */
+ return cciss_scsi_user_command(cntl_num, hostnum,
+ buffer, length);
+}
+
+/* this is via the generic proc support */
+const char *
+cciss_scsi_info(struct Scsi_Host *sa)
+{
+ static char buf[300];
+ ctlr_info_t *ci;
+
+ /* probably need to work on putting a bit more info in here... */
+ /* this is output via the /proc filesystem. */
+
+ ci = (ctlr_info_t *) sa->hostdata[0];
+
+ sprintf(buf, "%s %c%c%c%c\n",
+ ci->product_name,
+ ci->firm_ver[0],
+ ci->firm_ver[1],
+ ci->firm_ver[2],
+ ci->firm_ver[3]);
+
+ return buf;
+}
+
+
+/* cciss_scatter_gather takes a Scsi_Cmnd, (cmd), and does the pci
+ dma mapping and fills in the scatter gather entries of the
+ cciss command, cp. */
+
+static void
+cciss_scatter_gather(struct pci_dev *pdev,
+ CommandList_struct *cp,
+ Scsi_Cmnd *cmd)
+{
+ unsigned int use_sg, nsegs=0, len;
+ struct scatterlist *scatter = (struct scatterlist *) cmd->buffer;
+ __u64 addr64;
+
+ /* is it just one virtual address? */
+ if (!cmd->use_sg) {
+ if (cmd->request_bufflen) { /* anything to xfer? */
+
+ addr64 = (__u64) pci_map_single(pdev,
+ cmd->request_buffer,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+
+ cp->SG[0].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Len = cmd->request_bufflen;
+ nsegs=1;
+ }
+ } /* else, must be a list of virtual addresses.... */
+ else if (cmd->use_sg <= MAXSGENTRIES) { /* not too many addrs? */
+
+ use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+
+ for (nsegs=0; nsegs < use_sg; nsegs++) {
+ addr64 = (__u64) sg_dma_address(&scatter[nsegs]);
+ len = sg_dma_len(&scatter[nsegs]);
+ cp->SG[nsegs].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[nsegs].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[nsegs].Len = len;
+ cp->SG[nsegs].Ext = 0; // we are not chaining
+ }
+ } else BUG();
+
+ cp->Header.SGList = (__u8) nsegs; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */
+ return;
+}
+
+
+int
+cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+ ctlr_info_t **c;
+ int ctlr, rc;
+ unsigned char scsi3addr[8];
+ CommandList_struct *cp;
+ unsigned long flags;
+
+ // Get the ptr to our adapter structure (hba[i]) out of cmd->host.
+ // We violate cmd->host privacy here. (Is there another way?)
+ c = (ctlr_info_t **) &cmd->host->hostdata[0];
+ ctlr = (*c)->ctlr;
+
+ rc = lookup_scsi3addr(ctlr, cmd->channel, cmd->target, cmd->lun,
+ scsi3addr);
+ if (rc != 0) {
+ /* the scsi nexus does not match any that we presented... */
+ /* pretend to mid layer that we got selection timeout */
+ cmd->result = DID_NO_CONNECT << 16;
+ done(cmd);
+ /* we might want to think about registering controller itself
+ as a processor device on the bus so sg binds to it. */
+ return 0;
+ }
+
+ /* printk("cciss_queue_command, p=%p, cmd=0x%02x, c%db%dt%dl%d\n",
+ cmd, cmd->cmnd[0], ctlr, cmd->channel, cmd->target, cmd->lun);*/
+ // printk("q:%p:c%db%dt%dl%d ", cmd, ctlr, cmd->channel,
+ // cmd->target, cmd->lun);
+
+ /* Ok, we have a reasonable scsi nexus, so send the cmd down, and
+ see what the device thinks of it. */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ cp = scsi_cmd_alloc(*c);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (cp == NULL) { /* trouble... */
+ printk("scsi_cmd_alloc returned NULL!\n");
+ /* FIXME: next 3 lines are -> BAD! <- */
+ cmd->result = DID_NO_CONNECT << 16;
+ done(cmd);
+ return 0;
+ }
+
+ // Fill in the command list header
+
+ cmd->scsi_done = done; // save this for use by completion code
+
+ // save cp in case we have to abort it
+ cmd->host_scribble = (unsigned char *) cp;
+
+ cp->cmd_type = CMD_SCSI;
+ cp->scsi_cmd = cmd;
+ cp->Header.ReplyQueue = 0; // unused in simple mode
+ memcpy(&cp->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+ cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag
+
+ // Fill in the request block...
+
+ cp->Request.Timeout = 1000; // guarantee completion
+ memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
+ if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
+ cp->Request.CDBLen = cmd->cmd_len;
+ memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len);
+ cp->Request.Type.Type = TYPE_CMD;
+ cp->Request.Type.Attribute = ATTR_SIMPLE;
+ switch(cmd->sc_data_direction)
+ {
+ case SCSI_DATA_WRITE: cp->Request.Type.Direction = XFER_WRITE; break;
+ case SCSI_DATA_READ: cp->Request.Type.Direction = XFER_READ; break;
+ case SCSI_DATA_NONE: cp->Request.Type.Direction = XFER_NONE; break;
+
+ case SCSI_DATA_UNKNOWN:
+ // This can happen if a buggy application does a scsi passthru
+ // and sets both inlen and outlen to non-zero. ( see
+ // ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
+
+ cp->Request.Type.Direction = XFER_RSVD;
+ // This is technically wrong, and cciss controllers should
+ // reject it with CMD_INVALID, which is the most correct
+ // response, but non-fibre backends appear to let it
+ // slide by, and give the same results as if this field
+ // were set correctly. Either way is acceptable for
+ // our purposes here.
+
+ break;
+
+ default:
+ printk("cciss: unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+
+ cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list
+
+ /* Put the request on the tail of the request queue */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&(*c)->reqQ, cp);
+ (*c)->Qdepth++;
+ start_io(*c);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+ /* the cmd'll come back via intr handler in complete_scsi_command() */
+ return 0;
+}
+
+static void
+init_driver_template(int ctlr)
+{
+ memset(&driver_template[ctlr], 0, sizeof(driver_template[ctlr]));
+ driver_template[ctlr].name = ccissscsi[ctlr].name;
+ driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
+ driver_template[ctlr].detect = cciss_scsi_detect;
+ driver_template[ctlr].release = cciss_scsi_release;
+ driver_template[ctlr].proc_info = cciss_scsi_proc_info;
+ driver_template[ctlr].queuecommand = cciss_scsi_queue_command;
+ driver_template[ctlr].eh_abort_handler = NULL;
+ driver_template[ctlr].eh_device_reset_handler = NULL;
+ driver_template[ctlr].bios_param = scsicam_bios_param;
+ driver_template[ctlr].can_queue = SCSI_CCISS_CAN_QUEUE;
+ driver_template[ctlr].this_id = 7;
+ driver_template[ctlr].sg_tablesize = MAXSGENTRIES;
+ driver_template[ctlr].cmd_per_lun = 1;
+ driver_template[ctlr].use_clustering = DISABLE_CLUSTERING;
+ driver_template[ctlr].module = THIS_MODULE;
+
+ /* set scsi_host to NULL so our detect routine will
+ find us on register */
+
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->scsi_host = NULL;
+
+}
+
+static void
+cciss_unregister_scsi(int ctlr)
+{
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ unsigned long flags;
+
+ /* we are being forcibly unloaded, and may not refuse. */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+
+ /* if we weren't ever actually registered, don't unregister */
+ if (((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->registered) {
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ scsi_unregister_host(&driver_template[ctlr]);
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ }
+ init_driver_template(ctlr);
+ scsi_cmd_stack_free(ctlr);
+ kfree(hba[ctlr]->scsi_ctlr);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+}
+
+static int
+cciss_register_scsi(int ctlr, int this_is_init_time)
+{
+ unsigned long flags;
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+ driver_template[ctlr].name = ccissscsi[ctlr].name;
+ driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
+ driver_template[ctlr].module = THIS_MODULE;;
+
+ /* Since this is really a block driver, the SCSI core may not be
+ initialized yet, in which case, calling scsi_register_host
+ would hang. instead, we will do it later, via /proc filesystem
+ and rc scripts, when we know SCSI core is good to go. */
+
+ if (this_is_init_time) {
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return 0;
+ }
+
+ /* Only register if SCSI devices are detected. */
+ if (ccissscsi[ctlr].ndevices != 0) {
+ ((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->registered = 1;
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ return scsi_register_host(&driver_template[ctlr]);
+ }
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ printk(KERN_INFO
+ "cciss%d: No appropriate SCSI device detected, "
+ "SCSI subsystem not engaged.\n", ctlr);
+ return 0;
+}
+
+static int
+cciss_engage_scsi(int ctlr)
+{
+ struct cciss_scsi_adapter_data_t *sa;
+ struct cciss_scsi_cmd_stack_t *stk;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ stk = &sa->cmd_stack;
+
+ if (((struct cciss_scsi_adapter_data_t *)
+ hba[ctlr]->scsi_ctlr)->registered) {
+ printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ return ENXIO;
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ cciss_update_non_disk_devices(ctlr, -1);
+ cciss_register_scsi(ctlr, 0);
+ return 0;
+}
+
+static void
+cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
+{
+ int size;
+ unsigned int flags;
+
+ *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
+
+ CPQ_TAPE_LOCK(ctlr, flags);
+ size = sprintf(buffer + *len,
+ " Sequential access devices: %d\n\n",
+ ccissscsi[ctlr].ndevices);
+ CPQ_TAPE_UNLOCK(ctlr, flags);
+ *pos += size; *len += size;
+}
+
+#else /* no CONFIG_CISS_SCSI_TAPE */
+
+/* If no tape support, then these become defined out of existence */
+
+#define cciss_find_non_disk_devices(cntl_num)
+#define cciss_unregister_scsi(ctlr)
+#define cciss_register_scsi(ctlr, this_is_init_time)
+#define cciss_proc_tape_report(ctlr, buffer, pos, len)
+
+#endif /* CONFIG_CISS_SCSI_TAPE */
--- /dev/null
+/*
+ * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
+ * Copyright 2001 Compaq Computer Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ */
+#ifdef CONFIG_CISS_SCSI_TAPE
+#ifndef _CCISS_SCSI_H_
+#define _CCISS_SCSI_H_
+
+#include <scsi/scsicam.h> /* possibly irrelevant, since we don't show disks */
+
+ // the scsi id of the adapter...
+#define SELF_SCSI_ID 15
+ // 15 is somewhat arbitrary, since the scsi-2 bus
+ // that's presented by the driver to the OS is
+ // fabricated. The "real" scsi-3 bus the
+ // hardware presents is fabricated too.
+ // The actual, honest-to-goodness physical
+ // bus that the devices are attached to is not
+ // addressible natively, and may in fact turn
+ // out to be not scsi at all.
+
+#define SCSI_CCISS_CAN_QUEUE 2
+
+/* this notation works fine for static initializations (as is the usual
+ case for linux scsi drivers), but not so well for dynamic settings,
+ so, if you change this, you also have to change cciss_unregister_scsi()
+ in cciss_scsi.c */
+#define CCISS_SCSI { \
+ name: "", \
+ detect: cciss_scsi_detect, \
+ release: cciss_scsi_release, \
+ proc_info: cciss_scsi_proc_info, \
+ queuecommand: cciss_scsi_queue_command, \
+ bios_param: scsicam_bios_param, \
+ can_queue: SCSI_CCISS_CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: MAXSGENTRIES, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING,\
+}
+
+/*
+ info: cciss_scsi_info, \
+
+Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
+Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
+
+If the upper scsi layer tries to track how many commands we have
+outstanding, it will be operating under the misapprehension that it is
+the only one sending us requests. We also have the block interface,
+which is where most requests must surely come from, so the upper layer's
+notion of how many requests we have outstanding will be wrong most or
+all of the time.
+
+Note, the normal SCSI mid-layer error handling doesn't work well
+for this driver because 1) it takes the io_request_lock before
+calling error handlers and uses a local variable to store flags,
+so the io_request_lock cannot be released and interrupts enabled
+inside the error handlers, and, the error handlers cannot poll
+for command completion because they might get commands from the
+block half of the driver completing, and not know what to do
+with them. That's what we get for making a hybrid scsi/block
+driver, I suppose.
+
+*/
+
+struct cciss_scsi_dev_t {
+ int devtype;
+ int bus, target, lun; /* as presented to the OS */
+ unsigned char scsi3addr[8]; /* as presented to the HW */
+};
+
+struct cciss_scsi_hba_t {
+ char *name;
+ int ndevices;
+#define CCISS_MAX_SCSI_DEVS_PER_HBA 16
+ struct cciss_scsi_dev_t dev[CCISS_MAX_SCSI_DEVS_PER_HBA];
+};
+
+#endif /* _CCISS_SCSI_H_ */
+#endif /* CONFIG_CISS_SCSI_TAPE */
#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
static int nr_ctlr;
static ctlr_info_t *hba[MAX_CTLR];
+static devfs_handle_t de_arr[MAX_CTLR][NWD];
static int eisa[8];
del_gendisk(&ida_gendisk[i]);
}
+ devfs_unregister(devfs_find_handle(NULL, "ida", 0, 0, 0, 0));
remove_proc_entry("cpqarray", proc_root_driver);
kfree(ida);
kfree(ida_sizes);
ida_gendisk[i].part = ida + (i*256);
ida_gendisk[i].sizes = ida_sizes + (i*256);
ida_gendisk[i].nr_real = 0;
+ ida_gendisk[i].de_arr = de_arr[i];
+ ida_gendisk[i].fops = &ida_fops;
/* Get on the disk list */
add_gendisk(&ida_gendisk[i]);
return;
}
+ if (!de_arr[ctlr][log_unit]) {
+ char txt[16];
+
+ sprintf(txt, "ida/c%dd%d", ctlr,
+ log_unit);
+ de_arr[ctlr][log_unit] =
+ devfs_mk_dir(NULL, txt, NULL);
+ }
info_p->phys_drives =
sense_config_buf->ctlr_phys_drv;
info_p->drv_assign_map
next_rq = list_entry(next, struct request, queuelist);
- BUG_ON(next_rq->flags & REQ_STARTED);
-
/*
* not a sector based request
*/
*/
if (q->last_merge) {
struct request *__rq = list_entry_rq(q->last_merge);
- BUG_ON(__rq->flags & REQ_STARTED);
- if ((ret = elv_try_merge(__rq, bio)))
+ if (!rq_mergeable(__rq))
+ q->last_merge = NULL;
+ else if ((ret = elv_try_merge(__rq, bio)))
*req = __rq;
}
elevator_t *e = &q->elevator;
int lat = 0, *latency = e->elevator_data;
+ /*
+ * it's a bug to let this rq preempt an already started request
+ */
+ if (insert_here->next != &q->queue_head)
+ BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
+
if (!(rq->flags & REQ_BARRIER))
lat = latency[rq_data_dir(rq)];
q->plug_tq.data = q;
q->queue_flags = (1 << QUEUE_FLAG_CLUSTER);
q->queue_lock = lock;
- q->last_merge = NULL;
blk_queue_segment_boundary(q, 0xffffffff);
{
drive_stat_acct(req, req->nr_sectors, 1);
- /*
- * it's a bug to let this rq preempt an already started request
- */
- if (insert_here->next != &q->queue_head)
- BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
-
/*
* elevator indicated where it wants this request to be
* inserted at elevator_merge time
switch (el_ret) {
case ELEVATOR_BACK_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!q->back_merge_fn(q, req, bio))
+ if (!q->back_merge_fn(q, req, bio)) {
+ insert_here = &req->queuelist;
break;
+ }
elv_merge_cleanup(q, req, nr_sectors);
case ELEVATOR_FRONT_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!q->front_merge_fn(q, req, bio))
+ if (!q->front_merge_fn(q, req, bio)) {
+ insert_here = req->queuelist.prev;
break;
+ }
elv_merge_cleanup(q, req, nr_sectors);
if (result <= 0)
HARDFAIL("Recv control failed.");
memcpy(&xreq, reply.handle, sizeof(xreq));
- req = blkdev_entry_prev_request(&lo->queue_head);
+ req = blkdev_entry_to_request(lo->queue_head.prev);
if (xreq != req)
FAIL("Unexpected handle received.\n");
goto out;
}
#ifdef PARANOIA
- if (req != blkdev_entry_prev_request(&lo->queue_head)) {
+ if (req != blkdev_entry_to_request(lo->queue_head.prev)) {
printk(KERN_ALERT "NBD: I have problem...\n");
}
if (lo != &nbd_dev[minor(req->rq_dev)]) {
#endif
while (!list_empty(&lo->queue_head)) {
- req = blkdev_entry_prev_request(&lo->queue_head);
+ req = blkdev_entry_to_request(lo->queue_head.prev);
#ifdef PARANOIA
if (!req) {
printk( KERN_ALERT "NBD: panic, panic, panic\n" );
printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
#endif
#if RTC_IRQ
+ if (rtc_has_irq == 0)
+ goto no_irq2;
+
init_timer(&rtc_irq_timer);
rtc_irq_timer.function = rtc_dropped_irq;
spin_lock_irq(&rtc_lock);
CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
spin_unlock_irq(&rtc_lock);
rtc_freq = 1024;
+no_irq2:
#endif
printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
int err = 0;
struct block_device *bdev;
- bdev = bdget(rdev->dev);
+ bdev = bdget(kdev_t_to_nr(rdev->dev));
if (!bdev)
return -ENOMEM;
err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW);
* Searches all registered partitions for autorun RAID arrays
* at boot time.
*/
-static int detected_devices[128];
+static kdev_t detected_devices[128];
static int dev_cnt;
void md_autodetect_dev(kdev_t dev)
}
dev_cnt = 0;
- autorun_devices(-1);
+ autorun_devices(to_kdev_t(-1));
}
static struct {
*p++ = 0;
dev = name_to_kdev_t(devname);
- handle = devfs_find_handle(NULL, devname, MAJOR (dev), MINOR (dev),
+ handle = devfs_find_handle(NULL, devname, major(dev), minor(dev),
DEVFS_SPECIAL_BLK, 1);
if (handle != 0) {
unsigned major, minor;
devfs_get_maj_min(handle, &major, &minor);
dev = mk_kdev(major, minor);
}
- if (!dev) {
+ if (kdev_none(dev)) {
printk(KERN_WARNING "md: Unknown device name: %s\n", devname);
break;
}
devname = p;
}
- devices[i] = 0;
+ devices[i] = to_kdev_t(0);
if (!md_setup_args.device_set[minor])
continue;
ainfo.layout = 0;
ainfo.chunk_size = md_setup_args.chunk[minor];
err = set_array_info(mddev, &ainfo);
- for (i = 0; !err && (dev = devices[i]); i++) {
+ for (i = 0; !err && i <= MD_SB_DISKS; i++) {
+ dev = devices[i];
+ if (kdev_none(dev))
+ break;
dinfo.number = i;
dinfo.raid_disk = i;
dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC);
}
} else {
/* persistent */
- for (i = 0; (dev = devices[i]); i++) {
+ for (i = 0; i <= MD_SB_DISKS; i++) {
+ dev = devices[i];
+ if (kdev_none(dev))
+ break;
dinfo.major = major(dev);
dinfo.minor = minor(dev);
add_new_disk (mddev, &dinfo);
memcpy(bh_req, bh, sizeof(*bh));
bh_req->b_blocknr = bh->b_rsector;
bh_req->b_dev = multipath->dev;
+ /* FIXME - later we will need bdev here */
bh_req->b_rdev = multipath->dev;
/* bh_req->b_rsector = bh->n_rsector; */
bh_req->b_end_io = multipath_end_request;
init_buffer(bh, raid5_end_read_request, sh);
bh->b_dev = conf->disks[i].dev;
+ /* FIXME - later we will need bdev here */
bh->b_blocknr = block;
bh->b_state = (1 << BH_Req) | (1 << BH_Mapped);
else if (spare && action[i] == WRITE+1)
bh->b_dev = spare->dev;
else skip=1;
+ /* FIXME - later we will need bdev here */
if (!skip) {
PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, action[i]-1, i);
atomic_inc(&sh->count);
u32 m;
- while (!list_empty(&q->queue_head)) {
+ while (!blk_queue_empty(q)) {
/*
* On an IRQ completion if there is an inactive
* request on the queue head it means it isnt yet
* ready to dispatch.
*/
- req = blkdev_entry_next_request(&q->queue_head);
+ req = elv_next_request(q);
if(req->rq_status == RQ_INACTIVE)
return;
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
struct dev_mc_list *dmi=dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI){
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
- {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test)
- {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
char tx_full;
};
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
* Am7990 Control and Status Registers
*/
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/uaccess.h>
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
- int crc = -1;
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
-
- return crc;
-}
-
static void __cp_set_rx_mode (struct net_device *dev)
{
struct cp_private *cp = dev->priv;
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/completion.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/uaccess.h>
static int rtl8139_close (struct net_device *dev);
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
static void rtl8139_set_rx_mode (struct net_device *dev);
static void __set_rx_mode (struct net_device *dev);
static void rtl8139_hw_start (struct net_device *dev);
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
- int crc = -1;
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
-
- return crc;
-}
-
-
static void __set_rx_mode (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
#include <linux/in.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
return &ei_local->stat;
}
-/*
- * Update the given Autodin II CRC value with another data byte.
- */
-
-static inline u32 update_crc(u8 byte, u32 current_crc)
-{
- int bit;
- u8 ah = 0;
- for (bit=0; bit<8; bit++)
- {
- u8 carry = (current_crc>>31);
- current_crc <<= 1;
- ah = ((ah<<1) | carry) ^ byte;
- if (ah&1)
- current_crc ^= 0x04C11DB7; /* CRC polynomial */
- ah >>= 1;
- byte >>= 1;
- }
- return current_crc;
-}
-
/*
* Form the 64 bit 8390 multicast table from the linked list of addresses
* associated with this dev structure.
for (dmi=dev->mc_list; dmi; dmi=dmi->next)
{
- int i;
u32 crc;
if (dmi->dmi_addrlen != ETH_ALEN)
{
printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
continue;
}
- crc = 0xffffffff; /* initial CRC value */
- for (i=0; i<ETH_ALEN; i++)
- crc = update_crc(dmi->dmi_addr[i], crc);
+ crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
/*
* The 8390 uses the 6 most significant bits of the
* CRC to index the multicast table.
--- /dev/null
+# These drivers all require crc32.o
+obj-$(CONFIG_8139CP) += crc32.o
+obj-$(CONFIG_8139TOO) += crc32.o
+obj-$(CONFIG_A2065) += crc32.o
+obj-$(CONFIG_ARM_AM79C961A) += crc32.o
+obj-$(CONFIG_AT1700) += crc32.o
+obj-$(CONFIG_ATP) += crc32.o
+obj-$(CONFIG_DE2104X) += crc32.o
+obj-$(CONFIG_DE4X5) += crc32.o
+obj-$(CONFIG_DECLANCE) += crc32.o
+obj-$(CONFIG_DEPCA) += crc32.o
+obj-$(CONFIG_DL2K) += crc32.o
+obj-$(CONFIG_DM9102) += crc32.o
+obj-$(CONFIG_EPIC100) += crc32.o
+obj-$(CONFIG_EWRK3) += crc32.o
+obj-$(CONFIG_FEALNX) += crc32.o
+obj-$(CONFIG_HAPPYMEAL) += crc32.o
+obj-$(CONFIG_MACE) += crc32.o
+obj-$(CONFIG_MACMACE) += crc32.o
+obj-$(CONFIG_MIPS_AU1000_ENET) += crc32.o
+obj-$(CONFIG_NATSEMI) += crc32.o
+obj-$(CONFIG_PCMCIA_FMVJ18X) += crc32.o
+obj-$(CONFIG_PCMCIA_SMC91C92) += crc32.o
+obj-$(CONFIG_PCMCIA_XIRTULIP) += crc32.o
+obj-$(CONFIG_PCNET32) += crc32.o
+obj-$(CONFIG_SIS900) += crc32.o
+obj-$(CONFIG_SMC9194) += crc32.o
+obj-$(CONFIG_STARFIRE) += crc32.o
+obj-$(CONFIG_SUNBMAC) += crc32.o
+obj-$(CONFIG_SUNDANCE) += crc32.o
+obj-$(CONFIG_SUNGEM) += crc32.o
+obj-$(CONFIG_SUNGEM) += crc32.o
+obj-$(CONFIG_SUNLANCE) += crc32.o
+obj-$(CONFIG_SUNQE) += crc32.o
+obj-$(CONFIG_TULIP) += crc32.o
+obj-$(CONFIG_VIA_RHINE) += crc32.o
+obj-$(CONFIG_YELLOWFIN) += crc32.o
+obj-$(CONFIG_WINBOND_840) += crc32.o
+
+
+# These rely on drivers/net/7990.o which requires crc32.o
+obj-$(CONFIG_HPLANCE) += crc32.o
+obj-$(CONFIG_MVME147_NET) += crc32.o
+
+
+# These rely on drivers/net/8390.o which requires crc32.o
+obj-$(CONFIG_OAKNET) += crc32.o
+obj-$(CONFIG_NE2K_PCI) += crc32.o
+obj-$(CONFIG_STNIC) += crc32.o
+obj-$(CONFIG_MAC8390) += crc32.o
+obj-$(CONFIG_APNE) += crc32.o
+obj-$(CONFIG_PCMCIA_PCNET) += crc32.o
+obj-$(CONFIG_ARM_ETHERH) += crc32.o
+obj-$(CONFIG_WD80x3) += crc32.o
+obj-$(CONFIG_EL2) += crc32.o
+obj-$(CONFIG_NE2000) += crc32.o
+obj-$(CONFIG_NE2_MCA) += crc32.o
+obj-$(CONFIG_HPLAN) += crc32.o
+obj-$(CONFIG_HPLAN_PLUS) += crc32.o
+obj-$(CONFIG_ULTRA) += crc32.o
+obj-$(CONFIG_ULTRAMCA) += crc32.o
+obj-$(CONFIG_ULTRA32) += crc32.o
+obj-$(CONFIG_E2100) += crc32.o
+obj-$(CONFIG_ES3210) += crc32.o
+obj-$(CONFIG_LNE390) += crc32.o
+obj-$(CONFIG_NE3210) += crc32.o
+obj-$(CONFIG_AC3200) += crc32.o
+obj-$(CONFIG_ARIADNE2) += crc32.o
+obj-$(CONFIG_HYDRA) += crc32.o
* Fixes and tips by:
* - Janos Farkas (CHEXUM@sparta.banki.hu)
* - Jes Degn Soerensen (jds@kom.auc.dk)
+ * - Matt Domsch (Matt_Domsch@dell.com)
*
* ----------------------------------------------------------------------------
*
#include <linux/string.h>
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
struct dev_mc_list *dmi=dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI){
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
- {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test)
- {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
};
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
* Am7990 Control and Status Registers
*/
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
return &priv->stats;
}
-static inline u32 update_crc(u32 crc, u8 byte)
-{
- int i;
-
- for (i = 8; i != 0; i--) {
- byte ^= crc & 1;
- crc >>= 1;
-
- if (byte & 1)
- crc ^= 0xedb88320;
-
- byte >>= 1;
- }
-
- return crc;
-}
-
static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
{
if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
- int i, idx, bit;
+ int idx, bit;
u32 crc;
- crc = 0xffffffff;
-
- for (i = 0; i < ETH_ALEN; i++)
- crc = update_crc(crc, dmi->dmi_addr[i]);
+ crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
idx = crc >> 30;
bit = (crc >> 26) & 15;
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
Set the multicast/promiscuous mode for this adaptor.
*/
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void
set_rx_mode(struct net_device *dev)
{
#include <asm/dma.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
* Set or clear the multicast filter for this adapter.
*/
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode_8002(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/io.h>
au1000_init(dev);
}
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
/* The version of set_multicast below was lifted from sunhme.c */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void bmac_set_multicast(struct net_device *dev)
{
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
unsigned short rx_cfg;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
bmwrite(dev, BHASH0, 0xffff);
if(!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for(byte = 0; byte < 6; byte++) {
- for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if(test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
*
* 2001/10/23 - Takao Indoh <indou dot takao at jp dot fujitsu dot com>
* - Various memory leak fixes
+ *
+ * 2001/11/5 - Mark Huth <mark dot huth at mvista dot com>
+ * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under
+ * certain hotswap conditions.
+ * Note: this same change may be required in bond_arp_monitor ???
+ * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr
+ * - Handle hot swap ethernet interface deregistration events to remove
+ * kernel oops following hot swap of enslaved interface
*/
#include <linux/config.h>
#include <linux/if_bonding.h>
#include <linux/smp.h>
-#include <limits.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
static void bond_set_slave_active_flags(slave_t *slave);
static int bond_enslave(struct net_device *master, struct net_device *slave);
static int bond_release(struct net_device *master, struct net_device *slave);
+static int bond_release_all(struct net_device *master);
static int bond_sethwaddr(struct net_device *master, struct net_device *slave);
/*
static u16 bond_check_mii_link(bonding_t *bond)
{
int has_active_interface = 0;
+ unsigned long flags;
+ read_lock_irqsave(&bond->lock, flags);
read_lock(&bond->ptrlock);
has_active_interface = (bond->current_slave != NULL);
read_unlock(&bond->ptrlock);
+ read_unlock_irqrestore(&bond->lock, flags);
return (has_active_interface ? MII_LINK_READY : 0);
}
static int bond_close(struct net_device *master)
{
bonding_t *bond = (struct bonding *) master->priv;
- slave_t *slave;
unsigned long flags;
write_lock_irqsave(&bond->lock, flags);
if (arp_interval> 0) { /* arp interval, in milliseconds. */
del_timer(&bond->arp_timer);
}
- /* We need to unlock this because bond_release will re-lock it */
- write_unlock_irqrestore(&bond->lock, flags);
/* Release the bonded slaves */
- while ((slave = bond->prev) != (slave_t *)bond) {
- bond_release(master, slave->dev);
- }
+ bond_release_all(master);
+
+ write_unlock_irqrestore(&bond->lock, flags);
MOD_DEC_USE_COUNT;
return 0;
return -EINVAL;
}
+/*
+ * This function releases all slaves.
+ * Warning: must put write-locks around the call to this function.
+ */
+static int bond_release_all(struct net_device *master)
+{
+ bonding_t *bond;
+ slave_t *our_slave;
+ struct net_device *slave_dev;
+
+ if (master == NULL) {
+ return -ENODEV;
+ }
+
+ if (master->flags & IFF_SLAVE) {
+ return -EINVAL;
+ }
+
+ bond = (struct bonding *) master->priv;
+ bond->current_slave = NULL;
+
+ while ((our_slave = bond->prev) != (slave_t *)bond) {
+ slave_dev = our_slave->dev;
+ bond->prev = our_slave->prev;
+
+ kfree(our_slave);
+
+ netdev_set_master(slave_dev, NULL);
+
+ /* only restore its RUNNING flag if monitoring set it down */
+ if (slave_dev->flags & IFF_UP)
+ slave_dev->flags |= IFF_RUNNING;
+
+ if (slave_dev->flags & IFF_NOARP)
+ dev_close(slave_dev);
+ }
+ bond->next = (slave_t *)bond;
+ bond->slave_cnt = 0;
+ printk (KERN_INFO "%s: releases all slaves\n", master->name);
+
+ return 0;
+}
+
/* this function is called regularly to monitor each slave's link. */
static void bond_mii_monitor(struct net_device *master)
{
read_lock_irqsave(&bond->lock, flags);
- if (rtnl_shlock_nowait()) {
- goto monitor_out;
- }
-
- if (rtnl_exlock_nowait()) {
- rtnl_shunlock();
- goto monitor_out;
- }
/* we will try to read the link status of each of our slaves, and
* set their IFF_RUNNING flag appropriately. For each slave not
* supporting MII status, we won't do anything so that a user-space
} /* end of switch */
} /* end of while */
- /* if there's no active interface and we discovered that one
- of the slaves could be activated earlier, so we do it.
- */
+ /*
+ * if there's no active interface and we discovered that one
+ * of the slaves could be activated earlier, so we do it.
+ */
read_lock(&bond->ptrlock);
oldcurrent = bond->current_slave;
read_unlock(&bond->ptrlock);
}
}
- rtnl_exunlock();
- rtnl_shunlock();
-monitor_out:
read_unlock_irqrestore(&bond->lock, flags);
/* re-arm the timer */
mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000));
if (!IS_UP(master)) {
mod_timer(&bond->arp_timer, next_timer);
- goto monitor_out;
+ goto arp_monitor_out;
}
if (rtnl_shlock_nowait()) {
- goto monitor_out;
+ goto arp_monitor_out;
}
if (rtnl_exlock_nowait()) {
rtnl_shunlock();
- goto monitor_out;
+ goto arp_monitor_out;
}
/* see if any of the previous devices are up now (i.e. they have seen a
* an arp on all of the interfaces
*/
+ read_lock(&bond->ptrlock);
if (bond->current_slave == NULL) {
+ read_unlock(&bond->ptrlock);
slave = (slave_t *)bond;
while ((slave = slave->prev) != (slave_t *)bond) {
arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target,
slave->dev->dev_addr, arp_target_hw_addr);
}
}
+ else {
+ read_unlock(&bond->ptrlock);
+ }
rtnl_exunlock();
rtnl_shunlock();
-monitor_out:
+arp_monitor_out:
read_unlock_irqrestore(&bond->lock, flags);
/* re-arm the timer */
{
bonding_t *bond = (struct bonding *) master->priv;
slave_t *slave;
+ unsigned long flags;
info->bond_mode = mode;
info->num_slaves = 0;
info->miimon = miimon;
- read_lock(&bond->ptrlock);
+ read_lock_irqsave(&bond->lock, flags);
for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) {
info->num_slaves++;
}
- read_unlock(&bond->ptrlock);
+ read_unlock_irqrestore(&bond->lock, flags);
return 0;
}
bonding_t *bond = (struct bonding *) master->priv;
slave_t *slave;
int cur_ndx = 0;
+ unsigned long flags;
if (info->slave_id < 0) {
return -ENODEV;
}
- read_lock(&bond->ptrlock);
+ read_lock_irqsave(&bond->lock, flags);
for (slave = bond->prev;
slave != (slave_t *)bond && cur_ndx < info->slave_id;
slave = slave->prev) {
cur_ndx++;
}
+ read_unlock_irqrestore(&bond->lock, flags);
+
if (cur_ndx == info->slave_id) {
strcpy(info->slave_name, slave->dev->name);
info->link = slave->link;
info->state = slave->state;
info->link_failure_count = slave->link_failure_count;
} else {
- read_unlock(&bond->ptrlock);
return -ENODEV;
}
- read_unlock(&bond->ptrlock);
return 0;
}
}
slave_dev = dev_get_by_name(ifr->ifr_slave);
+
#ifdef BONDING_DEBUG
printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev);
printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name);
#endif
- switch (cmd) {
- case BOND_ENSLAVE_OLD:
- case SIOCBONDENSLAVE:
- ret = bond_enslave(master_dev, slave_dev);
- break;
- case BOND_RELEASE_OLD:
- case SIOCBONDRELEASE:
- ret = bond_release(master_dev, slave_dev);
- break;
- case BOND_SETHWADDR_OLD:
- case SIOCBONDSETHWADDR:
- ret = bond_sethwaddr(master_dev, slave_dev);
- break;
- case BOND_CHANGE_ACTIVE_OLD:
- case SIOCBONDCHANGEACTIVE:
- if (mode == BOND_MODE_ACTIVEBACKUP) {
- ret = bond_change_active(master_dev, slave_dev);
- }
- else {
- ret = -EINVAL;
- }
- break;
- default:
- ret = -EOPNOTSUPP;
- }
- if (slave_dev) {
- /*
- * Clear the module reference that was added by dev_get_by_name
- */
+ if (slave_dev == NULL) {
+ ret = -ENODEV;
+ } else {
+ switch (cmd) {
+ case BOND_ENSLAVE_OLD:
+ case SIOCBONDENSLAVE:
+ ret = bond_enslave(master_dev, slave_dev);
+ break;
+ case BOND_RELEASE_OLD:
+ case SIOCBONDRELEASE:
+ ret = bond_release(master_dev, slave_dev);
+ break;
+ case BOND_SETHWADDR_OLD:
+ case SIOCBONDSETHWADDR:
+ ret = bond_sethwaddr(master_dev, slave_dev);
+ break;
+ case BOND_CHANGE_ACTIVE_OLD:
+ case SIOCBONDCHANGEACTIVE:
+ if (mode == BOND_MODE_ACTIVEBACKUP) {
+ ret = bond_change_active(master_dev, slave_dev);
+ }
+ else {
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
dev_put(slave_dev);
}
return ret;
}
read_lock_irqsave(&bond->lock, flags);
- read_lock(&bond->ptrlock);
slave = bond->prev;
/* we're at the root, get the first slave */
if ((slave == NULL) || (slave->dev == NULL)) {
/* no suitable interface, frame not sent */
- read_unlock(&bond->ptrlock);
dev_kfree_skb(skb);
read_unlock_irqrestore(&bond->lock, flags);
return 0;
slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt;
- read_unlock(&bond->ptrlock);
-
while ( (slave_no > 0) && (slave != (slave_t *)bond) ) {
slave = slave->prev;
slave_no--;
off_t begin = 0;
u16 link;
slave_t *slave = NULL;
+ unsigned long flags;
while (bond != NULL) {
/*
*/
link = bond_check_mii_link(bond);
- read_lock(&bond->ptrlock);
-
len += sprintf(buf + len, "Bonding Mode: ");
len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing");
if (mode == BOND_MODE_ACTIVEBACKUP) {
+ read_lock_irqsave(&bond->lock, flags);
+ read_lock(&bond->ptrlock);
if (bond->current_slave != NULL) {
len += sprintf(buf + len,
"Currently Active Slave: %s\n",
bond->current_slave->dev->name);
}
+ read_unlock(&bond->ptrlock);
+ read_unlock_irqrestore(&bond->lock, flags);
}
len += sprintf(buf + len, "MII Status: ");
len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay);
+ read_lock_irqsave(&bond->lock, flags);
for (slave = bond->prev; slave != (slave_t *)bond;
slave = slave->prev) {
len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name);
len += sprintf(buf + len, "Link Failure Count: %d\n",
slave->link_failure_count);
}
+ read_unlock_irqrestore(&bond->lock, flags);
/*
* Figure out the calcs for the /proc/net interface
len = 0;
}
- read_unlock(&bond->ptrlock);
bond = bond->next_bond;
}
default:
return NOTIFY_DONE;
}
- }
+ } else if (this_bond->device == event_dev->master) {
+ switch (event) {
+ case NETDEV_UNREGISTER:
+ bond_release(this_bond->device, event_dev);
+ break;
+ }
+ return NOTIFY_DONE;
+ }
this_bond = this_bond->next_bond;
}
return NOTIFY_DONE;
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/rtnetlink.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
new frame, not around filling de->setup_frame. This is non-deterministic
when re-entered but still correct. */
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
#undef set_bit_le
#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
'pb' is now only initialized if a de4x5 chip is
present.
<france@handhelds.org>
+ 0.547 08-Nov-01 Use library crc32 functions by <Matt_Domsch@dell.com>
=========================================================================
*/
#include <linux/init.h>
#include <linux/version.h>
#include <linux/spinlock.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
** EISA bus defines
*/
u_long iobase = dev->base_addr;
int i, j, bit, byte;
u16 hashcode;
- u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
+ u32 omr, crc;
char *pa;
unsigned char *addrs;
addrs=dmi->dmi_addr;
dmi=dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
- /* process each address bit */
- for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
- crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
- }
- }
+ crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <linux/etherdevice.h>
#endif
static int type;
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_BE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI) {
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test) {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc(6, addrs);
crc = crc >> 26;
mcast_table[crc >> 3] |= 1 << (crc & 0xf);
}
by <peterd@pnd-pc.demon.co.uk>
0.53 12-Jan-01 Release resources on failure, bss tidbits
by acme@conectiva.com.br
+ 0.54 08-Nov-01 use library crc32 functions
+ by Matt_Domsch@dell.com
=========================================================================
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/io.h>
#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/*
** EISA bus defines
*/
char *addrs;
int i, j, bit, byte;
u16 hashcode;
- s32 crc, poly = CRC_POLYNOMIAL_BE;
+ u32 crc;
if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */
for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
addrs=dmi->dmi_addr;
dmi=dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
- /* process each address bit */
- for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
- crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
- }
- }
+ crc = ether_crc(ETH_ALEN, addrs);
hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
for (j=0;j<5;j++) { /* ... in reverse order. */
hashcode = (hashcode << 1) | ((crc>>=1) & 1);
static int find_miiphy (struct net_device *dev);
static int parse_eeprom (struct net_device *dev);
static int read_eeprom (long ioaddr, int eep_addr);
-static unsigned get_crc (unsigned char *p, int len);
static int mii_wait_link (struct net_device *dev, int wait);
static int mii_set_media (struct net_device *dev);
static int mii_get_media (struct net_device *dev);
}
/* Check CRC */
- crc = ~get_crc (sromdata, 256 - 4);
+ crc = ~ether_crc_le(256-4, sromdata);
if (psrom->crc != crc) {
printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
return -1;
return 0;
}
-#define CRC_POLY 0xedb88320
-static unsigned
-get_crc (unsigned char *p, int len)
-{
- int bit;
- unsigned char byte;
- unsigned crc = 0xffffffff;
-
- while (--len >= 0) {
- byte = *p++;
- for (bit = 0; bit < 8; bit++, byte >>= 1) {
- crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
- }
- }
- return crc;
-}
-
static void
set_multicast (struct net_device *dev)
{
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f,
+ set_bit (ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
hash_table);
}
writel (hash_table[0], ioaddr + HashTable0);
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/crc32.h>
#include <asm/processor.h>
#include <asm/bitops.h>
static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control
4: TX pause packet */
-unsigned long CrcTable[256] = {
- 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
- 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
- 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
- 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
- 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
- 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
- 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
- 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
- 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
- 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
- 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
- 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
- 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
- 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
- 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
- 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
- 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
- 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
- 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
- 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
- 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
- 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
- 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
- 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
- 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
- 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
- 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
- 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
- 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
- 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
- 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
- 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
- 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
- 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
- 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
- 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
- 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
- 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
- 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
- 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
- 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
- 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
- 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
- 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
- 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
- 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
- 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
- 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
- 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
- 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
- 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
- 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
- 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
- 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
- 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
- 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
- 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
- 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
- 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
- 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
- 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
- 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
- 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
- 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
-};
/* function declaration ------------------------------------- */
static int dmfe_open(struct DEVICE *);
static void dmfe_dynamic_reset(struct DEVICE *);
static void dmfe_free_rxbuffer(struct dmfe_board_info *);
static void dmfe_init_dm910x(struct DEVICE *);
-static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
+static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
static void dmfe_parse_srom(struct dmfe_board_info *);
static void dmfe_program_DM9801(struct dmfe_board_info *, int);
static void dmfe_program_DM9802(struct dmfe_board_info *);
* 0 : return the normal CRC (for Hash Table index)
*/
-unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
+static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
- unsigned long Crc = 0xffffffff;
-
- while (Len--) {
- Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
- }
-
- if (flag)
- return ~Crc;
- else
- return Crc;
+ u32 crc = crc32(~0, Data, Len);
+ if (flag) crc = ~crc;
+ return crc;
}
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
new frame, not around filling ep->setup_frame. This is non-deterministic
when re-entered but still correct. */
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
long ioaddr = dev->base_addr;
<kenneth@bbs.sas.ntu.ac.sg>.
0.42 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
+ 0.44 08-Nov-01 use library crc32 functions <Matt_Domsch@dell.com>
=========================================================================
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#define EISA_SLOT_INC 0x1000
#endif
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
#define QUEUE_PKT_TIMEOUT (1*HZ) /* Jiffies */
/*
struct dev_mc_list *dmi = dev->mc_list;
u_long iobase = dev->base_addr;
int i;
- char *addrs, j, bit, byte;
+ char *addrs, bit, byte;
short *p = (short *) lp->mctbl;
u16 hashcode;
- s32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
spin_lock_irq(&lp->hw_lock);
addrs = dmi->dmi_addr;
dmi = dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */
- /* process each address bit */
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
- }
- }
+ crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
static void set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
return &np->stats;
}
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
-
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
-
- return crc;
-}
-
-
static void set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
* - PHY updates
* BenH <benh@kernel.crashing.org> - 08/08/2001
* - Add more PHYs, fixes to sleep code
+ * Matt Domsch <Matt_Domsch@dell.com> - 11/12/2001
+ * - use library crc32 functions
*/
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/crc32.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/pgtable.h>
* Configure promisc mode and setup multicast hash table
* filter
*/
-#define CRC_POLY 0xedb88320
static void
gmac_set_multicast(struct net_device *dev)
{
struct gmac *gm = (struct gmac *) dev->priv;
struct dev_mc_list *dmi = dev->mc_list;
int i,j,k,b;
- unsigned long crc;
+ u32 crc;
int multicast_hash = 0;
int multicast_all = 0;
int promisc = 0;
hash_table[i] = 0;
for (i = 0; i < dev->mc_count; i++) {
- crc = ~0;
- for (j = 0; j < 6; ++j) {
- b = dmi->dmi_addr[j];
- for (k = 0; k < 8; ++k) {
- if ((crc ^ b) & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- b >>= 1;
- }
- }
+ crc = ether_crc_le(6, dmi->dmi_addr);
j = crc >> 24; /* bit number in multicast_filter */
hash_table[j >> 4] |= 1 << (15 - (j & 0xf));
dmi = dmi->next;
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/crc32.h>
#ifdef CONFIG_SERIAL
#include <linux/serial.h>
* Given a multicast ethernet address, this routine calculates the
* address's bit index in the logical address filter mask
*/
-#define CRC_MASK 0xedb88320
static inline unsigned int
ioc3_hash(const unsigned char *addr)
{
unsigned int temp = 0;
unsigned char byte;
- unsigned int crc;
- int bits, len;
-
- len = ETH_ALEN;
- for (crc = ~0; --len >= 0; addr++) {
- byte = *addr;
- for (bits = 8; --bits >= 0; ) {
- if ((byte ^ crc) & 1)
- crc = (crc >> 1) ^ CRC_MASK;
- else
- crc >>= 1;
- byte >>= 1;
- }
- }
+ u32 crc;
+ int bits;
+
+ crc = ether_crc_le(ETH_ALEN, addr);
crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */
for (bits = 6; --bits >= 0; ) {
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
return &p->stats;
}
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY 0xedb88320
-
static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
volatile struct mace *mb = mp->mace;
- int i, j, k, b;
- unsigned long crc;
+ int i, j;
+ u32 crc;
mp->maccc &= ~PROM;
if (dev->flags & IFF_PROMISC) {
for (i = 0; i < 8; i++)
multicast_filter[i] = 0;
for (i = 0; i < dev->mc_count; i++) {
- crc = ~0;
- for (j = 0; j < 6; ++j) {
- b = dmi->dmi_addr[j];
- for (k = 0; k < 8; ++k) {
- if ((crc ^ b) & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- b >>= 1;
- }
- }
+ crc = ether_crc_le(6, dmi->dmi_addr);
j = crc >> 26; /* bit number in multicast_filter */
multicast_filter[j >> 3] |= 1 << (j & 7);
dmi = dmi->next;
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/timer.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
return &p->stats;
}
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY 0xedb88320
-
static void mace68k_set_multicast(struct net_device *dev)
{
struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
volatile struct mace *mb = mp->mace;
int i, j, k, b;
- unsigned long crc;
+ u32 crc;
mp->maccc &= ~PROM;
if (dev->flags & IFF_PROMISC)
multicast_filter[i] = 0;
for (i = 0; i < dev->mc_count; i++)
{
- crc = ~0;
- for (j = 0; j < 6; ++j)
- {
- b = dmi->dmi_addr[j];
- for (k = 0; k < 8; ++k)
- {
- if ((crc ^ b) & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- b >>= 1;
- }
- }
+ crc = ether_crc_le(6, dmi->dmi_addr);
j = crc >> 26; /* bit number in multicast_filter */
multicast_filter[j >> 3] |= 1 << (j & 7);
dmi = dmi->next;
#define MYRI_NetReceiveBadCrcs 0xB8D4
#define MYRI_NetReceiveBytes 0xB8DC
-#endif SYMBOL_DEFINES_COMPILED
+#endif /* SYMBOL_DEFINES_COMPILED */
static struct net_device_stats *myri_get_stats(struct net_device *dev)
{ return &(((struct myri_eth *)dev->priv)->enet_stats); }
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void myri_set_multicast(struct net_device *dev)
{
/* Do nothing, all MyriCOM nodes transmit multicast frames
version 1.0.13:
* ETHTOOL_[GS]EEPROM support (Tim Hockin)
+ version 1.0.13:
+ * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
+
TODO:
* big endian support with CFG:BEM instead of cpu_to_le32
* support for an external PHY
#define DRV_NAME "natsemi"
#define DRV_VERSION "1.07+LK1.0.13"
-#define DRV_RELDATE "Oct 19, 2001"
+#define DRV_RELDATE "Nov 12, 2001"
/* Updated to recommendations in pci-skeleton v2.03. */
return &np->stats;
}
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
- them. Select the endian-ness that results in minimal calculations.
-*/
-#if 0
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-#else
+/**
+ * dp83815_crc - computer CRC for hash table entries
+ *
+ * Note - this is, for some reason, *not* the same function
+ * as ether_crc_le() or ether_crc(), though it uses the
+ * same big-endian polynomial.
+ */
#define DP_POLYNOMIAL 0x04C11DB7
-/* dp83815_crc - computer CRC for hash table entries */
-static unsigned ether_crc_le(int length, unsigned char *data)
+static unsigned dp83815_crc(int length, unsigned char *data)
{
u32 crc;
u8 cur_byte;
return (crc);
}
-#endif
+
void set_bit_le(int offset, unsigned char * data)
{
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ set_bit_le(dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
mc_filter);
}
rx_mode = RxFilterEnable | AcceptBroadcast
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#define NETDRV_VERSION "1.0.0"
static int netdrv_close (struct net_device *dev);
static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
static void netdrv_set_rx_mode (struct net_device *dev);
static void netdrv_hw_start (struct net_device *dev);
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
- int crc = -1;
-
- DPRINTK ("ENTER\n");
-
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
-
- DPRINTK ("EXIT\n");
- return crc;
-}
-
-
static void netdrv_set_rx_mode (struct net_device *dev)
{
struct netdrv_private *tp = dev->priv;
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
+#include <linux/crc32.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
Set the multicast/promiscuous mode for this adaptor.
*/
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/system.h>
return &smc->stats;
}
-/*======================================================================
-
- Compute the AUTODIN polynomial "CRC32" for ethernet packets.
-
-======================================================================*/
-
-static const u_int ethernet_polynomial = 0x04c11db7U;
-
-static u_int ether_crc(int length, u_char *data)
-{
- int crc = 0xffffffff; /* Initial value. */
-
- while (--length >= 0) {
- u_char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- /* The hash index is the either the upper or lower bits of the CRC, so
- * we return the entire CRC.
- */
- return crc;
-}
/*======================================================================
#include <linux/init.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
return -EOPNOTSUPP;
}
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
-
/* Set or clear the multicast filter for this adaptor.
Note that we only use exclusion around actually queueing the
new frame, not around filling tp->setup_frame. This is non-deterministic
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#define PCNET32_TOTAL_SIZE 0x20
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
volatile u16 *mcast_table = (u16 *)&ib->filter;
struct dev_mc_list *dmi=dev->mc_list;
char *addrs;
- int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ int i;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI){
if (!(*addrs & 1))
continue;
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++)
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test) {
- crc = crc ^ poly;
- }
- }
-
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
static void __exit shaper_exit (void)
{
+ int i;
+
+ for (i = 0; i < shapers; i++)
+ unregister_netdev(&devs[i]);
+
kfree(devs);
devs = NULL;
}
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.08.01 Aug. 25 2001
+ Revision: 1.08.02 Jan. 4 2002
Modified from the driver which is originally written by Donald Becker.
preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm
+ Rev 1.08.02 Jan. 4 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include "sis900.h"
static char version[] __devinitdata =
-KERN_INFO "sis900.c: v1.08.01 9/25/2001\n";
+KERN_INFO "sis900.c: v1.08.02 1/4/2002\n";
static int max_interrupt_work = 40;
static int multicast_filter_limit = 128;
static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision)
{
-/* what is the correct value of the POLYNOMIAL ??
- Donald Becker use 0x04C11DB7U
- Joseph Zbiciak im14u2c@primenet.com gives me the
- correct answer, thank you Joe !! */
-#define POLYNOMIAL 0x04C11DB7L
- u32 crc = 0xffffffff, msb;
- int i, j;
- u32 byte;
-
- for (i = 0; i < 6; i++) {
- byte = *addr++;
- for (j = 0; j < 8; j++) {
- msb = crc >> 31;
- crc <<= 1;
- if (msb ^ (byte & 1)) {
- crc ^= POLYNOMIAL;
- }
- byte >>= 1;
- }
- }
+ u32 crc = ether_crc(6, addr);
/* leave 8 or 7 most siginifant bits */
if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/crc32.h>
#include <asm/byteorder.h>
#include <asm/bitops.h>
#include <asm/io.h>
/* defines ********************************************************************/
-#define CRC32_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */
#define HASH_BITS 6 /* #bits in hash */
#define SK_MC_BIT 0x01
unsigned SkCrc32McHash(
unsigned char *pMc) /* Multicast address */
{
- unsigned Idx;
- unsigned Bit;
- unsigned Data;
- unsigned Crc;
-
- Crc = 0xFFFFFFFFUL;
- for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
- Data = *pMc++;
- for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
- Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0);
- }
- }
+ u32 Crc;
+
+ Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc);
return (Crc & ((1 << HASH_BITS) - 1));
} /* SkCrc32McHash */
. allocation
. 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet
. 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ"
+ . 11/08/01 Matt Domsch Use common crc32 function
----------------------------------------------------------------------------*/
static const char version[] =
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/errno.h>
*/
static void smc_set_multicast_list(struct net_device *dev);
-/*
- . CRC compute
- */
-static int crc32( char * s, int length );
/*---------------------------------------------------------------
.
continue;
/* only use the low order bits */
- position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+ position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f;
/* do some messy swapping to put the bit in the right spot */
multicast_table[invert3[position&7]] |=
}
}
-/*
- Finds the CRC32 of a set of bytes.
- Again, from Peter Cammaert's code.
-*/
-static int crc32( char * s, int length ) {
- /* indices */
- int perByte;
- int perBit;
- /* crc polynomial for Ethernet */
- const unsigned long poly = 0xedb88320;
- /* crc value - preinitialized to all 1's */
- unsigned long crc_value = 0xffffffff;
-
- for ( perByte = 0; perByte < length; perByte ++ ) {
- unsigned char c;
-
- c = *(s++);
- for ( perBit = 0; perBit < 8; perBit++ ) {
- crc_value = (crc_value>>1)^
- (((crc_value^c)&0x01)?poly:0);
- c >>= 1;
- }
- }
- return crc_value;
-}
-
-
/*
. Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
. Purpose:
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/uaccess.h>
#include <asm/io.h>
}
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
+/* Chips may use the upper or lower CRC bits, and may reverse and/or invert
them. Select the endian-ness that results in minimal calculations.
*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
return &bp->enet_stats;
}
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void bigmac_set_multicast(struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 tmp, crc, poly = CRC_POLYNOMIAL_LE;
+ u32 tmp, crc;
/* Disable the receiver. The bit self-clears when
* the operation is complete.
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
#include <linux/init.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
return &np->stats;
}
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
- them. Select the endian-ness that results in minimal calculations.
-*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
long ioaddr = dev->base_addr;
-/* $Id: sungem.c,v 1.30 2001/10/17 06:55:10 davem Exp $
+/* $Id: sungem.c,v 1.44 2001/12/08 04:06:27 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
* Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ *
+ * Support for Apple GMAC and assorted PHYs by
+ * Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ *
+ * TODO:
+ * - Get rid of all those nasty mdelay's and replace them
+ * with schedule_timeout.
+ * - Implement WOL
*/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
#ifdef __sparc__
#include <asm/idprom.h>
#include "sungem.h"
+#define DRV_NAME "sungem"
+#define DRV_VERSION "0.96"
+#define DRV_RELDATE "11/17/01"
+#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+
static char version[] __devinitdata =
- "sungem.c:v0.95 16/Oct/01 David S. Miller (davem@redhat.com)\n";
+ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
-MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
MODULE_LICENSE("GPL");
MODULE_PARM(gem_debug, "i");
MODULE_PARM_DESC(gem_debug, "(ignored)");
+MODULE_PARM(link_mode, "i");
+
+static int link_mode;
+
+static u16 link_modes[] __devinitdata = {
+ BMCR_ANENABLE, /* 0 : autoneg */
+ 0, /* 1 : 10bt half duplex */
+ BMCR_SPEED100, /* 2 : 100bt half duplex */
+ BMCR_SPD2, /* verify this */ /* 3 : 1000bt half duplex */
+ BMCR_FULLDPLX, /* 4 : 10bt full duplex */
+ BMCR_SPEED100|BMCR_FULLDPLX, /* 5 : 100bt full duplex */
+ BMCR_SPD2|BMCR_FULLDPLX /* 6 : 1000bt full duplex */
+};
#define GEM_MODULE_NAME "gem"
#define PFX GEM_MODULE_NAME ": "
* they only support 10/100 speeds. -DaveM
*
* Apple's GMAC does support gigabit on machines with
- * the BCM5400 or 5401 PHYs. -BenH
+ * the BCM54xx PHYs. -BenH
*/
{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
return 1;
}
-static void gem_stop(struct gem *, unsigned long);
-static void gem_init_rings(struct gem *, int);
-static void gem_init_hw(struct gem *);
-
/* All non-normal interrupt conditions get serviced here.
* Returns non-zero if we should just exit the interrupt
* handler right now (ie. if we reset the card which invalidates
return 0;
do_reset:
- gem_stop(gp, gp->regs);
- gem_init_rings(gp, 1);
- gem_init_hw(gp);
+ gp->reset_task_pending = 1;
+ schedule_task(&gp->reset_task);
+
return 1;
}
struct gem *gp = dev->priv;
printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+ if (!gp->hw_running) {
+ printk("%s: hrm.. hw not running !\n", dev->name);
+ return;
+ }
printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n",
dev->name,
readl(gp->regs + TXDMA_CFG),
spin_lock_irq(&gp->lock);
- gem_stop(gp, gp->regs);
- gem_init_rings(gp, 1);
- gem_init_hw(gp);
+ gp->reset_task_pending = 1;
+ schedule_task(&gp->reset_task);
spin_unlock_irq(&gp->lock);
+}
- netif_wake_queue(dev);
+static __inline__ int gem_intme(int entry)
+{
+ /* Algorithm: IRQ every 1/2 of descriptors. */
+ if (!(entry & ((TX_RING_SIZE>>1)-1)))
+ return 1;
+
+ return 0;
}
static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
~PAGE_MASK),
len, PCI_DMA_TODEVICE);
ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len;
+ if (gem_intme(entry))
+ ctrl |= TXDCTRL_INTME;
txd->buffer = cpu_to_le64(mapping);
txd->control_word = cpu_to_le64(ctrl);
entry = NEXT_TX(entry);
} else {
struct gem_txd *txd;
u32 first_len;
+ u64 intme;
dma_addr_t first_mapping;
int frag, first_entry = entry;
+ intme = 0;
+ if (gem_intme(entry))
+ intme |= TXDCTRL_INTME;
+
/* We must give this initial chunk to the device last.
* Otherwise we could race with the device.
*/
txd->buffer = cpu_to_le64(mapping);
txd->control_word = cpu_to_le64(this_ctrl | len);
+ if (gem_intme(entry))
+ intme |= TXDCTRL_INTME;
+
entry = NEXT_TX(entry);
}
txd = &gp->init_block->txd[first_entry];
txd->buffer = cpu_to_le64(first_mapping);
- txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | first_len);
+ txd->control_word =
+ cpu_to_le64(ctrl | TXDCTRL_SOF | intme | first_len);
}
gp->tx_new = entry;
return -EINVAL;
spin_lock_irq(&gp->lock);
- gem_stop(gp, gp->regs);
dev->mtu = new_mtu;
- gem_init_rings(gp, 1);
- gem_init_hw(gp);
+ gp->reset_task_pending = 1;
+ schedule_task(&gp->reset_task);
spin_unlock_irq(&gp->lock);
+ flush_scheduled_tasks();
+
return 0;
}
#define STOP_TRIES 32
-static void gem_stop(struct gem *gp, unsigned long regs)
+static void gem_stop(struct gem *gp)
{
int limit;
u32 val;
writel(0xffffffff, gp->regs + GREG_IMASK);
/* Reset the chip */
- writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST);
+ writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST);
limit = STOP_TRIES;
do {
udelay(20);
- val = readl(regs + GREG_SWRST);
+ val = readl(gp->regs + GREG_SWRST);
if (limit-- <= 0)
break;
} while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
val = readl(gp->regs + MAC_RXCFG);
writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+ (void) readl(gp->regs + MAC_RXCFG);
+ udelay(100);
+
writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
{ 1, 0, 1 }, /* 1000BT */
};
+static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
+{
+ u16 ctl;
+
+ /* Setup link parameters */
+ if (!ep)
+ goto start_aneg;
+ if (ep->autoneg == AUTONEG_ENABLE) {
+ /* TODO: parse ep->advertising */
+ gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
+ gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+ /* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+ gp->link_cntl = BMCR_ANENABLE;
+ } else {
+ gp->link_cntl = 0;
+ if (ep->speed == SPEED_100)
+ gp->link_cntl |= BMCR_SPEED100;
+ else if (ep->speed == SPEED_1000 && gp->gigabit_capable)
+ /* Hrm... check if this is right... */
+ gp->link_cntl |= BMCR_SPD2;
+ if (ep->duplex == DUPLEX_FULL)
+ gp->link_cntl |= BMCR_FULLDPLX;
+ }
+
+start_aneg:
+ spin_lock_irq(&gp->lock);
+ if (!gp->hw_running) {
+ spin_unlock_irq(&gp->lock);
+ return;
+ }
+
+ /* Configure PHY & start aneg */
+ ctl = phy_read(gp, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+ ctl |= gp->link_cntl;
+ if (ctl & BMCR_ANENABLE) {
+ ctl |= BMCR_ANRESTART;
+ gp->lstate = link_aneg;
+ } else {
+ gp->lstate = link_force_ok;
+ }
+ phy_write(gp, MII_BMCR, ctl);
+
+ gp->timer_ticks = 0;
+ gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
+ add_timer(&gp->link_timer);
+ spin_unlock_irq(&gp->lock);
+}
+
+static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
+{
+ u32 val;
+
+ *fd = 0;
+ *spd = 10;
+ *pause = 0;
+
+ if (gp->phy_mod == phymod_bcm5400 ||
+ gp->phy_mod == phymod_bcm5401 ||
+ gp->phy_mod == phymod_bcm5411) {
+ int link_mode;
+
+ val = phy_read(gp, MII_BCM5400_AUXSTATUS);
+ link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+ MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
+ *fd = phy_BCM5400_link_table[link_mode][0];
+ *spd = phy_BCM5400_link_table[link_mode][2] ?
+ 1000 :
+ (phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
+ val = phy_read(gp, MII_LPA);
+ if (val & LPA_PAUSE)
+ *pause = 1;
+ } else {
+ val = phy_read(gp, MII_LPA);
+
+ if (val & (LPA_10FULL | LPA_100FULL))
+ *fd = 1;
+ if (val & (LPA_100FULL | LPA_100HALF))
+ *spd = 100;
+ }
+}
+
/* A link-up condition has occurred, initialize and enable the
* rest of the chip.
*/
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
- if (gp->lstate == aneg_wait) {
- if (gp->phy_mod == phymod_bcm5400 ||
- gp->phy_mod == phymod_bcm5401 ||
- gp->phy_mod == phymod_bcm5411) {
- int link_mode;
- val = phy_read(gp, PHY_BCM5400_AUXSTATUS);
- link_mode = (val & PHY_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
- PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
- full_duplex = phy_BCM5400_link_table[link_mode][0];
- speed = phy_BCM5400_link_table[link_mode][2] ? 1000
- : (phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
- val = phy_read(gp, PHY_LPA);
- if (val & PHY_LPA_PAUSE)
- pause = 1;
- } else {
- val = phy_read(gp, PHY_LPA);
- if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
- full_duplex = 1;
- if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
- speed = 100;
- }
- } else {
- val = phy_read(gp, PHY_CTRL);
- if (val & PHY_CTRL_FDPLX)
+ val = phy_read(gp, MII_BMCR);
+ if (val & BMCR_ANENABLE)
+ gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
+ else {
+ if (val & BMCR_FULLDPLX)
full_duplex = 1;
- if (val & PHY_CTRL_SPD100)
+ if (val & BMCR_SPEED100)
speed = 100;
}
} else {
static int gem_mdio_link_not_up(struct gem *gp)
{
- if (gp->lstate == aneg_wait) {
- u16 val = phy_read(gp, PHY_CTRL);
+ if (gp->lstate == link_force_ret) {
+ printk(KERN_INFO "%s: Autoneg failed again, keeping"
+ " forced mode\n", gp->dev->name);
+ phy_write(gp, MII_BMCR, gp->link_fcntl);
+ gp->timer_ticks = 5;
+ gp->lstate = link_force_ok;
+ } else if (gp->lstate == link_aneg) {
+ u16 val = phy_read(gp, MII_BMCR);
/* Try forced modes. */
- val &= ~(PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
- val &= ~(PHY_CTRL_FDPLX);
- val |= PHY_CTRL_SPD100;
- phy_write(gp, PHY_CTRL, val);
- gp->timer_ticks = 0;
- gp->lstate = force_wait;
- return 1;
+ val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+ val &= ~(BMCR_FULLDPLX);
+ val |= BMCR_SPEED100;
+ phy_write(gp, MII_BMCR, val);
+ gp->timer_ticks = 5;
+ gp->lstate = link_force_try;
} else {
/* Downgrade from 100 to 10 Mbps if necessary.
* If already at 10Mbps, warn user about the
* situation every 10 ticks.
*/
- u16 val = phy_read(gp, PHY_CTRL);
- if (val & PHY_CTRL_SPD100) {
- val &= ~PHY_CTRL_SPD100;
- phy_write(gp, PHY_CTRL, val);
- gp->timer_ticks = 0;
- return 1;
+ u16 val = phy_read(gp, MII_BMCR);
+ if (val & BMCR_SPEED100) {
+ val &= ~BMCR_SPEED100;
+ phy_write(gp, MII_BMCR, val);
+ gp->timer_ticks = 5;
} else {
- printk(KERN_ERR "%s: Link down, cable problem?\n",
- gp->dev->name);
- val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
- phy_write(gp, PHY_CTRL, val);
- gp->timer_ticks = 1;
- gp->lstate = aneg_wait;
return 1;
}
}
+ return 0;
+}
+
+static void gem_init_rings(struct gem *, int);
+static void gem_init_hw(struct gem *, int);
+
+static void gem_reset_task(void *data)
+{
+ struct gem *gp = (struct gem *) data;
+
+ /* The link went down, we reset the ring, but keep
+ * DMA stopped. Todo: Use this function for reset
+ * on error as well.
+ */
+ if (gp->hw_running && gp->opened) {
+ /* Make sure we don't get interrupts or tx packets */
+ spin_lock_irq(&gp->lock);
+
+ netif_stop_queue(gp->dev);
+
+ writel(0xffffffff, gp->regs + GREG_IMASK);
+
+ spin_unlock_irq(&gp->lock);
+
+ /* Reset the chip & rings */
+ gem_stop(gp);
+ gem_init_rings(gp, 0);
+ gem_init_hw(gp, 0);
+
+ netif_wake_queue(gp->dev);
+ }
+ gp->reset_task_pending = 0;
}
static void gem_link_timer(unsigned long data)
{
struct gem *gp = (struct gem *) data;
- int restart_timer = 0;
- gp->timer_ticks++;
+ if (!gp->hw_running)
+ return;
+
+ /* If the link of task is still pending, we just
+ * reschedule the link timer
+ */
+ if (gp->reset_task_pending)
+ goto restart;
+
+ spin_lock_irq(&gp->lock);
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
- u16 val = phy_read(gp, PHY_STAT);
+ u16 val = phy_read(gp, MII_BMSR);
+ int up;
- if (val & PHY_STAT_LSTAT) {
- gem_set_link_modes(gp);
- } else if (gp->timer_ticks < 10) {
- restart_timer = 1;
+ /* When using autoneg, we really wait for ANEGCOMPLETE or we may
+ * get a "transcient" incorrect link state
+ */
+#if 0
+ {
+ u16 cntl = phy_read(gp, MII_BMCR);
+ if (cntl & BMCR_ANENABLE)
+ up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
+ else
+ up = (val & BMSR_LSTATUS) != 0;
+ }
+#else
+ up = (val & BMSR_LSTATUS) != 0;
+#endif
+ if (up) {
+ /* Ok, here we got a link. If we had it due to a forced
+ * fallback, and we were configured for autoneg, we do
+ * retry a short autoneg pass. If you know your hub is
+ * broken, use ethtool ;)
+ */
+ if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) {
+ gp->lstate = link_force_ret;
+ gp->link_fcntl = phy_read(gp, MII_BMCR);
+ gp->timer_ticks = 5;
+ printk(KERN_INFO "%s: Got link after fallback, retrying autoneg"
+ " once...\n", gp->dev->name);
+ phy_write(gp, MII_BMCR,
+ gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART);
+ } else if (gp->lstate != link_up) {
+ gp->lstate = link_up;
+ if (gp->opened)
+ gem_set_link_modes(gp);
+ }
} else {
- restart_timer = gem_mdio_link_not_up(gp);
+ int restart = 0;
+
+ /* If the link was previously up, we restart the
+ * whole process
+ */
+ if (gp->lstate == link_up) {
+ gp->lstate = link_down;
+ printk(KERN_INFO "%s: Link down\n", gp->dev->name);
+ gp->reset_task_pending = 1;
+ schedule_task(&gp->reset_task);
+ restart = 1;
+ } else if (++gp->timer_ticks > 10)
+ restart = gem_mdio_link_not_up(gp);
+
+ if (restart) {
+ spin_unlock_irq(&gp->lock);
+ gem_begin_auto_negotiation(gp, NULL);
+ return;
+ }
}
} else {
u32 val = readl(gp->regs + PCS_MIISTAT);
if (!(val & PCS_MIISTAT_LS))
val = readl(gp->regs + PCS_MIISTAT);
- if ((val & PCS_MIISTAT_LS) == 0) {
- restart_timer = 1;
- } else {
- gem_set_link_modes(gp);
+ if ((val & PCS_MIISTAT_LS) != 0) {
+ gp->lstate = link_up;
+ if (gp->opened)
+ gem_set_link_modes(gp);
}
}
- if (restart_timer) {
- gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
- add_timer(&gp->link_timer);
- }
+restart:
+ gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
+ add_timer(&gp->link_timer);
+ spin_unlock_irq(&gp->lock);
}
static void gem_clean_rings(struct gem *gp)
}
}
-static int
-gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
+static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
{
u16 val;
int limit = 10000;
- val = __phy_read(gp, PHY_CTRL, phy_addr);
- val &= ~PHY_CTRL_ISO;
- val |= PHY_CTRL_RST;
- __phy_write(gp, PHY_CTRL, val, phy_addr);
+ val = __phy_read(gp, MII_BMCR, phy_addr);
+ val &= ~BMCR_ISOLATE;
+ val |= BMCR_RESET;
+ __phy_write(gp, MII_BMCR, val, phy_addr);
udelay(100);
while (limit--) {
- val = __phy_read(gp, PHY_CTRL, phy_addr);
- if ((val & PHY_CTRL_RST) == 0)
+ val = __phy_read(gp, MII_BMCR, phy_addr);
+ if ((val & BMCR_RESET) == 0)
break;
udelay(10);
}
- if ((val & PHY_CTRL_ISO) && limit > 0)
- __phy_write(gp, PHY_CTRL, val & ~PHY_CTRL_ISO, phy_addr);
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ __phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr);
return (limit <= 0);
}
-static void
-gem_init_bcm5400_phy(struct gem *gp)
+static void gem_init_bcm5201_phy(struct gem *gp)
+{
+ u16 data;
+
+ data = phy_read(gp, MII_BCM5201_MULTIPHY);
+ data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
+ phy_write(gp, MII_BCM5201_MULTIPHY, data);
+}
+
+static void gem_init_bcm5400_phy(struct gem *gp)
{
u16 data;
/* Configure for gigabit full duplex */
- data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
- data |= PHY_BCM5400_AUXCONTROL_PWR10BASET;
- phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+ data = phy_read(gp, MII_BCM5400_AUXCONTROL);
+ data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(gp, MII_BCM5400_AUXCONTROL, data);
- data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
- data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
- phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+ data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(gp, MII_BCM5400_GB_CONTROL, data);
mdelay(10);
/* Reset and configure cascaded 10/100 PHY */
gem_reset_one_mii_phy(gp, 0x1f);
- data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
- data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
- __phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+ data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
- data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
- data &= ~PHY_BCM5400_AUXCONTROL_PWR10BASET;
- phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+ data = phy_read(gp, MII_BCM5400_AUXCONTROL);
+ data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(gp, MII_BCM5400_AUXCONTROL, data);
}
-static void
-gem_init_bcm5401_phy(struct gem *gp)
+static void gem_init_bcm5401_phy(struct gem *gp)
{
u16 data;
int rev;
- rev = phy_read(gp, PHY_ID1) & 0x000f;
+ rev = phy_read(gp, MII_PHYSID2) & 0x000f;
if (rev == 0 || rev == 3) {
/* Some revisions of 5401 appear to need this
* initialisation sequence to disable, according
}
/* Configure for gigabit full duplex */
- data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
- data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
- phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+ data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(gp, MII_BCM5400_GB_CONTROL, data);
mdelay(1);
/* Reset and configure cascaded 10/100 PHY */
gem_reset_one_mii_phy(gp, 0x1f);
- data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
- data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
- __phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+ data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
}
-static void
-gem_init_bcm5411_phy(struct gem *gp)
+static void gem_init_bcm5411_phy(struct gem *gp)
{
u16 data;
/* Here, Apple seems to want to reset it, do
* it as well
*/
- phy_write(gp, PHY_CTRL, PHY_CTRL_RST);
+ phy_write(gp, MII_BMCR, BMCR_RESET);
/* Start autoneg */
- phy_write(gp, PHY_CTRL,
- (PHY_CTRL_ANENAB | PHY_CTRL_FDPLX |
- PHY_CTRL_ANRES | PHY_CTRL_SPD2));
+ phy_write(gp, MII_BMCR,
+ (BMCR_ANENABLE | BMCR_FULLDPLX |
+ BMCR_ANRESTART | BMCR_SPD2));
- data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
- data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
- phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+ data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(gp, MII_BCM5400_GB_CONTROL, data);
}
static void gem_init_phy(struct gem *gp)
{
+ u32 mifcfg;
+
+ if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
+ phy_write(gp, MII_BCM5201_INTERRUPT, 0);
+
+ /* Revert MIF CFG setting done on stop_phy */
+ mifcfg = readl(gp->regs + MIF_CFG);
+ mifcfg &= ~MIF_CFG_BBMODE;
+ writel(mifcfg, gp->regs + MIF_CFG);
+
#ifdef CONFIG_ALL_PPC
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
int i;
pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
for (i = 0; i < 32; i++) {
gp->mii_phy_addr = i;
- if (phy_read(gp, PHY_CTRL) != 0xffff)
+ if (phy_read(gp, MII_BMCR) != 0xffff)
break;
}
if (i == 32) {
/* Take PHY out of isloate mode and reset it. */
gem_reset_one_mii_phy(gp, gp->mii_phy_addr);
- phy_id = (phy_read(gp, PHY_ID0) << 16 | phy_read(gp, PHY_ID1))
+ phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2))
& 0xfffffff0;
printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id);
switch(phy_id) {
- case 0x406210:
- gp->phy_mod = phymod_bcm5201;
- printk("BCM 5201\n");
- break;
- case 0x4061e0:
- printk("BCM 5221\n");
- gp->phy_mod = phymod_bcm5221;
- break;
- case 0x206040:
- printk("BCM 5400\n");
- gp->phy_mod = phymod_bcm5400;
- gem_init_bcm5400_phy(gp);
- break;
- case 0x206050:
- printk("BCM 5401\n");
- gp->phy_mod = phymod_bcm5401;
- gem_init_bcm5401_phy(gp);
- break;
- case 0x206070:
- printk("BCM 5411\n");
- gp->phy_mod = phymod_bcm5411;
- gem_init_bcm5411_phy(gp);
- break;
- default:
- printk("Generic\n");
- gp->phy_mod = phymod_generic;
+ case 0x406210:
+ gp->phy_mod = phymod_bcm5201;
+ gem_init_bcm5201_phy(gp);
+ printk("BCM 5201\n");
+ break;
+
+ case 0x4061e0:
+ printk("BCM 5221\n");
+ gp->phy_mod = phymod_bcm5221;
+ break;
+
+ case 0x206040:
+ printk("BCM 5400\n");
+ gp->phy_mod = phymod_bcm5400;
+ gem_init_bcm5400_phy(gp);
+ gp->gigabit_capable = 1;
+ break;
+
+ case 0x206050:
+ printk("BCM 5401\n");
+ gp->phy_mod = phymod_bcm5401;
+ gem_init_bcm5401_phy(gp);
+ gp->gigabit_capable = 1;
+ break;
+
+ case 0x206070:
+ printk("BCM 5411\n");
+ gp->phy_mod = phymod_bcm5411;
+ gem_init_bcm5411_phy(gp);
+ gp->gigabit_capable = 1;
+ break;
+
+ case 0x18074c0:
+ printk("Lucent\n");
+ gp->phy_mod = phymod_generic;
+ break;
+
+ case 0x437420:
+ printk("Enable Semiconductor\n");
+ gp->phy_mod = phymod_generic;
+ break;
+
+ default:
+ printk("Unknown\n");
+ gp->phy_mod = phymod_generic;
+ break;
};
/* Init advertisement and enable autonegotiation. */
- val = phy_read(gp, PHY_CTRL);
- val &= ~PHY_CTRL_ANENAB;
- phy_write(gp, PHY_CTRL, val);
+ val = phy_read(gp, MII_BMCR);
+ val &= ~BMCR_ANENABLE;
+ phy_write(gp, MII_BMCR, val);
udelay(10);
- phy_write(gp, PHY_ADV,
- phy_read(gp, PHY_ADV) |
- (PHY_ADV_10HALF | PHY_ADV_10FULL |
- PHY_ADV_100HALF | PHY_ADV_100FULL));
-
- val = phy_read(gp, PHY_CTRL);
- val |= PHY_CTRL_ANENAB;
- phy_write(gp, PHY_CTRL, val);
- val |= PHY_CTRL_ANRES;
- phy_write(gp, PHY_CTRL, val);
+ phy_write(gp, MII_ADVERTISE,
+ phy_read(gp, MII_ADVERTISE) |
+ (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL));
} else {
u32 val;
int limit;
else
val |= PCS_SCTRL_LOOP;
writel(val, gp->regs + PCS_SCTRL);
+ gp->gigabit_capable = 1;
}
}
writel(desc_dma >> 32, gp->regs + TXDMA_DBHI);
writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW);
- desc_dma += (TX_RING_SIZE * sizeof(struct gem_txd));
+ desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
writel(0, gp->regs + TXDMA_KICK);
writel(val, gp->regs + RXDMA_PTHRESH);
if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
- writel(((6 & RXDMA_BLANK_IPKTS) |
- ((4 << 12) & RXDMA_BLANK_ITIME)),
+ writel(((5 & RXDMA_BLANK_IPKTS) |
+ ((8 << 12) & RXDMA_BLANK_ITIME)),
gp->regs + RXDMA_BLANK);
else
- writel(((6 & RXDMA_BLANK_IPKTS) |
- ((2 << 12) & RXDMA_BLANK_ITIME)),
+ writel(((5 & RXDMA_BLANK_IPKTS) |
+ ((4 << 12) & RXDMA_BLANK_ITIME)),
gp->regs + RXDMA_BLANK);
}
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void gem_init_mac(struct gem *gp)
{
unsigned char *e = &gp->dev->dev_addr[0];
rxcfg |= MAC_RXCFG_PROM;
} else {
u16 hash_table[16];
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
struct dev_mc_list *dmi = gp->dev->mc_list;
- int i, j, bit, byte;
+ int i;
for (i = 0; i < 16; i++)
hash_table[i] = 0;
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 24;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
writel(0, gp->regs + MAC_MCCFG);
writel(0, gp->regs + MAC_XIFCFG);
- writel((MAC_TXSTAT_URUN | MAC_TXSTAT_MPE |
- MAC_TXSTAT_NCE | MAC_TXSTAT_ECE |
- MAC_TXSTAT_LCE | MAC_TXSTAT_FCE |
- MAC_TXSTAT_DTE | MAC_TXSTAT_PCE), gp->regs + MAC_TXMASK);
- writel((MAC_RXSTAT_OFLW | MAC_RXSTAT_FCE |
- MAC_RXSTAT_ACE | MAC_RXSTAT_CCE |
- MAC_RXSTAT_LCE | MAC_RXSTAT_VCE), gp->regs + MAC_RXMASK);
- writel(0, gp->regs + MAC_MCMASK);
+ /* Setup MAC interrupts. We want to get all of the interesting
+ * counter expiration events, but we do not want to hear about
+ * normal rx/tx as the DMA engine tells us that.
+ */
+ writel(MAC_TXSTAT_XMIT, gp->regs + MAC_TXMASK);
+ writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
+
+ /* Don't enable even the PAUSE interrupts for now, we
+ * make no use of those events other than to record them.
+ */
+ writel(0xffffffff, gp->regs + MAC_MCMASK);
}
-static void
-gem_init_pause_thresholds(struct gem* gp)
+static void gem_init_pause_thresholds(struct gem *gp)
{
/* Calculate pause thresholds. Setting the OFF threshold to the
* full RX fifo size effectively disables PAUSE generation which
}
{
- u32 cfg = readl(gp->regs + GREG_BIFCFG);
-
- /* XXX Why do I do this? -DaveM XXX */
- cfg |= GREG_BIFCFG_B64DIS;
- writel(cfg, gp->regs + GREG_BIFCFG);
+ u32 cfg;
cfg = GREG_CFG_IBURST;
cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
struct pci_dev *pdev = gp->pdev;
u32 mif_cfg;
- /* On Apple's sungem, we can't realy on registers as the chip
+ /* On Apple's sungem, we can't rely on registers as the chip
* was been powered down by the firmware. We do the PHY lookup
* when the interface is opened and we configure the driver
* with known values.
*/
if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
gp->phy_type = phy_mii_mdio0;
- mif_cfg = readl(gp->regs + MIF_CFG);
- mif_cfg &= ~MIF_CFG_PSELECT;
- writel(mif_cfg, gp->regs + MIF_CFG);
- writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
- writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
- gem_init_pause_thresholds(gp);
return 0;
}
for (i = 0; i < 32; i++) {
gp->mii_phy_addr = i;
- if (phy_read(gp, PHY_CTRL) != 0xffff)
+ if (phy_read(gp, MII_BMCR) != 0xffff)
break;
}
if (i == 32) {
}
}
- gem_init_pause_thresholds(gp);
-
return 0;
}
-static void gem_init_hw(struct gem *gp)
+static void gem_init_hw(struct gem *gp, int restart_link)
{
/* On Apple's gmac, I initialize the PHY only after
* setting up the chip. It appears the gigabit PHYs
* the chip is not running, I suspect it might not
* be clocked at that point. --BenH
*/
- if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
- gem_check_invariants(gp);
- gp->hw_running = 1;
- }
- gem_init_phy(gp);
+ if (restart_link)
+ gem_init_phy(gp);
gem_init_dma(gp);
gem_init_mac(gp);
+ gem_init_pause_thresholds(gp);
- gp->timer_ticks = 0;
- gp->lstate = aneg_wait;
- gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
- add_timer(&gp->link_timer);
+ spin_lock_irq(&gp->lock);
+ if (restart_link) {
+ /* Default aneg parameters */
+ gp->timer_ticks = 0;
+ gp->lstate = link_down;
+
+ spin_unlock_irq(&gp->lock);
+
+ /* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+ gem_begin_auto_negotiation(gp, NULL);
+ } else {
+ if (gp->lstate == link_up)
+ gem_set_link_modes(gp);
+
+ spin_unlock_irq(&gp->lock);
+ }
}
#ifdef CONFIG_ALL_PPC
* setup properly. There appear to be no need to restore the
* base addresses.
*/
-static void
-gem_apple_powerup(struct gem* gp)
+static void gem_apple_powerup(struct gem *gp)
{
u16 cmd;
+ u32 mif_cfg;
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
pci_write_config_word(gp->pdev, PCI_COMMAND, cmd);
pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6);
pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8);
+
+ mdelay(1);
+
+ mif_cfg = readl(gp->regs + MIF_CFG);
+ mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1);
+ mif_cfg |= MIF_CFG_MDI0;
+ writel(mif_cfg, gp->regs + MIF_CFG);
+ writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+ writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+
+ mdelay(1);
}
/* Turn off the chip's clock */
-static void
-gem_apple_powerdown(struct gem* gp)
+static void gem_apple_powerdown(struct gem *gp)
{
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
}
+
#endif /* CONFIG_ALL_PPC */
+static void gem_stop_phy(struct gem *gp)
+{
+ u32 mifcfg;
+
+ if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
+ phy_write(gp, MII_BCM5201_INTERRUPT, 0);
+
+ /* Make sure we aren't polling PHY status change. We
+ * don't currently use that feature though
+ */
+ mifcfg = readl(gp->regs + MIF_CFG);
+ mifcfg &= ~MIF_CFG_POLL;
+ writel(mifcfg, gp->regs + MIF_CFG);
+
+ /* Here's a strange hack used by both MacOS 9 and X */
+ phy_write(gp, MII_LPA, phy_read(gp, MII_LPA));
+
+ if (gp->wake_on_lan) {
+ /* Setup wake-on-lan */
+ } else
+ writel(0, gp->regs + MAC_RXCFG);
+ writel(0, gp->regs + MAC_TXCFG);
+ writel(0, gp->regs + MAC_XIFCFG);
+ writel(0, gp->regs + TXDMA_CFG);
+ writel(0, gp->regs + RXDMA_CFG);
+
+ if (!gp->wake_on_lan) {
+ gem_stop(gp);
+ writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST);
+ writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
+ if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 ||
+ gp->phy_mod == phymod_bcm5411) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+ phy_write(gp, MII_BMCR, BMCR_PDOWN);
+#endif
+ } else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+ u16 val = phy_read(gp, MII_BCM5201_AUXMODE2)
+ phy_write(gp, MII_BCM5201_AUXMODE2,
+ val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
+#endif
+ phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+ }
+
+ /* According to Apple, we must set the MDIO pins to this begnign
+ * state or we may 1) eat more current, 2) damage some PHYs
+ */
+ writel(mifcfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG);
+ writel(0, gp->regs + MIF_BBCLK);
+ writel(0, gp->regs + MIF_BBDATA);
+ writel(0, gp->regs + MIF_BBOENAB);
+ writel(MAC_XIFCFG_GMII | MAC_XIFCFG_LBCK, gp->regs + MAC_XIFCFG);
+ (void) readl(gp->regs + MAC_XIFCFG);
+ }
+}
+
+/* Shut down the chip, must be called with pm_sem held. */
+static void gem_shutdown(struct gem *gp)
+{
+ /* Make us not-running to avoid timers respawning */
+ gp->hw_running = 0;
+
+ /* Stop the link timer */
+ del_timer_sync(&gp->link_timer);
+
+ /* Stop the reset task */
+ while (gp->reset_task_pending)
+ schedule();
+
+ /* Actually stop the chip */
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ gem_stop_phy(gp);
+ else
+ gem_stop(gp);
+
+#ifdef CONFIG_ALL_PPC
+ /* Power down the chip */
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ gem_apple_powerdown(gp);
+#endif /* CONFIG_ALL_PPC */
+}
+
+static void gem_pm_task(void *data)
+{
+ struct gem *gp = (struct gem *) data;
+
+ /* We assume if we can't lock the pm_sem, then open() was
+ * called again (or suspend()), and we can safely ignore
+ * the PM request
+ */
+ if (down_trylock(&gp->pm_sem))
+ return;
+
+ /* Driver was re-opened or already shut down */
+ if (gp->opened || !gp->hw_running) {
+ up(&gp->pm_sem);
+ return;
+ }
+
+ gem_shutdown(gp);
+
+ up(&gp->pm_sem);
+}
+
+static void gem_pm_timer(unsigned long data)
+{
+ struct gem *gp = (struct gem *) data;
+
+ schedule_task(&gp->pm_task);
+}
+
static int gem_open(struct net_device *dev)
{
struct gem *gp = dev->priv;
- unsigned long regs = gp->regs;
+ int hw_was_up = gp->hw_running;
- del_timer(&gp->link_timer);
+ down(&gp->pm_sem);
+ /* Stop the PM timer/task */
+ del_timer(&gp->pm_timer);
+ flush_scheduled_tasks();
+
+ if (!gp->hw_running) {
#ifdef CONFIG_ALL_PPC
- /* First, we need to bring up the chip */
- if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
- gem_apple_powerup(gp);
+ /* First, we need to bring up the chip */
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ gem_apple_powerup(gp);
+ gem_check_invariants(gp);
+ }
#endif /* CONFIG_ALL_PPC */
+ /* Reset the chip */
+ gem_stop(gp);
- /* Reset the chip */
- gem_stop(gp, regs);
+ gp->hw_running = 1;
+ }
/* We can now request the interrupt as we know it's masked
* on the controller
if (request_irq(gp->pdev->irq, gem_interrupt,
SA_SHIRQ, dev->name, (void *)dev)) {
#ifdef CONFIG_ALL_PPC
- if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerdown(gp);
#endif /* CONFIG_ALL_PPC */
+ /* Fire the PM timer that will shut us down in about 10 seconds */
+ gp->pm_timer.expires = jiffies + 10*HZ;
+ add_timer(&gp->pm_timer);
+ up(&gp->pm_sem);
+
return -EAGAIN;
}
gem_init_rings(gp, 0);
/* Init & setup chip hardware */
- gem_init_hw(gp);
+ gem_init_hw(gp, !hw_was_up);
+
+ gp->opened = 1;
+
+ up(&gp->pm_sem);
return 0;
}
{
struct gem *gp = dev->priv;
- del_timer(&gp->link_timer);
- gem_stop(gp, gp->regs);
+ /* Make sure we don't get distracted by suspend/resume */
+ down(&gp->pm_sem);
+
+ /* Stop traffic, mark us closed */
+ spin_lock_irq(&gp->lock);
+
+ gp->opened = 0;
+ writel(0xffffffff, gp->regs + GREG_IMASK);
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&gp->lock);
+
+ /* Stop chip */
+ gem_stop(gp);
+
+ /* Get rid of rings */
gem_clean_rings(gp);
- gp->hw_running = 0;
+
+ /* Bye, the pm timer will finish the job */
+ free_irq(gp->pdev->irq, (void *) dev);
+
+ /* Fire the PM timer that will shut us down in about 10 seconds */
+ gp->pm_timer.expires = jiffies + 10*HZ;
+ add_timer(&gp->pm_timer);
+
+ up(&gp->pm_sem);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gem_suspend(struct pci_dev *pdev, u32 state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct gem *gp = dev->priv;
+
+ /* We hold the PM semaphore during entire driver
+ * sleep time
+ */
+ down(&gp->pm_sem);
+
+ printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
+ dev->name, gp->wake_on_lan ? "enabled" : "disabled");
+
+ /* If the driver is opened, we stop the DMA */
+ if (gp->opened) {
+ /* Stop traffic, mark us closed */
+ netif_device_detach(dev);
+
+ spin_lock_irq(&gp->lock);
+
+ writel(0xffffffff, gp->regs + GREG_IMASK);
+
+ spin_unlock_irq(&gp->lock);
+
+ /* Stop chip */
+ gem_stop(gp);
+
+ /* Get rid of ring buffers */
+ gem_clean_rings(gp);
+
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ disable_irq(gp->pdev->irq);
+ }
+
+ if (gp->hw_running) {
+ /* Kill PM timer if any */
+ del_timer_sync(&gp->pm_timer);
+ flush_scheduled_tasks();
+
+ gem_shutdown(gp);
+ }
+
+ return 0;
+}
+
+static int gem_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct gem *gp = dev->priv;
+
+ printk(KERN_INFO "%s: resuming\n", dev->name);
+
+ if (gp->opened) {
#ifdef CONFIG_ALL_PPC
- if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
- gem_apple_powerdown(gp);
+ /* First, we need to bring up the chip */
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ gem_apple_powerup(gp);
+ gem_check_invariants(gp);
+ }
#endif /* CONFIG_ALL_PPC */
- free_irq(gp->pdev->irq, (void *)dev);
+ gem_stop(gp);
+ gp->hw_running = 1;
+ gem_init_rings(gp, 0);
+ gem_init_hw(gp, 1);
+ netif_device_attach(dev);
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ enable_irq(gp->pdev->irq);
+ }
+ up(&gp->pm_sem);
+
return 0;
}
+#endif /* CONFIG_PM */
static struct net_device_stats *gem_get_stats(struct net_device *dev)
{
writel(rxcfg, gp->regs + MAC_RXCFG);
} else {
u16 hash_table[16];
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
struct dev_mc_list *dmi = gp->dev->mc_list;
- int i, j, bit, byte;
+ int i;
for (i = 0; i < 16; i++)
hash_table[i] = 0;
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 24;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
writel(hash_table[15], gp->regs + MAC_HASH15);
}
+ /* Hrm... we may walk on the reset task here... */
netif_wake_queue(dev);
}
+/* Eventually add support for changing the advertisement
+ * on autoneg.
+ */
+static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
+{
+ struct gem *gp = dev->priv;
+ u16 bmcr;
+ int full_duplex, speed, pause;
+ struct ethtool_cmd ecmd;
+
+ if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
+ return -EFAULT;
+
+ switch(ecmd.cmd) {
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = { cmd: ETHTOOL_GDRVINFO };
+
+ strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
+ strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
+ info.fw_version[0] = '\0';
+ strncpy(info.bus_info, gp->pdev->slot_name, ETHTOOL_BUSINFO_LEN);
+ info.regdump_len = 0; /*SUNGEM_NREGS;*/
+
+ if (copy_to_user(ep_user, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ case ETHTOOL_GSET:
+ ecmd.supported =
+ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+ if (gp->gigabit_capable)
+ ecmd.supported |=
+ (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+
+ /* XXX hardcoded stuff for now */
+ ecmd.port = PORT_MII;
+ ecmd.transceiver = XCVR_EXTERNAL;
+ ecmd.phy_address = 0; /* XXX fixed PHYAD */
+
+ /* Record PHY settings if HW is on. */
+ if (gp->hw_running) {
+ bmcr = phy_read(gp, MII_BMCR);
+ gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
+ } else
+ bmcr = 0;
+ if (bmcr & BMCR_ANENABLE) {
+ ecmd.autoneg = AUTONEG_ENABLE;
+ ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
+ ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ ecmd.autoneg = AUTONEG_DISABLE;
+ ecmd.speed =
+ (bmcr & BMCR_SPEED100) ?
+ SPEED_100 : SPEED_10;
+ ecmd.duplex =
+ (bmcr & BMCR_FULLDPLX) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+ if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+
+ case ETHTOOL_SSET:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Verify the settings we care about. */
+ if (ecmd.autoneg != AUTONEG_ENABLE &&
+ ecmd.autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+
+ if (ecmd.autoneg == AUTONEG_DISABLE &&
+ ((ecmd.speed != SPEED_100 &&
+ ecmd.speed != SPEED_10) ||
+ (ecmd.duplex != DUPLEX_HALF &&
+ ecmd.duplex != DUPLEX_FULL)))
+ return -EINVAL;
+
+ /* Apply settings and restart link process */
+ if (gp->hw_running)
+ del_timer(&gp->link_timer);
+ gem_begin_auto_negotiation(gp, &ecmd);
+ return 0;
+
+ case ETHTOOL_NWAY_RST:
+ if ((gp->link_cntl & BMCR_ANENABLE) == 0)
+ return -EINVAL;
+ if (gp->hw_running)
+ del_timer(&gp->link_timer);
+ gem_begin_auto_negotiation(gp, NULL);
+ return 0;
+
+ case ETHTOOL_GWOL:
+ case ETHTOOL_SWOL:
+ break; /* todo */
+
+ /* get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = { cmd: ETHTOOL_GLINK };
+
+ edata.data = (gp->lstate == link_up);
+ if (copy_to_user(ep_user, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get message-level */
+ case ETHTOOL_GMSGLVL: {
+ struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL };
+
+ edata.data = gem_debug;
+ if (copy_to_user(ep_user, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* set message-level */
+ case ETHTOOL_SMSGLVL: {
+ struct ethtool_value edata;
+
+ if (copy_from_user(&edata, ep_user, sizeof(edata)))
+ return -EFAULT;
+ gem_debug = edata.data;
+ return 0;
+ }
+
+#if 0
+ case ETHTOOL_GREGS: {
+ struct ethtool_regs regs;
+ u32 *regbuf;
+ int r = 0;
+
+ if (copy_from_user(®s, useraddr, sizeof(regs)))
+ return -EFAULT;
+
+ if (regs.len > SUNGEM_NREGS) {
+ regs.len = SUNGEM_NREGS;
+ }
+ regs.version = 0;
+ if (copy_to_user(useraddr, ®s, sizeof(regs)))
+ return -EFAULT;
+
+ if (!gp->hw_running)
+ return -ENODEV;
+ useraddr += offsetof(struct ethtool_regs, data);
+
+ /* Use kmalloc to avoid bloating the stack */
+ regbuf = kmalloc(4 * SUNGEM_NREGS, GFP_KERNEL);
+ if (!regbuf)
+ return -ENOMEM;
+ spin_lock_irq(&np->lock);
+ gem_get_regs(gp, regbuf);
+ spin_unlock_irq(&np->lock);
+
+ if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32)))
+ r = -EFAULT;
+ kfree(regbuf);
+ return r;
+ }
+#endif
+ };
+
+ return -EOPNOTSUPP;
+}
+
static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- return -EINVAL;
+ struct gem *gp = dev->priv;
+ struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+ int rc = -EOPNOTSUPP;
+
+ /* Hold the PM semaphore while doing ioctl's or we may collide
+ * with open/close and power management and oops.
+ */
+ down(&gp->pm_sem);
+
+ switch (cmd) {
+ case SIOCETHTOOL:
+ rc = gem_ethtool_ioctl(dev, ifr->ifr_data);
+ break;
+
+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
+ data->phy_id = gp->mii_phy_addr;
+ /* Fallthrough... */
+
+ case SIOCGMIIREG: /* Read MII PHY register. */
+ data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f);
+ rc = 0;
+ break;
+
+ case SIOCSMIIREG: /* Write MII PHY register. */
+ if (!capable(CAP_NET_ADMIN)) {
+ rc = -EPERM;
+ } else {
+ __phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f);
+ rc = 0;
+ }
+ break;
+ };
+
+ up(&gp->pm_sem);
+
+ return rc;
}
static int __devinit gem_get_device_address(struct gem *gp)
gp->dev = dev;
spin_lock_init(&gp->lock);
+ init_MUTEX(&gp->pm_sem);
+
+ init_timer(&gp->link_timer);
+ gp->link_timer.function = gem_link_timer;
+ gp->link_timer.data = (unsigned long) gp;
+
+ init_timer(&gp->pm_timer);
+ gp->pm_timer.function = gem_pm_timer;
+ gp->pm_timer.data = (unsigned long) gp;
+
+ INIT_TQUEUE(&gp->pm_task, gem_pm_task, gp);
+ INIT_TQUEUE(&gp->reset_task, gem_reset_task, gp);
+
+ /* Default link parameters */
+ if (link_mode >= 0 && link_mode <= 6)
+ gp->link_cntl = link_modes[link_mode];
+ else
+ gp->link_cntl = BMCR_ANENABLE;
+ gp->lstate = link_down;
+ gp->timer_ticks = 0;
gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len);
if (gp->regs == 0UL) {
goto err_out_free_mmio_res;
}
- /* On Apple's, we might not access the hardware at that point */
+ /* On Apple, we power the chip up now in order for check
+ * invariants to work, but also because the firmware might
+ * not have properly shut down the PHY.
+ */
+#ifdef CONFIG_ALL_PPC
+ if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ gem_apple_powerup(gp);
+ if (gem_check_invariants(gp))
+ goto err_out_iounmap;
+ gem_stop(gp);
+ gp->hw_running = 1;
+ gem_init_phy(gp);
+ gem_begin_auto_negotiation(gp, NULL);
+ }
+#endif
+ /* Non Apple hardware, we just reset the chip and check
+ * for invariants
+ */
if (pdev->vendor != PCI_VENDOR_ID_APPLE) {
- gem_stop(gp, gp->regs);
+ gem_stop(gp);
if (gem_check_invariants(gp))
goto err_out_iounmap;
gp->hw_running = 1;
i == 5 ? ' ' : ':');
printk("\n");
- init_timer(&gp->link_timer);
- gp->link_timer.function = gem_link_timer;
- gp->link_timer.data = (unsigned long) gp;
-
dev->open = gem_open;
dev->stop = gem_close;
dev->hard_start_xmit = gem_start_xmit;
if (pci_using_dac)
dev->features |= NETIF_F_HIGHDMA;
+ /* Fire the PM timer that will shut us down in about 10 seconds */
+ gp->pm_timer.expires = jiffies + 10*HZ;
+ add_timer(&gp->pm_timer);
+
return 0;
err_out_iounmap:
+ down(&gp->pm_sem);
+ /* Stop the PM timer & task */
+ del_timer_sync(&gp->pm_timer);
+ flush_scheduled_tasks();
+ if (gp->hw_running)
+ gem_shutdown(gp);
+ up(&gp->pm_sem);
iounmap((void *) gp->regs);
err_out_free_mmio_res:
unregister_netdev(dev);
+ down(&gp->pm_sem);
+ /* Stop the PM timer & task */
+ del_timer_sync(&gp->pm_timer);
+ flush_scheduled_tasks();
+ if (gp->hw_running)
+ gem_shutdown(gp);
+ up(&gp->pm_sem);
+
pci_free_consistent(pdev,
sizeof(struct gem_init_block),
gp->init_block,
iounmap((void *) gp->regs);
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
-#ifdef CONFIG_ALL_PPC
- pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
-#endif
kfree(dev);
pci_set_drvdata(pdev, NULL);
name: GEM_MODULE_NAME,
id_table: gem_pci_tbl,
probe: gem_init_one,
- remove: gem_remove_one,
+ remove: __devexit_p(gem_remove_one),
+#ifdef CONFIG_PM
+ suspend: gem_suspend,
+ resume: gem_resume,
+#endif /* CONFIG_PM */
};
static int __init gem_init(void)
-/* $Id: sungem.h,v 1.8 2001/10/17 05:55:39 davem Exp $
+/* $Id: sungem.h,v 1.10 2001/11/29 03:57:33 davem Exp $
* sungem.h: Definitions for Sun GEM ethernet driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
#define PROM_SIZE 0x0fffffUL /* Size of ROM */
#define PROM_END 0x200000UL /* End of ROM */
-/* MII phy registers */
-#define PHY_CTRL 0x00
-#define PHY_STAT 0x01
-#define PHY_ID0 0x02
-#define PHY_ID1 0x03
-#define PHY_ADV 0x04
-#define PHY_LPA 0x05
-
-#define PHY_CTRL_SPD2 0x0040 /* Gigabit enable? (bcm5411) */
-#define PHY_CTRL_FDPLX 0x0100 /* Full duplex */
-#define PHY_CTRL_ISO 0x0400 /* Isloate MII from PHY */
-#define PHY_CTRL_ANRES 0x0200 /* Auto-negotiation restart */
-#define PHY_CTRL_ANENAB 0x1000 /* Auto-negotiation enable */
-#define PHY_CTRL_SPD100 0x2000 /* Select 100Mbps */
-#define PHY_CTRL_RST 0x8000 /* Reset PHY */
-
-#define PHY_STAT_LSTAT 0x0004 /* Link status */
-#define PHY_STAT_ANEGC 0x0020 /* Auto-negotiation complete */
-
-#define PHY_ADV_10HALF 0x0020
-#define PHY_ADV_10FULL 0x0040
-#define PHY_ADV_100HALF 0x0080
-#define PHY_ADV_100FULL 0x0100
-
-#define PHY_LPA_10HALF 0x0020
-#define PHY_LPA_10FULL 0x0040
-#define PHY_LPA_100HALF 0x0080
-#define PHY_LPA_100FULL 0x0100
-#define PHY_LPA_PAUSE 0x0400
-#define PHY_LPA_FAULT 0x2000
+/* MII definitions missing from mii.h */
+
+#define BMCR_SPD2 0x0040 /* Gigabit enable? (bcm5411) */
+#define LPA_PAUSE 0x0400
/* More PHY registers (specific to Broadcom models) */
/* MII BCM5201 MULTIPHY interrupt register */
-#define PHY_BCM5201_INTERRUPT 0x1A
-#define PHY_BCM5201_INTERRUPT_INTENABLE 0x4000
+#define MII_BCM5201_INTERRUPT 0x1A
+#define MII_BCM5201_INTERRUPT_INTENABLE 0x4000
-#define PHY_BCM5201_AUXMODE2 0x1B
-#define PHY_BCM5201_AUXMODE2_LOWPOWER 0x0008
+#define MII_BCM5201_AUXMODE2 0x1B
+#define MII_BCM5201_AUXMODE2_LOWPOWER 0x0008
-#define PHY_BCM5201_MULTIPHY 0x1E
+#define MII_BCM5201_MULTIPHY 0x1E
/* MII BCM5201 MULTIPHY register bits */
-#define PHY_BCM5201_MULTIPHY_SERIALMODE 0x0002
-#define PHY_BCM5201_MULTIPHY_SUPERISOLATE 0x0008
+#define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002
+#define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008
/* MII BCM5400 1000-BASET Control register */
-#define PHY_BCM5400_GB_CONTROL 0x09
-#define PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200
+#define MII_BCM5400_GB_CONTROL 0x09
+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200
/* MII BCM5400 AUXCONTROL register */
-#define PHY_BCM5400_AUXCONTROL 0x18
-#define PHY_BCM5400_AUXCONTROL_PWR10BASET 0x0004
+#define MII_BCM5400_AUXCONTROL 0x18
+#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004
/* MII BCM5400 AUXSTATUS register */
-#define PHY_BCM5400_AUXSTATUS 0x19
-#define PHY_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
-#define PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+#define MII_BCM5400_AUXSTATUS 0x19
+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
/* When it can, GEM internally caches 4 aligned TX descriptors
* at a time, so that it can use full cacheline DMA reads.
#define RX_COPY_THRESHOLD 256
+#if TX_RING_SIZE < 128
+#define INIT_BLOCK_TX_RING_SIZE 128
+#else
+#define INIT_BLOCK_TX_RING_SIZE TX_RING_SIZE
+#endif
+
+#if RX_RING_SIZE < 128
+#define INIT_BLOCK_RX_RING_SIZE 128
+#else
+#define INIT_BLOCK_RX_RING_SIZE RX_RING_SIZE
+#endif
+
struct gem_init_block {
- struct gem_txd txd[TX_RING_SIZE];
- struct gem_rxd rxd[RX_RING_SIZE];
+ struct gem_txd txd[INIT_BLOCK_TX_RING_SIZE];
+ struct gem_rxd rxd[INIT_BLOCK_RX_RING_SIZE];
};
enum gem_phy_type {
};
enum link_state {
- aneg_wait,
- force_wait,
- aneg_up,
+ link_down = 0, /* No link, will retry */
+ link_aneg, /* Autoneg in progress */
+ link_force_try, /* Try Forced link speed */
+ link_force_ret, /* Forced mode worked, retrying autoneg */
+ link_force_ok, /* Stay in forced mode */
+ link_up /* Link is up */
};
struct gem {
* (ie. not power managed)
*/
int hw_running;
+ int opened;
+ struct semaphore pm_sem;
+ struct tq_struct pm_task;
+ struct timer_list pm_timer;
struct gem_init_block *init_block;
int rx_pause_off;
int rx_pause_on;
int mii_phy_addr;
-
+ int gigabit_capable;
+
+ /* Autoneg & PHY control */
+ int link_cntl;
+ int link_advertise;
+ int link_fcntl;
+ enum link_state lstate;
+ struct timer_list link_timer;
+ int timer_ticks;
+ int wake_on_lan;
+ struct tq_struct reset_task;
+ volatile int reset_task_pending;
+
/* Diagnostic counters and state. */
u64 pause_entered;
u16 pause_last_time_recvd;
- struct timer_list link_timer;
- int timer_ticks;
- enum link_state lstate;
-
dma_addr_t gblock_dvma;
struct pci_dev *pdev;
struct net_device *dev;
#include <linux/init.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
add_timer(&hp->happy_timer);
}
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static int happy_meal_init(struct happy_meal *hp, int from_irq)
{
unsigned long gregs = hp->gregs;
u16 hash_table[4];
struct dev_mc_list *dmi = hp->dev->mc_list;
char *addrs;
- int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ int i;
+ u32 crc;
for (i = 0; i < 4; i++)
hash_table[i] = 0;
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
unsigned long bregs = hp->bigmacregs;
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
- int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ int i;
+ u32 crc;
/* Lock out others. */
netif_stop_queue(dev);
if (!(*addrs & 1))
continue;
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
* Anton Blanchard (anton@progsoc.uts.edu.au)
* 2.00: 11/9/99: Massive overhaul and port to new SBUS driver interfaces.
* David S. Miller (davem@redhat.com)
+ * 2.01:
+ * 11/08/01: Use library crc32 functions (Matt_Domsch@dell.com)
+ *
*/
#undef DEBUG_DRIVER
static char version[] =
- "sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+ "sunlance.c:v2.01 08/Nov/01 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
static char lancestr[] = "LANCE";
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#define LANCE_LOG_RX_BUFFERS 4
#endif
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI) {
/* multicast address? */
if (!(*addrs & 1))
continue;
-
- crc = 0xffffffff;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
-
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc = crc >> 26;
if (lp->pio_buffer) {
u16 tmp = sbus_readw(&mcast_table[crc>>4]);
-/* $Id: sunqe.c,v 1.52 2001/10/18 08:18:08 davem Exp $
+/* $Id: sunqe.c,v 1.53 2001/12/21 00:54:31 davem Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/crc32.h>
#include <asm/system.h>
#include <asm/bitops.h>
spin_unlock(&qep->lock);
}
next:
+ ;
}
qec_status >>= 4;
channel++;
return &qep->net_stats;
}
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
static void qe_set_multicast(struct net_device *dev)
{
struct sunqe *qep = (struct sunqe *) dev->priv;
u8 new_mconfig = qep->mconfig;
char *addrs;
int i, j, bit, byte;
- u32 crc, poly = CRC_POLYNOMIAL_LE;
+ u32 crc;
/* Lock out others. */
netif_stop_queue(dev);
if (!(*addrs & 1))
continue;
-
- crc = 0xffffffffU;
- for (byte = 0; byte < 6; byte++) {
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- int test;
-
- test = ((bit ^ crc) & 0x01);
- crc >>= 1;
- if (test)
- crc = crc ^ poly;
- }
- }
+ crc = ether_crc_le(6, addrs);
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
#include <linux/delay.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
new frame, not around filling tp->setup_frame. This is non-deterministic
when re-entered but still correct. */
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
#undef set_bit_le
#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mii.h>
+#include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
readw(ioaddr + RxMissed);
}
-
-/* The big-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- return crc;
-}
-
static void via_rhine_set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/rtnetlink.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static void netdev_error(struct net_device *dev, int intr_status);
static int netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
static u32 __set_rx_mode(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
return &np->stats;
}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- return crc;
-}
static u32 __set_rx_mode(struct net_device *dev)
{
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/unaligned.h>
/* Set or clear the multicast filter for this adaptor. */
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-
-
static void set_rx_mode(struct net_device *dev)
{
struct yellowfin_private *yp = dev->priv;
static inline struct request *
dasd_next_request( request_queue_t *queue )
{
- return blkdev_entry_next_request(&queue->queue_head);
+ return elv_next_request(queue);
}
static inline void
dasd_dequeue_request( request_queue_t * q, struct request *req )
fault=0;
#if ( XPRAM_VERSION == 24 )
- current_req = blkdev_entry_next_request (&queue->queue_head);
+ current_req = CURRENT;
#endif /* V24 */
dev_no = DEVICE_NR(current_req->rq_dev);
/* Check if the minor number is in range */
static inline struct request *
tape_next_request( request_queue_t *queue )
{
- return blkdev_entry_next_request(&queue->queue_head);
+ return elv_next_request(queue);
}
static inline void
tape_dequeue_request( request_queue_t * q, struct request *req )
-/* $Id: audio.c,v 1.62 2001/10/08 22:19:50 davem Exp $
+/* $Id: audio.c,v 1.63 2002/01/08 16:00:21 davem Exp $
* drivers/sbus/audio/audio.c
*
* Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
{
unsigned int mask = 0;
struct inode *inode = file->f_dentry->d_inode;
- struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+ struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
SPARCAUDIO_DEVICE_SHIFT)];
poll_wait(file, &drv->input_read_wait, wait);
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+ struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
SPARCAUDIO_DEVICE_SHIFT)];
int bytes_to_copy, bytes_read = 0, err;
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+ struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
SPARCAUDIO_DEVICE_SHIFT)];
int bytes_written = 0, bytes_to_copy, err;
static int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned int *arg)
{
- struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+ struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
SPARCAUDIO_DEVICE_SHIFT)];
unsigned long i = 0, j = 0, l = 0, m = 0;
unsigned int k = 0;
unsigned int cmd, unsigned long arg)
{
int retval = 0, i, j, k;
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct audio_info ainfo;
audio_buf_info binfo;
count_info cinfo;
static int sparcaudio_open(struct inode * inode, struct file * file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct sparcaudio_driver *drv =
drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];
int err;
static int sparcaudio_release(struct inode * inode, struct file * file)
{
- struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+ struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
SPARCAUDIO_DEVICE_SHIFT)];
lock_kernel();
-/* $Id: aurora.c,v 1.18 2001/10/26 17:59:31 davem Exp $
+/* $Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $
* linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
*
* Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
printk("aurora_open: start\n");
#endif
- board = AURORA_BOARD(MINOR(tty->device));
+ board = AURORA_BOARD(minor(tty->device));
if (board > AURORA_NBOARD ||
!(aurora_board[board].flags & AURORA_BOARD_PRESENT)) {
#ifdef AURORA_DEBUG
}
bp = &aurora_board[board];
- port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(MINOR(tty->device));
+ port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(minor(tty->device));
if (aurora_paranoia_check(port, tty->device, "aurora_open")) {
#ifdef AURORA_DEBUG
printk("aurora_open: error paranoia check\n");
static int wd_open(struct inode *inode, struct file *f)
{
- switch(MINOR(inode->i_rdev))
+ switch(minor(inode->i_rdev))
{
case WD0_MINOR:
f->private_data = &wd_dev.watchdog[WD0_ID];
-/* $Id: display7seg.c,v 1.5 2001/10/08 22:19:51 davem Exp $
+/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $
*
* display7seg - Driver implementation for the 7-segment display
* present on Sun Microsystems CP1400 and CP1500
static int d7s_open(struct inode *inode, struct file *f)
{
- if (D7S_MINOR != MINOR(inode->i_rdev))
+ if (D7S_MINOR != minor(inode->i_rdev))
return -ENODEV;
MOD_INC_USE_COUNT;
static int d7s_release(struct inode *inode, struct file *f)
{
- if (D7S_MINOR != MINOR(inode->i_rdev))
+ if (D7S_MINOR != minor(inode->i_rdev))
return -ENODEV;
MOD_DEC_USE_COUNT;
__u8 regs = readb(d7s_regs);
__u8 ireg = 0;
- if (D7S_MINOR != MINOR(inode->i_rdev))
+ if (D7S_MINOR != minor(inode->i_rdev))
return -ENODEV;
switch (cmd) {
-/* $Id: sab82532.c,v 1.65 2001/10/13 08:27:50 davem Exp $
+/* $Id: sab82532.c,v 1.66 2002/01/08 16:00:16 davem Exp $
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
printk("sab82532_open: count = %d\n", info->count);
#endif
- line = MINOR(tty->device) - tty->driver.minor_start;
+ line = minor(tty->device) - tty->driver.minor_start;
if ((line < 0) || (line >= NR_PORTS))
return -ENODEV;
static inline void __init show_serial_version(void)
{
- char *revision = "$Revision: 1.65 $";
+ char *revision = "$Revision: 1.66 $";
char *version, *p;
version = strchr(revision, ' ');
static kdev_t
sab82532_console_device(struct console *con)
{
- return MKDEV(TTY_MAJOR, 64 + con->index);
+ return mk_kdev(TTY_MAJOR, 64 + con->index);
}
static int
-/* $Id: su.c,v 1.54 2001/11/07 14:52:30 davem Exp $
+/* $Id: su.c,v 1.55 2002/01/08 16:00:16 davem Exp $
* su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
int retval, line;
unsigned long page;
- line = MINOR(tty->device) - tty->driver.minor_start;
+ line = minor(tty->device) - tty->driver.minor_start;
if ((line < 0) || (line >= NR_PORTS))
return -ENODEV;
info = su_table + line;
*/
static __inline__ void __init show_su_version(void)
{
- char *revision = "$Revision: 1.54 $";
+ char *revision = "$Revision: 1.55 $";
char *version, *p;
version = strchr(revision, ' ');
static kdev_t
serial_console_device(struct console *c)
{
- return MKDEV(TTY_MAJOR, 64 + c->index);
+ return mk_kdev(TTY_MAJOR, 64 + c->index);
}
/*
-/* $Id: sunserial.c,v 1.79 2001/04/18 21:06:17 davem Exp $
+/* $Id: sunserial.c,v 1.81 2002/01/05 01:13:43 davem Exp $
* serial.c: Serial port driver infrastructure for the Sparc.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
-/* $Id: zs.c,v 1.68 2001/10/25 18:48:03 davem Exp $
+/* $Id: zs.c,v 1.70 2002/01/08 16:00:16 davem Exp $
* zs.c: Zilog serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
static DECLARE_MUTEX(tmp_buf_sem);
static inline int serial_paranoia_check(struct sun_serial *info,
- dev_t device, const char *routine)
+ kdev_t device, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
"Warning: null sun_serial for (%d, %d) in %s\n";
if (!info) {
- printk(badinfo, MAJOR(device), MINOR(device), routine);
+ printk(badinfo, major(device), minor(device), routine);
return 1;
}
if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, MAJOR(device), MINOR(device), routine);
+ printk(badmagic, major(device), minor(device), routine);
return 1;
}
#endif
static void receive_chars(struct sun_serial *info, struct pt_regs *regs)
{
struct tty_struct *tty = info->tty;
- unsigned char ch, stat;
- int do_queue_task = 1;
+ int do_queue_task = 0;
+
+ while (1) {
+ unsigned char ch, r1;
+
+ r1 = read_zsreg(info->zs_channel, R1);
+ if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+ sbus_writeb(ERR_RES, &info->zs_channel->control);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
+ ZSLOG(REGCTRL, ERR_RES, 1);
+ }
- do {
ch = sbus_readb(&info->zs_channel->data);
ZSLOG(REGDATA, ch, 0);
ch &= info->parity_mask;
/* If this is the console keyboard, we need to handle
* L1-A's here.
*/
- if(info->cons_keyb) {
- if(ch == SUNKBD_RESET) {
+ if (info->cons_keyb) {
+ if (ch == SUNKBD_RESET) {
l1a_state.kbd_id = 1;
l1a_state.l1_down = 0;
- } else if(l1a_state.kbd_id) {
+ } else if (l1a_state.kbd_id) {
l1a_state.kbd_id = 0;
- } else if(ch == SUNKBD_L1) {
+ } else if (ch == SUNKBD_L1) {
l1a_state.l1_down = 1;
- } else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+ } else if (ch == (SUNKBD_L1|SUNKBD_UP)) {
l1a_state.l1_down = 0;
- } else if(ch == SUNKBD_A && l1a_state.l1_down) {
+ } else if (ch == SUNKBD_A && l1a_state.l1_down) {
/* whee... */
batten_down_hatches();
/* Continue execution... */
return;
}
sunkbd_inchar(ch, regs);
- do_queue_task = 0;
goto next_char;
}
- if(info->cons_mouse) {
+ if (info->cons_mouse) {
sun_mouse_inbyte(ch, 0);
- do_queue_task = 0;
goto next_char;
}
- if(info->is_cons) {
- if(ch == 0) {
+ if (info->is_cons) {
+ if (ch == 0) {
/* whee, break received */
batten_down_hatches();
/* Continue execution... */
* documentation for remote target debugging and
* arch/sparc/kernel/sparc-stub.c to see how all this works.
*/
- if((info->kgdb_channel) && (ch =='\003')) {
+ if (info->kgdb_channel && (ch =='\003')) {
breakpoint();
return;
}
#endif
- if(!tty)
+ if (!tty)
return;
+ do_queue_task++;
+
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break;
tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = 0;
+ if (r1 & PAR_ERR)
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ else if (r1 & Rx_OVR)
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ else if (r1 & CRC_ERR)
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ else
+ *tty->flip.flag_buf_ptr++ = 0;
*tty->flip.char_buf_ptr++ = ch;
next_char:
- /* Check if we have another character... */
- stat = sbus_readb(&info->zs_channel->control);
- ZSDELAY();
- ZSLOG(REGCTRL, stat, 0);
- if (!(stat & Rx_CH_AV))
- break;
-
- /* ... and see if it is clean. */
- stat = read_zsreg(info->zs_channel, R1);
- } while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR)));
+ {
+ unsigned char stat;
+
+ /* Check if we have another character... */
+ stat = sbus_readb(&info->zs_channel->control);
+ ZSDELAY();
+ ZSLOG(REGCTRL, stat, 0);
+ if (!(stat & Rx_CH_AV))
+ break;
+ }
+ }
if (do_queue_task != 0)
queue_task(&tty->flip.tqueue, &tq_timer);
return;
}
- if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
+ if ((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
/* That's peculiar... */
sbus_writeb(RES_Tx_P, &info->zs_channel->control);
ZSDELAY();
if (info->xmit_cnt < WAKEUP_CHARS)
zs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
- if(info->xmit_cnt <= 0) {
+ if (info->xmit_cnt <= 0) {
sbus_writeb(RES_Tx_P, &info->zs_channel->control);
ZSDELAY();
ZS_WSYNC(info->zs_channel);
ZS_WSYNC(info->zs_channel);
ZSLOG(REGCTRL, RES_EXT_INT, 1);
#if 0
- if(status & DCD) {
- if((info->tty->termios->c_cflag & CRTSCTS) &&
- ((info->curregs[3] & AUTO_ENAB)==0)) {
+ if (status & DCD) {
+ if ((info->tty->termios->c_cflag & CRTSCTS) &&
+ ((info->curregs[3] & AUTO_ENAB)==0)) {
info->curregs[3] |= AUTO_ENAB;
write_zsreg(info->zs_channel, 3, info->curregs[3]);
}
} else {
- if((info->curregs[3] & AUTO_ENAB)) {
+ if ((info->curregs[3] & AUTO_ENAB)) {
info->curregs[3] &= ~AUTO_ENAB;
write_zsreg(info->zs_channel, 3, info->curregs[3]);
}
* 'break asserted' status change interrupt, call
* the boot prom.
*/
- if(status & BRK_ABRT) {
+ if (status & BRK_ABRT) {
if (info->break_abort)
batten_down_hatches();
if (info->cons_mouse)
return;
}
-static void special_receive(struct sun_serial *info)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch, stat;
-
- stat = read_zsreg(info->zs_channel, R1);
- if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
- ch = sbus_readb(&info->zs_channel->data);
- ZSDELAY();
- ZSLOG(REGDATA, ch, 0);
- }
-
- if (!tty)
- goto clear;
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- goto done;
-
- tty->flip.count++;
- if(stat & PAR_ERR)
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- else if(stat & Rx_OVR)
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
- else if(stat & CRC_ERR)
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
-
-done:
- queue_task(&tty->flip.tqueue, &tq_timer);
-clear:
- sbus_writeb(ERR_RES, &info->zs_channel->control);
- ZSDELAY();
- ZS_WSYNC(info->zs_channel);
- ZSLOG(REGCTRL, ERR_RES, 1);
-}
-
-
/*
* This is the serial driver's generic interrupt routine
*/
void zs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct sun_serial *info;
- unsigned char zs_intreg;
int i;
info = (struct sun_serial *)dev_id;
ZSLOG(REGIRQ, 0, 0);
for (i = 0; i < NUM_SERIAL; i++) {
- zs_intreg = read_zsreg(info->zs_next->zs_channel, 2);
- zs_intreg &= STATUS_MASK;
-
- /* NOTE: The read register 2, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the B
- * channel and is only valid when read from channel B.
- * When read from channel A, read register 2 contains
- * the value written to write register 2.
- */
+ unsigned char r3 = read_zsreg(info->zs_channel, 3);
/* Channel A -- /dev/ttya or /dev/kbd, could be the console */
- if (zs_intreg == CHA_Rx_AVAIL) {
- receive_chars(info, regs);
- return;
- }
- if(zs_intreg == CHA_Tx_EMPTY) {
- transmit_chars(info);
- return;
- }
- if (zs_intreg == CHA_EXT_STAT) {
- status_handle(info);
- return;
- }
- if (zs_intreg == CHA_SPECIAL) {
- special_receive(info);
- return;
+ if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+ sbus_writeb(RES_H_IUS, &info->zs_channel->control);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
+ ZSLOG(REGCTRL, RES_H_IUS, 1);
+ if (r3 & CHARxIP)
+ receive_chars(info, regs);
+ if (r3 & CHAEXT)
+ status_handle(info);
+ if (r3 & CHATxIP)
+ transmit_chars(info);
}
/* Channel B -- /dev/ttyb or /dev/mouse, could be the console */
- if(zs_intreg == CHB_Rx_AVAIL) {
- receive_chars(info->zs_next, regs);
- return;
+ info = info->zs_next;
+ if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+ sbus_writeb(RES_H_IUS, &info->zs_channel->control);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
+ ZSLOG(REGCTRL, RES_H_IUS, 1);
+ if (r3 & CHBRxIP)
+ receive_chars(info, regs);
+ if (r3 & CHBEXT)
+ status_handle(info);
+ if (r3 & CHBTxIP)
+ transmit_chars(info);
}
- if(zs_intreg == CHB_Tx_EMPTY) {
- transmit_chars(info->zs_next);
- return;
- }
- if (zs_intreg == CHB_EXT_STAT) {
- status_handle(info->zs_next);
- return;
- }
-
- /* NOTE: The default value for the IRQ status in read register
- * 2 in channel B is CHB_SPECIAL, so we need to look at
- * read register 3 in channel A to check if this is a
- * real interrupt, or just the default value.
- * Yes... broken hardware...
- */
- zs_intreg = read_zsreg(info->zs_channel, 3);
- if (zs_intreg & CHBRxIP) {
- special_receive(info->zs_next);
- return;
- }
- info = info->zs_next->zs_next;
+ info = info->zs_next;
}
}
struct sun_serial *info;
int retval, line;
- line = MINOR(tty->device) - tty->driver.minor_start;
+ line = minor(tty->device) - tty->driver.minor_start;
/* The zilog lines for the mouse/keyboard must be
* opened using their respective drivers.
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.68 $";
+ char *revision = "$Revision: 1.70 $";
char *version, *p;
version = strchr(revision, ' ');
/* Grab IRQ line before poking the chips so we do
* not lose any interrupts.
*/
- if (request_irq(zilog_irq, zs_interrupt,
- (SA_INTERRUPT | SA_STATIC_ALLOC),
+ if (request_irq(zilog_irq, zs_interrupt, SA_SHIRQ,
"Zilog8530", zs_chain)) {
prom_printf("Unable to attach zs intr\n");
prom_halt();
static kdev_t zs_console_device(struct console *con)
{
- return MKDEV(TTY_MAJOR, 64 + con->index);
+ return mk_kdev(TTY_MAJOR, 64 + con->index);
}
static int __init zs_console_setup(struct console *con, char *options)
-/* $Id: sbus.c,v 1.95 2001/03/15 02:11:10 davem Exp $
+/* $Id: sbus.c,v 1.98 2002/01/05 01:13:43 davem Exp $
* sbus.c: SBus support routines.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
return;
}
regs[regnum].which_io = ranges[rngnum].ot_parent_space;
+ regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
}
}
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
- shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
+" unchecked_isa_dma %d, use_clustering %d\n",
+ shp->unchecked_isa_dma, shp->use_clustering);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
s->dma_channel, s->this_id, s->can_queue);
printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
- s->loaded_as_module);
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
if (ASC_NARROW_BOARD(boardp)) {
asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
#include <linux/mm.h> /* For fetching system memory size */
#include <linux/blk.h>
+#include <scsi/scsicam.h>
/*
* To generate the correct addresses for the controller to issue
static __inline void
ahc_lockinit(struct ahc_softc *ahc)
{
- spin_lock_init(&ahc->platform_data->host->host_lock);
+ spin_lock_init(ahc->platform_data->host->host_lock);
}
static __inline void
ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
{
*flags = 0;
- spin_lock_irqsave(&ahc->platform_data->host->host_lock, *flags);
+ spin_lock_irqsave(ahc->platform_data->host->host_lock, *flags);
}
static __inline void
ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
{
- spin_unlock_irqrestore(&ahc->platform_data->host->host_lock, *flags);
+ spin_unlock_irqrestore(ahc->platform_data->host->host_lock, *flags);
}
static __inline void
struct Scsi_Host *host = ahc->platform_data->host;
*flags = 0;
- spin_lock_irqsave(&host->host_lock, *flags);
+ spin_lock_irqsave(host->host_lock, *flags);
}
static __inline void
{
struct Scsi_Host *host = ahc->platform_data->host;
- spin_unlock_irqrestore(&host->host_lock, *flags);
+ spin_unlock_irqrestore(host->host_lock, *flags);
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
*
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/config.h>
* hosts currently present in the system.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/blk.h>
#include <linux/kernel.h>
* number it is during detection.
*/
-/* This is a placeholder for controllers that are not configured into
- * the system - we do this to ensure that the controller numbering is
- * always consistent, no matter how the kernel is configured. */
-
-#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, 0, 0, 0, 0, 0, 0}
-
/*
* When figure is run, we don't want to link to any object code. Since
* the macro for each host will contain function pointers, we cannot
flag_new = 0;
retval->host_no = shn->host_no;
shn->host_registered = 1;
- shn->loaded_as_module = 1;
break;
}
}
- spin_lock_init(&retval->host_lock);
+ spin_lock_init(&retval->default_lock);
+ scsi_assign_lock(retval, &retval->default_lock);
atomic_set(&retval->host_active,0);
retval->host_busy = 0;
retval->host_failed = 0;
- if(j > 0xffff) panic("Too many extra bytes requested\n");
- retval->extra_bytes = j;
- retval->loaded_as_module = 1;
if (flag_new) {
shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
if (!shn) {
shn->name[hname_len] = 0;
shn->host_no = max_scsi_hosts++;
shn->host_registered = 1;
- shn->loaded_as_module = 1;
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
struct Scsi_Host * next;
Scsi_Device * host_queue;
- spinlock_t host_lock;
+ spinlock_t default_lock;
+ spinlock_t *host_lock;
struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits on
volatile unsigned short host_failed; /* commands that failed. */
/* public: */
- unsigned short extra_bytes;
unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
int resetting; /* if set, it means that last_reset is a valid value */
unsigned long last_reset;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned highmem_io:1;
- /*
- * True if this host was loaded as a loadable module
- */
- unsigned loaded_as_module:1;
/*
* Host has rejected a command because it was busy.
char * name;
unsigned short host_no;
unsigned short host_registered;
- unsigned loaded_as_module;
} Scsi_Host_Name;
extern Scsi_Host_Name * scsi_host_no_list;
unsigned int scsi_init(void);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
extern void scsi_unregister(struct Scsi_Host * i);
-
extern void scsi_register_blocked_host(struct Scsi_Host * SHpnt);
extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt);
+static inline void scsi_assign_lock(struct Scsi_Host *host, spinlock_t *lock)
+{
+ host->host_lock = lock;
+}
+
static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt,
struct pci_dev *pdev)
{
}
}
host = pc->scsi_cmd->host;
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
pc->done(pc->scsi_cmd);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
idescsi_free_bio (rq->bio);
kfree(pc); kfree(rq);
scsi->pc = NULL;
rq->special = (char *) pc;
rq->bio = idescsi_dma_bio (drive, pc);
rq->flags = REQ_SPECIAL;
- spin_unlock(&cmd->host->host_lock);
+ spin_unlock_irq(cmd->host->host_lock);
(void) ide_do_drive_cmd (drive, rq, ide_end);
- spin_lock_irq(&cmd->host->host_lock);
+ spin_lock_irq(cmd->host->host_lock);
return 0;
abort:
if (pc) kfree (pc);
#include <linux/kmod.h>
#endif
-#undef USE_STATIC_SCSI_MEMORY
-
struct proc_dir_entry *proc_scsi;
#ifdef CONFIG_PROC_FS
{
request_queue_t *q = &SDpnt->request_queue;
- blk_init_queue(q, scsi_request_fn, &SHpnt->host_lock);
+ /*
+ * tell block layer about assigned host_lock for this host
+ */
+ blk_init_queue(q, scsi_request_fn, SHpnt->host_lock);
+
q->queuedata = (void *) SDpnt;
/* Hardware imposed limit. */
blk_queue_max_hw_segments(q, SHpnt->sg_tablesize);
- blk_queue_max_sectors(q, SHpnt->max_sectors);
- /* scsi_alloc_sgtable max */
+ /*
+ * scsi_alloc_sgtable max
+ */
blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+ blk_queue_max_sectors(q, SHpnt->max_sectors);
+
if (!SHpnt->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
}
host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
/* Assign a unique nonzero serial_number. */
if (++serial_number == 0)
* length exceeds what the host adapter can handle.
*/
if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) {
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
rtn = host->hostt->queuecommand(SCpnt, scsi_done);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
if (rtn != 0) {
scsi_delete_timer(SCpnt);
scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
SCSI_LOG_MLQUEUE(3,
printk("queuecommand : command too long.\n"));
SCpnt->result = (DID_ABORT << 16);
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
scsi_done(SCpnt);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
rtn = 1;
}
} else {
int temp;
SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", host->hostt->command));
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
temp = host->hostt->command(SCpnt);
SCpnt->result = temp;
#ifdef DEBUG_DELAY
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
clock = jiffies + 4 * HZ;
while (time_before(jiffies, clock)) {
barrier();
}
printk("done(host = %d, result = %04x) : routine at %p\n",
host->host_no, temp, host->hostt->command);
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
#endif
scsi_done(SCpnt);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
}
SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
return rtn;
Scsi_Device * SDpnt = SRpnt->sr_device;
struct Scsi_Host *host = SDpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCSI_LOG_MLQUEUE(4,
{
{
struct Scsi_Host *host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
SRpnt->sr_command = SCpnt;
{
struct Scsi_Host *host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCpnt->pid = scsi_pid++;
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
host = SCpnt->host;
device = SCpnt->device;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
/*
* We need to protect the decrement, as otherwise a race condition
* one execution context, but the device and host structures are
* shared.
*/
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
host->host_busy--; /* Indicate that we are free */
device->device_busy--; /* Decrement device usage counter. */
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
/*
* Clear the flags which say that the device/host is no longer
shn->name[len] = 0;
shn->host_no = n;
shn->host_registered = 0;
- shn->loaded_as_module = 1; /* numbers shouldn't be freed in any case */
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
}
}
}
-#if defined(USE_STATIC_SCSI_MEMORY)
- printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
if (out_of_space) {
scsi_unregister_host(tpnt); /* easiest way to clean up?? */
printk(KERN_INFO "scsi : %d host%s left.\n", next_scsi_host,
(next_scsi_host == 1) ? "" : "s");
-#if defined(USE_STATIC_SCSI_MEMORY)
- printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
-
/*
* Remove it from the linked list and /proc if all
* hosts were successfully removed (ie preset == 0)
}
}
}
-
- for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
- for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
- /* Now dump the request lists for each block device */
- printk(KERN_INFO "Dump of pending block device requests\n");
- for (i = 0; i < MAX_BLKDEV; i++) {
- struct list_head * queue_head;
-
- queue_head = &blk_dev[i].request_queue.queue_head;
- if (!list_empty(queue_head)) {
- struct request *req;
- struct list_head * entry;
-
- printk(KERN_INFO "%d: ", i);
- entry = queue_head->next;
- do {
- req = blkdev_entry_to_request(entry);
- printk("(%s %d %ld %ld %ld) ",
- kdevname(req->rq_dev),
- req->cmd,
- req->sector,
- req->nr_sectors,
- req->current_nr_sectors);
- } while ((entry = entry->next) != queue_head);
- printk("\n");
- }
- }
- }
- }
#endif /* CONFIG_SCSI_LOGGING */ /* } */
}
#endif /* CONFIG_PROC_FS */
*
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
unsigned long flags;
struct Scsi_Host *host = SCpnt->host;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
retry:
/*
SCpnt->host->eh_action = &sem;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
host->hostt->queuecommand(SCpnt, scsi_eh_done);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
down(&sem);
* abort a timed out command or not. Not sure how
* we should treat them differently anyways.
*/
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
if (SCpnt->host->hostt->eh_abort_handler)
SCpnt->host->hostt->eh_abort_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
SCpnt->request.rq_status = RQ_SCSI_DONE;
SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
* timeout protection here, since we would end up waiting in
* the actual low level driver, we don't know how to wake it up.
*/
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
temp = host->hostt->command(SCpnt);
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
SCpnt->result = temp;
/* Fall through to code below to examine status. */
SCpnt->owner = SCSI_OWNER_LOWLEVEL;
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
return rtn;
}
}
SCpnt->owner = SCSI_OWNER_LOWLEVEL;
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
if (rtn == SUCCESS)
SCpnt->eh_state = SUCCESS;
return FAILED;
}
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
if (rtn == SUCCESS)
SCpnt->eh_state = SUCCESS;
if (SCpnt->host->hostt->eh_host_reset_handler == NULL) {
return FAILED;
}
- spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->host->host_lock, flags);
rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
- spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
if (rtn == SUCCESS)
SCpnt->eh_state = SUCCESS;
Scsi_Device *SDpnt;
unsigned long flags;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
/*
* Next free up anything directly waiting upon the host. This will be
* now that error recovery is done, we will need to ensure that these
* requests are started.
*/
- spin_lock_irqsave(&host->host_lock, flags);
+ spin_lock_irqsave(host->host_lock, flags);
for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q = &SDpnt->request_queue;
q->request_fn(q);
}
- spin_unlock_irqrestore(&host->host_lock, flags);
+ spin_unlock_irqrestore(host->host_lock, flags);
}
/*
Scsi_Cmnd *SCdone;
int timed_out;
- ASSERT_LOCK(&host->host_lock, 0);
+ ASSERT_LOCK(host->host_lock, 0);
SCdone = NULL;
* If the HA was compiled into the kernel, then we don't listen
* to any signals.
*/
- if( host->loaded_as_module ) {
siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
- } else {
- siginitsetinv(¤t->blocked, 0);
- }
lock_kernel();
* semaphores isn't unreasonable.
*/
down_interruptible(&sem);
- if( host->loaded_as_module ) {
- if (signal_pending(current))
- break;
- }
+ if (signal_pending(current))
+ break;
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n"));
* - get rid of some verify_areas and use __copy*user and __get/put_user
* for the ones that remain
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <asm/io.h>
* go through and retrofit queueing functions into all 30 some-odd drivers.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
* If there are blocks left over at the end, set up the command
* to queue the remainder of them.
*/
- if (end_that_request_first(req, 1, sectors)) {
+ if (end_that_request_first(req, uptodate, sectors)) {
if (!requeue)
return SCpnt;
{
struct request *req = &SCpnt->request;
- ASSERT_LOCK(&SCpnt->host->host_lock, 0);
+ ASSERT_LOCK(SCpnt->host->host_lock, 0);
/*
* Free up any indirection buffers we allocated for DMA purposes.
* be handled all at once by a host adapter.
*/
-#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
*/
#include <linux/config.h> /* for CONFIG_PROC_FS */
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/string.h>
* we attempt to remove commands from the queue and retry them.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
* Decrement the counters, since these commands are no longer
* active on the host/device.
*/
- spin_lock_irqsave(&cmd->host->host_lock, flags);
+ spin_lock_irqsave(cmd->host->host_lock, flags);
cmd->host->host_busy--;
cmd->device->device_busy--;
- spin_unlock_irqrestore(&cmd->host->host_lock, flags);
+ spin_unlock_irqrestore(cmd->host->host_lock, flags);
/*
* Insert this command at the head of the queue for it's device.
* clearer.
*/
-#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
* We should not even be trying to compile this if we are not doing
* a module.
*/
-#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
* For more information, please consult the SCSI-CAM draft.
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/fs.h>
#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags)
#define NCR_LOCK_SCSI_DONE(host, flags) \
- spin_lock_irqsave(&((host)->host_lock), flags)
+ spin_lock_irqsave(((host)->host_lock), flags)
#define NCR_UNLOCK_SCSI_DONE(host, flags) \
- spin_unlock_irqrestore(&((host)->host_lock), flags)
+ spin_unlock_irqrestore(((host)->host_lock), flags)
#else
#define SYM_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags)
#define SYM_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags)
-#define SYM_INIT_LOCK_HCB(np) spin_lock_init(&np->s.host->host_lock);
+#define SYM_INIT_LOCK_HCB(np) spin_lock_init((np)->s.host->host_lock);
#define SYM_LOCK_HCB(np, flags) \
- spin_lock_irqsave(&np->s.host->host_lock, flags)
+ spin_lock_irqsave((np)->s.host->host_lock, flags)
#define SYM_UNLOCK_HCB(np, flags) \
- spin_unlock_irqrestore(&np->s.host->host_lock, flags)
+ spin_unlock_irqrestore((np)->s.host->host_lock, flags)
/*
* These simple macros limit expression involving
#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */
+#define ALI_DMA_MASK 0xffffffff /* ALI Tridents lack the 30-bit limitation */
#define NR_HW_CH 32
static int trident_open(struct inode *inode, struct file *file)
{
int i = 0;
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct trident_card *card = devs;
struct trident_state *state = NULL;
struct dmabuf *dmabuf = NULL;
static int trident_open_mixdev(struct inode *inode, struct file *file)
{
int i = 0;
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct trident_card *card = devs;
for (card = devs; card != NULL; card = card->next)
u16 temp;
struct pci_dev *pci_dev_m1533 = NULL;
int rc = -ENODEV;
+ u64 dma_mask;
if (pci_enable_device(pci_dev))
goto out;
- if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) {
+ if (pci_dev->device == PCI_DEVICE_ID_ALI_5451)
+ dma_mask = ALI_DMA_MASK;
+ else
+ dma_mask = TRIDENT_DMA_MASK;
+ if (pci_set_dma_mask(pci_dev, dma_mask)) {
printk(KERN_ERR "trident: architecture does not support"
- " 30bit PCI busmaster DMA\n");
+ " %s PCI busmaster DMA\n",
+ pci_dev->device == PCI_DEVICE_ID_ALI_5451 ?
+ "32-bit" : "30-bit");
goto out;
}
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
/*
* Copyright 1999 Jaroslav Kysela <perex@suse.cz>
* Copyright 2000 Alan Cox <alan@redhat.com>
+ * Copyright 2001 Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
+ * Copyright 2002 Pete Zaitcev <zaitcev@yahoo.com>
*
* Yamaha YMF7xx driver.
*
* - Remove prog_dmabuf from read/write, leave it in open.
* - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
* native synthesizer through a playback slot.
- * - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus.
- * - Make the thing big endian compatible. ALSA has it done.
+ * - 2001/11/29 ac97_save_state
+ * Talk to Kai to remove ac97_save_state before it's too late!
+ * - Second AC97
+ * - Restore S/PDIF - Toshibas have it.
+ *
+ * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
+ * unconventional. However, given how small our fragments can be,
+ * a little uncached access is perhaps better than endless flushing.
+ * On i386 and other I/O-coherent architectures pci_alloc_consistent
+ * is entirely harmless.
*/
#include <linux/config.h>
schedule_timeout(1);
}
} while (end_time - (signed long)jiffies >= 0);
- printk("ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
+ printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
secondary, ymfpci_readw(codec, reg));
return -EBUSY;
}
static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
{
- ymfpci_t *codec = dev->private_data;
+ ymfpci_t *unit = dev->private_data;
+ int i;
- if (ymfpci_codec_ready(codec, 0, 0))
+ if (ymfpci_codec_ready(unit, 0, 0))
return ~0;
- ymfpci_writew(codec, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
- if (ymfpci_codec_ready(codec, 0, 0))
+ ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
+ if (ymfpci_codec_ready(unit, 0, 0))
return ~0;
- if (codec->pci->device == PCI_DEVICE_ID_YAMAHA_744 && codec->rev < 2) {
- int i;
+ if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
for (i = 0; i < 600; i++)
- ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+ ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
}
- return ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+ return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
}
/*
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 1
-/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct ymf_dmabuf *dmabuf)
+/*
+ * Allocate DMA buffer
+ */
+static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
{
void *rawbuf = NULL;
+ dma_addr_t dma_addr;
int order;
- struct page * map, * mapend;
+ struct page *map, *mapend;
/* alloc as big a chunk as we can */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+ rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
+ if (rawbuf)
break;
-
+ }
if (!rawbuf)
return -ENOMEM;
dmabuf->ready = dmabuf->mapped = 0;
dmabuf->rawbuf = rawbuf;
+ dmabuf->dma_addr = dma_addr;
dmabuf->buforder = order;
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
return 0;
}
-/* free DMA buffer */
-static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf)
+/*
+ * Free DMA buffer
+ */
+static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
{
struct page *map, *mapend;
mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
clear_bit(PG_reserved, &map->flags);
- free_pages((unsigned long)dmabuf->rawbuf,dmabuf->buforder);
+
+ pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
+ dmabuf->rawbuf, dmabuf->dma_addr);
}
dmabuf->rawbuf = NULL;
dmabuf->mapped = dmabuf->ready = 0;
/* allocate DMA buffer if not allocated yet */
if (!dmabuf->rawbuf)
- if ((ret = alloc_dmabuf(dmabuf)))
+ if ((ret = alloc_dmabuf(state->unit, dmabuf)))
return ret;
/*
dmabuf->ready = 1;
#if 0
- printk("prog_dmabuf: rate %d format 0x%x,"
+ printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
" numfrag %d fragsize %d dmasize %d\n",
state->format.rate, state->format.format, dmabuf->numfrag,
dmabuf->fragsize, dmabuf->dmasize);
if (ypcm->running) {
YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
voice->number, codec->active_bank, dmabuf->count,
- voice->bank[0].start, voice->bank[1].start);
+ le32_to_cpu(voice->bank[0].start),
+ le32_to_cpu(voice->bank[1].start));
silence = (ymf_pcm_format_width(state->format.format) == 16) ?
0 : 0x80;
/* We need actual left-hand-side redzone size here. */
redzone <<= (state->format.shift + 1);
swptr = dmabuf->swptr;
- pos = voice->bank[codec->active_bank].start;
+ pos = le32_to_cpu(voice->bank[codec->active_bank].start);
pos <<= state->format.shift;
if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
dmabuf->hwptr = pos;
if (dmabuf->count == 0) {
- printk("ymfpci%d: %d: strain: hwptr %d\n",
+ printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
codec->dev_audio, voice->number, dmabuf->hwptr);
ymf_playback_trigger(codec, ypcm, 0);
}
/*
* Lost interrupt or other screwage.
*/
- printk("ymfpci%d: %d: lost: delta %d"
+ printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
" hwptr %d swptr %d distance %d count %d\n",
codec->dev_audio, voice->number, delta,
dmabuf->hwptr, swptr, distance, dmabuf->count);
/*
* Normal end of DMA.
*/
-// printk("ymfpci%d: %d: done: delta %d"
-// " hwptr %d swptr %d distance %d count %d\n",
-// codec->dev_audio, voice->number, delta,
-// dmabuf->hwptr, swptr, distance, dmabuf->count);
+ YMFDBGI("ymfpci%d: %d: done: delta %d"
+ " hwptr %d swptr %d distance %d count %d\n",
+ codec->dev_audio, voice->number, delta,
+ dmabuf->hwptr, swptr, distance, dmabuf->count);
}
played = dmabuf->count;
if (ypcm->running) {
redzone = ymf_calc_lend(state->format.rate);
redzone <<= (state->format.shift + 1);
- pos = cap->bank[unit->active_bank].start;
+ pos = le32_to_cpu(cap->bank[unit->active_bank].start);
// pos <<= state->format.shift;
if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
return -EINVAL;
}
if (cmd != 0) {
- codec->ctrl_playback[ypcm->voices[0]->number + 1] = virt_to_bus(ypcm->voices[0]->bank);
+ codec->ctrl_playback[ypcm->voices[0]->number + 1] =
+ cpu_to_le32(ypcm->voices[0]->bank_ba);
if (ypcm->voices[1] != NULL)
- codec->ctrl_playback[ypcm->voices[1]->number + 1] = virt_to_bus(ypcm->voices[1]->bank);
+ codec->ctrl_playback[ypcm->voices[1]->number + 1] =
+ cpu_to_le32(ypcm->voices[1]->bank_ba);
ypcm->running = 1;
} else {
codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
u32 lpfK = ymfpci_calc_lpfK(rate);
ymfpci_playback_bank_t *bank;
int nbank;
+ unsigned le_0x40000000 = cpu_to_le32(0x40000000);
format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
if (stereo)
end >>= 1;
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
- bank->format = format;
+ bank->format = cpu_to_le32(format);
bank->loop_default = 0; /* 0-loops forever, otherwise count */
- bank->base = addr;
+ bank->base = cpu_to_le32(addr);
bank->loop_start = 0;
- bank->loop_end = end;
+ bank->loop_end = cpu_to_le32(end);
bank->loop_frac = 0;
- bank->eg_gain_end = 0x40000000;
- bank->lpfQ = lpfQ;
+ bank->eg_gain_end = le_0x40000000;
+ bank->lpfQ = cpu_to_le32(lpfQ);
bank->status = 0;
bank->num_of_frames = 0;
bank->loop_count = 0;
bank->start = 0;
bank->start_frac = 0;
bank->delta =
- bank->delta_end = delta;
+ bank->delta_end = cpu_to_le32(delta);
bank->lpfK =
- bank->lpfK_end = lpfK;
- bank->eg_gain = 0x40000000;
+ bank->lpfK_end = cpu_to_le32(lpfK);
+ bank->eg_gain = le_0x40000000;
bank->lpfD1 =
bank->lpfD2 = 0;
bank->left_gain =
bank->right_gain =
bank->left_gain_end =
- bank->right_gain_end = 0x40000000;
+ bank->right_gain_end = le_0x40000000;
} else {
bank->eff2_gain =
bank->eff2_gain_end =
bank->eff3_gain =
- bank->eff3_gain_end = 0x40000000;
+ bank->eff3_gain_end = le_0x40000000;
}
} else {
if (!spdif) {
if ((voice->number & 1) == 0) {
bank->left_gain =
- bank->left_gain_end = 0x40000000;
+ bank->left_gain_end = le_0x40000000;
} else {
- bank->format |= 1;
+ bank->format |= cpu_to_le32(1);
bank->right_gain =
- bank->right_gain_end = 0x40000000;
+ bank->right_gain_end = le_0x40000000;
}
} else {
if ((voice->number & 1) == 0) {
bank->eff2_gain =
- bank->eff2_gain_end = 0x40000000;
+ bank->eff2_gain_end = le_0x40000000;
} else {
- bank->format |= 1;
+ bank->format |= cpu_to_le32(1);
bank->eff3_gain =
- bank->eff3_gain_end = 0x40000000;
+ bank->eff3_gain_end = le_0x40000000;
}
}
}
ymf_pcm_init_voice(ypcm->voices[nvoice],
state->format.voices == 2, state->format.rate,
ymf_pcm_format_width(state->format.format) == 16,
- virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize,
+ ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
ypcm->spdif);
}
return 0;
}
for (nbank = 0; nbank < 2; nbank++) {
bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
- bank->base = virt_to_bus(ypcm->dmabuf.rawbuf);
+ bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
// bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
- bank->loop_end = ypcm->dmabuf.dmasize;
+ bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
bank->start = 0;
bank->num_of_loops = 0;
}
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
struct ymf_dmabuf *dmabuf;
+ int redzone;
unsigned long flags;
unsigned int mask = 0;
if (file->f_mode & FMODE_WRITE)
poll_wait(file, &state->wpcm.dmabuf.wait, wait);
- // if (file->f_mode & FMODE_READ)
- // poll_wait(file, &dmabuf->wait, wait);
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &state->rpcm.dmabuf.wait, wait);
spin_lock_irqsave(&state->unit->reg_lock, flags);
if (file->f_mode & FMODE_READ) {
mask |= POLLIN | POLLRDNORM;
}
if (file->f_mode & FMODE_WRITE) {
+ redzone = ymf_calc_lend(state->format.rate);
+ redzone <<= state->format.shift;
+ redzone *= 3;
+
dmabuf = &state->wpcm.dmabuf;
if (dmabuf->mapped) {
if (dmabuf->count >= (signed)dmabuf->fragsize)
mask |= POLLOUT | POLLWRNORM;
} else {
- if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+ /*
+ * Don't select unless a full fragment is available.
+ * Otherwise artsd does GETOSPACE, sees 0, and loops.
+ */
+ if (dmabuf->count + redzone + dmabuf->fragsize
+ <= dmabuf->dmasize)
mask |= POLLOUT | POLLWRNORM;
}
}
return -EAGAIN;
dmabuf->mapped = 1;
+/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
return 0;
}
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int redzone;
int val;
switch (cmd) {
case OSS_GETVERSION:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
return put_user(SOUND_VERSION, (int *)arg);
case SNDCTL_DSP_RESET:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
return 0;
case SNDCTL_DSP_SYNC:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
dmabuf = &state->wpcm.dmabuf;
if (file->f_flags & O_NONBLOCK) {
case SNDCTL_DSP_SPEED: /* set smaple rate */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
if (val >= 8000 && val <= 48000) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
return 0;
case SNDCTL_DSP_GETBLKSIZE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf(state, 0)))
return val;
- return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
+ val = state->wpcm.dmabuf.fragsize;
+ YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
+ return put_user(val, (int *)arg);
}
if (file->f_mode & FMODE_READ) {
if ((val = prog_dmabuf(state, 1)))
return val;
- return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
+ val = state->rpcm.dmabuf.fragsize;
+ YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
+ return put_user(val, (int *)arg);
}
return -EINVAL;
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Select sample format */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
if (val == AFMT_S16_LE || val == AFMT_U8) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
case SNDCTL_DSP_CHANNELS:
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
if (val != 0) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
return put_user(state->format.voices, (int *)arg);
case SNDCTL_DSP_POST:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
/*
* Quoting OSS PG:
* The ioctl SNDCTL_DSP_POST is a lightweight version of
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
+ cmd,
+ (val >> 16) & 0xFFFF, val & 0xFFFF,
+ (val >> 16) & 0xFFFF, val & 0xFFFF);
dmabuf = &state->wpcm.dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
return 0;
case SNDCTL_DSP_GETOSPACE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
+ redzone = ymf_calc_lend(state->format.rate);
+ redzone <<= state->format.shift;
+ redzone *= 3;
spin_lock_irqsave(&state->unit->reg_lock, flags);
abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+ abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_GETCAPS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
(int *)arg); */
return put_user(0, (int *)arg);
case SNDCTL_DSP_GETIPTR:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
- /* XXX fishy - breaks invariant count=hwptr-swptr */
- if (dmabuf->mapped)
- dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
+ cinfo.ptr, cinfo.bytes);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETOPTR:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
- /* XXX fishy - breaks invariant count=swptr-hwptr */
- if (dmabuf->mapped)
- dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
+ cinfo.ptr, cinfo.bytes);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */
- return -EINVAL;
+ case SNDCTL_DSP_SETDUPLEX:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
+ return 0; /* Always duplex */
case SOUND_PCM_READ_RATE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
return put_user(state->format.rate, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
return put_user(state->format.voices, (int *)arg);
case SOUND_PCM_READ_BITS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
return put_user(AFMT_S16_LE, (int *)arg);
case SNDCTL_DSP_MAPINBUF:
* Some programs mix up audio devices and ioctls
* or perhaps they expect "universal" ioctls,
* for instance we get SNDCTL_TMR_CONTINUE here.
+ * (mpg123 -g 100 ends here too - to be fixed.)
*/
YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
break;
}
#if 0 /* test if interrupts work */
- ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
- ymfpci_writeb(codec, YDSXGR_TIMERCTRL,
+ ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
+ ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
(YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
#endif
up(&unit->open_sem);
* a nestable exception, but here it is not nestable due to semaphore.
* XXX Doubtful technique of self-describing objects....
*/
- dealloc_dmabuf(&state->wpcm.dmabuf);
- dealloc_dmabuf(&state->rpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->rpcm.dmabuf);
ymf_pcm_free_substream(&state->wpcm);
ymf_pcm_free_substream(&state->rpcm);
static int ymf_release(struct inode *inode, struct file *file)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- ymfpci_t *codec = state->unit;
+ ymfpci_t *unit = state->unit;
#if 0 /* test if interrupts work */
- ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
+ ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
#endif
- down(&codec->open_sem);
+ down(&unit->open_sem);
/*
* XXX Solve the case of O_NONBLOCK close - don't deallocate here.
*/
ymf_wait_dac(state);
ymf_stop_adc(state); /* fortunately, it's immediate */
- dealloc_dmabuf(&state->wpcm.dmabuf);
- dealloc_dmabuf(&state->rpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+ dealloc_dmabuf(unit, &state->rpcm.dmabuf);
ymf_pcm_free_substream(&state->wpcm);
ymf_pcm_free_substream(&state->rpcm);
file->private_data = NULL; /* Can you tell I programmed Solaris */
kfree(state);
- up(&codec->open_sem);
+ up(&unit->open_sem);
return 0;
}
*/
static int ymf_open_mixdev(struct inode *inode, struct file *file)
{
- int i;
int minor = minor(inode->i_rdev);
struct list_head *list;
ymfpci_t *unit;
+ int i;
list_for_each(list, &ymf_devs) {
unit = list_entry(list, ymfpci_t, ymf_devs);
static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
{
- int i;
struct ymf_unit *unit = pci_get_drvdata(pcidev);
unsigned long flags;
struct ymf_dmabuf *dmabuf;
struct list_head *p;
struct ymf_state *state;
struct ac97_codec *codec;
+ int i;
spin_lock_irqsave(&unit->reg_lock, flags);
unit->suspended = 1;
for (i = 0; i < NR_AC97; i++) {
- codec = unit->ac97_codec[i];
- if (!codec)
- continue;
- ac97_save_state(codec);
+ if ((codec = unit->ac97_codec[i]) != NULL)
+ ac97_save_state(codec);
}
list_for_each(p, &unit->states) {
static int ymf_resume(struct pci_dev *pcidev)
{
- int i;
struct ymf_unit *unit = pci_get_drvdata(pcidev);
unsigned long flags;
struct list_head *p;
struct ymf_state *state;
struct ac97_codec *codec;
+ int i;
ymfpci_aclink_reset(unit->pci);
ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */
}
for (i = 0; i < NR_AC97; i++) {
- codec = unit->ac97_codec[i];
- if (!codec)
- continue;
- ac97_restore_state(codec);
+ if ((codec = unit->ac97_codec[i]) != NULL)
+ ac97_restore_state(codec);
}
unit->suspended = 0;
{
u8 cmd;
+ /*
+ * In the 744, 754 only 0x01 exists, 0x02 is undefined.
+ * It does not seem to hurt to trip both regardless of revision.
+ */
pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
- if (cmd & 0x03) {
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
- }
+ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
+ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+
pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
}
static int ymfpci_memalloc(ymfpci_t *codec)
{
- long size, playback_ctrl_size;
+ unsigned int playback_ctrl_size;
+ unsigned int bank_size_playback;
+ unsigned int bank_size_capture;
+ unsigned int bank_size_effect;
+ unsigned int size;
+ unsigned int off;
+ char *ptr;
+ dma_addr_t pba;
int voice, bank;
- u8 *ptr;
playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
- codec->bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
- codec->bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
- codec->bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
+ bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
+ bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
+ bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
- ((codec->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
- ((codec->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
- ((codec->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
+ ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
+ ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
+ ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
codec->work_size;
- ptr = (u8 *)kmalloc(size + 0x00ff, GFP_KERNEL);
+ ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
if (ptr == NULL)
return -ENOMEM;
+ codec->dma_area_va = ptr;
+ codec->dma_area_ba = pba;
+ codec->dma_area_size = size + 0xff;
- codec->work_ptr = ptr;
- ptr += 0x00ff;
- (long)ptr &= ~0x00ff;
+ if ((off = ((uint) ptr) & 0xff) != 0) {
+ ptr += 0x100 - off;
+ pba += 0x100 - off;
+ }
/*
* Hardware requires only ptr[playback_ctrl_size] zeroed,
*/
memset(ptr, 0, size);
- codec->bank_base_playback = ptr;
codec->ctrl_playback = (u32 *)ptr;
- codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES;
+ codec->ctrl_playback_ba = pba;
+ codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+ pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+
+ off = 0;
for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
- for (bank = 0; bank < 2; bank++) {
- codec->bank_playback[voice][bank] = (ymfpci_playback_bank_t *)ptr;
- ptr += codec->bank_size_playback;
- }
codec->voices[voice].number = voice;
- codec->voices[voice].bank = codec->bank_playback[voice][0];
+ codec->voices[voice].bank =
+ (ymfpci_playback_bank_t *) (ptr + off);
+ codec->voices[voice].bank_ba = pba + off;
+ off += 2 * bank_size_playback; /* 2 banks */
}
- ptr += (codec->bank_size_playback + 0x00ff) & ~0x00ff;
- codec->bank_base_capture = ptr;
+ off = (off + 0xff) & ~0xff;
+ ptr += off;
+ pba += off;
+
+ off = 0;
+ codec->bank_base_capture = pba;
for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
for (bank = 0; bank < 2; bank++) {
- codec->bank_capture[voice][bank] = (ymfpci_capture_bank_t *)ptr;
- ptr += codec->bank_size_capture;
+ codec->bank_capture[voice][bank] =
+ (ymfpci_capture_bank_t *) (ptr + off);
+ off += bank_size_capture;
}
- ptr += (codec->bank_size_capture + 0x00ff) & ~0x00ff;
- codec->bank_base_effect = ptr;
+ off = (off + 0xff) & ~0xff;
+ ptr += off;
+ pba += off;
+
+ off = 0;
+ codec->bank_base_effect = pba;
for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
for (bank = 0; bank < 2; bank++) {
- codec->bank_effect[voice][bank] = (ymfpci_effect_bank_t *)ptr;
- ptr += codec->bank_size_effect;
+ codec->bank_effect[voice][bank] =
+ (ymfpci_effect_bank_t *) (ptr + off);
+ off += bank_size_effect;
}
- ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff;
- codec->work_base = ptr;
+ off = (off + 0xff) & ~0xff;
+ ptr += off;
+ pba += off;
+
+ codec->work_base = pba;
return 0;
}
ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
- kfree(codec->work_ptr);
+ pci_free_consistent(codec->pci,
+ codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
}
static void ymf_memload(ymfpci_t *unit)
{
- ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, virt_to_bus(unit->bank_base_playback));
- ymfpci_writel(unit, YDSXGR_RECCTRLBASE, virt_to_bus(unit->bank_base_capture));
- ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, virt_to_bus(unit->bank_base_effect));
- ymfpci_writel(unit, YDSXGR_WORKBASE, virt_to_bus(unit->work_base));
+ ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
+ ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
+ ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
+ ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
/* S/PDIF output initialization */
codec->codec_write = ymfpci_codec_write;
if (ac97_probe_codec(codec) == 0) {
- printk("ymfpci: ac97_probe_codec failed\n");
+ printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
goto out_kfree;
}
static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
u16 ctrl;
+ unsigned long base;
ymfpci_t *codec;
int err;
printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
return err;
}
+ base = pci_resource_start(pcidev, 0);
if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "ymfpci: no core\n");
codec->pci = pcidev;
pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
- codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);
- if (codec->reg_area_virt == NULL) {
- printk(KERN_ERR "ymfpci: unable to map registers\n");
+
+ if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
+ printk(KERN_ERR "ymfpci: unable to request mem region\n");
goto out_free;
}
+ if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
+ printk(KERN_ERR "ymfpci: unable to map registers\n");
+ goto out_release_region;
+ }
+
pci_set_master(pcidev);
printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
- (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);
+ (char *)ent->driver_data, base, pcidev->irq);
ymfpci_aclink_reset(pcidev);
if (ymfpci_codec_ready(codec, 0, 1) < 0)
/* register /dev/dsp */
if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
- printk(KERN_ERR "ymfpci%d: unable to register dsp\n",
- codec->dev_audio);
+ printk(KERN_ERR "ymfpci: unable to register dsp\n");
goto out_free_irq;
}
codec->opl3_data.irq = -1;
codec->mpu_data.io_base = codec->iomidi;
- codec->mpu_data.irq = -1; /* XXX Make it ours. */
+ codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */
if (codec->iomidi) {
if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
ymfpci_writel(codec, YDSXGR_STATUS, ~0);
out_unmap:
iounmap(codec->reg_area_virt);
+ out_release_region:
+ release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
out_free:
kfree(codec);
return -ENODEV;
ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
iounmap(codec->reg_area_virt);
+ release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
#ifdef CONFIG_SOUND_YMFPCI_LEGACY
if (codec->iomidi) {
unload_uart401(&codec->mpu_data);
char use, pcm, synth, midi; // bool
ymfpci_playback_bank_t *bank;
struct ymf_pcm *ypcm;
+ dma_addr_t bank_ba;
};
struct ymf_capture {
struct ymf_unit {
u8 rev; /* PCI revision */
void *reg_area_virt;
- void *work_ptr;
+ void *dma_area_va;
+ dma_addr_t dma_area_ba;
+ unsigned int dma_area_size;
- unsigned int bank_size_playback;
- unsigned int bank_size_capture;
- unsigned int bank_size_effect;
+ dma_addr_t bank_base_capture;
+ dma_addr_t bank_base_effect;
+ dma_addr_t work_base;
unsigned int work_size;
- void *bank_base_playback;
- void *bank_base_capture;
- void *bank_base_effect;
- void *work_base;
-
u32 *ctrl_playback;
+ dma_addr_t ctrl_playback_ba;
ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
};
struct ymf_dmabuf {
-
- /* OSS buffer management stuff */
+ dma_addr_t dma_addr;
void *rawbuf;
unsigned buforder;
+
+ /* OSS buffer management stuff */
unsigned numfrag;
unsigned fragshift;
static int phone_open(struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
int err = 0;
struct phone_device *p;
struct file_operations *old_fops, *new_fops = NULL;
--- /dev/null
+obj-$(CONFIG_USB_CATC) += crc32.o
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
static void catc_multicast(unsigned char *addr, u8 *multicast)
{
- unsigned int crc = 0xffffffff;
- u8 byte, idx, bit;
-
- for (idx = 0; idx < 6; idx++)
- for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1)
- crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0);
+ u32 crc;
+ crc = ether_crc_le(6, addr);
multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
}
#ifndef __sparc__
sprintf (buf, "%d", dev->irq);
#else
- bufp = __irq_itoa(irq);
+ bufp = __irq_itoa(dev->irq);
#endif
if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
!= 0) {
static int __init init (void)
{
dbg (DRIVER_INFO);
- dbg ("block sizes: qh %d qtd %d itd %d sitd %d",
+ dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd",
sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
vdbg ("qh %p usecs %d period %d starting frame %d.%d",
qh, qh->usecs, period, frame, uframe);
do {
- if (unlikely ((int)ehci->pshadow [frame].ptr)) {
+ if (unlikely ((long)ehci->pshadow [frame].ptr)) {
// FIXME -- just link to the end, before any qh with a shorter period,
// AND handle it already being (implicitly) linked into this frame
BUG ();
fbcon_cfb##width##_clear_margins(conp, p, bottom_only), \
int bottom_only) \
\
-const struct display_switch fbcon_aty##width## = { \
+const struct display_switch fbcon_aty##width = { \
setup: fbcon_cfb##width##_setup, \
bmove: fbcon_aty_bmove, \
clear: fbcon_aty_clear, \
fix->type = FB_TYPE_PACKED_PIXELS;
fix->visual = FB_VISUAL_PSEUDOCOLOR;
- fb->info.node = -1;
+ fb->info.node = NODEV;
fb->info.fbops = &sbusfb_ops;
fb->info.disp = disp;
strcpy(fb->info.fontname, fontname);
--- /dev/null
+obj-$(CONFIG_FS_JFFS2) += crc32.o
+obj-$(CONFIG_EFI_PARTITION) += crc32.o
err_alloc:
brelse(ext_bh);
bh_result->b_state &= ~(1UL << BH_Mapped);
+ bh_result->b_bdev = NULL;
// unlock cache
affs_unlock_ext(inode);
return -ENOSPC;
return -EIO;
bh->b_dev = inode->i_rdev;
+ bh->b_bdev = inode->i_bdev;
bh->b_blocknr = iblock;
bh->b_state |= 1UL << BH_Mapped;
return 0;
static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
-static int grow_buffers(kdev_t dev, unsigned long block, int size);
+static int grow_buffers(struct block_device *bdev, unsigned long block, int size);
static void __refile_buffer(struct buffer_head *);
/* This is used by some architectures to estimate available memory. */
spin_unlock(&lru_list_lock);
}
-struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
+struct buffer_head * __get_hash_table(struct block_device *bdev, sector_t block, int size)
{
- struct buffer_head *bh, **p = &hash(dev, block);
+ struct buffer_head *bh, **p = &hash(to_kdev_t(bdev->bd_dev), block);
read_lock(&hash_table_lock);
continue;
if (bh->b_size != size)
continue;
- if (!kdev_same(bh->b_dev, dev))
+ if (bh->b_bdev != bdev)
continue;
get_bh(bh);
break;
*/
struct buffer_head * __getblk(struct block_device *bdev, sector_t block, int size)
{
- kdev_t dev = to_kdev_t(bdev->bd_dev);
for (;;) {
struct buffer_head * bh;
- bh = get_hash_table(dev, block, size);
+ bh = __get_hash_table(bdev, block, size);
if (bh)
return bh;
- if (!grow_buffers(dev, block, size))
+ if (!grow_buffers(bdev, block, size))
free_more_memory();
}
}
kmem_cache_free(bh_cachep, bh);
} else {
bh->b_dev = B_FREE;
+ bh->b_bdev = NULL;
bh->b_blocknr = -1;
bh->b_this_page = NULL;
goto no_grow;
bh->b_dev = NODEV;
+ bh->b_bdev = NULL;
bh->b_this_page = head;
head = bh;
if (buffer_mapped(bh)) {
mark_buffer_clean(bh);
lock_buffer(bh);
+ bh->b_bdev = NULL;
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Mapped, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
{
struct buffer_head *old_bh;
- old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ old_bh = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
if (old_bh) {
mark_buffer_clean(old_bh);
wait_on_buffer(old_bh);
* FIXME: we need a swapper_inode->get_block function to remove
* some of the bmap kludges and interface ugliness here.
*/
-int brw_page(int rw, struct page *page, kdev_t dev, sector_t b[], int size)
+int brw_page(int rw, struct page *page, struct block_device *bdev, sector_t b[], int size)
{
struct buffer_head *head, *bh;
do {
lock_buffer(bh);
bh->b_blocknr = *(b++);
- bh->b_dev = dev;
+ bh->b_bdev = bdev;
+ bh->b_dev = to_kdev_t(bdev->bd_dev);
set_bit(BH_Mapped, &bh->b_state);
set_buffer_async_io(bh);
bh = bh->b_this_page;
return NULL;
}
-static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size)
+static void hash_page_buffers(struct page *page, struct block_device *bdev, int block, int size)
{
struct buffer_head *head = page->buffers;
struct buffer_head *bh = head;
do {
if (!(bh->b_state & (1 << BH_Mapped))) {
init_buffer(bh, NULL, NULL);
- bh->b_dev = dev;
+ bh->b_bdev = bdev;
+ bh->b_dev = to_kdev_t(bdev->bd_dev);
bh->b_blocknr = block;
bh->b_state = uptodate;
}
* Try to increase the number of buffers available: the size argument
* is used to determine what kind of buffers we want.
*/
-static int grow_buffers(kdev_t dev, unsigned long block, int size)
+static int grow_buffers(struct block_device *bdev, unsigned long block, int size)
{
struct page * page;
- struct block_device *bdev;
unsigned long index;
int sizebits;
/* Size must be multiple of hard sectorsize */
- if (size & (get_hardsect_size(dev)-1))
+ if (size & (get_hardsect_size(to_kdev_t(bdev->bd_dev))-1))
BUG();
/* Size must be within 512 bytes and PAGE_SIZE */
if (size < 512 || size > PAGE_SIZE)
index = block >> sizebits;
block = index << sizebits;
- bdev = bdget(kdev_t_to_nr(dev));
- if (!bdev) {
- printk("No block device for %s\n", kdevname(dev));
- BUG();
- }
-
/* Create a page with the proper size buffers.. */
page = grow_dev_page(bdev, index, size);
- /* This is "wrong" - talk to Al Viro */
- atomic_dec(&bdev->bd_count);
if (!page)
return 0;
/* Hash in the buffers on the hash list */
- hash_page_buffers(page, dev, block, size);
+ hash_page_buffers(page, bdev, block, size);
UnlockPage(page);
page_cache_release(page);
goto error;
}
- printk("coda_read_super: rootinode is %ld dev %d\n",
- root->i_ino, root->i_dev);
+ printk("coda_read_super: rootinode is %ld dev %x\n",
+ root->i_ino, kdev_val(root->i_dev));
sb->s_root = d_alloc_root(root);
return sb;
}
CDEBUG(D_PIOCTL, "target ino: 0x%ld, dev: 0x%x\n",
- target_inode->i_ino, target_inode->i_dev);
+ target_inode->i_ino, kdev_val(target_inode->i_dev));
/* return if it is not a Coda inode */
if ( target_inode->i_sb != inode->i_sb ) {
panic("Cannot create buffer head SLAB cache");
names_cachep = kmem_cache_create("names_cache",
- PATH_MAX + 1, 0,
+ PATH_MAX, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!names_cachep)
panic("Cannot create names SLAB cache");
Only return old entry in <devfs_mk_dir> if a directory.
Defined macros for error and debug messages.
v1.8
+ 20020113 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed (rare, old) race in <devfs_lookup>.
+ v1.9
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
-#define DEVFS_VERSION "1.8 (20011226)"
+#define DEVFS_VERSION "1.9 (20020113)"
#define DEVFS_NAME "devfs"
{
devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
DEVFS_SPECIAL_BLK,
- mk_kdev(de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor) );
+ mk_kdev (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor) );
}
WRITE_ENTRY_MAGIC (de, 0);
#ifdef CONFIG_DEVFS_DEBUG
if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
(flags & DEVFS_FL_AUTO_DEVNUM) )
{
- if ( kdev_none( devnum = devfs_alloc_devnum (devtype) ) )
+ if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )
{
PRINTK ("(%s): exhausted %s device numbers\n",
name, S_ISCHR (mode) ? "char" : "block");
if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
{
PRINTK ("(%s): could not prepare leaf\n", name);
- if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum);
+ if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
return NULL;
}
if ( S_ISCHR (mode) || S_ISBLK (mode) )
{
de->u.fcb.u.device.major = major;
de->u.fcb.u.device.minor = minor;
- de->u.fcb.autogen = kdev_none(devnum) ? FALSE : TRUE;
+ de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;
}
else if ( !S_ISREG (mode) )
{
{
PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
devfs_put (dir);
- if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum);
+ if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
return NULL;
}
DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\" pp: %p\n",
* @buf: A working area that will be used. This must not go out of scope
* until devfsd is idle again.
*
- * Returns 0 on success, else a negative error code.
+ * Returns 0 on success (event was queued), else a negative error code.
*/
static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
current->euid, current->egid, fs_info, 0) )
return -ENOENT;
- /* Possible success */
+ /* Possible success: event has been queued */
return 0;
} /* End Function try_modload */
{
int tmp;
int retval = 0;
- kdev_t dev = mk_kdev(de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
+ kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
struct block_device_operations *bdops;
extern int warn_no_part;
inode->i_rdev = NODEV;
if ( S_ISCHR (de->mode) )
{
- inode->i_rdev = mk_kdev(de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor);
+ inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor);
inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
is_fcb = TRUE;
}
else if ( S_ISBLK (de->mode) )
{
- inode->i_rdev = mk_kdev(de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor);
+ inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor);
if (bd_acquire (inode) == 0)
{
if (!inode->i_bdev->bd_op && de->u.fcb.ops)
return 0;
} /* End Function devfs_d_delete */
+struct devfs_lookup_struct
+{
+ devfs_handle_t de;
+ wait_queue_head_t wait_queue;
+};
+
static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
{
struct inode *dir = dentry->d_parent->d_inode;
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+ devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+ struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
+ DECLARE_WAITQUEUE (wait, current);
if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
{
- devfs_handle_t de;
- devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+ devfs_handle_t de = lookup_info->de;
struct inode *inode;
- DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p by: \"%s\"\n",
- dentry->d_name.name, dentry, current->comm);
- read_lock (&parent->u.dir.lock);
- de = _devfs_search_dir (parent, dentry->d_name.name,
- dentry->d_name.len);
- read_unlock (&parent->u.dir.lock);
- if (de == NULL) return 1;
+ DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p de: %p by: \"%s\"\n",
+ dentry->d_name.name, dentry, de, current->comm);
+ if (de == NULL)
+ {
+ read_lock (&parent->u.dir.lock);
+ de = _devfs_search_dir (parent, dentry->d_name.name,
+ dentry->d_name.len);
+ read_unlock (&parent->u.dir.lock);
+ if (de == NULL) return 1;
+ lookup_info->de = de;
+ }
/* Create an inode, now that the driver information is available */
inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
- devfs_put (de);
if (!inode) return 1;
- DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n",
- de->name, de->inode.ino, inode, de);
+ DPRINTK (DEBUG_I_LOOKUP,
+ "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
+ de->name, de->inode.ino, inode, de, current->comm);
d_instantiate (dentry, inode);
return 1;
}
- if ( wait_for_devfsd_finished (fs_info) ) dentry->d_op = &devfs_dops;
+ if (lookup_info == NULL) return 1; /* Early termination */
+ read_lock (&parent->u.dir.lock);
+ if (dentry->d_fsdata)
+ {
+ add_wait_queue (&lookup_info->wait_queue, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ read_unlock (&parent->u.dir.lock);
+ schedule ();
+ }
+ else read_unlock (&parent->u.dir.lock);
return 1;
} /* End Function devfs_d_revalidate_wait */
static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
{
+ struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */
+ struct devfs_lookup_struct lookup_info;
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
struct devfs_entry *parent, *de;
struct inode *inode;
+ struct dentry *retval = NULL;
/* Set up the dentry operations before anything else, to ensure cleaning
up on any error */
dentry->d_name.len);
read_unlock (&parent->u.dir.lock);
}
+ lookup_info.de = de;
+ init_waitqueue_head (&lookup_info.wait_queue);
+ dentry->d_fsdata = &lookup_info;
if (de == NULL)
{ /* Try with devfsd. For any kind of failure, leave a negative dentry
so someone else can deal with it (in the case where the sysadmin
does a mknod()). It's important to do this before hashing the
dentry, so that the devfsd queue is filled before revalidates
can start */
- struct devfs_entry tmp;
-
if (try_modload (parent, fs_info,
dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
- {
+ { /* Lookup event was not queued to devfsd */
d_add (dentry, NULL);
return NULL;
}
- /* devfsd claimed success */
- dentry->d_op = &devfs_wait_dops;
- d_add (dentry, NULL); /* Open the floodgates */
- /* Unlock directory semaphore, which will release any waiters. They
- will get the hashed dentry, and may be forced to wait for
- revalidation */
- up (&dir->i_sem);
- devfs_d_revalidate_wait (dentry, 0); /* I might have to wait too */
- down (&dir->i_sem); /* Grab it again because them's the rules */
- /* If someone else has been so kind as to make the inode, we go home
- early */
- if (dentry->d_inode) return NULL;
+ }
+ dentry->d_op = &devfs_wait_dops;
+ d_add (dentry, NULL); /* Open the floodgates */
+ /* Unlock directory semaphore, which will release any waiters. They
+ will get the hashed dentry, and may be forced to wait for
+ revalidation */
+ up (&dir->i_sem);
+ wait_for_devfsd_finished (fs_info); /* If I'm not devfsd, must wait */
+ down (&dir->i_sem); /* Grab it again because them's the rules */
+ de = lookup_info.de;
+ /* If someone else has been so kind as to make the inode, we go home
+ early */
+ if (dentry->d_inode) goto out;
+ if (de == NULL)
+ {
read_lock (&parent->u.dir.lock);
de = _devfs_search_dir (parent, dentry->d_name.name,
dentry->d_name.len);
read_unlock (&parent->u.dir.lock);
- if (de == NULL) return NULL;
+ if (de == NULL) goto out;
/* OK, there's an entry now, but no VFS inode yet */
}
- else
- {
- dentry->d_op = &devfs_wait_dops;
- d_add (dentry, NULL); /* Open the floodgates */
- }
/* Create an inode, now that the driver information is available */
inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
- devfs_put (de);
- if (!inode) return ERR_PTR (-ENOMEM);
- DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n",
- de->name, de->inode.ino, inode, de);
- d_instantiate (dentry, inode);
- if (dentry->d_op == &devfs_wait_dops)
- { /* Unlock directory semaphore, which will release any waiters. They
- will get the hashed dentry, and may be forced to wait for
- revalidation */
- up (&dir->i_sem);
- devfs_d_revalidate_wait (dentry, 0); /* I might have to wait too */
- down (&dir->i_sem); /* Grab it again because them's the rules */
+ if (!inode)
+ {
+ retval = ERR_PTR (-ENOMEM);
+ goto out;
}
- return NULL;
+ DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
+ de->name, de->inode.ino, inode, de, current->comm);
+ d_instantiate (dentry, inode);
+out:
+ dentry->d_op = &devfs_dops;
+ dentry->d_fsdata = NULL;
+ write_lock (&parent->u.dir.lock);
+ wake_up (&lookup_info.wait_queue);
+ write_unlock (&parent->u.dir.lock);
+ devfs_put (de);
+ return retval;
} /* End Function devfs_lookup */
static int devfs_unlink (struct inode *dir, struct dentry *dentry)
int i;
const char *p;
- dentry->d_inode = NULL; /* Assume failure */
dentry->d_op = &devpts_dentry_operations;
if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
if ( entry >= sbi->max_ptys )
return NULL;
- dentry->d_inode = sbi->inodes[entry];
- if ( dentry->d_inode )
- atomic_inc(&dentry->d_inode->i_count);
+ if ( sbi->inodes[entry] )
+ atomic_inc(&sbi->inodes[entry]->i_count);
- d_add(dentry, dentry->d_inode);
+ d_add(dentry, sbi->inodes[entry]);
return NULL;
}
entry = (struct driver_file_entry *)dentry->d_fsdata;
if (entry)
- kfree(dentry);
+ kfree(entry);
return 0;
}
for (walk = fat_cache; walk; walk = walk->next) {
if (walk->sb)
- printk("<%s,%d>(%d,%d) ", walk->sb->s_dev->s_id,
+ printk("<%s,%d>(%d,%d) ", walk->sb->s_id,
walk->start_cluster, walk->file_cluster,
walk->disk_cluster);
else printk("-- ");
}
inode->i_blksize = 1 << sbi->cluster_bits;
inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)
- & ~(inode->i_blksize - 1)) / 512;
+ & ~(inode->i_blksize - 1)) >> 9;
MSDOS_I(inode)->i_logstart = 0;
MSDOS_I(inode)->mmu_private = inode->i_size;
/* this is as close to the truth as we can get ... */
inode->i_blksize = 1 << sbi->cluster_bits;
inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)
- & ~(inode->i_blksize - 1)) / 512;
+ & ~(inode->i_blksize - 1)) >> 9;
inode->i_mtime = inode->i_atime =
date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date));
inode->i_ctime =
}
inodes_stat.nr_unused++;
spin_unlock(&inode_lock);
- if (!sb || sb->s_flags & MS_ACTIVE)
+ if (!sb || (sb->s_flags & MS_ACTIVE))
return;
write_inode_now(inode, 1);
spin_lock(&inode_lock);
static inline int presto_cache_hash(kdev_t dev)
{
- return (CACHES_MASK) & ((0x000F & (dev)) + ((0x0F00 & (dev)) >>8));
+ return (CACHES_MASK) & ((0x000F & (kdev_val(dev))) + ((0x0F00 & (kdev_val(dev))) >>8));
}
inline void presto_cache_add(struct presto_cache *cache, kdev_t dev)
lh = tmp = &(presto_caches[presto_cache_hash(dev)]);
while ( (tmp = lh->next) != lh ) {
cache = list_entry(tmp, struct presto_cache, cache_chain);
- if ( cache->cache_dev == dev ) {
+ if ( kdev_same(cache->cache_dev, dev) ) {
return cache;
}
}
cache = presto_find_cache(inode->i_dev);
if ( !cache ) {
printk("WARNING: no presto cache for dev %x, ino %ld\n",
- inode->i_dev, inode->i_ino);
+ kdev_val(inode->i_dev), inode->i_ino);
EXIT;
return NULL;
}
cache = presto_get_cache(inode);
if ( !cache )
return 0;
- return (inode->i_dev == cache->cache_dev);
+ return (kdev_same(inode->i_dev, cache->cache_dev));
}
/* setup a cache structure when we need one */
cache = presto_get_cache(inode);
CDEBUG(D_PSDEV, "\n");
if ( !cache ) {
- printk("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
- inode->i_dev, inode->i_ino);
+ printk("PRESTO: BAD: cannot find cache for dev %x, ino %ld\n",
+ kdev_val(inode->i_dev), inode->i_ino);
EXIT;
return -1;
}
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
+#include <linux/tty.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/termios.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/poll.h>
#include <asm/uaccess.h>
+#include <asm/ioctls.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_upcall.h>
}
len = readmount.io_len;
- minor = MINOR(dev);
+ minor = minor(dev);
PRESTO_ALLOC(tmp, char *, len);
if (!tmp) {
EXIT;
EXIT;
return error;
}
- minor = MINOR(dev);
+ minor = minor(dev);
if (cmd == PRESTO_SETOPT)
error = dosetopt(minor, &kopt);
* current presto cache.
*/
int errorval = upc_comms[minor].uc_errorval;
+ kdev_t kdev = mk_kdev(MAJOR(-errorval), MINOR(-errorval));
if (errorval < 0) {
if (newval == 0)
- set_device_ro(-errorval, 0);
+ set_device_ro(kdev, 0);
else
printk("device %s already read only\n",
- kdevname(-errorval));
+ kdevname(kdev));
} else {
+ kdev = mk_kdev(MAJOR(-newval), MINOR(-newval));
if (newval < 0)
- set_device_ro(-newval, 1);
+ set_device_ro(kdev, 1);
upc_comms[minor].uc_errorval = newval;
CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
}
#ifdef PSDEV_DEBUG
case PSDEV_ERRORVAL: {
int errorval = upc_comms[minor].uc_errorval;
- if (errorval < 0 && is_read_only(-errorval))
+ kdev_t kdev = mk_kdev(MAJOR(-errorval), MINOR(-errorval));
+ if (errorval < 0 && is_read_only(kdev))
printk(KERN_INFO "device %s has been set read-only\n",
- kdevname(-errorval));
+ kdevname(kdev));
opt->optval = upc_comms[minor].uc_errorval;
break;
}
if (errorval && errorval == (long)value && !is_read_only(dev)) {
CDEBUG(D_SUPER, "setting device %s read only\n", kdevname(dev));
BLKDEV_FAIL(dev, 1);
- upc_comms[minor].uc_errorval = -dev;
+ upc_comms[minor].uc_errorval = -kdev_val(dev);
}
}
#else
goto exit_lock;
error = -EXDEV;
- if (dir->d_inode->i_dev != inode->i_dev)
+ if (!kdev_same(dir->d_inode->i_dev, inode->i_dev))
goto exit_lock;
/*
if (error)
return error;
- if (new_dir->i_dev != old_dir->i_dev)
+ if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
return -EXDEV;
if (!new_dentry->d_inode)
if (error)
return error;
- if (new_dir->i_dev != old_dir->i_dev)
+ if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
return -EXDEV;
if (!new_dentry->d_inode)
new_jh->b_transaction = NULL;
new_bh->b_size = jh2bh(jh_in)->b_size;
+ new_bh->b_bdev = transaction->t_journal->j_dev;
new_bh->b_dev = to_kdev_t(transaction->t_journal->j_dev->bd_dev);
new_bh->b_blocknr = blocknr;
new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty);
{
struct buffer_head *bh = NULL;
journal_t *journal;
- kdev_t dev;
+ struct block_device *bdev;
int err;
if (bh_in)
return -EINVAL;
}
- dev = to_kdev_t(journal->j_fs_dev->bd_dev);
+ bdev = journal->j_fs_dev;
bh = bh_in;
if (!bh) {
- bh = get_hash_table(dev, blocknr, journal->j_blocksize);
+ bh = __get_hash_table(bdev, blocknr, journal->j_blocksize);
if (bh)
BUFFER_TRACE(bh, "found on hash");
}
/* If there is a different buffer_head lying around in
* memory anywhere... */
- bh2 = get_hash_table(dev, blocknr, journal->j_blocksize);
+ bh2 = __get_hash_table(bdev, blocknr, journal->j_blocksize);
if (bh2) {
/* ... and it has RevokeValid status... */
if ((bh2 != bh) &&
* state machine will get very upset later on. */
if (need_cancel && !bh->b_pprev) {
struct buffer_head *bh2;
- bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ bh2 = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
if (bh2) {
clear_bit(BH_Revoked, &bh2->b_state);
__brelse(bh2);
clear_bit(BH_Mapped, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
clear_bit(BH_New, &bh->b_state);
+ bh->b_bdev = NULL;
return may_free;
}
COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
compr_zlib.o zlib.o
-JFFS2_OBJS := crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \
+JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
symlink.o build.o erase.o background.o
+++ /dev/null
-/*
- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
- * code or tables extracted from it, as desired without restriction.
- *
- * First, the polynomial itself and its table of feedback terms. The
- * polynomial is
- * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
- *
- * Note that we take it "backwards" and put the highest-order term in
- * the lowest-order bit. The X^32 term is "implied"; the LSB is the
- * X^31 term, etc. The X^0 term (usually shown as "+1") results in
- * the MSB being 1
- *
- * Note that the usual hardware shift register implementation, which
- * is what we're using (we're merely optimizing it by doing eight-bit
- * chunks at a time) shifts bits into the lowest-order term. In our
- * implementation, that means shifting towards the right. Why do we
- * do it this way? Because the calculated CRC must be transmitted in
- * order from highest-order term to lowest-order term. UARTs transmit
- * characters in order from LSB to MSB. By storing the CRC this way
- * we hand it to the UART in the order low-byte to high-byte; the UART
- * sends each low-bit to hight-bit; and the result is transmission bit
- * by bit from highest- to lowest-order term without requiring any bit
- * shuffling on our part. Reception works similarly
- *
- * The feedback terms table consists of 256, 32-bit entries. Notes
- *
- * The table can be generated at runtime if desired; code to do so
- * is shown later. It might not be obvious, but the feedback
- * terms simply represent the results of eight shift/xor opera
- * tions for all combinations of data and CRC register values
- *
- * The values must be right-shifted by eight bits by the "updcrc
- * logic; the shift must be unsigned (bring in zeroes). On some
- * hardware you could probably optimize the shift in assembler by
- * using byte-swap instructions
- * polynomial $edb88320
- */
-
-/* $Id: crc32.c,v 1.3 2001/02/07 16:45:32 dwmw2 Exp $ */
-
-#include "crc32.h"
-
-const __u32 crc32_table[256] = {
- 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
- 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
- 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
- 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
- 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
- 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
- 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
- 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
- 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
- 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
- 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
- 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
- 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
- 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
- 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
- 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
- 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
- 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
- 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
- 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
- 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
- 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
- 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
- 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
- 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
- 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
- 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
- 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
- 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
- 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
- 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
- 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
- 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
- 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
- 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
- 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
- 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
- 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
- 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
- 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
- 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
- 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
- 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
- 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
- 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
- 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
- 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
- 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
- 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
- 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
- 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
- 0x2d02ef8dL
-};
+++ /dev/null
-#ifndef CRC32_H
-#define CRC32_H
-
-/* $Id: crc32.h,v 1.3 2001/02/26 14:44:37 dwmw2 Exp $ */
-
-#include <linux/types.h>
-
-extern const __u32 crc32_table[256];
-
-/* Return a 32-bit CRC of the contents of the buffer. */
-
-static inline __u32
-crc32(__u32 val, const void *ss, int len)
-{
- const unsigned char *s = ss;
- while (--len >= 0)
- val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
- return val;
-}
-
-#endif
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/jffs2_fs_i.h>
#include <linux/jffs2_fs_sb.h>
#include "nodelist.h"
-#include "crc32.h"
static int jffs2_readdir (struct file *, void *, filldir_t);
#include <linux/mtd/mtd.h>
#include <linux/jffs2.h>
#include <linux/interrupt.h>
+#include <linux/crc32.h>
#include "nodelist.h"
-#include "crc32.h"
struct erase_priv_struct {
struct jffs2_eraseblock *jeb;
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include "nodelist.h"
-#include "crc32.h"
extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include "nodelist.h"
-#include "crc32.h"
static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct inode *inode, struct jffs2_full_dnode *fd);
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
-#include "crc32.h"
int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
{
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/crc32.h>
#include <linux/mtd/mtd.h>
#include <linux/jffs2.h>
#include "nodelist.h"
-#include "crc32.h"
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include "nodelist.h"
-#include "crc32.h"
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
#include <linux/kernel.h>
#include <linux/fs.h>
+#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
-#include "crc32.h"
/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
fill in the raw_inode while you're at it. */
* kernel data space before using them..
*
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
+ * PATH_MAX includes the nul terminator --RR.
*/
static inline int do_getname(const char *filename, char *page)
{
int retval;
- unsigned long len = PATH_MAX + 1;
+ unsigned long len = PATH_MAX;
if ((unsigned long) filename >= TASK_SIZE) {
if (!segment_eq(get_fs(), KERNEL_DS))
return -EFAULT;
- } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1)
+ } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
len = TASK_SIZE - (unsigned long) filename;
retval = strncpy_from_user((char *)page, filename, len);
-/* $Id: inode.c,v 1.14 2001/02/13 01:17:17 davem Exp $
+/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
add_gd_partition(hd, *current_minor, next, size);
#if CONFIG_BLK_DEV_MD
if (SYS_IND(p) == LINUX_RAID_PARTITION) {
- md_autodetect_dev(MKDEV(hd->major,*current_minor));
+ md_autodetect_dev(mk_kdev(hd->major,*current_minor));
}
#endif
NR_SECTS(p)*sector_size);
#if CONFIG_BLK_DEV_MD
if (SYS_IND(p) == LINUX_RAID_PARTITION) {
- md_autodetect_dev(MKDEV(hd->major,minor));
+ md_autodetect_dev(mk_kdev(hd->major,minor));
}
#endif
if (is_extended_partition(p)) {
block_to_try = (i * (s->s_blocksize << 3)) + j;
/* the block is not in the journal, we can proceed */
- if (!(reiserfs_in_journal(s, s->s_dev, block_to_try, s->s_blocksize, for_unformatted, &next_block_to_try))) {
+ if (!(reiserfs_in_journal(s, block_to_try, for_unformatted, &next_block_to_try))) {
*bmap_nr = i;
*offset = j;
return 1;
}
/* return a cnode with same dev, block number and size in table, or null if not found */
-static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct reiserfs_journal_cnode **table,
- kdev_t dev,long bl,int size) {
+static inline struct reiserfs_journal_cnode *
+get_journal_hash_dev(struct super_block *sb,
+ struct reiserfs_journal_cnode **table,
+ long bl)
+{
struct reiserfs_journal_cnode *cn ;
- cn = journal_hash(table, dev, bl) ;
+ cn = journal_hash(table, sb, bl) ;
while(cn) {
- if ((cn->blocknr == bl) && (kdev_same(cn->dev, dev)))
+ if (cn->blocknr == bl && cn->sb == sb)
return cn ;
cn = cn->hnext ;
}
static inline struct reiserfs_journal_cnode *get_journal_hash(struct super_block *p_s_sb, struct buffer_head *bh) {
struct reiserfs_journal_cnode *cn ;
if (bh) {
- cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_dev, bh->b_blocknr, bh->b_size) ;
+ cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_blocknr);
}
else {
return (struct reiserfs_journal_cnode *)0 ;
** reject it on the next call to reiserfs_in_journal
**
*/
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev,
- unsigned long bl, int size, int search_all,
+int reiserfs_in_journal(struct super_block *p_s_sb,
+ unsigned long bl, int search_all,
unsigned long *next_zero_bit) {
struct reiserfs_journal_cnode *cn ;
struct reiserfs_list_bitmap *jb ;
}
/* is it in any old transactions? */
- if (search_all && (cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, dev,bl,size))) {
+ if (search_all && (cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bl))) {
return 1;
}
/* is it in the current transaction. This should never happen */
- if ((cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, dev,bl,size))) {
+ if ((cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, bl))) {
return 1;
}
inline void insert_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_cnode *cn) {
struct reiserfs_journal_cnode *cn_orig ;
- cn_orig = journal_hash(table, cn->dev, cn->blocknr) ;
+ cn_orig = journal_hash(table, cn->sb, cn->blocknr) ;
cn->hnext = cn_orig ;
cn->hprev = NULL ;
if (cn_orig) {
cn_orig->hprev = cn ;
}
- journal_hash(table, cn->dev, cn->blocknr) = cn ;
+ journal_hash(table, cn->sb, cn->blocknr) = cn ;
}
/* lock the current transaction */
** returns NULL if it can't find anything
*/
static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journal_cnode *cn) {
- kdev_t dev = cn->dev;
+ struct super_block *sb = cn->sb;
unsigned long blocknr = cn->blocknr ;
cn = cn->hprev ;
while(cn) {
- if (kdev_same(cn->dev, dev) && cn->blocknr == blocknr && cn->jlist) {
+ if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist) {
return cn->jlist ;
}
cn = cn->hprev ;
return NULL ;
}
+void remove_journal_hash(struct super_block *, struct reiserfs_journal_cnode **,
+struct reiserfs_journal_list *, unsigned long, int);
/*
** once all the real blocks have been flushed, it is safe to remove them from the
** block to be reallocated for data blocks if it had been deleted.
*/
static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reiserfs_journal_list *jl, int debug) {
- struct buffer_head fake_bh ;
struct reiserfs_journal_cnode *cn, *last ;
cn = jl->j_realblock ;
/* which is better, to lock once around the whole loop, or
- ** to lock for each call to remove_from_journal_list?
+ ** to lock for each call to remove_journal_hash?
*/
while(cn) {
if (cn->blocknr != 0) {
printk("block %lu, bh is %d, state %d\n", cn->blocknr, cn->bh ? 1: 0,
cn->state) ;
}
- fake_bh.b_blocknr = cn->blocknr ;
- fake_bh.b_dev = cn->dev ;
cn->state = 0 ;
- remove_from_journal_list(p_s_sb, jl, &fake_bh, 1) ;
+ remove_journal_hash(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, jl, cn->blocknr, 1) ;
}
last = cn ;
cn = cn->next ;
mark_buffer_notjournal_dirty(cn->bh) ;
while(walk_cn) {
if (walk_cn->bh && walk_cn->blocknr == blocknr &&
- kdev_same(walk_cn->dev, cn->dev)) {
+ walk_cn->sb == cn->sb) {
if (walk_cn->jlist) {
atomic_dec(&(walk_cn->jlist->j_nonzerolen)) ;
}
** removes any nodes in table with name block and dev as bh.
** only touchs the hnext and hprev pointers.
*/
-void remove_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_list *jl,struct buffer_head *bh,
- int remove_freed){
+void remove_journal_hash(struct super_block *sb,
+ struct reiserfs_journal_cnode **table,
+ struct reiserfs_journal_list *jl,
+ unsigned long block, int remove_freed)
+{
struct reiserfs_journal_cnode *cur ;
struct reiserfs_journal_cnode **head ;
- if (!bh)
- return ;
-
- head= &(journal_hash(table, bh->b_dev, bh->b_blocknr)) ;
+ head= &(journal_hash(table, sb, block)) ;
if (!head) {
return ;
}
cur = *head ;
while(cur) {
- if (cur->blocknr == bh->b_blocknr && kdev_same(cur->dev, bh->b_dev) && (jl == NULL || jl == cur->jlist) &&
+ if (cur->blocknr == block && cur->sb == sb && (jl == NULL || jl == cur->jlist) &&
(!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) {
if (cur->hnext) {
cur->hnext->hprev = cur->hprev ;
*head = cur->hnext ;
}
cur->blocknr = 0 ;
- cur->dev = NODEV ;
+ cur->sb = NULL ;
cur->state = 0 ;
if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */
atomic_dec(&(cur->jlist->j_nonzerolen)) ;
cn->bh = bh ;
cn->blocknr = bh->b_blocknr ;
- cn->dev = bh->b_dev ;
+ cn->sb = p_s_sb;
cn->jlist = NULL ;
insert_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, cn) ;
if (!count_already_incd) {
buffer_journal_dirty(bh)) {
return journal_mark_dirty(th, p_s_sb, bh) ;
}
- if (get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_dev,bh->b_blocknr,bh->b_size)) {
+ if (get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_blocknr)) {
return journal_mark_dirty(th, p_s_sb, bh) ;
}
mark_buffer_dirty(bh) ;
struct reiserfs_journal_cnode *cn ;
int ret = 0;
- cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+ cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, blocknr) ;
if (!cn || !cn->bh) {
return ret ;
}
if (cn == SB_JOURNAL(p_s_sb)->j_last) {
SB_JOURNAL(p_s_sb)->j_last = cn->prev ;
}
- remove_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, NULL, bh, 0) ;
+ if (bh)
+ remove_journal_hash(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, NULL, bh->b_blocknr, 0) ;
mark_buffer_not_journaled(bh) ; /* don't log this one */
if (!already_cleaned) {
return ret ;
}
-/* removes from a specific journal list hash */
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
- remove_journal_hash(SB_JOURNAL(s)->j_list_hash_table, jl, bh, remove_freed) ;
- return 0 ;
-}
-
/*
** for any cnode in a journal list, it can only be dirtied of all the
** transactions that include it are commited to disk.
**
*/
static int can_dirty(struct reiserfs_journal_cnode *cn) {
- kdev_t dev = cn->dev ;
+ struct super_block *sb = cn->sb;
unsigned long blocknr = cn->blocknr ;
struct reiserfs_journal_cnode *cur = cn->hprev ;
int can_dirty = 1 ;
** to disk right now.
*/
while(cur && can_dirty) {
- if (cur->jlist && cur->bh && cur->blocknr && kdev_same(cur->dev, dev) &&
+ if (cur->jlist && cur->bh && cur->blocknr && cur->sb == sb &&
cur->blocknr == blocknr) {
can_dirty = 0 ;
}
while(cur && can_dirty) {
if (cur->jlist && cur->jlist->j_len > 0 &&
atomic_read(&(cur->jlist->j_commit_left)) > 0 && cur->bh &&
- cur->blocknr && kdev_same(cur->dev, dev) && cur->blocknr == blocknr) {
+ cur->blocknr && cur->sb == sb && cur->blocknr == blocknr) {
can_dirty = 0 ;
}
cur = cur->hnext ;
cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned) ;
/* find all older transactions with this block, make sure they don't try to write it out */
- cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+ cn = get_journal_hash_dev(p_s_sb,SB_JOURNAL(p_s_sb)->j_list_hash_table, blocknr) ;
while (cn) {
- if (kdev_same(p_s_sb->s_dev, cn->dev) && blocknr == cn->blocknr) {
+ if (p_s_sb == cn->sb && blocknr == cn->blocknr) {
set_bit(BLOCK_FREED, &cn->state) ;
if (cn->bh) {
if (!cleaned) {
}
jl_cn->blocknr = cn->bh->b_blocknr ;
jl_cn->state = 0 ;
- jl_cn->dev = cn->bh->b_dev ;
+ jl_cn->sb = p_s_sb ;
jl_cn->bh = cn->bh ;
jl_cn->jlist = SB_JOURNAL_LIST(p_s_sb) + SB_JOURNAL_LIST_INDEX(p_s_sb) ;
insert_journal_hash(SB_JOURNAL(p_s_sb)->j_list_hash_table, jl_cn) ;
clear_bit(BH_Mapped, &bh->b_state) ;
clear_bit(BH_Req, &bh->b_state) ;
clear_bit(BH_New, &bh->b_state) ;
+ bh->b_bdev = NULL;
unlock_buffer(bh) ;
}
}
-/* $Id: bitops.h,v 1.65 2001/10/30 04:08:26 davem Exp $
+/* $Id: bitops.h,v 1.67 2001/11/19 18:36:34 davem Exp $
* bitops.h: Bit string operations on the Sparc.
*
* Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
/*
- * $Id: io.h,v 1.29 2001/11/10 09:28:34 davem Exp $
+ * $Id: io.h,v 1.30 2001/12/21 01:23:21 davem Exp $
*/
#ifndef __SPARC_IO_H
#define __SPARC_IO_H
#include <asm/page.h> /* IO address mapping routines need this */
#include <asm/system.h>
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
+#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
static __inline__ u32 flip_dword (u32 d)
{
-/* $Id: keyboard.h,v 1.7 2001/08/18 09:40:46 davem Exp $
+/* $Id: keyboard.h,v 1.8 2002/01/08 16:00:20 davem Exp $
* linux/include/asm-sparc/keyboard.h
*
* sparc64 Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
#ifndef __ASSEMBLY__
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be clear. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+
+static inline int sched_find_first_zero_bit(unsigned long *b)
+{
+ unsigned int rt;
+
+ rt = b[0] & b[1] & b[2] & b[3];
+ if (unlikely(rt != 0xffffffff))
+ return find_first_zero_bit(b, MAX_RT_PRIO);
+
+ if (b[4] != ~0)
+ return ffz(b[4]) + MAX_RT_PRIO;
+ return ffz(b[5]) + 32 + MAX_RT_PRIO;
+}
+
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
{
}
-/* $Id: oplib.h,v 1.21 2000/08/26 02:38:04 anton Exp $
+/* $Id: oplib.h,v 1.23 2001/12/21 00:54:31 davem Exp $
* oplib.h: Describes the interface and available routines in the
* Linux Prom library.
*
/* Dorking with Bus ranges... */
-/* Adjust reg values with the passed ranges. */
-extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
- struct linux_prom_ranges *rangep, int nranges);
-
-/* Adjust child ranges with the passed parent ranges. */
-extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
- struct linux_prom_ranges *pranges, int npranges);
-
-/* Apply promlib probed OBIO ranges to registers. */
+/* Apply promlib probes OBIO ranges to registers. */
extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
/* Apply ranges of any prom node (and optionally parent node as well) to registers. */
/* Dynamic DMA mapping stuff.
*/
+#define PCI_DMA_BUS_IS_PHYS (0)
#include <asm/scatterlist.h>
#define MBOX_IDLECPU2 0xFD
#define MBOX_STOPCPU2 0xFE
-#define PROC_CHANGE_PENALTY 15
-
#endif /* !(CONFIG_SMP) */
#define NO_PROC_ID 0xFF
*
* Default SMP lock implementation
*/
+#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
extern spinlock_t kernel_flag;
-#define kernel_locked() spin_is_locked(&kernel_flag)
+#define kernel_locked() \
+ (spin_is_locked(&kernel_flag) &&\
+ (current->lock_depth >= 0))
/*
* Release global kernel lock and global interrupt lock
*/
-#define release_kernel_lock(task, cpu) \
-do { \
- if (task->lock_depth >= 0) \
- spin_unlock(&kernel_flag); \
- release_irqlock(cpu); \
- __sti(); \
+#define release_kernel_lock(task, cpu) \
+do { \
+ if (unlikely(task->lock_depth >= 0)) { \
+ spin_unlock(&kernel_flag); \
+ release_irqlock(cpu); \
+ __sti(); \
+ } \
} while (0)
/*
* Re-acquire the kernel lock
*/
-#define reacquire_kernel_lock(task) \
-do { \
- if (task->lock_depth >= 0) \
- spin_lock(&kernel_flag); \
+#define reacquire_kernel_lock(task) \
+do { \
+ if (unlikely(task->lock_depth >= 0)) \
+ spin_lock(&kernel_flag); \
} while (0)
* so we only need to worry about other
* CPU's.
*/
-extern __inline__ void lock_kernel(void)
-{
- if (!++current->lock_depth)
- spin_lock(&kernel_flag);
-}
+#define lock_kernel() \
+do { \
+ if (!++current->lock_depth) \
+ spin_lock(&kernel_flag); \
+} while(0)
-extern __inline__ void unlock_kernel(void)
-{
- if (--current->lock_depth < 0)
- spin_unlock(&kernel_flag);
-}
+#define unlock_kernel() \
+do { \
+ if (--current->lock_depth < 0) \
+ spin_unlock(&kernel_flag); \
+} while(0)
-/* $Id: string.h,v 1.35 2000/05/02 01:47:01 davem Exp $
+/* $Id: string.h,v 1.36 2001/12/21 00:54:31 davem Exp $
* string.h: External definitions for optimized assembly string
* routines for the Linux Kernel.
*
})
#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *,const void *,__kernel_size_t);
/* Now the str*() stuff... */
#define __HAVE_ARCH_STRLEN
+extern __kernel_size_t strlen(const char *);
#define __HAVE_ARCH_STRNCMP
-/* $Id: types.h,v 1.12 2000/01/29 02:23:25 anton Exp $ */
+/* $Id: types.h,v 1.13 2001/12/21 01:22:59 davem Exp $ */
#ifndef _SPARC_TYPES_H
#define _SPARC_TYPES_H
#define BITS_PER_LONG 32
typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
#endif /* __KERNEL__ */
-/* $Id: bitops.h,v 1.36 2001/06/14 12:34:49 davem Exp $
+/* $Id: bitops.h,v 1.38 2001/11/19 18:36:34 davem Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
-#define test_and_set_bit(nr,addr) (___test_and_set_bit(nr,addr)!=0)
-#define test_and_clear_bit(nr,addr) (___test_and_clear_bit(nr,addr)!=0)
-#define test_and_change_bit(nr,addr) (___test_and_change_bit(nr,addr)!=0)
+#define test_and_set_bit(nr,addr) ({___test_and_set_bit(nr,addr)!=0;})
+#define test_and_clear_bit(nr,addr) ({___test_and_clear_bit(nr,addr)!=0;})
+#define test_and_change_bit(nr,addr) ({___test_and_change_bit(nr,addr)!=0;})
#define set_bit(nr,addr) ((void)___test_and_set_bit(nr,addr))
#define clear_bit(nr,addr) ((void)___test_and_clear_bit(nr,addr))
#define change_bit(nr,addr) ((void)___test_and_change_bit(nr,addr))
extern long ___test_and_set_le_bit(int nr, volatile void *addr);
extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
-#define test_and_set_le_bit(nr,addr) (___test_and_set_le_bit(nr,addr)!=0)
-#define test_and_clear_le_bit(nr,addr) (___test_and_clear_le_bit(nr,addr)!=0)
+#define test_and_set_le_bit(nr,addr) ({___test_and_set_le_bit(nr,addr)!=0;})
+#define test_and_clear_le_bit(nr,addr) ({___test_and_clear_le_bit(nr,addr)!=0;})
#define set_le_bit(nr,addr) ((void)___test_and_set_le_bit(nr,addr))
#define clear_le_bit(nr,addr) ((void)___test_and_clear_le_bit(nr,addr))
-/* $Id: elf.h,v 1.30 2001/08/30 23:35:38 kanoj Exp $ */
+/* $Id: elf.h,v 1.31 2002/01/08 16:00:20 davem Exp $ */
#ifndef __ASM_SPARC64_ELF_H
#define __ASM_SPARC64_ELF_H
else \
flags &= ~SPARC_FLAG_32BIT; \
if (flags != current->thread.flags) { \
- unsigned long pgd_cache = 0UL; \
- if (flags & SPARC_FLAG_32BIT) { \
- pgd_t *pgd0 = ¤t->mm->pgd[0]; \
- if (pgd_none (*pgd0)) { \
- pmd_t *page = pmd_alloc_one_fast(NULL, 0); \
- if (!page) \
- page = pmd_alloc_one(NULL, 0); \
- pgd_set(pgd0, page); \
- } \
- pgd_cache = pgd_val(*pgd0) << 11UL; \
- } \
- __asm__ __volatile__( \
- "stxa\t%0, [%1] %2\n\t" \
- "membar #Sync" \
- : /* no outputs */ \
- : "r" (pgd_cache), \
- "r" (TSB_REG), \
- "i" (ASI_DMMU)); \
+ /* flush_thread will update pgd cache */\
current->thread.flags = flags; \
} \
\
-/* $Id: io.h,v 1.46 2001/12/13 04:16:52 davem Exp $ */
+/* $Id: io.h,v 1.47 2001/12/13 10:36:02 davem Exp $ */
#ifndef __SPARC64_IO_H
#define __SPARC64_IO_H
-/* $Id: keyboard.h,v 1.5 2001/08/18 09:40:46 davem Exp $
+/* $Id: keyboard.h,v 1.6 2002/01/08 16:00:20 davem Exp $
* linux/include/asm-sparc64/keyboard.h
*
* Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
-/* $Id: mmu_context.h,v 1.51 2001/08/17 04:55:09 kanoj Exp $ */
+/* $Id: mmu_context.h,v 1.52 2002/01/11 08:45:38 davem Exp $ */
#ifndef __SPARC64_MMU_CONTEXT_H
#define __SPARC64_MMU_CONTEXT_H
#include <asm/system.h>
#include <asm/spitfire.h>
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be clear. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+
+static inline int sched_find_first_zero_bit(unsigned long *b)
+{
+ unsigned long rt;
+
+ rt = b[0] & b[1];
+ if (unlikely(rt != 0xffffffffffffffff))
+ return find_first_zero_bit(b, MAX_RT_PRIO);
+
+ return ffz(b[2]) + MAX_RT_PRIO;
+}
+
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
{
}
-/* $Id: oplib.h,v 1.13 2000/05/09 17:40:15 davem Exp $
+/* $Id: oplib.h,v 1.14 2001/12/19 00:29:51 davem Exp $
* oplib.h: Describes the interface and available routines in the
* Linux Prom library.
*
/* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba);
-/* Dorking with Bus ranges... */
-
-/* Adjust reg values with the passed ranges. */
-extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
- struct linux_prom_ranges *rangep, int nranges);
-
-/* Adjust child ranges with the passed parent ranges. */
-extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
- struct linux_prom_ranges *pranges, int npranges);
-
-/* Apply ranges of any prom node (and optionally parent node as well) to registers. */
-extern void prom_apply_generic_ranges(int node, int parent,
- struct linux_prom_registers *sbusregs, int nregs);
-
extern long p1275_cmd (char *, long, ...);
-/* $Id: page.h,v 1.36 2000/08/10 01:04:53 davem Exp $ */
+/* $Id: page.h,v 1.38 2001/11/30 01:04:10 davem Exp $ */
#ifndef _SPARC64_PAGE_H
#define _SPARC64_PAGE_H
#ifndef __ASSEMBLY__
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void do_BUG(const char *file, int line);
+#define BUG() do { \
+ do_BUG(__FILE__, __LINE__); \
+ __builtin_trap(); \
+} while (0)
+#else
#define BUG() __builtin_trap()
+#endif
+
#define PAGE_BUG(page) BUG()
extern void _clear_page(void *page);
-extern void _copy_page(void *to, void *from);
#define clear_page(X) _clear_page((void *)(X))
-#define copy_page(X,Y) _copy_page((void *)(X), (void *)(Y))
extern void clear_user_page(void *page, unsigned long vaddr);
extern void copy_user_page(void *to, void *from, unsigned long vaddr);
-/* $Id: processor.h,v 1.76 2001/10/08 09:32:13 davem Exp $
+/* $Id: processor.h,v 1.80 2001/11/17 00:10:48 davem Exp $
* include/asm-sparc64/processor.h
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
unsigned long gsr[7];
unsigned long xfsr[7];
+#ifdef CONFIG_DEBUG_SPINLOCK
+ /* How many spinlocks held by this thread.
+ * Used with spin lock debugging to catch tasks
+ * sleeping illegally with locks held.
+ */
+ int smp_lock_count;
+ unsigned int smp_lock_pc;
+#endif
+
struct reg_window reg_window[NSWINS];
unsigned long rwbuf_stkptrs[NSWINS];
#define FAULT_CODE_ITLB 0x04 /* Miss happened in I-TLB */
#define FAULT_CODE_WINFIXUP 0x08 /* Miss happened during spill/fill */
+#ifndef CONFIG_DEBUG_SPINLOCK
#define INIT_THREAD { \
/* ksp, wstate, cwp, flags, current_ds, */ \
0, 0, 0, 0, KERNEL_DS, \
/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
0, 0, 0, 0, 0, \
}
+#else /* CONFIG_DEBUG_SPINLOCK */
+#define INIT_THREAD { \
+/* ksp, wstate, cwp, flags, current_ds, */ \
+ 0, 0, 0, 0, KERNEL_DS, \
+/* w_saved, fpdepth, fault_code, use_blkcommit, */ \
+ 0, 0, 0, 0, \
+/* fault_address, fpsaved, __pad2, kregs, */ \
+ 0, { 0 }, 0, 0, \
+/* utraps, gsr, xfsr, smp_lock_count, smp_lock_pc, */\
+ 0, { 0 }, { 0 }, 0, 0, \
+/* reg_window */ \
+ { { { 0, }, { 0, } }, }, \
+/* rwbuf_stkptrs */ \
+ { 0, 0, 0, 0, 0, 0, 0, }, \
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+ 0, 0, 0, 0, 0, \
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
#ifdef __KERNEL__
#if PAGE_SHIFT == 13
-/* $Id: rwsem.h,v 1.4 2001/04/26 02:36:36 davem Exp $
+/* $Id: rwsem.h,v 1.5 2001/11/18 00:12:56 davem Exp $
* rwsem.h: R/W semaphores implemented using CAS
*
* Written by David S. Miller (davem@redhat.com), 2001.
" add %%g7, 1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
- " membar #StoreStore\n"
+ " membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"bne,pn %%icc, 1b\n\t"
" cmp %%g7, 0\n\t"
"bne,pn %%icc, 3f\n\t"
- " membar #StoreStore\n"
+ " membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"bne,pn %%icc, 1b\n\t"
" cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
- " membar #StoreStore\n"
+ " membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tsethi %%hi(%2), %%g1\n\t"
" sub %%g7, %%g1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
- " membar #StoreStore\n"
+ " membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"cas [%2], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
- " nop\n\t"
+ " membar #StoreLoad | #StoreStore\n\t"
"mov %%g7, %0\n\t"
: "=&r" (tmp)
: "0" (tmp), "r" (sem)
again:
__asm__ __volatile__("cas [%2], %3, %0\n\t"
- "membar #StoreStore | #StoreLoad"
+ "membar #StoreLoad | #StoreStore"
: "=&r" (prev)
: "0" (new), "r" (sem), "r" (old)
: "memory");
" bne,pn %%icc, 1b\n"
" cmp %%g7, 1\n"
" bl,pn %%icc, 3f\n"
-" membar #StoreStore\n"
+" membar #StoreLoad | #StoreStore\n"
"2:\n"
" .subsection 2\n"
"3: mov %0, %%g5\n"
" bne,pn %%icc, 1b\n"
" cmp %%g7, 1\n"
" bl,pn %%icc, 3f\n"
-" membar #StoreStore\n"
+" membar #StoreLoad | #StoreStore\n"
"2:\n"
" .subsection 2\n"
"3: mov %2, %%g5\n"
" cmp %%g5, %%g7\n"
" bne,pn %%icc, 1b\n"
" mov 0, %0\n"
-" membar #StoreStore\n"
+" membar #StoreLoad | #StoreStore\n"
"2:\n"
: "=&r" (ret)
: "r" (sem)
" bne,pn %%icc, 1b\n"
" addcc %%g7, 1, %%g0\n"
" ble,pn %%icc, 3f\n"
-" nop\n"
+" membar #StoreLoad | #StoreStore\n"
"2:\n"
" .subsection 2\n"
"3: mov %0, %%g5\n"
#include <linux/config.h>
#include <linux/threads.h>
+#include <linux/cache.h>
#include <asm/asi.h>
#include <asm/starfire.h>
#include <asm/spitfire.h>
/* Per processor Sparc parameters we need. */
/* Keep this a multiple of 64-bytes for cache reasons. */
-struct cpuinfo_sparc {
+typedef struct {
/* Dcache line 1 */
unsigned int __pad0; /* bh_count moved to irq_stat for consistency. KAO */
unsigned int multiplier;
/* Dcache lines 3 and 4 */
unsigned int irq_worklists[16];
-};
+} ____cacheline_aligned cpuinfo_sparc;
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern cpuinfo_sparc cpu_data[NR_CPUS];
/*
* Private routines/data
}
}
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current->cpu)
/* This needn't do anything as we do not sleep the cpu
* inside of the idler task, so an interrupt is not needed
* to get a clean fast response.
*
+ * XXX Reverify this assumption... -DaveM
+ *
* Addendum: We do want it to do something for the signal
* delivery case, we detect that by just seeing
* if we are trying to send this to an idler or not.
*/
-extern __inline__ void smp_send_reschedule(int cpu)
+static __inline__ void smp_send_reschedule(int cpu)
{
extern void smp_receive_signal(int);
- if(cpu_data[cpu].idle_volume == 0)
+ if (cpu_data[cpu].idle_volume == 0)
smp_receive_signal(cpu);
}
#endif /* !(__ASSEMBLY__) */
-#define PROC_CHANGE_PENALTY 20
-
#endif /* !(CONFIG_SMP) */
#define NO_PROC_ID 0xFF
extern spinlock_t kernel_flag;
-#define kernel_locked() spin_is_locked(&kernel_flag)
+#define kernel_locked() \
+ (spin_is_locked(&kernel_flag) &&\
+ (current->lock_depth >= 0))
/*
* Release global kernel lock and global interrupt lock
*/
-#define release_kernel_lock(task, cpu) \
-do { \
- if (task->lock_depth >= 0) \
- spin_unlock(&kernel_flag); \
- release_irqlock(cpu); \
- __sti(); \
+#define release_kernel_lock(task, cpu) \
+do { \
+ if (unlikely(task->lock_depth >= 0)) { \
+ spin_unlock(&kernel_flag); \
+ release_irqlock(cpu); \
+ __sti(); \
+ } \
} while (0)
/*
* Re-acquire the kernel lock
*/
-#define reacquire_kernel_lock(task) \
-do { \
- if (task->lock_depth >= 0) \
- spin_lock(&kernel_flag); \
+#define reacquire_kernel_lock(task) \
+do { \
+ if (unlikely(task->lock_depth >= 0)) \
+ spin_lock(&kernel_flag); \
} while (0)
* so we only need to worry about other
* CPU's.
*/
-#define lock_kernel() \
-do { \
- if (!++current->lock_depth) \
- spin_lock(&kernel_flag); \
+#define lock_kernel() \
+do { \
+ if (!++current->lock_depth) \
+ spin_lock(&kernel_flag); \
} while(0)
-#define unlock_kernel() \
-do { \
- if (--current->lock_depth < 0) \
- spin_unlock(&kernel_flag); \
+#define unlock_kernel() \
+do { \
+ if (--current->lock_depth < 0) \
+ spin_unlock(&kernel_flag); \
} while(0)
#ifndef __SPARC64_SPINLOCK_H
#define __SPARC64_SPINLOCK_H
+#include <linux/config.h>
+
#ifndef __ASSEMBLY__
/* To get debugging spinlocks which detect and catch
- * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
- * specific makefile and rebuild your kernel.
+ * deadlock situations, set CONFIG_DEBUG_SPINLOCK
+ * and rebuild your kernel.
*/
/* All of these locking primitives are expected to work properly
* must be pre-V9 branches.
*/
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
typedef unsigned char spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
: "memory");
}
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
typedef struct {
unsigned char lock;
#define spin_lock(lock) _do_spin_lock(lock, "spin_lock")
#define spin_unlock(lock) _do_spin_unlock(lock)
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
typedef unsigned int rwlock_t;
#define RW_LOCK_UNLOCKED 0
#define write_lock(p) __write_lock(p)
#define write_unlock(p) __write_unlock(p)
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
typedef struct {
unsigned long lock;
__restore_flags(flags); \
} while(0)
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
#endif /* !(__ASSEMBLY__) */
-/* $Id: spitfire.h,v 1.16 2001/09/24 21:17:57 kanoj Exp $
+/* $Id: spitfire.h,v 1.18 2001/11/29 16:42:10 kanoj Exp $
* spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
#define VIRT_WATCHPOINT 0x0000000000000038
#define PHYS_WATCHPOINT 0x0000000000000040
+#define SPITFIRE_HIGHEST_LOCKED_TLBENT (64 - 1)
+
#ifndef __ASSEMBLY__
enum ultra_tlb_layout {
#define SPARC64_USE_STICK (tlb_type == cheetah)
-#define SPITFIRE_HIGHEST_LOCKED_TLBENT (64 - 1)
#define CHEETAH_HIGHEST_LOCKED_TLBENT (16 - 1)
#define L1DCACHE_SIZE 0x4000
* 2 way assosciative, and holds 512 entries. The fourth TLB is for
* instruction accesses to 8K non-locked translations, is 2 way
* assosciative, and holds 128 entries.
+ *
+ * Cheetah has some bug where bogus data can be returned from
+ * ASI_{D,I}TLB_DATA_ACCESS loads, doing the load twice fixes
+ * the problem for me. -DaveM
*/
extern __inline__ unsigned long cheetah_get_ldtlb_data(int entry)
{
unsigned long data;
- __asm__ __volatile__("ldxa [%1] %2, %0"
+ __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t"
+ "ldxa [%1] %2, %0"
: "=r" (data)
: "r" ((0 << 16) | (entry << 3)),
"i" (ASI_DTLB_DATA_ACCESS));
{
unsigned long data;
- __asm__ __volatile__("ldxa [%1] %2, %0"
+ __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t"
+ "ldxa [%1] %2, %0"
: "=r" (data)
: "r" ((0 << 16) | (entry << 3)),
"i" (ASI_ITLB_DATA_ACCESS));
{
unsigned long data;
- __asm__ __volatile__("ldxa [%1] %2, %0"
+ __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t"
+ "ldxa [%1] %2, %0"
: "=r" (data)
: "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
{
unsigned long data;
- __asm__ __volatile__("ldxa [%1] %2, %0"
+ __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t"
+ "ldxa [%1] %2, %0"
: "=r" (data)
: "r" ((2 << 16) | (entry << 3)),
"i" (ASI_ITLB_DATA_ACCESS));
-/* $Id: system.h,v 1.64 2001/08/30 03:22:00 kanoj Exp $ */
+/* $Id: system.h,v 1.68 2001/11/18 00:12:56 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
#define flush_register_windows flushw_all
#define prepare_to_switch flushw_all
+#ifndef CONFIG_DEBUG_SPINLOCk
+#define CHECK_LOCKS(PREV) do { } while(0)
+#else /* CONFIG_DEBUG_SPINLOCk */
+#define CHECK_LOCKS(PREV) \
+if ((PREV)->thread.smp_lock_count) { \
+ unsigned long rpc; \
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (rpc)); \
+ printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n", \
+ (PREV)->comm, (PREV)->pid, \
+ (PREV)->thread.smp_lock_count); \
+ printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n", \
+ (PREV)->comm, (PREV)->pid, \
+ (PREV)->thread.smp_lock_pc); \
+ printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n", \
+ (PREV)->comm, (PREV)->pid, rpc); \
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCk) */
+
/* See what happens when you design the chip correctly?
*
* We tell gcc we clobber all non-fixed-usage registers except
* and 2 stores in this critical code path. -DaveM
*/
#define switch_to(prev, next, last) \
-do { if (current->thread.flags & SPARC_FLAG_PERFCTR) { \
+do { CHECK_LOCKS(prev); \
+ if (current->thread.flags & SPARC_FLAG_PERFCTR) { \
unsigned long __tmp; \
read_pcr(__tmp); \
current->thread.pcr_reg = __tmp; \
__cmpxchg_u32(volatile int *m, int old, int new)
{
__asm__ __volatile__("cas [%2], %3, %0\n\t"
- "membar #StoreStore | #StoreLoad"
+ "membar #StoreLoad | #StoreStore"
: "=&r" (new)
: "0" (new), "r" (m), "r" (old)
: "memory");
__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
{
__asm__ __volatile__("casx [%2], %3, %0\n\t"
- "membar #StoreStore | #StoreLoad"
+ "membar #StoreLoad | #StoreStore"
: "=&r" (new)
: "0" (new), "r" (m), "r" (old)
: "memory");
-/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */
+/* $Id: ttable.h,v 1.17 2001/11/28 23:32:16 davem Exp $ */
#ifndef _SPARC64_TTABLE_H
#define _SPARC64_TTABLE_H
clr %l6; \
nop;
+#define TRAP_7INSNS(routine) \
+ sethi %hi(109f), %g7; \
+ ba,pt %xcc, etrap; \
+109: or %g7, %lo(109b), %g7; \
+ call routine; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ ba,pt %xcc, rtrap; \
+ clr %l6;
+
#define TRAP_SAVEFPU(routine) \
sethi %hi(109f), %g7; \
ba,pt %xcc, do_fptrap; \
nop; \
nop; nop; nop; nop; nop; nop;
+#define TRAP_NOSAVE_7INSNS(routine) \
+ ba,pt %xcc, routine; \
+ nop; \
+ nop; nop; nop; nop; nop;
+
#define TRAPTL1(routine) \
sethi %hi(109f), %g7; \
ba,pt %xcc, etraptl1; \
#define MIN_READAHEAD 3
#define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
-#define blkdev_entry_next_request(entry) blkdev_entry_to_request((entry)->next)
-#define blkdev_entry_prev_request(entry) blkdev_entry_to_request((entry)->prev)
-#define blkdev_next_request(req) blkdev_entry_to_request((req)->queuelist.next)
-#define blkdev_prev_request(req) blkdev_entry_to_request((req)->queuelist.prev)
extern void drive_stat_acct(struct request *, int, int);
--- /dev/null
+/*
+ * crc32.h
+ * See linux/lib/crc32.c for license and changes
+ */
+#ifndef _LINUX_CRC32_H
+#define _LINUX_CRC32_H
+
+#include <linux/types.h>
+
+extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len);
+extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len);
+
+#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length)
+#define ether_crc_le(length, data) crc32_le(~0, data, length)
+#define ether_crc(length, data) crc32_be(~0, data, length)
+
+#endif /* _LINUX_CRC32_H */
unsigned short b_size; /* block size */
unsigned short b_list; /* List that this buffer appears */
kdev_t b_dev; /* device (B_FREE = free) */
+ struct block_device *b_bdev;
atomic_t b_count; /* users using this block */
unsigned long b_state; /* buffer state bitmap (see above) */
extern void remove_inode_hash(struct inode *);
extern struct file * get_empty_filp(void);
extern void file_move(struct file *f, struct list_head *list);
-extern struct buffer_head * get_hash_table(kdev_t, sector_t, int);
+extern struct buffer_head * __get_hash_table(struct block_device *, sector_t, int);
+static inline struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
+{
+ struct block_device *bdev;
+ struct buffer_head *bh;
+ bdev = bdget(kdev_t_to_nr(dev));
+ if (!bdev) {
+ printk("No block device for %s\n", bdevname(dev));
+ BUG();
+ }
+ bh = __get_hash_table(bdev, block, size);
+ atomic_dec(&bdev->bd_count);
+ return bh;
+}
extern struct buffer_head * __getblk(struct block_device *, sector_t, int);
static inline struct buffer_head * getblk(kdev_t dev, sector_t block, int size)
{
}
static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
{
- return get_hash_table(sb->s_dev, block, sb->s_blocksize);
+ return __get_hash_table(sb->s_bdev, block, sb->s_blocksize);
}
static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
{
bh->b_state |= 1 << BH_Mapped;
+ bh->b_bdev = sb->s_bdev;
bh->b_dev = sb->s_dev;
bh->b_blocknr = block;
}
extern void put_unused_buffer_head(struct buffer_head * bh);
extern struct buffer_head * get_unused_buffer_head(int async);
-extern int brw_page(int, struct page *, kdev_t, sector_t [], int);
+extern int brw_page(int, struct page *, struct block_device *, sector_t [], int);
typedef int (get_block_t)(struct inode*,sector_t,struct buffer_head*,int);
/* 787->799 reserved for fibrechannel media types */
#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */
#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
+#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
u32 link_failure_count;
} slave_t;
+/*
+ * Here are the locking policies for the two bonding locks:
+ *
+ * 1) Get bond->lock when reading/writing slave list.
+ * 2) Get bond->ptrlock when reading/writing bond->current_slave.
+ * (It is unnecessary when the write-lock is put with bond->lock.)
+ * 3) When we lock with bond->ptrlock, we must lock with bond->lock
+ * beforehand.
+ */
typedef struct bonding {
slave_t *next;
slave_t *prev;
#ifndef _KBD_KERN_H
#define _KBD_KERN_H
+#include <linux/tty.h>
#include <linux/interrupt.h>
#include <linux/keyboard.h>
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
#define NAME_MAX 255 /* # chars in a file name */
-#define PATH_MAX 4095 /* # chars in a path name */
+#define PATH_MAX 4096 /* # chars in a path name including nul */
#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
#define RTSIG_MAX 32
IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
};
+/* Bitset representing status of connection. */
+enum ip_conntrack_status {
+ /* It's an expected connection: bit 0 set. This bit never changed */
+ IPS_EXPECTED_BIT = 0,
+ IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
+
+ /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
+ IPS_SEEN_REPLY_BIT = 1,
+ IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
+
+ /* Conntrack should never be early-expired. */
+ IPS_ASSURED_BIT = 2,
+ IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+};
+
#ifdef __KERNEL__
#include <linux/types.h>
#define IP_NF_ASSERT(x)
#endif
-/* Bitset representing status of connection. */
-enum ip_conntrack_status {
- /* It's an expected connection: bit 0 set. This bit never changed */
- IPS_EXPECTED_BIT = 0,
- IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
-
- /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
- IPS_SEEN_REPLY_BIT = 1,
- IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
-
- /* Conntrack should never be early-expired. */
- IPS_ASSURED_BIT = 2,
- IPS_ASSURED = (1 << IPS_ASSURED_BIT),
-};
-
struct ip_conntrack_expect
{
/* Internal linked list */
} dst;
};
+enum ip_conntrack_dir
+{
+ IP_CT_DIR_ORIGINAL,
+ IP_CT_DIR_REPLY,
+ IP_CT_DIR_MAX
+};
+
#ifdef __KERNEL__
#define DUMP_TUPLE(tp) \
/* If we're the first tuple, it's the original dir. */
#define DIRECTION(h) ((enum ip_conntrack_dir)(&(h)->ctrack->tuplehash[1] == (h)))
-enum ip_conntrack_dir
+/* Connections have two entries in the hash table: one for each way */
+struct ip_conntrack_tuple_hash
{
- IP_CT_DIR_ORIGINAL,
- IP_CT_DIR_REPLY,
- IP_CT_DIR_MAX
+ struct list_head list;
+
+ struct ip_conntrack_tuple tuple;
+
+ /* this == &ctrack->tuplehash[DIRECTION(this)]. */
+ struct ip_conntrack *ctrack;
};
+#endif /* __KERNEL__ */
+
static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
const struct ip_conntrack_tuple *t2)
{
& mask->dst.protonum));
}
-/* Connections have two entries in the hash table: one for each way */
-struct ip_conntrack_tuple_hash
-{
- struct list_head list;
-
- struct ip_conntrack_tuple tuple;
-
- /* this == &ctrack->tuplehash[DIRECTION(this)]. */
- struct ip_conntrack *ctrack;
-};
-
-#endif /* __KERNEL__ */
#endif /* _IP_CONNTRACK_TUPLE_H */
#define _jhashfn(dev,block) \
((((dev)<<(JBH_HASH_SHIFT - 6)) ^ ((dev)<<(JBH_HASH_SHIFT - 9))) ^ \
(((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
-#define journal_hash(t,dev,block) ((t)[_jhashfn((kdev_t_to_nr(dev)),(block)) & JBH_HASH_MASK])
+#define journal_hash(t,sb,block) ((t)[_jhashfn((kdev_t_to_nr(sb->s_dev)),(block)) & JBH_HASH_MASK])
/* finds n'th buffer with 0 being the start of this commit. Needs to go away, j_ap_blocks has changed
** since I created this. One chunk of code in journal.c needs changing before deleting it
int journal_lock_dobalance(struct super_block *p_s_sb) ;
int journal_unlock_dobalance(struct super_block *p_s_sb) ;
int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
+int reiserfs_in_journal(struct super_block *p_s_sb, unsigned long bl, int searchall, unsigned long *next) ;
int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
int journal_join(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
struct super_block *reiserfs_get_super(kdev_t dev) ;
void flush_async_commits(struct super_block *p_s_sb) ;
int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) ;
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) ;
int buffer_journaled(const struct buffer_head *bh) ;
int mark_buffer_journal_new(struct buffer_head *bh) ;
*/
struct reiserfs_journal_cnode {
struct buffer_head *bh ; /* real buffer head */
- kdev_t dev ; /* dev of real buffer head */
+ struct super_block *sb ; /* dev of real buffer head */
unsigned long blocknr ; /* block number of real buffer head, == 0 when buffer on disk */
int state ;
struct reiserfs_journal_list *jlist ; /* journal list this cnode lives in */
prio_array_t *array;
unsigned int time_slice;
- unsigned long swap_cnt_last;
+ unsigned long sleep_jtime;
unsigned long policy;
unsigned long cpus_allowed;
* swapper address space.
*
* We have to move it here, since not every user of fs.h is including
- * mm.h, but m.h is including fs.h via sched .h :-/
+ * mm.h, but mm.h is including fs.h via sched .h :-/
*/
typedef struct {
unsigned long val;
#define AF_IRDA 23 /* IRDA sockets */
#define AF_PPPOX 24 /* PPPoX sockets */
#define AF_WANPIPE 25 /* Wanpipe API Sockets */
+#define AF_LLC 26 /* Linux LLC */
#define AF_BLUETOOTH 31 /* Bluetooth sockets */
#define AF_MAX 32 /* For now.. */
#define PF_IRDA AF_IRDA
#define PF_PPPOX AF_PPPOX
#define PF_WANPIPE AF_WANPIPE
+#define PF_LLC AF_LLC
#define PF_BLUETOOTH AF_BLUETOOTH
#define PF_MAX AF_MAX
#define SOL_ATM 264 /* ATM layer (cell level) */
#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */
#define SOL_IRDA 266
+#define SOL_NETBEUI 267
+#define SOL_LLC 268
/* IPX options */
#define IPX_TYPE 1
xprt_set_timeout(&clnt->cl_timeout, retr, incr);
}
-extern void rpciod_tcp_dispatcher(void);
extern void rpciod_wake_up(void);
/*
unsigned int flags;
kdev_t swap_device;
spinlock_t sdev_lock;
- struct dentry * swap_file;
- struct vfsmount *swap_vfsmnt;
+ struct file *swap_file;
unsigned short * swap_map;
unsigned int lowest_bit;
unsigned int highest_bit;
extern int is_swap_partition(kdev_t);
extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(void);
-extern void get_swaphandle_info(swp_entry_t, unsigned long *, kdev_t *,
- struct inode **);
+extern void get_swaphandle_info(swp_entry_t, unsigned long *, struct inode **);
extern int swap_duplicate(swp_entry_t);
extern int swap_count(struct page *);
extern int valid_swaphandles(swp_entry_t, unsigned long *);
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_DOUBLE_H__
+#define __MATH_EMU_DOUBLE_H__
+
#if _FP_W_TYPE_SIZE < 32
#error "Here's a nickel kid. Go buy yourself a real computer."
#endif
#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_1(X)
#endif /* W_TYPE_SIZE < 64 */
+
+
+#endif /* __MATH_EMU_DOUBLE_H__ */
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef __MATH_EMU_EXTENDED_H__
+#define __MATH_EMU_EXTENDED_H__
+
#if _FP_W_TYPE_SIZE < 32
#error "Here's a nickel, kid. Go buy yourself a real computer."
#endif
#define _FP_FRAC_HIGH_RAW_E(X) (X##_f0)
#endif /* not _FP_W_TYPE_SIZE < 64 */
+
+#endif /* __MATH_EMU_EXTENDED_H__ */
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_OP_1_H__
+#define __MATH_EMU_OP_1_H__
+
#define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f
#define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f)
#define _FP_FRAC_SET_1(X,I) (X##_f = I)
else \
D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \
} while (0)
+
+#endif /* __MATH_EMU_OP_1_H__ */
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_OP_2_H__
+#define __MATH_EMU_OP_2_H__
+
#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1
#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1)
#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I)
_FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
} while (0)
+#endif
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_OP_4_H__
+#define __MATH_EMU_OP_4_H__
+
#define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4]
#define _FP_FRAC_COPY_4(D,S) \
(D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \
_FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
} while (0)
+#endif
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_OP_8_H__
+#define __MATH_EMU_OP_8_H__
+
/* We need just a few things from here for op-4, if we ever need some
other macros, they can be added. */
#define _FP_FRAC_DECL_8(X) _FP_W_TYPE X##_f[8]
X##_f[0] |= (_s != 0); \
} while (0)
+#endif
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_OP_COMMON_H__
+#define __MATH_EMU_OP_COMMON_H__
+
#define _FP_DECL(wc, X) \
_FP_I_TYPE X##_c, X##_s, X##_e; \
_FP_FRAC_DECL_##wc(X)
q = n / d, r = n % d; \
} while (0)
+#endif /* __MATH_EMU_OP_COMMON_H__ */
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_QUAD_H__
+#define __MATH_EMU_QUAD_H__
+
#if _FP_W_TYPE_SIZE < 32
#error "Here's a nickel, kid. Go buy yourself a real computer."
#endif
#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_2(X)
#endif /* not _FP_W_TYPE_SIZE < 64 */
+
+#endif /* __MATH_EMU_QUAD_H__ */
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#ifndef __MATH_EMU_SINGLE_H__
+#define __MATH_EMU_SINGLE_H__
+
#if _FP_W_TYPE_SIZE < 32
#error "Here's a nickel kid. Go buy yourself a real computer."
#endif
#define _FP_FRAC_HIGH_S(X) _FP_FRAC_HIGH_1(X)
#define _FP_FRAC_HIGH_RAW_S(X) _FP_FRAC_HIGH_1(X)
+
+#endif /* __MATH_EMU_SINGLE_H__ */
not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#ifndef SOFT_FP_H
-#define SOFT_FP_H
+#ifndef __MATH_EMU_SOFT_FP_H__
+#define __MATH_EMU_SOFT_FP_H__
#include <asm/sfp-machine.h>
#include <stdlib/longlong.h>
#endif
-#endif
+#endif /* __MATH_EMU_SOFT_FP_H__ */
EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode);
EXPORT_SYMBOL(read_ahead);
-EXPORT_SYMBOL(get_hash_table);
+EXPORT_SYMBOL(__get_hash_table);
EXPORT_SYMBOL(get_empty_inode);
EXPORT_SYMBOL(insert_inode_hash);
EXPORT_SYMBOL(remove_inode_hash);
#include <asm/mmu_context.h>
#define BITMAP_SIZE ((MAX_PRIO+7)/8)
+#define PRIO_INTERACTIVE (MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 4)
+#define TASK_INTERACTIVE(p) ((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
+#define JSLEEP_TO_PRIO(t) (((t) * 20) / HZ)
typedef struct runqueue runqueue_t;
spinlock_t lock;
unsigned long nr_running, nr_switches;
task_t *curr, *idle;
- unsigned long swap_cnt;
prio_array_t *active, *expired, arrays[2];
char __pad [SMP_CACHE_BYTES];
} runqueues [NR_CPUS] __cacheline_aligned;
prio_array_t *array = rq->active;
if (!rt_task(p)) {
- unsigned long prio_bonus = rq->swap_cnt - p->swap_cnt_last;
+ unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
if (prio_bonus > MAX_PRIO)
prio_bonus = MAX_PRIO;
rq->nr_running--;
dequeue_task(p, p->array);
p->array = NULL;
- p->swap_cnt_last = rq->swap_cnt;
+ p->sleep_jtime = jiffies;
}
static inline void resched_task(task_t *p)
p->prio = MAX_PRIO - 1;
}
p->time_slice = time_slice;
- enqueue_task(p, rq->expired);
+ if (TASK_INTERACTIVE(p))
+ enqueue_task(p, rq->active);
+ else
+ enqueue_task(p, rq->expired);
}
spin_unlock_irqrestore(&rq->lock, flags);
}
spin_lock_irq(&rq->lock);
switch (prev->state) {
- case TASK_INTERRUPTIBLE:
- if (unlikely(signal_pending(prev))) {
- prev->state = TASK_RUNNING;
- break;
- }
- default:
- deactivate_task(prev, rq);
- case TASK_RUNNING:
+ case TASK_INTERRUPTIBLE:
+ if (unlikely(signal_pending(prev))) {
+ prev->state = TASK_RUNNING;
+ break;
+ }
+ default:
+ deactivate_task(prev, rq);
+ case TASK_RUNNING:
}
pick_next_task:
if (unlikely(!rq->nr_running)) {
rq->active = rq->expired;
rq->expired = array;
array = rq->active;
- rq->swap_cnt++;
}
idx = sched_find_first_zero_bit(array->bitmap);
rq->expired = rq->arrays + 1;
spin_lock_init(&rq->lock);
rq->cpu = i;
- rq->swap_cnt = 0;
for (j = 0; j < 2; j++) {
array = rq->arrays + j;
--- /dev/null
+#
+# Library configuration
+#
+mainmenu_option next_comment
+comment 'Library routines'
+
+tristate 'CRC32 functions' CONFIG_CRC32
+endmenu
L_TARGET := lib.a
-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o
obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
obj-y += dec_and_lock.o
endif
+obj-$(CONFIG_CRC32) += crc32.o
+include $(TOPDIR)/drivers/net/Makefile.lib
+include $(TOPDIR)/drivers/usb/Makefile.lib
+include $(TOPDIR)/fs/Makefile.lib
+
include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks!
+ *
+ * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Same crc32 function was used in 5 other places in the kernel.
+ * I made one version, and deleted the others.
+ * There are various incantations of crc32(). Some use a seed of 0 or ~0.
+ * Some xor at the end with ~0. The generic crc32() function takes
+ * seed as an argument, and doesn't xor at the end. Then individual
+ * users can do whatever they need.
+ * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
+ * fs/jffs2 uses seed 0, doesn't xor with ~0.
+ * fs/partitions/efi.c uses seed ~0, xor's with ~0.
+ *
+ */
+
+#include <linux/crc32.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+
+#if __GNUC__ >= 3 /* 2.x has "attribute", but only 3.0 has "pure */
+#define attribute(x) __attribute__(x)
+#else
+#define attribute(x)
+#endif
+
+/*
+ * This code is in the public domain; copyright abandoned.
+ * Liability for non-performance of this code is limited to the amount
+ * you paid for it. Since it is distributed for free, your refund will
+ * be very very small. If it breaks, you get to keep both pieces.
+ */
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
+MODULE_DESCRIPTION("Ethernet CRC32 calculations");
+MODULE_LICENSE("GPL and additional rights");
+
+
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/* How many bits at a time to use. Requires a table of 4<<CRC_xx_BITS bytes. */
+/* For less performance-sensitive, use 4 */
+#define CRC_LE_BITS 8
+#define CRC_BE_BITS 8
+
+/*
+ * Little-endian CRC computation. Used with serial bit streams sent
+ * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC.
+ */
+#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
+# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#if CRC_LE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+#define crc32init_le()
+#define crc32cleanup_le()
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ }
+ return crc;
+}
+#else /* Table-based approach */
+
+static u32 *crc32table_le;
+/**
+ * crc32init_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+static int __init crc32init_le(void)
+{
+ unsigned i, j;
+ u32 crc = 1;
+
+ crc32table_le =
+ kmalloc((1 << CRC_LE_BITS) * sizeof(u32), GFP_KERNEL);
+ if (!crc32table_le)
+ return 1;
+ crc32table_le[0] = 0;
+
+ for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i)
+ crc32table_le[i + j] = crc ^ crc32table_le[j];
+ }
+ return 0;
+}
+
+/**
+ * crc32cleanup_le(): free LE table data
+ */
+static void __exit crc32cleanup_le(void)
+{
+ if (crc32table_le) kfree(crc32table_le);
+ crc32table_le = NULL;
+}
+
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+ while (len--) {
+# if CRC_LE_BITS == 8
+ crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255];
+# elif CRC_LE_BITS == 4
+ crc ^= *p++;
+ crc = (crc >> 4) ^ crc32table_le[crc & 15];
+ crc = (crc >> 4) ^ crc32table_le[crc & 15];
+# elif CRC_LE_BITS == 2
+ crc ^= *p++;
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+# endif
+ }
+ return crc;
+}
+#endif
+
+/*
+ * Big-endian CRC computation. Used with serial bit streams sent
+ * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC.
+ */
+#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
+# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#if CRC_BE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+#define crc32init_be()
+#define crc32cleanup_be()
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++ << 24;
+ for (i = 0; i < 8; i++)
+ crc =
+ (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+ 0);
+ }
+ return crc;
+}
+
+#else /* Table-based approach */
+static u32 *crc32table_be;
+
+/**
+ * crc32init_be() - allocate and initialize BE table data
+ */
+static int __init crc32init_be(void)
+{
+ unsigned i, j;
+ u32 crc = 0x80000000;
+
+ crc32table_be =
+ kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
+ if (!crc32table_be)
+ return 1;
+ crc32table_be[0] = 0;
+
+ for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
+ crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+ for (j = 0; j < i; j++)
+ crc32table_be[i + j] = crc ^ crc32table_be[j];
+ }
+ return 0;
+}
+
+/**
+ * crc32cleanup_be(): free BE table data
+ */
+static void __exit crc32cleanup_be(void)
+{
+ if (crc32table_be) kfree(crc32table_be);
+ crc32table_be = NULL;
+}
+
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ *
+ */
+u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+ while (len--) {
+# if CRC_BE_BITS == 8
+ crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++];
+# elif CRC_BE_BITS == 4
+ crc ^= *p++ << 24;
+ crc = (crc << 4) ^ crc32table_be[crc >> 28];
+ crc = (crc << 4) ^ crc32table_be[crc >> 28];
+# elif CRC_BE_BITS == 2
+ crc ^= *p++ << 24;
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+# endif
+ }
+ return crc;
+}
+#endif
+
+/*
+ * A brief CRC tutorial.
+ *
+ * A CRC is a long-division remainder. You add the CRC to the message,
+ * and the whole thing (message+CRC) is a multiple of the given
+ * CRC polynomial. To check the CRC, you can either check that the
+ * CRC matches the recomputed value, *or* you can check that the
+ * remainder computed on the message+CRC is 0. This latter approach
+ * is used by a lot of hardware implementations, and is why so many
+ * protocols put the end-of-frame flag after the CRC.
+ *
+ * It's actually the same long division you learned in school, except that
+ * - We're working in binary, so the digits are only 0 and 1, and
+ * - When dividing polynomials, there are no carries. Rather than add and
+ * subtract, we just xor. Thus, we tend to get a bit sloppy about
+ * the difference between adding and subtracting.
+ *
+ * A 32-bit CRC polynomial is actually 33 bits long. But since it's
+ * 33 bits long, bit 32 is always going to be set, so usually the CRC
+ * is written in hex with the most significant bit omitted. (If you're
+ * familiar with the IEEE 754 floating-point format, it's the same idea.)
+ *
+ * Note that a CRC is computed over a string of *bits*, so you have
+ * to decide on the endianness of the bits within each byte. To get
+ * the best error-detecting properties, this should correspond to the
+ * order they're actually sent. For example, standard RS-232 serial is
+ * little-endian; the most significant bit (sometimes used for parity)
+ * is sent last. And when appending a CRC word to a message, you should
+ * do it in the right order, matching the endianness.
+ *
+ * Just like with ordinary division, the remainder is always smaller than
+ * the divisor (the CRC polynomial) you're dividing by. Each step of the
+ * division, you take one more digit (bit) of the dividend and append it
+ * to the current remainder. Then you figure out the appropriate multiple
+ * of the divisor to subtract to being the remainder back into range.
+ * In binary, it's easy - it has to be either 0 or 1, and to make the
+ * XOR cancel, it's just a copy of bit 32 of the remainder.
+ *
+ * When computing a CRC, we don't care about the quotient, so we can
+ * throw the quotient bit away, but subtract the appropriate multiple of
+ * the polynomial from the remainder and we're back to where we started,
+ * ready to process the next bit.
+ *
+ * A big-endian CRC written this way would be coded like:
+ * for (i = 0; i < input_bits; i++) {
+ * multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+ * remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+ * }
+ * Notice how, to get at bit 32 of the shifted remainder, we look
+ * at bit 31 of the remainder *before* shifting it.
+ *
+ * But also notice how the next_input_bit() bits we're shifting into
+ * the remainder don't actually affect any decision-making until
+ * 32 bits later. Thus, the first 32 cycles of this are pretty boring.
+ * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+ * the end, so we have to add 32 extra cycles shifting in zeros at the
+ * end of every message,
+ *
+ * So the standard trick is to rearrage merging in the next_input_bit()
+ * until the moment it's needed. Then the first 32 cycles can be precomputed,
+ * and merging in the final 32 zero bits to make room for the CRC can be
+ * skipped entirely.
+ * This changes the code to:
+ * for (i = 0; i < input_bits; i++) {
+ * remainder ^= next_input_bit() << 31;
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * With this optimization, the little-endian code is simpler:
+ * for (i = 0; i < input_bits; i++) {
+ * remainder ^= next_input_bit();
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder >> 1) ^ multiple;
+ * }
+ *
+ * Note that the other details of endianness have been hidden in CRCPOLY
+ * (which must be bit-reversed) and next_input_bit().
+ *
+ * However, as long as next_input_bit is returning the bits in a sensible
+ * order, we can actually do the merging 8 or more bits at a time rather
+ * than one bit at a time:
+ * for (i = 0; i < input_bytes; i++) {
+ * remainder ^= next_input_byte() << 24;
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * }
+ * Or in little-endian:
+ * for (i = 0; i < input_bytes; i++) {
+ * remainder ^= next_input_byte();
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * }
+ * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+ * word at a time and increase the inner loop count to 32.
+ *
+ * You can also mix and match the two loop styles, for example doing the
+ * bulk of a message byte-at-a-time and adding bit-at-a-time processing
+ * for any fractional bytes at the end.
+ *
+ * The only remaining optimization is to the byte-at-a-time table method.
+ * Here, rather than just shifting one bit of the remainder to decide
+ * in the correct multiple to subtract, we can shift a byte at a time.
+ * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+ * but again the multiple of the polynomial to subtract depends only on
+ * the high bits, the high 8 bits in this case.
+ *
+ * The multile we need in that case is the low 32 bits of a 40-bit
+ * value whose high 8 bits are given, and which is a multiple of the
+ * generator polynomial. This is simply the CRC-32 of the given
+ * one-byte message.
+ *
+ * Two more details: normally, appending zero bits to a message which
+ * is already a multiple of a polynomial produces a larger multiple of that
+ * polynomial. To enable a CRC to detect this condition, it's common to
+ * invert the CRC before appending it. This makes the remainder of the
+ * message+crc come out not as zero, but some fixed non-zero value.
+ *
+ * The same problem applies to zero bits prepended to the message, and
+ * a similar solution is used. Instead of starting with a remainder of
+ * 0, an initial remainder of all ones is used. As long as you start
+ * the same way on decoding, it doesn't make a difference.
+ */
+
+#if UNITTEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#if 0 /*Not used at present */
+static void
+buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+{
+ fputs(prefix, stdout);
+ while (len--)
+ printf(" %02x", *buf++);
+ putchar('\n');
+
+}
+#endif
+
+static u32 attribute((const)) bitreverse(u32 x)
+{
+ x = (x >> 16) | (x << 16);
+ x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
+ x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
+ x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
+ x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
+ return x;
+}
+
+static void bytereverse(unsigned char *buf, size_t len)
+{
+ while (len--) {
+ unsigned char x = *buf;
+ x = (x >> 4) | (x << 4);
+ x = (x >> 2 & 0x33) | (x << 2 & 0xcc);
+ x = (x >> 1 & 0x55) | (x << 1 & 0xaa);
+ *buf++ = x;
+ }
+}
+
+static void random_garbage(unsigned char *buf, size_t len)
+{
+ while (len--)
+ *buf++ = (unsigned char) random();
+}
+
+#if 0 /* Not used at present */
+static void store_le(u32 x, unsigned char *buf)
+{
+ buf[0] = (unsigned char) x;
+ buf[1] = (unsigned char) (x >> 8);
+ buf[2] = (unsigned char) (x >> 16);
+ buf[3] = (unsigned char) (x >> 24);
+}
+#endif
+
+static void store_be(u32 x, unsigned char *buf)
+{
+ buf[0] = (unsigned char) (x >> 24);
+ buf[1] = (unsigned char) (x >> 16);
+ buf[2] = (unsigned char) (x >> 8);
+ buf[3] = (unsigned char) x;
+}
+
+/*
+ * This checks that CRC(buf + CRC(buf)) = 0, and that
+ * CRC commutes with bit-reversal. This has the side effect
+ * of bytewise bit-reversing the input buffer, and returns
+ * the CRC of the reversed buffer.
+ */
+static u32 test_step(u32 init, unsigned char *buf, size_t len)
+{
+ u32 crc1, crc2;
+ size_t i;
+
+ crc1 = crc32_be(init, buf, len);
+ store_be(crc1, buf + len);
+ crc2 = crc32_be(init, buf, len + 4);
+ if (crc2)
+ printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+ crc2);
+
+ for (i = 0; i <= len + 4; i++) {
+ crc2 = crc32_be(init, buf, i);
+ crc2 = crc32_be(crc2, buf + i, len + 4 - i);
+ if (crc2)
+ printf("\nCRC split fail: 0x%08x\n", crc2);
+ }
+
+ /* Now swap it around for the other test */
+
+ bytereverse(buf, len + 4);
+ init = bitreverse(init);
+ crc2 = bitreverse(crc1);
+ if (crc1 != bitreverse(crc2))
+ printf("\nBit reversal fail: 0x%08x -> %0x08x -> 0x%08x\n",
+ crc1, crc2, bitreverse(crc2));
+ crc1 = crc32_le(init, buf, len);
+ if (crc1 != crc2)
+ printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
+ crc2);
+ crc2 = crc32_le(init, buf, len + 4);
+ if (crc2)
+ printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+ crc2);
+
+ for (i = 0; i <= len + 4; i++) {
+ crc2 = crc32_le(init, buf, i);
+ crc2 = crc32_le(crc2, buf + i, len + 4 - i);
+ if (crc2)
+ printf("\nCRC split fail: 0x%08x\n", crc2);
+ }
+
+ return crc1;
+}
+
+#define SIZE 64
+#define INIT1 0
+#define INIT2 0
+
+int main(void)
+{
+ unsigned char buf1[SIZE + 4];
+ unsigned char buf2[SIZE + 4];
+ unsigned char buf3[SIZE + 4];
+ int i, j;
+ u32 crc1, crc2, crc3;
+
+ crc32init_le();
+ crc32init_be();
+
+ for (i = 0; i <= SIZE; i++) {
+ printf("\rTesting length %d...", i);
+ fflush(stdout);
+ random_garbage(buf1, i);
+ random_garbage(buf2, i);
+ for (j = 0; j < i; j++)
+ buf3[j] = buf1[j] ^ buf2[j];
+
+ crc1 = test_step(INIT1, buf1, i);
+ crc2 = test_step(INIT2, buf2, i);
+ /* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
+ crc3 = test_step(INIT1 ^ INIT2, buf3, i);
+ if (crc3 != (crc1 ^ crc2))
+ printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
+ crc3, crc1, crc2);
+ }
+ printf("\nAll test complete. No failures expected.\n");
+ return 0;
+}
+
+#endif /* UNITTEST */
+
+/**
+ * init_crc32(): generates CRC32 tables
+ *
+ * On successful initialization, use count is increased.
+ * This guarantees that the library functions will stay resident
+ * in memory, and prevents someone from 'rmmod crc32' while
+ * a driver that needs it is still loaded.
+ * This also greatly simplifies drivers, as there's no need
+ * to call an initialization/cleanup function from each driver.
+ * Since crc32.o is a library module, there's no requirement
+ * that the user can unload it.
+ */
+static int __init init_crc32(void)
+{
+ int rc1, rc2, rc;
+ rc1 = crc32init_le();
+ rc2 = crc32init_be();
+ rc = rc1 || rc2;
+ if (!rc) MOD_INC_USE_COUNT;
+ return rc;
+}
+
+/**
+ * cleanup_crc32(): frees crc32 data when no longer needed
+ */
+static void cleanup_crc32(void)
+{
+ crc32cleanup_le();
+ crc32cleanup_be();
+}
+
+module_init(init_crc32);
+module_exit(cleanup_crc32);
+
+EXPORT_SYMBOL(crc32_le);
+EXPORT_SYMBOL(crc32_be);
if (align & (align-1))
BUG();
+ offset = 0;
+ if (align &&
+ (bdata->node_boot_start & (align - 1UL)) != 0)
+ offset = (align - (bdata->node_boot_start & (align - 1UL)));
+ offset >>= PAGE_SHIFT;
+
/*
* We try to allocate bootmem pages above 'goal'
* first, then we try to allocate lower pages.
preferred = 0;
preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
+ preferred += offset;
areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
incr = align >> PAGE_SHIFT ? : 1;
fail_block:;
}
if (preferred) {
- preferred = 0;
+ preferred = offset;
goto restart_scan;
}
return NULL;
static void *page_pool_alloc(int gfp_mask, void *data)
{
- int gfp = gfp_mask | (int) data;
+ int gfp = gfp_mask | (int) (long) data;
return alloc_page(gfp);
}
unsigned long offset;
sector_t zones[PAGE_SIZE/512];
int zones_used;
- kdev_t dev = NODEV;
int block_size;
struct inode *swapf = 0;
+ struct block_device *bdev;
if (rw == READ) {
ClearPageUptodate(page);
} else
kstat.pswpout++;
- get_swaphandle_info(entry, &offset, &dev, &swapf);
- if (!kdev_none(dev)) {
+ get_swaphandle_info(entry, &offset, &swapf);
+ bdev = swapf->i_bdev;
+ if (bdev) {
zones[0] = offset;
zones_used = 1;
block_size = PAGE_SIZE;
- } else if (swapf) {
+ } else {
int i, j;
unsigned int block = offset
<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
return 0;
}
zones_used = i;
- dev = swapf->i_dev;
- } else {
- return 0;
+ bdev = swapf->i_sb->s_bdev;
}
/* block_size == PAGE_SIZE/zones_used */
- brw_page(rw, page, dev, zones, block_size);
+ brw_page(rw, page, bdev, zones, block_size);
/* Note! For consistency we do all of the logic,
* decrementing the page count, and unlocking the page in the
#include <linux/kernel_stat.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
-#include <linux/blkdev.h> /* for blk_size */
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/shm.h>
{
struct swap_info_struct * p = NULL;
unsigned short *swap_map;
+ struct file *swap_file;
struct nameidata nd;
int i, type, prev;
int err;
for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
p = swap_info + type;
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- if (p->swap_file == nd.dentry)
- break;
+ if (p->swap_file->f_dentry == nd.dentry)
+ break;
}
prev = type;
}
swap_list_unlock();
goto out_dput;
}
- if (!kdev_none(p->swap_device))
- blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
- path_release(&nd);
-
swap_list_lock();
swap_device_lock(p);
- nd.mnt = p->swap_vfsmnt;
- nd.dentry = p->swap_file;
- p->swap_vfsmnt = NULL;
+ swap_file = p->swap_file;
p->swap_file = NULL;
p->swap_device = NODEV;
p->max = 0;
swap_device_unlock(p);
swap_list_unlock();
vfree(swap_map);
+ filp_close(swap_file, NULL);
err = 0;
out_dput:
len = sprintf(buf, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
if ((ptr->flags & SWP_USED) && ptr->swap_map) {
- char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
+ char * path = d_path(ptr->swap_file->f_dentry,
+ ptr->swap_file->f_vfsmnt,
page, PAGE_SIZE);
int j, usedswap = 0;
for (j = 0; j < ptr->max; ++j)
}
len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
path,
- kdev_none(ptr->swap_device) ? "file\t" : "partition",
+ !kdev_none(ptr->swap_device) ? "partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10),
usedswap << (PAGE_SHIFT - 10),
ptr->prio);
asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
{
struct swap_info_struct * p;
- struct nameidata nd;
- struct inode * swap_inode;
+ char *name;
+ struct file *swap_file = NULL;
+ struct address_space *mapping;
unsigned int type;
int i, j, prev;
int error;
int nr_good_pages = 0;
unsigned long maxpages = 1;
int swapfilesize;
- struct block_device *bdev = NULL;
unsigned short *swap_map;
if (!capable(CAP_SYS_ADMIN))
nr_swapfiles = type+1;
p->flags = SWP_USED;
p->swap_file = NULL;
- p->swap_vfsmnt = NULL;
p->swap_device = NODEV;
p->swap_map = NULL;
p->lowest_bit = 0;
p->prio = --least_priority;
}
swap_list_unlock();
- error = user_path_walk(specialfile, &nd);
+ name = getname(specialfile);
+ error = PTR_ERR(name);
+ if (IS_ERR(name))
+ goto bad_swap_2;
+ swap_file = filp_open(name, O_RDWR, 0);
+ putname(name);
+ error = PTR_ERR(swap_file);
if (error)
goto bad_swap_2;
- p->swap_file = nd.dentry;
- p->swap_vfsmnt = nd.mnt;
- swap_inode = nd.dentry->d_inode;
- error = -EINVAL;
-
- if (S_ISBLK(swap_inode->i_mode)) {
- kdev_t dev = swap_inode->i_rdev;
- struct block_device_operations *bdops;
- devfs_handle_t de;
+ p->swap_file = swap_file;
- p->swap_device = dev;
- set_blocksize(dev, PAGE_SIZE);
-
- bd_acquire(swap_inode);
- bdev = swap_inode->i_bdev;
- de = devfs_get_handle_from_inode(swap_inode);
- bdops = devfs_get_ops(de); /* Increments module use count */
- if (bdops) bdev->bd_op = bdops;
-
- error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
- devfs_put_ops(de);/*Decrement module use count now we're safe*/
- if (error)
- goto bad_swap_2;
- set_blocksize(dev, PAGE_SIZE);
- error = -ENODEV;
- if (kdev_none(dev) || (blk_size[major(dev)] &&
- !blk_size[major(dev)][minor(dev)]))
- goto bad_swap;
- swapfilesize = 0;
- if (blk_size[major(dev)])
- swapfilesize = blk_size[major(dev)][minor(dev)]
- >> (PAGE_SHIFT - 10);
- } else if (S_ISREG(swap_inode->i_mode))
- swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
- else
+ if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
+ p->swap_device = swap_file->f_dentry->d_inode->i_rdev;
+ set_blocksize(p->swap_device, PAGE_SIZE);
+ } else if (!S_ISREG(swap_file->f_dentry->d_inode->i_mode))
goto bad_swap;
+ mapping = swap_file->f_dentry->d_inode->i_mapping;
+ swapfilesize = mapping->host->i_size >> PAGE_SHIFT;
+
error = -EBUSY;
for (i = 0 ; i < nr_swapfiles ; i++) {
struct swap_info_struct *q = &swap_info[i];
if (i == type || !q->swap_file)
continue;
- if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping)
+ if (mapping == q->swap_file->f_dentry->d_inode->i_mapping)
goto bad_swap;
}
error = 0;
goto out;
bad_swap:
- if (bdev)
- blkdev_put(bdev, BDEV_SWAP);
bad_swap_2:
swap_list_lock();
swap_map = p->swap_map;
- nd.mnt = p->swap_vfsmnt;
- nd.dentry = p->swap_file;
p->swap_device = NODEV;
p->swap_file = NULL;
- p->swap_vfsmnt = NULL;
p->swap_map = NULL;
p->flags = 0;
if (!(swap_flags & SWAP_FLAG_PREFER))
swap_list_unlock();
if (swap_map)
vfree(swap_map);
- path_release(&nd);
+ if (swap_file)
+ filp_close(swap_file, NULL);
out:
if (swap_header)
free_page((long) swap_header);
* Prior swap_duplicate protects against swap device deletion.
*/
void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
- kdev_t *dev, struct inode **swapf)
+ struct inode **swapf)
{
unsigned long type;
struct swap_info_struct *p;
return;
}
- if (!kdev_none(p->swap_device)) {
- *dev = p->swap_device;
- } else if (p->swap_file) {
- *swapf = p->swap_file->d_inode;
- } else {
- printk(KERN_ERR "rw_swap_page: no swap file or device\n");
- }
- return;
+ *swapf = p->swap_file->f_dentry->d_inode;
}
/*
/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
+ * INET 802.1Q VLAN
* Ethernet-type device handling.
*
- * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com>
+ * Authors: Ben Greear <greearb@candelatech.com>
+ * Please send support related email to: vlan@scry.wanfear.com
+ * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
*
* Fixes:
* Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
static char vlan_fullname[] = "802.1Q VLAN Support";
static unsigned int vlan_version = 1;
-static unsigned int vlan_release = 5;
+static unsigned int vlan_release = 6;
static char vlan_copyright[] = " Ben Greear <greearb@candelatech.com>";
static int vlan_device_event(struct notifier_block *, unsigned long, void *);
return 0;
}
+/*
+ * Cleanup of groups before exit
+ */
+
+static void vlan_group_cleanup(void)
+{
+ struct vlan_group *grp = NULL;
+ struct vlan_group *nextgroup;
+
+ for (grp = p802_1Q_vlan_list; (grp != NULL);) {
+ nextgroup = grp->next;
+ kfree(grp);
+ grp = nextgroup;
+ }
+ p802_1Q_vlan_list = NULL;
+}
+
/*
* Module 'remove' entry point.
* o delete /proc/net/router directory and static entries.
dev_remove_pack(&vlan_packet_type);
vlan_proc_cleanup();
-
+ vlan_group_cleanup();
vlan_ioctl_hook = NULL;
}
/* set up method calls */
new_dev->init = vlan_dev_init;
new_dev->destructor = vlan_dev_destruct;
+ new_dev->features |= NETIF_F_DYNALLOC ;
/* new_dev->ifindex = 0; it will be set when added to
* the global list.
/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
+ * INET 802.1Q VLAN
* Ethernet-type device handling.
*
- * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com>
+ * Authors: Ben Greear <greearb@candelatech.com>
+ * Please send support related email to: vlan@scry.wanfear.com
+ * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
*
* Fixes: Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com>
* - reset skb->pkt_type on incoming packets when MAC was changed
VLAN_FMEM_DBG("dev->priv free, addr: %p\n", dev->priv);
dev->priv = NULL;
}
-
- kfree(dev);
- VLAN_FMEM_DBG("net_device free, addr: %p\n", dev);
- dev = NULL;
}
}
* Clean up /proc/net/vlan entries
*/
-void __exit vlan_proc_cleanup(void)
+void vlan_proc_cleanup(void)
{
if (proc_vlan_conf)
remove_proc_entry(name_conf, proc_vlan_dir);
return 0;
}
-void __exit vlan_proc_cleanup(void)
+void vlan_proc_cleanup(void)
{
return;
}
if [ "$CONFIG_DECNET" != "n" ]; then
source net/decnet/Config.in
fi
-tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
+dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
unix alan@lxorguk.ukuu.org.uk
x25 g4klx@g4klx.demon.co.uk
bluetooth maxk@qualcomm.com
-
+8021q greearb@candelatech.com, vlan@scry.wanfear.com
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br.c,v 1.46 2001/10/02 02:22:36 davem Exp $
+ * $Id: br.c,v 1.47 2001/12/24 00:56:41 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
br_handle_frame_hook = br_handle_frame;
-#ifdef CONFIG_INET
br_ioctl_hook = br_ioctl_deviceless_stub;
-#endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
br_fdb_get_hook = br_fdb_get;
br_fdb_put_hook = br_fdb_put;
static void __br_clear_ioctl_hook(void)
{
-#ifdef CONFIG_INET
br_ioctl_hook = NULL;
-#endif
}
static void __exit br_deinit(void)
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_device.c,v 1.5 2001/08/14 22:05:57 davem Exp $
+ * $Id: br_device.c,v 1.6 2001/12/24 00:59:55 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
return 0;
}
-static int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_bridge *br;
int ret;
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_if.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ * $Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
return -EINVAL;
+ if (dev->hard_start_xmit == br_dev_xmit)
+ return -ELOOP;
+
dev_hold(dev);
write_lock_bh(&br->lock);
if ((p = new_nbp(br, dev)) == NULL) {
struct net_bridge *br;
int i;
- i = 0;
-
br = bridge_list;
for (i=0;i<num;i++) {
if (br == NULL)
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.9 2001/08/14 22:05:57 davem Exp $
+ * $Id: br_input.c,v 1.10 2001/12/24 04:50:20 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
br_pass_frame_up_finish);
}
-static void __br_handle_frame(struct sk_buff *skb)
+static int br_handle_frame_finish(struct sk_buff *skb)
{
struct net_bridge *br;
unsigned char *dest;
dest = skb->mac.ethernet->h_dest;
p = skb->dev->br_port;
- br = p->br;
- passedup = 0;
+ if (p == NULL)
+ goto err_nolock;
- if (!(br->dev.flags & IFF_UP) ||
- p->state == BR_STATE_DISABLED)
- goto freeandout;
+ br = p->br;
+ read_lock(&br->lock);
+ if (skb->dev->br_port == NULL)
+ goto err;
+ passedup = 0;
if (br->dev.flags & IFF_PROMISC) {
struct sk_buff *skb2;
skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2) {
+ if (skb2 != NULL) {
passedup = 1;
br_pass_frame_up(br, skb2);
}
}
- if (skb->mac.ethernet->h_source[0] & 1)
- goto freeandout;
-
- if (!passedup &&
- (dest[0] & 1) &&
- (br->dev.flags & IFF_ALLMULTI || br->dev.mc_list != NULL)) {
- struct sk_buff *skb2;
-
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2) {
- passedup = 1;
- br_pass_frame_up(br, skb2);
- }
- }
-
- if (br->stp_enabled &&
- !memcmp(dest, bridge_ula, 5) &&
- !(dest[5] & 0xF0))
- goto handle_special_frame;
-
- if (p->state == BR_STATE_LEARNING ||
- p->state == BR_STATE_FORWARDING)
- br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
-
- if (p->state != BR_STATE_FORWARDING)
- goto freeandout;
-
if (dest[0] & 1) {
- br_flood_forward(br, skb, 1);
+ br_flood_forward(br, skb, !passedup);
if (!passedup)
br_pass_frame_up(br, skb);
- else
- kfree_skb(skb);
- return;
+ goto out;
}
dst = br_fdb_get(br, dest);
-
if (dst != NULL && dst->is_local) {
if (!passedup)
br_pass_frame_up(br, skb);
else
kfree_skb(skb);
br_fdb_put(dst);
- return;
+ goto out;
}
if (dst != NULL) {
br_forward(dst->dst, skb);
br_fdb_put(dst);
- return;
+ goto out;
}
br_flood_forward(br, skb, 0);
- return;
- handle_special_frame:
- if (!dest[5]) {
- br_stp_handle_bpdu(skb);
- return;
- }
+out:
+ read_unlock(&br->lock);
+ return 0;
- freeandout:
+err:
+ read_unlock(&br->lock);
+err_nolock:
kfree_skb(skb);
+ return 0;
}
-static int br_handle_frame_finish(struct sk_buff *skb)
+void br_handle_frame(struct sk_buff *skb)
{
struct net_bridge *br;
+ unsigned char *dest;
+ struct net_bridge_port *p;
- br = skb->dev->br_port->br;
+ dest = skb->mac.ethernet->h_dest;
+
+ p = skb->dev->br_port;
+ if (p == NULL)
+ goto err_nolock;
+
+ br = p->br;
read_lock(&br->lock);
- __br_handle_frame(skb);
- read_unlock(&br->lock);
+ if (skb->dev->br_port == NULL)
+ goto err;
- return 0;
-}
+ if (!(br->dev.flags & IFF_UP) ||
+ p->state == BR_STATE_DISABLED)
+ goto err;
-void br_handle_frame(struct sk_buff *skb)
-{
- NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+ if (skb->mac.ethernet->h_source[0] & 1)
+ goto err;
+
+ if (p->state == BR_STATE_LEARNING ||
+ p->state == BR_STATE_FORWARDING)
+ br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
+
+ if (br->stp_enabled &&
+ !memcmp(dest, bridge_ula, 5) &&
+ !(dest[5] & 0xF0))
+ goto handle_special_frame;
+
+ if (p->state == BR_STATE_FORWARDING) {
+ NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
+ read_unlock(&br->lock);
+ return;
+ }
+
+err:
+ read_unlock(&br->lock);
+err_nolock:
+ kfree_skb(skb);
+ return;
+
+handle_special_frame:
+ if (!dest[5]) {
+ br_stp_handle_bpdu(skb);
+ return;
+ }
+
+ kfree_skb(skb);
}
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private.h,v 1.6 2001/06/01 09:28:28 davem Exp $
+ * $Id: br_private.h,v 1.7 2001/12/24 00:59:55 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/* br_device.c */
extern void br_dev_setup(struct net_device *dev);
+extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev);
/* br_fdb.c */
extern void br_fdb_changeaddr(struct net_bridge_port *p,
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.82 2001/11/01 23:44:31 davem Exp $
+ * Version: $Id: icmp.c,v 1.83 2001/12/13 09:00:19 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* it's bit position.
*
* default:
- * dest unreachable (0x03), source quench (0x04),
- * time exceeded (0x11), parameter problem (0x12)
+ * dest unreachable (3), source quench (4),
+ * time exceeded (11), parameter problem (12)
*/
int sysctl_icmp_ratelimit = 1*HZ;
-/* IRC extension for IP connection tracking, Version 1.19
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+/* IRC extension for IP connection tracking, Version 1.20
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
* based on RR's ip_conntrack_ftp.c
*
- * ip_conntrack_irc.c,v 1.19 2001/10/25 14:34:21 laforge Exp
+ * ip_conntrack_irc.c,v 1.20 2001/12/06 07:42:10 laforge Exp
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 2 of the License, or (at your option) any later version.
**
* Module load syntax:
- * insmod ip_nat_irc.o ports=port1,port2,...port<MAX_PORTS>
+ * insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
*
* please give the ports of all IRC servers You wish to connect to.
* If You don't specify ports, the default will be port 6667
ret = nf_register_hook(&ip_conntrack_in_ops);
if (ret < 0) {
- printk("ip_conntrack: can't register in hook.\n");
+ printk("ip_conntrack: can't register pre-routing hook.\n");
goto cleanup_proc;
}
ret = nf_register_hook(&ip_conntrack_local_out_ops);
if ((*pskb)->ip_summed == CHECKSUM_HW)
(*pskb)->ip_summed = CHECKSUM_NONE;
+ /* Firewall rules can alter TOS: raw socket (tcpdump) may have
+ clone of incoming skb: don't disturb it --RR */
+ if (skb_cloned(*pskb) && !(*pskb)->sk) {
+ struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!nskb)
+ return NF_DROP;
+ kfree_skb(*pskb);
+ *pskb = nskb;
+ }
+
switch (hooknum) {
case NF_IP_PRE_ROUTING:
if (fwops->fw_acct_in)
}
list_prepend(&redirs, redir);
init_timer(&redir->destroyme);
+ redir->destroyme.expires = jiffies + 75*HZ;
+ add_timer(&redir->destroyme);
}
/* In case mangling has changed, rewrite this part. */
redir->core = ((struct redir_core)
synchronize_bh()) can vanish. */
READ_LOCK(&ip_nat_lock);
for (i = 0; i < info->num_manips; i++) {
+ /* raw socket (tcpdump) may have clone of incoming
+ skb: don't disturb it --RR */
+ if (skb_cloned(*pskb) && !(*pskb)->sk) {
+ struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!nskb) {
+ READ_UNLOCK(&ip_nat_lock);
+ return NF_DROP;
+ }
+ kfree_skb(*pskb);
+ *pskb = nskb;
+ }
+
if (info->manips[i].direction == dir
&& info->manips[i].hooknum == hooknum) {
DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
}
}
+ /* Alexey says: if a hook changes _data_ ... it can break
+ original packet sitting in tcp queue and this is fatal */
+ if (skb_cloned(*skb)) {
+ struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
+ if (!nskb) {
+ if (net_ratelimit())
+ printk("Out of memory cloning TCP packet\n");
+ return 0;
+ }
+ /* Rest of kernel will get very unhappy if we pass it
+ a suddenly-orphaned skbuff */
+ if ((*skb)->sk)
+ skb_set_owner_w(nskb, (*skb)->sk);
+ kfree_skb(*skb);
+ *skb = nskb;
+ }
+
/* skb may be copied !! */
iph = (*skb)->nh.iph;
tcph = (void *)iph + iph->ihl*4;
/* IRC extension for TCP NAT alteration.
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
* based on a copy of RR's ip_nat_ftp.c
*
- * ip_nat_irc.c,v 1.15 2001/10/22 10:43:53 laforge Exp
+ * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
}
newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
- newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
NIPQUAD(newsrcip), NIPQUAD(newdstip));
Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
+ Changes:
+ 25 Aug 2001 Harald Welte <laforge@gnumonks.org>
+ - decrement and check TTL if not called from FORWARD hook
+
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
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/ip.h>
+#include <net/icmp.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h>
#include <linux/route.h>
const void *targinfo,
void *userinfo)
{
- if ((*pskb)->dst != NULL) {
- if (route_mirror(*pskb)) {
- ip_rewrite(*pskb);
- /* Don't let conntrack code see this packet:
- it will think we are starting a new
- connection! --RR */
- ip_direct_send(*pskb);
- return NF_STOLEN;
+ if (((*pskb)->dst != NULL) &&
+ route_mirror(*pskb)) {
+
+ ip_rewrite(*pskb);
+
+ /* If we are not at FORWARD hook (INPUT/PREROUTING),
+ * the TTL isn't decreased by the IP stack */
+ if (hooknum != NF_IP_FORWARD) {
+ struct iphdr *iph = (*pskb)->nh.iph;
+ if (iph->ttl <= 1) {
+ /* this will traverse normal stack, and
+ * thus call conntrack on the icmp packet */
+ icmp_send(*pskb, ICMP_TIME_EXCEEDED,
+ ICMP_EXC_TTL, 0);
+ return NF_DROP;
+ }
+ ip_decrease_ttl(iph);
}
+
+ /* Don't let conntrack code see this packet:
+ it will think we are starting a new
+ connection! --RR */
+ ip_direct_send(*pskb);
+
+ return NF_STOLEN;
}
return NF_DROP;
}
{
const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
struct tcphdr *tcph;
- struct iphdr *iph = (*pskb)->nh.iph;
+ struct iphdr *iph;
u_int16_t tcplen, newtotlen, oldval, newmss;
unsigned int i;
u_int8_t *opt;
+ /* raw socket (tcpdump) may have clone of incoming skb: don't
+ disturb it --RR */
+ if (skb_cloned(*pskb) && !(*pskb)->sk) {
+ struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!nskb)
+ return NF_DROP;
+ kfree_skb(*pskb);
+ *pskb = nskb;
+ }
+
+ iph = (*pskb)->nh.iph;
tcplen = (*pskb)->len - iph->ihl*4;
tcph = (void *)iph + iph->ihl*4;
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
u_int16_t diffs[2];
+ /* raw socket (tcpdump) may have clone of incoming
+ skb: don't disturb it --RR */
+ if (skb_cloned(*pskb) && !(*pskb)->sk) {
+ struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!nskb)
+ return NF_DROP;
+ kfree_skb(*pskb);
+ *pskb = nskb;
+ iph = (*pskb)->nh.iph;
+ }
+
diffs[0] = htons(iph->tos) ^ 0xFFFF;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
diffs[1] = htons(iph->tos);
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
+#define TH_ECE 0x40
+#define TH_CWR 0x80
/* TCP-specific checks. */
static int
}
/* CHECK: TCP flags. */
- tcpflags = ((u_int8_t *)tcph)[13];
+ tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
if (tcpflags != TH_SYN
&& tcpflags != (TH_SYN|TH_ACK)
+ && tcpflags != TH_RST
&& tcpflags != (TH_RST|TH_ACK)
&& tcpflags != (TH_RST|TH_ACK|TH_PUSH)
&& tcpflags != (TH_FIN|TH_ACK)
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.140 2001/10/15 12:34:50 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.143 2001/12/21 05:05:41 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
tcp_parse_options(skb, &tp, 0);
+ tp.tstamp_ok = tp.saw_tstamp;
tcp_openreq_init(req, &tp, skb);
req->class = &or_ipv6;
#include <linux/spinlock.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
#ifdef RPC_DEBUG
#define RPCDBG_FACILITY RPCDBG_SCHED
int to_move = cur_len;
if (to_move > copied)
to_move = copied;
- if (need_csum)
- csum = skb_copy_and_csum_bits(skb, offset, cur_ptr,
- to_move, csum);
- else
+ if (need_csum) {
+ unsigned int csum2;
+
+ csum2 = skb_copy_and_csum_bits(skb, offset,
+ cur_ptr,
+ to_move, 0);
+ csum = csum_block_add(csum, csum2, offset);
+ } else
skb_copy_bits(skb, offset, cur_ptr, to_move);
offset += to_move;
copied -= to_move;
}
}
if (need_csum) {
- if (slack > 0)
- csum = skb_checksum(skb, offset, slack, csum);
+ if (slack > 0) {
+ unsigned int csum2;
+
+ csum2 = skb_checksum(skb, offset, slack, 0);
+ csum = csum_block_add(csum, csum2, offset);
+ }
if ((unsigned short)csum_fold(csum))
return -1;
}