| summaryrefslogtreecommitdiff |
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-05 08:13:33 (GMT) |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-05 08:13:33 (GMT) |
| commit | 5fb612aa91a08c183200312d943de6691f806ce6 (patch) (side-by-side diff) | |
| tree | eeab4310853f2b2f3bed3a1931932d46b2bf39f9 | |
| parent | 18a933102825ea1e1b7e059234537d4d927e9216 (diff) | |
v2.5.1.11 -> v2.5.2v2.5.2
- Matt Domsch: combine common crc32 library
- Pete Zaitcev: ymfpci update
- Davide Libenzi: scheduler improvements
- Al Viro: almost there: "struct block_device *" everywhere
- Richard Gooch: devfs cpqarray update, race fix
- Rusty Russell: PATH_MAX should include the final '0' count
- David Miller: various random updates (mainly net and sparc)
317 files changed, 6121 insertions, 3168 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 9be2197..9bc25ad 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -6301,6 +6301,18 @@ CONFIG_BLK_CPQ_CISS_DA 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 @@ -24029,6 +24041,13 @@ CONFIG_GDB_CONSOLE 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, diff --git a/Documentation/block/request.txt b/Documentation/block/request.txt new file mode 100644 index 0000000..b8de235 --- a/dev/null +++ b/Documentation/block/request.txt @@ -0,0 +1,86 @@ + +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 diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt index d8c95d5..8548f91 100644 --- a/Documentation/cciss.txt +++ b/Documentation/cciss.txt @@ -100,7 +100,7 @@ lun used to address the device. Once this is done, the SCSI mid layer 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 diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog index 407a684..de386c4 100644 --- a/Documentation/filesystems/devfs/ChangeLog +++ b/Documentation/filesystems/devfs/ChangeLog @@ -1863,3 +1863,9 @@ Changes for patch v205 - 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> diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 9d54549..e0588af 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -309,13 +309,20 @@ icmp_echo_ignore_broadcasts - BOOLEAN 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 @@ -511,4 +518,4 @@ IPv6 Update by: 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 $ @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 2 -EXTRAVERSION =-pre11 +EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -122,7 +122,7 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o 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 := @@ -261,9 +261,9 @@ vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o ini $(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 diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 91f072a..14ca220 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -393,3 +393,5 @@ else fi endmenu + +source lib/Config.in diff --git a/arch/arm/config.in b/arch/arm/config.in index 02bcbfa..f71bf71 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -709,3 +709,5 @@ dep_bool ' Kernel low-level debugging messages via footbridge serial port' CO 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 diff --git a/arch/cris/config.in b/arch/cris/config.in index 5a9ee03..6601335 100644 --- a/arch/cris/config.in +++ b/arch/cris/config.in @@ -251,3 +251,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi endmenu + +source lib/Config.in diff --git a/arch/i386/config.in b/arch/i386/config.in index 68a6cc9..aa1284a 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -419,3 +419,5 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then fi endmenu + +source lib/Config.in diff --git a/arch/i386/defconfig b/arch/i386/defconfig index b954777..11ce0b5 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -130,6 +130,7 @@ CONFIG_BLK_DEV_FD=y # 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 @@ -831,3 +832,8 @@ CONFIG_USB_STORAGE=y # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index efd313e..52b2a38 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -748,6 +748,7 @@ void __init setup_arch(char **cmdline_p) 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) { diff --git a/arch/ia64/config.in b/arch/ia64/config.in index fb0931f..dff81a6 100644 --- a/arch/ia64/config.in +++ b/arch/ia64/config.in @@ -234,6 +234,8 @@ endmenu source drivers/usb/Config.in +source lib/Config.in + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in fi diff --git a/arch/m68k/config.in b/arch/m68k/config.in index a65b213..44bc86f 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -546,3 +546,5 @@ comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +source lib/Config.in diff --git a/arch/mips/config.in b/arch/mips/config.in index 3136bd0..25b7fd9 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -520,3 +520,5 @@ if [ "$CONFIG_SMP" != "y" ]; then bool 'Run uncached' CONFIG_MIPS_UNCACHED fi endmenu + +source lib/Config.in diff --git a/arch/mips64/config.in b/arch/mips64/config.in index 4ebb9f2..5ddba84 100644 --- a/arch/mips64/config.in +++ b/arch/mips64/config.in @@ -276,3 +276,5 @@ if [ "$CONFIG_SMP" != "y" ]; then bool 'Run uncached' CONFIG_MIPS_UNCACHED fi endmenu + +source lib/Config.in diff --git a/arch/parisc/config.in b/arch/parisc/config.in index f68410f..367242b 100644 --- a/arch/parisc/config.in +++ b/arch/parisc/config.in @@ -208,3 +208,4 @@ comment 'Kernel hacking' bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source lib/Config.in diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 3545adc..7dfaf4d 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -393,3 +393,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ bool 'Include kgdb kernel debugger' CONFIG_KGDB bool 'Include xmon kernel debugger' CONFIG_XMON endmenu + +source lib/Config.in diff --git a/arch/s390/config.in b/arch/s390/config.in index c545c36..f5932ba 100644 --- a/arch/s390/config.in +++ b/arch/s390/config.in @@ -73,3 +73,4 @@ fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source lib/Config.in diff --git a/arch/s390x/config.in b/arch/s390x/config.in index 5a9c5b6..1ab8e3c 100644 --- a/arch/s390x/config.in +++ b/arch/s390x/config.in @@ -77,3 +77,4 @@ fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source lib/Config.in diff --git a/arch/sh/config.in b/arch/sh/config.in index 7b70ccc..32fb221 100644 --- a/arch/sh/config.in +++ b/arch/sh/config.in @@ -386,3 +386,5 @@ if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then bool 'Early printk support' CONFIG_SH_EARLY_PRINTK fi endmenu + +source lib/Config.in diff --git a/arch/sparc/config.in b/arch/sparc/config.in index 9f05197..032e160 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -266,3 +266,5 @@ comment 'Kernel hacking' bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +source lib/Config.in diff --git a/arch/sparc/kernel/check_asm.sh b/arch/sparc/kernel/check_asm.sh index 1c2aecb..f9157e4 100755 --- a/arch/sparc/kernel/check_asm.sh +++ b/arch/sparc/kernel/check_asm.sh @@ -1,12 +1,12 @@ #!/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 ;; diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index f8a9ea6..ecd4e6d 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -4,9 +4,10 @@ * 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> diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index 609ab36..ee31e2a 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $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) diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index 5633c88..d6d5e35 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -14,6 +14,6 @@ struct mm_struct init_mm = INIT_MM(init_mm); * 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) }; diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 49e6f1a4..5e3a400 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $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 diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 0cadcd7..2e477bf 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $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) @@ -60,9 +60,6 @@ int cpu_idle(void) goto out; /* endless idle loop with no priority at all */ - current->nice = 20; - init_idle(); - for (;;) { if (ARCH_SUN4C_SUN4) { static int count = HZ; @@ -108,9 +105,6 @@ out: int cpu_idle(void) { /* endless idle loop with no priority at all */ - current->nice = 20; - init_idle(); - while(1) { if(current->need_resched) { schedule(); @@ -283,37 +277,29 @@ void show_regs(struct pt_regs * regs) 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.. diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 957ddc1..51bfe75 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,4 +1,4 @@ -/* $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 @@ -16,6 +16,7 @@ #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> diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 2a47968..c53e219 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -1,4 +1,4 @@ -/* $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. * diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index e8f5fb3..a63ffb0 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -127,7 +127,7 @@ void __init smp4d_callin(void) 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. */ @@ -197,10 +197,9 @@ void __init smp4d_boot_cpus(void) 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. */ @@ -222,14 +221,11 @@ void __init smp4d_boot_cpus(void) 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++) diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 676b9f2..4cd8f8b 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -170,12 +170,11 @@ void __init smp4m_boot_cpus(void) 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. */ @@ -195,14 +194,11 @@ void __init smp4m_boot_cpus(void) 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... */ diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 3180994..8dd283c 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $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) @@ -90,8 +90,8 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, * 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; diff --git a/arch/sparc/kernel/trampoline.S b/arch/sparc/kernel/trampoline.S index b7b7025..d316096 100644 --- a/arch/sparc/kernel/trampoline.S +++ b/arch/sparc/kernel/trampoline.S @@ -1,4 +1,4 @@ -/* $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) @@ -88,6 +88,8 @@ cpu3_startup: .align 4 smp_do_cpu_idle: + call C_LABEL(init_idle) + nop call C_LABEL(cpu_idle) mov 0, %o0 diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c index 0f718ba..5f90082 100644 --- a/arch/sparc/kernel/unaligned.c +++ b/arch/sparc/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $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. * @@ -224,7 +224,7 @@ __asm__ __volatile__ ( \ "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" \ @@ -277,7 +277,7 @@ __asm__ __volatile__ ( \ "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" \ diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c index 165c83a..5f63e46 100644 --- a/arch/sparc/mm/extable.c +++ b/arch/sparc/mm/extable.c @@ -11,35 +11,49 @@ extern const struct exception_table_entry __stop___ex_table[]; 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; } diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index b422c57..8f1d7e7 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -1,4 +1,4 @@ -/* $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) @@ -155,34 +155,47 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk, 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; } diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 34e289e..c0baac1 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $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) @@ -410,9 +410,6 @@ void __init mem_init(void) 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; diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index be4522e..16fcc37 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -1,4 +1,4 @@ -/* $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) @@ -131,7 +131,7 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus /* 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); diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 3bd631f..cfd35db 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -1,4 +1,4 @@ -/* $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) @@ -168,7 +168,7 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb 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); } } @@ -177,7 +177,7 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu { 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); } } @@ -187,14 +187,14 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu 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; diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c index 244619e..96e3a34 100644 --- a/arch/sparc/prom/ranges.c +++ b/arch/sparc/prom/ranges.c @@ -1,4 +1,4 @@ -/* $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) @@ -16,26 +16,25 @@ struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; 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) { diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index 64233d5..75ce131 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,4 +1,4 @@ -# $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 @@ -38,11 +38,6 @@ CC_UNDECL = -Wa,--undeclared-regs 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 @@ -53,25 +48,6 @@ else 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 diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index 1b91160..72294c1 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $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. # @@ -31,6 +31,8 @@ bool 'Symmetric multi-processing support' CONFIG_SMP # 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 @@ -89,7 +91,6 @@ endmenu 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 @@ -191,21 +192,21 @@ if [ "$CONFIG_SCSI" != "n" ]; then 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 @@ -295,6 +296,15 @@ endmenu 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 diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 813126d..3ff8f94 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -22,6 +22,7 @@ CONFIG_VT=y 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 @@ -84,7 +85,6 @@ CONFIG_WATCHDOG_RIO=m # Console drivers # CONFIG_PROM_CONSOLE=y -CONFIG_FB=y # # Frame-buffer support @@ -158,11 +158,11 @@ CONFIG_BLK_DEV_NBD=m # # 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 @@ -174,8 +174,6 @@ CONFIG_BLK_DEV_NBD=m # 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 @@ -266,8 +264,8 @@ CONFIG_BLK_DEV_IDEDISK=y # 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 # @@ -313,9 +311,9 @@ CONFIG_IDEDMA_AUTO=y # 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 @@ -354,15 +352,11 @@ CONFIG_SCSI_AIC7XXX_OLD=m 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 @@ -470,6 +464,7 @@ CONFIG_PCNET32=m 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 @@ -493,6 +488,7 @@ CONFIG_EPIC100=m 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 @@ -539,7 +535,7 @@ CONFIG_SLIP_SMART=y CONFIG_NET_FC=y # CONFIG_IPHASE5526 is not set # CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set +CONFIG_SHAPER=m # # Wan interfaces @@ -603,7 +599,7 @@ CONFIG_EFS_FS=m # 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 @@ -743,8 +739,9 @@ CONFIG_USB_DEVICEFS=y # 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 @@ -789,6 +786,8 @@ CONFIG_USB_IBMCAM=m 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 @@ -817,6 +816,7 @@ CONFIG_USB_SERIAL_DIGI_ACCELEPORT=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 @@ -830,6 +830,7 @@ CONFIG_USB_SERIAL_KEYSPAN=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 @@ -839,6 +840,7 @@ CONFIG_USB_SERIAL_OMNINET=m # USB Miscellaneous drivers # CONFIG_USB_RIO500=m +CONFIG_USB_AUERSWALD=m # # Bluetooth support @@ -861,4 +863,9 @@ CONFIG_BLUEZ_HCIVHCI=m # # 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 diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index f80dcd0..b4b2515 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $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 @@ -68,7 +68,7 @@ check_asm: dummy @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 @@ -95,12 +95,12 @@ check_asm: dummy ./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 @@ -127,9 +127,9 @@ check_asm: dummy $(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 @@ -140,7 +140,7 @@ check_asm: dummy $(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 @@ -156,7 +156,7 @@ check_asm: dummy $(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 \ diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c index dba732a..318efe3 100644 --- a/arch/sparc64/kernel/central.c +++ b/arch/sparc64/kernel/central.c @@ -1,4 +1,4 @@ -/* $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) @@ -67,6 +67,7 @@ static void adjust_regs(struct linux_prom_registers *regp, int nregs, 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; } } diff --git a/arch/sparc64/kernel/check_asm.sh b/arch/sparc64/kernel/check_asm.sh index beaf653..65259c2 100755 --- a/arch/sparc64/kernel/check_asm.sh +++ b/arch/sparc64/kernel/check_asm.sh @@ -1,12 +1,12 @@ #!/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 ;; diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 1cf4f31..b75122e 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c @@ -1,4 +1,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) @@ -9,6 +9,10 @@ #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> diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index acbb1b5..d0bbcf1 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $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) @@ -483,7 +483,11 @@ do_ivec_xcall: 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: @@ -657,15 +661,15 @@ floppy_tdone: 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)] @@ -678,7 +682,12 @@ floppy_fifo_emptied: 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... @@ -1615,6 +1624,11 @@ do_gettimeofday: /* %o0 = timevalp */ * * 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 @@ -1626,6 +1640,7 @@ do_gettimeofday: /* %o0 = timevalp */ 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 @@ -1634,6 +1649,7 @@ do_gettimeofday: /* %o0 = timevalp */ 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 diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 2a3ef1f..c4bb21f 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $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) @@ -472,6 +472,7 @@ static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) 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); @@ -2421,6 +2422,7 @@ typedef struct { 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 { @@ -2462,7 +2464,7 @@ typedef struct { } lv_status_byindex_req32_t; typedef struct { - dev_t dev; + __kernel_dev_t32 dev; u32 lv; } lv_status_bydev_req32_t; @@ -2535,7 +2537,8 @@ static lv_t *get_lv_t(u32 p, int *errp) 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; @@ -2565,12 +2568,11 @@ static lv_t *get_lv_t(u32 p, int *errp) 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); } } } @@ -2608,7 +2610,7 @@ static int copy_lv_t(u32 ptr, lv_t *l) 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; @@ -2626,17 +2628,22 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 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; @@ -2648,39 +2655,46 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 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: @@ -2688,54 +2702,70 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 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) { @@ -2748,42 +2778,60 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) } 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 @@ -3379,11 +3427,11 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) } 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; }; @@ -3413,14 +3461,14 @@ static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long /* 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; } @@ -3432,8 +3480,8 @@ static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long 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; } @@ -4666,6 +4714,7 @@ HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) 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) @@ -4675,6 +4724,7 @@ HANDLE_IOCTL(LV_REDUCE, 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 */ diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c index 134be5c..12c93a3 100644 --- a/arch/sparc64/kernel/iommu_common.c +++ b/arch/sparc64/kernel/iommu_common.c @@ -1,4 +1,4 @@ -/* $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) @@ -66,9 +66,7 @@ static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, 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; @@ -118,9 +116,7 @@ static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, 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) { @@ -183,10 +179,11 @@ void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages 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); } } @@ -201,21 +198,15 @@ unsigned long prepare_sg(struct scatterlist *sg, int nents) 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; diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index dedf08d..59b4f9c 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $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) @@ -19,6 +19,7 @@ #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> @@ -35,6 +36,7 @@ #include <asm/softirq.h> #include <asm/starfire.h> #include <asm/uaccess.h> +#include <asm/cache.h> #ifdef CONFIG_SMP static void distribute_irqs(void); @@ -53,10 +55,10 @@ 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)]) @@ -116,19 +118,19 @@ int show_interrupts(struct seq_file *p, void *v) 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'); } @@ -161,7 +163,7 @@ void enable_irq(unsigned int irq) 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; } @@ -823,6 +825,11 @@ void handler_irq(int irq, struct pt_regs *regs) 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) ? @@ -1246,19 +1253,15 @@ void enable_prom_timer(void) 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 diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 38d253c..b2f3417 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -1,4 +1,4 @@ -/* $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) @@ -425,9 +425,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int } #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) @@ -522,9 +520,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int 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; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 7ea3a30..59ea29a 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1,4 +1,4 @@ -/* $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) @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <asm/pbm.h> +#include <asm/fhc.h> #include <asm/iommu.h> #include <asm/irq.h> #include <asm/starfire.h> @@ -371,6 +372,7 @@ static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: ret = 10; break; @@ -1479,8 +1481,7 @@ static void psycho_pbm_init(struct pci_controller_info *p, { 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; @@ -1489,13 +1490,9 @@ static void psycho_pbm_init(struct pci_controller_info *p, 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; } diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index b5a5861..7f86b6f 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1,4 +1,4 @@ -/* $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) @@ -589,6 +589,11 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) { 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; @@ -609,6 +614,7 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: ret = 10; break; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 3e35c92..a660d05 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1,4 +1,4 @@ -/* $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) @@ -337,6 +337,11 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) { 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; @@ -357,6 +362,7 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: ret = 10; break; diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 35f1cc2..320fa25 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -1,4 +1,4 @@ -/* $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) @@ -61,7 +61,7 @@ static int powerd(void *__unused) 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); @@ -98,16 +98,19 @@ void __init power_init(void) 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 */ diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 797e5c7..cedff9e 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $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) @@ -53,9 +53,6 @@ int cpu_idle(void) 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 @@ -78,13 +75,10 @@ int cpu_idle(void) /* * 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(); @@ -274,7 +268,12 @@ void __show_regs(struct pt_regs * regs) #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()), @@ -296,7 +295,9 @@ void __show_regs(struct pt_regs * regs) 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 } @@ -462,6 +463,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) 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])); @@ -582,6 +584,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, 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)); diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 20cd9a5..5625e6c 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $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) @@ -18,14 +18,13 @@ #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 @@ -34,42 +33,100 @@ __handle_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 @@ -84,7 +141,7 @@ __handle_signal: .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 @@ -99,29 +156,43 @@ __handle_softirq_continue: 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 diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 0e5a073..4998dcf 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1,4 +1,4 @@ -/* $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) @@ -377,9 +377,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, } #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) { @@ -470,9 +468,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int di 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; diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c index 3e3b38e..e3c7926 100644 --- a/arch/sparc64/kernel/semaphore.c +++ b/arch/sparc64/kernel/semaphore.c @@ -1,4 +1,4 @@ -/* $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 @@ -31,7 +31,7 @@ static __inline__ int __sem_update_count(struct semaphore *sem, int incr) " 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"); diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 3540212..10785cb 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $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 @@ -17,6 +17,7 @@ #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> diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 956a804..62db94b 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $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 @@ -16,6 +16,7 @@ #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> diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index a6f259c..a4fd67d 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -209,23 +209,10 @@ void __init smp_callin(void) 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) @@ -251,7 +238,6 @@ void __init smp_boot_cpus(void) printk("Entering UltraSMPenguin Mode...\n"); __sti(); smp_store_cpu_info(boot_cpu_id); - init_idle(); if (linux_num_cpus == 1) return; @@ -270,16 +256,13 @@ void __init smp_boot_cpus(void) 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; @@ -483,7 +466,7 @@ retry: __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. */ @@ -543,6 +526,9 @@ struct call_data_struct { 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, @@ -550,6 +536,7 @@ 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; @@ -559,19 +546,36 @@ int smp_call_function(void (*func)(void *info), void *info, 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; @@ -598,7 +602,7 @@ extern unsigned long xcall_receive_signal; 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 @@ -621,7 +625,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) 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()) { @@ -643,13 +647,46 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) __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) { @@ -1075,7 +1112,6 @@ void __init smp_tick_init(void) __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; } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 234e0af..8c9333d 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $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) @@ -98,7 +98,7 @@ extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs); #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); @@ -113,7 +113,7 @@ extern unsigned long phys_base; /* 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); @@ -145,7 +145,7 @@ EXPORT_SYMBOL(__cpu_number_map); 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); @@ -319,7 +319,6 @@ EXPORT_SYMBOL(sparc32_open); 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); @@ -354,4 +353,8 @@ EXPORT_SYMBOL_NOVERS(memmove); void VISenter(void); /* RAID code needs this */ -EXPORT_SYMBOL(VISenter); +EXPORT_SYMBOL_NOVERS(VISenter); + +#ifdef CONFIG_DEBUG_BUGVERBOSE +EXPORT_SYMBOL(do_BUG); +#endif diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index f174b54..353ddf6 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $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 @@ -40,12 +40,15 @@ asmlinkage unsigned long sys_getpagesize(void) 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 @@ -63,11 +66,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi 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) { @@ -81,8 +87,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi 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); } } @@ -255,27 +261,15 @@ extern asmlinkage long sys_personality(unsigned long); 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 */ diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 39e2781..47e5a44 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $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) @@ -68,7 +68,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of 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", @@ -76,15 +76,15 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of 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; @@ -92,7 +92,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of } retval = -EINVAL; - if(!(flags & MAP_FIXED)) + if (!(flags & MAP_FIXED)) addr = 0; else if (len > 0xf0000000 || addr > 0xf0000000 - len) goto out_putf; @@ -106,7 +106,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of (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) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index b89235a..3119c67 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $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) @@ -609,7 +609,6 @@ void __init time_init(void) unsigned long clock; init_timers(timer_interrupt, &clock); - timer_tick_offset = clock / HZ; timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020)); } diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index fdf4a00..eda8ed5 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S @@ -1,4 +1,4 @@ -/* $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) @@ -262,7 +262,7 @@ startup_continue: 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 diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 90063fb..f022447 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $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) @@ -38,16 +38,19 @@ 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; @@ -56,7 +59,7 @@ void bad_trap (struct pt_regs *regs, long lvl) 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); } @@ -68,6 +71,14 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl) 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) { @@ -947,6 +958,7 @@ static int cheetah_fix_ce(unsigned long physaddr) __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" @@ -1648,13 +1660,16 @@ void do_getpsr(struct pt_regs *regs) } } +/* 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 } diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 182fb0f..9b2e54e 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $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) @@ -15,11 +15,13 @@ 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) diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S index 35a34eb..77be8b1 100644 --- a/arch/sparc64/lib/atomic.S +++ b/arch/sparc64/lib/atomic.S @@ -1,4 +1,4 @@ -/* $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) @@ -19,7 +19,7 @@ __atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ cas [%o1], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __atomic_add - nop + membar #StoreLoad | #StoreStore retl add %g7, %o0, %o0 @@ -30,7 +30,7 @@ __atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */ cas [%o1], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __atomic_sub - nop + membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 atomic_impl_end: diff --git a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S index fafe016..fa85582 100644 --- a/arch/sparc64/lib/bitops.S +++ b/arch/sparc64/lib/bitops.S @@ -1,4 +1,4 @@ -/* $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) @@ -28,7 +28,7 @@ ___test_and_set_bit: /* %o0=nr, %o1=addr */ 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 */ @@ -47,7 +47,7 @@ ___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 */ @@ -65,7 +65,7 @@ ___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 @@ -85,7 +85,7 @@ ___test_and_set_le_bit: /* %o0=nr, %o1=addr */ 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 */ @@ -104,7 +104,7 @@ ___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: diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index dedc035..7042ae2 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,4 +1,4 @@ -/* $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) @@ -17,10 +17,9 @@ 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) @@ -34,64 +33,6 @@ .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 */ @@ -110,7 +51,7 @@ 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 @@ -134,6 +75,7 @@ cheetah_patch_1: 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 @@ -152,6 +94,7 @@ cheetah_patch_1: 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 @@ -169,9 +112,10 @@ cheetah_patch_1: 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 @@ -402,7 +346,7 @@ clear_user_page: /* %o0=dest, %o1=vaddr */ 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 @@ -420,6 +364,7 @@ cheetah_patch_2: 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 @@ -430,8 +375,9 @@ cheetah_patch_2: 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 diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c index b518114..ea62c3e 100644 --- a/arch/sparc64/lib/debuglocks.c +++ b/arch/sparc64/lib/debuglocks.c @@ -1,4 +1,4 @@ -/* $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) @@ -10,10 +10,7 @@ #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)) @@ -56,6 +53,7 @@ void _do_spin_lock(spinlock_t *lock, char *str) unsigned long caller, val; int stuck = INIT_STUCK; int cpu = smp_processor_id(); + int shown = 0; GET_CALLER(caller); again: @@ -67,7 +65,8 @@ again: if (val) { while (lock->lock) { if (!--stuck) { - show(str, lock, caller); + if (shown++ <= 2) + show(str, lock, caller); stuck = INIT_STUCK; } membar("#LoadLoad"); @@ -76,6 +75,8 @@ again: } 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) @@ -92,6 +93,8 @@ 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; } @@ -102,6 +105,7 @@ void _do_spin_unlock(spinlock_t *lock) lock->owner_cpu = NO_PROC_ID; membar("#StoreStore | #LoadStore"); lock->lock = 0; + current->thread.smp_lock_count--; } /* Keep INIT_STUCK the same... */ @@ -111,13 +115,15 @@ void _do_read_lock (rwlock_t *rw, char *str) 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"); @@ -137,6 +143,8 @@ wlock_again: 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) @@ -144,11 +152,13 @@ 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__( @@ -162,7 +172,8 @@ runlock_again: : "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; @@ -174,13 +185,15 @@ void _do_write_lock (rwlock_t *rw, char *str) 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"); @@ -204,7 +217,8 @@ wlock_again: 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; @@ -214,7 +228,8 @@ 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__( @@ -231,7 +246,8 @@ wlock_again: : "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"); @@ -242,18 +258,22 @@ wlock_again: /* 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" @@ -268,12 +288,21 @@ wlock_again: : "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 */ diff --git a/arch/sparc64/lib/dec_and_lock.S b/arch/sparc64/lib/dec_and_lock.S index 2a59b27..b7c2631 100644 --- a/arch/sparc64/lib/dec_and_lock.S +++ b/arch/sparc64/lib/dec_and_lock.S @@ -1,10 +1,12 @@ -/* $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 @@ -34,13 +36,15 @@ nzero: cas [%o0], %g5, %g7 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 @@ -61,3 +65,5 @@ spin_on_lock: ba,pt %xcc, to_zero nop nop + +#endif /* !(CONFIG_DEBUG_SPINLOCK) */ diff --git a/arch/sparc64/mm/extable.c b/arch/sparc64/mm/extable.c index dcd982b..595eff6 100644 --- a/arch/sparc64/mm/extable.c +++ b/arch/sparc64/mm/extable.c @@ -11,35 +11,49 @@ extern const struct exception_table_entry __stop___ex_table[]; 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; } diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 2d36362..151ff52 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -111,7 +111,7 @@ int do_check_pgt_cache(int low, int high) 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); @@ -120,7 +120,7 @@ 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 @@ -152,7 +152,7 @@ static __inline__ void set_dcache_dirty(struct page *page) "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"); @@ -172,7 +172,7 @@ static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long c "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) @@ -261,14 +261,14 @@ void mmu_info(struct seq_file *m) 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 { diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 8faa359..828749f 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $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) @@ -117,7 +117,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ 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 @@ -642,7 +642,7 @@ __spitfire_xcall_flush_tlb_all: 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 @@ -679,20 +679,15 @@ __cheetah_xcall_flush_cache_all: .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 diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 98b1610..0ba7167 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -1,4 +1,4 @@ -/* $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) @@ -429,7 +429,7 @@ static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf) __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) || @@ -463,7 +463,7 @@ static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf) __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) || diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 5a368d5..3393729 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -1,4 +1,4 @@ -/* $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) @@ -15,6 +15,7 @@ #include <linux/mman.h> #include <linux/file.h> #include <linux/timex.h> +#include <linux/major.h> #include <asm/uaccess.h> #include <asm/string.h> @@ -74,8 +75,8 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o 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; diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index 320f85c..dd06c16 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -1,4 +1,4 @@ -/* $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) @@ -61,14 +61,14 @@ static int socksys_open(struct inode * inode, struct file * filp) (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; diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index 6728b59..d279989 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -1,4 +1,4 @@ -/* $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) @@ -921,7 +921,7 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) 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); diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 7902e3f..c787546 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -35,6 +35,7 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then 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 diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e279273..35543c2 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -126,6 +126,8 @@ static struct block_device_operations cciss_fops = { revalidate: frevalidate_logvol, }; +#include "cciss_scsi.c" /* For SCSI tape support */ + /* * Report information about this controller. */ @@ -160,6 +162,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 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", @@ -179,20 +182,53 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 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 */ @@ -824,9 +860,12 @@ static int sendcmd( 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; @@ -860,15 +899,23 @@ static int sendcmd( 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) { @@ -884,6 +931,7 @@ static int sendcmd( 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. @@ -893,7 +941,7 @@ static int sendcmd( 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; @@ -971,6 +1019,7 @@ static int sendcmd( 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) || @@ -1356,6 +1405,10 @@ static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) } 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; } } @@ -1592,7 +1645,7 @@ static void cciss_getgeometry(int cntl_num) } /* 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]; @@ -1606,7 +1659,7 @@ static void cciss_getgeometry(int cntl_num) } /* 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) { @@ -1652,7 +1705,7 @@ static void cciss_getgeometry(int cntl_num) 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 & @@ -1684,7 +1737,7 @@ static void cciss_getgeometry(int cntl_num) /* 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) @@ -1860,6 +1913,8 @@ static int __init cciss_init_one(struct pci_dev *pdev, 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); @@ -1901,6 +1956,8 @@ static int __init cciss_init_one(struct pci_dev *pdev, MAX_PART, &cciss_fops, hba[i]->drv[j].nr_blocks); + cciss_register_scsi(i, 1); /* hook ourself into SCSI subsystem */ + return(1); } @@ -1927,6 +1984,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) 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); diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 1dafe1e..c6eb34d 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -83,6 +83,9 @@ struct ctlr_info 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 */ diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 7faf6f0..6ba126d 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -89,6 +89,7 @@ typedef union _u64bit //STRUCTURES //########################################################################### #define CISS_MAX_LUN 16 +#define CISS_MAX_PHYS_LUN 1024 // SCSI-3 Cmmands #pragma pack(1) @@ -101,6 +102,7 @@ typedef struct _InquiryData_struct } InquiryData_struct; #define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */ +#define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */ // Data returned typedef struct _ReportLUNdata_struct { @@ -215,6 +217,9 @@ typedef struct _ErrorInfo_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; @@ -229,6 +234,9 @@ typedef struct _CommandList_struct { 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 diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c new file mode 100644 index 0000000..ad40c68 --- a/dev/null +++ b/drivers/block/cciss_scsi.c @@ -0,0 +1,1634 @@ +/* + * 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 */ diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h new file mode 100644 index 0000000..1e580f1 --- a/dev/null +++ b/drivers/block/cciss_scsi.h @@ -0,0 +1,98 @@ +/* + * 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 */ diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 6a92fa4..b67eeec 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -32,6 +32,7 @@ #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> @@ -70,6 +71,7 @@ MODULE_LICENSE("GPL"); static int nr_ctlr; static ctlr_info_t *hba[MAX_CTLR]; +static devfs_handle_t de_arr[MAX_CTLR][NWD]; static int eisa[8]; @@ -336,6 +338,7 @@ void cleanup_module(void) 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); @@ -486,6 +489,8 @@ int __init cpqarray_init(void) 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]); @@ -1795,6 +1800,14 @@ static void getgeometry(int ctlr) 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 diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 8fcdc77..8b55360 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -58,8 +58,6 @@ inline int bio_rq_in_between(struct bio *bio, struct request *rq, next_rq = list_entry(next, struct request, queuelist); - BUG_ON(next_rq->flags & REQ_STARTED); - /* * not a sector based request */ @@ -147,9 +145,10 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req, */ 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; } @@ -231,6 +230,12 @@ void elevator_linus_add_request(request_queue_t *q, struct request *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)]; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f98c41e..142b4a8 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -818,7 +818,6 @@ int blk_init_queue(request_queue_t *q, request_fn_proc *rfn, spinlock_t *lock) 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); @@ -964,12 +963,6 @@ static inline void add_request(request_queue_t * q, struct request * req, 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 */ @@ -1121,8 +1114,10 @@ again: 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); @@ -1135,8 +1130,10 @@ again: 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); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 49b2e7d..740e5c8 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -206,7 +206,7 @@ struct request *nbd_read_stat(struct nbd_device *lo) 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"); @@ -250,7 +250,7 @@ void nbd_do_it(struct nbd_device *lo) 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)]) { @@ -285,7 +285,7 @@ void nbd_clear_que(struct nbd_device *lo) #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" ); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index f8964bf..6f27a61 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -785,6 +785,9 @@ no_irq: 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); @@ -792,6 +795,7 @@ no_irq: 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"); diff --git a/drivers/md/md.c b/drivers/md/md.c index a02c0fc..3fb9ad1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -641,7 +641,7 @@ static int lock_rdev(mdk_rdev_t *rdev) 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); @@ -3697,7 +3697,7 @@ struct { * 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) @@ -3738,7 +3738,7 @@ static void autostart_arrays(void) } dev_cnt = 0; - autorun_devices(-1); + autorun_devices(to_kdev_t(-1)); } static struct { @@ -3855,14 +3855,14 @@ void __init md_setup_drive(void) *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; } @@ -3872,7 +3872,7 @@ void __init md_setup_drive(void) devname = p; } - devices[i] = 0; + devices[i] = to_kdev_t(0); if (!md_setup_args.device_set[minor]) continue; @@ -3908,7 +3908,10 @@ void __init md_setup_drive(void) 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); @@ -3922,7 +3925,10 @@ void __init md_setup_drive(void) } } 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); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 94d3cbb..792e787 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -274,6 +274,7 @@ static int multipath_make_request (mddev_t *mddev, int rw, 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; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6773bf2..385f263 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -469,6 +469,7 @@ static struct buffer_head *raid5_build_block (struct stripe_head *sh, int i) 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); @@ -1137,6 +1138,7 @@ static void handle_stripe(struct stripe_head *sh) 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); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 9387ad2..bd57c42 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -892,13 +892,13 @@ static void i2ob_request(request_queue_t *q) 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; diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 765d9bd..7c99d9e 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -25,6 +25,7 @@ #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> @@ -569,7 +570,7 @@ static void lance_load_multicast (struct net_device *dev) 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){ @@ -590,21 +591,7 @@ static void lance_load_multicast (struct net_device *dev) 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); } diff --git a/drivers/net/7990.h b/drivers/net/7990.h index 0fb2a48..6875780 100644 --- a/drivers/net/7990.h +++ b/drivers/net/7990.h @@ -132,9 +132,6 @@ struct lance_private 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 */ diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ff5f579..e9f2252 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -55,6 +55,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/ethtool.h> +#include <linux/crc32.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -723,22 +724,6 @@ static int cp_start_xmit (struct sk_buff *skb, 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 __cp_set_rx_mode (struct net_device *dev) { struct cp_private *cp = dev->priv; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 2d219b4..c96bce2 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -109,6 +109,7 @@ #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/completion.h> +#include <linux/crc32.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -587,7 +588,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance, 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); @@ -2371,23 +2371,6 @@ static struct net_device_stats *rtl8139_get_stats (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; diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 6706405..06e0746 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -68,6 +68,7 @@ static const char version[] = #include <linux/in.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/crc32.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -885,27 +886,6 @@ static struct net_device_stats *get_stats(struct net_device *dev) } /* - * 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. */ @@ -916,16 +896,13 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev) 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. diff --git a/drivers/net/Makefile.lib b/drivers/net/Makefile.lib new file mode 100644 index 0000000..af22a0e --- a/dev/null +++ b/drivers/net/Makefile.lib @@ -0,0 +1,69 @@ +# 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 diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index e00dee5..63ed2cbd 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -6,6 +6,7 @@ * Fixes and tips by: * - Janos Farkas (CHEXUM@sparta.banki.hu) * - Jes Degn Soerensen (jds@kom.auc.dk) + * - Matt Domsch (Matt_Domsch@dell.com) * * ---------------------------------------------------------------------------- * @@ -47,6 +48,7 @@ #include <linux/string.h> #include <linux/config.h> #include <linux/init.h> +#include <linux/crc32.h> #include <asm/bitops.h> #include <asm/io.h> @@ -639,7 +641,7 @@ static void lance_load_multicast (struct net_device *dev) 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){ @@ -660,21 +662,7 @@ static void lance_load_multicast (struct net_device *dev) 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); } diff --git a/drivers/net/a2065.h b/drivers/net/a2065.h index f6e4d25..184ad57 100644 --- a/drivers/net/a2065.h +++ b/drivers/net/a2065.h @@ -43,9 +43,6 @@ struct lance_regs { }; -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - /* * Am7990 Control and Status Registers */ diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c index 30840e5..b7bb8f4 100644 --- a/drivers/net/am79c961a.c +++ b/drivers/net/am79c961a.c @@ -29,6 +29,7 @@ #include <linux/skbuff.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/crc32.h> #include <asm/system.h> #include <asm/bitops.h> @@ -308,33 +309,13 @@ static struct net_device_stats *am79c961_getstats (struct net_device *dev) 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; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 5a9ad62..badecbc 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -49,6 +49,7 @@ #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> @@ -804,27 +805,6 @@ net_get_stats(struct net_device *dev) 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) { diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 62d7cea..5a31cfe 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -140,6 +140,7 @@ static int xcvr[NUM_UNITS]; /* The data transfer mode. */ #include <asm/dma.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/crc32.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -857,26 +858,6 @@ net_get_stats(struct net_device *dev) * 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; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 168b9dd..a9a4ac1 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -47,6 +47,7 @@ #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> @@ -1094,22 +1095,6 @@ static void au1000_tx_timeout(struct net_device *dev) 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; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index cf0d30d..e94ccb9 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1053,16 +1053,13 @@ static void bmac_set_multicast(struct net_device *dev) /* 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); @@ -1089,17 +1086,7 @@ static void bmac_set_multicast(struct net_device *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); } diff --git a/drivers/net/bonding.c b/drivers/net/bonding.c index 63e0c1e..e9736dc 100644 --- a/drivers/net/bonding.c +++ b/drivers/net/bonding.c @@ -153,6 +153,14 @@ * * 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> @@ -185,7 +193,6 @@ #include <linux/if_bonding.h> #include <linux/smp.h> -#include <limits.h> #include <linux/if_ether.h> #include <linux/if_arp.h> @@ -257,6 +264,7 @@ static void bond_set_slave_inactive_flags(slave_t *slave); 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); /* @@ -372,10 +380,13 @@ static u16 bond_check_dev_link(struct net_device *dev) 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); } @@ -407,7 +418,6 @@ static int bond_open(struct net_device *dev) 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); @@ -418,13 +428,11 @@ static int bond_close(struct net_device *master) 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; @@ -866,6 +874,49 @@ static int bond_release(struct net_device *master, struct net_device *slave) 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) { @@ -876,14 +927,6 @@ 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 @@ -1057,9 +1100,10 @@ static void bond_mii_monitor(struct net_device *master) } /* 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); @@ -1097,9 +1141,6 @@ static void bond_mii_monitor(struct net_device *master) } } - 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)); @@ -1128,17 +1169,17 @@ static void bond_arp_monitor(struct net_device *master) 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 @@ -1243,7 +1284,9 @@ static void bond_arp_monitor(struct net_device *master) * 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, @@ -1251,11 +1294,14 @@ static void bond_arp_monitor(struct net_device *master) 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 */ @@ -1367,16 +1413,17 @@ static int bond_info_query(struct net_device *master, struct ifbond *info) { 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; } @@ -1387,27 +1434,28 @@ static int bond_slave_info_query(struct net_device *master, 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; } @@ -1480,40 +1528,40 @@ static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) } 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; @@ -1593,13 +1641,11 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) } 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; @@ -1607,8 +1653,6 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) 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--; @@ -1749,6 +1793,7 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) off_t begin = 0; u16 link; slave_t *slave = NULL; + unsigned long flags; while (bond != NULL) { /* @@ -1757,17 +1802,19 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) */ 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: "); @@ -1778,6 +1825,7 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) 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); @@ -1790,6 +1838,7 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) 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 @@ -1803,7 +1852,6 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) len = 0; } - read_unlock(&bond->ptrlock); bond = bond->next_bond; } @@ -1844,7 +1892,14 @@ static int bond_event(struct notifier_block *this, unsigned long event, 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; diff --git a/drivers/net/de2104x.c b/drivers/net/de2104x.c index 45ceb74..2d8145d 100644 --- a/drivers/net/de2104x.c +++ b/drivers/net/de2104x.c @@ -43,6 +43,7 @@ #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> @@ -656,41 +657,6 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) 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) diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 2b5cff2..3af7268 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -436,6 +436,7 @@ '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> ========================================================================= */ @@ -457,6 +458,7 @@ static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.c #include <linux/init.h> #include <linux/version.h> #include <linux/spinlock.h> +#include <linux/crc32.h> #include <asm/bitops.h> #include <asm/io.h> @@ -622,9 +624,6 @@ struct parameters { #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 */ @@ -2050,7 +2049,7 @@ SetMulticastFilter(struct net_device *dev) 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; @@ -2065,13 +2064,7 @@ SetMulticastFilter(struct net_device *dev) 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 */ diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 173e42b..f5c8288 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -79,6 +79,7 @@ static char *lancestr = "LANCE"; #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> @@ -88,9 +89,6 @@ unsigned long dmaptr; #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 @@ -920,7 +918,7 @@ static void lance_load_multicast(struct net_device *dev) 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) { @@ -945,19 +943,7 @@ static void lance_load_multicast(struct net_device *dev) 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); } diff --git a/drivers/net/depca.c b/drivers/net/depca.c index e6f061b..9095f2f 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -228,6 +228,8 @@ 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 ========================================================================= */ @@ -245,6 +247,7 @@ #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> @@ -296,9 +299,6 @@ static int depca_debug = 1; #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 */ @@ -1225,7 +1225,7 @@ static void SetMulticastFilter(struct net_device *dev) 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++) { @@ -1240,13 +1240,7 @@ static void SetMulticastFilter(struct net_device *dev) 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); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 1610757..1c23273 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -75,7 +75,6 @@ static int rio_close (struct net_device *dev); 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); @@ -327,7 +326,7 @@ parse_eeprom (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; @@ -972,23 +971,6 @@ change_mtu (struct net_device *dev, int new_mtu) 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) { @@ -1023,7 +1005,7 @@ 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); diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index fb1a8cd..49ed98d 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -26,6 +26,7 @@ #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> diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index c94409b..4cca074 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -84,6 +84,7 @@ #include <linux/skbuff.h> #include <linux/delay.h> #include <linux/spinlock.h> +#include <linux/crc32.h> #include <asm/processor.h> #include <asm/bitops.h> @@ -288,72 +289,6 @@ static u8 HPNA_NoiseFloor; /* Default: HPNA NoiseFloor */ 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 *); @@ -382,7 +317,7 @@ static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *); 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 *); @@ -1851,18 +1786,11 @@ static u16 phy_read_1bit(unsigned long ioaddr) * 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; } diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 468c675..7c30e77 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -124,6 +124,7 @@ static int rx_copybreak; #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> @@ -1302,27 +1303,6 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev) 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; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 4b93190..dadc8c8 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -132,6 +132,7 @@ <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> ========================================================================= */ @@ -148,6 +149,7 @@ #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> @@ -207,9 +209,6 @@ static int ewrk3_debug = 1; #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 */ /* @@ -1174,10 +1173,10 @@ static void SetMulticastFilter(struct net_device *dev) 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); @@ -1219,13 +1218,7 @@ static void SetMulticastFilter(struct net_device *dev) 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 */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e63a3c54..e35d85f 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -72,6 +72,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #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> @@ -426,7 +427,6 @@ static void init_ring(struct net_device *dev); 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); @@ -1711,26 +1711,6 @@ 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 void set_rx_mode(struct net_device *dev) { struct netdev_private *np = dev->priv; diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c index 8d3e0b2..1406a5e 100644 --- a/drivers/net/gmac.c +++ b/drivers/net/gmac.c @@ -16,6 +16,8 @@ * - 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> @@ -33,6 +35,7 @@ #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> @@ -997,14 +1000,13 @@ gmac_stop_dma(struct gmac *gm) * 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; @@ -1027,17 +1029,7 @@ gmac_set_multicast(struct net_device *dev) 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; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index dc1667b..1a3e62e 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -33,6 +33,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/crc32.h> #ifdef CONFIG_SERIAL #include <linux/serial.h> @@ -1611,27 +1612,16 @@ static void ioc3_timeout(struct net_device *dev) * 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; ) { diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 04ca3c7..7704924 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -15,6 +15,7 @@ #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> @@ -508,17 +509,12 @@ static struct net_device_stats *mace_stats(struct net_device *dev) 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) { @@ -534,17 +530,7 @@ static void mace_set_multicast(struct net_device *dev) 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; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 099b1fc..9f792a4 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -19,6 +19,7 @@ #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> @@ -539,17 +540,12 @@ static struct net_device_stats *mace68k_stats(struct net_device *dev) 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) @@ -570,19 +566,7 @@ static void mace68k_set_multicast(struct net_device *dev) 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; diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h index 18e2642a..851eba8 100644 --- a/drivers/net/myri_code.h +++ b/drivers/net/myri_code.h @@ -6284,4 +6284,4 @@ static unsigned char lanai4_data[20472] __initdata = { #define MYRI_NetReceiveBadCrcs 0xB8D4 #define MYRI_NetReceiveBytes 0xB8DC -#endif SYMBOL_DEFINES_COMPILED +#endif /* SYMBOL_DEFINES_COMPILED */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 4ea8280..09b2d04 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -800,9 +800,6 @@ static int myri_change_mtu(struct net_device *dev, int new_mtu) 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 diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 7d01a2c..a94d694 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -102,6 +102,9 @@ 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 @@ -110,7 +113,7 @@ #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. */ @@ -1706,36 +1709,15 @@ static struct net_device_stats *get_stats(struct net_device *dev) 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; @@ -1759,7 +1741,7 @@ static unsigned ether_crc_le(int length, unsigned char *data) return (crc); } -#endif + void set_bit_le(int offset, unsigned char * data) { @@ -1788,7 +1770,7 @@ static void __set_rx_mode(struct net_device *dev) 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 diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index e94d6c3..6743227 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -96,6 +96,7 @@ IVc. Errata #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" @@ -509,7 +510,6 @@ static void netdrv_interrupt (int irq, void *dev_instance, 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); @@ -1853,27 +1853,6 @@ static struct net_device_stats *netdrv_get_stats (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; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 3816934..6c47c37 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -47,6 +47,7 @@ #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> @@ -1181,27 +1182,6 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev) 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; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index f1c322b..44c218c 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -34,6 +34,7 @@ #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/crc32.h> #include <asm/io.h> #include <asm/system.h> @@ -1740,31 +1741,6 @@ static struct net_device_stats *smc91c92_get_stats(struct net_device *dev) 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; -} /*====================================================================== diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index e7fe6ae..578af8d 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -101,6 +101,7 @@ static int csr0 = 0x00A00000 | 0x4800; #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. */ @@ -1518,43 +1519,6 @@ static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 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 diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 4ad12ac..25b86ec 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -36,6 +36,7 @@ static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken #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> @@ -215,8 +216,6 @@ static int full_duplex[MAX_UNITS]; #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; @@ -1425,8 +1424,8 @@ static void pcnet32_load_multicast (struct net_device *dev) 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){ @@ -1447,19 +1446,7 @@ static void pcnet32_load_multicast (struct net_device *dev) 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); } diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 9e1e2e3..3ff3c5f 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -737,6 +737,11 @@ static int __init shaper_init(void) static void __exit shaper_exit (void) { + int i; + + for (i = 0; i < shapers; i++) + unregister_netdev(&devs[i]); + kfree(devs); devs = NULL; } diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index e6140c6..6724c74 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1,6 +1,6 @@ /* 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. @@ -18,6 +18,7 @@ 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 @@ -62,11 +63,12 @@ #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; @@ -1928,26 +1930,7 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map) 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)) diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h index 7a7c953..4f8e308 100644 --- a/drivers/net/sk98lin/h/skdrv1st.h +++ b/drivers/net/sk98lin/h/skdrv1st.h @@ -116,6 +116,7 @@ typedef struct s_AC SK_AC; #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> diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c index b7381fe..ca223be 100644 --- a/drivers/net/sk98lin/skaddr.c +++ b/drivers/net/sk98lin/skaddr.c @@ -199,7 +199,6 @@ extern "C" { /* defines ********************************************************************/ -#define CRC32_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */ #define HASH_BITS 6 /* #bits in hash */ #define SK_MC_BIT 0x01 @@ -534,18 +533,9 @@ int Flags) /* permanent/non-perm, sw-only */ 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 */ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index c40f7dc..07337b7 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -51,6 +51,7 @@ . 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[] = @@ -69,6 +70,7 @@ 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> @@ -223,10 +225,6 @@ static struct net_device_stats * smc_query_statistics( struct net_device *dev); */ static void smc_set_multicast_list(struct net_device *dev); -/* - . CRC compute - */ -static int crc32( char * s, int length ); /*--------------------------------------------------------------- . @@ -436,7 +434,7 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs 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]] |= @@ -452,33 +450,6 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs } /* - 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: . Attempt to allocate memory for a packet, if chip-memory is not diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 0fec2bc..3d17fd6 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -109,6 +109,7 @@ TODO: #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> @@ -1612,32 +1613,9 @@ static struct net_device_stats *get_stats(struct net_device *dev) } -/* 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) { diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 0170283..1555eac 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -18,6 +18,7 @@ #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> @@ -979,9 +980,6 @@ static struct net_device_stats *bigmac_get_stats(struct net_device *dev) 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; @@ -989,7 +987,7 @@ static void bigmac_set_multicast(struct net_device *dev) 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. @@ -1022,17 +1020,7 @@ static void bigmac_set_multicast(struct net_device *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); } diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index ab376ff..c55a85e 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -98,6 +98,7 @@ static char *media[MAX_UNITS]; #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> @@ -1262,32 +1263,6 @@ static struct net_device_stats *get_stats(struct net_device *dev) 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; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 88ca377..bf06abc 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1,7 +1,15 @@ -/* $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> @@ -23,11 +31,16 @@ #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> @@ -45,15 +58,33 @@ #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 ": " @@ -73,7 +104,7 @@ static struct pci_device_id gem_pci_tbl[] __devinitdata = { * 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 }, @@ -362,10 +393,6 @@ static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta 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 @@ -418,9 +445,9 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat 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; } @@ -627,6 +654,10 @@ static void gem_tx_timeout(struct net_device *dev) 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), @@ -640,13 +671,19 @@ static void gem_tx_timeout(struct net_device *dev) 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) @@ -690,15 +727,22 @@ 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. */ @@ -727,11 +771,15 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) 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; @@ -761,18 +809,19 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) 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; @@ -781,13 +830,13 @@ static void gem_stop(struct gem *gp, unsigned long regs) 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)); @@ -810,6 +859,9 @@ static void gem_start_dma(struct gem *gp) 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); @@ -828,6 +880,88 @@ static int phy_BCM5400_link_table[8][3] = { { 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. */ @@ -842,32 +976,13 @@ static void gem_set_link_modes(struct gem *gp) 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 { @@ -944,56 +1059,142 @@ static void gem_set_link_modes(struct gem *gp) 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); @@ -1001,17 +1202,17 @@ static void gem_link_timer(unsigned long data) 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) @@ -1108,66 +1309,72 @@ static void gem_init_rings(struct gem *gp, int from_irq) } } -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 @@ -1191,22 +1398,21 @@ gem_init_bcm5401_phy(struct gem *gp) } /* 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; @@ -1220,20 +1426,30 @@ gem_init_bcm5411_phy(struct gem *gp) /* 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; @@ -1241,7 +1457,7 @@ static void gem_init_phy(struct gem *gp) 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) { @@ -1277,54 +1493,68 @@ static void gem_init_phy(struct gem *gp) /* 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; @@ -1379,6 +1609,7 @@ static void gem_init_phy(struct gem *gp) else val |= PCS_SCTRL_LOOP; writel(val, gp->regs + PCS_SCTRL); + gp->gigabit_capable = 1; } } @@ -1392,7 +1623,7 @@ static void gem_init_dma(struct gem *gp) 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); @@ -1410,17 +1641,15 @@ static void gem_init_dma(struct gem *gp) 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]; @@ -1484,9 +1713,9 @@ static void gem_init_mac(struct gem *gp) 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; @@ -1499,17 +1728,7 @@ static void gem_init_mac(struct gem *gp) 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); } @@ -1551,18 +1770,20 @@ static void gem_init_mac(struct gem *gp) 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 @@ -1580,11 +1801,7 @@ gem_init_pause_thresholds(struct gem* gp) } { - 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); @@ -1598,21 +1815,15 @@ static int gem_check_invariants(struct gem *gp) 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; } @@ -1651,7 +1862,7 @@ static int gem_check_invariants(struct gem *gp) 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) { @@ -1685,12 +1896,10 @@ static int gem_check_invariants(struct gem *gp) } } - 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 @@ -1698,18 +1907,28 @@ static void gem_init_hw(struct gem *gp) * 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 @@ -1717,10 +1936,10 @@ static void gem_init_hw(struct gem *gp) * 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); @@ -1731,31 +1950,162 @@ gem_apple_powerup(struct gem* gp) 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 @@ -1763,9 +2113,14 @@ static int gem_open(struct net_device *dev) 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; } @@ -1773,7 +2128,11 @@ static int gem_open(struct net_device *dev) 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; } @@ -1782,17 +2141,110 @@ static int gem_close(struct net_device *dev) { 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) { @@ -1861,9 +2313,9 @@ static void gem_set_multicast(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; @@ -1876,17 +2328,7 @@ static void gem_set_multicast(struct net_device *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 >>= 24; hash_table[crc >> 4] |= 1 << (crc & 0xf); } @@ -1908,12 +2350,219 @@ static void gem_set_multicast(struct net_device *dev) 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) @@ -2030,6 +2679,26 @@ static int __devinit gem_init_one(struct pci_dev *pdev, 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) { @@ -2038,9 +2707,26 @@ static int __devinit gem_init_one(struct pci_dev *pdev, 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; @@ -2074,10 +2760,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, 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; @@ -2095,9 +2777,20 @@ static int __devinit gem_init_one(struct pci_dev *pdev, 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: @@ -2120,6 +2813,14 @@ static void __devexit gem_remove_one(struct pci_dev *pdev) 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, @@ -2127,9 +2828,6 @@ static void __devexit gem_remove_one(struct pci_dev *pdev) 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); @@ -2140,7 +2838,11 @@ static struct pci_driver gem_driver = { 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) diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index a4a63f2..ec136a8 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -1,4 +1,4 @@ -/* $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) @@ -753,64 +753,38 @@ #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. @@ -936,9 +910,21 @@ struct gem_rxd { #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 { @@ -958,9 +944,12 @@ enum gem_phy_model { }; 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 { @@ -973,6 +962,10 @@ 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; @@ -988,15 +981,23 @@ struct gem { 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; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 2affbd1..25778dc 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -33,6 +33,7 @@ static char version[] = #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> @@ -1469,9 +1470,6 @@ force_link: 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; @@ -1583,8 +1581,8 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) 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; @@ -1596,17 +1594,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) 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); } @@ -2385,8 +2373,8 @@ static void happy_meal_set_multicast(struct net_device *dev) 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); @@ -2412,17 +2400,7 @@ static void happy_meal_set_multicast(struct net_device *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); } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 2f9cc0d..c42003b 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -62,12 +62,15 @@ * 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"; @@ -86,6 +89,7 @@ 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> @@ -115,9 +119,6 @@ static char lancestr[] = "LANCE"; #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 @@ -1181,7 +1182,7 @@ static void lance_load_multicast(struct net_device *dev) 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) { @@ -1211,19 +1212,7 @@ static void lance_load_multicast(struct net_device *dev) /* 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]); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 30f06d1..7ddedce 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1,4 +1,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 @@ -24,6 +24,7 @@ static char version[] = #include <linux/string.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/crc32.h> #include <asm/system.h> #include <asm/bitops.h> @@ -494,6 +495,7 @@ static void qec_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock(&qep->lock); } next: + ; } qec_status >>= 4; channel++; @@ -621,9 +623,6 @@ static struct net_device_stats *qe_get_stats(struct net_device *dev) 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; @@ -631,7 +630,7 @@ static void qe_set_multicast(struct net_device *dev) 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); @@ -659,18 +658,7 @@ static void qe_set_multicast(struct net_device *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); } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 917f1a9..b396f5b 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -27,6 +27,7 @@ #include <linux/delay.h> #include <linux/mii.h> #include <linux/ethtool.h> +#include <linux/crc32.h> #include <asm/unaligned.h> #include <asm/uaccess.h> @@ -968,41 +969,6 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) 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) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 2e753ad..0aed62e 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -151,6 +151,7 @@ static const int multicast_filter_limit = 32; #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> @@ -1519,26 +1520,6 @@ static inline void clear_tally_counters(const long ioaddr) 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; diff --git a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c index f81fc20..92e1880 100644 --- a/drivers/net/winbond-840.c +++ b/drivers/net/winbond-840.c @@ -136,6 +136,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #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> @@ -389,7 +390,6 @@ 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 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); @@ -1407,21 +1407,6 @@ 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) { diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index e169ad5..e56ab05 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -125,6 +125,7 @@ static int gx_fix; #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> @@ -1339,29 +1340,6 @@ static struct net_device_stats *yellowfin_get_stats(struct net_device *dev) /* 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; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index f1deb2a..bb14996 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -115,7 +115,7 @@ do { \ 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 ) diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index d6715d1..064a5cc 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -771,7 +771,7 @@ void xpram_request(request_queue_t * queue) 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 */ diff --git a/drivers/s390/char/tapedefs.h b/drivers/s390/char/tapedefs.h index fa714c2..8506921 100644 --- a/drivers/s390/char/tapedefs.h +++ b/drivers/s390/char/tapedefs.h @@ -41,7 +41,7 @@ do { \ 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 ) diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c index cbf93b3..1ee7f17 100644 --- a/drivers/sbus/audio/audio.c +++ b/drivers/sbus/audio/audio.c @@ -1,4 +1,4 @@ -/* $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) @@ -202,7 +202,7 @@ static unsigned int sparcaudio_poll(struct file *file, poll_table * wait) { 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); @@ -221,7 +221,7 @@ static ssize_t sparcaudio_read(struct file * file, char *buf, 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; @@ -296,7 +296,7 @@ static ssize_t sparcaudio_write(struct file * file, const char *buf, 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; @@ -396,7 +396,7 @@ static ssize_t sparcaudio_write(struct file * file, const char *buf, 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; @@ -647,7 +647,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, 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; @@ -1701,7 +1701,7 @@ static struct file_operations sparcaudioctl_fops = { 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; @@ -1835,7 +1835,7 @@ static int sparcaudio_open(struct inode * inode, struct file * file) 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(); diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index 38b53ee..86b08d5 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -1,4 +1,4 @@ -/* $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) @@ -1427,7 +1427,7 @@ static int aurora_open(struct tty_struct * tty, struct file * filp) 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 @@ -1438,7 +1438,7 @@ static int aurora_open(struct tty_struct * tty, struct file * filp) } 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"); diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index f5ed491..fdc9936 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -297,7 +297,7 @@ static inline int wd_opt_timeout(void) 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]; diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index ea2430e..cebf4df 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -1,4 +1,4 @@ -/* $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 @@ -89,7 +89,7 @@ static inline int d7s_obpflipped(void) 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; @@ -98,7 +98,7 @@ static int d7s_open(struct inode *inode, struct file *f) 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; @@ -125,7 +125,7 @@ static int d7s_ioctl(struct inode *inode, struct file *f, __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) { diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index fec4c3e..99fe2b4 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $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) @@ -1913,7 +1913,7 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) 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; @@ -2200,7 +2200,7 @@ static void __init sab82532_kgdb_hook(int line) static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.65 $"; + char *revision = "$Revision: 1.66 $"; char *version, *p; version = strchr(revision, ' '); @@ -2540,7 +2540,7 @@ sab82532_console_write(struct console *con, const char *s, unsigned n) 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 diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c index ac0a1c4..acdabc8 100644 --- a/drivers/sbus/char/su.c +++ b/drivers/sbus/char/su.c @@ -1,4 +1,4 @@ -/* $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) @@ -2061,7 +2061,7 @@ su_open(struct tty_struct *tty, struct file * filp) 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; @@ -2252,7 +2252,7 @@ done: */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.54 $"; + char *revision = "$Revision: 1.55 $"; char *version, *p; version = strchr(revision, ' '); @@ -2857,7 +2857,7 @@ serial_console_write(struct console *co, const char *s, static kdev_t serial_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, 64 + c->index); + return mk_kdev(TTY_MAJOR, 64 + c->index); } /* diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c index 5ac8a93..6ee3b00 100644 --- a/drivers/sbus/char/sunserial.c +++ b/drivers/sbus/char/sunserial.c @@ -1,4 +1,4 @@ -/* $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) diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index e9562c2..a31e963 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $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) @@ -224,7 +224,7 @@ static unsigned char *tmp_buf = 0; 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 = @@ -233,11 +233,11 @@ static inline int serial_paranoia_check(struct sun_serial *info, "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 @@ -486,10 +486,19 @@ extern void breakpoint(void); /* For the KGDB frame character */ 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; @@ -498,17 +507,17 @@ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) /* 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... */ @@ -517,16 +526,14 @@ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) 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... */ @@ -538,32 +545,42 @@ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) * 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); @@ -580,7 +597,7 @@ static void transmit_chars(struct sun_serial *info) 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(); @@ -597,7 +614,7 @@ static void transmit_chars(struct sun_serial *info) 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); @@ -619,14 +636,14 @@ static void status_handle(struct sun_serial *info) 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]); } @@ -636,7 +653,7 @@ static void status_handle(struct sun_serial *info) * '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) @@ -649,110 +666,49 @@ static void status_handle(struct sun_serial *info) 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; } } @@ -1847,7 +1803,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) 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. @@ -1931,7 +1887,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.68 $"; + char *revision = "$Revision: 1.70 $"; char *version, *p; version = strchr(revision, ' '); @@ -2467,8 +2423,7 @@ int __init zs_init(void) /* 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(); @@ -2761,7 +2716,7 @@ zs_console_write(struct console *con, const char *s, unsigned count) 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) diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 96bba64..c64a090 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -1,4 +1,4 @@ -/* $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) @@ -231,6 +231,7 @@ static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, 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; } } diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 85a9121..9835bfc 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -8392,8 +8392,8 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen) 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, @@ -9411,9 +9411,8 @@ asc_prt_scsi_host(struct Scsi_Host *s) 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); diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c index 6242554..e656d4d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_linux.c +++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c @@ -130,6 +130,7 @@ #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 diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index a6036dd..f008205 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -713,20 +713,20 @@ static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags); 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 @@ -741,7 +741,7 @@ ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags) 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 @@ -749,7 +749,7 @@ ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags) { 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) */ diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 23113ae..ebbd33c 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -5,7 +5,6 @@ * */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/config.h> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index aa0fd64..e276376 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -24,7 +24,6 @@ * hosts currently present in the system. */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/blk.h> #include <linux/kernel.h> @@ -55,13 +54,6 @@ static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v * 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 @@ -157,17 +149,14 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j) 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) { @@ -181,7 +170,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j) 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) diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index 3246ba6..8604eb3 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -312,7 +312,8 @@ struct Scsi_Host 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 @@ -329,7 +330,6 @@ struct Scsi_Host 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; @@ -386,10 +386,6 @@ struct Scsi_Host 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. @@ -451,7 +447,6 @@ typedef struct SHN 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; @@ -471,10 +466,14 @@ extern int next_scsi_host; 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) { diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 3bb3bef..1c47f9c 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -292,9 +292,9 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup) } } 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; @@ -805,9 +805,9 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) 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); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b3257fc4..554dc6b4 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -75,8 +75,6 @@ #include <linux/kmod.h> #endif -#undef USE_STATIC_SCSI_MEMORY - struct proc_dir_entry *proc_scsi; #ifdef CONFIG_PROC_FS @@ -195,16 +193,23 @@ void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) { 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); } @@ -647,7 +652,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) 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) @@ -698,9 +703,9 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) * 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); @@ -711,20 +716,20 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) 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(); @@ -732,10 +737,10 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) } 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; @@ -805,7 +810,7 @@ void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd, 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, { @@ -902,7 +907,7 @@ void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt) { 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; @@ -992,7 +997,7 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd, { 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; @@ -1346,7 +1351,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt) 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 @@ -1355,10 +1360,10 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt) * 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 @@ -1512,7 +1517,6 @@ void __init scsi_host_no_insert(char *str, int n) 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) @@ -1968,12 +1972,6 @@ int scsi_register_host(Scsi_Host_Template * tpnt) } } } -#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?? */ @@ -2163,13 +2161,6 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt) 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) @@ -2406,35 +2397,6 @@ static void scsi_dump_status(int level) } } } - - 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 */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index b689464..57596d9 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -8,7 +8,6 @@ * */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/sched.h> @@ -583,7 +582,7 @@ STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout) unsigned long flags; struct Scsi_Host *host = SCpnt->host; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); retry: /* @@ -605,9 +604,9 @@ 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); @@ -630,10 +629,10 @@ retry: * 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; @@ -650,9 +649,9 @@ retry: * 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. */ @@ -772,9 +771,9 @@ STATIC int scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout) 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; } @@ -804,9 +803,9 @@ STATIC int scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout) } 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; @@ -837,9 +836,9 @@ STATIC int scsi_try_bus_reset(Scsi_Cmnd * SCpnt) 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; @@ -883,9 +882,9 @@ STATIC int scsi_try_host_reset(Scsi_Cmnd * SCpnt) 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; @@ -1226,7 +1225,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host) 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 @@ -1243,7 +1242,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host) * 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; @@ -1256,7 +1255,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host) q->request_fn(q); } - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } /* @@ -1303,7 +1302,7 @@ STATIC int scsi_unjam_host(struct Scsi_Host *host) Scsi_Cmnd *SCdone; int timed_out; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); SCdone = NULL; @@ -1844,11 +1843,7 @@ void scsi_error_handler(void *data) * 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(); @@ -1894,10 +1889,8 @@ void scsi_error_handler(void *data) * 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")); diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index f64d200..b99553c 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -4,7 +4,6 @@ * - 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> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 4e8745f..b23f616 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -17,7 +17,6 @@ * go through and retrofit queueing functions into all 30 some-odd drivers. */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/sched.h> @@ -365,7 +364,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, * 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; @@ -444,7 +443,7 @@ static void scsi_release_buffers(Scsi_Cmnd * 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. diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c index 3368906..807ecbc 100644 --- a/drivers/scsi/scsi_merge.c +++ b/drivers/scsi/scsi_merge.c @@ -15,7 +15,6 @@ * be handled all at once by a host adapter. */ -#define __NO_VERSION__ #include <linux/config.h> #include <linux/module.h> diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 01d6679..2f7e4ad 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -17,7 +17,6 @@ */ #include <linux/config.h> /* for CONFIG_PROC_FS */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/string.h> diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c index 1d9a90b..40d2ad5 100644 --- a/drivers/scsi/scsi_queue.c +++ b/drivers/scsi/scsi_queue.c @@ -10,7 +10,6 @@ * we attempt to remove commands from the queue and retry them. */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/sched.h> @@ -137,10 +136,10 @@ int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) * 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. diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index aede1a6..8f4d70c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -8,7 +8,6 @@ * clearer. */ -#define __NO_VERSION__ #include <linux/config.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index 8f511d1..e363fac 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -2,7 +2,6 @@ * 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> diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index e8f8c90..3582d44 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -10,7 +10,6 @@ * For more information, please consult the SCSI-CAM draft. */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/fs.h> diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index bc030dc..f22d141 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -643,9 +643,9 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; #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 diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index d8c43a9..10e68e0 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -138,11 +138,11 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; #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 diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index aabd8ad..19169b4 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -187,6 +187,7 @@ #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 @@ -2555,7 +2556,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm 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; @@ -3750,7 +3751,7 @@ static int ali_write_proc(struct file *file, const char *buffer, unsigned long c 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) @@ -3948,13 +3949,20 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device 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); diff --git a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c index 25cf21c..d426b7d 100644 --- a/drivers/sound/ymfpci.c +++ b/drivers/sound/ymfpci.c @@ -1,6 +1,8 @@ /* * 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. * @@ -37,8 +39,16 @@ * - 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> @@ -155,7 +165,7 @@ static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched) 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; } @@ -173,19 +183,19 @@ static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val) 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); } /* @@ -279,18 +289,22 @@ static void ymf_pcm_update_shift(struct ymf_pcm_format *f) #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; @@ -301,6 +315,7 @@ static int alloc_dmabuf(struct ymf_dmabuf *dmabuf) 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 */ @@ -311,8 +326,10 @@ static int alloc_dmabuf(struct ymf_dmabuf *dmabuf) 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; @@ -321,7 +338,9 @@ static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf) 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; @@ -347,7 +366,7 @@ static int prog_dmabuf(struct ymf_state *state, int rec) /* allocate DMA buffer if not allocated yet */ if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(dmabuf))) + if ((ret = alloc_dmabuf(state->unit, dmabuf))) return ret; /* @@ -404,7 +423,7 @@ static int prog_dmabuf(struct ymf_state *state, int rec) 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); @@ -587,7 +606,8 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) 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. */ @@ -595,7 +615,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) 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", @@ -615,7 +635,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) 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); } @@ -633,7 +653,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) /* * 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); @@ -641,10 +661,10 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) /* * 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) { @@ -698,7 +718,7 @@ static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap) 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", @@ -742,9 +762,11 @@ static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd) 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; @@ -810,6 +832,7 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo, 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) @@ -818,24 +841,24 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int 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; @@ -855,31 +878,31 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo, 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; } } } @@ -920,7 +943,7 @@ static int ymf_playback_prepare(struct ymf_state *state) 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; @@ -969,9 +992,9 @@ static int ymf_capture_prepare(struct ymf_state *state) } 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; } @@ -1442,13 +1465,14 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) { 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) { @@ -1457,12 +1481,21 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) 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; } } @@ -1497,6 +1530,7 @@ static int ymf_mmap(struct file *file, struct vm_area_struct *vma) return -EAGAIN; dmabuf->mapped = 1; +/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n"); return 0; } @@ -1508,13 +1542,16 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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; @@ -1536,6 +1573,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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) { @@ -1554,6 +1592,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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); @@ -1585,6 +1624,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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; @@ -1606,24 +1646,31 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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); @@ -1649,6 +1696,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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); @@ -1676,6 +1724,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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 @@ -1697,6 +1746,10 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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; @@ -1707,20 +1760,25 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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; @@ -1735,15 +1793,18 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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; @@ -1751,13 +1812,13 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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; @@ -1765,22 +1826,25 @@ static int ymf_ioctl(struct inode *inode, struct file *file, 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: @@ -1796,6 +1860,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, * 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; @@ -1866,8 +1931,8 @@ static int ymf_open(struct inode *inode, struct file *file) } #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); @@ -1880,8 +1945,8 @@ out_nodma: * 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); @@ -1895,13 +1960,13 @@ out_nodma: 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. @@ -1909,8 +1974,8 @@ static int ymf_release(struct inode *inode, struct file *file) */ 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); @@ -1918,7 +1983,7 @@ static int ymf_release(struct inode *inode, struct file *file) file->private_data = NULL; /* Can you tell I programmed Solaris */ kfree(state); - up(&codec->open_sem); + up(&unit->open_sem); return 0; } @@ -1928,10 +1993,10 @@ static int ymf_release(struct inode *inode, struct file *file) */ 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); @@ -1988,23 +2053,21 @@ static /*const*/ struct file_operations ymf_mixer_fops = { 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) { @@ -2031,12 +2094,12 @@ static int ymf_suspend(struct pci_dev *pcidev, u32 unused) 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. */ @@ -2057,10 +2120,8 @@ static int ymf_resume(struct pci_dev *pcidev) } 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; @@ -2160,12 +2221,15 @@ static void ymfpci_aclink_reset(struct pci_dev * pci) { 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); } @@ -2241,29 +2305,39 @@ static void ymfpci_download_image(ymfpci_t *codec) 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, @@ -2271,34 +2345,49 @@ static int ymfpci_memalloc(ymfpci_t *codec) */ 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; } @@ -2310,16 +2399,17 @@ static void ymfpci_memfree(ymfpci_t *codec) 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 */ @@ -2357,7 +2447,7 @@ static int ymf_ac97_init(ymfpci_t *unit, int num_ac97) 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; } @@ -2398,6 +2488,7 @@ static int assigned; 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; @@ -2406,6 +2497,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi 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"); @@ -2420,16 +2512,21 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi 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) @@ -2459,8 +2556,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi /* 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; } @@ -2478,7 +2574,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi 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)) { @@ -2506,6 +2602,8 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi 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; @@ -2529,6 +2627,7 @@ static void __devexit ymf_remove_one(struct pci_dev *pcidev) 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); diff --git a/drivers/sound/ymfpci.h b/drivers/sound/ymfpci.h index 1686f204..9ecf6b2 100644 --- a/drivers/sound/ymfpci.h +++ b/drivers/sound/ymfpci.h @@ -227,6 +227,7 @@ struct ymf_voice { char use, pcm, synth, midi; // bool ymfpci_playback_bank_t *bank; struct ymf_pcm *ypcm; + dma_addr_t bank_ba; }; struct ymf_capture { @@ -239,19 +240,17 @@ 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]; @@ -286,10 +285,11 @@ struct ymf_unit { }; struct ymf_dmabuf { - - /* OSS buffer management stuff */ + dma_addr_t dma_addr; void *rawbuf; unsigned buforder; + + /* OSS buffer management stuff */ unsigned numfrag; unsigned fragshift; diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c index 0380ee2..c8eb8d1 100644 --- a/drivers/telephony/phonedev.c +++ b/drivers/telephony/phonedev.c @@ -46,7 +46,7 @@ static DECLARE_MUTEX(phone_lock); 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; diff --git a/drivers/usb/Makefile.lib b/drivers/usb/Makefile.lib new file mode 100644 index 0000000..891c918 --- a/dev/null +++ b/drivers/usb/Makefile.lib @@ -0,0 +1 @@ +obj-$(CONFIG_USB_CATC) += crc32.o diff --git a/drivers/usb/catc.c b/drivers/usb/catc.c index 856fb1c..cc14861 100644 --- a/drivers/usb/catc.c +++ b/drivers/usb/catc.c @@ -39,6 +39,7 @@ #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/ethtool.h> +#include <linux/crc32.h> #include <asm/bitops.h> #include <asm/uaccess.h> @@ -531,13 +532,9 @@ static struct net_device_stats *catc_get_stats(struct net_device *netdev) 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); } diff --git a/drivers/usb/hcd.c b/drivers/usb/hcd.c index f9e9765..8d4799a 100644 --- a/drivers/usb/hcd.c +++ b/drivers/usb/hcd.c @@ -624,7 +624,7 @@ clean_2: #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) { diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c index 83a3321..41b8f3f 100644 --- a/drivers/usb/hcd/ehci-hcd.c +++ b/drivers/usb/hcd/ehci-hcd.c @@ -743,7 +743,7 @@ MODULE_LICENSE ("GPL"); 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)); diff --git a/drivers/usb/hcd/ehci-sched.c b/drivers/usb/hcd/ehci-sched.c index 905e506..5a971fe 100644 --- a/drivers/usb/hcd/ehci-sched.c +++ b/drivers/usb/hcd/ehci-sched.c @@ -381,7 +381,7 @@ static int intr_submit ( 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 (); diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index 37baf66..1252d73 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -326,7 +326,7 @@ static void name(struct vc_data *conp, struct display *p, args) \ 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, \ diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c index 34ee6dd..63d3b3f 100644 --- a/drivers/video/sbusfb.c +++ b/drivers/video/sbusfb.c @@ -1019,7 +1019,7 @@ sizechange: 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); diff --git a/fs/Makefile.lib b/fs/Makefile.lib new file mode 100644 index 0000000..0ca1cff --- a/dev/null +++ b/fs/Makefile.lib @@ -0,0 +1,2 @@ +obj-$(CONFIG_FS_JFFS2) += crc32.o +obj-$(CONFIG_EFI_PARTITION) += crc32.o diff --git a/fs/affs/file.c b/fs/affs/file.c index a09a450..6a36022 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -401,6 +401,7 @@ err_ext: 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; diff --git a/fs/block_dev.c b/fs/block_dev.c index 672bd95..4f34a8c 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -128,6 +128,7 @@ static int blkdev_get_block(struct inode * inode, sector_t iblock, struct buffer 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; diff --git a/fs/buffer.c b/fs/buffer.c index b55ac6a..8a9233a 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -83,7 +83,7 @@ static int nr_unused_buffer_heads; 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. */ @@ -557,9 +557,9 @@ static void remove_from_queues(struct buffer_head *bh) 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); @@ -572,7 +572,7 @@ struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size) continue; if (bh->b_size != size) continue; - if (!kdev_same(bh->b_dev, dev)) + if (bh->b_bdev != bdev) continue; get_bh(bh); break; @@ -1024,15 +1024,14 @@ void invalidate_inode_buffers(struct inode *inode) */ 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(); } } @@ -1202,6 +1201,7 @@ static void __put_unused_buffer_head(struct buffer_head * bh) 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; @@ -1305,6 +1305,7 @@ try_again: goto no_grow; bh->b_dev = NODEV; + bh->b_bdev = NULL; bh->b_this_page = head; head = bh; @@ -1366,6 +1367,7 @@ static void discard_buffer(struct buffer_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); @@ -1487,7 +1489,7 @@ static void unmap_underlying_metadata(struct buffer_head * bh) { 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); @@ -2119,7 +2121,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], kdev_t dev, sector_t b[], * 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; @@ -2134,7 +2136,8 @@ int brw_page(int rw, struct page *page, kdev_t dev, sector_t b[], int size) 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; @@ -2234,7 +2237,7 @@ failed: 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; @@ -2248,7 +2251,8 @@ static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size 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; } @@ -2267,15 +2271,14 @@ static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size * 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) @@ -2289,22 +2292,14 @@ static int grow_buffers(kdev_t dev, unsigned long block, int 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); diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 8dc0020..3918709 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -151,8 +151,8 @@ static struct super_block * coda_read_super(struct super_block *sb, 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; diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 92ce22a..861a877 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -81,7 +81,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp, } 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 ) { diff --git a/fs/dcache.c b/fs/dcache.c index d4379a0..7246506 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1262,7 +1262,7 @@ void __init vfs_caches_init(unsigned long mempages) 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"); diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 639ae74..19c4066 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -601,6 +601,9 @@ 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> @@ -633,7 +636,7 @@ #include <asm/bitops.h> #include <asm/atomic.h> -#define DEVFS_VERSION "1.8 (20011226)" +#define DEVFS_VERSION "1.9 (20020113)" #define DEVFS_NAME "devfs" @@ -894,8 +897,8 @@ void devfs_put (devfs_handle_t de) { 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 @@ -1552,7 +1555,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, 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"); @@ -1564,14 +1567,14 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, 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) ) { @@ -1601,7 +1604,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, { 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", @@ -2378,7 +2381,7 @@ EXPORT_SYMBOL(devfs_unregister_blkdev); * @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, @@ -2397,7 +2400,7 @@ 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 */ @@ -2413,7 +2416,7 @@ static int check_disc_changed (struct devfs_entry *de) { 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; @@ -2599,15 +2602,15 @@ static struct inode *_devfs_get_vfs_inode (struct super_block *sb, 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) @@ -2861,34 +2864,55 @@ static int devfs_d_delete (struct dentry *dentry) 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 */ @@ -2897,9 +2921,12 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) 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 */ @@ -2921,60 +2948,61 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) 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) diff --git a/fs/devpts/root.c b/fs/devpts/root.c index dd69670..e93c335 100644 --- a/fs/devpts/root.c +++ b/fs/devpts/root.c @@ -101,7 +101,6 @@ static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * den 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' ) { @@ -127,11 +126,10 @@ static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * den 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; } diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c index 1a37b22..c8d9f41 100644 --- a/fs/driverfs/inode.c +++ b/fs/driverfs/inode.c @@ -374,7 +374,7 @@ static int driverfs_d_delete_file (struct dentry * dentry) entry = (struct driver_file_entry *)dentry->d_fsdata; if (entry) - kfree(dentry); + kfree(entry); return 0; } diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 540d9df..a376239 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -189,7 +189,7 @@ static void list_cache(void) 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("-- "); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index e6daf9d..904a5b2 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -407,7 +407,7 @@ static void fat_read_root(struct inode *inode) } 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; @@ -949,7 +949,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) /* 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 = @@ -1082,7 +1082,7 @@ void iput(struct inode *inode) } 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); diff --git a/fs/intermezzo/cache.c b/fs/intermezzo/cache.c index db9d6948..b7ef2eb 100644 --- a/fs/intermezzo/cache.c +++ b/fs/intermezzo/cache.c @@ -46,7 +46,7 @@ static struct list_head presto_caches[CACHES_SIZE]; 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) @@ -73,7 +73,7 @@ struct presto_cache *presto_find_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; } } @@ -90,7 +90,7 @@ struct presto_cache *presto_get_cache(struct inode *inode) 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; } @@ -174,7 +174,7 @@ int presto_ispresto(struct inode *inode) 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 */ diff --git a/fs/intermezzo/presto.c b/fs/intermezzo/presto.c index 5da2e10..1eba374 100644 --- a/fs/intermezzo/presto.c +++ b/fs/intermezzo/presto.c @@ -71,8 +71,8 @@ int presto_i2m(struct inode *inode) 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; } diff --git a/fs/intermezzo/psdev.c b/fs/intermezzo/psdev.c index 0785b7d..0384ab5 100644 --- a/fs/intermezzo/psdev.c +++ b/fs/intermezzo/psdev.c @@ -43,14 +43,15 @@ #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> @@ -290,7 +291,7 @@ static int presto_psdev_ioctl(struct inode *inode, struct file *file, } len = readmount.io_len; - minor = MINOR(dev); + minor = minor(dev); PRESTO_ALLOC(tmp, char *, len); if (!tmp) { EXIT; @@ -627,7 +628,7 @@ static int presto_psdev_ioctl(struct inode *inode, struct file *file, EXIT; return error; } - minor = MINOR(dev); + minor = minor(dev); if (cmd == PRESTO_SETOPT) error = dosetopt(minor, &kopt); diff --git a/fs/intermezzo/sysctl.c b/fs/intermezzo/sysctl.c index 9a0c34f..212e4c1 100644 --- a/fs/intermezzo/sysctl.c +++ b/fs/intermezzo/sysctl.c @@ -161,15 +161,17 @@ int dosetopt(int minor, struct psdev_opt *opt) * 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); } @@ -224,9 +226,10 @@ int dogetopt(int minor, struct psdev_opt *opt) #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; } diff --git a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c index 8d37756..f8fbdc9 100644 --- a/fs/intermezzo/vfs.c +++ b/fs/intermezzo/vfs.c @@ -136,7 +136,7 @@ inline void presto_debug_fail_blkdev(struct presto_file_set *fset, 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 @@ -602,7 +602,7 @@ int presto_do_link(struct presto_file_set *fset, struct dentry *old_dentry, 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; /* @@ -1609,7 +1609,7 @@ int presto_rename_dir(struct presto_file_set *fset, struct dentry *old_parent, 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) @@ -1690,7 +1690,7 @@ int presto_rename_other(struct presto_file_set *fset, struct dentry *old_parent, 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) diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index a483de6..92388ce 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -475,6 +475,7 @@ int journal_write_metadata_buffer(transaction_t *transaction, 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); diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index faf2b41..43987b6 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -278,7 +278,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, { struct buffer_head *bh = NULL; journal_t *journal; - kdev_t dev; + struct block_device *bdev; int err; if (bh_in) @@ -290,11 +290,11 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, 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"); } @@ -304,7 +304,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, /* 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) && @@ -408,7 +408,7 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) * 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); diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 16d8e3e..1b11394 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1864,6 +1864,7 @@ zap_buffer: 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; } diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 9c9e76f..7cc0da6 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -12,7 +12,7 @@ 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 diff --git a/fs/jffs2/crc32.c b/fs/jffs2/crc32.c deleted file mode 100644 index b3b6a81..0000000 --- a/fs/jffs2/crc32.c +++ b/dev/null @@ -1,97 +0,0 @@ -/* - * 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 -}; diff --git a/fs/jffs2/crc32.h b/fs/jffs2/crc32.h deleted file mode 100644 index cd8979f..0000000 --- a/fs/jffs2/crc32.h +++ b/dev/null @@ -1,21 +0,0 @@ -#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 diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index c40a8fb..c1e9143 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -38,11 +38,11 @@ #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); diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 633875a..115c7a2 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -39,8 +39,8 @@ #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; diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 4771c02..f0446ac 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -40,9 +40,9 @@ #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)); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 4cdb285..9294e58 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -42,8 +42,8 @@ #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); diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index cce4256..fd46ae9 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -37,10 +37,10 @@ #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) { diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 2e1d93d..f72affe 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -41,10 +41,10 @@ #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) diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index c8708da..d1b870b 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -39,8 +39,8 @@ #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); \ diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index e8af189..32c11f9 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -37,10 +37,10 @@ #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. */ @@ -99,16 +99,17 @@ * 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); diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index b0e1fd0..61c8b2b 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -1,4 +1,4 @@ -/* $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) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 68a58ff..870f9c1 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -166,7 +166,7 @@ static void extended_partition(struct gendisk *hd, struct block_device *bdev, 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 @@ -580,7 +580,7 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev, 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)) { diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 9caf732..a426e4f 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -168,7 +168,7 @@ retry: 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; diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 634747f..98d6b2d 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -414,12 +414,15 @@ void reiserfs_check_lock_depth(char *caller) { } /* 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 ; } @@ -430,7 +433,7 @@ static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct reiserf 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 ; @@ -502,8 +505,8 @@ int dump_journal_writers(void) { ** 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 ; @@ -540,12 +543,12 @@ int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, } /* 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; } @@ -559,13 +562,13 @@ int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, 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 */ @@ -760,12 +763,12 @@ reiserfs_panic(s, "journal-539: flush_commit_list: BAD count(%d) > orig_commit_l ** 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 ; @@ -773,6 +776,8 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journa 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 @@ -780,12 +785,11 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journa ** 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) { @@ -793,10 +797,8 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reis 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 ; @@ -1178,7 +1180,7 @@ loop_start: 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)) ; } @@ -1267,21 +1269,21 @@ static unsigned long reiserfs_journal_kupdate(struct super_block *s) { ** 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 ; @@ -1292,7 +1294,7 @@ void remove_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_ *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)) ; @@ -2184,7 +2186,7 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, struct super_bloc 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) { @@ -2215,7 +2217,7 @@ int journal_mark_dirty_nolog(struct reiserfs_transaction_handle *th, struct supe 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) ; @@ -2238,7 +2240,7 @@ int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, i 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 ; } @@ -2255,7 +2257,8 @@ int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, i 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) { @@ -2273,12 +2276,6 @@ int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, i 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. @@ -2290,7 +2287,7 @@ int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list ** */ 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 ; @@ -2300,7 +2297,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) { ** 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 ; } @@ -2313,7 +2310,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) { 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 ; @@ -2578,9 +2575,9 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, struct super_bloc 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) { @@ -2821,7 +2818,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b } 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) ; diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index 775f81c..5648d09 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -142,6 +142,7 @@ void reiserfs_unmap_buffer(struct buffer_head *bh) { 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) ; } } diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h index 7cf6d03..e4f65b8 100644 --- a/include/asm-sparc/bitops.h +++ b/include/asm-sparc/bitops.h @@ -1,4 +1,4 @@ -/* $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) diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h index 3d74130..d42fa22 100644 --- a/include/asm-sparc/io.h +++ b/include/asm-sparc/io.h @@ -1,5 +1,5 @@ /* - * $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 @@ -11,8 +11,7 @@ #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) { diff --git a/include/asm-sparc/keyboard.h b/include/asm-sparc/keyboard.h index 6e59c6d..6155ccb 100644 --- a/include/asm-sparc/keyboard.h +++ b/include/asm-sparc/keyboard.h @@ -1,4 +1,4 @@ -/* $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) diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h index 274707e..8391aff 100644 --- a/include/asm-sparc/mmu_context.h +++ b/include/asm-sparc/mmu_context.h @@ -5,6 +5,29 @@ #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) { } diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index 4e2e601..27ab73c 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h @@ -1,4 +1,4 @@ -/* $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. * @@ -298,15 +298,7 @@ extern int prom_inst2pkg(int); /* 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. */ diff --git a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h index 0bc0b40..701ec03 100644 --- a/include/asm-sparc/pci.h +++ b/include/asm-sparc/pci.h @@ -26,6 +26,7 @@ extern inline void pcibios_penalize_isa_irq(int irq) /* Dynamic DMA mapping stuff. */ +#define PCI_DMA_BUS_IS_PHYS (0) #include <asm/scatterlist.h> diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h index dbdab2c..c283f51 100644 --- a/include/asm-sparc/smp.h +++ b/include/asm-sparc/smp.h @@ -190,8 +190,6 @@ extern __inline__ void smp_send_stop(void) { } #define MBOX_IDLECPU2 0xFD #define MBOX_STOPCPU2 0xFE -#define PROC_CHANGE_PENALTY 15 - #endif /* !(CONFIG_SMP) */ #define NO_PROC_ID 0xFF diff --git a/include/asm-sparc/smplock.h b/include/asm-sparc/smplock.h index 9656506..dd2cc2b 100644 --- a/include/asm-sparc/smplock.h +++ b/include/asm-sparc/smplock.h @@ -3,31 +3,35 @@ * * 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) @@ -38,14 +42,14 @@ do { \ * 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) diff --git a/include/asm-sparc/string.h b/include/asm-sparc/string.h index 7bce820..1182435f 100644 --- a/include/asm-sparc/string.h +++ b/include/asm-sparc/string.h @@ -1,4 +1,4 @@ -/* $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. * @@ -126,9 +126,11 @@ static inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count) }) #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 diff --git a/include/asm-sparc/types.h b/include/asm-sparc/types.h index 8a43339..8e72670 100644 --- a/include/asm-sparc/types.h +++ b/include/asm-sparc/types.h @@ -1,4 +1,4 @@ -/* $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 @@ -46,6 +46,7 @@ typedef unsigned long long u64; #define BITS_PER_LONG 32 typedef u32 dma_addr_t; +typedef u32 dma64_addr_t; #endif /* __KERNEL__ */ diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h index 17ef067..69e5059 100644 --- a/include/asm-sparc64/bitops.h +++ b/include/asm-sparc64/bitops.h @@ -1,4 +1,4 @@ -/* $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) @@ -13,9 +13,9 @@ extern long ___test_and_set_bit(unsigned long nr, volatile void *addr); 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)) @@ -214,8 +214,8 @@ found_middle: 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)) diff --git a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h index d9a5a90..dd584ac 100644 --- a/include/asm-sparc64/elf.h +++ b/include/asm-sparc64/elf.h @@ -1,4 +1,4 @@ -/* $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 @@ -75,24 +75,7 @@ do { unsigned char flags = current->thread.flags; \ 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; \ } \ \ diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index 8b8c056..58a8ae5 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -1,4 +1,4 @@ -/* $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 diff --git a/include/asm-sparc64/keyboard.h b/include/asm-sparc64/keyboard.h index 2202e5a..fc81294 100644 --- a/include/asm-sparc64/keyboard.h +++ b/include/asm-sparc64/keyboard.h @@ -1,4 +1,4 @@ -/* $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) diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index c8296b0..11bb4c2 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h @@ -1,4 +1,4 @@ -/* $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 @@ -27,6 +27,27 @@ #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) { } diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index cf6cbc5..77ee8a0 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -1,4 +1,4 @@ -/* $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. * @@ -326,20 +326,6 @@ extern int prom_inst2pkg(int); /* 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, ...); diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index 6c65d32..c5de1e2 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -1,4 +1,4 @@ -/* $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 @@ -18,13 +18,20 @@ #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); diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h index c026b64..dc0e882 100644 --- a/include/asm-sparc64/processor.h +++ b/include/asm-sparc64/processor.h @@ -1,4 +1,4 @@ -/* $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) @@ -66,6 +66,15 @@ struct thread_struct { 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]; @@ -88,6 +97,7 @@ struct thread_struct { #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, \ @@ -104,6 +114,24 @@ struct thread_struct { /* 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 diff --git a/include/asm-sparc64/rwsem.h b/include/asm-sparc64/rwsem.h index 535ca47..1717d1a 100644 --- a/include/asm-sparc64/rwsem.h +++ b/include/asm-sparc64/rwsem.h @@ -1,4 +1,4 @@ -/* $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. @@ -59,7 +59,7 @@ static inline void __down_read(struct rw_semaphore *sem) " 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" @@ -92,7 +92,7 @@ static inline void __down_write(struct rw_semaphore *sem) "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" @@ -122,7 +122,7 @@ static inline void __up_read(struct rw_semaphore *sem) "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" @@ -160,7 +160,7 @@ static inline void __up_write(struct rw_semaphore *sem) " 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" @@ -189,7 +189,7 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) "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) @@ -208,7 +208,7 @@ static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 __old, __u16 |