http://linus.bkbits.net/linux-2.5 jgarzik@redhat.com|ChangeSet|20040426022709|55970 jgarzik # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/25 18:50:17-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] prevent module unloading for legacy IDE chipset drivers # # It is unsafe thing to do (no locking, no reference counting etc). # Just remove module_exit() as it was done for IDE PCI drivers. # # drivers/ide/legacy/umc8672.c # 2004/04/23 13:16:37-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -26 # prevent module unloading for legacy IDE chipset drivers # # drivers/ide/legacy/qd65xx.c # 2004/04/23 13:16:37-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +2 -9 # prevent module unloading for legacy IDE chipset drivers # # drivers/ide/legacy/pdc4030.c # 2004/04/23 13:16:37-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -22 # prevent module unloading for legacy IDE chipset drivers # # drivers/ide/legacy/ht6560b.c # 2004/04/23 13:16:37-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -24 # prevent module unloading for legacy IDE chipset drivers # # drivers/ide/legacy/dtc2278.c # 2004/04/23 13:16:37-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -20 # prevent module unloading for legacy IDE chipset drivers # # drivers/ide/legacy/ali14xx.c # 2004/04/23 13:16:37-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -18 # prevent module unloading for legacy IDE chipset drivers # # ChangeSet # 2004/04/25 18:50:03-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] use kernel min/max in IDE code (2/2) # # From: Randy Dunlap # From: Michael Veeck # # Removes unnecessary IDE_MIN()/IDE_MAX() macros # and changes calls to use kernel.h macros instead. # # include/linux/ide.h # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -2 # use kernel min/max in IDE code (2/2) # # drivers/scsi/ide-scsi.c # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +5 -5 # use kernel min/max in IDE code (2/2) # # drivers/ide/pci/via82cxxx.c # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +1 -1 # use kernel min/max in IDE code (2/2) # # drivers/ide/pci/cmd64x.c # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +1 -1 # use kernel min/max in IDE code (2/2) # # drivers/ide/legacy/qd65xx.c # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +1 -1 # use kernel min/max in IDE code (2/2) # # drivers/ide/ide-proc.c # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +2 -2 # use kernel min/max in IDE code (2/2) # # drivers/ide/ide-io.c # 2004/04/23 12:19:49-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +1 -1 # use kernel min/max in IDE code (2/2) # # ChangeSet # 2004/04/25 18:49:54-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] use kernel min/max in IDE code (1/2) # # From: Randy Dunlap # From: Michael Veeck # # ide-cd.h: remove unnecessary MIN() macro # ide-cd.c: change MIN() calls to use kernel.h calls # ide-tape.c: use min_t()/max_t() instead of min()/max() # # drivers/ide/ide-tape.c # 2004/04/23 12:09:54-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +1 -1 # use kernel min/max in IDE code (1/2) # # drivers/ide/ide-cd.h # 2004/04/23 12:09:53-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -2 # use kernel min/max in IDE code (1/2) # # drivers/ide/ide-cd.c # 2004/04/23 12:09:53-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +4 -4 # use kernel min/max in IDE code (1/2) # # ChangeSet # 2004/04/25 18:49:42-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] generic PCI IDE support for Toshiba Piccolo chips # # From: Daniel Drake # # Adds Toshiba chips to the list supported by the generic PCI IDE driver. # The 2.4 tree already contained an entry for 0x1179:0x0102, this patch # adds that entry to 2.6 as well as two new ones (0x0103 and 0x0105). # This then allows DMA to be enabled on disks. # # include/linux/pci_ids.h # 2004/04/23 12:04:40-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +3 -0 # generic PCI IDE support for Toshiba Piccolo chips # # drivers/ide/pci/generic.h # 2004/04/23 12:03:11-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +27 -0 # generic PCI IDE support for Toshiba Piccolo chips # # drivers/ide/pci/generic.c # 2004/04/23 12:01:57-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +3 -0 # generic PCI IDE support for Toshiba Piccolo chips # # ChangeSet # 2004/04/25 21:43:37-04:00 khc@pm.waw.pl # [netdrvr tulip] fix use-after-free # # The attached patch fixes an "oops" in tulip driver when a live interface # is deactivated (i.e. PC Card ejected or module unloaded) without being # brought down first. # # drivers/net/tulip/tulip_core.c # 2004/04/25 21:43:32-04:00 khc@pm.waw.pl +1 -1 # [netdrvr tulip] fix use-after-free # # The attached patch fixes an "oops" in tulip driver when a live interface # is deactivated (i.e. PC Card ejected or module unloaded) without being # brought down first. # # ChangeSet # 2004/04/24 22:19:01-04:00 scott.feldman@intel.com # [PATCH] e100: ICH 10/H Tx hang fix # # * Need to carry forward this workaround from old e100 driver to # avoid a Tx hang on ICH systems linked at 10/Half. Workaround # adds a stall before each Tx command queued by issuing a NOP # command followed by 1us delay. Yuck! Otherwise HW locks hard. # (Probably needed for eepro100 also ;-). # # drivers/net/e100.c # 2004/04/20 18:55:32-04:00 scott.feldman@intel.com +23 -5 # ICH 10/H Tx hang fix # # ChangeSet # 2004/04/24 22:19:55+01:00 dsaxena@net.rmk.(none) # [ARM PATCH] 1815/1: Generic DMA buffer bouncing support for ARM targets # # Patch from Deepak Saxena # # Latest (and hopefully last :) patch for generic DMA buffer bouncing. # # - Fixed SA1111 dma_needs_bounce # - Added check for out of bounds buffers. # - Made dmabounce.c directly implement dma_* API # # Note that I didn't do the following: # # #ifndef CONFIG_DMABOUNCE # inline implementations of all functions # #else # extern declarations # #endif # # Instead I wrapped it individual in #ifndef/#else blocks to keep the # comments in the same area as function declarations. IMHO this makes # it easier for someone to go look at the comments if they need to know # what a specific API does. # # # include/asm-arm/dma-mapping.h # 2004/04/15 00:46:10+01:00 dsaxena@net.rmk.(none) +92 -61 # [PATCH] 1815/1: Generic DMA buffer bouncing support for ARM targets # # arch/arm/common/sa1111.c # 2004/04/15 04:39:12+01:00 dsaxena@net.rmk.(none) +38 -55 # [PATCH] 1815/1: Generic DMA buffer bouncing support for ARM targets # # arch/arm/common/Makefile # 2004/04/15 00:43:53+01:00 dsaxena@net.rmk.(none) +2 -1 # [PATCH] 1815/1: Generic DMA buffer bouncing support for ARM targets # # arch/arm/common/dmabounce.c # 2004/04/15 00:43:53+01:00 dsaxena@net.rmk.(none) +331 -222 # [PATCH] 1815/1: Generic DMA buffer bouncing support for ARM targets # # arch/arm/Kconfig # 2004/04/15 00:43:52+01:00 dsaxena@net.rmk.(none) +5 -0 # [PATCH] 1815/1: Generic DMA buffer bouncing support for ARM targets # # ChangeSet # 2004/04/24 21:47:18+01:00 rmk@flint.arm.linux.org.uk # [ARM] Remove extraneous "volatile" from atomic_t pointers. # # include/asm-arm/atomic.h # 2004/04/24 21:44:53+01:00 rmk@flint.arm.linux.org.uk +10 -10 # Remove "volatile" from atomic_xxx() atomic_t pointers. # # ChangeSet # 2004/04/23 22:34:47+01:00 nico@org.rmk.(none) # [ARM PATCH] 1825/1: abort on bad code generation with div64 in some cases # # Patch from Nicolas Pitre # # One case was found when the kernel is compiled with -O2 (instead of the # default -Os). However, all gcc-3.* versions seem to have a problem with # this. Instead of blacklisting them all unconditionally, better just abort # when a bad case occurs especially since this bad case doesn't seem to # appear with current default compiler flags. Depends on patch #1824. # # include/asm-arm/div64.h # 2004/04/23 06:08:46+01:00 nico@org.rmk.(none) +7 -1 # [PATCH] 1825/1: abort on bad code generation with div64 in some cases # # ChangeSet # 2004/04/23 22:31:14+01:00 nico@org.rmk.(none) # [ARM PATCH] 1824/1: guard against gcc not respecting local variable register assignment # # Patch from Nicolas Pitre # # The recent discovery of a problem with gcc not always respecting register # assignment for local variables to be used with inline assembly is worrisome. # If unnoticed, such problems can cover bugs that might prove hard to find # especially when the code is right but silently ignored. This patch adds a # test where needed to have the assembler confirm our register selection and # fail the kernel build if the wrong registers are allocated. # # include/asm-arm/uaccess.h # 2004/04/23 04:12:15+01:00 nico@org.rmk.(none) +7 -2 # [PATCH] 1824/1: guard against gcc not respecting local variable register assignment # # include/asm-arm/system.h # 2004/04/23 04:17:02+01:00 nico@org.rmk.(none) +9 -0 # [PATCH] 1824/1: guard against gcc not respecting local variable register assignment # # ChangeSet # 2004/04/23 13:29:15-07:00 davem@nuts.davemloft.net # [SPARC64]: Update defconfig. # # arch/sparc64/defconfig # 2004/04/23 13:28:57-07:00 davem@nuts.davemloft.net +140 -140 # [SPARC64]: Update defconfig. # # ChangeSet # 2004/04/23 16:48:55+01:00 aia21@cantab.net # Merge cantab.net:/usr/src/bklinux-2.6 into cantab.net:/usr/src/ntfs-2.6 # # fs/ntfs/aops.c # 2004/04/23 16:48:49+01:00 aia21@cantab.net +0 -0 # Auto merged # # ChangeSet # 2004/04/23 16:22:42+01:00 aia21@cantab.net # NTFS: Finally fix NFS exporting of mounted NTFS volumes by checking the # return of d_splice_alias() and acting accordingly rather than just # ignoring the returned dentry. # # fs/ntfs/namei.c # 2004/04/23 16:22:33+01:00 aia21@cantab.net +23 -13 # Finally fix NFS exporting of mounted NTFS volumes by checking the # return of d_splice_alias() and acting accordingly rather than just # ignoring the returned dentry. # # fs/ntfs/ChangeLog # 2004/04/23 16:22:33+01:00 aia21@cantab.net +2 -0 # Update. # # ChangeSet # 2004/04/23 06:32:08-07:00 akpm@osdl.org # [PATCH] writeback livelock fix # # If a filesystem's ->writepage implementation repeatedly refuses to write the # page (it keeps on redirtying it instead) (reiserfs seems to do this) then the # writeback logic can get stuck repeately trying to write the same page. # # Fix that up by correctly setting wbc->pages_skipped, to tell the writeback # logic that things aren't working out. # # mm/page-writeback.c # 2004/04/22 16:20:51-07:00 akpm@osdl.org +12 -0 # writeback livelock fix # # include/linux/mm.h # 2004/04/22 16:20:51-07:00 akpm@osdl.org +2 -0 # writeback livelock fix # # fs/reiserfs/inode.c # 2004/04/22 16:20:51-07:00 akpm@osdl.org +1 -1 # writeback livelock fix # # fs/ntfs/aops.c # 2004/04/22 16:20:51-07:00 akpm@osdl.org +5 -14 # writeback livelock fix # # fs/ext3/inode.c # 2004/04/22 16:20:51-07:00 akpm@osdl.org +3 -3 # writeback livelock fix # # fs/buffer.c # 2004/04/22 16:20:51-07:00 akpm@osdl.org +1 -1 # writeback livelock fix # # ChangeSet # 2004/04/23 06:36:35-05:00 stevef@steveft21.ltcsamba # do not allow routine user signals to kill SendReceive wait for response (which was damaging performance badly) # # fs/cifs/transport.c # 2004/04/23 06:36:18-05:00 stevef@steveft21.ltcsamba +12 -5 # do not allow routine user signals to kill SendReceive wait for response (which was damaging performance badly) # # ChangeSet # 2004/04/23 12:12:25+01:00 aia21@cantab.net # NTFS: Move a few assignments after a NULL check in fs/ntfs/attrib.c. # # fs/ntfs/attrib.c # 2004/04/23 12:06:51+01:00 aia21@cantab.net +6 -3 # Move assignments after NULL check. # # ChangeSet # 2004/04/23 09:19:18+01:00 aia21@cantab.net # Merge cantab.net:/home/src/bklinux-2.6 # into cantab.net:/home/src/ntfs-2.6 # # fs/ntfs/aops.c # 2004/04/23 09:19:11+01:00 aia21@cantab.net +0 -0 # Auto merged # # ChangeSet # 2004/04/22 22:55:12-05:00 stevef@stevef95.austin.ibm.com # fix timeout on close operation when pending signal # # ChangeSet # 2004/04/23 02:18:21-05:00 stevef@steveft21.ltcsamba # fix error code mapping on bad host # # fs/cifs/transport.c # 2004/04/22 22:55:05-05:00 stevef@stevef95.austin.ibm.com +16 -8 # fix timeout on close operation when pending signal # # fs/cifs/transport.c # 2004/04/23 02:18:04-05:00 stevef@steveft21.ltcsamba +11 -8 # fix error code mapping on bad host # # ChangeSet # 2004/04/23 01:59:28-05:00 stevef@steveft21.ltcsamba # proper rc on host down # # fs/cifs/README # 2004/04/23 01:59:05-05:00 stevef@steveft21.ltcsamba +9 -3 # update readme for guest option # # ChangeSet # 2004/04/22 23:38:25-07:00 davidm@tiger.hpl.hp.com # ia64: Add message-queue support to copy_siginfo_from_user(). # # include/asm-ia64/siginfo.h # 2004/04/22 23:38:17-07:00 davidm@tiger.hpl.hp.com +0 -2 # (copy_siginfo_from_user): Delete. # # arch/ia64/kernel/signal.c # 2004/04/22 23:38:17-07:00 davidm@tiger.hpl.hp.com +6 -34 # (copy_siginfo_to_user): Handle __SI_RT and __SI_MESGQ. # (copy_siginfo_from_user): Delete. # # arch/ia64/ia32/ia32_signal.c # 2004/04/22 23:38:17-07:00 davidm@tiger.hpl.hp.com +6 -2 # (copy_siginfo_from_user32): Handle __SI_RT and __SI_MESGQ. # (sys32_rt_sigqueueinfo): Remove unneded copy_siginfo_from_user32() decl. # # fs/cifs/connect.c # 2004/04/22 22:55:04-05:00 stevef@stevef95.austin.ibm.com +2 -0 # fix timeout logic # # fs/cifs/cifssmb.c # 2004/04/22 22:55:04-05:00 stevef@stevef95.austin.ibm.com +4 -1 # do not log expected error on close # # fs/cifs/cifsfs.c # 2004/04/22 22:55:04-05:00 stevef@stevef95.austin.ibm.com +1 -0 # fix oplock timeout # # fs/cifs/CHANGES # 2004/04/22 22:55:04-05:00 stevef@stevef95.austin.ibm.com +2 -1 # update cifs vfs change log for version 1.10 # # ChangeSet # 2004/04/22 18:38:48-05:00 stevef@stevef95.austin.ibm.com # Update change log for 1.10 cifs vfs # # fs/cifs/CHANGES # 2004/04/22 18:38:40-05:00 stevef@stevef95.austin.ibm.com +6 -0 # Update change log for 1.10 cifs vfs # # ChangeSet # 2004/04/22 18:17:11-05:00 stevef@stevef95.austin.ibm.com # exit from waiting on smb response when session dead # # fs/cifs/transport.c # 2004/04/22 18:17:03-05:00 stevef@stevef95.austin.ibm.com +4 -4 # exit from waiting on smb response when session dead # # fs/cifs/connect.c # 2004/04/22 18:17:03-05:00 stevef@stevef95.austin.ibm.com +4 -4 # Do not reset capabilities on failed negprot # # ChangeSet # 2004/04/22 15:11:12-07:00 lxiep@us.ibm.com # [PATCH] symlink doesn't support kobj name > 20 charaters (KOBJ_NAME_LEN) # # Since symlink.c uses "name" field of a kobj when it calculates the # length, it gets a wrong value if the kobj's name has more than 20 # charathers. A correct way to do that is to call kobject_name(kobj) # instead of using kobj->name directly. # # fs/sysfs/symlink.c # 2003/12/17 12:08:01-08:00 lxiep@us.ibm.com +3 -3 # symlink doesn't support kobj name > 20 charaters (KOBJ_NAME_LEN) # # ChangeSet # 2004/04/22 14:36:55-07:00 lkml@lievin.net # [PATCH] tipar char driver: wrong timeout value # # this patch (2.4 & 2.6) fixes a bug about the timeout value. The formula # used to calculate jiffies from timeout is wrong. # The new formula is ok and takes care of integer computation/rounding. # There is the same bug in the tiglusb.c module which will be fixed by another # patch. # # drivers/char/tipar.c # 2004/04/19 00:23:25-07:00 lkml@lievin.net +1 -1 # tipar char driver: wrong timeout value # # ChangeSet # 2004/04/22 16:29:05-05:00 stevef@stevef95.austin.ibm.com # resolve merge conflict # # fs/cifs/connect.c # 2004/04/22 16:28:57-05:00 stevef@stevef95.austin.ibm.com +0 -1 # resolve merge conflict # # ChangeSet # 2004/04/22 16:02:53-05:00 stevef@stevef95.austin.ibm.com # RFC1002 fixup # # fs/cifs/rfc1002pdu.h # 2004/04/22 16:02:44-05:00 stevef@stevef95.austin.ibm.com +75 -0 # # fs/cifs/rfc1002pdu.h # 2004/04/22 16:02:44-05:00 stevef@stevef95.austin.ibm.com +0 -0 # BitKeeper file /usr/src/bk/linux-2.5cifs/fs/cifs/rfc1002pdu.h # # fs/cifs/connect.c # 2004/04/22 16:02:44-05:00 stevef@stevef95.austin.ibm.com +12 -9 # RFC1002 fixup # # ChangeSet # 2004/04/22 13:53:58-07:00 david-b@pacbell.net # [PATCH] USB: usbnet and pl2301/2302 reset # # Handle some PL-2301/2302 devices better. # # drivers/usb/net/usbnet.c # 2004/04/20 20:44:45-07:00 david-b@pacbell.net +5 -1 # USB: usbnet and pl2301/2302 reset # # ChangeSet # 2004/04/22 13:53:33-07:00 jan@ccsinfo.com # [PATCH] USB: ftdi patch fixup # # I just checked out the latest 2.6.6-rc1-mm1 to see that the ID patch for # ftdi has applied cleanly, but apparently someone was faster and in the # combined ID table our ID's were missing. # Most probably the patch program got confused and applied the hung at wrong # spot.. # # Attached is a patch that places that 2 lines in the correct spot. # # drivers/usb/serial/ftdi_sio.c # 2004/04/20 12:50:39-07:00 jan@ccsinfo.com +2 -2 # USB: ftdi patch fixup # # ChangeSet # 2004/04/22 13:53:08-07:00 lkml@lievin.net # [PATCH] USB: tiglusb: wrong timeout value # # Hi, # # this patch (cumulative; 2.4 & 2.6) fixes another bug in the tiglusb # driver. The formula used to calculate jiffies from timeout is wrong. # The new formula is ok and takes care of integer computation/rounding. # This is the same kind of bug than in the tipar char driver. # # drivers/usb/misc/tiglusb.c # 2004/04/19 01:47:59-07:00 lkml@lievin.net +26 -26 # USB: tiglusb: wrong timeout value # # ChangeSet # 2004/04/22 13:52:40-07:00 wli@holomorphy.com # [PATCH] USB: silence dpcm warning # # Warnings aren't terribly important in and of themselves, but there # isn't really much the warning tells us to do here, so it would appear # that caving in to the compiler is the thing to do for now. # # drivers/usb/storage/dpcm.c # 2004/04/16 05:59:19-07:00 wli@holomorphy.com +6 -3 # USB: silence dpcm warning # # ChangeSet # 2004/04/22 13:43:39-07:00 david-b@pacbell.net # [PATCH] USB: rndis gadget driver updates # # Various build fixes: 64bit (Andrew Morton), static linking, # broken on big-endian, etc. # # Tighten up the integration with the main "ether" driver, so # state transitions and host ethernet addresses are shared too. # Add missing spinlock calls around RNDIS command outcall, # fix GET_INTERFACE issue, host mustn't clobber netdev flags. # # Minor code cleanups. # # drivers/usb/gadget/rndis.h # 2004/04/22 11:22:03-07:00 david-b@pacbell.net +5 -2 # USB: rndis gadget driver updates # # drivers/usb/gadget/rndis.c # 2004/04/22 11:22:03-07:00 david-b@pacbell.net +87 -48 # USB: rndis gadget driver updates # # drivers/usb/gadget/ether.c # 2004/04/22 11:22:03-07:00 david-b@pacbell.net +28 -21 # USB: rndis gadget driver updates # # ChangeSet # 2004/04/22 13:43:11-07:00 david-b@pacbell.net # [PATCH] USB: ehci handles pci misbehavior better # # Cope better when PCI misbehaves badly and registers misbehave: # # - terminate some loops before they get to infinity # * capability scan # * port reset # - after init failure, memory may already be cleaned up # # Some systems have been reporting such problems after ACPI resume. # # drivers/usb/host/ehci-hub.c # 2004/04/22 02:04:22-07:00 david-b@pacbell.net +10 -6 # USB: ehci handles pci misbehavior better # # drivers/usb/host/ehci-hcd.c # 2004/04/22 02:04:21-07:00 david-b@pacbell.net +14 -3 # USB: ehci handles pci misbehavior better # # ChangeSet # 2004/04/22 13:38:54-07:00 mikpe@csd.uu.se # [PATCH] use smp_processor_id() in init_IRQ() # # This replaces current_thread_info()->cpu in i386' init_IRQ() by the # equivalent smp_processor_id(). # # Reduces overhead on UP, and makes the code cleaner. # # arch/i386/kernel/i8259.c # 2004/04/22 04:15:40-07:00 mikpe@csd.uu.se +1 -1 # use smp_processor_id() in init_IRQ() # # ChangeSet # 2004/04/22 13:38:42-07:00 mikpe@csd.uu.se # [PATCH] clean up Pentium M quirk code in nmi.c # # This simplifies the Pentium M quirk code in nmi.c, and eliminates an # unnecessary apic_read(). # # Local APIC accesses are not zero-cycle; let's not inflict more damage # than we must. # # arch/i386/kernel/nmi.c # 2004/04/22 04:09:54-07:00 mikpe@csd.uu.se +1 -2 # clean up Pentium M quirk code in nmi.c # # ChangeSet # 2004/04/22 13:38:29-07:00 akpm@osdl.org # [PATCH] ppc64: Set ARCH_MIN_TASKALIGN # # From: Benjamin Herrenschmidt # # We need some alignement of those structs for proper operations especially # with FP and Altivec, or SLAB_DEBUG can break us. # # include/asm-ppc64/processor.h # 2004/04/22 01:40:36-07:00 akpm@osdl.org +2 -0 # ppc64: Set ARCH_MIN_TASKALIGN # # ChangeSet # 2004/04/22 13:38:16-07:00 akpm@osdl.org # [PATCH] ppc64: add some iSeries proc entries # # From: Stephen Rothwell # # This patch just adds some proc entries for the virtual tape and cdrom # drivers to allow mapping between linux devices and OS/400 ones. This is # expected by existing users and there is no other way to do this # translation. # # drivers/char/viotape.c # 2004/04/22 01:40:36-07:00 akpm@osdl.org +40 -1 # ppc64: add some iSeries proc entries # # drivers/cdrom/viocd.c # 2004/04/22 01:40:36-07:00 akpm@osdl.org +37 -0 # ppc64: add some iSeries proc entries # # ChangeSet # 2004/04/22 13:38:04-07:00 akpm@osdl.org # [PATCH] sunrpc rmmod oops fix # # From: "J. Bruce Fields" # # Unregister svcauth_gss caches on exit from gss module; fixes an oops on # rmmod. # # net/sunrpc/auth_gss/svcauth_gss.c # 2004/04/22 01:40:36-07:00 akpm@osdl.org +7 -0 # sunrpc rmmod oops fix # # net/sunrpc/auth_gss/auth_gss.c # 2004/04/22 01:40:36-07:00 akpm@osdl.org +1 -0 # sunrpc rmmod oops fix # # include/linux/sunrpc/svcauth_gss.h # 2004/04/22 01:40:36-07:00 akpm@osdl.org +1 -0 # sunrpc rmmod oops fix # # ChangeSet # 2004/04/22 13:37:51-07:00 akpm@osdl.org # [PATCH] Set ARCH_MIN_TASKALIGN on ppc32 # # From: Benjamin Herrenschmidt # # From: David Woodhouse # # Without this the task struct gets unaligned when using SLAB_DEBUG, causing # random problems with FP and Altivec. # # include/asm-ppc/processor.h # 2004/04/22 01:40:36-07:00 akpm@osdl.org +2 -0 # Set ARCH_MIN_TASKALIGN on ppc32 # # ChangeSet # 2004/04/22 13:37:38-07:00 akpm@osdl.org # [PATCH] Update comment in fs/compat.c # # From: Ralf Baechle # # MIPS now also uses the generic ioctl compat code. # # fs/compat.c # 2004/04/22 01:40:35-07:00 akpm@osdl.org +1 -1 # Update comment in fs/compat.c # # ChangeSet # 2004/04/22 13:37:25-07:00 akpm@osdl.org # [PATCH] MIPS is an a.out free zone # # From: Ralf Baechle # # MIPS never uses a.out # # fs/Kconfig.binfmt # 2004/04/22 01:40:35-07:00 akpm@osdl.org +1 -1 # MIPS is an a.out free zone # # ChangeSet # 2004/04/22 13:37:12-07:00 akpm@osdl.org # [PATCH] Merge missing MIPS i8042 bits # # From: Ralf Baechle # # - Add HPC3 PS/2 driver bits for SGI IP22 aka Indy # - Add Mace PS/2 driver bits for SGI IP32 aka O2 # - Add R4030 PS/2 driver bits for Jazz family # - Don't register I/O ports where we're using the I/O port memory window # to access the i8042 registers # # drivers/input/serio/maceps2.c # 2004/04/22 01:40:35-07:00 akpm@osdl.org +160 -0 # Merge missing MIPS i8042 bits # # drivers/input/serio/i8042-jazzio.h # 2004/04/22 01:40:35-07:00 akpm@osdl.org +69 -0 # Merge missing MIPS i8042 bits # # drivers/input/serio/i8042-ip22io.h # 2004/04/22 01:40:35-07:00 akpm@osdl.org +76 -0 # Merge missing MIPS i8042 bits # # drivers/input/serio/maceps2.c # 2004/04/22 01:40:35-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/input/serio/maceps2.c # # drivers/input/serio/i8042.h # 2004/04/22 01:40:35-07:00 akpm@osdl.org +7 -1 # Merge missing MIPS i8042 bits # # drivers/input/serio/i8042-jazzio.h # 2004/04/22 01:40:35-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/input/serio/i8042-jazzio.h # # drivers/input/serio/i8042-ip22io.h # 2004/04/22 01:40:35-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/input/serio/i8042-ip22io.h # # drivers/input/serio/i8042-io.h # 2004/04/22 01:40:35-07:00 akpm@osdl.org +1 -1 # Merge missing MIPS i8042 bits # # drivers/input/serio/Makefile # 2004/04/22 01:40:35-07:00 akpm@osdl.org +1 -0 # Merge missing MIPS i8042 bits # # drivers/input/serio/Kconfig # 2004/04/22 01:40:35-07:00 akpm@osdl.org +10 -0 # Merge missing MIPS i8042 bits # # ChangeSet # 2004/04/22 13:36:59-07:00 akpm@osdl.org # [PATCH] Add Pete Popov to credits # # From: Ralf Baechle # # Add Pete to CREDITS for all the time he's invested into supporting the AMD # Alchemy of SOCs and eval boards. # # CREDITS # 2004/04/22 01:40:35-07:00 akpm@osdl.org +6 -0 # Add Pete Popov to credits # # ChangeSet # 2004/04/22 13:36:45-07:00 akpm@osdl.org # [PATCH] MIPS: PCI code is now shared. # # From: Ralf Baechle # # All MIPS systems use the same PCI code now. # # drivers/pci/Makefile # 2004/04/22 01:40:35-07:00 akpm@osdl.org +1 -2 # MIPS: PCI code is now shared. # # ChangeSet # 2004/04/22 13:36:32-07:00 akpm@osdl.org # [PATCH] fbdev comment fix # # Fix the incorrect comment which caused the fb_ioctl confusion. # # drivers/video/fbcmap.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +1 -1 # fbdev comment fix # # ChangeSet # 2004/04/22 13:36:19-07:00 akpm@osdl.org # [PATCH] dynamic proc cleanups # # From: Matt Mackall # # Delete obsolete comment and kill test of obsolete define. # # include/linux/proc_fs.h # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -2 # dynamic proc cleanups # # arch/alpha/kernel/irq.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +5 -9 # dynamic proc cleanups # # ChangeSet # 2004/04/22 13:36:07-07:00 akpm@osdl.org # [PATCH] EDD: set sysfs attr owner field # # From: Matt Domsch # # The patch below from Michael E. Brown properly sets the owner field of a # sysfs attribute. Without this patch, it is possible to crash the kernel with # a simultaneous insmod/rmmod while reading files exported by the module. # # drivers/firmware/edd.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +1 -1 # EDD: set sysfs attr owner field # # ChangeSet # 2004/04/22 13:35:53-07:00 akpm@osdl.org # [PATCH] s390: crypto api. # # From: Martin Schwidefsky # # Add support for z990 crypto instructions to in-kernel crypto api. # # arch/s390/crypto/sha1_z990.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +167 -0 # s390: crypto api. # # arch/s390/crypto/des_z990.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +284 -0 # s390: crypto api. # # arch/s390/crypto/des_check_key.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +130 -0 # s390: crypto api. # # arch/s390/crypto/crypt_z990_query.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +111 -0 # s390: crypto api. # # arch/s390/crypto/crypt_z990.h # 2004/04/22 01:40:34-07:00 akpm@osdl.org +374 -0 # s390: crypto api. # # arch/s390/crypto/Makefile # 2004/04/22 01:40:34-07:00 akpm@osdl.org +8 -0 # s390: crypto api. # # Documentation/s390/crypto/crypto-API.txt # 2004/04/22 01:40:34-07:00 akpm@osdl.org +83 -0 # s390: crypto api. # # crypto/Kconfig # 2004/04/22 01:40:34-07:00 akpm@osdl.org +12 -0 # s390: crypto api. # # arch/s390/defconfig # 2004/04/22 01:40:34-07:00 akpm@osdl.org +2 -0 # s390: crypto api. # # arch/s390/crypto/sha1_z990.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/sha1_z990.c # # arch/s390/crypto/des_z990.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/des_z990.c # # arch/s390/crypto/des_check_key.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/des_check_key.c # # arch/s390/crypto/crypto_des.h # 2004/04/22 01:40:34-07:00 akpm@osdl.org +18 -0 # s390: crypto api. # # arch/s390/crypto/crypt_z990_query.c # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/crypt_z990_query.c # # arch/s390/crypto/crypt_z990.h # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/crypt_z990.h # # arch/s390/crypto/Makefile # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/Makefile # # arch/s390/Makefile # 2004/04/22 01:40:34-07:00 akpm@osdl.org +1 -1 # s390: crypto api. # # Documentation/s390/crypto/crypto-API.txt # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/Documentation/s390/crypto/crypto-API.txt # # arch/s390/crypto/crypto_des.h # 2004/04/22 01:40:34-07:00 akpm@osdl.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/arch/s390/crypto/crypto_des.h # # ChangeSet # 2004/04/22 13:35:40-07:00 akpm@osdl.org # [PATCH] s390: zfcp adapter fixes. # # From: Martin Schwidefsky # # zfcp host adapter changes: # - Fix error recovery stall in case of unavailable nameserver. # - Reset host_scribble field to NULL in scsi_cmd. # - Remove request debug code. # # drivers/s390/scsi/zfcp_scsi.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +1 -5 # s390: zfcp adapter fixes. # # drivers/s390/scsi/zfcp_qdio.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +1 -10 # s390: zfcp adapter fixes. # # drivers/s390/scsi/zfcp_fsf.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +4 -37 # s390: zfcp adapter fixes. # # drivers/s390/scsi/zfcp_erp.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +13 -12 # s390: zfcp adapter fixes. # # drivers/s390/scsi/zfcp_def.h # 2004/04/22 01:40:33-07:00 akpm@osdl.org +1 -14 # s390: zfcp adapter fixes. # # drivers/s390/scsi/zfcp_aux.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +2 -14 # s390: zfcp adapter fixes. # # ChangeSet # 2004/04/22 13:35:26-07:00 akpm@osdl.org # [PATCH] s390: dasd device driver. # # From: Martin Schwidefsky # # dasd device driver changes: # - Initialize open_count with -1 to account for blkdev_open in # dasd_scan_partitions. # - Introduce USE_ERP request flag to selectivly switch off error # recovery for reserve, release & unconditional reserve ioctls. # # drivers/s390/block/dasd_int.h # 2004/04/22 01:40:33-07:00 akpm@osdl.org +5 -1 # s390: dasd device driver. # # drivers/s390/block/dasd_eckd.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +4 -1 # s390: dasd device driver. # # drivers/s390/block/dasd_3990_erp.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +2 -1 # s390: dasd device driver. # # drivers/s390/block/dasd.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +11 -4 # s390: dasd device driver. # # ChangeSet # 2004/04/22 13:35:12-07:00 akpm@osdl.org # [PATCH] s390: network device drivers. # # From: Martin Schwidefsky # # Network driver changes: # - qeth: Fix reference counting in regard to sysfs backing store patches. # - qeth: Prefix kernel thread names with qeth_. # - qeth: Remove inbound and outbound tasklets. Handle buffers directly # in the interrupts handlers. # - iucv: Add missing kfree in iucv_register_program. # - iucv: Add missing return in netiucv_transmit_skb. # - iucv: Check for NULL pointer in conn_action_txdone. # # drivers/s390/net/qeth_main.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +138 -188 # s390: network device drivers. # # drivers/s390/net/qeth.h # 2004/04/22 01:40:33-07:00 akpm@osdl.org +1 -4 # s390: network device drivers. # # drivers/s390/net/netiucv.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +10 -8 # s390: network device drivers. # # drivers/s390/net/iucv.c # 2004/04/22 01:40:33-07:00 akpm@osdl.org +4 -3 # s390: network device drivers. # # ChangeSet # 2004/04/22 13:34:58-07:00 akpm@osdl.org # [PATCH] s390: 3270 device driver. # # From: Martin Schwidefsky # # 3270 device driver changes: # - Add NULL pointer checks. # # drivers/s390/char/raw3270.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +3 -1 # s390: 3270 device driver. # # ChangeSet # 2004/04/22 13:34:46-07:00 akpm@osdl.org # [PATCH] s390: common i/o layer. # # From: Martin Schwidefsky # # Common i/o layer changes: # - Quiesce active subchannels for lpar reipl. # - Delete timer after reception of interrupt for kill on timeout. # - Cleanup some comments in qdio. # # drivers/s390/cio/qdio.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +6 -6 # s390: common i/o layer. # # drivers/s390/cio/device_fsm.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +3 -0 # s390: common i/o layer. # # drivers/s390/cio/cio.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +66 -1 # s390: common i/o layer. # # arch/s390/kernel/smp.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +2 -2 # s390: common i/o layer. # # arch/s390/kernel/setup.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +2 -2 # s390: common i/o layer. # # ChangeSet # 2004/04/22 13:34:32-07:00 akpm@osdl.org # [PATCH] s390: core s390. # # From: Martin Schwidefsky # # s390 core changes: # - Fix race in do_call_softirq in regard to kernel preemption. # - Fix typo in compat mq system call wrappers. # - Add s390 to Kconfig for AUDITSYSCALL. # - Redefine TASK_SIZE to TASK31_SIZE for compilation of binfmt_elf32. # - Use correct error value for sys32_ipc when called with an invalid number. # - New default configuration. # # init/Kconfig # 2004/04/22 01:40:32-07:00 akpm@osdl.org +1 -1 # s390: core s390. # # arch/s390/kernel/entry64.S # 2004/04/22 01:40:32-07:00 akpm@osdl.org +4 -2 # s390: core s390. # # arch/s390/kernel/entry.S # 2004/04/22 01:40:32-07:00 akpm@osdl.org +4 -2 # s390: core s390. # # arch/s390/kernel/compat_wrapper.S # 2004/04/22 01:40:32-07:00 akpm@osdl.org +1 -1 # s390: core s390. # # arch/s390/kernel/compat_linux.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +35 -53 # s390: core s390. # # arch/s390/kernel/binfmt_elf32.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +2 -0 # s390: core s390. # # arch/s390/defconfig # 2004/04/22 01:40:32-07:00 akpm@osdl.org +19 -27 # s390: core s390. # # ChangeSet # 2004/04/22 13:34:19-07:00 akpm@osdl.org # [PATCH] ppc64: iSeries virtual cdrom module fix # # From: Stephen Rothwell # # This patch fixes loading viocd as a module. It would oops because I was # passing the address of a static buffer to dma_map_single and when loaded as # a module, this address is not valid for that purpose. # # There are a couple of simple cleanups here as well. # # drivers/cdrom/viocd.c # 2004/04/22 01:40:32-07:00 akpm@osdl.org +30 -20 # ppc64: iSeries virtual cdrom module fix # # ChangeSet # 2004/04/22 13:34:05-07:00 akpm@osdl.org # [PATCH] remove show_trace_task() # # It no longer has any callers. # # include/linux/sched.h # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -1 # remove show_trace_task() # # arch/x86_64/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -10 # remove show_trace_task() # # arch/v850/kernel/process.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -7 # remove show_trace_task() # # arch/um/kernel/sysrq.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -11 # remove show_trace_task() # # arch/sparc64/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -7 # remove show_trace_task() # # arch/sh/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -6 # remove show_trace_task() # # arch/s390/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -11 # remove show_trace_task() # # arch/ppc64/kernel/process.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -6 # remove show_trace_task() # # arch/parisc/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -5 # remove show_trace_task() # # arch/mips/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -5 # remove show_trace_task() # # arch/i386/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -10 # remove show_trace_task() # # arch/h8300/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -6 # remove show_trace_task() # # arch/cris/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -8 # remove show_trace_task() # # arch/arm26/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -12 # remove show_trace_task() # # arch/alpha/kernel/traps.c # 2004/04/22 01:40:31-07:00 akpm@osdl.org +0 -12 # remove show_trace_task() # # ChangeSet # 2004/04/22 13:32:53-07:00 greg@kroah.com # [PATCH] USB: fix cdc-acm warnings due to previous patch # # drivers/usb/class/cdc-acm.c # 2004/04/22 06:31:18-07:00 greg@kroah.com +5 -3 # USB: fix cdc-acm warnings due to previous patch # # ChangeSet # 2004/04/22 13:32:24-07:00 colin@colino.net # [PATCH] USB: fix cdc-acm as it is still (differently) broken # # drivers/usb/class/cdc-acm.c # 2004/04/18 04:18:36-07:00 colin@colino.net +47 -36 # USB: fix cdc-acm as it is still (differently) broken # # ChangeSet # 2004/04/22 13:03:22-07:00 stern@rowland.harvard.edu # [PATCH] USB: Important bugfix for UHCI list management code # # A major bug in the UHCI driver turned up recently. Thanks to a lot of # help from Simone Gotti it was identified and fixed late last week. It # turned out to be entirely my fault -- a previous patch had introduced two # (!) errors. (A combination of carelessness and a nasty thinko, and # somehow it passed the regression tests...) # # Anyway, it's entirely possible that many of the problems people have been # seeing are caused by that bug. This patch is the solution. # # drivers/usb/host/uhci-hcd.c # 2004/04/16 06:43:12-07:00 stern@rowland.harvard.edu +22 -14 # USB: Important bugfix for UHCI list management code # # ChangeSet # 2004/04/22 12:19:51-07:00 mebrown@michaels-house.net # [PATCH] sysfs module unload race fix for bin_attributes # # - Add module locking to sysfs bin_attribute files. Update all in-tree # users to set module owner. # # Compile tested. booted. stress tests pass: # # while true; do modprobe mymod; rmmod mymod; done & # while true; do hexdump -C /sys/path/to/sysfs/binary/file; done # # fs/sysfs/bin.c # 2004/04/21 13:42:04-07:00 mebrown@michaels-house.net +13 -3 # sysfs module unload race fix for bin_attributes # # drivers/scsi/qla2xxx/qla_os.c # 2004/04/21 13:42:05-07:00 mebrown@michaels-house.net +2 -0 # sysfs module unload race fix for bin_attributes # # drivers/i2c/chips/eeprom.c # 2004/04/21 13:42:04-07:00 mebrown@michaels-house.net +1 -0 # sysfs module unload race fix for bin_attributes # # drivers/base/firmware_class.c # 2004/04/21 13:42:04-07:00 mebrown@michaels-house.net +1 -1 # sysfs module unload race fix for bin_attributes # # ChangeSet # 2004/04/22 12:10:05-07:00 greg@kroah.com # [PATCH] USB: Don't try to suspend devices that do not support it. # # Patch originally from luming.yu@intel.com and closes bug #1557 # # drivers/usb/core/hcd-pci.c # 2004/04/22 04:53:11-07:00 greg@kroah.com +5 -0 # USB: Don't try to suspend devices that do not support it. # # ChangeSet # 2004/04/21 23:10:52-07:00 davem@nuts.davemloft.net # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # net/ipv4/tcp_output.c # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +18 -0 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # net/ipv4/tcp_minisocks.c # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +1 -0 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # net/ipv4/tcp_input.c # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +289 -9 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # net/ipv4/sysctl_net_ipv4.c # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +32 -1 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # include/net/tcp.h # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +52 -0 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # include/linux/tcp.h # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +12 -0 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # include/linux/sysctl.h # 2004/04/21 23:10:19-07:00 davem@nuts.davemloft.net +4 -0 # [TCP]: Add vegas congestion avoidance support. # # A forward port of an old 2.3.x kernel hack done # years ago. I (DaveM) did the first rough port, # Stephen Hemminger actually cleaned it up and # made it usable. # # ChangeSet # 2004/04/21 22:47:05-07:00 davem@nuts.davemloft.net # [TCP]: Abstract out all settings of tcp_opt->ca_state into a function. # # net/ipv4/tcp_output.c # 2004/04/21 22:46:46-07:00 davem@nuts.davemloft.net +1 -1 # [TCP]: Abstract out all settings of tcp_opt->ca_state into a function. # # net/ipv4/tcp_minisocks.c # 2004/04/21 22:46:46-07:00 davem@nuts.davemloft.net +1 -1 # [TCP]: Abstract out all settings of tcp_opt->ca_state into a function. # # net/ipv4/tcp_input.c # 2004/04/21 22:46:46-07:00 davem@nuts.davemloft.net +9 -9 # [TCP]: Abstract out all settings of tcp_opt->ca_state into a function. # # net/ipv4/tcp.c # 2004/04/21 22:46:46-07:00 davem@nuts.davemloft.net +1 -1 # [TCP]: Abstract out all settings of tcp_opt->ca_state into a function. # # include/net/tcp.h # 2004/04/21 22:46:46-07:00 davem@nuts.davemloft.net +6 -1 # [TCP]: Abstract out all settings of tcp_opt->ca_state into a function. # # ChangeSet # 2004/04/21 23:08:55-05:00 stevef@smfhome.smfdom # Retry 2nd time after failure on correct port # # fs/cifs/connect.c # 2004/04/21 23:08:47-05:00 stevef@smfhome.smfdom +33 -5 # Retry 2nd time after failure on correct port # # ChangeSet # 2004/04/21 22:31:41-04:00 ralf@linux-mips.org # [PATCH] declance updates # # Various small changes, DEC still doesn't work under 2.6. # # drivers/net/declance.c # 2004/04/11 23:42:10-04:00 ralf@linux-mips.org +47 -20 # declance updates # # drivers/net/Kconfig # 2004/04/11 23:42:10-04:00 ralf@linux-mips.org +1 -1 # declance updates # # ChangeSet # 2004/04/21 22:10:31-04:00 ralf@linux-mips.org # [PATCH] IOC3 updates # # Use generic MII code, compile time configurable rx and tx checksumming. # Try to handle IOC3 attached 16552 serials. Fix descriptor setup when # crossing a 16kB page. Use generic PCI API. Use generic ethtool code, # small cleanups, use a temporary kludge to exploit virtual device # functionality for significantly better performance. # # drivers/net/ioc3-eth.c # 2004/04/19 11:20:48-04:00 ralf@linux-mips.org +561 -802 # IOC3 updates # # drivers/net/Kconfig # 2004/04/11 23:42:10-04:00 ralf@linux-mips.org +21 -0 # IOC3 updates # # ChangeSet # 2004/04/21 21:52:14-04:00 ralf@linux-mips.org # [PATCH] sgiseeq fixes # # Resurrect into working order for 2.6. # # drivers/net/sgiseeq.c # 2004/04/11 23:46:46-04:00 ralf@linux-mips.org +102 -94 # sgiseeq fixes # # ChangeSet # 2004/04/21 21:52:06-04:00 ralf@linux-mips.org # [PATCH] BCM1250 network driver updates # # Resurrect into working order for 2.6. # # drivers/net/sb1250-mac.c # 2004/04/11 23:46:46-04:00 ralf@linux-mips.org +106 -110 # BCM1250 network driver updates # # ChangeSet # 2004/04/21 21:51:58-04:00 ralf@linux-mips.org # [PATCH] meth updates # # More work on the meth driver for SGI IP32 aka O2. # # drivers/net/meth.h # 2004/01/20 16:30:12-05:00 ralf@linux-mips.org +32 -59 # meth updates # # drivers/net/meth.c # 2004/03/10 23:32:41-05:00 ralf@linux-mips.org +425 -422 # meth updates # # ChangeSet # 2004/04/21 21:51:51-04:00 ralf@linux-mips.org # [PATCH] Remove RCS Id string # # drivers/net/bagetlance.c # 2004/04/11 23:42:10-04:00 ralf@linux-mips.org +1 -1 # Remove RCS Id string # # ChangeSet # 2004/04/21 21:51:43-04:00 ralf@linux-mips.org # [PATCH] Au1000 IrDA driver update # # Get to build under 2.6, random updates to debugging code, new eval boards. # # drivers/net/irda/au1k_ir.c # 2004/03/10 23:41:43-05:00 ralf@linux-mips.org +61 -49 # Au1000 IrDA driver update # # ChangeSet # 2004/04/21 21:00:25-04:00 akpm@osdl.org # [PATCH] pcmcia netdev ordering fixes # # From: Russell King # # This is an *untested* patch (PCMCIA people, please test) to fix # initialisation ordering issues in these network device drivers. I don't # have the hardware to be able to test these changes, although it passes a # modular build without warnings. # # Andrew - it may be worth sticking these in -mm so they get some visibility # via your tree as well. # # Many of these drivers were calling register_netdev() before they had # completed their initialisation. # # In addition, they were calling register_netdev with the # "DEV_CONFIG_PENDING" flag still set, which prevents hotplug scripts from # bringing up the interface. # # Also, we take care to ensure that link->dev is correctly set - this is used # to tell the PCMCIA release code if the netdev is currently registered (yes, # that's probably racy at present, but lets sort one problem at a time.) # # I've arranged that all drivers register the netdevice as close as possible # to the end of their initialisation, copy the net device's name for cardmgr # to pass to it's network scripts, and then print out whatever information # the driver wants to. # # Finally, a note about ibmtr - it seemed to assume that cardmgr wanted "tr0" # or "tr1" depending on the base address, and completely ignoring the real # device which the netdev layer allocated it. I've assumed that this is # wrong (since the netdev name is used in printk messages), and changed it to # behave the same as the other drivers. # # drivers/net/pcmcia/xirc2ps_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +8 -5 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/smc91c92_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +38 -25 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/nmclan_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +9 -6 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/ibmtr_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +6 -7 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/fmvj18x_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +10 -8 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/com20020_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +5 -8 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/axnet_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +15 -15 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/3c589_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +14 -12 # pcmcia-netdev-ordering-fixes.patch # # drivers/net/pcmcia/3c574_cs.c # 2004/03/07 20:26:49-05:00 akpm@osdl.org +23 -19 # pcmcia-netdev-ordering-fixes.patch # # ChangeSet # 2004/04/21 20:47:42-04:00 simon@thekelleys.org.uk # [PATCH] atmel wireless update # # Fixes to avoid problems when the driver shares an interrupt. These were # caused because the ISR cannot determine the status of the chip without # changing its state and the driver was only disabling the interrupts from # the card during some critical regions. An interrupt originating from # another device at the wrong moment could run the ISR and corrupt chip # state. Fixed by blocking interupts in the processor in critical regions # and never checking the chip interrupt status before the driver is fully # up. # # # Added the ability to override the Regulatory Domain stored in ROM. The # following command achieves this # # iwpriv regdomain # # vaild domains are USA,Canada,Europe,Spain,France,MKK,MKK1,Israel # # The current regulatory domain affects which radio channels are available # for use. # # # Some minor tidying to calibrate busy-wait loops using udelay and remove # inclusion of obsolete include/linux/802_11.h # # drivers/net/wireless/atmel_cs.c # 2004/04/14 15:08:30-04:00 simon@thekelleys.org.uk +3 -4 # atmel updated # # drivers/net/wireless/atmel.c # 2004/04/20 13:48:49-04:00 simon@thekelleys.org.uk +269 -208 # atmel updated # # ChangeSet # 2004/04/21 17:00:02-07:00 shemminger@osdl.org # [TCP]: Add sysctl to turn off matrics caching. # # net/ipv4/tcp_input.c # 2004/04/21 16:59:48-07:00 shemminger@osdl.org +4 -0 # [TCP]: Add sysctl to turn off matrics caching. # # net/ipv4/sysctl_net_ipv4.c # 2004/04/21 16:59:48-07:00 shemminger@osdl.org +9 -0 # [TCP]: Add sysctl to turn off matrics caching. # # include/net/tcp.h # 2004/04/21 16:59:48-07:00 shemminger@osdl.org +1 -0 # [TCP]: Add sysctl to turn off matrics caching. # # include/linux/sysctl.h # 2004/04/21 16:59:48-07:00 shemminger@osdl.org +1 -0 # [TCP]: Add sysctl to turn off matrics caching. # # ChangeSet # 2004/04/21 16:57:58-07:00 shemminger@osdl.org # [TCP]: Better packing of frto fields into tcp_opt. # # include/linux/tcp.h # 2004/04/21 16:57:43-07:00 shemminger@osdl.org +4 -3 # [TCP]: Better packing of frto fields into tcp_opt. # # ChangeSet # 2004/04/21 16:49:05-07:00 rusty@rustcorp.com.au # [NETFILTER]: Missing ip_rt_put in ipt_MASQUERADE. # # net/ipv4/netfilter/ipt_MASQUERADE.c # 2004/04/21 16:48:52-07:00 rusty@rustcorp.com.au +1 -0 # [NETFILTER]: Missing ip_rt_put in ipt_MASQUERADE. # # ChangeSet # 2004/04/21 16:45:18-07:00 chrisw@osdl.org # [IPV4]: Fix return value on MCAST_MSFILTER error case. # # net/ipv4/ip_sockglue.c # 2004/04/21 16:45:03-07:00 chrisw@osdl.org +1 -1 # [IPV4]: Fix return value on MCAST_MSFILTER error case. # # ChangeSet # 2004/04/21 16:23:05-07:00 jbglaw@lug-owl.de # [PATCH] lkkbd: Current version # # This updates the lkkbd driver to it's current version. # # It also incorporates two patches suggested on LKML (fixing # some leading whitespace and an unneccessary check). # # drivers/input/keyboard/lkkbd.c # 2004/04/21 05:33:59-07:00 jbglaw@lug-owl.de +127 -22 # lkkbd: Current version # # ChangeSet # 2004/04/21 16:22:53-07:00 jbglaw@lug-owl.de # [PATCH] New set of input patches # # This updates the vsxxx driver to it's current version. # # Even DEC tablet support (VSXXX-AB) is now tested - it works:) # You can even hotplug between mouse and digitizer... # # drivers/input/mouse/vsxxxaa.c # 2004/04/21 05:27:03-07:00 jbglaw@lug-owl.de +72 -58 # New set of input patches # # drivers/input/mouse/Kconfig # 2004/04/21 05:27:03-07:00 jbglaw@lug-owl.de +1 -1 # New set of input patches # # ChangeSet # 2004/04/21 16:22:42-07:00 sfr@canb.auug.org.au # [PATCH] PPC64 iSeries virtual ethernet fix # # This patch is needed due to other patches that were applied in parallel # with the inclusion of the iSeries virtual ethernet driver. # # drivers/net/iseries_veth.c # 2004/04/20 21:35:45-07:00 sfr@canb.auug.org.au +7 -7 # PPC64 iSeries virtual ethernet fix # # ChangeSet # 2004/04/21 16:16:05-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] removal of MOD_{INC,DEC}_USE_COUNT in ide-cs.c # # From: Pavel Roskin # # The "ide-cs" module cannot be unloaded because it uses obsolete # MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros. In fact, they are not # needed in ide-cs.c in 2.6 kernels. The generic PCMCIA code already # increases use count for every device served by the driver, so it's # impossible to unload the ide-cs driver while it's in use. # # I was told that the removal of IDE interfaces may be unsafe in 2.6 # kernels. However, MOD_INC_USE_COUNT only prevents removal of the module, # not the interface. It's also the first obstacle, albeit a trivial one, # for anybody debugging those problems (i.e. loading a modified module # requires "rmmod -f" or reboot to unload the old version). # # drivers/ide/legacy/ide-cs.c # 2004/04/20 11:30:34-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -2 # removal of MOD_{INC,DEC}_USE_COUNT in ide-cs.c # # ChangeSet # 2004/04/21 16:15:54-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] ide-probe.c: kill duplicate #include # # From: Arthur Othieno # # drivers/ide/ide-probe.c # 2004/04/20 11:45:01-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +0 -1 # ide-probe.c: kill duplicate #include # # ChangeSet # 2004/04/21 16:15:42-07:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] ide-disk.c: fix for IDE CF card ejection with devfs # # From: Pavel Roskin # # If I eject IDE CompactFlash card, I get a stack dump from # devfs_remove() because ide/host2/bus0/target0/lun0 doesn't exist. # # After del_gendisk() is called from idedisk_cleanup() drive->devfs_name refers # to a non-existent directory and should be erased, so that ide_unregister() # doesn't try to remove that directory again. # # drivers/ide/ide-disk.c # 2004/04/20 11:40:34-07:00 B.Zolnierkiewicz@elka.pw.edu.pl +1 -0 # ide-disk.c: fix for IDE CF card ejection with devfs # # ChangeSet # 2004/04/21 16:13:25-07:00 torvalds@ppc970.osdl.org # Merge bk://bk.arm.linux.org.uk/linux-2.6-serial # into ppc970.osdl.org:/home/torvalds/v2.6/linux # # drivers/serial/Kconfig # 2004/04/21 16:13:22-07:00 torvalds@ppc970.osdl.org +0 -0 # Auto merged # # ChangeSet # 2004/04/21 23:39:45+01:00 rmk@flint.arm.linux.org.uk # [SERIAL] Correct PL011 help text. # # drivers/serial/Kconfig # 2004/04/21 23:37:54+01:00 rmk@flint.arm.linux.org.uk +1 -1 # Correct PL011 help text. # # ChangeSet # 2004/04/21 23:33:52+01:00 rmk@flint.arm.linux.org.uk # [ARM] Add support for ARM Versatile platform. # # This cset adds minimal support for ARM Ltd's ARM926EJ-S "Versatile" # platform. # # include/asm-arm/arch-versatile/vmalloc.h # 2004/04/21 23:31:54+01:00 rmk@flint.arm.linux.org.uk +33 -0 # # include/asm-arm/arch-versatile/vmalloc.h # 2004/04/21 23:31:54+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/vmalloc.h # # include/asm-arm/arch-versatile/uncompress.h # 2004/04/21 23:31:48+01:00 rmk@flint.arm.linux.org.uk +54 -0 # # include/asm-arm/arch-versatile/uncompress.h # 2004/04/21 23:31:48+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/uncompress.h # # include/asm-arm/arch-versatile/timex.h # 2004/04/21 23:31:42+01:00 rmk@flint.arm.linux.org.uk +23 -0 # # include/asm-arm/arch-versatile/timex.h # 2004/04/21 23:31:42+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/timex.h # # include/asm-arm/arch-versatile/time.h # 2004/04/21 23:31:35+01:00 rmk@flint.arm.linux.org.uk +158 -0 # # include/asm-arm/arch-versatile/time.h # 2004/04/21 23:31:35+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/time.h # # include/asm-arm/arch-versatile/system.h # 2004/04/21 23:31:29+01:00 rmk@flint.arm.linux.org.uk +51 -0 # # include/asm-arm/arch-versatile/system.h # 2004/04/21 23:31:29+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/system.h # # include/asm-arm/arch-versatile/serial.h # 2004/04/21 23:31:23+01:00 rmk@flint.arm.linux.org.uk +37 -0 # # include/asm-arm/arch-versatile/serial.h # 2004/04/21 23:31:23+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/serial.h # # include/asm-arm/arch-versatile/platform.h # 2004/04/21 23:31:17+01:00 rmk@flint.arm.linux.org.uk +488 -0 # # include/asm-arm/arch-versatile/platform.h # 2004/04/21 23:31:17+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/platform.h # # include/asm-arm/arch-versatile/param.h # 2004/04/21 23:31:10+01:00 rmk@flint.arm.linux.org.uk +19 -0 # # include/asm-arm/arch-versatile/param.h # 2004/04/21 23:31:10+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/param.h # # include/asm-arm/arch-versatile/memory.h # 2004/04/21 23:31:04+01:00 rmk@flint.arm.linux.org.uk +61 -0 # # include/asm-arm/arch-versatile/memory.h # 2004/04/21 23:31:04+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/memory.h # # include/asm-arm/arch-versatile/irqs.h # 2004/04/21 23:30:58+01:00 rmk@flint.arm.linux.org.uk +211 -0 # # include/asm-arm/arch-versatile/irqs.h # 2004/04/21 23:30:58+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/irqs.h # # include/asm-arm/arch-versatile/io.h # 2004/04/21 23:30:50+01:00 rmk@flint.arm.linux.org.uk +29 -0 # # include/asm-arm/arch-versatile/io.h # 2004/04/21 23:30:50+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/io.h # # include/asm-arm/arch-versatile/hardware.h # 2004/04/21 23:30:39+01:00 rmk@flint.arm.linux.org.uk +45 -0 # # include/asm-arm/arch-versatile/hardware.h # 2004/04/21 23:30:39+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/hardware.h # # include/asm-arm/arch-versatile/dma.h # 2004/04/21 23:30:32+01:00 rmk@flint.arm.linux.org.uk +27 -0 # # include/asm-arm/arch-versatile/dma.h # 2004/04/21 23:30:32+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/include/asm-arm/arch-versatile/dma.h # # arch/arm/mach-versatile/core.c # 2004/04/21 23:30:20+01:00 rmk@flint.arm.linux.org.uk +507 -0 # # arch/arm/mach-versatile/core.c # 2004/04/21 23:30:20+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/arch/arm/mach-versatile/core.c # # arch/arm/mach-versatile/Makefile # 2004/04/21 23:30:08+01:00 rmk@flint.arm.linux.org.uk +5 -0 # # arch/arm/mm/Kconfig # 2004/04/21 23:30:08+01:00 rmk@flint.arm.linux.org.uk +3 -2 # Add support for ARM Versatile platform. # # arch/arm/mach-versatile/Makefile # 2004/04/21 23:30:08+01:00 rmk@flint.arm.linux.org.uk +0 -0 # BitKeeper file /usr/src/bk/linux-2.6-rmk/arch/arm/mach-versatile/Makefile # # arch/arm/kernel/entry-armv.S # 2004/04/21 23:30:08+01:00 rmk@flint.arm.linux.org.uk +31 -0 # Add support for ARM Versatile platform. # # arch/arm/kernel/debug.S # 2004/04/21 23:30:07+01:00 rmk@flint.arm.linux.org.uk +29 -0 # Add support for ARM Versatile platform. # # arch/arm/boot/Makefile # 2004/04/21 23:30:07+01:00 rmk@flint.arm.linux.org.uk +3 -0 # Add support for ARM Versatile platform. # # arch/arm/Makefile # 2004/04/21 23:30:07+01:00 rmk@flint.arm.linux.org.uk +1 -0 # Add support for ARM Versatile platform. # # arch/arm/Kconfig # 2004/04/21 23:30:06+01:00 rmk@flint.arm.linux.org.uk +10 -5 # Add support for ARM Versatile platform. # # ChangeSet # 2004/04/21 14:47:01-07:00 jakub@redhat.com # [PATCH] ia64: add mq support for ia64 # # # include/asm-ia64/unistd.h # 2004/04/15 01:26:53-07:00 jakub@redhat.com +6 -0 # ia64: add mq support for ia64 # # include/asm-ia64/ia32.h # 2004/04/15 01:34:49-07:00 jakub@redhat.com +1 -1 # ia64: add mq support for ia64 # # arch/ia64/kernel/fsys.S # 2004/04/15 01:38:34-07:00 jakub@redhat.com +6 -6 # ia64: add mq support for ia64 # # arch/ia64/kernel/entry.S # 2004/04/15 01:29:03-07:00 jakub@redhat.com +6 -6 # ia64: add mq support for ia64 # # arch/ia64/ia32/ia32_entry.S # 2004/04/15 01:32:46-07:00 jakub@redhat.com +8 -0 # ia64: add mq support for ia64 # # ChangeSet # 2004/04/21 14:26:14-07:00 davidm@tiger.hpl.hp.com # Merge tiger.hpl.hp.com:/data1/bk/vanilla/linux-2.5 # into tiger.hpl.hp.com:/data1/bk/lia64/to-linus-2.5 # # arch/ia64/pci/pci.c # 2004/04/21 14:26:09-07:00 davidm@tiger.hpl.hp.com +0 -0 # Auto merged # # arch/ia64/kernel/iosapic.c # 2004/04/21 14:26:09-07:00 davidm@tiger.hpl.hp.com +0 -0 # Auto merged # # ChangeSet # 2004/04/21 12:02:58-07:00 torvalds@ppc970.osdl.org # Revert fb_ioctl "fix" with extreme prejudice. # # As Arjan points out, the patch does exactly the opposite # of what it was claimed to do. # # Andrea: tssk tssk. # # Cset exclude: akpm@osdl.org[torvalds]|ChangeSet|20040421144431|15930 # # drivers/video/fbmem.c # 2004/04/21 12:02:56-07:00 torvalds@ppc970.osdl.org +0 -0 # Exclude # # ChangeSet # 2004/04/21 19:49:59+01:00 davej@redhat.com # [CPUFREQ] Fix security hole in proc handler. # Brad Spengler found an exploitable bug in the proc handler # of cpufreq, where a user-supplied unsigned int is cast to a signed int and then # passed on to copy_[to|from]_user() allowing arbitary amounts of memory to be written # (root only thankfully), or read (as any user). # # The Common Vulnerabilities and Exposures project (cve.mitre.org) has assigned # the name CAN-2004-0228 to this issue. # # drivers/cpufreq/cpufreq_userspace.c # 2004/04/21 19:49:53+01:00 davej@redhat.com +1 -1 # [CPUFREQ] Fix security hole in proc handler. # Brad Spengler found an exploitable bug in the proc handler # of cpufreq, where a user-supplied unsigned int is cast to a signed int and then # passed on to copy_[to|from]_user() allowing arbitary amounts of memory to be written # (root only thankfully), or read (as any user). # # The Common Vulnerabilities and Exposures project (cve.mitre.org) has assigned # the name CAN-2004-0228 to this issue. # # ChangeSet # 2004/04/21 19:20:17+01:00 davej@redhat.com # [CPUFREQ] Export an array of acpi driver supported frequencies in sysfs # From Dominik. # # arch/i386/kernel/cpu/cpufreq/acpi.c # 2004/04/21 19:20:11+01:00 davej@redhat.com +9 -1 # [CPUFREQ] Export an array of acpi driver supported frequencies in sysfs # From Dominik. # # ChangeSet # 2004/04/21 19:18:57+01:00 davej@redhat.com # [CPUFREQ] Make an educated guess at the current P-state in the ACPI driver. # One big limitation of the ACPI specification is that it's impossible to # detect the current P-State by reading from ACPI-defined registers. And the # CPU isn't always at P0 when the system boots. So, try to "guess" the current # P-State by analyzing cpu_khz. # # From Dominik. # # arch/i386/kernel/cpu/cpufreq/acpi.c # 2004/04/21 19:18:50+01:00 davej@redhat.com +30 -5 # [CPUFREQ] Make an educated guess at the current P-state in the ACPI driver. # One big limitation of the ACPI specification is that it's impossible to # detect the current P-State by reading from ACPI-defined registers. And the # CPU isn't always at P0 when the system boots. So, try to "guess" the current # P-State by analyzing cpu_khz. # # From Dominik. # # ChangeSet # 2004/04/21 17:58:29+01:00 davej@redhat.com # [CPUFREQ] Remove redundant part of powernow-k7 module parm # If used as a bootparam, this would've become powernow-k7.powernow_acpi_force which looks silly. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/21 17:58:22+01:00 davej@redhat.com +1 -1 # [CPUFREQ] Remove redundant part of powernow-k7 module parm # If used as a bootparam, this would've become powernow-k7.powernow_acpi_force which looks silly. # # ChangeSet # 2004/04/21 17:07:29+01:00 davej@redhat.com # [CPUFREQ] Fix unbalanced try_get_module/put_module # Spotted by Charles Coffing # # drivers/cpufreq/cpufreq.c # 2004/04/21 17:07:23+01:00 davej@redhat.com +8 -4 # [CPUFREQ] Fix unbalanced try_get_module/put_module # Spotted by Charles Coffing # # ChangeSet # 2004/04/21 07:44:58-07:00 akpm@osdl.org # [PATCH] loop_set_fd() sendfile check fix # # From: Yury Umanets # # I have found small inconsistency in loop_set_fd(). It checks if # ->sendfile() is implemented for passed block device file. But in fact, # loop back device driver never calls it. It uses ->sendfile() from backing # store file. # # drivers/block/loop.c # 2004/04/21 02:15:37-07:00 akpm@osdl.org +1 -1 # loop_set_fd() sendfile check fix # # ChangeSet # 2004/04/21 07:44:44-07:00 akpm@osdl.org # [PATCH] i386 hugetlb tlb correction # # From: William Lee Irwin III # # i386 does hardware interpretation of pagetables, so pte_clear() can't be # used on present ptes, as it sets the upper half of the hugepte prior to # setting the lower half (which includes the valid bit). i.e. there is a # window where having a hugepage mapped at 56GB and doing pte_clear() in # unmap_hugepage_range() allows other threads of the process to see a # hugepage at 0 in place of the original hugepage at 56GB. # # This patch corrects the situation by using ptep_get_and_clear(), which # clears the lower word of the pte prior to clearing the upper word. # # There is another nasty where huge_page_release() needs to wait for TLB # flushes before returning the hugepages to the free pool, analogous to the # issue tlb_remove_page() and tlb_flush_mm() repair. # # arch/i386/mm/hugetlbpage.c # 2004/04/21 02:15:17-07:00 akpm@osdl.org +4 -5 # i386 hugetlb tlb correction # # ChangeSet # 2004/04/21 07:44:18-07:00 akpm@osdl.org # [PATCH] i810_dma range check # # From: Andrea Arcangeli # # Correctly range-check an incoming-from-userspace argument. Found by the # Stanford checker. # # drivers/char/drm/i810_dma.c # 2004/04/21 02:15:15-07:00 akpm@osdl.org +3 -0 # i810_dma range check # # ChangeSet # 2004/04/21 07:44:05-07:00 akpm@osdl.org # [PATCH] selinux: remove hardcoded policy assumption from get_user_sids() logic # # From: Stephen Smalley # # This patch removes a hardcoded policy assumption from the get_user_sids logic # in the SELinux module that was preventing it from returning contexts that had # the same type as the caller even if the policy allowed such a transition. The # assumption is not valid for all policies, and can be handled via policy # configuration and userspace rather than hardcoding it in the module logic. # # security/selinux/ss/services.c # 2004/04/21 02:15:15-07:00 akpm@osdl.org +0 -2 # selinux: remove hardcoded policy assumption from get_user_sids() logic # # ChangeSet # 2004/04/21 07:43:53-07:00 akpm@osdl.org # [PATCH] selinux: add runtime disable # # From: Stephen Smalley # # This patch adds a kernel configuration option that enables writing to a new # selinuxfs node 'disable' that allows SELinux to be disabled at runtime prior # to initial policy load. SELinux will then remain disabled until next boot. # This option is similar to the selinux=0 boot parameter, but is to support # runtime disabling of SELinux, e.g. from /sbin/init, for portability across # platforms where boot parameters are difficult to employ (based on feedback by # Jeremy Katz). # # security/selinux/selinuxfs.c # 2004/04/21 02:15:14-07:00 akpm@osdl.org +60 -2 # selinux: add runtime disable # # security/selinux/hooks.c # 2004/04/21 02:15:14-07:00 akpm@osdl.org +53 -0 # selinux: add runtime disable # # security/selinux/Kconfig # 2004/04/21 02:15:14-07:00 akpm@osdl.org +15 -0 # selinux: add runtime disable # # ChangeSet # 2004/04/21 07:43:42-07:00 akpm@osdl.org # [PATCH] selinux: change context_to_sid handling for no-policy case # # From: Stephen Smalley # # This patch changes the behavior of security_context_to_sid in the no-policy # case so that it simply accepts all contexts and maps them to the kernel SID # rather than rejecting anything other than an initial SID. The change avoids # error conditions when using SELinux in permissive/no-policy mode, so that any # file contexts left on disk from prior use of SELinux with a policy will not # cause an error when they are looked up and userspace attempts to set contexts # can succeed. # # security/selinux/ss/services.c # 2004/04/21 02:20:45-07:00 akpm@osdl.org +1 -3 # selinux: change context_to_sid handling for no-policy case # # ChangeSet # 2004/04/21 07:43:30-07:00 akpm@osdl.org # [PATCH] i4l: add compat ioctl's for CAPI # # From: Marcel Holtmann # # This patch adds the needed compat ioctl's for the CAPI on 64bit platforms. # # include/linux/compat_ioctl.h # 2004/04/21 02:15:11-07:00 akpm@osdl.org +15 -1 # i4l: add compat ioctl's for CAPI # # fs/compat_ioctl.c # 2004/04/21 02:15:11-07:00 akpm@osdl.org +3 -1 # i4l: add compat ioctl's for CAPI # # ChangeSet # 2004/04/21 07:43:17-07:00 akpm@osdl.org # [PATCH] lockfs - dm bits # # From: Christoph Hellwig # # This patch makes the device mapper use the new freeze_bdev/thaw_bdev # interface. Extracted from Chris Mason's patch. # # drivers/md/dm.c # 2004/04/21 02:13:50-07:00 akpm@osdl.org +70 -1 # lockfs - dm bits # # ChangeSet # 2004/04/21 07:43:05-07:00 akpm@osdl.org # [PATCH] lockfs - xfs bits # # From: Christoph Hellwig # # Remove all the code now in the VFS, make XFS's freeze ioctls use the new # infastructure and reorganize some code. # # This code needs some work so the source files shared with 2.4 aren't # exposed to the new VFS interfaces directly. You'll get an update once this # has been discussed with the other XFS developers and is implemented. Note # that the current patch works fine and I wouldn't complain if it gets into # Linus' tree as-is. # # fs/xfs/xfs_vfsops.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +15 -0 # lockfs - xfs bits # # fs/xfs/xfs_trans.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +3 -1 # lockfs - xfs bits # # fs/xfs/xfs_mount.h # 2004/04/21 02:13:46-07:00 akpm@osdl.org +0 -14 # lockfs - xfs bits # # fs/xfs/xfs_mount.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +0 -61 # lockfs - xfs bits # # fs/xfs/xfs_log.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +1 -1 # lockfs - xfs bits # # fs/xfs/xfs_fsops.h # 2004/04/21 02:13:46-07:00 akpm@osdl.org +0 -8 # lockfs - xfs bits # # fs/xfs/xfs_fsops.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +14 -52 # lockfs - xfs bits # # fs/xfs/linux/xfs_vfs.h # 2004/04/21 02:13:46-07:00 akpm@osdl.org +5 -0 # lockfs - xfs bits # # fs/xfs/linux/xfs_vfs.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +12 -0 # lockfs - xfs bits # # fs/xfs/linux/xfs_super.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +1 -23 # lockfs - xfs bits # # fs/xfs/linux/xfs_lrw.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +0 -2 # lockfs - xfs bits # # fs/xfs/linux/xfs_ioctl.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +3 -2 # lockfs - xfs bits # # ChangeSet # 2004/04/21 07:42:53-07:00 akpm@osdl.org # [PATCH] lockfs: reiserfs fix # # From: Chris Mason # # reiserfs_write_super_lockfs() is supposed to wait for the transaction to # commit. # # fs/reiserfs/super.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +1 -1 # lockfs: reiserfs fix # # ChangeSet # 2004/04/21 07:42:39-07:00 akpm@osdl.org # [PATCH] lockfs - vfs bits # # From: Christoph Hellwig # # These are the generic lockfs bits. Basically it takes the XFS freezing # statemachine into the VFS. It's all behind the kernel-doc documented # freeze_bdev and thaw_bdev interfaces. # # Based on an older patch from Chris Mason. # # include/linux/fs.h # 2004/04/21 02:13:46-07:00 akpm@osdl.org +16 -0 # lockfs - vfs bits # # include/linux/buffer_head.h # 2004/04/21 02:13:46-07:00 akpm@osdl.org +2 -0 # lockfs - vfs bits # # fs/super.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +8 -0 # lockfs - vfs bits # # fs/buffer.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +71 -0 # lockfs - vfs bits # # fs/block_dev.c # 2004/04/21 02:13:46-07:00 akpm@osdl.org +1 -0 # lockfs - vfs bits # # ChangeSet # 2004/04/21 07:42:28-07:00 akpm@osdl.org # [PATCH] remove amd7xx_tco # # From: Zwane Mwaikambo # # We've had trouble with this driver, it appears to work but the hardware # never does the final reboot. I have yet to come across someone with a # board which works and don't have personal access to one. So how about # scrapping the whole thing. # # drivers/char/watchdog/Makefile # 2004/04/21 02:13:46-07:00 akpm@osdl.org +0 -1 # remove amd7xx_tco # # drivers/char/watchdog/Kconfig # 2004/04/21 02:13:46-07:00 akpm@osdl.org +0 -13 # remove amd7xx_tco # # BitKeeper/deleted/.del-amd7xx_tco.c~64cd2de85782ffa2 # 2004/04/21 07:42:23-07:00 akpm@osdl.org +0 -0 # Delete: drivers/char/watchdog/amd7xx_tco.c # # ChangeSet # 2004/04/21 07:42:18-07:00 akpm@osdl.org # [PATCH] Call populate_rootfs later in boot # # populate_rootfs() is called rather early - before we've called init_idle(). # # But populate_rootfs() does file I/O, which involves calls to cond_resched(), # and downing of semaphores, etc. If it scheules, the scheduler emits # scheduling-while-atomic warnings and sometimes oopses. # # So run populate_rootfs() later, after the scheduler is all set up. # # init/main.c # 2004/04/21 02:13:45-07:00 akpm@osdl.org +10 -11 # Call populate_rootfs later in boot # # ChangeSet # 2004/04/21 07:42:05-07:00 akpm@osdl.org # [PATCH] ext3 avoid writing kernel memory to disk # # From: Marc-Christian Petersen # # Solar Designer discovered an information leak in the ext3 code of Linux. # In a worst case an attacker could read sensitive data such as cryptographic # keys which would otherwise never hit disk media. Theodore Ts'o developed a # correction for this. # # fs/jbd/journal.c # 2004/04/21 02:13:45-07:00 akpm@osdl.org +1 -0 # ext3 avoid writing kernel memory to disk # # ChangeSet # 2004/04/21 07:41:53-07:00 akpm@osdl.org # [PATCH] compute_creds race # # From: Andy Lutomirski # # Fixes from me, Olaf Dietsche # # In fs/exec.c, compute_creds does: # # task_lock(current); # if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { # current->mm->dumpable = 0; # # if (must_not_trace_exec(current) # || atomic_read(¤t->fs->count) > 1 # || atomic_read(¤t->files->count) > 1 # || atomic_read(¤t->sighand->count) > 1) { # if(!capable(CAP_SETUID)) { # bprm->e_uid = current->uid; # bprm->e_gid = current->gid; # } # } # } # # current->suid = current->euid = current->fsuid = bprm->e_uid; # current->sgid = current->egid = current->fsgid = bprm->e_gid; # # task_unlock(current); # # security_bprm_compute_creds(bprm); # # I assume the task_lock is to prevent another process (on SMP or preempt) # from ptracing the execing process between the check and the assignment. If # that's the concern then the fact that the lock is dropped before the call # to security_brpm_compute_creds means that, if security_bprm_compute_creds # does anything interesting, there's a race. # # For my (nearly complete) caps patch, I obviously need to fix this. But I # think it may be exploitable now. Suppose there are two processes, A (the # malicious code) and B (which uses exec). B starts out unprivileged (A and # B have, e.g., uid and euid = 500). # # 1. A ptraces B. # # 2. B calls exec on some setuid-root program. # # 3. in cap_bprm_set_security, B sets bprm->cap_permitted to the full # set. # # 4. B gets to compute_creds in exec.c, calls task_lock, and does not # change its uid. # # 5. B calls task_unlock. # # 6. A detaches from B (on preempt or SMP). # # 7. B gets to task_lock in cap_bprm_compute_creds, changes its # capabilities, and returns from compute_creds into load_elf_binary. # # 8. load_elf_binary calls create_elf_tables (line 852 in 2.6.5-mm1), # which calls cap_bprm_secureexec (through LSM), which returns false (!). # # 9. exec finishes. # # The setuid program is now running with uid=euid=500 but full permitted # capabilities. There are two (or three) ways to effectively get local root # now: # # 1. IIRC, linux 2.4 doesn't check capabilities in ptrace, so A could # just ptrace B again. # # 2. LD_PRELOAD. # # 3. There are probably programs that will misbehave on their own under # these circumstances. # # Is there some reason why this is not doable? # # The patch renames bprm_compute_creds to bprm_apply_creds and moves all uid # logic into the hook, where the test and the resulting modification can both # happen under task_lock(). # # This way, out-of-tree LSMs will fail to compile instead of malfunctioning. # It should also make life easier for LSMs and will certainly make it easier # for me to finish the cap patch. # # security/selinux/hooks.c # 2004/04/21 02:20:45-07:00 akpm@osdl.org +4 -4 # compute_creds race # # security/root_plug.c # 2004/04/21 02:12:01-07:00 akpm@osdl.org +1 -1 # compute_creds race # # security/dummy.c # 2004/04/21 02:12:12-07:00 akpm@osdl.org +27 -4 # compute_creds race # # security/commoncap.c # 2004/04/21 02:12:12-07:00 akpm@osdl.org +24 -14 # compute_creds race # # security/capability.c # 2004/04/21 02:11:57-07:00 akpm@osdl.org +1 -1 # compute_creds race # # include/linux/security.h # 2004/04/21 02:11:57-07:00 akpm@osdl.org +9 -9 # compute_creds race # # fs/exec.c # 2004/04/21 02:11:57-07:00 akpm@osdl.org +1 -30 # compute_creds race # # ChangeSet # 2004/04/21 07:41:40-07:00 akpm@osdl.org # [PATCH] Fix nfsroot option handling # # From: Trond Myklebust # # The following patch fixes up a number of bugs in the NFSroot parser # rewrite from patchset # trond.myklebust@fys.uio.no|ChangeSet|20040411182341|00938 # # It also ensures that NFSroot mount options are consistent with the userland # "mount" program. # # fs/nfs/nfsroot.c # 2004/04/21 02:11:54-07:00 akpm@osdl.org +19 -11 # Fix nfsroot option handling # # ChangeSet # 2004/04/21 07:24:51-07:00 drepper@redhat.com # [PATCH] Add missing __initdata # # One of the stack size optimizations introduced a new static variable in # a function marked with __init. But the variable is not marked # appropriately and so 1k of data is never freed. # # fs/nfs/nfsroot.c # 2004/04/21 06:48:23-07:00 drepper@redhat.com +1 -1 # Add missing __initdata # # ChangeSet # 2004/04/20 11:06:13-07:00 jakub@redhat.com # [SPARC64]: Missing part of posix timers fix. # # include/asm-sparc64/siginfo.h # 2004/04/20 11:06:00-07:00 jakub@redhat.com +4 -2 # [SPARC64]: Missing part of posix timers fix. # # ChangeSet # 2004/04/20 12:31:50-05:00 stevef@stevef95.austin.ibm.com # Do not cache inode metadata when cache time set to 0 (fix hardlink count caching) # # fs/cifs/inode.c # 2004/04/20 12:31:36-05:00 stevef@stevef95.austin.ibm.com +4 -2 # Do not cache inode metadata when cache time set to 0 (fix hardlink count caching) # # fs/cifs/CHANGES # 2004/04/20 12:31:36-05:00 stevef@stevef95.austin.ibm.com +3 -1 # Update change log for cifs version 1.09 # # ChangeSet # 2004/04/20 09:56:50-07:00 jakub@redhat.com # [SPARC64]: Fix 32-bit posix timers. # # arch/sparc64/kernel/signal32.c # 2004/04/20 09:56:37-07:00 jakub@redhat.com +5 -0 # [SPARC64]: Fix 32-bit posix timers. # # ChangeSet # 2004/04/20 15:58:21+01:00 rmk@flint.arm.linux.org.uk # [ARM] Add find_first_bit and find_next_bit. # # include/asm-arm/bitops.h # 2004/04/20 15:56:33+01:00 rmk@flint.arm.linux.org.uk +8 -1 # Add find_first_bit and find_next_bit # # arch/arm/lib/findbit.S # 2004/04/20 15:56:33+01:00 rmk@flint.arm.linux.org.uk +57 -0 # Add BE and LE find_first_bit/find_next_bit implementations. # # ChangeSet # 2004/04/19 22:16:40-07:00 davem@nuts.davemloft.net # Merge http://linux-lksctp.bkbits.net/lksctp-2.5.work # into nuts.davemloft.net:/disk1/BK/net-2.6 # # net/sctp/socket.c # 2004/04/19 22:16:30-07:00 davem@nuts.davemloft.net +0 -0 # Auto merged # # include/linux/sysctl.h # 2004/04/19 22:16:30-07:00 davem@nuts.davemloft.net +0 -0 # Auto merged # # ChangeSet # 2004/04/19 14:31:26-05:00 stevef@stevef95.austin.ibm.com # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/fcntl.c # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +97 -0 # # fs/cifs/fcntl.c # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +0 -0 # BitKeeper file /usr/src/bk/linux-2.5cifs/fs/cifs/fcntl.c # # fs/cifs/cifsfs.h # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +1 -0 # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/cifsfs.c # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +7 -1 # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/Makefile # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +1 -1 # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/CHANGES # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +5 -0 # Update change log for cifs version 1.09 # # ChangeSet # 2004/04/19 11:26:22-07:00 sri@us.ibm.com # [SCTP] Propagate error from sctp_proc_init. (Olaf Kirch) # # net/sctp/protocol.c # 2004/04/19 11:26:03-07:00 sri@us.ibm.com +4 -1 # [SCTP] Propagate error from sctp_proc_init. (Olaf Kirch) # # ChangeSet # 2004/04/19 10:58:26-07:00 sri@us.ibm.com # [SCTP] Partial Reliability Extension support. # # net/sctp/ulpqueue.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +65 -0 # [SCTP] Partial Reliability Extension support. # # net/sctp/tsnmap.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +36 -1 # [SCTP] Partial Reliability Extension support. # # net/sctp/sysctl.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +10 -1 # [SCTP] Partial Reliability Extension support. # # net/sctp/sm_statetable.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +37 -3 # [SCTP] Partial Reliability Extension support. # # net/sctp/sm_statefuns.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +137 -0 # [SCTP] Partial Reliability Extension support. # # net/sctp/sm_sideeffect.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +27 -2 # [SCTP] Partial Reliability Extension support. # # net/sctp/sm_make_chunk.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +67 -9 # [SCTP] Partial Reliability Extension support. # # net/sctp/protocol.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +3 -0 # [SCTP] Partial Reliability Extension support. # # net/sctp/outqueue.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +189 -35 # [SCTP] Partial Reliability Extension support. # # net/sctp/output.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +3 -1 # [SCTP] Partial Reliability Extension support. # # net/sctp/debug.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +5 -1 # [SCTP] Partial Reliability Extension support. # # net/sctp/chunk.c # 2004/04/19 10:58:09-07:00 sri@us.ibm.com +12 -15 # [SCTP] Partial Reliability Extension support. # # net/sctp/associola.c # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +3 -0 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/ulpqueue.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +5 -1 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/tsnmap.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +5 -1 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/structs.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +42 -23 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/sm.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +7 -20 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/sctp.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +8 -0 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/constants.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +3 -1 # [SCTP] Partial Reliability Extension support. # # include/net/sctp/command.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +4 -1 # [SCTP] Partial Reliability Extension support. # # include/linux/sysctl.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +1 -2 # [SCTP] Partial Reliability Extension support. # # include/linux/sctp.h # 2004/04/19 10:58:08-07:00 sri@us.ibm.com +67 -3 # [SCTP] Partial Reliability Extension support. # # ChangeSet # 2004/04/19 10:46:21-07:00 sri@us.ibm.com # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # net/sctp/transport.c # 2004/04/19 10:46:03-07:00 sri@us.ibm.com +2 -1 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # net/sctp/sm_statefuns.c # 2004/04/19 10:46:03-07:00 sri@us.ibm.com +2 -11 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # net/sctp/outqueue.c # 2004/04/19 10:46:03-07:00 sri@us.ibm.com +29 -56 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # net/sctp/output.c # 2004/04/19 10:46:03-07:00 sri@us.ibm.com +30 -35 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # net/sctp/associola.c # 2004/04/19 10:46:03-07:00 sri@us.ibm.com +2 -10 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # include/net/sctp/structs.h # 2004/04/19 10:46:03-07:00 sri@us.ibm.com +9 -47 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # include/net/sctp/constants.h # 2004/04/19 10:46:02-07:00 sri@us.ibm.com +0 -1 # [SCTP] Cleanup sctp_packet and sctp_outq infrastructure. # # ChangeSet # 2004/04/19 10:36:56-07:00 sri@us.ibm.com # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # net/sctp/ulpevent.c # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +8 -0 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # net/sctp/socket.c # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +12 -5 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # net/sctp/outqueue.c # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +1 -1 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # net/sctp/output.c # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +19 -14 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # net/sctp/chunk.c # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +1 -16 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # include/net/sctp/structs.h # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +7 -0 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # include/net/sctp/sctp.h # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +5 -2 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # include/net/sctp/constants.h # 2004/04/19 10:36:38-07:00 sri@us.ibm.com +0 -9 # [SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the # max data size in a SCTP packet. # # Calculate the overhead based on the socket's protocol family header # length. # # ChangeSet # 2004/04/19 12:18:17-05:00 stevef@stevef95.austin.ibm.com # Remove "badness in remove_proc_entry" warning logged on module unload of cifs # # fs/cifs/cifs_debug.c # 2004/04/19 12:17:17-05:00 stevef@stevef95.austin.ibm.com +1 -1 # Remove "badness in remove_proc_entry" warning logged on module unload of cifs # # ChangeSet # 2004/04/19 09:23:44+01:00 davej@redhat.com # [CPUFREQ] Fix broken cast. # This breaks on x86-64 with the following warning. # # drivers/cpufreq/cpufreq_userspace.c: In function `cpufreq_procctl': # drivers/cpufreq/cpufreq_userspace.c:170: warning: cast from pointer to integer of different size # drivers/cpufreq/cpufreq_userspace.c: In function `cpufreq_sysctl': # drivers/cpufreq/cpufreq_userspace.c:208: warning: cast from pointer to integer of different size # # drivers/cpufreq/cpufreq_userspace.c # 2004/04/19 09:23:38+01:00 davej@redhat.com +2 -2 # [CPUFREQ] Fix broken cast. # This breaks on x86-64 with the following warning. # # drivers/cpufreq/cpufreq_userspace.c: In function `cpufreq_procctl': # drivers/cpufreq/cpufreq_userspace.c:170: warning: cast from pointer to integer of different size # drivers/cpufreq/cpufreq_userspace.c: In function `cpufreq_sysctl': # drivers/cpufreq/cpufreq_userspace.c:208: warning: cast from pointer to integer of different size # # ChangeSet # 2004/04/19 09:20:19+01:00 davej@redhat.com # [CPUFREQ] Fix up missing CONFIG_X86_POWERNOW_K8_ACPI # We don't need this, we can infer from CONFIG_ACPI_PROCESSOR # # arch/i386/kernel/cpu/cpufreq/powernow-k8.h # 2004/04/19 09:20:13+01:00 davej@redhat.com +1 -1 # [CPUFREQ] Fix up missing CONFIG_X86_POWERNOW_K8_ACPI # We don't need this, we can infer from CONFIG_ACPI_PROCESSOR # # arch/i386/kernel/cpu/cpufreq/powernow-k8.c # 2004/04/19 09:20:13+01:00 davej@redhat.com +2 -2 # [CPUFREQ] Fix up missing CONFIG_X86_POWERNOW_K8_ACPI # We don't need this, we can infer from CONFIG_ACPI_PROCESSOR # # ChangeSet # 2004/04/19 08:08:52+01:00 davej@redhat.com # [CPUFREQ] Fix debug build of powernow-k8 # From Paul Devriendt # # arch/i386/kernel/cpu/cpufreq/powernow-k8.c # 2004/04/19 08:08:46+01:00 davej@redhat.com +1 -1 # [CPUFREQ] Fix debug build of powernow-k8 # From Paul Devriendt # # ChangeSet # 2004/04/16 17:32:36-07:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/cifsfs.c # 2004/04/16 17:32:30-07:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/04/16 13:37:58-07:00 mbp@vexed.ozlabs.hp.com # [PATCH] ia64: fpswa_interface needs to be exported # # efivars can be built as a module, but it depends on 'fpswa_interface' # which is not exported by fpswa.c. Patch below fixes this problem. # # arch/ia64/kernel/traps.c # 2004/04/14 23:18:55-07:00 mbp@vexed.ozlabs.hp.com +2 -0 # ia64: fpswa_interface needs to be exported # # ChangeSet # 2004/04/16 11:20:24-05:00 stevef@stevef95.austin.ibm.com # Remove 64 bit compiler warning # # fs/cifs/cifsfs.c # 2004/04/16 11:20:02-05:00 stevef@stevef95.austin.ibm.com +2 -2 # Remove 64 bit compiler warning # # ChangeSet # 2004/04/16 16:41:34+01:00 davej@redhat.com # [CPUFREQ] Not all powernow-K7 BIOS's put the frequency at MAX at POST. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/16 16:41:26+01:00 davej@redhat.com +1 -1 # [CPUFREQ] Not all powernow-K7 BIOS's put the frequency at MAX at POST. # # ChangeSet # 2004/04/15 22:17:31-05:00 stevef@smfhome.smfdom # check permission locally for servers that do not support the CIFS Unix Extensions (allowing file_mode and dir_mode to augment the # server permission check, by doing local vfs_permission check) # # fs/cifs/connect.c # 2004/04/15 22:14:00-05:00 stevef@smfhome.smfdom +3 -1 # Fix multiple mount problem (mount to same server) temporarily introduced when compiler warning removed from cifs_mount # # fs/cifs/cifsfs.c # 2004/04/15 22:14:00-05:00 stevef@smfhome.smfdom +15 -2 # check permission locally for servers that do not support the CIFS Unix Extensions (allowing file_mode and dir_mode to augment the # server permission check, by doing local vfs_permission check) # # fs/cifs/CHANGES # 2004/04/15 22:14:00-05:00 stevef@smfhome.smfdom +7 -0 # update change log for cifs version 1.08 # # ChangeSet # 2004/04/15 17:51:05-05:00 stevef@stevef95.austin.ibm.com # Fix major page leak in read code caused by extra page_cache_get call # # fs/cifs/netmisc.c # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +11 -5 # remove ipv6 compiler warning # # fs/cifs/file.c # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +7 -9 # Fix major page leak in read code caused by extra page_cache_get call # # fs/cifs/connect.c # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +18 -2 # remove ipv6 compiler warning # # fs/cifs/CHANGES # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +3 -1 # Update change log for cifs 1.07a # # ChangeSet # 2004/04/14 16:45:54-05:00 stevef@stevef95.austin.ibm.com # free cifs read buffer on retry # # fs/cifs/file.c # 2004/04/14 16:45:39-05:00 stevef@stevef95.austin.ibm.com +6 -0 # free buffer on retry # # ChangeSet # 2004/04/14 22:26:47+01:00 davej@redhat.com # [CPUFREQ] clear defaults before powernow-k7 acpi fallback # Decoding the legacy tables may have set these values. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 22:26:42+01:00 davej@redhat.com +3 -0 # [CPUFREQ] clear defaults before powernow-k7 acpi fallback # Decoding the legacy tables may have set these values. # # ChangeSet # 2004/04/14 22:22:30+01:00 davej@redhat.com # [CPUFREQ] powernow-k7 ACPI->PST values were a factor of 10 off. # As much as I like the idea of a 13GHz laptop, setting it to 1.3GHz is probably # for the best for the time being. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 22:22:22+01:00 davej@redhat.com +1 -1 # [CPUFREQ] powernow-k7 ACPI->PST values were a factor of 10 off. # As much as I like the idea of a 13GHz laptop, setting it to 1.3GHz is probably # for the best for the time being. # # ChangeSet # 2004/04/14 22:20:31+01:00 davej@redhat.com # [CPUFREQ] Make powernow-k7 acpi debug output a little less verbose. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 22:20:25+01:00 davej@redhat.com +1 -4 # [CPUFREQ] Make powernow-k7 acpi debug output a little less verbose. # # ChangeSet # 2004/04/14 16:19:59-05:00 stevef@stevef95.austin.ibm.com # Fix misc. minor memory leaks in error paths # # fs/cifs/link.c # 2004/04/14 16:19:51-05:00 stevef@stevef95.austin.ibm.com +7 -2 # Fix misc. minor memory leaks in error paths # # fs/cifs/inode.c # 2004/04/14 16:19:51-05:00 stevef@stevef95.austin.ibm.com +11 -11 # white space cleanup # # fs/cifs/file.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +10 -10 # Fix misc. minor memory leaks in error paths # # fs/cifs/connect.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +45 -4 # Fix misc. minor memory leaks in error paths # # fs/cifs/cifssmb.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +27 -27 # white space cleanup # # fs/cifs/cifsfs.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +4 -3 # Fix misc. minor memory leaks in error paths # # fs/cifs/CHANGES # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +4 -0 # Fix misc. minor memory leaks in error paths # # ChangeSet # 2004/04/14 22:18:39+01:00 davej@redhat.com # [CPUFREQ] Add a module parameter to force ACPI to be used. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 22:18:33+01:00 davej@redhat.com +12 -1 # [CPUFREQ] Add a module parameter to force ACPI to be used. # # ChangeSet # 2004/04/14 18:21:08+01:00 davej@redhat.com # [CPUFREQ] Remove bogus newline in powernow-k7 driver. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 18:21:02+01:00 davej@redhat.com +0 -2 # [CPUFREQ] Remove bogus newline in powernow-k7 driver. # # ChangeSet # 2004/04/14 15:15:56+01:00 davej@redhat.com # [CPUFREQ] powernow-k7 needs to init later. # Due to the possible dependancy on ACPI. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 15:15:50+01:00 davej@redhat.com +1 -1 # [CPUFREQ] powernow-k7 needs to init later. # Due to the possible dependancy on ACPI. # # ChangeSet # 2004/04/14 15:14:35+01:00 davej@redhat.com # [CPUFREQ] Drop unneeded part of last patch. # acpi fallback is handled already in the init function. # # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 15:14:29+01:00 davej@redhat.com +6 -7 # [CPUFREQ] Drop unneeded part of last patch. # acpi fallback is handled already in the init function. # # # ChangeSet # 2004/04/14 13:26:15+01:00 davej@redhat.com # [CPUFREQ] powernow-k7 ACPI integration. # More from Bruno Ducrot. # # Warning: it will only half work on the ACER Aspire, though: there is # no pstate in the DSDT corresponding to the max frequency... # I'm looking how to handle that correctly, probably at the init stage, # if the max frequency is not given, then add it to powernow_table. # # * Integrate acpi perflib from Dominik. # * Use acpi if the PST tables are known to be broken (ASUS Aspire match one PST, # but give brain damaged values), or use ACPI if no PST found. # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 13:26:09+01:00 davej@redhat.com +168 -12 # [CPUFREQ] powernow-k7 ACPI integration. # More from Bruno Ducrot. # # Warning: it will only half work on the ACER Aspire, though: there is # no pstate in the DSDT corresponding to the max frequency... # I'm looking how to handle that correctly, probably at the init stage, # if the max frequency is not given, then add it to powernow_table. # # * Integrate acpi perflib from Dominik. # * Use acpi if the PST tables are known to be broken (ASUS Aspire match one PST, # but give brain damaged values), or use ACPI if no PST found. # # ChangeSet # 2004/04/14 12:22:15+01:00 davej@redhat.com # [CPUFREQ] don't use speedstep-centrino on unsupported CPUs # # From: Dominik Brodowski # # Don't use the ACPI data on CPUs we don't know nothing about. # # arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c # 2004/04/14 12:20:07+01:00 davej@redhat.com +16 -15 # [CPUFREQ] don't use speedstep-centrino on unsupported CPUs # # From: Dominik Brodowski # # Don't use the ACPI data on CPUs we don't know nothing about. # # ChangeSet # 2004/04/14 11:40:42+01:00 davej@redhat.com # [CPUFREQ] Correcting SGTC. Timer is based upon FSB # From: Bruno Ducrot # # I think this patch is needed especially if the FSB is around 166MHz or # 200MHz, or else I believe we get instabilities on some K7's motherboard # powernow capable (it's called Cool'n Quiet IIRC). # # # * Deduce fsb from cpu_khz and the max multiplier. It will be given as kHz now, # so that frequency associated to a multiplier will be computate more # accurately. Also, we need it for SGTC (see below). # * Fix how cpuid is computed in powernow_decode_bios(). # * Be more restrictive for PST. It may be possible (on desktop shipped with # low power Athlon models) that FSB can be changed by dip switchs on # motherboard for example. # * Fix computation for SGTC. It use the bus timer (and then the bus # frequency given by fsb). # # # arch/i386/kernel/cpu/cpufreq/powernow-k7.c # 2004/04/14 11:40:36+01:00 davej@redhat.com +59 -16 # [CPUFREQ] Correcting SGTC. Timer is based upon FSB # From: Bruno Ducrot # # I think this patch is needed especially if the FSB is around 166MHz or # 200MHz, or else I believe we get instabilities on some K7's motherboard # powernow capable (it's called Cool'n Quiet IIRC). # # # * Deduce fsb from cpu_khz and the max multiplier. It will be given as kHz now, # so that frequency associated to a multiplier will be computate more # accurately. Also, we need it for SGTC (see below). # * Fix how cpuid is computed in powernow_decode_bios(). # * Be more restrictive for PST. It may be possible (on desktop shipped with # low power Athlon models) that FSB can be changed by dip switchs on # motherboard for example. # * Fix computation for SGTC. It use the bus timer (and then the bus # frequency given by fsb). # # # ChangeSet # 2004/04/13 17:19:16-07:00 davidm@tiger.hpl.hp.com # ia64: When delivering a signal, force byte-order to little-endian. # # arch/ia64/kernel/signal.c # 2004/04/13 17:19:09-07:00 davidm@tiger.hpl.hp.com +1 -0 # (setup_frame): Force byte-order in signal handler to little-endian. # # ChangeSet # 2004/04/13 17:17:41-07:00 davidm@tiger.hpl.hp.com # ia64: Drop pci_sal_ext_{read,write}() and instead simply switch to # extended config-space addresses when needed. This avoids # the fragile SAL version testing. # # arch/ia64/pci/pci.c # 2004/04/13 17:17:34-07:00 davidm@tiger.hpl.hp.com +32 -59 # (pci_sal_read): Use extended addressing when seg > 255 or reg > 255. # (pci_sal_write): Likewise. # (pci_sal_ext_read): Remove. # (pci_sal_ext_write): Likewise. # (pci_sal_ext_ops): Remove. # (pci_set_sal_ops): Remove. # # ChangeSet # 2004/04/13 17:14:59-07:00 davidm@tiger.hpl.hp.com # ia64: Quiet another compiler-warning. # # arch/ia64/kernel/iosapic.c # 2004/04/13 17:14:52-07:00 davidm@tiger.hpl.hp.com +1 -1 # (iosapic_set_affinity): Drop annoying check whose only effect was to # solicit a compiler-warning. # # ChangeSet # 2004/04/13 16:58:22-05:00 stevef@stevef95.austin.ibm.com # fix merge problem with 2.6.5 (rename of page struct field list to lru) # # fs/cifs/file.c # 2004/04/13 16:58:14-05:00 stevef@stevef95.austin.ibm.com +2 -2 # fix merge problem with 2.6.5 (rename of page struct field list to lru) # # ChangeSet # 2004/04/13 14:31:41-05:00 stevef@stevef95.austin.ibm.com # Resolve merge conflict due to list to lru field renaming in page struct # # fs/cifs/file.c # 2004/04/13 14:31:34-05:00 stevef@stevef95.austin.ibm.com +10 -7 # Resolve merge conflict due to list to lru field renaming in page struct # # ChangeSet # 2004/04/06 20:30:33-05:00 stevef@steveft21.ltcsamba # Fix 20 second hang on some deletes of reopened file due to semaphore conflict with vfs_delete on i_sem # # fs/cifs/file.c # 2004/04/06 20:30:14-05:00 stevef@steveft21.ltcsamba +0 -8 # cleanup unused disabled error logging # # fs/cifs/cifsfs.c # 2004/04/06 20:30:14-05:00 stevef@steveft21.ltcsamba +7 -2 # Fix 20 second hang on some deletes of reopened file due to semaphore conflict with vfs_delete on i_sem # # fs/cifs/cifsencrypt.c # 2004/04/06 20:30:13-05:00 stevef@steveft21.ltcsamba +13 -14 # fix whitespace # # fs/cifs/CHANGES # 2004/04/06 20:30:13-05:00 stevef@steveft21.ltcsamba +3 -1 # update cifs vfs changelog for 1.06 version # # ChangeSet # 2004/04/05 21:34:11-05:00 stevef@steveft21.ltcsamba # Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated # with server. This allows files that differ only in case and # improves performance of file creation and file open to such servers # # fs/cifs/cifssmb.c # 2004/04/05 21:23:08-05:00 stevef@steveft21.ltcsamba +8 -2 # Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated # with server. This allows files that differ only in case and # improves performance of file creation and file open to such servers # # fs/cifs/CHANGES # 2004/04/05 21:23:07-05:00 stevef@steveft21.ltcsamba +7 -0 # Update CIFS VFS changelog for 1.0.6 # # ChangeSet # 2004/04/02 18:30:51-08:00 wesolows@foobazco.org # [SPARC32]: Fix wraparound bug in bitmap allocator # # arch/sparc/lib/bitext.c # 2004/04/02 18:30:40-08:00 wesolows@foobazco.org +1 -1 # [SPARC32]: Fix wraparound bug in bitmap allocator # # ChangeSet # 2004/04/02 16:54:19-06:00 stevef@stevef95.austin.ibm.com # Invalidate readahead data properly when file closed, but other client changed it on server # # fs/cifs/inode.c # 2004/04/02 16:54:09-06:00 stevef@stevef95.austin.ibm.com +7 -2 # Invalidate readahead data properly when file closed, but other client changed it on server # # fs/cifs/file.c # 2004/04/02 16:54:09-06:00 stevef@stevef95.austin.ibm.com +20 -1 # Invalidate readahead data properly when file closed, but other client changed it on server # # ChangeSet # 2004/04/02 13:50:54-08:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/connect.c # 2004/04/02 13:50:48-08:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/04/01 18:39:11-06:00 stevef@stevef95.austin.ibm.com # Add missing description about how to specify credentials file # # fs/cifs/README # 2004/04/01 18:39:03-06:00 stevef@stevef95.austin.ibm.com +20 -2 # Add missing description about how to specify credentials file # # ChangeSet # 2004/03/26 16:32:07-06:00 stevef@stevef95.austin.ibm.com # clean up compiler warnings # # fs/cifs/file.c # 2004/03/26 16:31:59-06:00 stevef@stevef95.austin.ibm.com +7 -7 # clean up compiler warnings # # fs/cifs/cifssmb.c # 2004/03/26 16:31:59-06:00 stevef@stevef95.austin.ibm.com +1 -1 # clean up compiler warnings # # fs/cifs/cifsfs.c # 2004/03/26 16:31:59-06:00 stevef@stevef95.austin.ibm.com +2 -2 # clean up compiler warnings # # ChangeSet # 2004/03/25 18:34:51-06:00 stevef@stevef95.austin.ibm.com # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/inode.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +66 -105 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/file.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +94 -40 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/cifssmb.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +1 -1 # debug value missing # # fs/cifs/cifspdu.h # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +3 -3 # whitespace cleanup # # fs/cifs/cifsfs.h # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +0 -2 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/cifsfs.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +12 -6 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/CHANGES # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +3 -0 # update change log for cifs 1.05 # # ChangeSet # 2004/03/20 15:27:50-08:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/cifsfs.c # 2004/03/20 15:27:43-08:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/03/15 10:52:37+00:00 aia21@cantab.net # NTFS: Enforce no atime and no dir atime updates at mount/remount time # as they are not implemented yet anyway. # # fs/ntfs/super.c # 2004/03/15 10:52:32+00:00 aia21@cantab.net +7 -0 # Enforce no atime and no dir atime updates at mount/remount time as # they are not implemented yet anyway. # # fs/ntfs/ChangeLog # 2004/03/15 10:52:32+00:00 aia21@cantab.net +2 -0 # Enforce no atime and no dir atime updates at mount/remount time as # they are not implemented yet anyway. # # ChangeSet # 2004/02/26 14:41:51+00:00 aia21@cantab.net # NTFS: Fix off by one error in ntfs_get_parent(). # # fs/ntfs/namei.c # 2004/02/26 14:39:09+00:00 aia21@cantab.net +1 -1 # Fix off by one error in ntfs_get_parent(). # # ChangeSet # 2004/02/19 16:41:23-06:00 stevef@stevef95.austin.ibm.com # use safer i_size_write mechanism to update i_size # # ChangeSet # 2004/02/19 20:48:48-06:00 stevef@steveft21.ltcsamba # fix caching data integrity problem # # fs/cifs/inode.c # 2004/02/19 16:41:15-06:00 stevef@stevef95.austin.ibm.com +3 -3 # use safer i_size_write mechanism to update i_size # # fs/cifs/inode.c # 2004/02/19 20:48:30-06:00 stevef@steveft21.ltcsamba +7 -27 # fix caching data integrity problem and remove dead code # # fs/cifs/cifsfs.c # 2004/02/19 20:48:30-06:00 stevef@steveft21.ltcsamba +14 -12 # fix caching data integrity problem # # fs/cifs/CHANGES # 2004/02/19 20:48:30-06:00 stevef@steveft21.ltcsamba +7 -0 # update change log for 1.0.4 version # # fs/cifs/misc.c # 2004/02/19 16:41:16-06:00 stevef@stevef95.austin.ibm.com +0 -2 # remove dead code # # fs/cifs/file.c # 2004/02/19 16:41:15-06:00 stevef@stevef95.austin.ibm.com +13 -30 # use safer i_size_write mechanism to update i_size # # ChangeSet # 2004/02/18 09:20:18-08:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/file.c # 2004/02/18 09:20:13-08:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/02/17 15:59:49-06:00 stevef@stevef95.austin.ibm.com # Fix the exec, suid, dev mount parms to not log warnings when specified # # fs/cifs/connect.c # 2004/02/17 15:59:42-06:00 stevef@stevef95.austin.ibm.com +13 -9 # Fix the exec, suid, dev mount parms to not log warnings when specified # # ChangeSet # 2004/02/16 20:00:07-06:00 stevef@stevef95.austin.ibm.com # fix problem with inode revalidation and cache page invalidation # # fs/cifs/misc.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +4 -4 # cleanup smb header validation to avoid potential 32 bit overflow # # fs/cifs/inode.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +31 -5 # Fix revalidate code to invalidate remote inode more sanely # # fs/cifs/file.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +0 -1 # remove excessive inode page invalidation # # fs/cifs/connect.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +7 -4 # clean up demultiplex buffer checking description # # fs/cifs/README # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +22 -1 # update readme instructions # # fs/cifs/AUTHORS # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +2 -1 # update list of bug report submitters # # ChangeSet # 2004/02/12 10:58:31+00:00 aia21@cantab.net # NTFS: Add missing return -EOPNOTSUPP; in fs/ntfs/aops.c::ntfs_commit_nonresident_write(). # # fs/ntfs/ChangeLog # 2004/02/12 10:58:16+00:00 aia21@cantab.net +6 -0 # Update changelog. # # fs/ntfs/aops.c # 2004/02/12 10:53:42+00:00 aia21@cantab.net +13 -12 # - Add missing return -EOPNOTSUPP; in ntfs_commit_nonresident_write(). # - White space cleanup. # # ChangeSet # 2004/02/11 23:44:57+00:00 aia21@cantab.net # NTFS: Release 2.1.7 - Enable NFS exporting of mounted NTFS volumes. # - Implement ntfs_get_parent() and ntfs_get_dentry() as the NTFS specific # export operations ->get_parent() and ->get_dentry() respectively. # # fs/ntfs/namei.c # 2004/02/11 23:41:30+00:00 aia21@cantab.net +124 -1 # Implement ntfs_get_parent() and ntfs_get_dentry() as the NTFS specific # export operations ->get_parent() and ->get_dentry() respectively. # # fs/ntfs/inode.c # 2004/02/11 23:41:20+00:00 aia21@cantab.net +1 -1 # Fix a typo in a comment. # # ChangeSet # 2004/02/10 11:41:26-06:00 stevef@smfhome.smfdom # allow nosuid mounts # # fs/cifs/connect.c # 2004/02/10 11:41:02-06:00 stevef@smfhome.smfdom +9 -0 # allow nosuid mounts # # Documentation/filesystems/ntfs.txt # 2004/02/10 13:44:29+00:00 aia21@cantab.net +2 -0 # Update for 2.1.7 release. # # fs/ntfs/super.c # 2004/02/10 13:41:24+00:00 aia21@cantab.net +28 -5 # Finish off the implementation of NFS exporting of mounted NTFS volumes. # # fs/ntfs/Makefile # 2004/02/10 13:41:24+00:00 aia21@cantab.net +1 -1 # Update for 2.1.7 release. # # fs/ntfs/ChangeLog # 2004/02/10 13:41:24+00:00 aia21@cantab.net +10 -2 # Update for 2.1.7 release. # # ChangeSet # 2004/02/10 02:51:42-06:00 stevef@steveft21.ltcsamba # improve resume key resetting logic when filldir returns error and filename is in unicode # # fs/cifs/file.c # 2004/02/10 02:51:11-06:00 stevef@steveft21.ltcsamba +20 -24 # improve resume key resetting logic when filldir returns error and filename is in unicode # # fs/ntfs/super.c # 2004/02/09 17:19:43+00:00 aia21@cantab.net +15 -3 # Define sb->s_export_op for NTFS. (Just NULL for now.) # # fs/ntfs/inode.c # 2004/02/09 17:06:54+00:00 aia21@cantab.net +17 -10 # sf.net sourceforge.net # # fs/ntfs/dir.c # 2004/02/09 17:06:54+00:00 aia21@cantab.net +5 -3 # sf.net sourceforge.net # # ChangeSet # 2004/02/09 14:22:55+00:00 aia21@cantab.net # NTFS: Make it compile... # # fs/ntfs/namei.c # 2004/02/09 14:22:48+00:00 aia21@cantab.net +3 -2 # eeek. make it compile... # # ChangeSet # 2004/02/09 13:38:17+00:00 aia21@cantab.net # NTFS: Make ntfs_lookup() NFS export safe, i.e. use d_splice_alias(), etc. # # fs/ntfs/layout.h # 2004/02/09 13:38:11+00:00 aia21@cantab.net +1 -1 # Update copyright. # # fs/ntfs/ChangeLog # 2004/02/09 13:38:11+00:00 aia21@cantab.net +1 -0 # Update # # fs/ntfs/namei.c # 2004/02/09 13:19:43+00:00 aia21@cantab.net +62 -20 # Make ntfs_lookup() NFS safe, i.e. use d_splice_alias() as necessary. # # fs/ntfs/unistr.c # 2004/02/09 11:18:59+00:00 aia21@cantab.net +4 -3 # Update function description for ntfs_ucstonls(). # # ChangeSet # 2004/02/08 18:45:25+00:00 aia21@cantab.net # NTFS: Set i_generation in VFS inode from seq_no in NTFS inode. # # fs/ntfs/layout.h # 2004/02/08 18:44:29+00:00 aia21@cantab.net +1 -1 # Update # # fs/ntfs/inode.c # 2004/02/08 18:44:07+00:00 aia21@cantab.net +3 -3 # Set i_generation in VFS inode from seq_no in NTFS inode. # # fs/ntfs/Makefile # 2004/02/08 18:44:00+00:00 aia21@cantab.net +1 -1 # Update version. # # fs/ntfs/ChangeLog # 2004/02/08 18:43:54+00:00 aia21@cantab.net +4 -0 # Update. # # ChangeSet # 2004/02/08 04:16:42-06:00 stevef@smfhome.smfdom # Spurious white space and duplicated line cleanup # # fs/cifs/connect.c # 2004/02/08 04:16:29-06:00 stevef@smfhome.smfdom +0 -4 # Spurious white space and duplicated line cleanup # # ChangeSet # 2004/02/06 17:37:36-06:00 stevef@steveft21.ltcsamba # ipv6 enablement for cifs vfs fixes # # fs/cifs/connect.c # 2004/02/06 17:37:19-06:00 stevef@steveft21.ltcsamba +14 -12 # ipv6 enablement for cifs vfs fixes # # ChangeSet # 2004/02/06 15:56:08-06:00 stevef@stevef95.austin.ibm.com # reset searches properly when filldir fails # # fs/cifs/transport.c # 2004/02/06 15:56:02-06:00 stevef@stevef95.austin.ibm.com +1 -1 # ipv6 missing structure # # fs/cifs/file.c # 2004/02/06 15:56:02-06:00 stevef@stevef95.austin.ibm.com +22 -4 # reset searches properly when filldir fails # # fs/cifs/cifsglob.h # 2004/02/06 15:56:01-06:00 stevef@stevef95.austin.ibm.com +5 -1 # ipv6 missing structure # # fs/cifs/CHANGES # 2004/02/06 15:56:01-06:00 stevef@stevef95.austin.ibm.com +3 -2 # Update cifs vfs changelog # # ChangeSet # 2004/02/06 12:25:38-06:00 stevef@stevef95.austin.ibm.com # fix problem not connecting to server when port not specified explicitly and port field unitialized # # fs/cifs/connect.c # 2004/02/06 12:25:24-06:00 stevef@stevef95.austin.ibm.com +76 -40 # fix problem not connecting to server when port not specified explicitly and port field unitialized # # fs/cifs/cifsglob.h # 2004/02/06 12:25:24-06:00 stevef@stevef95.austin.ibm.com +8 -1 # fix problem not connecting to server when port not specified explicitly and port field unitialized # # fs/cifs/CHANGES # 2004/02/06 12:25:24-06:00 stevef@stevef95.austin.ibm.com +5 -0 # Update cifs vfs change log for 1.0.3 # # ChangeSet # 2004/02/03 14:51:25-06:00 stevef@stevef95.austin.ibm.com # remove spurious debug messages # # fs/cifs/connect.c # 2004/02/03 14:51:18-06:00 stevef@stevef95.austin.ibm.com +2 -4 # remove spurious debug messages # # ChangeSet # 2004/02/02 17:54:45-06:00 stevef@stevef95.austin.ibm.com # fix remoting caching part 2 # # fs/cifs/misc.c # 2004/02/02 17:54:39-06:00 stevef@stevef95.austin.ibm.com +1 -1 # initialize smb buffer to zero # # fs/cifs/cifsfs.c # 2004/02/02 17:54:39-06:00 stevef@stevef95.austin.ibm.com +11 -10 # fix remoting caching part 2 # # ChangeSet # 2004/01/30 17:20:19-06:00 stevef@stevef95.austin.ibm.com # Relax requested CIFS permissions on open to simply request GENERIC_READ and GENERIC_WRITE (instead of GENERIC_ALL which # can unnecessarily conflict with share permissions by asking implicitly for take ownership and other unneeded flags) # # fs/cifs/file.c # 2004/01/30 17:20:13-06:00 stevef@stevef95.austin.ibm.com +12 -4 # Relax requested CIFS permissions on open to simply request GENERIC_READ and GENERIC_WRITE (instead of GENERIC_ALL which # can unnecessarily conflict with share permissions by asking implicitly for take ownership and other unneeded flags) # # fs/cifs/dir.c # 2004/01/30 17:20:13-06:00 stevef@stevef95.austin.ibm.com +7 -3 # Relax requested CIFS permissions on open to simply request GENERIC_READ and GENERIC_WRITE (instead of GENERIC_ALL which # can unnecessarily conflict with share permissions by asking implicitly for take ownership and other unneeded flags) # # ChangeSet # 2004/01/29 18:40:09-06:00 stevef@stevef95.austin.ibm.com # Fix caching problem with multiply open files from different clients # # fs/cifs/cifsfs.c # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +31 -4 # Fix caching problem with multiply open files from different clients # # fs/cifs/TODO # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +6 -10 # update to do list for cifs vfs # # fs/cifs/README # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +10 -0 # add missing description for mount option # # fs/cifs/CHANGES # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +9 -0 # update cifs vfs change log for version 1.0.2 # # ChangeSet # 2004/01/26 17:22:34-06:00 stevef@steveft21.ltcsamba # finish off mount parm sep override # # fs/cifs/connect.c # 2004/01/26 17:22:20-06:00 stevef@steveft21.ltcsamba +18 -5 # finish off mount parm sep override # # ChangeSet # 2004/01/23 22:34:13-06:00 stevef@steveft21.ltcsamba # finish handling commas in passwords # # fs/cifs/connect.c # 2004/01/23 22:33:57-06:00 stevef@steveft21.ltcsamba +7 -10 # finish handling commas in passwords # # ChangeSet # 2004/01/22 17:51:52-06:00 stevef@steveft21.ltcsamba # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/smbencrypt.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +11 -6 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/misc.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +2 -0 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/connect.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +70 -23 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/cifsglob.h # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +1 -1 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/cifsencrypt.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +4 -5 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/CHANGES # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +4 -0 # update change log for cifs vfs # # ChangeSet # 2004/01/20 23:46:57-06:00 stevef@smfhome.smfdom # Check return on failed dentry allocation. Suggested by Randy Dunlap # # fs/cifs/file.c # 2004/01/20 23:44:53-06:00 stevef@smfhome.smfdom +5 -0 # Check return on failed dentry allocation. # # ChangeSet # 2004/01/08 17:17:13-06:00 stevef@stevef95.austin.ibm.com # Fix global kernel name space pollution # # fs/cifs/transport.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +1 -1 # Fix global kernel name space pollution # # fs/cifs/smbencrypt.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +0 -23 # Fix global kernel name space pollution # # fs/cifs/netmisc.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +1 -1 # Fix global kernel name space pollution # # fs/cifs/misc.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +4 -14 # Fix global kernel name space pollution # # fs/cifs/file.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +5 -3 # Fix global kernel name space pollution # # fs/cifs/connect.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +177 -163 # Fix global kernel name space pollution # # fs/cifs/cifssmb.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +37 -37 # Fix global kernel name space pollution # # fs/cifs/cifsproto.h # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +3 -22 # Fix global kernel name space pollution # # fs/cifs/cifsfs.c # 2004/01/08 17:17:06-06:00 stevef@stevef95.austin.ibm.com +10 -10 # Fix global kernel name space pollution # # fs/cifs/cifs_unicode.h # 2004/01/08 17:17:06-06:00 stevef@stevef95.austin.ibm.com +0 -15 # Fix global kernel name space pollution # # fs/cifs/cifs_unicode.c # 2004/01/08 17:17:06-06:00 stevef@stevef95.austin.ibm.com +0 -44 # Fix global kernel name space pollution # # ChangeSet # 2004/01/07 16:58:55-06:00 stevef@stevef95.austin.ibm.com # fix failed mounts to win98 part II # # fs/cifs/connect.c # 2004/01/07 16:58:48-06:00 stevef@stevef95.austin.ibm.com +1 -1 # fix failed mounts to win98 part II # # ChangeSet # 2004/01/06 17:55:00-06:00 stevef@stevef95.austin.ibm.com # gracefully exit on failed mounts to win98 (which closes tcp session rather than erroring on smb protocol negotiation) # # fs/cifs/transport.c # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +4 -0 # gracefully exit on failed mounts to win98 (which closes tcp session rather than erroring on smb protocol negotiation) # # fs/cifs/connect.c # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +18 -8 # gracefully exit on failed mounts to win98 (which closes tcp session rather than erroring on smb protocol negotiation) # # fs/cifs/cifssmb.c # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +8 -9 # fix white space # # fs/cifs/CHANGES # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +6 -0 # Update cifs change log for cifs 1.0.0 # # ChangeSet # 2004/01/06 10:05:09-06:00 stevef@steveft21.ltcsamba # fix cifs readme # # fs/cifs/README # 2004/01/06 10:04:56-06:00 stevef@steveft21.ltcsamba +8 -3 # fix cifs readme # # ChangeSet # 2003/12/11 09:14:24-06:00 stevef@steveft21.ltcsamba # set byte range locktimeouts properly # # fs/cifs/cifssmb.c # 2003/12/11 09:14:11-06:00 stevef@steveft21.ltcsamba +6 -4 # set byte range locktimeouts properly # # ChangeSet # 2003/12/08 11:00:47-06:00 stevef@steveft21.ltcsamba # Fix an incorrect mapping of open flags to cifs open disposition. Fix blocking byte range locks. These fix breakages that were notice running lock tests 1 and 7 of the connectathon posix file api tests # # fs/cifs/transport.c # 2003/12/08 11:00:34-06:00 stevef@steveft21.ltcsamba +4 -2 # Fix breakage in lock tests 1 and 7 of connectathon posix testing, due to invalid open disposition in one case in which create called when file exists, and problem with blocking lock operations # # fs/cifs/file.c # 2003/12/08 11:00:33-06:00 stevef@steveft21.ltcsamba +64 -49 # Fix breakage in lock test 7 of connectathon posix testing # # fs/cifs/dir.c # 2003/12/08 11:00:33-06:00 stevef@steveft21.ltcsamba +7 -7 # fix incorrect formatting # # fs/cifs/cifssmb.c # 2003/12/08 11:00:33-06:00 stevef@steveft21.ltcsamba +6 -1 # Fix breakage in lock test 7 of connectathon posix testing # # ChangeSet # 2003/12/06 11:21:50-06:00 stevef@steveft21.ltcsamba # allow disabling cifs Linux extensions via proc # # fs/cifs/connect.c # 2003/12/06 11:21:28-06:00 stevef@steveft21.ltcsamba +2 -0 # allow disabling cifs Linux extensions via proc # # fs/cifs/README # 2003/12/06 11:21:28-06:00 stevef@steveft21.ltcsamba +24 -14 # allow disabling cifs Linux extensions via proc # # fs/cifs/CHANGES # 2003/12/06 11:21:26-06:00 stevef@steveft21.ltcsamba +2 -1 # update change log for cifs vfs # # ChangeSet # 2003/12/05 10:46:56-06:00 stevef@steveft21.ltcsamba # Fix check of filldir return code during readdir to avoid incomplete search results displayed on very large directories. Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # fs/cifs/file.c # 2003/12/05 10:46:37-06:00 stevef@steveft21.ltcsamba +86 -15 # Handle errors on filldir (e.g. for readdir problems on large directory searches or when memory constrained) # # fs/cifs/cifsglob.h # 2003/12/05 10:46:37-06:00 stevef@steveft21.ltcsamba +2 -0 # Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # fs/cifs/cifsfs.c # 2003/12/05 10:46:37-06:00 stevef@steveft21.ltcsamba +1 -0 # Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # fs/cifs/cifs_debug.c # 2003/12/05 10:46:36-06:00 stevef@steveft21.ltcsamba +67 -17 # Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # ChangeSet # 2003/12/02 08:11:41-06:00 stevef@steveft21.ltcsamba # fix double incrementing of transaction counter # # fs/cifs/file.c # 2003/12/02 08:11:25-06:00 stevef@steveft21.ltcsamba +0 -9 # fix double incrementing of transaction counter # # ChangeSet # 2003/12/01 16:36:38-06:00 stevef@steveft21.ltcsamba # invalidate cached pages when last local instance closed so we do # not use stale data while someone may be modifying the file on the # server. # # fs/cifs/file.c # 2003/12/01 16:36:25-06:00 stevef@steveft21.ltcsamba +3 -2 # invalidate cached pages when last local instance closed so we do # not use stale data while someone may be modifying the file on the # server. # # fs/cifs/CHANGES # 2003/12/01 16:36:25-06:00 stevef@steveft21.ltcsamba +4 -3 # Update change log for cifs vfs # # ChangeSet # 2003/12/01 15:43:13-06:00 stevef@steveft21.ltcsamba # Oops on reopen files when dentry already freed # # fs/cifs/file.c # 2003/12/01 15:42:52-06:00 stevef@steveft21.ltcsamba +3 -3 # Oops on reopen files when dentry already freed # # ChangeSet # 2003/11/27 04:50:46-06:00 stevef@steveft21.ltcsamba # invalidate locally cached pages when server breaks oplock. Do not loop reconnecting for servers that drop tcp session rather than sending smb negprot response # # fs/cifs/connect.c # 2003/11/27 04:43:51-06:00 stevef@steveft21.ltcsamba +12 -1 # Do not reconnect session repeatedly for servers that drop tcp sessions rather than sending negprot response # # fs/cifs/cifsfs.c # 2003/11/27 04:43:51-06:00 stevef@steveft21.ltcsamba +4 -2 # invalidate locally cached pages when server breaks oplock # # fs/cifs/CHANGES # 2003/11/27 04:43:50-06:00 stevef@steveft21.ltcsamba +6 -0 # Update change log for cifs vfs 0.99 # # ChangeSet # 2003/11/25 17:09:03-06:00 stevef@stevef95.austin.ibm.com # rcvtimeout set improperly for some cifs servers # # fs/cifs/connect.c # 2003/11/25 17:08:57-06:00 stevef@stevef95.austin.ibm.com +7 -7 # rcvtimeout set improperly for some cifs servers # # fs/cifs/README # 2003/11/25 17:08:57-06:00 stevef@stevef95.austin.ibm.com +8 -7 # typo in cifs README # # ChangeSet # 2003/11/21 17:26:27-06:00 stevef@stevef95.austin.ibm.com # missing message on timed out requests # # fs/cifs/cifssmb.c # 2003/11/21 17:26:21-06:00 stevef@stevef95.austin.ibm.com +3 -2 # missing message on timed out requests # # ChangeSet # 2003/11/20 19:27:13-06:00 stevef@stevef95.austin.ibm.com # Avoid smb data corruption under heavy stress # # fs/cifs/transport.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +7 -2 # Avoid smb data corruption under heavy stress # # fs/cifs/file.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +2 -0 # Avoid smb data corruption under heavy stress # # fs/cifs/dir.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +1 -0 # Avoid smb data corruption under heavy stress # # fs/cifs/connect.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +1 -0 # Avoid smb data corruption under heavy stress # # fs/cifs/CHANGES # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +4 -1 # update change log for 0.9.8 cifs vfs # # ChangeSet # 2003/11/19 11:24:43-06:00 stevef@linux-udp14619769uds.austin.ibm.com # Fix oops in mount error path when unload_nls called with bad pointer. # # ChangeSet # 2003/11/19 17:32:27-06:00 stevef@stevef95.austin.ibm.com # Do not grab i_sem (already taken in filemap.c across commit write calls) during reopen of invalidated file handle. # # fs/cifs/file.c # 2003/11/19 17:32:21-06:00 stevef@stevef95.austin.ibm.com +5 -5 # Do not grab i_sem (already taken in filemap.c across commit write calls) during reopen of invalidated file handle. # # fs/cifs/cifsglob.h # 2003/11/19 17:32:21-06:00 stevef@stevef95.austin.ibm.com +2 -1 # Do not grab i_sem (already taken in filemap.c across commit write calls) during reopen of invalidated file handle. # # fs/cifs/cifsfs.c # 2003/11/19 11:24:19-06:00 stevef@linux-udp14619769uds.austin.ibm.com +3 -0 # Fix oops in mount error path when unload_nls called with bad pointer. # # fs/cifs/CHANGES # 2003/11/19 11:24:19-06:00 stevef@linux-udp14619769uds.austin.ibm.com +5 -0 # Fix oops in mount error path when unload_nls called with bad pointer. # # ChangeSet # 2003/11/18 17:48:08-06:00 stevef@stevef95.austin.ibm.com # Missing soft vs. hard retry mount option # # fs/cifs/connect.c # 2003/11/18 17:48:02-06:00 stevef@stevef95.austin.ibm.com +26 -3 # Missing soft vs. hard retry mount option # # fs/cifs/cifssmb.c # 2003/11/18 17:48:02-06:00 stevef@stevef95.austin.ibm.com +11 -7 # Missing soft vs. hard retry mount option # # fs/cifs/cifsglob.h # 2003/11/18 17:48:02-06:00 stevef@stevef95.austin.ibm.com +5 -0 # Missing soft vs. hard retry mount option # # ChangeSet # 2003/11/16 21:52:41-06:00 stevef@steveft21.austin.ibm.com # Fix compile error # # fs/cifs/cifssmb.c # 2003/11/16 21:52:29-06:00 stevef@steveft21.austin.ibm.com +4 -2 # Fix compile error # # ChangeSet # 2003/11/14 16:42:04-06:00 stevef@stevef95.austin.ibm.com # correct retry on remaining handles based calls # # fs/cifs/inode.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +2 -2 # correct retry on remaining handles based calls # # fs/cifs/file.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +19 -12 # correct retry on remaining handles based calls # # fs/cifs/connect.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +2 -0 # correct retry on remaining handles based calls # # fs/cifs/cifssmb.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +23 -0 # correct retry on remaining handles based calls # # fs/cifs/cifsglob.h # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +3 -0 # correct retry on remaining handles based calls # # fs/cifs/cifsfs.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +18 -6 # correct retry on remaining handles based calls # # fs/cifs/cifs_debug.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +23 -1 # Update debugging code for session reconnection info # # ChangeSet # 2003/11/12 13:10:10-06:00 stevef@stevef95.austin.ibm.com # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/file.c # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +144 -169 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/cifssmb.c # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +26 -8 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/cifsproto.h # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +0 -1 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/cifsglob.h # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +0 -1 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # ChangeSet # 2003/11/11 17:51:40-06:00 stevef@stevef95.austin.ibm.com # have to reconnect open files safely, one at a time, as needed # # fs/cifs/transport.c # 2003/11/11 17:51:24-06:00 stevef@stevef95.austin.ibm.com +0 -3 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/inode.c # 2003/11/11 17:51:24-06:00 stevef@stevef95.austin.ibm.com +24 -7 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/file.c # 2003/11/11 17:51:24-06:00 stevef@stevef95.austin.ibm.com +15 -3 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/connect.c # 2003/11/11 17:51:23-06:00 stevef@stevef95.austin.ibm.com +3 -2 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/cifssmb.c # 2003/11/11 17:51:23-06:00 stevef@stevef95.austin.ibm.com +79 -42 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/cifsglob.h # 2003/11/11 17:51:23-06:00 stevef@stevef95.austin.ibm.com +1 -0 # have to reconnect open files safely, one at a time, as needed # # ChangeSet # 2003/11/10 00:57:19-06:00 stevef@steveft21.austin.ibm.com # fix endian bug in lockingX and add retry on EAGAIN # # fs/cifs/transport.c # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +1 -1 # typo in retry # # fs/cifs/cifssmb.c # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +151 -26 # fix endian bug in lockingX and add retry on EAGAIN # # fs/cifs/cifspdu.h # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +4 -2 # fix endian bug in lockingX # # fs/cifs/CHANGES # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +5 -0 # update cifs vfs change log # # ChangeSet # 2003/11/04 17:46:07-06:00 stevef@stevef95.austin.ibm.com # move bad smb session retry to correct location, up one level in cifs vfs code # # fs/cifs/transport.c # 2003/11/04 17:46:01-06:00 stevef@stevef95.austin.ibm.com +39 -39 # move bad smb session retry to correct location, up one level in cifs vfs code # # ChangeSet # 2003/11/03 23:17:47-06:00 stevef@smfhome.smfdom # Do not return buffer if request has already timed out. # # fs/cifs/transport.c # 2003/11/03 23:15:09-06:00 stevef@smfhome.smfdom +19 -7 # Do not return buffer if request has already timed out. # # fs/cifs/connect.c # 2003/11/03 23:15:09-06:00 stevef@smfhome.smfdom +1 -1 # Do not return buffer if request has already timed out. # # ChangeSet # 2003/11/03 18:36:00-06:00 stevef@stevef95.austin.ibm.com # Merge bk://cifs.bkbits.net/linux-2.5cifs # into stevef95.austin.ibm.com:/home/stevef/bk/linux-2.5cifs # # fs/cifs/connect.c # 2003/11/03 18:35:52-06:00 stevef@stevef95.austin.ibm.com +0 -0 # Auto merged # # ChangeSet # 2003/11/03 18:30:25-06:00 stevef@stevef95.austin.ibm.com # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/transport.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +9 -4 # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/file.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +7 -4 # Fix oops when invalid inode in reopening dentry # # fs/cifs/connect.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +19 -0 # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/cifsglob.h # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +1 -0 # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/cifsfs.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +1 -1 # oplock thread can sleep too long when multiple oplock requests come in at the same time # # ChangeSet # 2003/11/02 23:44:48-06:00 stevef@linux.local # Fix EIO caused by network timeouts on changing file size. # To avoid spurious oplock breaks from server, in the case # of inodes that we already have open, avoid doing path # based setting of file size if we can do it by handle. # This keeps our caching token (oplock) and avoids # timeouts when the local oplock break takes longer to flush # writebehind data than the SMB timeout for the SetPathInfo # request would allow # # fs/cifs/inode.c # 2003/11/02 23:44:42-06:00 stevef@linux.local +68 -26 # To avoid spurious oplock breaks from server, in the case # of inodes that we already have open, avoid doing path # based setting of file size if we can do it by handle. # This keeps our caching token (oplock) and avoids # timeouts when the local oplock break takes longer to flush # writebehind data than the SMB timeout for the SetPathInfo # request would allow # # ChangeSet # 2003/11/02 14:58:15-06:00 stevef@linux.local # fix oops in send_sig on unmount of cifs vfs due to sending signal to demultiplex thread after it has exited. # Do not treat invalid handle warning in response to oplock break (of file that is now closed) as an error. # # fs/cifs/misc.c # 2003/11/02 14:55:37-06:00 stevef@linux.local +18 -2 # Do not treat invalid handle on oplock break as an error. After writing out dirty file data for file that has been cached locally it is harmless for close and response to oplock break to be sent out of order # # fs/cifs/connect.c # 2003/11/02 14:55:37-06:00 stevef@linux.local +2 -3 # fix oops in send_sig on unmount of cifs vfs due to sending signal to demultiplex thread after it has exited # # fs/cifs/CHANGES # 2003/11/02 14:55:37-06:00 stevef@linux.local +7 -1 # Update cifs change log # # ChangeSet # 2003/10/30 16:39:04-06:00 stevef@stevef95.austin.ibm.com # Fix invalid dentry when race in mkdir between two clients # # fs/cifs/inode.c # 2003/10/30 16:36:52-06:00 stevef@stevef95.austin.ibm.com +1 -0 # Fix invalid dentry when race in mkdir between two clients # # fs/cifs/CHANGES # 2003/10/30 16:36:52-06:00 stevef@stevef95.austin.ibm.com +2 -1 # Update cifs change log # # ChangeSet # 2003/10/28 17:44:29-06:00 stevef@linux.local # Fix problem reconnecting additional mounts to the same server after # session failure. # # fs/cifs/cifssmb.c # 2003/10/28 17:44:14-06:00 stevef@linux.local +2 -2 # Fix problem reconnecting additional mounts to the same server after # session failure. # # fs/cifs/CHANGES # 2003/10/28 17:44:14-06:00 stevef@linux.local +2 -0 # Update cifs change log # # ChangeSet # 2003/10/27 16:50:37-06:00 stevef@linux.local # Can not mount from cifs vfs client built with gcc 3.3.1 due to compiler optimization of unsafe global variable. Remove unsafe global variable. # # fs/cifs/smbencrypt.c # 2003/10/27 16:50:06-06:00 stevef@linux.local +0 -116 # Remove broken lmv2 encrypt functions # # fs/cifs/md4.c # 2003/10/27 16:50:06-06:00 stevef@linux.local +28 -34 # Can not mount from cifs vfs client built with gcc 3.3.1 due to compiler optimization of unsafe global variable. Remove unsafe global variable. # # fs/cifs/cifsglob.h # 2003/10/27 16:50:06-06:00 stevef@linux.local +3 -3 # text beyond 80 chars # # fs/cifs/README # 2003/10/27 16:50:06-06:00 stevef@linux.local +77 -56 # Update cifs vfs readme to fix formatting to be readable and correct mount helper writeup # # fs/cifs/CHANGES # 2003/10/27 16:50:05-06:00 stevef@linux.local +4 -0 # Update cifs vfs change log for 0.9.5 # diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Sun Apr 25 22:39:31 2004 +++ b/CREDITS Sun Apr 25 22:39:31 2004 @@ -1944,6 +1944,12 @@ S: Niwot, Colorado 80503 S: USA +N: Pete Popov +E: pete_popov@yahoo.com +D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging +S: San Jose, CA 95134 +S: USA + N: Robert M. Love E: rml@tech9.net E: rml@ufl.edu diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt --- a/Documentation/filesystems/ntfs.txt Sun Apr 25 22:39:31 2004 +++ b/Documentation/filesystems/ntfs.txt Sun Apr 25 22:39:31 2004 @@ -272,6 +272,8 @@ Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.7: + - Enable NFS exporting of mounted NTFS volumes. 2.1.6: - Fix minor bug in handling of compressed directories that fixes the erroneous "du" and "stat" output people reported. diff -Nru a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/s390/crypto/crypto-API.txt Sun Apr 25 22:39:32 2004 @@ -0,0 +1,83 @@ +crypto-API support for z990 Message Security Assist (MSA) instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +AUTHOR: Thomas Spatzier (tspat@de.ibm.com) + + +1. Introduction crypto-API +~~~~~~~~~~~~~~~~~~~~~~~~~~ +See Documentation/crypto/api-intro.txt for an introduction/description of the +kernel crypto API. +According to api-intro.txt support for z990 crypto instructions has been added +in the algorithm api layer of the crypto API. Several files containing z990 +optimized implementations of crypto algorithms are placed in the +arch/s390/crypto directory. + + +2. Probing for availability of MSA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It should be possible to use Kernels with the z990 crypto implementations both +on machines with MSA available an on those without MSA (pre z990 or z990 +without MSA). Therefore a simple probing mechanisms has been implemented: +In the init function of each crypto module the availability of MSA and of the +respective crypto algorithm in particular will be tested. If the algorithm is +available the module will load and register its algorithm with the crypto API. + +If the respective crypto algorithm is not available, the init function will +return -ENOSYS. In that case a fallback to the standard software implementation +of the crypto algorithm must be taken ( -> the standard crypto modules are +also build when compiling the kernel). + + +3. Ensuring z990 crypto module preference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If z990 crypto instructions are available the optimized modules should be +preferred instead of standard modules. + +3.1. compiled-in modules +~~~~~~~~~~~~~~~~~~~~~~~~ +For compiled-in modules it has to be ensured that the z990 modules are linked +before the standard crypto modules. Then, on system startup the init functions +of z990 crypto modules will be called first and query for availability of z990 +crypto instructions. If instruction is available, the z990 module will register +its crypto algorithm implementation -> the load of the standard module will fail +since the algorithm is already registered. +If z990 crypto instruction is not available the load of the z990 module will +fail -> the standard module will load and register its algorithm. + +3.2. dynamic modules +~~~~~~~~~~~~~~~~~~~~ +A system administrator has to take care of giving preference to z990 crypto +modules. If MSA is available appropriate lines have to be added to +/etc/modprobe.conf. + +Example: z990 crypto instruction for SHA1 algorithm is available + + add the following line to /etc/modprobe.conf (assuming the + z990 crypto modules for SHA1 is called sha1_z990): + + alias sha1 sha1_z990 + + -> when the sha1 algorithm is requested through the crypto API + (which has a module autoloader) the z990 module will be loaded. + +TBD: a userspace module probin mechanism + something like 'probe sha1 sha1_z990 sha1' in modprobe.conf + -> try module sha1_z990, if it fails to load load standard module sha1 + the 'probe' statement is currently not supported in modprobe.conf + + +4. Currently implemented z990 crypto algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following crypto algorithms with z990 MSA support are currently implemented. +The name of each algorithm under which it is registered in crypto API and the +name of the respective module is given in square brackets. + +- SHA1 Digest Algorithm [sha1 -> sha1_z990] +- DES Encrypt/Decrypt Algorithm (64bit key) [des -> des_z990] +- Tripple DES Encrypt/Decrypt Algorithm (128bit key) [des3_ede128 -> des_z990] +- Tripple DES Encrypt/Decrypt Algorithm (192bit key) [des3_ede -> des_z990] + +In order to load, for example, the sha1_z990 module when the sha1 algorithm is +requested (see 3.2.) add 'alias sha1 sha1_z990' to /etc/modprobe.conf. + diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c --- a/arch/alpha/kernel/irq.c Sun Apr 25 22:39:31 2004 +++ b/arch/alpha/kernel/irq.c Sun Apr 25 22:39:31 2004 @@ -415,16 +415,12 @@ #endif /* - * Create entries for all existing IRQs. If the number of IRQs - * is greater the 1/4 the total dynamic inode space for /proc, - * don't pollute the inode space + * Create entries for all existing IRQs. */ - if (ACTUAL_NR_IRQS < (PROC_NDYNAMIC / 4)) { - for (i = 0; i < ACTUAL_NR_IRQS; i++) { - if (irq_desc[i].handler == &no_irq_type) - continue; - register_irq_proc(i); - } + for (i = 0; i < ACTUAL_NR_IRQS; i++) { + if (irq_desc[i].handler == &no_irq_type) + continue; + register_irq_proc(i); } } diff -Nru a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c --- a/arch/alpha/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/alpha/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -137,18 +137,6 @@ printk("\n"); } -void show_trace_task(struct task_struct * tsk) -{ - struct thread_info *ti = tsk->thread_info; - unsigned long fp, sp = ti->pcb.ksp, base = (unsigned long) ti; - - if (sp > base && sp+6*8 < base + 16*1024) { - fp = ((unsigned long*)sp)[6]; - if (fp > sp && fp < base + 16*1024) - dik_show_trace((unsigned long *)fp); - } -} - static int kstack_depth_to_print = 24; void show_stack(struct task_struct *task, unsigned long *sp) diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig Sun Apr 25 22:39:31 2004 +++ b/arch/arm/Kconfig Sun Apr 25 22:39:31 2004 @@ -145,6 +145,11 @@ config ARCH_OMAP bool "TI OMAP" +config ARCH_VERSATILE_PB + bool "Versatile PB" + help + This enables support for ARM Ltd Versatile PB board. + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -205,6 +210,11 @@ depends on SA1111 default "9" +config DMABOUNCE + bool + depends on SA1111 + default y + source arch/arm/mm/Kconfig # bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER @@ -262,7 +272,7 @@ config ARM_AMBA bool - depends on ARCH_INTEGRATOR + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB default y config ISA @@ -514,7 +524,7 @@ config LEDS bool "Timer and CPU usage LEDs" - depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP + depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE_PB help If you say Y here, the LEDs on your machine will be used to provide useful information about your current system status. @@ -527,8 +537,8 @@ system, but the driver will do nothing. config LEDS_TIMER - bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T) - depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP + bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE_PB) + depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE_PB default y if ARCH_EBSA110 help If you say Y here, one of the system LEDs (the green one on the @@ -543,7 +553,7 @@ config LEDS_CPU bool "CPU usage LED" - depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T) + depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE_PB) help If you say Y here, the red LED will be used to give a good real time indication of CPU usage, by lighting whenever the idle task diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile --- a/arch/arm/Makefile Sun Apr 25 22:39:31 2004 +++ b/arch/arm/Makefile Sun Apr 25 22:39:31 2004 @@ -94,6 +94,7 @@ machine-$(CONFIG_ARCH_ADIFCC) := adifcc machine-$(CONFIG_ARCH_OMAP) := omap machine-$(CONFIG_ARCH_S3C2410) := s3c2410 + machine-$(CONFIG_ARCH_VERSATILE_PB) := versatile TEXTADDR := $(textaddr-y) ifeq ($(incdir-y),) diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile --- a/arch/arm/boot/Makefile Sun Apr 25 22:39:31 2004 +++ b/arch/arm/boot/Makefile Sun Apr 25 22:39:31 2004 @@ -56,6 +56,9 @@ initrd_phys-$(CONFIG_ARCH_OMAP) := 0x10800000 zreladdr-$(CONFIG_ARCH_S3C2410) := 0x30008000 params_phys-$(CONFIG_ARCH_S3C2410) := 0x30000100 + zreladdr-$(CONFIG_ARCH_VERSATILE_PB) := 0x00008000 +params_phys-$(CONFIG_ARCH_VERSATILE_PB) := 0x00000100 +initrd_phys-$(CONFIG_ARCH_VERSATILE_PB) := 0x00800000 ZRELADDR := $(zreladdr-y) ZTEXTADDR := $(ztextaddr-y) diff -Nru a/arch/arm/common/Makefile b/arch/arm/common/Makefile --- a/arch/arm/common/Makefile Sun Apr 25 22:39:31 2004 +++ b/arch/arm/common/Makefile Sun Apr 25 22:39:31 2004 @@ -5,6 +5,7 @@ obj-y += platform.o obj-$(CONFIG_ARM_AMBA) += amba.o obj-$(CONFIG_ICST525) += icst525.o -obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o +obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o +obj-$(CONFIG_DMABOUNCE) += dmabounce.o diff -Nru a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/common/dmabounce.c Sun Apr 25 22:39:31 2004 @@ -0,0 +1,675 @@ +/* + * arch/arm/common/dmabounce.c + * + * Special dma_{map/unmap/dma_sync}_* routines for systems that have + * limited DMA windows. These functions utilize bounce buffers to + * copy data to/from buffers located outside the DMA region. This + * only works for systems in which DMA memory is at the bottom of + * RAM and the remainder of memory is at the top an the DMA memory + * can be marked as ZONE_DMA. Anything beyond that such as discontigous + * DMA windows will require custom implementations that reserve memory + * areas at early bootup. + * + * Original version by Brad Parker (brad@heeltoe.com) + * Re-written by Christopher Hoover + * Made generic by Deepak Saxena + * + * Copyright (C) 2002 Hewlett Packard Company. + * Copyright (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#undef STATS +#ifdef STATS +#define DO_STATS(X) do { X ; } while (0) +#else +#define DO_STATS(X) do { } while (0) +#endif + +/* ************************************************** */ + +struct safe_buffer { + struct list_head node; + + /* original request */ + void *ptr; + size_t size; + int direction; + + /* safe buffer info */ + struct dma_pool *pool; + void *safe; + dma_addr_t safe_dma_addr; +}; + +struct dmabounce_device_info { + struct list_head node; + + struct device *dev; + struct dma_pool *small_buffer_pool; + struct dma_pool *large_buffer_pool; + struct list_head safe_buffers; + unsigned long small_buffer_size, large_buffer_size; +#ifdef STATS + unsigned long sbp_allocs; + unsigned long lbp_allocs; + unsigned long total_allocs; + unsigned long map_op_count; + unsigned long bounce_count; +#endif +}; + +static LIST_HEAD(dmabounce_devs); + +#ifdef STATS +static void print_alloc_stats(struct dmabounce_device_info *device_info) +{ + printk(KERN_INFO + "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", + device_info->dev->bus_id, + device_info->sbp_allocs, device_info->lbp_allocs, + device_info->total_allocs - device_info->sbp_allocs - + device_info->lbp_allocs, + device_info->total_allocs); +} +#endif + +/* find the given device in the dmabounce device list */ +static inline struct dmabounce_device_info * +find_dmabounce_dev(struct device *dev) +{ + struct list_head *entry; + + list_for_each(entry, &dmabounce_devs) { + struct dmabounce_device_info *d = + list_entry(entry, struct dmabounce_device_info, node); + + if (d->dev == dev) + return d; + } +} + + +/* allocate a 'safe' buffer and keep track of it */ +static inline struct safe_buffer * +alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, + size_t size, enum dma_data_direction dir) +{ + struct safe_buffer *buf; + struct dma_pool *pool; + struct device *dev = device_info->dev; + void *safe; + dma_addr_t safe_dma_addr; + + dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n", + __func__, ptr, size, dir); + + DO_STATS ( device_info->total_allocs++ ); + + buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); + if (buf == 0) { + dev_warn(dev, "%s: kmalloc failed\n", __func__); + return 0; + } + + if (size <= device_info->small_buffer_size) { + pool = device_info->small_buffer_pool; + safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); + + DO_STATS ( device_info->sbp_allocs++ ); + } else if (size <= device_info->large_buffer_size) { + pool = device_info->large_buffer_pool; + safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); + + DO_STATS ( device_info->lbp_allocs++ ); + } else { + pool = 0; + safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC); + } + + if (safe == 0) { + dev_warn(device_info->dev, + "%s: could not alloc dma memory (size=%d)\n", + __func__, size); + kfree(buf); + return 0; + } + +#ifdef STATS + if (device_info->total_allocs % 1000 == 0) + print_alloc_stats(device_info); +#endif + + buf->ptr = ptr; + buf->size = size; + buf->direction = dir; + buf->pool = pool; + buf->safe = safe; + buf->safe_dma_addr = safe_dma_addr; + + list_add(&buf->node, &device_info->safe_buffers); + + return buf; +} + +/* determine if a buffer is from our "safe" pool */ +static inline struct safe_buffer * +find_safe_buffer(struct dmabounce_device_info *device_info, dma_addr_t safe_dma_addr) +{ + struct list_head *entry; + + list_for_each(entry, &device_info->safe_buffers) { + struct safe_buffer *b = + list_entry(entry, struct safe_buffer, node); + + if (b->safe_dma_addr == safe_dma_addr) + return b; + } + + return NULL; +} + +static inline void +free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer *buf) +{ + dev_dbg(dev_info->dev, "%s(buf=%p)\n", __func__, buf); + + list_del(&buf->node); + + if (buf->pool) + dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); + else + dma_free_coherent(device_info->dev, buf->size, buf->safe, + buf->safe_dma_addr); + + kfree(buf); +} + +/* ************************************************** */ + +#ifdef STATS + +static void print_map_stats(struct dmabounce_device_info *device_info) +{ + printk(KERN_INFO + "%s: dmabounce: map_op_count=%lu, bounce_count=%lu\n", + device_info->dev->bus_id, + device_info->map_op_count, device_info->bounce_count); +} +#endif + +static inline dma_addr_t +map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + dma_addr_t dma_addr; + struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + + if (device_info) + DO_STATS ( device_info->map_op_count++ ); + + if (dev->dma_mask) { + unsigned long limit; + + limit = (*dev->dma_mask + 1) & ~(*dev->dma_mask); + if (limit && (size > limit)) { + dev_err(dev, "DMA mapping too big " + "(requested %#x mask %#Lx)\n", + size, *dev->dma_mask); + return ~0; + } + } + + dma_addr = virt_to_bus(ptr); + + if (device_info && dma_needs_bounce(dev, dma_addr, size)) { + struct safe_buffer *buf; + + buf = alloc_safe_buffer(device_info, ptr, size, dir); + if (buf == 0) { + dev_err(dev, "%s: unable to map unsafe buffer %p!\n", + __func__, ptr); + return 0; + } + + dev_dbg(dev, + "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", + __func__, buf->ptr, (void *) virt_to_bus(buf->ptr), + buf->safe, (void *) buf->safe_dma_addr); + + if ((dir == DMA_TO_DEVICE) || + (dir == DMA_BIDIRECTIONAL)) { + dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", + __func__, ptr, buf->safe, size); + memcpy(buf->safe, ptr, size); + } + consistent_sync(buf->safe, size, dir); + + dma_addr = buf->safe_dma_addr; + } else { + consistent_sync(ptr, size, dir); + } + + return dma_addr; +} + +static inline void +unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) +{ + struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + struct safe_buffer *buf = NULL; + + /* + * Trying to unmap an invalid mapping + */ + if (dma_addr == ~0) { + dev_err(dev, "Trying to unmap invalid mapping\n"); + return; + } + + if (device_info) + buf = find_safe_buffer(device_info, dma_addr); + + if (buf) { + BUG_ON(buf->size != size); + + dev_dbg(dev, + "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", + __func__, buf->ptr, (void *) virt_to_bus(buf->ptr), + buf->safe, (void *) buf->safe_dma_addr); + + + DO_STATS ( device_info->bounce_count++ ); + + if ((dir == DMA_FROM_DEVICE) || + (dir == DMA_BIDIRECTIONAL)) { + dev_dbg(dev, + "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe, buf->ptr, size); + memcpy(buf->ptr, buf->safe, size); + } + free_safe_buffer(device_info, buf); + } +} + +static inline void +sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) +{ + struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + struct safe_buffer *buf = NULL; + + if (device_info) + buf = find_safe_buffer(device_info, dma_addr); + + if (buf) { + /* + * Both of these checks from original code need to be + * commented out b/c some drivers rely on the following: + * + * 1) Drivers may map a large chunk of memory into DMA space + * but only sync a small portion of it. Good example is + * allocating a large buffer, mapping it, and then + * breaking it up into small descriptors. No point + * in syncing the whole buffer if you only have to + * touch one descriptor. + * + * 2) Buffers that are mapped as DMA_BIDIRECTIONAL are + * usually only synced in one dir at a time. + * + * See drivers/net/eepro100.c for examples of both cases. + * + * -ds + * + * BUG_ON(buf->size != size); + * BUG_ON(buf->direction != dir); + */ + + dev_dbg(dev, + "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", + __func__, buf->ptr, (void *) virt_to_bus(buf->ptr), + buf->safe, (void *) buf->safe_dma_addr); + + DO_STATS ( device_info->bounce_count++ ); + + switch (dir) { + case DMA_FROM_DEVICE: + dev_dbg(dev, + "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe, buf->ptr, size); + memcpy(buf->ptr, buf->safe, size); + break; + case DMA_TO_DEVICE: + dev_dbg(dev, + "%s: copy out unsafe %p to safe %p, size %d\n", + __func__,buf->ptr, buf->safe, size); + memcpy(buf->safe, buf->ptr, size); + break; + case DMA_BIDIRECTIONAL: + BUG(); /* is this allowed? what does it mean? */ + default: + BUG(); + } + consistent_sync(buf->safe, size, dir); + } else { + consistent_sync(bus_to_virt(dma_addr), size, dir); + } +} + +/* ************************************************** */ + +/* + * see if a buffer address is in an 'unsafe' range. if it is + * allocate a 'safe' buffer and copy the unsafe buffer into it. + * substitute the safe buffer for the unsafe one. + * (basically move the buffer from an unsafe area to a safe one) + */ +dma_addr_t +dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + unsigned long flags; + dma_addr_t dma_addr; + + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, ptr, size, dir); + + BUG_ON(dir == DMA_NONE); + + local_irq_save(flags); + + dma_addr = map_single(dev, ptr, size, dir); + + local_irq_restore(flags); + + return dma_addr; +} + +/* + * see if a mapped address was really a "safe" buffer and if so, copy + * the data from the safe buffer back to the unsafe buffer and free up + * the safe buffer. (basically return things back to the way they + * should be) + */ + +void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) +{ + unsigned long flags; + + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, dir); + + BUG_ON(dir == DMA_NONE); + + local_irq_save(flags); + + unmap_single(dev, dma_addr, size, dir); + + local_irq_restore(flags); +} + +int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + unsigned long flags; + int i; + + dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, dir); + + BUG_ON(dir == DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + struct page *page = sg->page; + unsigned int offset = sg->offset; + unsigned int length = sg->length; + void *ptr = page_address(page) + offset; + + sg->dma_address = + map_single(dev, ptr, length, dir); + } + + local_irq_restore(flags); + + return nents; +} + +void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + unsigned long flags; + int i; + + dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, dir); + + BUG_ON(dir == DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + dma_addr_t dma_addr = sg->dma_address; + unsigned int length = sg->length; + + unmap_single(dev, dma_addr, length, dir); + } + + local_irq_restore(flags); +} + +void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) +{ + unsigned long flags; + + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, dir); + + local_irq_save(flags); + + sync_single(dev, dma_addr, size, dir); + + local_irq_restore(flags); +} + +void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) +{ + unsigned long flags; + + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, dir); + + local_irq_save(flags); + + sync_single(dev, dma_addr, size, dir); + + local_irq_restore(flags); +} + +void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + unsigned long flags; + int i; + + dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, dir); + + BUG_ON(dir == DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + dma_addr_t dma_addr = sg->dma_address; + unsigned int length = sg->length; + + sync_single(dev, dma_addr, length, dir); + } + + local_irq_restore(flags); +} + +void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + unsigned long flags; + int i; + + dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, dir); + + BUG_ON(dir == DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + dma_addr_t dma_addr = sg->dma_address; + unsigned int length = sg->length; + + sync_single(dev, dma_addr, length, dir); + } + + local_irq_restore(flags); +} + +int +dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, + unsigned long large_buffer_size) +{ + struct dmabounce_device_info *device_info; + + device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC); + if (!device_info) { + printk(KERN_ERR + "Could not allocated dmabounce_device_info for %s", + dev->bus_id); + return -ENOMEM; + } + + device_info->small_buffer_pool = + dma_pool_create("small_dmabounce_pool", + dev, + small_buffer_size, + 0 /* byte alignment */, + 0 /* no page-crossing issues */); + if (!device_info->small_buffer_pool) { + printk(KERN_ERR + "dmabounce: could not allocate small DMA pool for %s\n", + dev->bus_id); + kfree(device_info); + return -ENOMEM; + } + + if (large_buffer_size) { + device_info->large_buffer_pool = + dma_pool_create("large_dmabounce_pool", + dev, + large_buffer_size, + 0 /* byte alignment */, + 0 /* no page-crossing issues */); + if (!device_info->large_buffer_pool) { + printk(KERN_ERR + "dmabounce: could not allocate large DMA pool for %s\n", + dev->bus_id); + dma_pool_destroy(device_info->small_buffer_pool); + + return -ENOMEM; + } + } + + device_info->dev = dev; + device_info->small_buffer_size = small_buffer_size; + device_info->large_buffer_size = large_buffer_size; + INIT_LIST_HEAD(&device_info->safe_buffers); + +#ifdef STATS + device_info->sbp_allocs = 0; + device_info->lbp_allocs = 0; + device_info->total_allocs = 0; + device_info->map_op_count = 0; + device_info->bounce_count = 0; +#endif + + list_add(&device_info->node, &dmabounce_devs); + + printk(KERN_INFO "dmabounce: registered device %s on %s bus\n", + dev->bus_id, dev->bus->name); + + return 0; +} + +void +dmabounce_unregister_dev(struct device *dev) +{ + struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); + + if (!device_info) { + printk(KERN_WARNING + "%s: Never registered with dmabounce but attempting" \ + "to unregister!\n", dev->bus_id); + return; + } + + if (!list_empty(&device_info->safe_buffers)) { + printk(KERN_ERR, + "%s: Removing from dmabounce with pending buffers!\n", + dev->bus_id); + BUG(); + } + + if (device_info->small_buffer_pool) + dma_pool_destroy(device_info->small_buffer_pool); + if (device_info->large_buffer_pool) + dma_pool_destroy(device_info->large_buffer_pool); + +#ifdef STATS + print_alloc_stats(device_info); + print_map_stats(device_info); +#endif + + list_del(&device_info->node); + + kfree(device_info); + + printk(KERN_INFO "dmabounce: device %s on %s bus unregistered\n", + dev->bus_id, dev->bus->name); +} + + +EXPORT_SYMBOL(dma_map_single); +EXPORT_SYMBOL(dma_unmap_single); +EXPORT_SYMBOL(dma_map_sg); +EXPORT_SYMBOL(dma_unmap_sg); +EXPORT_SYMBOL(dma_sync_single); +EXPORT_SYMBOL(dma_sync_sg); +EXPORT_SYMBOL(dmabounce_register_dev); +EXPORT_SYMBOL(dmabounce_unregister_dev); + +MODULE_AUTHOR("Christopher Hoover , Deepak Saxena "); +MODULE_DESCRIPTION("Special dma_{map/unmap/dma_sync}_* routines for systems with limited DMA windows"); +MODULE_LICENSE("GPL"); diff -Nru a/arch/arm/common/sa1111-pcibuf.c b/arch/arm/common/sa1111-pcibuf.c --- a/arch/arm/common/sa1111-pcibuf.c Sun Apr 25 22:39:31 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,566 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/sa1111-pcibuf.c - * - * Special dma_{map/unmap/dma_sync}_* routines for SA-1111. - * - * These functions utilize bouncer buffers to compensate for a bug in - * the SA-1111 hardware which don't allow DMA to/from addresses - * certain addresses above 1MB. - * - * Re-written by Christopher Hoover - * Original version by Brad Parker (brad@heeltoe.com) - * - * Copyright (C) 2002 Hewlett Packard Company. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * */ - -//#define DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include - -//#define STATS -#ifdef STATS -#define DO_STATS(X) do { X ; } while (0) -#else -#define DO_STATS(X) do { } while (0) -#endif - -/* ************************************************** */ - -struct safe_buffer { - struct list_head node; - - /* original request */ - void *ptr; - size_t size; - enum dma_data_direction direction; - - /* safe buffer info */ - struct dma_pool *pool; - void *safe; - dma_addr_t safe_dma_addr; - struct device *dev; -}; - -static LIST_HEAD(safe_buffers); - - -#define SIZE_SMALL 1024 -#define SIZE_LARGE (4*1024) - -static struct dma_pool *small_buffer_pool, *large_buffer_pool; - -#ifdef STATS -static unsigned long sbp_allocs __initdata = 0; -static unsigned long lbp_allocs __initdata = 0; -static unsigned long total_allocs __initdata= 0; - -static void print_alloc_stats(void) -{ - printk(KERN_INFO - "sa1111_dmabuf: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", - sbp_allocs, lbp_allocs, - total_allocs - sbp_allocs - lbp_allocs, total_allocs); -} -#endif - -static int __init create_safe_buffer_pools(void) -{ - small_buffer_pool = dma_pool_create("sa1111_small_dma_buffer", - NULL, SIZE_SMALL, - 0 /* byte alignment */, - 0 /* no page-crossing issues */); - if (small_buffer_pool == NULL) { - printk(KERN_ERR - "sa1111_dmabuf: could not allocate small pci pool\n"); - return -ENOMEM; - } - - large_buffer_pool = dma_pool_create("sa1111_large_dma_buffer", - NULL, SIZE_LARGE, - 0 /* byte alignment */, - 0 /* no page-crossing issues */); - if (large_buffer_pool == NULL) { - printk(KERN_ERR - "sa1111_dmabuf: could not allocate large pci pool\n"); - dma_pool_destroy(small_buffer_pool); - small_buffer_pool = NULL; - return -ENOMEM; - } - - printk(KERN_INFO "SA1111: DMA buffer sizes: small=%u, large=%u\n", - SIZE_SMALL, SIZE_LARGE); - - return 0; -} - -static void __exit destroy_safe_buffer_pools(void) -{ - if (small_buffer_pool) - dma_pool_destroy(small_buffer_pool); - if (large_buffer_pool) - dma_pool_destroy(large_buffer_pool); - - small_buffer_pool = large_buffer_pool = NULL; -} - - -/* allocate a 'safe' buffer and keep track of it */ -static struct safe_buffer *alloc_safe_buffer(struct device *dev, void *ptr, - size_t size, - enum dma_data_direction dir) -{ - struct safe_buffer *buf; - struct dma_pool *pool; - void *safe; - dma_addr_t safe_dma_addr; - - dev_dbg(dev, "%s(ptr=%p, size=%d, direction=%d)\n", - __func__, ptr, size, dir); - - DO_STATS ( total_allocs++ ); - - buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); - if (buf == NULL) { - printk(KERN_WARNING "%s: kmalloc failed\n", __func__); - return 0; - } - - if (size <= SIZE_SMALL) { - pool = small_buffer_pool; - safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); - - DO_STATS ( sbp_allocs++ ); - } else if (size <= SIZE_LARGE) { - pool = large_buffer_pool; - safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); - - DO_STATS ( lbp_allocs++ ); - } else { - pool = NULL; - safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC); - } - - if (safe == NULL) { - printk(KERN_WARNING - "%s: could not alloc dma memory (size=%d)\n", - __func__, size); - kfree(buf); - return 0; - } - -#ifdef STATS - if (total_allocs % 1000 == 0) - print_alloc_stats(); -#endif - - BUG_ON(sa1111_check_dma_bug(safe_dma_addr)); // paranoia - - buf->ptr = ptr; - buf->size = size; - buf->direction = dir; - buf->pool = pool; - buf->safe = safe; - buf->safe_dma_addr = safe_dma_addr; - buf->dev = dev; - - list_add(&buf->node, &safe_buffers); - - return buf; -} - -/* determine if a buffer is from our "safe" pool */ -static struct safe_buffer *find_safe_buffer(struct device *dev, - dma_addr_t safe_dma_addr) -{ - struct list_head *entry; - - list_for_each(entry, &safe_buffers) { - struct safe_buffer *b = - list_entry(entry, struct safe_buffer, node); - - if (b->safe_dma_addr == safe_dma_addr && - b->dev == dev) { - return b; - } - } - - return 0; -} - -static void free_safe_buffer(struct safe_buffer *buf) -{ - pr_debug("%s(buf=%p)\n", __func__, buf); - - list_del(&buf->node); - - if (buf->pool) - dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); - else - dma_free_coherent(buf->dev, buf->size, buf->safe, - buf->safe_dma_addr); - kfree(buf); -} - -static inline int dma_range_is_safe(struct device *dev, dma_addr_t addr, - size_t size) -{ - unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr); - - /* Any address within one megabyte of the start of the target - * bank will be OK. This is an overly conservative test: - * other addresses can be OK depending on the dram - * configuration. (See sa1111.c:sa1111_check_dma_bug() * for - * details.) - * - * We take care to ensure the entire dma region is within - * the safe range. - */ - - return ((physaddr + size - 1) < (1<<20)); -} - -/* ************************************************** */ - -#ifdef STATS -static unsigned long map_op_count __initdata = 0; -static unsigned long bounce_count __initdata = 0; - -static void print_map_stats(void) -{ - printk(KERN_INFO - "sa1111_dmabuf: map_op_count=%lu, bounce_count=%lu\n", - map_op_count, bounce_count); -} -#endif - -static dma_addr_t map_single(struct device *dev, void *ptr, - size_t size, enum dma_data_direction dir) -{ - dma_addr_t dma_addr; - - DO_STATS ( map_op_count++ ); - - dma_addr = virt_to_bus(ptr); - - if (!dma_range_is_safe(dev, dma_addr, size)) { - struct safe_buffer *buf; - - DO_STATS ( bounce_count++ ) ; - - buf = alloc_safe_buffer(dev, ptr, size, dir); - if (buf == NULL) { - printk(KERN_ERR - "%s: unable to map unsafe buffer %p!\n", - __func__, ptr); - return 0; - } - - dev_dbg(dev, "%s: unsafe buffer %p (phy=%08lx) mapped to %p (phy=%08x)\n", - __func__, - buf->ptr, virt_to_bus(buf->ptr), - buf->safe, buf->safe_dma_addr); - - if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { - dev_dbg(dev, "%s: copy out from unsafe %p, to safe %p, size %d\n", - __func__, ptr, buf->safe, size); - memcpy(buf->safe, ptr, size); - } - - dma_addr = buf->safe_dma_addr; - ptr = buf->safe; - } - - consistent_sync(ptr, size, dir); - -#ifdef STATS - if (map_op_count % 1000 == 0) - print_map_stats(); -#endif - - return dma_addr; -} - -static void unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir) -{ - struct safe_buffer *buf; - - buf = find_safe_buffer(dev, dma_addr); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != dir); - - dev_dbg(dev, "%s: unsafe buffer %p (phy=%08lx) mapped to %p (phy=%08lx)\n", - __func__, - buf->ptr, virt_to_bus(buf->ptr), - buf->safe, buf->safe_dma_addr); - - DO_STATS ( bounce_count++ ); - - if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { - dev_dbg(dev, "%s: copy back from safe %p, to unsafe %p size %d\n", - __func__, buf->safe, buf->ptr, size); - memcpy(buf->ptr, buf->safe, size); - } - free_safe_buffer(buf); - } -} - -static void sync_single(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir) -{ - struct safe_buffer *buf; - void *ptr; - - buf = find_safe_buffer(dev, dma_addr); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != dir); - - dev_dbg(dev, "%s: unsafe buffer %p (phy=%08lx) mapped to %p (phy=%08lx)\n", - __func__, - buf->ptr, virt_to_bus(buf->ptr), - buf->safe, buf->safe_dma_addr); - - DO_STATS ( bounce_count++ ); - - switch (dir) { - case DMA_FROM_DEVICE: - dev_dbg(dev, "%s: copy back from safe %p, to unsafe %p size %d\n", - __func__, buf->safe, buf->ptr, size); - memcpy(buf->ptr, buf->safe, size); - break; - case DMA_TO_DEVICE: - dev_dbg(dev, "%s: copy out from unsafe %p, to safe %p, size %d\n", - __func__,buf->ptr, buf->safe, size); - memcpy(buf->safe, buf->ptr, size); - break; - case DMA_BIDIRECTIONAL: - BUG(); /* is this allowed? what does it mean? */ - default: - BUG(); - } - ptr = buf->safe; - } else { - ptr = bus_to_virt(dma_addr); - } - consistent_sync(ptr, size, dir); -} - -/* ************************************************** */ - -/* - * see if a buffer address is in an 'unsafe' range. if it is - * allocate a 'safe' buffer and copy the unsafe buffer into it. - * substitute the safe buffer for the unsafe one. - * (basically move the buffer from an unsafe area to a safe one) - */ -dma_addr_t sa1111_map_single(struct device *dev, void *ptr, - size_t size, enum dma_data_direction dir) -{ - unsigned long flags; - dma_addr_t dma_addr; - - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, ptr, size, dir); - - BUG_ON(dir == DMA_NONE); - - local_irq_save(flags); - - dma_addr = map_single(dev, ptr, size, dir); - - local_irq_restore(flags); - - return dma_addr; -} - -/* - * see if a mapped address was really a "safe" buffer and if so, copy - * the data from the safe buffer back to the unsafe buffer and free up - * the safe buffer. (basically return things back to the way they - * should be) - */ -void sa1111_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir) -{ - unsigned long flags; - - dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n", - __func__, dma_addr, size, dir); - - local_irq_save(flags); - - unmap_single(dev, dma_addr, size, dir); - - local_irq_restore(flags); -} - -int sa1111_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir) -{ - unsigned long flags; - int i; - - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); - - BUG_ON(dir == DMA_NONE); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - struct page *page = sg->page; - unsigned int offset = sg->offset; - unsigned int length = sg->length; - void *ptr = page_address(page) + offset; - - sg->dma_address = map_single(dev, ptr, length, dir); - } - - local_irq_restore(flags); - - return nents; -} - -void sa1111_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir) -{ - unsigned long flags; - int i; - - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; - - unmap_single(dev, dma_addr, length, dir); - } - - local_irq_restore(flags); -} - -void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir) -{ - unsigned long flags; - - dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n", - __func__, dma_addr, size, dir); - - local_irq_save(flags); - - sync_single(dev, dma_addr, size, dir); - - local_irq_restore(flags); -} - -void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir) -{ - unsigned long flags; - - dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n", - __func__, dma_addr, size, dir); - - local_irq_save(flags); - - sync_single(dev, dma_addr, size, dir); - - local_irq_restore(flags); -} - -void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir) -{ - unsigned long flags; - int i; - - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; - - sync_single(dev, dma_addr, length, dir); - } - - local_irq_restore(flags); -} - -void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir) -{ - unsigned long flags; - int i; - - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; - - sync_single(dev, dma_addr, length, dir); - } - - local_irq_restore(flags); -} - -EXPORT_SYMBOL(sa1111_map_single); -EXPORT_SYMBOL(sa1111_unmap_single); -EXPORT_SYMBOL(sa1111_map_sg); -EXPORT_SYMBOL(sa1111_unmap_sg); -EXPORT_SYMBOL(sa1111_dma_sync_single_for_cpu); -EXPORT_SYMBOL(sa1111_dma_sync_single_for_device); -EXPORT_SYMBOL(sa1111_dma_sync_sg_for_cpu); -EXPORT_SYMBOL(sa1111_dma_sync_sg_for_device); - -/* **************************************** */ - -static int __init sa1111_dmabuf_init(void) -{ - printk(KERN_DEBUG "sa1111_dmabuf: initializing SA-1111 DMA buffers\n"); - - return create_safe_buffer_pools(); -} -module_init(sa1111_dmabuf_init); - -static void __exit sa1111_dmabuf_exit(void) -{ - BUG_ON(!list_empty(&safe_buffers)); - -#ifdef STATS - print_alloc_stats(); - print_map_stats(); -#endif - - destroy_safe_buffer_pools(); -} -module_exit(sa1111_dmabuf_exit); - -MODULE_AUTHOR("Christopher Hoover "); -MODULE_DESCRIPTION("Special dma_{map/unmap/dma_sync}_* routines for SA-1111."); -MODULE_LICENSE("GPL"); diff -Nru a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c --- a/arch/arm/common/sa1111.c Sun Apr 25 22:39:31 2004 +++ b/arch/arm/common/sa1111.c Sun Apr 25 22:39:31 2004 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -547,15 +548,6 @@ snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "%4.4lx", info->offset); - /* - * If the parent device has a DMA mask associated with it, - * propagate it down to the children. - */ - if (sachip->dev->dma_mask) { - dev->dma_mask = *sachip->dev->dma_mask; - dev->dev.dma_mask = &dev->dma_mask; - } - dev->devid = info->devid; dev->dev.parent = sachip->dev; dev->dev.bus = &sa1111_bus_type; @@ -573,15 +565,37 @@ if (ret) { printk("SA1111: failed to allocate resource for %s\n", dev->res.name); + kfree(dev); goto out; } + ret = device_register(&dev->dev); if (ret) { release_resource(&dev->res); - out: kfree(dev); + goto out; + } + + /* + * If the parent device has a DMA mask associated with it, + * propagate it down to the children. + */ + if (sachip->dev->dma_mask) { + dev->dma_mask = *sachip->dev->dma_mask; + dev->dev.dma_mask = &dev->dma_mask; + + if (dev->dma_mask != 0xffffffffUL) { + ret = dmabounce_register_dev(&dev->dev, 1024, 4096); + if (ret) { + printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id); + kfree(dev); + device_unregister(dev); + } + } } + +out: return ret; } @@ -742,61 +756,31 @@ * * This routine only identifies whether or not a given DMA address * is susceptible to the bug. + * + * This should only get called for sa1111_device types due to the + * way we configure our device dma_masks. */ -int sa1111_check_dma_bug(dma_addr_t addr) +int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) { - struct sa1111 *sachip = g_sa1111; unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr); - unsigned int smcr; + u32 dma_mask = *dev->dma_mask; - /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module + /* + * Section 4.6 of the "Intel StrongARM SA-1111 Development Module * User's Guide" mentions that jumpers R51 and R52 control the * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * SDRAM bank 1 on Neponset). The default configuration selects * Assabet, so any address in bank 1 is necessarily invalid. */ - if ((machine_is_assabet() || machine_is_pfs168()) && addr >= 0xc8000000) - return -1; + if ((machine_is_assabet() || machine_is_pfs168()) && + (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)) + return 1; - /* The bug only applies to buffers located more than one megabyte - * above the start of the target bank: + /* + * Check to see if either the start or end are illegal. */ - if (physaddr<(1<<20)) - return 0; - - smcr = sa1111_readl(sachip->base + SA1111_SMCR); - switch (FExtr(smcr, SMCR_DRAC)) { - case 01: /* 10 row + bank address bits, A<20> must not be set */ - if (physaddr & (1<<20)) - return -1; - break; - case 02: /* 11 row + bank address bits, A<23> must not be set */ - if (physaddr & (1<<23)) - return -1; - break; - case 03: /* 12 row + bank address bits, A<24> must not be set */ - if (physaddr & (1<<24)) - return -1; - break; - case 04: /* 13 row + bank address bits, A<25> must not be set */ - if (physaddr & (1<<25)) - return -1; - break; - case 05: /* 14 row + bank address bits, A<20> must not be set */ - if (physaddr & (1<<20)) - return -1; - break; - case 06: /* 15 row + bank address bits, A<20> must not be set */ - if (physaddr & (1<<20)) - return -1; - break; - default: - printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n", - __FUNCTION__, FExtr(smcr, SMCR_DRAC)); - return -1; - } - - return 0; + return ((addr & ~(*dev->dma_mask))) || + ((addr + size - 1) & ~(*dev->dma_mask)); } struct sa1111_save_data { @@ -1293,7 +1277,6 @@ MODULE_DESCRIPTION("Intel Corporation SA1111 core driver"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(sa1111_check_dma_bug); EXPORT_SYMBOL(sa1111_select_audio_mode); EXPORT_SYMBOL(sa1111_set_audio_rate); EXPORT_SYMBOL(sa1111_get_audio_rate); diff -Nru a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S --- a/arch/arm/kernel/debug.S Sun Apr 25 22:39:31 2004 +++ b/arch/arm/kernel/debug.S Sun Apr 25 22:39:31 2004 @@ -550,6 +550,35 @@ 1002: @ exit busyuart .endm + +#elif defined(CONFIG_ARCH_VERSATILE_PB) + +#include + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x10000000 + movne \rx, #0xf1000000 @ virtual base + orr \rx, \rx, #0x001F0000 + orr \rx, \rx, #0x00001000 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #UART01x_DR] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy + bne 1001b + .endm #else #error Unknown architecture #endif diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S Sun Apr 25 22:39:31 2004 +++ b/arch/arm/kernel/entry-armv.S Sun Apr 25 22:39:31 2004 @@ -463,6 +463,37 @@ .macro irq_prio_table .endm +#elif defined(CONFIG_ARCH_VERSATILE_PB) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =IO_ADDRESS(VERSATILE_VIC_BASE) + ldr \irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status + mov \irqnr, #0 + teq \irqstat, #0 + beq 1003f + +1001: tst \irqstat, #15 + bne 1002f + add \irqnr, \irqnr, #4 + movs \irqstat, \irqstat, lsr #4 + bne 1001b +1002: tst \irqstat, #1 + bne 1003f + add \irqnr, \irqnr, #1 + movs \irqstat, \irqstat, lsr #1 + bne 1002b +1003: /* EQ will be set if no irqs pending */ + +@ clz \irqnr, \irqstat +@1003: /* EQ will be set if we reach MAXIRQNUM */ + .endm + + .macro irq_prio_table + .endm + #elif defined(CONFIG_ARCH_CLPS711X) #include diff -Nru a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S --- a/arch/arm/lib/findbit.S Sun Apr 25 22:39:31 2004 +++ b/arch/arm/lib/findbit.S Sun Apr 25 22:39:31 2004 @@ -51,6 +51,39 @@ add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit +/* + * Purpose : Find a 'one' bit + * Prototype: int find_first_bit(const unsigned long *addr, unsigned int maxbit); + */ +ENTRY(_find_first_bit_le) + teq r1, #0 + beq 3f + mov r2, #0 +1: ldrb r3, [r0, r2, lsr #3] + movs r3, r3 + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer +2: cmp r2, r1 @ any more? + blo 1b +3: mov r0, r1 @ no free bits + RETINSTR(mov,pc,lr) + +/* + * Purpose : Find next 'one' bit + * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) + */ +ENTRY(_find_next_bit_le) + teq r1, #0 + beq 2b + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + ldrb r3, [r0, r2, lsr #3] + movs r3, r3, lsr ip @ shift off unused bits + bne .found + orr r2, r2, #7 @ if zero, then no bits here + add r2, r2, #1 @ align bit pointer + b 2b @ loop for next bit + #ifdef __ARMEB__ ENTRY(_find_first_zero_bit_be) @@ -73,6 +106,30 @@ eor r3, r2, #0x18 @ big endian byte ordering ldrb r3, [r0, r3, lsr #3] eor r3, r3, #0xff @ now looking for a 1 bit + movs r3, r3, lsr ip @ shift off unused bits + orreq r2, r2, #7 @ if zero, then no bits here + addeq r2, r2, #1 @ align bit pointer + beq 2b @ loop for next bit + +ENTRY(_find_first_bit_be) + teq r1, #0 + beq 3f + mov r2, #0 +1: eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr #3] + movs r3, r3 + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer +2: cmp r2, r1 @ any more? + blo 1b +3: mov r0, r1 @ no free bits + RETINSTR(mov,pc,lr) + +ENTRY(_find_next_bit_be) + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr #3] movs r3, r3, lsr ip @ shift off unused bits orreq r2, r2, #7 @ if zero, then no bits here addeq r2, r2, #1 @ align bit pointer diff -Nru a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-versatile/Makefile Sun Apr 25 22:39:32 2004 @@ -0,0 +1,5 @@ +# +# Makefile for the linux kernel. +# + +obj-y := core.o diff -Nru a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-versatile/core.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,507 @@ +/* + * linux/arch/arm/mach-versatile/core.c + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Versatile Vectored Interrupt Controller. + */ +#define VA_VIC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) +#define VA_SIC_BASE IO_ADDRESS(VERSATILE_SIC_BASE) + +static void vic_mask_irq(unsigned int irq) +{ + irq -= IRQ_VIC_START; + writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); +} + +static void vic_unmask_irq(unsigned int irq) +{ + irq -= IRQ_VIC_START; + writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE); +} + +static struct irqchip vic_chip = { + .ack = vic_mask_irq, + .mask = vic_mask_irq, + .unmask = vic_unmask_irq, +}; + +static void sic_mask_irq(unsigned int irq) +{ + irq -= IRQ_SIC_START; + writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); +} + +static void sic_unmask_irq(unsigned int irq) +{ + irq -= IRQ_SIC_START; + writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET); +} + +static struct irqchip sic_chip = { + .ack = sic_mask_irq, + .mask = sic_mask_irq, + .unmask = sic_unmask_irq, +}; + +static void +sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); + + if (status == 0) { + do_bad_IRQ(irq, desc, regs); + return; + } + + do { + irq = ffs(status) - 1; + status &= ~(1 << irq); + + irq += IRQ_SIC_START; + + desc = irq_desc + irq; + desc->handle(irq, desc, regs); + } while (status); +} + +#if 1 +#define IRQ_MMCI0A IRQ_VICSOURCE22 +#define IRQ_MMCI1A IRQ_VICSOURCE23 +#define IRQ_AACI IRQ_VICSOURCE24 +#define IRQ_ETH IRQ_VICSOURCE25 +#define PIC_MASK 0xFFD00000 +#else +#define IRQ_MMCI0A IRQ_SIC_MMCI0A +#define IRQ_MMCI1A IRQ_SIC_MMCI1A +#define IRQ_AACI IRQ_SIC_AACI +#define IRQ_ETH IRQ_SIC_ETH +#define PIC_MASK 0 +#endif + +static void __init versatile_init_irq(void) +{ + unsigned int i, value; + + /* Disable all interrupts initially. */ + + writel(0, VA_VIC_BASE + VIC_INT_SELECT); + writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE); + writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); + writel(0, VA_VIC_BASE + VIC_IRQ_STATUS); + writel(0, VA_VIC_BASE + VIC_ITCR); + writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR); + + /* + * Make sure we clear all existing interrupts + */ + writel(0, VA_VIC_BASE + VIC_VECT_ADDR); + for (i = 0; i < 19; i++) { + value = readl(VA_VIC_BASE + VIC_VECT_ADDR); + writel(value, VA_VIC_BASE + VIC_VECT_ADDR); + } + + for (i = 0; i < 16; i++) { + value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); + writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); + } + + writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR); + + for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) { + if (i != IRQ_VICSOURCE31) { + set_irq_chip(i, &vic_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } + + set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq); + vic_unmask_irq(IRQ_VICSOURCE31); + + /* Do second interrupt controller */ + writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); + + for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { + if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) { + set_irq_chip(i, &sic_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } + + /* + * Interrupts on secondary controller from 0 to 8 are routed to + * source 31 on PIC. + * Interrupts from 21 to 31 are routed directly to the VIC on + * the corresponding number on primary controller. This is controlled + * by setting PIC_ENABLEx. + */ + writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE); +} + +static struct map_desc versatile_io_desc[] __initdata = { + { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE }, +#ifdef CONFIG_DEBUG_LL + { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, +#endif +#ifdef FIXME + { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, + { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, + { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K, MT_DEVICE }, + { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }, +#endif +}; + +static void __init versatile_map_io(void) +{ + iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); +} + +#define VERSATILE_REFCOUNTER (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) + +/* + * This is the VersatilePB sched_clock implementation. This has + * a resolution of 41.7ns, and a maximum value of about 179s. + */ +unsigned long long sched_clock(void) +{ + unsigned long long v; + + v = (unsigned long long)readl(VERSATILE_REFCOUNTER) * 125; + do_div(v, 3); + + return v; +} + + +#define VERSATILE_FLASHCTRL (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET) + +static int versatile_flash_init(void) +{ + u32 val; + + val = __raw_readl(VERSATILE_FLASHCTRL); + val &= ~VERSATILE_FLASHPROG_FLVPPEN; + __raw_writel(val, VERSATILE_FLASHCTRL); + + return 0; +} + +static void versatile_flash_exit(void) +{ + u32 val; + + val = __raw_readl(VERSATILE_FLASHCTRL); + val &= ~VERSATILE_FLASHPROG_FLVPPEN; + __raw_writel(val, VERSATILE_FLASHCTRL); +} + +static void versatile_flash_set_vpp(int on) +{ + u32 val; + + val = __raw_readl(VERSATILE_FLASHCTRL); + if (on) + val |= VERSATILE_FLASHPROG_FLVPPEN; + else + val &= ~VERSATILE_FLASHPROG_FLVPPEN; + __raw_writel(val, VERSATILE_FLASHCTRL); +} + +static struct flash_platform_data versatile_flash_data = { + .map_name = "cfi_probe", + .width = 4, + .init = versatile_flash_init, + .exit = versatile_flash_exit, + .set_vpp = versatile_flash_set_vpp, +}; + +static struct resource versatile_flash_resource = { + .start = VERSATILE_FLASH_BASE, + .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device versatile_flash_device = { + .name = "armflash", + .id = 0, + .dev = { + .platform_data = &versatile_flash_data, + }, + .num_resources = 1, + .resource = &versatile_flash_resource, +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = VERSATILE_ETH_BASE, + .end = VERSATILE_ETH_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_ETH, + .end = IRQ_ETH, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +#define VERSATILE_SYSMCI (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET) + +static unsigned int mmc_status(struct device *dev) +{ + struct amba_device *adev = container_of(dev, struct amba_device, dev); + u32 mask; + + if (adev->res.start == VERSATILE_MMCI0_BASE) + mask = 1; + else + mask = 2; + + return readl(VERSATILE_SYSMCI) & mask; +} + +static struct mmc_platform_data mmc0_plat_data = { + .mclk = 33000000, + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +static struct mmc_platform_data mmc1_plat_data = { + .mclk = 33000000, + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +#define AMBA_DEVICE(name,busid,base,plat) \ +static struct amba_device name##_device = { \ + .dev = { \ + .coherent_dma_mask = ~0, \ + .bus_id = busid, \ + .platform_data = plat, \ + }, \ + .res = { \ + .start = VERSATILE_##base##_BASE, \ + .end = (VERSATILE_##base##_BASE) + SZ_4K - 1,\ + .flags = IORESOURCE_MEM, \ + }, \ + .irq = base##_IRQ, \ + .dma = base##_DMA, \ +} + +#define AACI_IRQ { IRQ_AACI, NO_IRQ } +#define AACI_DMA { 0x80, 0x81 } +#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B } +#define MMCI0_DMA { 0x84, 0 } +#define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ } +#define KMI0_DMA { 0, 0 } +#define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ } +#define KMI1_DMA { 0, 0 } +#define UART3_IRQ { IRQ_SIC_UART3, NO_IRQ } +#define UART3_DMA { 0x86, 0x87 } +#define SCI1_IRQ { IRQ_SIC_SCI3, NO_IRQ } +#define SCI1_DMA { 0x88, 0x89 } +#define MMCI1_IRQ { IRQ_MMCI1A, IRQ_SIC_MMCI1B } +#define MMCI1_DMA { 0x85, 0 } + +/* + * These devices are connected directly to the multi-layer AHB switch + */ +#define SMC_IRQ { NO_IRQ, NO_IRQ } +#define SMC_DMA { 0, 0 } +#define MPMC_IRQ { NO_IRQ, NO_IRQ } +#define MPMC_DMA { 0, 0 } +#define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } +#define CLCD_DMA { 0, 0 } +#define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } +#define DMAC_DMA { 0, 0 } + +/* + * These devices are connected via the core APB bridge + */ +#define SCTL_IRQ { NO_IRQ, NO_IRQ } +#define SCTL_DMA { 0, 0 } +#define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } +#define WATCHDOG_DMA { 0, 0 } +#define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } +#define GPIO0_DMA { 0, 0 } +#define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } +#define GPIO1_DMA { 0, 0 } +#define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } +#define GPIO2_DMA { 0, 0 } +#define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } +#define GPIO3_DMA { 0, 0 } +#define RTC_IRQ { IRQ_RTCINT, NO_IRQ } +#define RTC_DMA { 0, 0 } + +/* + * These devices are connected via the DMA APB bridge + */ +#define SCI_IRQ { IRQ_SCIINT, NO_IRQ } +#define SCI_DMA { 7, 6 } +#define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } +#define UART0_DMA { 15, 14 } +#define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } +#define UART1_DMA { 13, 12 } +#define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } +#define UART2_DMA { 11, 10 } +#define SSP_IRQ { IRQ_SSPINT, NO_IRQ } +#define SSP_DMA { 9, 8 } + +/* FPGA Primecells */ +AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); +AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data); +AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); +AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); +AMBA_DEVICE(uart3, "fpga:09", UART3, NULL); +AMBA_DEVICE(sci1, "fpga:0a", SCI1, NULL); +AMBA_DEVICE(mmc1, "fpga:0b", MMCI1, &mmc1_plat_data); + +/* DevChip Primecells */ +AMBA_DEVICE(smc, "dev:00", SMC, NULL); +AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); +AMBA_DEVICE(clcd, "dev:20", CLCD, NULL); +AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); +AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); +AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); +AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); +AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); +AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL); +AMBA_DEVICE(gpio3, "dev:e7", GPIO3, NULL); +AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); +AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); +AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); +AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); +AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); +AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); + +static struct amba_device *amba_devs[] __initdata = { + &dmac_device, + &uart0_device, + &uart1_device, + &uart2_device, + &uart3_device, + &smc_device, + &mpmc_device, + &clcd_device, + &sctl_device, + &wdog_device, + &gpio0_device, + &gpio1_device, + &gpio2_device, + &gpio3_device, + &rtc_device, + &sci0_device, + &ssp0_device, + &aaci_device, + &mmc0_device, + &kmi0_device, + &kmi1_device, + &sci1_device, + &mmc1_device, +}; + +#define VA_LEDS_BASE (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) + +static void versatile_leds_event(led_event_t ledevt) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(VA_LEDS_BASE); + + switch (ledevt) { + case led_idle_start: + val = val & ~VERSATILE_SYS_LED0; + break; + + case led_idle_end: + val = val | VERSATILE_SYS_LED0; + break; + + case led_timer: + val = val ^ VERSATILE_SYS_LED1; + break; + + case led_halted: + val = 0; + break; + + default: + break; + } + + writel(val, VA_LEDS_BASE); + local_irq_restore(flags); +} + +static void __init versatile_init(void) +{ + int i; + + platform_add_device(&versatile_flash_device); + platform_add_device(&smc91x_device); + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + amba_device_register(d, &iomem_resource); + } + + leds_event = versatile_leds_event; +} + +MACHINE_START(VERSATILE_PB, "ARM-Versatile PB") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000) + BOOT_PARAMS(0x00000100) + MAPIO(versatile_map_io) + INITIRQ(versatile_init_irq) + INIT_MACHINE(versatile_init) +MACHINE_END diff -Nru a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig --- a/arch/arm/mm/Kconfig Sun Apr 25 22:39:31 2004 +++ b/arch/arm/mm/Kconfig Sun Apr 25 22:39:31 2004 @@ -114,8 +114,9 @@ # ARM926T config CPU_ARM926T - bool "Support ARM926T processor" - depends on ARCH_INTEGRATOR || ARCH_OMAP1610 + bool "Support ARM926T processor" if ARCH_INTEGRATOR + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || ARCH_OMAP1610 + default y if ARCH_VERSATILE_PB select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_COPY_V4WB diff -Nru a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c --- a/arch/arm26/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/arm26/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -165,18 +165,6 @@ c_backtrace(fp, processor_mode(regs)); } -/* - * This is called from SysRq-T (show_task) to display the current - * call trace for each process. Very useful. - */ -void show_trace_task(struct task_struct *tsk) -{ - if (tsk != current) { - unsigned int fp = thread_saved_fp(tsk); - c_backtrace(fp, 0x10); - } -} - /* FIXME - this is probably wrong.. */ void show_stack(struct task_struct *task, unsigned long *sp) { dump_mem("Stack: ", (unsigned long)sp, 8192+(unsigned long)task->thread_info); diff -Nru a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c --- a/arch/cris/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/cris/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -60,14 +60,6 @@ } } -void show_trace_task(struct task_struct *tsk) -{ - /* TODO, this is not really useful since its called from - * SysRq-T and we don't have a keyboard.. :) - */ -} - - /* * These constants are for searching for possible module text * segments. MODULE_RANGE is a guess of how much space is likely diff -Nru a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c --- a/arch/h8300/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/h8300/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -156,14 +156,8 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_stack(tsk,(unsigned long *)tsk->thread.esp0); -} - void dump_stack(void) { show_stack(NULL,NULL); } - EXPORT_SYMBOL(dump_stack); diff -Nru a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c --- a/arch/i386/kernel/cpu/cpufreq/acpi.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c Sun Apr 25 22:39:31 2004 @@ -238,6 +238,34 @@ } +static unsigned long +acpi_cpufreq_guess_freq ( + struct cpufreq_acpi_io *data, + unsigned int cpu) +{ + if (cpu_khz) { + /* search the closest match to cpu_khz */ + unsigned int i; + unsigned long freq; + unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000; + + for (i=0; i < (data->acpi_data.state_count - 1); i++) { + freq = freqn; + freqn = data->acpi_data.states[i+1].core_frequency * 1000; + if ((2 * cpu_khz) > (freqn + freq)) { + data->acpi_data.state = i; + return (freq); + } + } + data->acpi_data.state = data->acpi_data.state_count - 1; + return (freqn); + } else + /* assume CPU is at P0... */ + data->acpi_data.state = 0; + return data->acpi_data.states[0].core_frequency * 1000; + +} + static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -290,11 +318,8 @@ } policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* - * The current speed is unknown and not detectable by ACPI... argh! Assume - * it's P0, it will be set to this value later during initialization. - */ - policy->cur = data->acpi_data.states[0].core_frequency * 1000; + /* The current speed is unknown and not detectable by ACPI... */ + policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); /* table init */ for (i=0; i<=data->acpi_data.state_count; i++) @@ -306,7 +331,7 @@ data->freq_table[i].frequency = CPUFREQ_TABLE_END; } - result = cpufreq_frequency_table_cpuinfo(policy, &data->freq_table[0]); + result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); if (result) { goto err_freqfree; } @@ -321,6 +346,7 @@ (u32) data->acpi_data.states[i].power, (u32) data->acpi_data.states[i].transition_latency); + cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); return_VALUE(result); err_freqfree: @@ -345,6 +371,7 @@ ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit"); if (data) { + cpufreq_frequency_table_put_attr(policy->cpu); acpi_io_data[policy->cpu] = NULL; acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); kfree(data); @@ -354,6 +381,11 @@ } +static struct freq_attr* acpi_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + static struct cpufreq_driver acpi_cpufreq_driver = { .verify = acpi_cpufreq_verify, .target = acpi_cpufreq_target, @@ -361,6 +393,7 @@ .exit = acpi_cpufreq_cpu_exit, .name = "acpi-cpufreq", .owner = THIS_MODULE, + .attr = acpi_cpufreq_attr, }; diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Sun Apr 25 22:39:31 2004 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,11 @@ #include #include +#ifdef CONFIG_ACPI_PROCESSOR +#include +#include +#endif + #include "powernow-k7.h" #define DEBUG @@ -57,6 +63,17 @@ u8 numpstates; }; +#ifdef CONFIG_ACPI_PROCESSOR +union powernow_acpi_control_t { + struct { + unsigned long fid:5, + vid:5, + sgtc:20, + res1:2; + } bits; + unsigned long val; +}; +#endif /* divide by 1000 to get VID. */ static int mobile_vid_table[32] = { @@ -74,6 +91,12 @@ 150, 225, 160, 165, 170, 180, -1, -1, }; +/* This parameter is used in order to force ACPI instead of legacy method for + * configuration purpose. + */ + +static int powernow_acpi_force; + static struct cpufreq_frequency_table *powernow_table; static unsigned int can_scale_bus; @@ -85,6 +108,14 @@ static unsigned int latency; static char have_a0; +static int check_fsb(unsigned int fsbspeed) +{ + int delta; + unsigned int f = fsb / 1000; + + delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed; + return (delta < 5); +} static int check_powernow(void) { @@ -140,7 +171,8 @@ static int get_ranges (unsigned char *pst) { - unsigned int j, speed; + unsigned int j; + unsigned int speed; u8 fid, vid; powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); @@ -151,12 +183,12 @@ for (j=0 ; j < number_scales; j++) { fid = *pst++; - powernow_table[j].frequency = fsb * fid_codes[fid] * 100; + powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10; powernow_table[j].index = fid; /* lower 8 bits */ - speed = fsb * (fid_codes[fid]/10); + speed = powernow_table[j].frequency; + if ((fid_codes[fid] % 10)==5) { - speed += fsb/2; #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) if (have_a0 == 1) powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; @@ -164,7 +196,7 @@ } dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, - fid_codes[fid] / 10, fid_codes[fid] % 10, speed); + fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); if (speed < minimum_speed) minimum_speed = speed; @@ -176,8 +208,6 @@ dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); } - dprintk ("\n"); - powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; powernow_table[number_scales].index = 0; @@ -234,7 +264,8 @@ rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); cfid = fidvidstatus.bits.CFID; - freqs.old = fsb * fid_codes[cfid] * 100; + freqs.old = fsb * fid_codes[cfid] / 10; + freqs.new = powernow_table[index].frequency; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); @@ -262,19 +293,136 @@ } +#ifdef CONFIG_ACPI_PROCESSOR + +struct acpi_processor_performance *acpi_processor_perf; + +static int powernow_acpi_init(void) +{ + int i; + int retval = 0; + union powernow_acpi_control_t pc; + + if (acpi_processor_perf != NULL && powernow_table != NULL) { + retval = -EINVAL; + goto err0; + } + + acpi_processor_perf = kmalloc(sizeof(struct acpi_processor_performance), + GFP_KERNEL); + + if (!acpi_processor_perf) { + retval = -ENOMEM; + goto err0; + } + + memset(acpi_processor_perf, 0, sizeof(struct acpi_processor_performance)); + + if (acpi_processor_register_performance(acpi_processor_perf, 0)) { + retval = -EIO; + goto err1; + } + + if (acpi_processor_perf->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { + retval = -ENODEV; + goto err2; + } + + if (acpi_processor_perf->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { + retval = -ENODEV; + goto err2; + } + + number_scales = acpi_processor_perf->state_count; + + if (number_scales < 2) { + retval = -ENODEV; + goto err2; + } + + powernow_table = kmalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL); + if (!powernow_table) { + retval = -ENOMEM; + goto err2; + } + + memset(powernow_table, 0, ((number_scales + 1) * sizeof(struct cpufreq_frequency_table))); + + pc.val = (unsigned long) acpi_processor_perf->states[0].control; + for (i = 0; i < number_scales; i++) { + u8 fid, vid; + unsigned int speed; + + pc.val = (unsigned long) acpi_processor_perf->states[i].control; + dprintk (KERN_INFO PFX "acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", + i, + (u32) acpi_processor_perf->states[i].core_frequency, + (u32) acpi_processor_perf->states[i].power, + (u32) acpi_processor_perf->states[i].transition_latency, + (u32) acpi_processor_perf->states[i].control, + pc.bits.sgtc); + + vid = pc.bits.vid; + fid = pc.bits.fid; + + powernow_table[i].frequency = fsb * fid_codes[fid] / 10; + powernow_table[i].index = fid; /* lower 8 bits */ + powernow_table[i].index |= (vid << 8); /* upper 8 bits */ + + speed = powernow_table[i].frequency; + + if ((fid_codes[fid] % 10)==5) { + if (have_a0 == 1) + powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; + } + + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); + dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, + mobile_vid_table[vid]%1000); + + if (latency < pc.bits.sgtc) + latency = pc.bits.sgtc; + + if (speed < minimum_speed) + minimum_speed = speed; + if (speed > maximum_speed) + maximum_speed = speed; + } + + powernow_table[i].frequency = CPUFREQ_TABLE_END; + powernow_table[i].index = 0; + + return 0; + +err2: + acpi_processor_unregister_performance(acpi_processor_perf, 0); +err1: + kfree(acpi_processor_perf); +err0: + printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n"); + acpi_processor_perf = NULL; + return retval; +} +#else +static int powernow_acpi_init(void) +{ + printk(KERN_INFO PFX "no support for ACPI processor found." + " Please recompile your kernel with ACPI processor\n"); + return -EINVAL; +} +#endif + static int powernow_decode_bios (int maxfid, int startvid) { struct psb_s *psb; struct pst_s *pst; - struct cpuinfo_x86 *c = cpu_data; unsigned int i, j; unsigned char *p; unsigned int etuple; unsigned int ret; etuple = cpuid_eax(0x80000001); - etuple &= 0xf00; - etuple |= (c->x86_model<<4)|(c->x86_mask); for (i=0xC0000; i < 0xffff0 ; i+=16) { @@ -305,7 +453,6 @@ } dprintk (KERN_INFO PFX "Settling Time: %d microseconds.\n", psb->settlingtime); dprintk (KERN_INFO PFX "Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst); - latency *= 100; /* SGTC needs to be in units of 10ns */ p += sizeof (struct psb_s); @@ -315,7 +462,8 @@ pst = (struct pst_s *) p; number_scales = pst->numpstates; - if ((etuple == pst->cpuid) && (maxfid==pst->maxfid) && (startvid==pst->startvid)) + if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) && + (maxfid==pst->maxfid) && (startvid==pst->startvid)) { dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst); dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid); @@ -323,7 +471,6 @@ dprintk ("maxFID: 0x%x\t", pst->maxfid); dprintk ("startvid: 0x%x\n", pst->startvid); - fsb = pst->fsbspeed; ret = get_ranges ((char *) pst + sizeof (struct pst_s)); return ret; @@ -335,7 +482,7 @@ } printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple); printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n"); - printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.shtml\n"); + return -EINVAL; } p++; @@ -365,6 +512,33 @@ return cpufreq_frequency_table_verify(policy, powernow_table); } +/* + * We use the fact that the bus frequency is somehow + * a multiple of 100000/3 khz, then we compute sgtc according + * to this multiple. + * That way, we match more how AMD thinks all of that work. + * We will then get the same kind of behaviour already tested under + * the "well-known" other OS. + */ +static int __init fixup_sgtc(void) +{ + unsigned int sgtc; + unsigned int m; + + m = fsb / 3333; + if ((m % 10) >= 5) + m += 5; + + m /= 10; + + sgtc = 100 * m * latency; + sgtc = sgtc / 3; + if (sgtc > 0xfffff) { + printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc); + sgtc = 0xfffff; + } + return sgtc; +} static int __init powernow_cpu_init (struct cpufreq_policy *policy) { @@ -376,18 +550,45 @@ rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); - result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID); + /* A K7 with powernow technology is set to max frequency by BIOS */ + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; + if (!fsb) { + printk(KERN_WARNING PFX "can not determine bus frequency\n"); + return -EINVAL; + } + dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); + + if ((dmi_broken & BROKEN_CPUFREQ) || powernow_acpi_force) { + printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); + result = powernow_acpi_init(); + } else { + result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID); + if (result) { + printk (KERN_INFO PFX "Trying ACPI perflib\n"); + maximum_speed = 0; + minimum_speed = -1; + latency = 0; + result = powernow_acpi_init(); + if (result) { + printk (KERN_INFO PFX "ACPI and legacy methods failed\n"); + printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.shtml\n"); + } + } else { + /* SGTC use the bus clock as timer */ + latency = fixup_sgtc(); + printk(KERN_INFO PFX "SGTC: %d\n", latency); + } + } + if (result) return result; printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", - minimum_speed, maximum_speed); + minimum_speed/1000, maximum_speed/1000); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* latency is in 10 ns (look for SGTC above) for each VID - * and FID transition, so multiply that value with 20 */ - policy->cpuinfo.transition_latency = latency * 20; + policy->cpuinfo.transition_latency = 20 * latency / fsb; policy->cur = maximum_speed; @@ -418,10 +619,6 @@ static int __init powernow_init (void) { - if (dmi_broken & BROKEN_CPUFREQ) { - printk (KERN_INFO PFX "Disabled at boot time by DMI,\n"); - return -ENODEV; - } if (check_powernow()==0) return -ENODEV; return cpufreq_register_driver(&powernow_driver); @@ -430,15 +627,25 @@ static void __exit powernow_exit (void) { +#ifdef CONFIG_ACPI_PROCESSOR + if (acpi_processor_perf) { + acpi_processor_unregister_performance(acpi_processor_perf, 0); + kfree(acpi_processor_perf); + } +#endif cpufreq_unregister_driver(&powernow_driver); if (powernow_table) kfree(powernow_table); } +module_param(powernow_acpi_force, int, 0444); + +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used"); + MODULE_AUTHOR ("Dave Jones "); MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); MODULE_LICENSE ("GPL"); -module_init(powernow_init); +late_initcall(powernow_init); module_exit(powernow_exit); diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c Sun Apr 25 22:39:31 2004 @@ -32,7 +32,7 @@ #include #include -#ifdef CONFIG_X86_POWERNOW_K8_ACPI +#ifdef CONFIG_ACPI_PROCESSOR #include #include #endif @@ -269,7 +269,7 @@ dprintk(KERN_DEBUG PFX "ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", - smp_processor_id(); + smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); while (data->currvid > reqvid) { @@ -666,7 +666,7 @@ return -ENODEV; } -#ifdef CONFIG_X86_POWERNOW_K8_ACPI +#ifdef CONFIG_ACPI_PROCESSOR static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { if (!data->acpi_data.state_count) diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h Sun Apr 25 22:39:31 2004 @@ -29,7 +29,7 @@ * frequency is in kHz */ struct cpufreq_frequency_table *powernow_table; -#ifdef CONFIG_X86_POWERNOW_K8_ACPI +#ifdef CONFIG_ACPI_PROCESSOR /* the acpi table needs to be kept. it's only available if ACPI was * used to determine valid frequency/vid/fid states */ struct acpi_processor_performance acpi_data; diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c Sun Apr 25 22:39:31 2004 @@ -195,21 +195,6 @@ struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; struct cpu_model *model; - if (!cpu_has(cpu, X86_FEATURE_EST)) - return -ENODEV; - - /* Only Intel Pentium M stepping 5 for now - add new CPUs as - they appear after making sure they use PERF_CTL in the same - way. */ - if (cpu->x86_vendor != X86_VENDOR_INTEL || - cpu->x86 != 6 || - cpu->x86_model != 9 || - cpu->x86_mask != 5) { - printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " - "send /proc/cpuinfo to " MAINTAINER "\n"); - return -ENODEV; - } - for(model = models; model->model_name != NULL; model++) if (strcmp(cpu->x86_model_id, model->model_name) == 0) break; @@ -361,12 +346,28 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) { + struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; unsigned freq; unsigned l, h; int ret; if (policy->cpu != 0) return -ENODEV; + + if (!cpu_has(cpu, X86_FEATURE_EST)) + return -ENODEV; + + /* Only Intel Pentium M stepping 5 for now - add new CPUs as + they appear after making sure they use PERF_CTL in the same + way. */ + if (cpu->x86_vendor != X86_VENDOR_INTEL || + cpu->x86 != 6 || + cpu->x86_model != 9 || + cpu->x86_mask != 5) { + printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " + "send /proc/cpuinfo to " MAINTAINER "\n"); + return -ENODEV; + } if (centrino_cpu_init_acpi(policy)) { if (centrino_cpu_init_table(policy)) { diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c --- a/arch/i386/kernel/i8259.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/i8259.c Sun Apr 25 22:39:31 2004 @@ -445,5 +445,5 @@ if (boot_cpu_data.hard_math && !cpu_has_fpu) setup_irq(FPU_IRQ, &fpu_irq); - irq_ctx_init(current_thread_info()->cpu); + irq_ctx_init(smp_processor_id()); } diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c --- a/arch/i386/kernel/nmi.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/nmi.c Sun Apr 25 22:39:31 2004 @@ -462,8 +462,7 @@ /* Only P6 based Pentium M need to re-unmask * the apic vector but it doesn't hurt * other P6 variant */ - apic_write(APIC_LVTPC, - apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); + apic_write(APIC_LVTPC, APIC_DM_NMI); } wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); } diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -123,16 +123,6 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - unsigned long esp = tsk->thread.esp; - - /* User space on another CPU? */ - if ((esp ^ (unsigned long)tsk->thread_info) & ~(THREAD_SIZE - 1)) - return; - show_trace(tsk, (unsigned long *)esp); -} - void show_stack(struct task_struct *task, unsigned long *esp) { unsigned long *stack; diff -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c --- a/arch/i386/mm/hugetlbpage.c Sun Apr 25 22:39:31 2004 +++ b/arch/i386/mm/hugetlbpage.c Sun Apr 25 22:39:31 2004 @@ -210,19 +210,18 @@ { struct mm_struct *mm = vma->vm_mm; unsigned long address; - pte_t *pte; + pte_t pte; struct page *page; BUG_ON(start & (HPAGE_SIZE - 1)); BUG_ON(end & (HPAGE_SIZE - 1)); for (address = start; address < end; address += HPAGE_SIZE) { - pte = huge_pte_offset(mm, address); - if (pte_none(*pte)) + pte = ptep_get_and_clear(huge_pte_offset(mm, address)); + if (pte_none(pte)) continue; - page = pte_page(*pte); + page = pte_page(pte); huge_page_release(page); - pte_clear(pte); } mm->rss -= (end - start) >> PAGE_SHIFT; flush_tlb_range(vma, start, end); diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S Sun Apr 25 22:39:31 2004 +++ b/arch/ia64/ia32/ia32_entry.S Sun Apr 25 22:39:31 2004 @@ -483,6 +483,14 @@ data8 sys32_fadvise64_64 data8 sys_ni_syscall data8 sys_ni_syscall + data8 sys_ni_syscall /* 275 */ + data8 sys_ni_syscall + data8 compat_sys_mq_open + data8 sys_mq_unlink + data8 compat_sys_mq_timedsend + data8 compat_sys_mq_timedreceive /* 280 */ + data8 compat_sys_mq_notify + data8 compat_sys_mq_getsetattr // guard against failures to increase IA32_NR_syscalls .org ia32_syscall_table + 8*IA32_NR_syscalls diff -Nru a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c --- a/arch/ia64/ia32/ia32_signal.c Sun Apr 25 22:39:31 2004 +++ b/arch/ia64/ia32/ia32_signal.c Sun Apr 25 22:39:31 2004 @@ -169,7 +169,12 @@ addr = (unsigned long) from->si_ptr; err |= __put_user(addr, &to->si_ptr); break; - /* case __SI_RT: This is not generated by the kernel as of now. */ + case __SI_RT >> 16: /* Not generated by the kernel as of now. */ + case __SI_MESGQ >> 16: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; } } return err; @@ -612,7 +617,6 @@ asmlinkage long sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo) { - extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from); mm_segment_t old_fs = get_fs(); siginfo_t info; int ret; diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S Sun Apr 25 22:39:31 2004 +++ b/arch/ia64/kernel/entry.S Sun Apr 25 22:39:31 2004 @@ -1504,12 +1504,12 @@ data8 sys_ni_syscall data8 sys_ni_syscall // 1260 data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall // 1265 - data8 sys_ni_syscall - data8 sys_ni_syscall + data8 sys_mq_open + data8 sys_mq_unlink + data8 sys_mq_timedsend + data8 sys_mq_timedreceive // 1265 + data8 sys_mq_notify + data8 sys_mq_getsetattr data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall // 1270 diff -Nru a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S --- a/arch/ia64/kernel/fsys.S Sun Apr 25 22:39:32 2004 +++ b/arch/ia64/kernel/fsys.S Sun Apr 25 22:39:32 2004 @@ -851,12 +851,12 @@ data8 0 data8 0 // 1260 data8 0 - data8 0 - data8 0 - data8 0 - data8 0 // 1265 - data8 0 - data8 0 + data8 0 // mq_open + data8 0 // mq_unlink + data8 0 // mq_timedsend + data8 0 // mq_timedreceive // 1265 + data8 0 // mq_notify + data8 0 // mq_getsetattr data8 0 data8 0 data8 0 // 1270 diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Sun Apr 25 22:39:31 2004 +++ b/arch/ia64/kernel/iosapic.c Sun Apr 25 22:39:31 2004 @@ -293,7 +293,7 @@ irq &= (~IA64_IRQ_REDIRECTED); vec = irq_to_vector(irq); - if (cpus_empty(mask) || vec >= IA64_NUM_VECTORS) + if (cpus_empty(mask)) return; dest = cpu_physical_id(first_cpu(mask)); diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c --- a/arch/ia64/kernel/signal.c Sun Apr 25 22:39:31 2004 +++ b/arch/ia64/kernel/signal.c Sun Apr 25 22:39:31 2004 @@ -205,6 +205,12 @@ err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_ptr, &to->si_ptr); break; + case __SI_RT >> 16: /* Not generated by the kernel as of now. */ + case __SI_MESGQ >> 16: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); @@ -213,45 +219,11 @@ err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); break; - /* case __SI_RT: This is not generated by the kernel as of now. */ } return err; } } -int -copy_siginfo_from_user (siginfo_t *to, siginfo_t *from) -{ - if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t))) - return -EFAULT; - if (__copy_from_user(to, from, sizeof(siginfo_t)) != 0) - return -EFAULT; - - if (SI_FROMUSER(to)) - return 0; - - to->si_code &= ~__SI_MASK; - if (to->si_code != 0) { - switch (to->si_signo) { - case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGTRAP: - to->si_code |= __SI_FAULT; - break; - - case SIGCHLD: - to->si_code |= __SI_CHLD; - break; - - case SIGPOLL: - to->si_code |= __SI_POLL; - break; - - default: - break; - } - } - return 0; -} - long ia64_rt_sigreturn (struct sigscratch *scr) { @@ -445,6 +417,7 @@ scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ scr->pt.cr_iip = tramp_addr; ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */ + ia64_psr(&scr->pt)->be = 0; /* force little-endian byte-order */ /* * Force the interruption function mask to zero. This has no effect when a * system-call got interrupted by a signal (since, in that case, scr->pt_cr_ifs is diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c --- a/arch/ia64/kernel/traps.c Sun Apr 25 22:39:32 2004 +++ b/arch/ia64/kernel/traps.c Sun Apr 25 22:39:32 2004 @@ -13,6 +13,7 @@ #include #include #include /* For unblank_screen() */ +#include /* for EXPORT_SYMBOL */ #include #include @@ -47,6 +48,7 @@ extern spinlock_t timerlist_lock; fpswa_interface_t *fpswa_interface; +EXPORT_SYMBOL(fpswa_interface); void __init trap_init (void) diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c Sun Apr 25 22:39:31 2004 +++ b/arch/ia64/pci/pci.c Sun Apr 25 22:39:31 2004 @@ -54,56 +54,33 @@ * synchronization mechanism here. */ -#define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \ - ((u64)(seg << 24) | (u64)(bus << 16) | \ +#define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \ + ((u64)(seg << 24) | (u64)(bus << 16) | \ (u64)(devfn << 8) | (u64)(reg)) -static int -pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value) -{ - int result = 0; - u64 data = 0; - - if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), 0, len, &data); - - *value = (u32) data; - - return result; -} - -static int -pci_sal_write (int seg, int bus, int devfn, int reg, int len, u32 value) -{ - if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), 0, len, value); -} - -static struct pci_raw_ops pci_sal_ops = { - .read = pci_sal_read, - .write = pci_sal_write -}; - /* SAL 3.2 adds support for extended config space. */ -#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \ - ((u64)(seg << 28) | (u64)(bus << 20) | \ +#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \ + ((u64)(seg << 28) | (u64)(bus << 20) | \ (u64)(devfn << 12) | (u64)(reg)) static int -pci_sal_ext_read (int seg, int bus, int devfn, int reg, int len, u32 *value) +pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value) { + u64 addr, mode, data = 0; int result = 0; - u64 data = 0; - if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) + if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; - result = ia64_sal_pci_config_read(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), 1, len, &data); + if ((seg | reg) <= 255) { + addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg); + mode = 0; + } else { + addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); + mode = 1; + } + result = ia64_sal_pci_config_read(addr, mode, len, &data); *value = (u32) data; @@ -111,46 +88,42 @@ } static int -pci_sal_ext_write (int seg, int bus, int devfn, int reg, int len, u32 value) +pci_sal_write (int seg, int bus, int devfn, int reg, int len, u32 value) { + u64 addr, mode; + if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; - return ia64_sal_pci_config_write(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), 1, len, value); -} - -static struct pci_raw_ops pci_sal_ext_ops = { - .read = pci_sal_ext_read, - .write = pci_sal_ext_write -}; - -struct pci_raw_ops *raw_pci_ops = &pci_sal_ops; /* default to SAL < 3.2 */ - -static int __init -pci_set_sal_ops (void) -{ - if (sal_revision >= SAL_VERSION_CODE(3, 2)) { - printk("Using SAL 3.2 to access PCI config space\n"); - raw_pci_ops = &pci_sal_ext_ops; + if ((seg | reg) <= 255) { + addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg); + mode = 0; + } else { + addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); + mode = 1; } - return 0; + return ia64_sal_pci_config_write(addr, mode, len, value); } -arch_initcall(pci_set_sal_ops); +static struct pci_raw_ops pci_sal_ops = { + .read = pci_sal_read, + .write = pci_sal_write +}; +struct pci_raw_ops *raw_pci_ops = &pci_sal_ops; static int pci_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { return raw_pci_ops->read(pci_domain_nr(bus), bus->number, - devfn, where, size, value); + devfn, where, size, value); } static int pci_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { return raw_pci_ops->write(pci_domain_nr(bus), bus->number, - devfn, where, size, value); + devfn, where, size, value); } static struct pci_ops pci_root_ops = { diff -Nru a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c --- a/arch/mips/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/mips/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -126,11 +126,6 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_trace(tsk, (long *)tsk->thread.reg29); -} - /* * The architecture-independent dump_stack generator */ diff -Nru a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c --- a/arch/parisc/kernel/traps.c Sun Apr 25 22:39:32 2004 +++ b/arch/parisc/kernel/traps.c Sun Apr 25 22:39:32 2004 @@ -202,11 +202,6 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_trace(tsk, (unsigned long *)tsk->thread.regs.ksp); -} - void die_if_kernel(char *str, struct pt_regs *regs, long err) { if (user_mode(regs)) { diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c --- a/arch/ppc64/kernel/process.c Sun Apr 25 22:39:31 2004 +++ b/arch/ppc64/kernel/process.c Sun Apr 25 22:39:31 2004 @@ -536,10 +536,4 @@ { show_stack(current, (unsigned long *)__get_SP()); } - EXPORT_SYMBOL(dump_stack); - -void show_trace_task(struct task_struct *tsk) -{ - show_stack(tsk, (unsigned long *)tsk->thread.ksp); -} diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile --- a/arch/s390/Makefile Sun Apr 25 22:39:31 2004 +++ b/arch/s390/Makefile Sun Apr 25 22:39:31 2004 @@ -44,7 +44,7 @@ head-$(CONFIG_ARCH_S390X) += arch/$(ARCH)/kernel/head64.o head-y += arch/$(ARCH)/kernel/init_task.o -core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ \ +core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ arch/$(ARCH)/crypto/ \ arch/$(ARCH)/appldata/ libs-y += arch/$(ARCH)/lib/ drivers-y += drivers/s390/ diff -Nru a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/Makefile Sun Apr 25 22:39:32 2004 @@ -0,0 +1,8 @@ +# +# Cryptographic API +# + +obj-$(CONFIG_CRYPTO_SHA1_Z990) += sha1_z990.o +obj-$(CONFIG_CRYPTO_DES_Z990) += des_z990.o des_check_key.o + +obj-$(CONFIG_CRYPTO_TEST) += crypt_z990_query.o diff -Nru a/arch/s390/crypto/crypt_z990.h b/arch/s390/crypto/crypt_z990.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/crypt_z990.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,374 @@ +/* + * Cryptographic API. + * + * Support for z990 cryptographic instructions. + * + * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#ifndef _CRYPTO_ARCH_S390_CRYPT_Z990_H +#define _CRYPTO_ARCH_S390_CRYPT_Z990_H + +#include + +#define CRYPT_Z990_OP_MASK 0xFF00 +#define CRYPT_Z990_FUNC_MASK 0x00FF + + +/*z990 cryptographic operations*/ +enum crypt_z990_operations { + CRYPT_Z990_KM = 0x0100, + CRYPT_Z990_KMC = 0x0200, + CRYPT_Z990_KIMD = 0x0300, + CRYPT_Z990_KLMD = 0x0400, + CRYPT_Z990_KMAC = 0x0500 +}; + +/*function codes for KM (CIPHER MESSAGE) instruction*/ +enum crypt_z990_km_func { + KM_QUERY = CRYPT_Z990_KM | 0, + KM_DEA_ENCRYPT = CRYPT_Z990_KM | 1, + KM_DEA_DECRYPT = CRYPT_Z990_KM | 1 | 0x80, //modifier bit->decipher + KM_TDEA_128_ENCRYPT = CRYPT_Z990_KM | 2, + KM_TDEA_128_DECRYPT = CRYPT_Z990_KM | 2 | 0x80, + KM_TDEA_192_ENCRYPT = CRYPT_Z990_KM | 3, + KM_TDEA_192_DECRYPT = CRYPT_Z990_KM | 3 | 0x80, +}; + +/*function codes for KMC (CIPHER MESSAGE WITH CHAINING) instruction*/ +enum crypt_z990_kmc_func { + KMC_QUERY = CRYPT_Z990_KMC | 0, + KMC_DEA_ENCRYPT = CRYPT_Z990_KMC | 1, + KMC_DEA_DECRYPT = CRYPT_Z990_KMC | 1 | 0x80, //modifier bit->decipher + KMC_TDEA_128_ENCRYPT = CRYPT_Z990_KMC | 2, + KMC_TDEA_128_DECRYPT = CRYPT_Z990_KMC | 2 | 0x80, + KMC_TDEA_192_ENCRYPT = CRYPT_Z990_KMC | 3, + KMC_TDEA_192_DECRYPT = CRYPT_Z990_KMC | 3 | 0x80, +}; + +/*function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) instruction*/ +enum crypt_z990_kimd_func { + KIMD_QUERY = CRYPT_Z990_KIMD | 0, + KIMD_SHA_1 = CRYPT_Z990_KIMD | 1, +}; + +/*function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) instruction*/ +enum crypt_z990_klmd_func { + KLMD_QUERY = CRYPT_Z990_KLMD | 0, + KLMD_SHA_1 = CRYPT_Z990_KLMD | 1, +}; + +/*function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) instruction*/ +enum crypt_z990_kmac_func { + KMAC_QUERY = CRYPT_Z990_KMAC | 0, + KMAC_DEA = CRYPT_Z990_KMAC | 1, + KMAC_TDEA_128 = CRYPT_Z990_KMAC | 2, + KMAC_TDEA_192 = CRYPT_Z990_KMAC | 3 +}; + +/*status word for z990 crypto instructions' QUERY functions*/ +struct crypt_z990_query_status { + u64 high; + u64 low; +}; + +/* + * Standard fixup and ex_table sections for crypt_z990 inline functions. + * label 0: the z990 crypto operation + * label 1: just after 1 to catch illegal operation exception on non-z990 + * label 6: the return point after fixup + * label 7: set error value if exception _in_ crypto operation + * label 8: set error value if illegal operation exception + * [ret] is the variable to receive the error code + * [ERR] is the error code value + */ +#ifndef __s390x__ +#define __crypt_z990_fixup \ + ".section .fixup,\"ax\" \n" \ + "7: lhi %0,%h[e1] \n" \ + " bras 1,9f \n" \ + " .long 6b \n" \ + "8: lhi %0,%h[e2] \n" \ + " bras 1,9f \n" \ + " .long 6b \n" \ + "9: l 1,0(1) \n" \ + " br 1 \n" \ + ".previous \n" \ + ".section __ex_table,\"a\" \n" \ + " .align 4 \n" \ + " .long 0b,7b \n" \ + " .long 1b,8b \n" \ + ".previous" +#else /* __s390x__ */ +#define __crypt_z990_fixup \ + ".section .fixup,\"ax\" \n" \ + "7: lhi %0,%h[e1] \n" \ + " jg 6b \n" \ + "8: lhi %0,%h[e2] \n" \ + " jg 6b \n" \ + ".previous\n" \ + ".section __ex_table,\"a\" \n" \ + " .align 8 \n" \ + " .quad 0b,7b \n" \ + " .quad 1b,8b \n" \ + ".previous" +#endif /* __s390x__ */ + +/* + * Standard code for setting the result of z990 crypto instructions. + * %0: the register which will receive the result + * [result]: the register containing the result (e.g. second operand length + * to compute number of processed bytes]. + */ +#ifndef __s390x__ +#define __crypt_z990_set_result \ + " lr %0,%[result] \n" +#else /* __s390x__ */ +#define __crypt_z990_set_result \ + " lgr %0,%[result] \n" +#endif + +/* + * Executes the KM (CIPHER MESSAGE) operation of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_km_func + * @param param: address of parameter block; see POP for details on each func + * @param dest: address of destination memory area + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for encryption/decryption funcs + */ +static inline int +crypt_z990_km(long func, void* param, u8* dest, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register u8* __dest asm("4") = dest; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB92E0000,%1,%2 \n" //KM opcode + "1: brc 1,0b \n" //handle partial completion + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__dest), "+a" (__src), + [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_kmc_func + * @param param: address of parameter block; see POP for details on each func + * @param dest: address of destination memory area + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for encryption/decryption funcs + */ +static inline int +crypt_z990_kmc(long func, void* param, u8* dest, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register u8* __dest asm("4") = dest; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB92F0000,%1,%2 \n" //KMC opcode + "1: brc 1,0b \n" //handle partial completion + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__dest), "+a" (__src), + [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation + * of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_kimd_func + * @param param: address of parameter block; see POP for details on each func + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for digest funcs + */ +static inline int +crypt_z990_kimd(long func, void* param, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB93E0000,%1,%1 \n" //KIMD opcode + "1: brc 1,0b \n" /*handle partical completion of kimd*/ + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && (func & CRYPT_Z990_FUNC_MASK)){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_klmd_func + * @param param: address of parameter block; see POP for details on each func + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for digest funcs + */ +static inline int +crypt_z990_klmd(long func, void* param, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB93F0000,%1,%1 \n" //KLMD opcode + "1: brc 1,0b \n" /*handle partical completion of klmd*/ + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation + * of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_klmd_func + * @param param: address of parameter block; see POP for details on each func + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for digest funcs + */ +static inline int +crypt_z990_kmac(long func, void* param, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB91E0000,%5,%5 \n" //KMAC opcode + "1: brc 1,0b \n" /*handle partical completion of klmd*/ + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/** + * Tests if a specific z990 crypto function is implemented on the machine. + * @param func: the function code of the specific function; 0 if op in general + * @return 1 if func available; 0 if func or op in general not available + */ +static inline int +crypt_z990_func_available(int func) +{ + int ret; + + struct crypt_z990_query_status status = { + .high = 0, + .low = 0 + }; + switch (func & CRYPT_Z990_OP_MASK){ + case CRYPT_Z990_KM: + ret = crypt_z990_km(KM_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_Z990_KMC: + ret = crypt_z990_kmc(KMC_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_Z990_KIMD: + ret = crypt_z990_kimd(KIMD_QUERY, &status, NULL, 0); + break; + case CRYPT_Z990_KLMD: + ret = crypt_z990_klmd(KLMD_QUERY, &status, NULL, 0); + break; + case CRYPT_Z990_KMAC: + ret = crypt_z990_kmac(KMAC_QUERY, &status, NULL, 0); + break; + default: + ret = 0; + return ret; + } + if (ret >= 0){ + func &= CRYPT_Z990_FUNC_MASK; + func &= 0x7f; //mask modifier bit + if (func < 64){ + ret = (status.high >> (64 - func - 1)) & 0x1; + } else { + ret = (status.low >> (128 - func - 1)) & 0x1; + } + } else { + ret = 0; + } + return ret; +} + + +#endif // _CRYPTO_ARCH_S390_CRYPT_Z990_H diff -Nru a/arch/s390/crypto/crypt_z990_query.c b/arch/s390/crypto/crypt_z990_query.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/crypt_z990_query.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,111 @@ +/* + * Cryptographic API. + * + * Support for z990 cryptographic instructions. + * Testing module for querying processor crypto capabilities. + * + * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include "crypt_z990.h" + +static void +query_available_functions(void) +{ + printk(KERN_INFO "#####################\n"); + //query available KM functions + printk(KERN_INFO "KM_QUERY: %d\n", + crypt_z990_func_available(KM_QUERY)); + printk(KERN_INFO "KM_DEA: %d\n", + crypt_z990_func_available(KM_DEA_ENCRYPT)); + printk(KERN_INFO "KM_TDEA_128: %d\n", + crypt_z990_func_available(KM_TDEA_128_ENCRYPT)); + printk(KERN_INFO "KM_TDEA_192: %d\n", + crypt_z990_func_available(KM_TDEA_192_ENCRYPT)); + //query available KMC functions + printk(KERN_INFO "KMC_QUERY: %d\n", + crypt_z990_func_available(KMC_QUERY)); + printk(KERN_INFO "KMC_DEA: %d\n", + crypt_z990_func_available(KMC_DEA_ENCRYPT)); + printk(KERN_INFO "KMC_TDEA_128: %d\n", + crypt_z990_func_available(KMC_TDEA_128_ENCRYPT)); + printk(KERN_INFO "KMC_TDEA_192: %d\n", + crypt_z990_func_available(KMC_TDEA_192_ENCRYPT)); + //query available KIMD fucntions + printk(KERN_INFO "KIMD_QUERY: %d\n", + crypt_z990_func_available(KIMD_QUERY)); + printk(KERN_INFO "KIMD_SHA_1: %d\n", + crypt_z990_func_available(KIMD_SHA_1)); + //query available KLMD functions + printk(KERN_INFO "KLMD_QUERY: %d\n", + crypt_z990_func_available(KLMD_QUERY)); + printk(KERN_INFO "KLMD_SHA_1: %d\n", + crypt_z990_func_available(KLMD_SHA_1)); + //query available KMAC functions + printk(KERN_INFO "KMAC_QUERY: %d\n", + crypt_z990_func_available(KMAC_QUERY)); + printk(KERN_INFO "KMAC_DEA: %d\n", + crypt_z990_func_available(KMAC_DEA)); + printk(KERN_INFO "KMAC_TDEA_128: %d\n", + crypt_z990_func_available(KMAC_TDEA_128)); + printk(KERN_INFO "KMAC_TDEA_192: %d\n", + crypt_z990_func_available(KMAC_TDEA_192)); +} + +static int +init(void) +{ + struct crypt_z990_query_status status = { + .high = 0, + .low = 0 + }; + + printk(KERN_INFO "crypt_z990: querying available crypto functions\n"); + crypt_z990_km(KM_QUERY, &status, NULL, NULL, 0); + printk(KERN_INFO "KM: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_kmc(KMC_QUERY, &status, NULL, NULL, 0); + printk(KERN_INFO "KMC: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_kimd(KIMD_QUERY, &status, NULL, 0); + printk(KERN_INFO "KIMD: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_klmd(KLMD_QUERY, &status, NULL, 0); + printk(KERN_INFO "KLMD: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_kmac(KMAC_QUERY, &status, NULL, 0); + printk(KERN_INFO "KMAC: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + + query_available_functions(); + return -1; +} + +static void __exit +cleanup(void) +{ +} + +module_init(init); +module_exit(cleanup); + +MODULE_LICENSE("GPL"); diff -Nru a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/crypto_des.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,18 @@ +/* + * Cryptographic API. + * + * Function for checking keys for the DES and Tripple DES Encryption + * algorithms. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#ifndef __CRYPTO_DES_H__ +#define __CRYPTO_DES_H__ + +extern int crypto_des_check_key(const u8*, unsigned int, u32*); + +#endif //__CRYPTO_DES_H__ diff -Nru a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/des_check_key.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,130 @@ +/* + * Cryptographic API. + * + * Function for checking keys for the DES and Tripple DES Encryption + * algorithms. + * + * Originally released as descore by Dana L. How . + * Modified by Raimar Falke for the Linux-Kernel. + * Derived from Cryptoapi and Nettle implementations, adapted for in-place + * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. + * + * s390 Version: + * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * Derived from "crypto/des.c" + * Copyright (c) 1992 Dana L. How. + * Copyright (c) Raimar Falke + * Copyright (c) Gisle Sflensminde + * Copyright (C) 2001 Niels Mvller. + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include + +#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) + +static const u8 parity[] = { + 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, +}; + +/* + * RFC2451: Weak key checks SHOULD be performed. + */ +int +crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags) +{ + u32 n, w; + + n = parity[key[0]]; n <<= 4; + n |= parity[key[1]]; n <<= 4; + n |= parity[key[2]]; n <<= 4; + n |= parity[key[3]]; n <<= 4; + n |= parity[key[4]]; n <<= 4; + n |= parity[key[5]]; n <<= 4; + n |= parity[key[6]]; n <<= 4; + n |= parity[key[7]]; + w = 0x88888888L; + + if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) + && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ + if (n < 0x41415151) { + if (n < 0x31312121) { + if (n < 0x14141515) { + /* 01 01 01 01 01 01 01 01 */ + if (n == 0x11111111) goto weak; + /* 01 1F 01 1F 01 0E 01 0E */ + if (n == 0x13131212) goto weak; + } else { + /* 01 E0 01 E0 01 F1 01 F1 */ + if (n == 0x14141515) goto weak; + /* 01 FE 01 FE 01 FE 01 FE */ + if (n == 0x16161616) goto weak; + } + } else { + if (n < 0x34342525) { + /* 1F 01 1F 01 0E 01 0E 01 */ + if (n == 0x31312121) goto weak; + /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ + if (n == 0x33332222) goto weak; + } else { + /* 1F E0 1F E0 0E F1 0E F1 */ + if (n == 0x34342525) goto weak; + /* 1F FE 1F FE 0E FE 0E FE */ + if (n == 0x36362626) goto weak; + } + } + } else { + if (n < 0x61616161) { + if (n < 0x44445555) { + /* E0 01 E0 01 F1 01 F1 01 */ + if (n == 0x41415151) goto weak; + /* E0 1F E0 1F F1 0E F1 0E */ + if (n == 0x43435252) goto weak; + } else { + /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ + if (n == 0x44445555) goto weak; + /* E0 FE E0 FE F1 FE F1 FE */ + if (n == 0x46465656) goto weak; + } + } else { + if (n < 0x64646565) { + /* FE 01 FE 01 FE 01 FE 01 */ + if (n == 0x61616161) goto weak; + /* FE 1F FE 1F FE 0E FE 0E */ + if (n == 0x63636262) goto weak; + } else { + /* FE E0 FE E0 FE F1 FE F1 */ + if (n == 0x64646565) goto weak; + /* FE FE FE FE FE FE FE FE */ + if (n == 0x66666666) goto weak; + } + } + } + } + return 0; +weak: + *flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; +} + +EXPORT_SYMBOL(crypto_des_check_key); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms"); diff -Nru a/arch/s390/crypto/des_z990.c b/arch/s390/crypto/des_z990.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/des_z990.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,284 @@ +/* + * Cryptographic API. + * + * z990 implementation of the DES Cipher Algorithm. + * + * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include "crypt_z990.h" +#include "crypto_des.h" + +#define DES_BLOCK_SIZE 8 +#define DES_KEY_SIZE 8 + +#define DES3_128_KEY_SIZE (2 * DES_KEY_SIZE) +#define DES3_128_BLOCK_SIZE DES_BLOCK_SIZE + +#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE + +struct crypt_z990_des_ctx { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES_KEY_SIZE]; +}; + +struct crypt_z990_des3_128_ctx { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES3_128_KEY_SIZE]; +}; + +struct crypt_z990_des3_192_ctx { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES3_192_KEY_SIZE]; +}; + +static int +des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + struct crypt_z990_des_ctx *dctx; + int ret; + + dctx = ctx; + //test if key is valid (not a weak key) + ret = crypto_des_check_key(key, keylen, flags); + if (ret == 0){ + memcpy(dctx->key, key, keylen); + } + return ret; +} + + +static void +des_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_DEA_ENCRYPT, dctx->key, dst, src, DES_BLOCK_SIZE); +} + +static void +des_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_DEA_DECRYPT, dctx->key, dst, src, DES_BLOCK_SIZE); +} + +static struct crypto_alg des_alg = { + .cra_name = "des", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_des_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = DES_KEY_SIZE, + .cia_max_keysize = DES_KEY_SIZE, + .cia_setkey = des_setkey, + .cia_encrypt = des_encrypt, + .cia_decrypt = des_decrypt } } +}; + +/* + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the two independent 64-bit keys are equal, + * then the DES3 operation is simply the same as DES. + * Implementers MUST reject keys that exhibit this property. + * + */ +static int +des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + int i, ret; + struct crypt_z990_des3_128_ctx *dctx; + const u8* temp_key = key; + + dctx = ctx; + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) { + + *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } + for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) { + ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags); + if (ret < 0) + return ret; + } + memcpy(dctx->key, key, keylen); + return 0; +} + +static void +des3_128_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_128_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src, + DES3_128_BLOCK_SIZE); +} + +static void +des3_128_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_128_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src, + DES3_128_BLOCK_SIZE); +} + +static struct crypto_alg des3_128_alg = { + .cra_name = "des3_ede128", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_128_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_des3_128_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = DES3_128_KEY_SIZE, + .cia_max_keysize = DES3_128_KEY_SIZE, + .cia_setkey = des3_128_setkey, + .cia_encrypt = des3_128_encrypt, + .cia_decrypt = des3_128_decrypt } } +}; + +/* + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the first two or last two independent 64-bit keys are + * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the + * same as DES. Implementers MUST reject keys that exhibit this + * property. + * + */ +static int +des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + int i, ret; + struct crypt_z990_des3_192_ctx *dctx; + const u8* temp_key; + + dctx = ctx; + temp_key = key; + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && + memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], + DES_KEY_SIZE))) { + + *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } + for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) { + ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags); + if (ret < 0){ + return ret; + } + } + memcpy(dctx->key, key, keylen); + return 0; +} + +static void +des3_192_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_192_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src, + DES3_192_BLOCK_SIZE); +} + +static void +des3_192_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_192_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src, + DES3_192_BLOCK_SIZE); +} + +static struct crypto_alg des3_192_alg = { + .cra_name = "des3_ede", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_des3_192_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = DES3_192_KEY_SIZE, + .cia_max_keysize = DES3_192_KEY_SIZE, + .cia_setkey = des3_192_setkey, + .cia_encrypt = des3_192_encrypt, + .cia_decrypt = des3_192_decrypt } } +}; + + + +static int +init(void) +{ + int ret; + + if (!crypt_z990_func_available(KM_DEA_ENCRYPT) || + !crypt_z990_func_available(KM_TDEA_128_ENCRYPT) || + !crypt_z990_func_available(KM_TDEA_192_ENCRYPT)){ + return -ENOSYS; + } + + ret = 0; + ret |= (crypto_register_alg(&des_alg) == 0)? 0:1; + ret |= (crypto_register_alg(&des3_128_alg) == 0)? 0:2; + ret |= (crypto_register_alg(&des3_192_alg) == 0)? 0:4; + if (ret){ + crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&des3_128_alg); + crypto_unregister_alg(&des_alg); + return -EEXIST; + } + + printk(KERN_INFO "crypt_z990: des_z990 loaded.\n"); + return 0; +} + +static void __exit +fini(void) +{ + crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&des3_128_alg); + crypto_unregister_alg(&des_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("des"); +MODULE_ALIAS("des3_ede"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); diff -Nru a/arch/s390/crypto/sha1_z990.c b/arch/s390/crypto/sha1_z990.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/s390/crypto/sha1_z990.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,167 @@ +/* + * Cryptographic API. + * + * z990 implementation of the SHA1 Secure Hash Algorithm. + * + * Derived from cryptoapi implementation, adapted for in-place + * scatterlist interface. Originally based on the public domain + * implementation written by Steve Reid. + * + * s390 Version: + * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * Derived from "crypto/sha1.c" + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald + * Copyright (c) Jean-Francois Dive + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include "crypt_z990.h" + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +struct crypt_z990_sha1_ctx { + u64 count; + u32 state[5]; + u32 buf_len; + u8 buffer[2 * SHA1_BLOCK_SIZE]; +}; + +static void +sha1_init(void *ctx) +{ + static const struct crypt_z990_sha1_ctx initstate = { + .state = { + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0 + }, + }; + memcpy(ctx, &initstate, sizeof(initstate)); +} + +static void +sha1_update(void *ctx, const u8 *data, unsigned int len) +{ + struct crypt_z990_sha1_ctx *sctx; + long imd_len; + + sctx = ctx; + sctx->count += len * 8; //message bit length + + //anything in buffer yet? -> must be completed + if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) { + //complete full block and hash + memcpy(sctx->buffer + sctx->buf_len, data, + SHA1_BLOCK_SIZE - sctx->buf_len); + crypt_z990_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, + SHA1_BLOCK_SIZE); + data += SHA1_BLOCK_SIZE - sctx->buf_len; + len -= SHA1_BLOCK_SIZE - sctx->buf_len; + sctx->buf_len = 0; + } + + //rest of data contains full blocks? + imd_len = len & ~0x3ful; + if (imd_len){ + crypt_z990_kimd(KIMD_SHA_1, sctx->state, data, imd_len); + data += imd_len; + len -= imd_len; + } + //anything left? store in buffer + if (len){ + memcpy(sctx->buffer + sctx->buf_len , data, len); + sctx->buf_len += len; + } +} + + +static void +pad_message(struct crypt_z990_sha1_ctx* sctx) +{ + int index; + + index = sctx->buf_len; + sctx->buf_len = (sctx->buf_len < 56)? + SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; + //start pad with 1 + sctx->buffer[index] = 0x80; + //pad with zeros + index++; + memset(sctx->buffer + index, 0x00, sctx->buf_len - index); + //append length + memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count, + sizeof sctx->count); +} + +/* Add padding and return the message digest. */ +static void +sha1_final(void* ctx, u8 *out) +{ + struct crypt_z990_sha1_ctx *sctx = ctx; + + //must perform manual padding + pad_message(sctx); + crypt_z990_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len); + //copy digest to out + memcpy(out, sctx->state, SHA1_DIGEST_SIZE); + /* Wipe context */ + memset(sctx, 0, sizeof *sctx); +} + +static struct crypto_alg alg = { + .cra_name = "sha1", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_sha1_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA1_DIGEST_SIZE, + .dia_init = sha1_init, + .dia_update = sha1_update, + .dia_final = sha1_final } } +}; + +static int +init(void) +{ + int ret = -ENOSYS; + + if (crypt_z990_func_available(KIMD_SHA_1)){ + ret = crypto_register_alg(&alg); + if (ret == 0){ + printk(KERN_INFO "crypt_z990: sha1_z990 loaded.\n"); + } + } + return ret; +} + +static void __exit +fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("sha1"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig --- a/arch/s390/defconfig Sun Apr 25 22:39:31 2004 +++ b/arch/s390/defconfig Sun Apr 25 22:39:31 2004 @@ -18,8 +18,10 @@ # CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y @@ -31,6 +33,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -231,8 +234,6 @@ # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set # CONFIG_IPV6_TUNNEL is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set # CONFIG_NETFILTER is not set CONFIG_XFRM=y # CONFIG_XFRM_USER is not set @@ -242,7 +243,9 @@ # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -286,6 +289,11 @@ # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m @@ -305,20 +313,16 @@ # # Ethernet (10000 Mbit) # -# CONFIG_PPP is not set -# CONFIG_SLIP is not set # -# Wireless LAN (non-hamradio) +# Token Ring devices # -# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set # -# Token Ring devices +# Wireless LAN (non-hamradio) # -# CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces @@ -341,23 +345,10 @@ # CONFIG_QETH_IPV6 is not set # CONFIG_QETH_PERF_STATS is not set CONFIG_CCWGROUP=y - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # File systems @@ -397,6 +388,7 @@ # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -493,9 +485,11 @@ # CONFIG_CRYPTO_MD4 is not set # CONFIG_CRYPTO_MD5 is not set # CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_Z990 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DES_Z990 is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set diff -Nru a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c --- a/arch/s390/kernel/binfmt_elf32.c Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/binfmt_elf32.c Sun Apr 25 22:39:31 2004 @@ -33,6 +33,8 @@ #define NUM_ACRS 16 #define TASK31_SIZE (0x80000000UL) +#undef TASK_SIZE +#define TASK_SIZE TASK31_SIZE /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ diff -Nru a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c --- a/arch/s390/kernel/compat_linux.c Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/compat_linux.c Sun Apr 25 22:39:31 2004 @@ -297,64 +297,46 @@ */ asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr) { - if(call >> 16) /* hack for backward compatibility */ + if (call >> 16) /* hack for backward compatibility */ return -EINVAL; call &= 0xffff; - if (call <= SEMTIMEDOP) - switch (call) { - case SEMTIMEDOP: - if (third) - return compat_sys_semtimedop(first, - compat_ptr(ptr), second, - compat_ptr(third)); - /* else fall through for normal semop() */ - case SEMOP: - /* struct sembuf is the same on 32 and 64bit :)) */ - return sys_semtimedop (first, compat_ptr(ptr), - second, NULL); - case SEMGET: - return sys_semget (first, second, third); - case SEMCTL: - return compat_sys_semctl (first, second, third, - compat_ptr(ptr)); - default: - return -EINVAL; - }; - if (call <= MSGCTL) - switch (call) { - case MSGSND: - return compat_sys_msgsnd (first, second, third, - compat_ptr(ptr)); - case MSGRCV: - return compat_sys_msgrcv (first, second, 0, third, - 0, compat_ptr(ptr)); - case MSGGET: - return sys_msgget ((key_t) first, second); - case MSGCTL: - return compat_sys_msgctl (first, second, - compat_ptr(ptr)); - default: - return -EINVAL; - } - if (call <= SHMCTL) - switch (call) { - case SHMAT: - return compat_sys_shmat (first, second, third, - 0, compat_ptr(ptr)); - case SHMDT: - return sys_shmdt(compat_ptr(ptr)); - case SHMGET: - return sys_shmget(first, second, third); - case SHMCTL: - return compat_sys_shmctl(first, second, - compat_ptr(ptr)); - default: - return -EINVAL; - } + switch (call) { + case SEMTIMEDOP: + return compat_sys_semtimedop(first, compat_ptr(ptr), + second, compat_ptr(third)); + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + return sys_semtimedop(first, compat_ptr(ptr), + second, NULL); + case SEMGET: + return sys_semget(first, second, third); + case SEMCTL: + return compat_sys_semctl(first, second, third, + compat_ptr(ptr)); + case MSGSND: + return compat_sys_msgsnd(first, second, third, + compat_ptr(ptr)); + case MSGRCV: + return compat_sys_msgrcv(first, second, 0, third, + 0, compat_ptr(ptr)); + case MSGGET: + return sys_msgget((key_t) first, second); + case MSGCTL: + return compat_sys_msgctl(first, second, compat_ptr(ptr)); + case SHMAT: + return compat_sys_shmat(first, second, third, + 0, compat_ptr(ptr)); + case SHMDT: + return sys_shmdt(compat_ptr(ptr)); + case SHMGET: + return sys_shmget(first, second, third); + case SHMCTL: + return compat_sys_shmctl(first, second, compat_ptr(ptr)); + } - return -EINVAL; + return -ENOSYS; } asmlinkage long sys32_truncate64(const char * path, unsigned long high, unsigned long low) diff -Nru a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S --- a/arch/s390/kernel/compat_wrapper.S Sun Apr 25 22:39:32 2004 +++ b/arch/s390/kernel/compat_wrapper.S Sun Apr 25 22:39:32 2004 @@ -1361,7 +1361,7 @@ llgtr %r5,%r5 # struct compat_mq_attr * jg compat_sys_mq_open - .globl sys_mq_unlink_wrapper + .globl sys32_mq_unlink_wrapper sys32_mq_unlink_wrapper: llgtr %r2,%r2 # const char * jg sys_mq_unlink diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S --- a/arch/s390/kernel/entry.S Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/entry.S Sun Apr 25 22:39:31 2004 @@ -198,7 +198,8 @@ */ .global do_call_softirq do_call_softirq: - stm %r12,%r15,24(%r15) + stnsm 24(%r15),0xfc + stm %r12,%r15,28(%r15) lr %r12,%r15 basr %r13,0 do_call_base: @@ -211,7 +212,8 @@ st %r12,0(%r15) # store backchain l %r1,.Ldo_softirq-do_call_base(%r13) basr %r14,%r1 - lm %r12,%r15,24(%r12) + lm %r12,%r15,28(%r12) + ssm 24(%r15) br %r14 __critical_start: diff -Nru a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S --- a/arch/s390/kernel/entry64.S Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/entry64.S Sun Apr 25 22:39:31 2004 @@ -186,7 +186,8 @@ */ .global do_call_softirq do_call_softirq: - stmg %r12,%r15,48(%r15) + stnsm 48(%r15),0xfc + stmg %r12,%r15,56(%r15) lgr %r12,%r15 lg %r0,__LC_ASYNC_STACK slgr %r0,%r15 @@ -196,7 +197,8 @@ 0: aghi %r15,-STACK_FRAME_OVERHEAD stg %r12,0(%r15) # store back chain brasl %r14,do_softirq - lmg %r12,%r15,48(%r12) + lmg %r12,%r15,56(%r12) + ssm 48(%r15) br %r14 __critical_start: diff -Nru a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c --- a/arch/s390/kernel/setup.c Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/setup.c Sun Apr 25 22:39:31 2004 @@ -254,13 +254,13 @@ /* * Reboot, halt and power_off routines for non SMP. */ -extern void do_reipl(unsigned long devno); +extern void reipl(unsigned long devno); static void do_machine_restart_nonsmp(char * __unused) { if (MACHINE_IS_VM) cpcmd ("IPL", NULL, 0); else - do_reipl (0x10000 | S390_lowcore.ipl_device); + reipl (0x10000 | S390_lowcore.ipl_device); } static void do_machine_halt_nonsmp(void) diff -Nru a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c --- a/arch/s390/kernel/smp.c Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/smp.c Sun Apr 25 22:39:31 2004 @@ -64,7 +64,7 @@ extern char vmhalt_cmd[]; extern char vmpoff_cmd[]; -extern void do_reipl(unsigned long devno); +extern void reipl(unsigned long devno); static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); @@ -278,7 +278,7 @@ if (MACHINE_IS_VM) cpcmd ("IPL", NULL, 0); else - do_reipl (0x10000 | S390_lowcore.ipl_device); + reipl (0x10000 | S390_lowcore.ipl_device); } signal_processor(smp_processor_id(), sigp_stop); } diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c --- a/arch/s390/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/s390/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -105,17 +105,6 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - /* - * We can't print the backtrace of a running process. It is - * unreliable at best and can cause kernel oopses. - */ - if (tsk->state == TASK_RUNNING) - return; - show_trace(tsk, (unsigned long *) tsk->thread.ksp); -} - void show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack; diff -Nru a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c --- a/arch/sh/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/sh/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -705,14 +705,8 @@ show_stack(NULL, sp); } -void show_trace_task(struct task_struct *tsk) -{ - show_task((unsigned long *)tsk->thread.sp); -} - void dump_stack(void) { show_stack(NULL, NULL); } - EXPORT_SYMBOL(dump_stack); diff -Nru a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c --- a/arch/sparc/lib/bitext.c Sun Apr 25 22:39:31 2004 +++ b/arch/sparc/lib/bitext.c Sun Apr 25 22:39:31 2004 @@ -60,8 +60,8 @@ } if (offset + len > t->size) { - offset = 0; count += t->size - offset; + offset = 0; continue; } diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Sun Apr 25 22:39:31 2004 +++ b/arch/sparc64/defconfig Sun Apr 25 22:39:31 2004 @@ -16,8 +16,10 @@ # CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=15 CONFIG_HOTPLUG=y # CONFIG_IKCONFIG is not set @@ -28,6 +30,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -306,7 +309,7 @@ # # SCSI Transport Attributes # -CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=m # @@ -332,6 +335,7 @@ CONFIG_SCSI_ATA_PIIX=m CONFIG_SCSI_SATA_PROMISE=m CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m CONFIG_SCSI_SATA_VIA=m CONFIG_SCSI_SATA_VITESSE=m # CONFIG_SCSI_BUSLOGIC is not set @@ -508,11 +512,6 @@ CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m -CONFIG_DECNET=m -CONFIG_DECNET_SIOCGIFCONF=y -CONFIG_DECNET_ROUTER=y -CONFIG_DECNET_ROUTE_FWMARK=y -CONFIG_BRIDGE=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y @@ -574,6 +573,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_COMPAT_IPFWADM=m +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m # # IPv6: Netfilter Configuration @@ -597,6 +598,7 @@ CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m # # DECnet: Netfilter Configuration @@ -644,7 +646,12 @@ CONFIG_ATM_MPOA=m CONFIG_ATM_BR2684=m CONFIG_ATM_BR2684_IPFILTER=y +CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +CONFIG_DECNET_SIOCGIFCONF=y +CONFIG_DECNET_ROUTER=y +CONFIG_DECNET_ROUTE_FWMARK=y CONFIG_LLC=m CONFIG_LLC2=m CONFIG_IPX=m @@ -693,12 +700,96 @@ # Network testing # CONFIG_NET_PKTGEN=m -CONFIG_NETDEVICES=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_HAMRADIO=y # -# ARCnet devices +# Packet Radio protocols # -# CONFIG_ARCNET is not set +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +# CONFIG_BPQETHER is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_YAM is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set + +# +# Dongle support +# + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +CONFIG_SIGMATEL_FIR=m +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIVHCI=m +CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m CONFIG_EQUALIZER=m @@ -706,6 +797,11 @@ # CONFIG_ETHERTAP is not set # +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -754,7 +850,6 @@ # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set -CONFIG_8139_RXBUF_IDX=1 CONFIG_SIS900=m CONFIG_EPIC100=m CONFIG_SUNDANCE=m @@ -775,7 +870,6 @@ CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m CONFIG_R8169=m -# CONFIG_SIS190 is not set CONFIG_SK98LIN=m CONFIG_TIGON3=m @@ -784,25 +878,13 @@ # CONFIG_IXGB=m CONFIG_IXGB_NAPI=y -CONFIG_FDDI=y -# CONFIG_DEFXX is not set -CONFIG_SKFP=m -CONFIG_HIPPI=y -# CONFIG_ROADRUNNER is not set -CONFIG_PLIP=m -CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_PPPOATM=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set # # Wireless LAN (non-hamradio) @@ -832,14 +914,6 @@ CONFIG_NET_WIRELESS=y # -# Token Ring devices -# -# CONFIG_TR is not set -CONFIG_NET_FC=y -CONFIG_SHAPER=m -CONFIG_NETCONSOLE=m - -# # Wan interfaces # # CONFIG_WAN is not set @@ -865,107 +939,28 @@ CONFIG_ATM_FORE200E=m CONFIG_ATM_HE=m CONFIG_ATM_HE_USE_SUNI=y - -# -# Amateur Radio support -# -CONFIG_HAMRADIO=y - -# -# Packet Radio protocols -# -CONFIG_AX25=m -CONFIG_AX25_DAMA_SLAVE=y -CONFIG_NETROM=m -CONFIG_ROSE=m - -# -# AX.25 network device drivers -# -# CONFIG_BPQETHER is not set -# CONFIG_BAYCOM_SER_FDX is not set -# CONFIG_BAYCOM_SER_HDX is not set -# CONFIG_BAYCOM_PAR is not set -# CONFIG_YAM is not set - -# -# IrDA (infrared) support -# -CONFIG_IRDA=m - -# -# IrDA protocols -# -CONFIG_IRLAN=m -CONFIG_IRNET=m -CONFIG_IRCOMM=m -CONFIG_IRDA_ULTRA=y - -# -# IrDA options -# -CONFIG_IRDA_CACHE_LAST_LSAP=y -CONFIG_IRDA_FAST_RR=y -# CONFIG_IRDA_DEBUG is not set - -# -# Infrared-port device drivers -# - -# -# SIR device drivers -# -# CONFIG_IRTTY_SIR is not set - -# -# Dongle support -# - -# -# Old SIR device drivers -# - -# -# Old Serial dongle support -# - -# -# FIR device drivers -# -# CONFIG_USB_IRDA is not set -CONFIG_SIGMATEL_FIR=m -# CONFIG_TOSHIBA_FIR is not set -# CONFIG_VLSI_FIR is not set - -# -# Bluetooth support -# -CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m -CONFIG_BT_RFCOMM=m -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=m -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_CMTP=m - -# -# Bluetooth device drivers -# -CONFIG_BT_HCIUSB=m -CONFIG_BT_HCIUSB_SCO=y -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_BCSP_TXCRC=y -CONFIG_BT_HCIBCM203X=m -CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIVHCI=m -CONFIG_NETPOLL=y -# CONFIG_NETPOLL_RX is not set -# CONFIG_NETPOLL_TRAP is not set -CONFIG_NET_POLL_CONTROLLER=y +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +# CONFIG_ROADRUNNER is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +# CONFIG_SLIP_MODE_SLIP6 is not set +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m # # ISDN subsystem @@ -1096,6 +1091,7 @@ # I2C Hardware Bus support # CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m CONFIG_I2C_ALI15X3=m CONFIG_I2C_AMD756=m CONFIG_I2C_AMD8111=m @@ -1140,6 +1136,8 @@ # Other I2C Chip support # CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -1198,6 +1196,7 @@ # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y CONFIG_DEVFS_FS=y CONFIG_DEVFS_MOUNT=y # CONFIG_DEVFS_DEBUG is not set @@ -1522,6 +1521,7 @@ # CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_UHCI_HCD=m @@ -1578,7 +1578,6 @@ # CONFIG_USB_IBMCAM is not set # CONFIG_USB_KONICAWC is not set # CONFIG_USB_OV511 is not set -# CONFIG_USB_PWC is not set # CONFIG_USB_SE401 is not set # CONFIG_USB_STV680 is not set CONFIG_USB_W9968CF=m @@ -1669,6 +1668,7 @@ CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_LED=m +CONFIG_USB_CYTHERM=m CONFIG_USB_SPEEDTOUCH=m CONFIG_USB_TEST=m diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c --- a/arch/sparc64/kernel/signal32.c Sun Apr 25 22:39:31 2004 +++ b/arch/sparc64/kernel/signal32.c Sun Apr 25 22:39:31 2004 @@ -116,6 +116,11 @@ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_overrun, &to->si_overrun); + err |= __put_user((u32)(u64)from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c --- a/arch/sparc64/kernel/traps.c Sun Apr 25 22:39:32 2004 +++ b/arch/sparc64/kernel/traps.c Sun Apr 25 22:39:32 2004 @@ -1760,13 +1760,6 @@ #endif } -void show_trace_task(struct task_struct *tsk) -{ - if (tsk) - show_stack(tsk, - (unsigned long *) tsk->thread_info->ksp); -} - void dump_stack(void) { unsigned long *ksp; diff -Nru a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c --- a/arch/um/kernel/sysrq.c Sun Apr 25 22:39:31 2004 +++ b/arch/um/kernel/sysrq.c Sun Apr 25 22:39:31 2004 @@ -42,18 +42,7 @@ show_trace(&stack); } - EXPORT_SYMBOL(dump_stack); - -void show_trace_task(struct task_struct *tsk) -{ - unsigned long esp = PT_REGS_SP(&tsk->thread.regs); - - /* User space on another CPU? */ - if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1)) - return; - show_trace((unsigned long *)esp); -} /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -Nru a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c --- a/arch/v850/kernel/process.c Sun Apr 25 22:39:31 2004 +++ b/arch/v850/kernel/process.c Sun Apr 25 22:39:31 2004 @@ -234,10 +234,3 @@ return 0; } - -void show_trace_task (struct task_struct *t) -{ - /* blarg XXX */ - printk ("show_trace_task: KSP = 0x%lx, USP = 0x%lx, UPC = 0x%lx\n", - t->thread.ksp, KSTK_ESP (t), KSTK_EIP (t)); -} diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c Sun Apr 25 22:39:31 2004 +++ b/arch/x86_64/kernel/traps.c Sun Apr 25 22:39:31 2004 @@ -197,16 +197,6 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - unsigned long rsp = tsk->thread.rsp; - - /* User space on another CPU? */ - if ((rsp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1)) - return; - show_trace((unsigned long *)rsp); -} - void show_stack(struct task_struct *tsk, unsigned long * rsp) { unsigned long *stack; diff -Nru a/crypto/Kconfig b/crypto/Kconfig --- a/crypto/Kconfig Sun Apr 25 22:39:31 2004 +++ b/crypto/Kconfig Sun Apr 25 22:39:31 2004 @@ -40,6 +40,12 @@ help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). +config CRYPTO_SHA1_Z990 + tristate "SHA1 digest algorithm for IBM zSeries z990" + depends on CRYPTO && ARCH_S390 + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + config CRYPTO_SHA256 tristate "SHA256 digest algorithm" depends on CRYPTO @@ -64,6 +70,12 @@ config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" depends on CRYPTO + help + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + +config CRYPTO_DES_Z990 + tristate "DES and Triple DES cipher algorithms for IBM zSeries z990" + depends on CRYPTO && ARCH_S390 help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). diff -Nru a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c --- a/drivers/base/firmware_class.c Sun Apr 25 22:39:31 2004 +++ b/drivers/base/firmware_class.c Sun Apr 25 22:39:31 2004 @@ -254,7 +254,7 @@ return retval; } static struct bin_attribute firmware_attr_data_tmpl = { - .attr = {.name = "data", .mode = 0644}, + .attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE}, .size = 0, .read = firmware_data_read, .write = firmware_data_write, diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c Sun Apr 25 22:39:31 2004 +++ b/drivers/block/loop.c Sun Apr 25 22:39:31 2004 @@ -656,7 +656,7 @@ * If we can't read - sorry. If we only can't write - well, * it's going to be read-only. */ - if (!lo_file->f_op->sendfile) + if (!file->f_op->sendfile) goto out_putf; if (!aops->prepare_write || !aops->commit_write) diff -Nru a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c --- a/drivers/cdrom/viocd.c Sun Apr 25 22:39:32 2004 +++ b/drivers/cdrom/viocd.c Sun Apr 25 22:39:32 2004 @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include @@ -132,7 +134,12 @@ char type[4]; char model[3]; }; -static struct cdrom_info viocd_unitinfo[VIOCD_MAX_CD]; +/* + * This needs to be allocated since it is passed to the + * Hypervisor and we may be a module. + */ +static struct cdrom_info *viocd_unitinfo; +static dma_addr_t unitinfo_dmaaddr; struct disk_info { struct gendisk *viocd_disk; @@ -141,13 +148,39 @@ static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; #define DEVICE_NR(di) ((di) - &viocd_diskinfo[0]) -#define VIOCDI viocd_diskinfo[deviceno].viocd_info static request_queue_t *viocd_queue; static spinlock_t viocd_reqlock; #define MAX_CD_REQ 1 +/* procfs support */ +static int proc_viocd_show(struct seq_file *m, void *v) +{ + int i; + + for (i = 0; i < viocd_numdev; i++) { + seq_printf(m, "viocd device %d is iSeries resource %10.10s" + "type %4.4s, model %3.3s\n", + i, viocd_unitinfo[i].rsrcname, + viocd_unitinfo[i].type, + viocd_unitinfo[i].model); + } + return 0; +} + +static int proc_viocd_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viocd_show, NULL); +} + +static struct file_operations proc_viocd_operations = { + .open = proc_viocd_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int viocd_blk_open(struct inode *inode, struct file *file) { struct disk_info *di = inode->i_bdev->bd_disk->private_data; @@ -184,18 +217,20 @@ /* Get info on CD devices from OS/400 */ static void __init get_viocd_info(void) { - dma_addr_t dmaaddr; HvLpEvent_Rc hvrc; int i; struct viocd_waitevent we; - dmaaddr = dma_map_single(iSeries_vio_dev, viocd_unitinfo, - sizeof(viocd_unitinfo), DMA_FROM_DEVICE); - if (dmaaddr == (dma_addr_t)-1) { - printk(VIOCD_KERN_WARNING "error allocating tce\n"); + viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + &unitinfo_dmaaddr, GFP_ATOMIC); + if (viocd_unitinfo == NULL) { + printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); return; } + memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); + init_completion(&we.com); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, @@ -204,29 +239,34 @@ HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), - (u64)&we, VIOVERSION << 16, dmaaddr, 0, - sizeof(viocd_unitinfo), 0); + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", (int)hvrc); - return; + goto error_ret; } wait_for_completion(&we.com); - dma_unmap_single(iSeries_vio_dev, dmaaddr, sizeof(viocd_unitinfo), - DMA_FROM_DEVICE); - if (we.rc) { const struct vio_error_entry *err = vio_lookup_rc(viocd_err_table, we.sub_result); printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", we.rc, we.sub_result, err->msg); - return; + goto error_ret; } for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) viocd_numdev++; + + return; + +error_ret: + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); + viocd_unitinfo = NULL; } static int viocd_open(struct cdrom_device_info *cdi, int purpose) @@ -307,10 +347,6 @@ } dmaaddr = sg_dma_address(&sg); len = sg_dma_len(&sg); - if (dmaaddr == (dma_addr_t)-1) { - printk(VIOCD_KERN_WARNING "error allocating tce\n"); - return -1; - } hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, @@ -534,6 +570,7 @@ struct gendisk *gendisk; int deviceno; int ret = 0; + struct proc_dir_entry *e; if (viopath_hostLp == HvLpIndexInvalid) { vio_set_hostlp(); @@ -604,7 +641,7 @@ printk(VIOCD_KERN_WARNING "Cannot create gendisk for %s!\n", c->name); - unregister_cdrom(&VIOCDI); + unregister_cdrom(c); continue; } gendisk->major = VIOCD_MAJOR; @@ -622,6 +659,12 @@ add_disk(gendisk); } + e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); + if (e) { + e->owner = THIS_MODULE; + e->proc_fops = &proc_viocd_operations; + } + return 0; out_undo_vio: @@ -636,6 +679,7 @@ { int deviceno; + remove_proc_entry("iSeries/viocd", NULL); for (deviceno = 0; deviceno < viocd_numdev; deviceno++) { struct disk_info *d = &viocd_diskinfo[deviceno]; if (unregister_cdrom(&d->viocd_info) != 0) @@ -646,7 +690,10 @@ put_disk(d->viocd_disk); } blk_cleanup_queue(viocd_queue); - + if (viocd_unitinfo != NULL) + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); vio_clearHandler(viomajorsubtype_cdio); unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c --- a/drivers/char/drm/i810_dma.c Sun Apr 25 22:39:31 2004 +++ b/drivers/char/drm/i810_dma.c Sun Apr 25 22:39:31 2004 @@ -1275,6 +1275,9 @@ return -EINVAL; } + if (mc.idx >= dma->buf_count || mc.idx < 0) + return -EINVAL; + i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used, mc.last_render ); diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c --- a/drivers/char/tipar.c Sun Apr 25 22:39:31 2004 +++ b/drivers/char/tipar.c Sun Apr 25 22:39:31 2004 @@ -121,7 +121,7 @@ /* ----- global defines ----------------------------------------------- */ -#define START(x) { x=jiffies+HZ/(timeout/10); } +#define START(x) { x = jiffies + (HZ * timeout) / 10; } #define WAIT(x) { \ if (time_before((x), jiffies)) return -1; \ if (need_resched()) schedule(); } diff -Nru a/drivers/char/viotape.c b/drivers/char/viotape.c --- a/drivers/char/viotape.c Sun Apr 25 22:39:31 2004 +++ b/drivers/char/viotape.c Sun Apr 25 22:39:31 2004 @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include @@ -56,7 +58,7 @@ #include #include -#define VIOTAPE_VERSION "1.1" +#define VIOTAPE_VERSION "1.2" #define VIOTAPE_MAXREQ 1 #define VIOTAPE_KERN_WARN KERN_WARNING "viotape: " @@ -269,6 +271,34 @@ /* forward declaration to resolve interdependence */ static int chg_state(int index, unsigned char new_state, struct file *file); +/* procfs support */ +static int proc_viotape_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n"); + for (i = 0; i < viotape_numdev; i++) { + seq_printf(m, "viotape device %d is iSeries resource %10.10s" + "type %4.4s, model %3.3s\n", + i, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, + viotape_unitinfo[i].model); + } + return 0; +} + +static int proc_viotape_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viotape_show, NULL); +} + +static struct file_operations proc_viotape_operations = { + .open = proc_viotape_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* Decode the device minor number into its parts */ void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi) { @@ -912,6 +942,7 @@ int ret; char tapename[32]; int i; + struct proc_dir_entry *e; op_struct_list = NULL; if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) { @@ -988,6 +1019,12 @@ viotape_unitinfo[i].model); } + e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); + if (e) { + e->owner = THIS_MODULE; + e->proc_fops = &proc_viotape_operations; + } + return 0; unreg_class: @@ -1028,6 +1065,8 @@ static void __exit viotap_exit(void) { int i, ret; + + remove_proc_entry("iSeries/viotape", NULL); for (i = 0; i < viotape_numdev; ++i) { devfs_remove("iseries/nvt%d", i); diff -Nru a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig --- a/drivers/char/watchdog/Kconfig Sun Apr 25 22:39:31 2004 +++ b/drivers/char/watchdog/Kconfig Sun Apr 25 22:39:31 2004 @@ -143,19 +143,6 @@ Most people will say N. -config AMD7XX_TCO - tristate "AMD 766/768 TCO Timer/Watchdog" - depends on WATCHDOG && X86 && PCI - help - This is the driver for the hardware watchdog built in to the - AMD 766/768 chipsets. - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called amd7xx_tco. - config SC520_WDT tristate "AMD Elan SC520 processor Watchdog" depends on WATCHDOG && X86 diff -Nru a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile --- a/drivers/char/watchdog/Makefile Sun Apr 25 22:39:31 2004 +++ b/drivers/char/watchdog/Makefile Sun Apr 25 22:39:31 2004 @@ -32,7 +32,6 @@ obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o -obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o diff -Nru a/drivers/char/watchdog/amd7xx_tco.c b/drivers/char/watchdog/amd7xx_tco.c --- a/drivers/char/watchdog/amd7xx_tco.c Sun Apr 25 22:39:31 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,374 +0,0 @@ -/* - * AMD 766/768 TCO Timer Driver - * (c) Copyright 2002 Zwane Mwaikambo - * All Rights Reserved. - * - * Parts from; - * Hardware driver for the AMD 768 Random Number Generator (RNG) - * (c) Copyright 2001 Red Hat Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * The author(s) of this software shall not be held liable for damages - * of any nature resulting due to the use of this software. This - * software is provided AS-IS with no warranties. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AMDTCO_MODULE_VER "build 20021116" -#define AMDTCO_MODULE_NAME "amd7xx_tco" -#define PFX AMDTCO_MODULE_NAME ": " - -#define MAX_TIMEOUT 38 /* max of 38 seconds, although the system will only - * reset itself after the second timeout */ - -/* pmbase registers */ -#define TCO_RELOAD_REG 0x40 /* bits 0-5 are current count, 6-7 are reserved */ -#define TCO_INITVAL_REG 0x41 /* bits 0-5 are value to load, 6-7 are reserved */ -#define TCO_TIMEOUT_MASK 0x3f -#define TCO_STATUS1_REG 0x44 -#define TCO_STATUS2_REG 0x46 -#define NDTO_STS2 (1 << 1) /* we're interested in the second timeout */ -#define BOOT_STS (1 << 2) /* will be set if NDTO_STS2 was set before reboot */ -#define TCO_CTRL1_REG 0x48 -#define TCO_HALT (1 << 11) -#define NO_REBOOT (1 << 10) /* in DevB:3x48 */ - -static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n"; -static int timeout = MAX_TIMEOUT; -static u32 pmbase; /* PMxx I/O base */ -static struct pci_dev *dev; -static struct semaphore open_sem; -static spinlock_t amdtco_lock; /* only for device access */ -static char expect_close; - -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -static inline u8 seconds_to_ticks(int seconds) -{ - /* the internal timer is stored as ticks which decrement - * every 0.6 seconds */ - return (seconds * 10) / 6; -} - -static inline int ticks_to_seconds(u8 ticks) -{ - return (ticks * 6) / 10; -} - -static inline int amdtco_status(void) -{ - u16 reg; - int status = 0; - - reg = inb(pmbase+TCO_CTRL1_REG); - if ((reg & TCO_HALT) == 0) - status |= WDIOF_KEEPALIVEPING; - - reg = inb(pmbase+TCO_STATUS2_REG); - if (reg & BOOT_STS) - status |= WDIOF_CARDRESET; - - return status; -} - -static inline void amdtco_ping(void) -{ - outb(1, pmbase+TCO_RELOAD_REG); -} - -static inline int amdtco_gettimeout(void) -{ - u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK; - return ticks_to_seconds(reg); -} - -static inline void amdtco_settimeout(unsigned int timeout) -{ - u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK; - outb(reg, pmbase+TCO_INITVAL_REG); -} - -static inline void amdtco_global_enable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - - /* clear NO_REBOOT on DevB:3x48 p97 */ - pci_read_config_word(dev, 0x48, ®); - reg &= ~NO_REBOOT; - pci_write_config_word(dev, 0x48, reg); - - spin_unlock(&amdtco_lock); -} - -static inline void amdtco_enable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - reg = inw(pmbase+TCO_CTRL1_REG); - reg &= ~TCO_HALT; - outw(reg, pmbase+TCO_CTRL1_REG); - spin_unlock(&amdtco_lock); -} - -static inline void amdtco_disable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - reg = inw(pmbase+TCO_CTRL1_REG); - reg |= TCO_HALT; - outw(reg, pmbase+TCO_CTRL1_REG); - spin_unlock(&amdtco_lock); -} - -static int amdtco_fop_open(struct inode *inode, struct file *file) -{ - if (down_trylock(&open_sem)) - return -EBUSY; - - if (timeout > MAX_TIMEOUT) - timeout = MAX_TIMEOUT; - - amdtco_disable(); - amdtco_settimeout(timeout); - amdtco_global_enable(); - amdtco_enable(); - amdtco_ping(); - printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n", - amdtco_gettimeout(), timeout); - - return 0; -} - - -static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - int new_timeout; - int tmp; - - static struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT | WDIOF_CARDRESET, - .identity = "AMD 766/768", - }; - - switch (cmd) { - default: - return -ENOIOCTLCMD; - - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident)) - return -EFAULT; - return 0; - - case WDIOC_GETSTATUS: - return put_user(amdtco_status(), (int *)arg); - - case WDIOC_KEEPALIVE: - amdtco_ping(); - return 0; - - case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, (int *)arg)) - return -EFAULT; - - if (new_timeout < 0) - return -EINVAL; - - if (new_timeout > MAX_TIMEOUT) - new_timeout = MAX_TIMEOUT; - - timeout = new_timeout; - amdtco_settimeout(timeout); - /* fall through and return the new timeout */ - - case WDIOC_GETTIMEOUT: - return put_user(amdtco_gettimeout(), (int *)arg); - - case WDIOC_SETOPTIONS: - if (copy_from_user(&tmp, (int *)arg, sizeof tmp)) - return -EFAULT; - - if (tmp & WDIOS_DISABLECARD) - amdtco_disable(); - - if (tmp & WDIOS_ENABLECARD) - amdtco_enable(); - - return 0; - } -} - - -static int amdtco_fop_release(struct inode *inode, struct file *file) -{ - if (expect_close == 42) { - amdtco_disable(); - printk(KERN_INFO PFX "Watchdog disabled\n"); - } else { - amdtco_ping(); - printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout); - } - - expect_close = 0; - up(&open_sem); - return 0; -} - - -static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos) -{ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (len) { - if (!nowayout) { - size_t i; - char c; - expect_close = 0; - - for (i = 0; i != len; i++) { - if (get_user(c, data + i)) - return -EFAULT; - - if (c == 'V') - expect_close = 42; - } - } - amdtco_ping(); - } - - return len; -} - - -static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - amdtco_disable(); - - return NOTIFY_DONE; -} - - -static struct notifier_block amdtco_notifier = -{ - .notifier_call = amdtco_notify_sys, -}; - -static struct file_operations amdtco_fops = -{ - .owner = THIS_MODULE, - .write = amdtco_fop_write, - .ioctl = amdtco_fop_ioctl, - .open = amdtco_fop_open, - .release = amdtco_fop_release, -}; - -static struct miscdevice amdtco_miscdev = -{ - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &amdtco_fops, -}; - -static struct pci_device_id amdtco_pci_tbl[] = { - /* AMD 766 PCI_IDs here */ - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, }, -}; - -MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl); - -static int __init amdtco_init(void) -{ - int ret; - - sema_init(&open_sem, 1); - spin_lock_init(&amdtco_lock); - - dev = NULL; - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_match_device (amdtco_pci_tbl, dev) != NULL) - goto found_one; - } - - return -ENODEV; - -found_one: - - if ((ret = register_reboot_notifier(&amdtco_notifier))) { - printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); - goto out_clean; - } - - if ((ret = misc_register(&amdtco_miscdev))) { - printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); - goto out_unreg_reboot; - } - - pci_read_config_dword(dev, 0x58, &pmbase); - pmbase &= 0x0000FF00; - - if (pmbase == 0) { - printk (KERN_ERR PFX "power management base not set\n"); - ret = -EIO; - goto out_unreg_misc; - } - - /* ret = 0; */ - printk(banner); - goto out_clean; - -out_unreg_misc: - misc_deregister(&amdtco_miscdev); -out_unreg_reboot: - unregister_reboot_notifier(&amdtco_notifier); -out_clean: - return ret; -} - -static void __exit amdtco_exit(void) -{ - misc_deregister(&amdtco_miscdev); - unregister_reboot_notifier(&amdtco_notifier); -} - -module_init(amdtco_init); -module_exit(amdtco_exit); - -MODULE_AUTHOR("Zwane Mwaikambo "); -MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff -Nru a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c --- a/drivers/cpufreq/cpufreq.c Sun Apr 25 22:39:31 2004 +++ b/drivers/cpufreq/cpufreq.c Sun Apr 25 22:39:31 2004 @@ -360,8 +360,10 @@ return -EINVAL; policy = kmalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); - if (!policy) - return -ENOMEM; + if (!policy) { + ret = -ENOMEM; + goto nomem_out; + } memset(policy, 0, sizeof(struct cpufreq_policy)); policy->cpu = cpu; @@ -410,7 +412,7 @@ return 0; - err_out_unregister: +err_out_unregister: spin_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_cpu_data[cpu] = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -418,8 +420,10 @@ kobject_unregister(&policy->kobj); wait_for_completion(&policy->kobj_unregister); - err_out: +err_out: kfree(policy); + +nomem_out: module_put(cpufreq_driver->owner); return ret; } diff -Nru a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c --- a/drivers/cpufreq/cpufreq_userspace.c Sun Apr 25 22:39:31 2004 +++ b/drivers/cpufreq/cpufreq_userspace.c Sun Apr 25 22:39:31 2004 @@ -167,8 +167,8 @@ void __user *buffer, size_t *lenp) { char buf[16], *p; - int cpu = (int) ctl->extra1; - int len, left = *lenp; + int cpu = (long) ctl->extra1; + unsigned int len, left = *lenp; if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) { *lenp = 0; @@ -205,7 +205,7 @@ void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { - int cpu = (int) table->extra1; + int cpu = (long) table->extra1; if (!cpu_online(cpu)) return -EINVAL; diff -Nru a/drivers/firmware/edd.c b/drivers/firmware/edd.c --- a/drivers/firmware/edd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/firmware/edd.c Sun Apr 25 22:39:31 2004 @@ -86,7 +86,7 @@ #define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \ struct edd_attribute edd_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .test = _test, \ }; diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c --- a/drivers/i2c/chips/eeprom.c Sun Apr 25 22:39:31 2004 +++ b/drivers/i2c/chips/eeprom.c Sun Apr 25 22:39:31 2004 @@ -155,6 +155,7 @@ .attr = { .name = "eeprom", .mode = S_IRUGO, + .owner = THIS_MODULE, }, .size = EEPROM_SIZE, .read = eeprom_read, diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/ide-cd.c Sun Apr 25 22:39:31 2004 @@ -965,7 +965,7 @@ struct cdrom_info *info = drive->driver_data; /* Number of sectors to read into the buffer. */ - int sectors_to_buffer = MIN (sectors_to_transfer, + int sectors_to_buffer = min_t(int, sectors_to_transfer, (SECTOR_BUFFER_SIZE >> SECTOR_BITS) - info->nsectors_buffered); @@ -1114,7 +1114,7 @@ /* First, figure out if we need to bit-bucket any of the leading sectors. */ - nskip = MIN((int)(rq->current_nr_sectors - bio_cur_sectors(rq->bio)), sectors_to_transfer); + nskip = min_t(int, rq->current_nr_sectors - bio_cur_sectors(rq->bio), sectors_to_transfer); while (nskip > 0) { /* We need to throw away a sector. */ @@ -1144,7 +1144,7 @@ /* Transfer data to the buffers. Figure out how many sectors we can transfer to the current buffer. */ - this_transfer = MIN (sectors_to_transfer, + this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors); /* Read this_transfer sectors @@ -1860,7 +1860,7 @@ /* * Figure out how many sectors we can transfer */ - this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors); + this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors); while (this_transfer > 0) { HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE); diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h --- a/drivers/ide/ide-cd.h Sun Apr 25 22:39:32 2004 +++ b/drivers/ide/ide-cd.h Sun Apr 25 22:39:32 2004 @@ -54,8 +54,6 @@ #define BLOCKS_PER_FRAME (CD_FRAMESIZE / BLOCK_SIZE) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - /* special command codes for strategy routine. */ #define PACKET_COMMAND 4315 #define REQUEST_SENSE_COMMAND 4316 diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/ide-disk.c Sun Apr 25 22:39:31 2004 @@ -1695,6 +1695,7 @@ if (ide_unregister_subdriver(drive)) return 1; del_gendisk(g); + drive->devfs_name[0] = '\0'; g->fops = ide_fops; return 0; } diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c --- a/drivers/ide/ide-io.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/ide-io.c Sun Apr 25 22:39:31 2004 @@ -741,7 +741,7 @@ && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time)) && 0 < (signed long)((jiffies + t) - WAKEUP(drive))) { - ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP)); + ide_stall_queue(best, min_t(long, t, 10 * WAIT_MIN_SLEEP)); goto repeat; } } while ((drive = drive->next) != best); diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/ide-probe.c Sun Apr 25 22:39:31 2004 @@ -48,7 +48,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c --- a/drivers/ide/ide-proc.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/ide-proc.c Sun Apr 25 22:39:31 2004 @@ -508,8 +508,8 @@ } if (*p != ':') goto parse_error; - len = IDE_MIN(p - start, MAX_LEN); - strncpy(name, start, IDE_MIN(len, MAX_LEN)); + len = min(p - start, MAX_LEN); + strncpy(name, start, min(len, MAX_LEN)); name[len] = 0; if (n > 0) { diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/ide-tape.c Sun Apr 25 22:39:31 2004 @@ -4698,7 +4698,7 @@ * Ensure that the number we got makes sense; limit * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. */ - tape->best_dsc_rw_frequency = max((unsigned long) min(t, (unsigned long) IDETAPE_DSC_RW_MAX), (unsigned long) IDETAPE_DSC_RW_MIN); + tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN); printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, " "%dkB pipeline, %lums tDSC%s\n", drive->name, tape->name, tape->capabilities.speed, diff -Nru a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c --- a/drivers/ide/legacy/ali14xx.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/ali14xx.c Sun Apr 25 22:39:31 2004 @@ -243,25 +243,7 @@ } #ifdef MODULE -static void __exit ali14xx_release_hwif(ide_hwif_t *hwif) -{ - if (hwif->chipset != ide_ali14xx) - return; - - hwif->chipset = ide_unknown; - hwif->tuneproc = NULL; - hwif->mate = NULL; - hwif->channel = 0; -} - -static void __exit ali14xx_exit(void) -{ - ali14xx_release_hwif(&ide_hwifs[0]); - ali14xx_release_hwif(&ide_hwifs[1]); -} - module_init(ali14xx_init); -module_exit(ali14xx_exit); #endif MODULE_AUTHOR("see local file"); diff -Nru a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c --- a/drivers/ide/legacy/dtc2278.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/dtc2278.c Sun Apr 25 22:39:31 2004 @@ -155,27 +155,7 @@ } #ifdef MODULE -static void __exit dtc2278_release_hwif(ide_hwif_t *hwif) -{ - if (hwif->chipset != ide_dtc2278) - return; - - hwif->serialized = 0; - hwif->chipset = ide_unknown; - hwif->tuneproc = NULL; - hwif->drives[0].no_unmask = 0; - hwif->drives[1].no_unmask = 0; - hwif->mate = NULL; -} - -static void __exit dtc2278_exit(void) -{ - dtc2278_release_hwif(&ide_hwifs[0]); - dtc2278_release_hwif(&ide_hwifs[1]); -} - module_init(dtc2278_init); -module_exit(dtc2278_exit); #endif MODULE_AUTHOR("See Local File"); diff -Nru a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c --- a/drivers/ide/legacy/ht6560b.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/ht6560b.c Sun Apr 25 22:39:31 2004 @@ -360,31 +360,7 @@ } #ifdef MODULE -static void __exit ht6560b_release_hwif(ide_hwif_t *hwif) -{ - if (hwif->chipset != ide_ht6560b) - return; - - hwif->chipset = ide_unknown; - hwif->tuneproc = NULL; - hwif->selectproc = NULL; - hwif->serialized = 0; - hwif->mate = NULL; - hwif->channel = 0; - - hwif->drives[0].drive_data = 0; - hwif->drives[1].drive_data = 0; -} - -static void __exit ht6560b_exit(void) -{ - ht6560b_release_hwif(&ide_hwifs[0]); - ht6560b_release_hwif(&ide_hwifs[1]); - release_region(HT_CONFIG_PORT, 1); -} - module_init(ht6560b_init); -module_exit(ht6560b_exit); #endif MODULE_AUTHOR("See Local File"); diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c --- a/drivers/ide/legacy/ide-cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/ide-cs.c Sun Apr 25 22:39:31 2004 @@ -362,7 +362,6 @@ goto failed; } - MOD_INC_USE_COUNT; info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2)); info->node.major = ide_major[hd]; @@ -408,7 +407,6 @@ if (link->io.NumPorts2) request_region(link->io.BasePort2, link->io.NumPorts2, info->node.dev_name); - MOD_DEC_USE_COUNT; } info->ndev = 0; link->dev = NULL; diff -Nru a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c --- a/drivers/ide/legacy/pdc4030.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/pdc4030.c Sun Apr 25 22:39:31 2004 @@ -311,29 +311,7 @@ } #ifdef MODULE -static void __exit pdc4030_release_hwif(ide_hwif_t *hwif) -{ - hwif->chipset = ide_unknown; - hwif->selectproc = NULL; - hwif->serialized = 0; - hwif->drives[0].io_32bit = 0; - hwif->drives[1].io_32bit = 0; - hwif->drives[0].keep_settings = 0; - hwif->drives[1].keep_settings = 0; - hwif->drives[0].noprobe = 0; - hwif->drives[1].noprobe = 0; -} - -static void __exit pdc4030_exit(void) -{ - unsigned int index; - - for (index = 0; index < MAX_HWIFS; index++) - pdc4030_release_hwif(&ide_hwifs[index]); -} - module_init(pdc4030_init); -module_exit(pdc4030_exit); #endif MODULE_AUTHOR("Peter Denison"); diff -Nru a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c --- a/drivers/ide/legacy/qd65xx.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/qd65xx.c Sun Apr 25 22:39:31 2004 @@ -262,7 +262,7 @@ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { pio = ide_get_best_pio_mode(drive, pio, 255, &d); - pio = IDE_MIN(pio,4); + pio = min_t(u8, pio, 4); switch (pio) { case 0: break; @@ -354,12 +354,12 @@ probe_hwif_init(hwif); } -#ifdef MODULE /* * qd_unsetup: * * called to unsetup an ata channel : back to default values, unlinks tuning */ +/* static void __exit qd_unsetup(ide_hwif_t *hwif) { u8 config = hwif->config_data; @@ -389,7 +389,7 @@ printk(KERN_WARNING "keeping settings !\n"); } } -#endif +*/ /* * qd_probe: @@ -496,14 +496,7 @@ } #ifdef MODULE -static void __exit qd65xx_exit(void) -{ - qd_unsetup(&ide_hwifs[0]); - qd_unsetup(&ide_hwifs[1]); -} - module_init(qd65xx_init); -module_exit(qd65xx_exit); #endif MODULE_AUTHOR("Samuel Thibault"); diff -Nru a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c --- a/drivers/ide/legacy/umc8672.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/legacy/umc8672.c Sun Apr 25 22:39:31 2004 @@ -173,33 +173,7 @@ } #ifdef MODULE -static void __exit umc8672_release_hwif(ide_hwif_t *hwif) -{ - if (hwif->chipset != ide_umc8672) - return; - - hwif->chipset = ide_unknown; - hwif->tuneproc = NULL; - hwif->mate = NULL; - hwif->channel = 0; -} - -static void __exit umc8672_exit(void) -{ - unsigned long flags; - - umc8672_release_hwif(&ide_hwifs[0]); - umc8672_release_hwif(&ide_hwifs[1]); - - local_irq_save(flags); - outb_p(0xa5, 0x108); /* disable umc */ - local_irq_restore(flags); - - release_region(0x108, 2); -} - module_init(umc8672_init); -module_exit(umc8672_exit); #endif MODULE_AUTHOR("Wolfram Podien"); diff -Nru a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c --- a/drivers/ide/pci/cmd64x.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/pci/cmd64x.c Sun Apr 25 22:39:31 2004 @@ -200,7 +200,7 @@ */ if (channel) { drive->drive_data = setup_count; - setup_count = IDE_MAX(drives[0].drive_data, + setup_count = max(drives[0].drive_data, drives[1].drive_data); cmdprintk("Secondary interface, setup_count = %d\n", setup_count); diff -Nru a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c --- a/drivers/ide/pci/generic.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/pci/generic.c Sun Apr 25 22:39:31 2004 @@ -132,6 +132,9 @@ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, { 0, }, }; MODULE_DEVICE_TABLE(pci, generic_pci_tbl); diff -Nru a/drivers/ide/pci/generic.h b/drivers/ide/pci/generic.h --- a/drivers/ide/pci/generic.h Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/pci/generic.h Sun Apr 25 22:39:31 2004 @@ -129,6 +129,33 @@ .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = OFF_BOARD, .extra = 0, + },{ /* 10 */ + .vendor = PCI_VENDOR_ID_TOSHIBA, + .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO, + .name = "Piccolo0102", + .init_chipset = init_chipset_generic, + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = NOAUTODMA, + .bootable = ON_BOARD, + },{ /* 11 */ + .vendor = PCI_VENDOR_ID_TOSHIBA, + .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, + .name = "Piccolo0103", + .init_chipset = init_chipset_generic, + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = NOAUTODMA, + .bootable = ON_BOARD, + },{ /* 12 */ + .vendor = PCI_VENDOR_ID_TOSHIBA, + .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, + .name = "Piccolo0105", + .init_chipset = init_chipset_generic, + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = NOAUTODMA, + .bootable = ON_BOARD, },{ .vendor = 0, .device = 0, diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c --- a/drivers/ide/pci/via82cxxx.c Sun Apr 25 22:39:31 2004 +++ b/drivers/ide/pci/via82cxxx.c Sun Apr 25 22:39:31 2004 @@ -375,7 +375,7 @@ return; } - via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5)); + via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); } /** diff -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c --- a/drivers/input/keyboard/lkkbd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/input/keyboard/lkkbd.c Sun Apr 25 22:39:31 2004 @@ -11,8 +11,8 @@ * and VAXstations, but can also be used on any standard RS232 with an * adaptor). * - * DISCLAUNER: This works for _me_. If you break anything by using the - * information given below, I will _not_ be lieable! + * DISCLAIMER: This works for _me_. If you break anything by using the + * information given below, I will _not_ be liable! * * RJ11 pinout: To DB9: Or DB25: * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) @@ -34,23 +34,32 @@ * Additionally, you have to get +12V from somewhere. * Most easily, you'll get that from a floppy or HDD power connector. * It's the yellow cable there (black is ground and red is +5V). + * + * The keyboard and all the commands it understands are documented in + * "VCB02 Video Subsystem - Technical Manual", EK-104AA-TM-001. This + * document is LK201 specific, but LK401 is mostly compatible. It comes + * up in LK201 mode and doesn't report any of the additional keys it + * has. These need to be switched on with the LK_CMD_ENABLE_LK401 + * command. You'll find this document (scanned .pdf file) on MANX, + * a search engine specific to DEC documentation. Try + * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * email or by paper mail: * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), @@ -67,8 +76,7 @@ #include #include - -MODULE_AUTHOR ("Jan-Benedict Glaw "); +MODULE_AUTHOR ("Jan-Benedict Glaw "); MODULE_DESCRIPTION ("LK keyboard driver"); MODULE_LICENSE ("GPL"); @@ -92,6 +100,11 @@ module_param (ctrlclick_volume, int, 0); MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); +static int lk201_compose_is_alt = 0; +module_param (lk201_compose_is_alt, int, 0); +MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " + "will act as an Alt key"); + #undef LKKBD_DEBUG @@ -126,8 +139,11 @@ #define LK_CMD_SET_DEFAULTS 0xd3 #define LK_CMD_POWERCYCLE_RESET 0xfd #define LK_CMD_ENABLE_LK401 0xe9 +#define LK_CMD_REQUEST_ID 0xab /* Misc responses from keyboard */ +#define LK_STUCK_KEY 0x3d +#define LK_SELFTEST_FAILED 0x3e #define LK_ALL_KEYS_UP 0xb3 #define LK_METRONOME 0xb4 #define LK_OUTPUT_ERROR 0xb5 @@ -139,6 +155,7 @@ #define LK_RESPONSE_RESERVED 0xbb #define LK_NUM_KEYCODES 256 +#define LK_NUM_IGNORE_BYTES 6 typedef u_int16_t lk_keycode_t; @@ -267,6 +284,7 @@ struct lkkbd { lk_keycode_t keycode[LK_NUM_KEYCODES]; int ignore_bytes; + unsigned char id[LK_NUM_IGNORE_BYTES]; struct input_dev dev; struct serio *serio; struct work_struct tq; @@ -313,6 +331,82 @@ return ret; } +static void +lkkbd_detection_done (struct lkkbd *lk) +{ + int i; + + /* + * Reset setting for Compose key. Let Compose be KEY_COMPOSE. + */ + lk->keycode[0xb1] = KEY_COMPOSE; + + /* + * Print keyboard name and modify Compose=Alt on user's request. + */ + switch (lk->id[4]) { + case 1: + sprintf (lk->name, "DEC LK201 keyboard"); + + if (lk201_compose_is_alt) + lk->keycode[0xb1] = KEY_LEFTALT; + break; + + case 2: + sprintf (lk->name, "DEC LK401 keyboard"); + break; + + default: + sprintf (lk->name, "Unknown DEC keyboard"); + printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " + "please report to Jan-Benedict Glaw " + "\n", lk->phys); + printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); + for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) + printk (" 0x%02x", lk->id[i]); + printk ("\n"); + break; + } + printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", + lk->phys, lk->name); + + /* + * Report errors during keyboard boot-up. + */ + switch (lk->id[2]) { + case 0x00: + /* All okay */ + break; + + case LK_STUCK_KEY: + printk (KERN_ERR "lkkbd: Stuck key on keyboard at " + "%s\n", lk->phys); + break; + + case LK_SELFTEST_FAILED: + printk (KERN_ERR "lkkbd: Selftest failed on keyboard " + "at %s, keyboard may not work " + "properly\n", lk->phys); + break; + + default: + printk (KERN_ERR "lkkbd: Unknown error %02x on " + "keyboard at %s\n", lk->id[2], + lk->phys); + break; + } + + /* + * Try to hint user if there's a stuck key. + */ + if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) + printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " + "is 0x%04x\n", lk->id[3], + lk->keycode[lk->id[3]]); + + return; +} + /* * lkkbd_interrupt() is called by the low level driver when a character * is received. @@ -329,7 +423,11 @@ if (lk->ignore_bytes > 0) { DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); - lk->ignore_bytes--; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; + + if (lk->ignore_bytes == 0) + lkkbd_detection_done (lk); + return IRQ_HANDLED; } @@ -375,7 +473,8 @@ break; case 0x01: DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); - lk->ignore_bytes = 3; + lk->ignore_bytes = LK_NUM_IGNORE_BYTES; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; schedule_work (&lk->tq); break; @@ -389,7 +488,7 @@ input_sync (&lk->dev); } else printk (KERN_WARNING "%s: Unknown key with " - "scancode %02x on %s.\n", + "scancode 0x%02x on %s.\n", __FILE__, data, lk->name); } @@ -467,6 +566,9 @@ unsigned char leds_on = 0; unsigned char leds_off = 0; + /* Ask for ID */ + lk->serio->write (lk->serio, LK_CMD_REQUEST_ID); + /* Reset parameters */ lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); @@ -527,9 +629,7 @@ if ((serio->type & SERIO_TYPE) != SERIO_RS232) return; - if (!(serio->type & SERIO_PROTO)) - return; - if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_LKKBD) + if ((serio->type & SERIO_PROTO) != SERIO_LKKBD) return; if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) @@ -537,10 +637,16 @@ memset (lk, 0, sizeof (struct lkkbd)); init_input_dev (&lk->dev); - - lk->dev.evbit[0] = BIT (EV_KEY) | BIT (EV_LED) | BIT (EV_SND) | BIT (EV_REP); - lk->dev.ledbit[0] = BIT (LED_CAPSL) | BIT (LED_COMPOSE) | BIT (LED_SCROLLL) | BIT (LED_SLEEP); - lk->dev.sndbit[0] = BIT (SND_CLICK) | BIT (SND_BELL); + set_bit (EV_KEY, lk->dev.evbit); + set_bit (EV_LED, lk->dev.evbit); + set_bit (EV_SND, lk->dev.evbit); + set_bit (EV_REP, lk->dev.evbit); + set_bit (LED_CAPSL, lk->dev.ledbit); + set_bit (LED_SLEEP, lk->dev.ledbit); + set_bit (LED_COMPOSE, lk->dev.ledbit); + set_bit (LED_SCROLLL, lk->dev.ledbit); + set_bit (SND_BELL, lk->dev.sndbit); + set_bit (SND_CLICK, lk->dev.sndbit); lk->serio = serio; @@ -564,14 +670,13 @@ return; } - sprintf (lk->name, "LK keyboard"); + sprintf (lk->name, "DEC LK keyboard"); + sprintf (lk->phys, "%s/input0", serio->phys); memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); for (i = 0; i < LK_NUM_KEYCODES; i++) set_bit (lk->keycode[i], lk->dev.keybit); - sprintf (lk->name, "%s/input0", serio->phys); - lk->dev.name = lk->name; lk->dev.phys = lk->phys; lk->dev.id.bustype = BUS_RS232; @@ -599,9 +704,9 @@ } static struct serio_dev lkkbd_dev = { - .interrupt = lkkbd_interrupt, .connect = lkkbd_connect, .disconnect = lkkbd_disconnect, + .interrupt = lkkbd_interrupt, }; /* diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig --- a/drivers/input/mouse/Kconfig Sun Apr 25 22:39:31 2004 +++ b/drivers/input/mouse/Kconfig Sun Apr 25 22:39:31 2004 @@ -119,7 +119,7 @@ module will be called rpcmouse. config MOUSE_VSXXXAA - tristate "DEC VSXXX-AA/GA mouse and tablet" + tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet" depends on INPUT && INPUT_MOUSE select SERIO help diff -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c --- a/drivers/input/mouse/vsxxxaa.c Sun Apr 25 22:39:32 2004 +++ b/drivers/input/mouse/vsxxxaa.c Sun Apr 25 22:39:32 2004 @@ -11,14 +11,14 @@ /* * 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 + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -45,32 +45,32 @@ * * DEC socket DB9 DB25 Note * 1 (GND) 5 7 - - * 2 (RxD) 3 3 - - * 3 (TxD) 2 2 - + * 2 (RxD) 2 3 - + * 3 (TxD) 3 2 - * 4 (-12V) - - Somewhere from the PSU. At ATX, it's - * the blue wire at pin 12 of the ATX - * power connector. Please note that the - * docs say this should be +12V! However, - * I measured -12V... - * 5 (+5V) - - PSU (red wire of ATX power connector + * the thin blue wire at pin 12 of the + * ATX power connector. Only required for + * VSXXX-AA/-GA mice. + * 5 (+5V) - - PSU (red wires of ATX power connector * on pin 4, 6, 19 or 20) or HDD power - * connector (also red wire) - * 6 (not conn.) - - - + * connector (also red wire). + * 6 (+12V) - - HDD power connector, yellow wire. Only + * required for VSXXX-AB digitizer. * 7 (dev. avail.) - - The mouse shorts this one to pin 1. * This way, the host computer can detect * the mouse. To use it with the adaptor, * simply don't connect this pin. * * So to get a working adaptor, you need to connect the mouse with three - * wires to a RS232 port and two additional wires for +5V and -12V to the - * PSU. + * wires to a RS232 port and two or three additional wires for +5V, +12V and + * -12V to the PSU. * * Flow specification for the link is 4800, 8o1. - */ - -/* - * TODO list: - * - Automatically attach to a given serial port (no need for inputattach). + * + * The mice and tablet are described in "VCB02 Video Subsystem - Technical + * Manual", DEC EK-104AA-TM-001. You'll find it at MANX, a search engine + * specific for DEC documentation. Try + * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 */ #include @@ -115,6 +115,7 @@ unsigned char version; unsigned char country; unsigned char type; + char name[64]; char phys[32]; }; @@ -134,27 +135,34 @@ { if (mouse->count == BUFLEN) { printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", - mouse->dev.name, mouse->dev.phys); + mouse->name, mouse->phys); vsxxxaa_drop_bytes (mouse, 1); } + DBG (KERN_INFO "Queueing byte 0x%02x\n", byte); mouse->buf[mouse->count++] = byte; } static void -vsxxxaa_report_mouse (struct vsxxxaa *mouse) +vsxxxaa_detection_done (struct vsxxxaa *mouse) { - char *devtype; - switch (mouse->type) { - case 0x02: devtype = "DEC mouse"; break; - case 0x04: devtype = "DEC tablet"; break; - default: devtype = "unknown DEC device"; break; + case 0x02: + sprintf (mouse->name, "DEC VSXXX-AA/GA mouse"); + break; + + case 0x04: + sprintf (mouse->name, "DEC VSXXX-AB digitizer"); + break; + + default: + sprintf (mouse->name, "unknown DEC pointer device"); + break; } - printk (KERN_INFO "Found %s version 0x%x from country 0x%x " - "on port %s\n", devtype, mouse->version, - mouse->country, mouse->dev.phys); + printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x " + "on port %s\n", mouse->name, mouse->version, + mouse->country, mouse->phys); } /* @@ -216,7 +224,7 @@ * 0, bit 4 of byte 0 is direction. */ dx = buf[1] & 0x7f; - dx *= ((buf[0] >> 4) & 0x01)? -1: 1; + dx *= ((buf[0] >> 4) & 0x01)? 1: -1; /* * Low 7 bit of byte 2 are abs(dy), bit 7 is @@ -236,7 +244,7 @@ vsxxxaa_drop_bytes (mouse, 3); DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", - mouse->dev.name, mouse->dev.phys, dx, dy, + mouse->name, mouse->phys, dx, dy, left? "L": "l", middle? "M": "m", right? "R": "r"); /* @@ -246,6 +254,7 @@ input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); + input_report_key (dev, BTN_TOUCH, 0); input_report_rel (dev, REL_X, dx); input_report_rel (dev, REL_Y, dy); input_sync (dev); @@ -256,7 +265,7 @@ { struct input_dev *dev = &mouse->dev; unsigned char *buf = mouse->buf; - int left, middle, right, extra; + int left, middle, right, touch; int x, y; /* @@ -270,10 +279,12 @@ */ /* - * Get X/Y position + * Get X/Y position. Y axis needs to be inverted since VSXXX-AB + * counts down->top while monitor counts top->bottom. */ x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f); y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f); + y = 1023 - y; /* * Get button state. It's bits <4..1> of byte 0. @@ -281,14 +292,14 @@ left = (buf[0] & 0x02)? 1: 0; middle = (buf[0] & 0x04)? 1: 0; right = (buf[0] & 0x08)? 1: 0; - extra = (buf[0] & 0x10)? 1: 0; + touch = (buf[0] & 0x10)? 1: 0; vsxxxaa_drop_bytes (mouse, 5); DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", - mouse->dev.name, mouse->dev.phys, x, y, + mouse->name, mouse->phys, x, y, left? "L": "l", middle? "M": "m", - right? "R": "r", extra? "E": "e"); + right? "R": "r", touch? "T": "t"); /* * Report what we've found so far... @@ -297,7 +308,7 @@ input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_EXTRA, extra); + input_report_key (dev, BTN_TOUCH, touch); input_report_abs (dev, ABS_X, x); input_report_abs (dev, ABS_Y, y); input_sync (dev); @@ -334,7 +345,7 @@ mouse->version = buf[0] & 0x0f; mouse->country = (buf[1] >> 4) & 0x07; - mouse->type = buf[1] & 0x07; + mouse->type = buf[1] & 0x0f; error = buf[2] & 0x7f; /* @@ -347,7 +358,7 @@ right = (buf[0] & 0x01)? 1: 0; vsxxxaa_drop_bytes (mouse, 4); - vsxxxaa_report_mouse (mouse); + vsxxxaa_detection_done (mouse); if (error <= 0x1f) { /* No error. Report buttons */ @@ -355,20 +366,22 @@ input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); + input_report_key (dev, BTN_TOUCH, 0); input_sync (dev); } else { printk (KERN_ERR "Your %s on %s reports an undefined error, " - "please check it...\n", mouse->dev.name, - mouse->dev.phys); + "please check it...\n", mouse->name, + mouse->phys); } /* - * If the mouse was hot-plugged, we need to - * force differential mode now... + * If the mouse was hot-plugged, we need to force differential mode + * now... However, give it a second to recover from it's reset. */ printk (KERN_NOTICE "%s on %s: Forceing standard packet format and " - "streaming mode\n", mouse->dev.name, mouse->dev.phys); + "streaming mode\n", mouse->name, mouse->phys); mouse->serio->write (mouse->serio, 'S'); + mdelay (50); mouse->serio->write (mouse->serio, 'R'); } @@ -392,7 +405,7 @@ while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { printk (KERN_ERR "%s on %s: Dropping a byte to regain " "sync with mouse data stream...\n", - mouse->dev.name, mouse->dev.phys); + mouse->name, mouse->phys); vsxxxaa_drop_bytes (mouse, 1); } @@ -475,7 +488,6 @@ if ((serio->type & SERIO_TYPE) != SERIO_RS232) return; - if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA) return; @@ -486,14 +498,15 @@ init_input_dev (&mouse->dev); set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ - set_bit (EV_REL, mouse->dev.evbit); /* We can move */ + set_bit (EV_REL, mouse->dev.evbit); + set_bit (EV_ABS, mouse->dev.evbit); set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ set_bit (BTN_MIDDLE, mouse->dev.keybit); set_bit (BTN_RIGHT, mouse->dev.keybit); - set_bit (BTN_EXTRA, mouse->dev.keybit); /* ...and Tablet */ - set_bit (REL_X, mouse->dev.relbit); /* We can move in */ - set_bit (REL_Y, mouse->dev.relbit); /* two dimensions */ - set_bit (ABS_X, mouse->dev.absbit); /* DEC tablet support */ + set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */ + set_bit (REL_X, mouse->dev.relbit); + set_bit (REL_Y, mouse->dev.relbit); + set_bit (ABS_X, mouse->dev.absbit); set_bit (ABS_Y, mouse->dev.absbit); mouse->dev.absmin[ABS_X] = 0; @@ -504,9 +517,10 @@ mouse->dev.private = mouse; serio->private = mouse; + sprintf (mouse->name, "DEC VSXXX-AA/GA mouse or VSXXX-AB digitizer"); sprintf (mouse->phys, "%s/input0", serio->phys); + mouse->dev.name = mouse->name; mouse->dev.phys = mouse->phys; - mouse->dev.name = "DEC VSXXX-AA/GA mouse or DEC tablet"; mouse->dev.id.bustype = BUS_RS232; mouse->serio = serio; @@ -516,20 +530,20 @@ } /* - * Request selftest and differential stream mode. + * Request selftest. Standard packet format and differential + * mode will be requested after the device ID'ed successfully. */ mouse->serio->write (mouse->serio, 'T'); /* Test */ - mouse->serio->write (mouse->serio, 'R'); /* Differential stream */ input_register_device (&mouse->dev); - printk (KERN_INFO "input: %s on %s\n", mouse->dev.name, serio->phys); + printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); } static struct serio_dev vsxxxaa_dev = { - .interrupt = vsxxxaa_interrupt, - .connect = vsxxxaa_connect, - .disconnect = vsxxxaa_disconnect + .connect = vsxxxaa_connect, + .interrupt = vsxxxaa_interrupt, + .disconnect = vsxxxaa_disconnect, }; int __init diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig --- a/drivers/input/serio/Kconfig Sun Apr 25 22:39:31 2004 +++ b/drivers/input/serio/Kconfig Sun Apr 25 22:39:31 2004 @@ -130,3 +130,13 @@ To compile this driver as a module, choose M here: the module will be called pcips2. + +config SERIO_MACEPS2 + tristate "SGI O2 MACE PS/2 controller" + depends on SGI_IP32 && SERIO + help + Say Y here if you have SGI O2 workstation and want to use its + PS/2 ports. + + To compile this driver as a module, choose M here: the + module will be called maceps2. diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile --- a/drivers/input/serio/Makefile Sun Apr 25 22:39:31 2004 +++ b/drivers/input/serio/Makefile Sun Apr 25 22:39:31 2004 @@ -16,3 +16,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o +obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h --- a/drivers/input/serio/i8042-io.h Sun Apr 25 22:39:31 2004 +++ b/drivers/input/serio/i8042-io.h Sun Apr 25 22:39:31 2004 @@ -69,7 +69,7 @@ * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. */ -#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(__mips__) if (!request_region(I8042_DATA_REG, 16, "i8042")) return -1; #endif diff -Nru a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/i8042-ip22io.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,76 @@ +#ifndef _I8042_IP22_H +#define _I8042_IP22_H + +#include +#include + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "hpc3ps2/serio0" +#define I8042_AUX_PHYS_DESC "hpc3ps2/serio1" +#define I8042_MUX_PHYS_DESC "hpc3ps2/serio%d" + +/* + * IRQs. + */ + +#define I8042_KBD_IRQ SGI_KEYBD_IRQ +#define I8042_AUX_IRQ SGI_KEYBD_IRQ + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG ((unsigned long)&sgioc->kbdmouse.command) +#define I8042_STATUS_REG ((unsigned long)&sgioc->kbdmouse.command) +#define I8042_DATA_REG ((unsigned long)&sgioc->kbdmouse.data) + +static inline int i8042_read_data(void) +{ + return sgioc->kbdmouse.data; +} + +static inline int i8042_read_status(void) +{ + return sgioc->kbdmouse.command; +} + +static inline void i8042_write_data(int val) +{ + sgioc->kbdmouse.data = val; +} + +static inline void i8042_write_command(int val) +{ + sgioc->kbdmouse.command = val; +} + +static inline int i8042_platform_init(void) +{ +#if 0 + /* XXX sgi_kh is a virtual address */ + if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) + return 1; +#endif + + i8042_reset = 1; + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#if 0 + release_mem_region(JAZZ_KEYBOARD_ADDRESS, sizeof(struct hpc_keyb)); +#endif +} + +#endif /* _I8042_IP22_H */ diff -Nru a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/i8042-jazzio.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,69 @@ +#ifndef _I8042_JAZZ_H +#define _I8042_JAZZ_H + +#include + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "R4030/serio0" +#define I8042_AUX_PHYS_DESC "R4030/serio1" +#define I8042_MUX_PHYS_DESC "R4030/serio%d" + +/* + * IRQs. + */ + +#define I8042_KBD_IRQ JAZZ_KEYBOARD_IRQ +#define I8042_AUX_IRQ JAZZ_MOUSE_IRQ + +#define I8042_COMMAND_REG ((unsigned long)&jazz_kh->command) +#define I8042_STATUS_REG ((unsigned long)&jazz_kh->command) +#define I8042_DATA_REG ((unsigned long)&jazz_kh->data) + +static inline int i8042_read_data(void) +{ + return jazz_kh->data; +} + +static inline int i8042_read_status(void) +{ + return jazz_kh->command; +} + +static inline void i8042_write_data(int val) +{ + jazz_kh->data = val; +} + +static inline void i8042_write_command(int val) +{ + jazz_kh->command = val; +} + +static inline int i8042_platform_init(void) +{ +#if 0 + /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ + if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) + return 1; +#endif + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#if 0 + release_mem_region(JAZZ_KEYBOARD_ADDRESS, 2); +#endif +} + +#endif /* _I8042_JAZZ_H */ diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h --- a/drivers/input/serio/i8042.h Sun Apr 25 22:39:31 2004 +++ b/drivers/input/serio/i8042.h Sun Apr 25 22:39:31 2004 @@ -1,6 +1,8 @@ #ifndef _I8042_H #define _I8042_H +#include + /* * Copyright (c) 1999-2002 Vojtech Pavlik * @@ -13,7 +15,11 @@ * Arch-dependent inline functions and defines. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_MIPS_JAZZ) +#include "i8042-jazzio.h" +#elif defined(CONFIG_SGI_IP22) +#include "i8042-ip22io.h" +#elif defined(CONFIG_PPC) #include "i8042-ppcio.h" #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) #include "i8042-sparcio.h" diff -Nru a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/maceps2.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,160 @@ +/* + * SGI O2 MACE PS2 controller driver for linux + * + * Copyright (C) 2002 Vivien Chappelier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vivien Chappelier driver)->port; + unsigned int timeout = MACE_PS2_TIMEOUT; + + do { + if (mace_read(port->status) & PS2_STATUS_TX_EMPTY) { + mace_write(val, port->tx); + return 0; + } + udelay(50); + } while (timeout--); + + return -1; +} + +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct serio *dev = dev_id; + struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + unsigned int byte; + + if (mace_read(port->status) & PS2_STATUS_RX_FULL) { + byte = mace_read(port->rx); + serio_interrupt(dev, byte & 0xff, 0, regs); + } + + return IRQ_HANDLED; +} + +static int maceps2_open(struct serio *dev) +{ + struct maceps2_data *data = (struct maceps2_data *)dev->driver; + + if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { + printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); + return -EBUSY; + } + + /* Reset port */ + mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, + data->port->control); + udelay(100); + + /* Enable interrupts */ + mace_write(PS2_CONTROL_RX_CLOCK_ENABLE | PS2_CONTROL_TX_ENABLE | + PS2_CONTROL_RX_INT_ENABLE, data->port->control); + + return 0; +} + +static void maceps2_close(struct serio *dev) +{ + struct maceps2_data *data = (struct maceps2_data *)dev->driver; + + mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, + data->port->control); + udelay(100); + free_irq(data->irq, dev); +} + +static struct maceps2_data port0_data, port1_data; + +static struct serio maceps2_port0 = +{ + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port0", + .phys = "mace/serio0", + .driver = &port0_data, +}; + +static struct serio maceps2_port1 = +{ + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port1", + .phys = "mace/serio1", + .driver = &port1_data, +}; + +static int __init maceps2_init(void) +{ + port0_data.port = &mace->perif.ps2.keyb; + port0_data.irq = MACEISA_KEYB_IRQ; + port1_data.port = &mace->perif.ps2.mouse; + port1_data.irq = MACEISA_MOUSE_IRQ; + serio_register_port(&maceps2_port0); + serio_register_port(&maceps2_port1); + + return 0; +} + +static void __exit maceps2_exit(void) +{ + serio_unregister_port(&maceps2_port0); + serio_unregister_port(&maceps2_port1); +} + +module_init(maceps2_init); +module_exit(maceps2_exit); diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c --- a/drivers/md/dm.c Sun Apr 25 22:39:31 2004 +++ b/drivers/md/dm.c Sun Apr 25 22:39:31 2004 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ */ #define DMF_BLOCK_IO 0 #define DMF_SUSPENDED 1 +#define DMF_FS_LOCKED 2 struct mapped_device { struct rw_semaphore lock; @@ -80,6 +82,11 @@ */ uint32_t event_nr; wait_queue_head_t eventq; + + /* + * freeze/thaw support require holding onto a super block + */ + struct super_block *frozen_sb; }; #define MIN_IOS 256 @@ -885,6 +892,52 @@ } /* + * Functions to lock and unlock any filesystem running on the + * device. + */ +static int __lock_fs(struct mapped_device *md) +{ + struct block_device *bdev; + + if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) + return 0; + + bdev = bdget_disk(md->disk, 0); + if (!bdev) { + DMWARN("bdget failed in __lock_fs"); + return -ENOMEM; + } + + WARN_ON(md->frozen_sb); + md->frozen_sb = freeze_bdev(bdev); + /* don't bdput right now, we don't want the bdev + * to go away while it is locked. We'll bdput + * in __unlock_fs + */ + return 0; +} + +static int __unlock_fs(struct mapped_device *md) +{ + struct block_device *bdev; + + if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) + return 0; + + bdev = bdget_disk(md->disk, 0); + if (!bdev) { + DMWARN("bdget failed in __unlock_fs"); + return -ENOMEM; + } + + thaw_bdev(bdev, md->frozen_sb); + md->frozen_sb = NULL; + bdput(bdev); + bdput(bdev); + return 0; +} + +/* * We need to be able to change a mapping table under a mounted * filesystem. For example we might want to move some data in * the background. Before the table can be swapped with @@ -896,13 +949,27 @@ struct dm_table *map; DECLARE_WAITQUEUE(wait, current); - down_write(&md->lock); + /* Flush I/O to the device. */ + down_read(&md->lock); + if (test_bit(DMF_BLOCK_IO, &md->flags)) { + up_read(&md->lock); + return -EINVAL; + } + + __lock_fs(md); + up_read(&md->lock); /* * First we set the BLOCK_IO flag so no more ios will be * mapped. */ + down_write(&md->lock); if (test_bit(DMF_BLOCK_IO, &md->flags)) { + /* + * If we get here we know another thread is + * trying to suspend as well, so we leave the fs + * locked for this thread. + */ up_write(&md->lock); return -EINVAL; } @@ -937,6 +1004,7 @@ /* were we interrupted ? */ if (atomic_read(&md->pending)) { + __unlock_fs(md); clear_bit(DMF_BLOCK_IO, &md->flags); up_write(&md->lock); return -EINTR; @@ -974,6 +1042,7 @@ def = bio_list_get(&md->deferred); __flush_deferred_io(md, def); up_write(&md->lock); + __unlock_fs(md); dm_table_unplug_all(map); dm_table_put(map); diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Sun Apr 25 22:39:31 2004 +++ b/drivers/net/Kconfig Sun Apr 25 22:39:31 2004 @@ -471,11 +471,32 @@ bool "SGI IOC3 Ethernet" depends on NET_ETHERNET && SGI_IP27 select CRC32 + select MII help If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from . +config SGI_IOC3_ETH_HW_RX_CSUM + bool "Receive hardware checksums" + depends on SGI_IOC3_ETH && INET + default y + help + The SGI IOC3 network adapter supports TCP and UDP checksums in + hardware to offload processing of these checksums from the CPU. At + the moment only acceleration of IPv4 is supported. This option + enables offloading for checksums on receive. If unsure, say Y. + +config SGI_IOC3_ETH_HW_TX_CSUM + bool "Transmit hardware checksums" + depends on SGI_IOC3_ETH && INET + default y + help + The SGI IOC3 network adapter supports TCP and UDP checksums in + hardware to offload processing of these checksums from the CPU. At + the moment only acceleration of IPv4 is supported. This option + enables offloading for checksums on transmit. If unsure, say Y. + config SGI_O2MACE_ETH tristate "SGI O2 MACE Fast Ethernet support" depends on NET_ETHERNET && SGI_IP32=y @@ -1777,7 +1798,7 @@ config DECLANCE tristate "DEC LANCE ethernet controller support" - depends on NET_ETHERNET && DECSTATION + depends on NET_ETHERNET && MACH_DECSTATION select CRC32 help This driver is for the series of Ethernet controllers produced by diff -Nru a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c --- a/drivers/net/bagetlance.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/bagetlance.c Sun Apr 25 22:39:31 2004 @@ -1,4 +1,4 @@ -/* $Id$ +/* * bagetlance.c: Ethernet driver for VME Lance cards on Baget/MIPS * This code stealed and adopted from linux/drivers/net/atarilance.c * See that for author info diff -Nru a/drivers/net/declance.c b/drivers/net/declance.c --- a/drivers/net/declance.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/declance.c Sun Apr 25 22:39:31 2004 @@ -786,7 +786,7 @@ /* Associate IRQ with lance_interrupt */ if (request_irq(dev->irq, &lance_interrupt, 0, "lance", dev)) { - printk("lance: Can't get IRQ %d\n", dev->irq); + printk("%s: Can't get IRQ %d\n", dev->name, dev->irq); return -EAGAIN; } if (lp->dma_irq >= 0) { @@ -795,7 +795,8 @@ if (request_irq(lp->dma_irq, &lance_dma_merr_int, 0, "lance error", dev)) { free_irq(dev->irq, dev); - printk("lance: Can't get DMA IRQ %d\n", lp->dma_irq); + printk("%s: Can't get DMA IRQ %d\n", dev->name, + lp->dma_irq); return -EAGAIN; } @@ -877,8 +878,8 @@ volatile struct lance_regs *ll = lp->ll; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", - dev->name, ll->rdp); - lance_reset(dev); + dev->name, ll->rdp); + lance_reset(dev); netif_wake_queue(dev); } @@ -1025,6 +1026,8 @@ static int __init dec_lance_init(const int type, const int slot) { static unsigned version_printed; + static const char fmt[] = "declance%d"; + char name[10]; struct net_device *dev; struct lance_private *lp; volatile struct lance_regs *ll; @@ -1039,10 +1042,22 @@ if (dec_lance_debug && version_printed++ == 0) printk(version); + i = 0; + dev = root_lance_dev; + while (dev) { + i++; + lp = (struct lance_private *)dev->priv; + dev = lp->next; + } + snprintf(name, sizeof(name), fmt, i); + dev = alloc_etherdev(sizeof(struct lance_private)); - if (!dev) - return -ENOMEM; - SET_MODULE_OWNER(dev); + if (!dev) { + printk(KERN_ERR "%s: Unable to allocate etherdev, aborting.\n", + name); + ret = -ENOMEM; + goto err_out; + } /* * alloc_etherdev ensures the data structures used by the LANCE @@ -1160,9 +1175,10 @@ break; default: - printk("declance_init called with unknown type\n"); + printk(KERN_ERR "%s: declance_init called with unknown type\n", + name); ret = -ENODEV; - goto err_out; + goto err_out_free_dev; } ll = (struct lance_regs *) dev->base_addr; @@ -1172,19 +1188,21 @@ /* First, check for test pattern */ if (esar[0x60] != 0xff && esar[0x64] != 0x00 && esar[0x68] != 0x55 && esar[0x6c] != 0xaa) { - printk("Ethernet station address prom not found!\n"); + printk(KERN_ERR + "%s: Ethernet station address prom not found!\n", + name); ret = -ENODEV; - goto err_out; + goto err_out_free_dev; } /* Check the prom contents */ for (i = 0; i < 8; i++) { if (esar[i * 4] != esar[0x3c - i * 4] && esar[i * 4] != esar[0x40 + i * 4] && esar[0x3c - i * 4] != esar[0x40 + i * 4]) { - printk("Something is wrong with the ethernet " - "station address prom!\n"); + printk(KERN_ERR "%s: Something is wrong with the " + "ethernet station address prom!\n", name); ret = -ENODEV; - goto err_out; + goto err_out_free_dev; } } @@ -1194,13 +1212,13 @@ */ switch (type) { case ASIC_LANCE: - printk("%s: IOASIC onboard LANCE, addr = ", dev->name); + printk("%s: IOASIC onboard LANCE, addr = ", name); break; case PMAD_LANCE: - printk("%s: PMAD-AA, addr = ", dev->name); + printk("%s: PMAD-AA, addr = ", name); break; case PMAX_LANCE: - printk("%s: PMAX onboard LANCE, addr = ", dev->name); + printk("%s: PMAX onboard LANCE, addr = ", name); break; } for (i = 0; i < 6; i++) { @@ -1236,15 +1254,24 @@ init_timer(&lp->multicast_timer); lp->multicast_timer.data = (unsigned long) dev; lp->multicast_timer.function = &lance_set_multicast_retry; + ret = register_netdev(dev); - if (ret) - goto err_out; + if (ret) { + printk(KERN_ERR + "%s: Unable to register netdev, aborting.\n", name); + goto err_out_free_dev; + } + lp->next = root_lance_dev; root_lance_dev = dev; + + printk("%s: registered as %s.\n", name, dev->name); return 0; +err_out_free_dev: + kfree(dev); + err_out: - free_netdev(dev); return ret; } diff -Nru a/drivers/net/e100.c b/drivers/net/e100.c --- a/drivers/net/e100.c Sun Apr 25 22:39:32 2004 +++ b/drivers/net/e100.c Sun Apr 25 22:39:32 2004 @@ -287,6 +287,7 @@ }; enum scb_cmd_lo { + cuc_nop = 0x00, ruc_start = 0x01, ruc_load_base = 0x06, cuc_start = 0x10, @@ -514,10 +515,11 @@ /* End: frequently used values: keep adjacent for cache effect */ enum { - ich = (1 << 0), - promiscuous = (1 << 1), - multicast_all = (1 << 2), - wol_magic = (1 << 3), + ich = (1 << 0), + promiscuous = (1 << 1), + multicast_all = (1 << 2), + wol_magic = (1 << 3), + ich_10h_workaround = (1 << 4), } flags ____cacheline_aligned; enum mac mac; @@ -1225,6 +1227,12 @@ /* Issue a multicast command to workaround a 557 lock up */ e100_set_multicast_list(nic->netdev); + if(nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF) + /* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */ + nic->flags |= ich_10h_workaround; + else + nic->flags &= ~ich_10h_workaround; + mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); } @@ -1244,7 +1252,17 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct nic *nic = netdev->priv; - int err = e100_exec_cb(nic, skb, e100_xmit_prepare); + int err; + + if(nic->flags & ich_10h_workaround) { + /* SW workaround for ICH[x] 10Mbps/half duplex Tx hang. + Issue a NOP command followed by a 1us delay before + issuing the Tx command. */ + e100_exec_cmd(nic, cuc_nop, 0); + udelay(1); + } + + err = e100_exec_cb(nic, skb, e100_xmit_prepare); switch(err) { case -ENOSPC: diff -Nru a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c --- a/drivers/net/ioc3-eth.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/ioc3-eth.c Sun Apr 25 22:39:31 2004 @@ -26,6 +26,10 @@ * which workarounds are required for them? Do we ever have Lucent's? * o For the 2.5 branch kill the mii-tool ioctls. */ + +#define IOC3_NAME "ioc3-eth" +#define IOC3_VERSION "2.6.3-3" + #include #include #include @@ -35,6 +39,11 @@ #include #include #include +#include +#include +#include +#include +#include #ifdef CONFIG_SERIAL_8250 #include @@ -48,8 +57,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -68,18 +79,12 @@ */ #define RX_BUFFS 64 -/* Timer state engine. */ -enum ioc3_timer_state { - arbwait = 0, /* Waiting for auto negotiation to complete. */ - lupwait = 1, /* Auto-neg complete, awaiting link-up status. */ - ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */ - asleep = 3, /* Time inactive. */ -}; +#define ETCSR_FD ((17<data); \ - if(__offset) \ - skb_reserve(__skb, __offset); \ - } \ - __skb; \ -}) +#define IOC3_CACHELINE 128UL + +static inline unsigned long aligned_rx_skb_addr(unsigned long addr) +{ + return (~addr + 1) & (IOC3_CACHELINE - 1UL); +} + +static inline struct sk_buff * ioc3_alloc_skb(unsigned long length, + unsigned int gfp_mask) +{ + struct sk_buff *skb; + + skb = alloc_skb(length + IOC3_CACHELINE - 1, gfp_mask); + if (likely(skb)) { + int offset = aligned_rx_skb_addr((unsigned long) skb->data); + if (offset) + skb_reserve(skb, offset); + } + + return skb; +} + +static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) +{ +#ifdef CONFIG_SGI_IP27 + vdev <<= 58; /* Shift to PCI64_ATTR_VIRTUAL */ + + return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF | + ((unsigned long)ptr & TO_PHYS_MASK); +#else + return virt_to_bus(ptr); +#endif +} /* BEWARE: The IOC3 documentation documents the size of rx buffers as 1644 while it's actually 1664. This one was nasty to track down ... */ #define RX_OFFSET 10 -#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + 128) +#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + IOC3_CACHELINE) /* DMA barrier to separate cached and uncached accesses. */ #define BARRIER() \ @@ -144,70 +168,114 @@ #define IOC3_SIZE 0x100000 -#define ioc3_r(reg) \ -({ \ - u32 __res; \ - __res = ioc3->reg; \ - __res; \ -}) - -#define ioc3_w(reg,val) \ -do { \ - (ioc3->reg = (val)); \ -} while(0) +/* + * IOC3 is a big endian device + * + * Unorthodox but makes the users of these macros more readable - the pointer + * to the IOC3's memory mapped registers is expected as struct ioc3 * ioc3 + * in the environment. + */ +#define ioc3_r_mcr() be32_to_cpu(ioc3->mcr) +#define ioc3_w_mcr(v) do { ioc3->mcr = cpu_to_be32(v); } while (0) +#define ioc3_w_gpcr_s(v) do { ioc3->gpcr_s = cpu_to_be32(v); } while (0) +#define ioc3_r_emcr() be32_to_cpu(ioc3->emcr) +#define ioc3_w_emcr(v) do { ioc3->emcr = cpu_to_be32(v); } while (0) +#define ioc3_r_eisr() be32_to_cpu(ioc3->eisr) +#define ioc3_w_eisr(v) do { ioc3->eisr = cpu_to_be32(v); } while (0) +#define ioc3_r_eier() be32_to_cpu(ioc3->eier) +#define ioc3_w_eier(v) do { ioc3->eier = cpu_to_be32(v); } while (0) +#define ioc3_r_ercsr() be32_to_cpu(ioc3->ercsr) +#define ioc3_w_ercsr(v) do { ioc3->ercsr = cpu_to_be32(v); } while (0) +#define ioc3_r_erbr_h() be32_to_cpu(ioc3->erbr_h) +#define ioc3_w_erbr_h(v) do { ioc3->erbr_h = cpu_to_be32(v); } while (0) +#define ioc3_r_erbr_l() be32_to_cpu(ioc3->erbr_l) +#define ioc3_w_erbr_l(v) do { ioc3->erbr_l = cpu_to_be32(v); } while (0) +#define ioc3_r_erbar() be32_to_cpu(ioc3->erbar) +#define ioc3_w_erbar(v) do { ioc3->erbar = cpu_to_be32(v); } while (0) +#define ioc3_r_ercir() be32_to_cpu(ioc3->ercir) +#define ioc3_w_ercir(v) do { ioc3->ercir = cpu_to_be32(v); } while (0) +#define ioc3_r_erpir() be32_to_cpu(ioc3->erpir) +#define ioc3_w_erpir(v) do { ioc3->erpir = cpu_to_be32(v); } while (0) +#define ioc3_r_ertr() be32_to_cpu(ioc3->ertr) +#define ioc3_w_ertr(v) do { ioc3->ertr = cpu_to_be32(v); } while (0) +#define ioc3_r_etcsr() be32_to_cpu(ioc3->etcsr) +#define ioc3_w_etcsr(v) do { ioc3->etcsr = cpu_to_be32(v); } while (0) +#define ioc3_r_ersr() be32_to_cpu(ioc3->ersr) +#define ioc3_w_ersr(v) do { ioc3->ersr = cpu_to_be32(v); } while (0) +#define ioc3_r_etcdc() be32_to_cpu(ioc3->etcdc) +#define ioc3_w_etcdc(v) do { ioc3->etcdc = cpu_to_be32(v); } while (0) +#define ioc3_r_ebir() be32_to_cpu(ioc3->ebir) +#define ioc3_w_ebir(v) do { ioc3->ebir = cpu_to_be32(v); } while (0) +#define ioc3_r_etbr_h() be32_to_cpu(ioc3->etbr_h) +#define ioc3_w_etbr_h(v) do { ioc3->etbr_h = cpu_to_be32(v); } while (0) +#define ioc3_r_etbr_l() be32_to_cpu(ioc3->etbr_l) +#define ioc3_w_etbr_l(v) do { ioc3->etbr_l = cpu_to_be32(v); } while (0) +#define ioc3_r_etcir() be32_to_cpu(ioc3->etcir) +#define ioc3_w_etcir(v) do { ioc3->etcir = cpu_to_be32(v); } while (0) +#define ioc3_r_etpir() be32_to_cpu(ioc3->etpir) +#define ioc3_w_etpir(v) do { ioc3->etpir = cpu_to_be32(v); } while (0) +#define ioc3_r_emar_h() be32_to_cpu(ioc3->emar_h) +#define ioc3_w_emar_h(v) do { ioc3->emar_h = cpu_to_be32(v); } while (0) +#define ioc3_r_emar_l() be32_to_cpu(ioc3->emar_l) +#define ioc3_w_emar_l(v) do { ioc3->emar_l = cpu_to_be32(v); } while (0) +#define ioc3_r_ehar_h() be32_to_cpu(ioc3->ehar_h) +#define ioc3_w_ehar_h(v) do { ioc3->ehar_h = cpu_to_be32(v); } while (0) +#define ioc3_r_ehar_l() be32_to_cpu(ioc3->ehar_l) +#define ioc3_w_ehar_l(v) do { ioc3->ehar_l = cpu_to_be32(v); } while (0) +#define ioc3_r_micr() be32_to_cpu(ioc3->micr) +#define ioc3_w_micr(v) do { ioc3->micr = cpu_to_be32(v); } while (0) +#define ioc3_r_midr_r() be32_to_cpu(ioc3->midr_r) +#define ioc3_w_midr_r(v) do { ioc3->midr_r = cpu_to_be32(v); } while (0) +#define ioc3_r_midr_w() be32_to_cpu(ioc3->midr_w) +#define ioc3_w_midr_w(v) do { ioc3->midr_w = cpu_to_be32(v); } while (0) -static inline u32 -mcr_pack(u32 pulse, u32 sample) +static inline u32 mcr_pack(u32 pulse, u32 sample) { return (pulse << 10) | (sample << 2); } -static int -nic_wait(struct ioc3 *ioc3) +static int nic_wait(struct ioc3 *ioc3) { u32 mcr; do { - mcr = ioc3_r(mcr); + mcr = ioc3_r_mcr(); } while (!(mcr & 2)); return mcr & 1; } -static int -nic_reset(struct ioc3 *ioc3) +static int nic_reset(struct ioc3 *ioc3) { int presence; - ioc3_w(mcr, mcr_pack(500, 65)); + ioc3_w_mcr(mcr_pack(500, 65)); presence = nic_wait(ioc3); - ioc3_w(mcr, mcr_pack(0, 500)); + ioc3_w_mcr(mcr_pack(0, 500)); nic_wait(ioc3); return presence; } -static inline int -nic_read_bit(struct ioc3 *ioc3) +static inline int nic_read_bit(struct ioc3 *ioc3) { int result; - ioc3_w(mcr, mcr_pack(6, 13)); + ioc3_w_mcr(mcr_pack(6, 13)); result = nic_wait(ioc3); - ioc3_w(mcr, mcr_pack(0, 100)); + ioc3_w_mcr(mcr_pack(0, 100)); nic_wait(ioc3); return result; } -static inline void -nic_write_bit(struct ioc3 *ioc3, int bit) +static inline void nic_write_bit(struct ioc3 *ioc3, int bit) { if (bit) - ioc3_w(mcr, mcr_pack(6, 110)); + ioc3_w_mcr(mcr_pack(6, 110)); else - ioc3_w(mcr, mcr_pack(80, 30)); + ioc3_w_mcr(mcr_pack(80, 30)); nic_wait(ioc3); } @@ -215,8 +283,7 @@ /* * Read a byte from an iButton device */ -static u32 -nic_read_byte(struct ioc3 *ioc3) +static u32 nic_read_byte(struct ioc3 *ioc3) { u32 result = 0; int i; @@ -230,8 +297,7 @@ /* * Write a byte to an iButton device */ -static void -nic_write_byte(struct ioc3 *ioc3, int byte) +static void nic_write_byte(struct ioc3 *ioc3, int byte) { int i, bit; @@ -243,8 +309,7 @@ } } -static u64 -nic_find(struct ioc3 *ioc3, int *last) +static u64 nic_find(struct ioc3 *ioc3, int *last) { int a, b, index, disc; u64 address = 0; @@ -352,7 +417,7 @@ int tries = 2; /* There may be some problem with the battery? */ int i; - ioc3_w(gpcr_s, (1 << 21)); + ioc3_w_gpcr_s(1 << 21); while (tries--) { if (!nic_init(ioc3)) @@ -374,7 +439,7 @@ nic[i] = nic_read_byte(ioc3); for (i = 2; i < 8; i++) - ip->dev->dev_addr[i - 2] = nic[i]; + priv_netdev(ip)->dev_addr[i - 2] = nic[i]; } /* @@ -391,7 +456,7 @@ printk("Ethernet address is "); for (i = 0; i < 6; i++) { - printk("%02x", ip->dev->dev_addr[i]); + printk("%02x", priv_netdev(ip)->dev_addr[i]); if (i < 5) printk(":"); } @@ -403,42 +468,112 @@ * Caller must hold the ioc3_lock ever for MII readers. This is also * used to protect the transmitter side but it's low contention. */ -static u16 mii_read(struct ioc3_private *ip, int reg) +static int ioc3_mdio_read(struct net_device *dev, int phy, int reg) { + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; - int phy = ip->phy; - while (ioc3->micr & MICR_BUSY); - ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG; - while (ioc3->micr & MICR_BUSY); + while (ioc3_r_micr() & MICR_BUSY); + ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG); + while (ioc3_r_micr() & MICR_BUSY); - return ioc3->midr_r & MIDR_DATA_MASK; + return ioc3_r_micr() & MIDR_DATA_MASK; } -static void mii_write(struct ioc3_private *ip, int reg, u16 data) +static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data) { + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; - int phy = ip->phy; - while (ioc3->micr & MICR_BUSY); - ioc3->midr_w = data; - ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg; - while (ioc3->micr & MICR_BUSY); + while (ioc3_r_micr() & MICR_BUSY); + ioc3_w_midr_w(data); + ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg); + while (ioc3_r_micr() & MICR_BUSY); } static int ioc3_mii_init(struct ioc3_private *ip); static struct net_device_stats *ioc3_get_stats(struct net_device *dev) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; - ip->stats.collisions += (ioc3->etcdc & ETCDC_COLLCNT_MASK); + ip->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK); return &ip->stats; } -static inline void -ioc3_rx(struct ioc3_private *ip) +#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM + +static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) +{ + struct ethhdr *eh = skb->mac.ethernet; + uint32_t csum, ehsum; + unsigned int proto; + struct iphdr *ih; + uint16_t *ew; + unsigned char *cp; + + /* + * Did hardware handle the checksum at all? The cases we can handle + * are: + * + * - TCP and UDP checksums of IPv4 only. + * - IPv6 would be doable but we keep that for later ... + * - Only unfragmented packets. Did somebody already tell you + * fragmentation is evil? + * - don't care about packet size. Worst case when processing a + * malformed packet we'll try to access the packet at ip header + + * 64 bytes which is still inside the skb. Even in the unlikely + * case where the checksum is right the higher layers will still + * drop the packet as appropriate. + */ + if (eh->h_proto != ntohs(ETH_P_IP)) + return; + + ih = (struct iphdr *) ((char *)eh + ETH_HLEN); + if (ih->frag_off & htons(IP_MF | IP_OFFSET)) + return; + + proto = ih->protocol; + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) + return; + + /* Same as tx - compute csum of pseudo header */ + csum = hwsum + + (ih->tot_len - (ih->ihl << 2)) + + htons((uint16_t)ih->protocol) + + (ih->saddr >> 16) + (ih->saddr & 0xffff) + + (ih->daddr >> 16) + (ih->daddr & 0xffff); + + /* Sum up ethernet dest addr, src addr and protocol */ + ew = (uint16_t *) eh; + ehsum = ew[0] + ew[1] + ew[2] + ew[3] + ew[4] + ew[5] + ew[6]; + + ehsum = (ehsum & 0xffff) + (ehsum >> 16); + ehsum = (ehsum & 0xffff) + (ehsum >> 16); + + csum += 0xffff ^ ehsum; + + /* In the next step we also subtract the 1's complement + checksum of the trailing ethernet CRC. */ + cp = (char *)eh + len; /* points at trailing CRC */ + if (len & 1) { + csum += 0xffff ^ (uint16_t) ((cp[1] << 8) | cp[0]); + csum += 0xffff ^ (uint16_t) ((cp[3] << 8) | cp[2]); + } else { + csum += 0xffff ^ (uint16_t) ((cp[0] << 8) | cp[1]); + csum += 0xffff ^ (uint16_t) ((cp[2] << 8) | cp[3]); + } + + csum = (csum & 0xffff) + (csum >> 16); + csum = (csum & 0xffff) + (csum >> 16); + + if (csum == 0xffff) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} +#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */ + +static inline void ioc3_rx(struct ioc3_private *ip) { struct sk_buff *skb, *new_skb; struct ioc3 *ioc3 = ip->regs; @@ -460,7 +595,7 @@ if (err & ERXBUF_GOODPKT) { len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; skb_trim(skb, len); - skb->protocol = eth_type_trans(skb, ip->dev); + skb->protocol = eth_type_trans(skb, priv_netdev(ip)); new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); if (!new_skb) { @@ -470,18 +605,23 @@ new_skb = skb; goto next; } + +#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM + ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len); +#endif + netif_rx(skb); ip->rx_skbs[rx_entry] = NULL; /* Poison */ - new_skb->dev = ip->dev; + new_skb->dev = priv_netdev(ip); /* Because we reserve afterwards. */ skb_put(new_skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) new_skb->data; skb_reserve(new_skb, RX_OFFSET); - ip->dev->last_rx = jiffies; + priv_netdev(ip)->last_rx = jiffies; ip->stats.rx_packets++; /* Statistics */ ip->stats.rx_bytes += len; } else { @@ -497,8 +637,7 @@ ip->stats.rx_frame_errors++; next: ip->rx_skbs[n_entry] = new_skb; - rxr[n_entry] = cpu_to_be64((0xa5UL << 56) | - ((unsigned long) rxb & TO_PHYS_MASK)); + rxr[n_entry] = cpu_to_be64(ioc3_map(rxb, 1)); rxb->w0 = 0; /* Clear valid flag */ n_entry = (n_entry + 1) & 511; /* Update erpir */ @@ -508,13 +647,12 @@ rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); w0 = be32_to_cpu(rxb->w0); } - ioc3->erpir = (n_entry << 3) | ERPIR_ARM; + ioc3_w_erpir((n_entry << 3) | ERPIR_ARM); ip->rx_pi = n_entry; ip->rx_ci = rx_entry; } -static inline void -ioc3_tx(struct ioc3_private *ip) +static inline void ioc3_tx(struct ioc3_private *ip) { unsigned long packets, bytes; struct ioc3 *ioc3 = ip->regs; @@ -523,7 +661,7 @@ u32 etcir; spin_lock(&ip->ioc3_lock); - etcir = ioc3->etcir; + etcir = ioc3_r_etcir(); tx_entry = (etcir >> 7) & 127; o_entry = ip->tx_ci; @@ -539,7 +677,7 @@ o_entry = (o_entry + 1) & 127; /* Next */ - etcir = ioc3->etcir; /* More pkts sent? */ + etcir = ioc3_r_etcir(); /* More pkts sent? */ tx_entry = (etcir >> 7) & 127; } @@ -548,7 +686,7 @@ ip->txqlen -= packets; if (ip->txqlen < 128) - netif_wake_queue(ip->dev); + netif_wake_queue(priv_netdev(ip)); ip->tx_ci = o_entry; spin_unlock(&ip->ioc3_lock); @@ -561,12 +699,13 @@ * with such error interrupts if something really goes wrong, so we might * also consider to take the interface down. */ -static void -ioc3_error(struct ioc3_private *ip, u32 eisr) +static void ioc3_error(struct ioc3_private *ip, u32 eisr) { - struct net_device *dev = ip->dev; + struct net_device *dev = priv_netdev(ip); unsigned char *iface = dev->name; + spin_lock(&ip->ioc3_lock); + if (eisr & EISR_RXOFLO) printk(KERN_ERR "%s: RX overflow.\n", iface); if (eisr & EISR_RXBUFOFLO) @@ -581,11 +720,12 @@ printk(KERN_ERR "%s: TX PCI error.\n", iface); ioc3_stop(ip); - ioc3_init(ip); + ioc3_init(dev); ioc3_mii_init(ip); - dev->trans_start = jiffies; netif_wake_queue(dev); + + spin_unlock(&ip->ioc3_lock); } /* The interrupt handler does all of the Rx thread work and cleans up @@ -593,524 +733,100 @@ static irqreturn_t ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)_dev; - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXEXPLICIT | EISR_TXMEMERR; u32 eisr; - eisr = ioc3->eisr & enabled; + eisr = ioc3_r_eisr() & enabled; - while (eisr) { - ioc3->eisr = eisr; - ioc3->eisr; /* Flush */ - - if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR | - EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR)) - ioc3_error(ip, eisr); - if (eisr & EISR_RXTIMERINT) - ioc3_rx(ip); - if (eisr & EISR_TXEXPLICIT) - ioc3_tx(ip); + ioc3_w_eisr(eisr); + (void) ioc3_r_eisr(); /* Flush */ - eisr = ioc3->eisr & enabled; - } - return IRQ_HANDLED; -} + if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR | + EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR)) + ioc3_error(ip, eisr); + if (eisr & EISR_RXTIMERINT) + ioc3_rx(ip); + if (eisr & EISR_TXEXPLICIT) + ioc3_tx(ip); -/* - * Auto negotiation. The scheme is very simple. We have a timer routine that - * keeps watching the auto negotiation process as it progresses. The DP83840 - * is first told to start doing it's thing, we set up the time and place the - * timer state machine in it's initial state. - * - * Here the timer peeks at the DP83840 status registers at each click to see - * if the auto negotiation has completed, we assume here that the DP83840 PHY - * will time out at some point and just tell us what (didn't) happen. For - * complete coverage we only allow so many of the ticks at this level to run, - * when this has expired we print a warning message and try another strategy. - * This "other" strategy is to force the interface into various speed/duplex - * configurations and we stop when we see a link-up condition before the - * maximum number of "peek" ticks have occurred. - * - * Once a valid link status has been detected we configure the IOC3 to speak - * the most efficient protocol we could get a clean link for. The priority - * for link configurations, highest first is: - * - * 100 Base-T Full Duplex - * 100 Base-T Half Duplex - * 10 Base-T Full Duplex - * 10 Base-T Half Duplex - * - * We start a new timer now, after a successful auto negotiation status has - * been detected. This timer just waits for the link-up bit to get set in - * the BMCR of the DP83840. When this occurs we print a kernel log message - * describing the link type in use and the fact that it is up. - * - * If a fatal error of some sort is signalled and detected in the interrupt - * service routine, and the chip is reset, or the link is ifconfig'd down - * and then back up, this entire process repeats itself all over again. - */ -static int ioc3_try_next_permutation(struct ioc3_private *ip) -{ - ip->sw_bmcr = mii_read(ip, MII_BMCR); - - /* Downgrade from full to half duplex. Only possible via ethtool. */ - if (ip->sw_bmcr & BMCR_FULLDPLX) { - ip->sw_bmcr &= ~BMCR_FULLDPLX; - mii_write(ip, MII_BMCR, ip->sw_bmcr); - - return 0; - } - - /* Downgrade from 100 to 10. */ - if (ip->sw_bmcr & BMCR_SPEED100) { - ip->sw_bmcr &= ~BMCR_SPEED100; - mii_write(ip, MII_BMCR, ip->sw_bmcr); - - return 0; - } - - /* We've tried everything. */ - return -1; -} - -static void -ioc3_display_link_mode(struct ioc3_private *ip) -{ - char *tmode = ""; - - ip->sw_lpa = mii_read(ip, MII_LPA); - - if (ip->sw_lpa & (LPA_100HALF | LPA_100FULL)) { - if (ip->sw_lpa & LPA_100FULL) - tmode = "100Mb/s, Full Duplex"; - else - tmode = "100Mb/s, Half Duplex"; - } else { - if (ip->sw_lpa & LPA_10FULL) - tmode = "10Mb/s, Full Duplex"; - else - tmode = "10Mb/s, Half Duplex"; - } - - printk(KERN_INFO "%s: Link is up at %s.\n", ip->dev->name, tmode); -} - -static void -ioc3_display_forced_link_mode(struct ioc3_private *ip) -{ - char *speed = "", *duplex = ""; - - ip->sw_bmcr = mii_read(ip, MII_BMCR); - if (ip->sw_bmcr & BMCR_SPEED100) - speed = "100Mb/s, "; - else - speed = "10Mb/s, "; - if (ip->sw_bmcr & BMCR_FULLDPLX) - duplex = "Full Duplex.\n"; - else - duplex = "Half Duplex.\n"; - - printk(KERN_INFO "%s: Link has been forced up at %s%s", ip->dev->name, - speed, duplex); + return IRQ_HANDLED; } -static int ioc3_set_link_modes(struct ioc3_private *ip) +static inline void ioc3_setup_duplex(struct ioc3_private *ip) { struct ioc3 *ioc3 = ip->regs; - int full; - /* - * All we care about is making sure the bigmac tx_cfg has a - * proper duplex setting. - */ - if (ip->timer_state == arbwait) { - ip->sw_lpa = mii_read(ip, MII_LPA); - if (!(ip->sw_lpa & (LPA_10HALF | LPA_10FULL | - LPA_100HALF | LPA_100FULL))) - goto no_response; - if (ip->sw_lpa & LPA_100FULL) - full = 1; - else if (ip->sw_lpa & LPA_100HALF) - full = 0; - else if (ip->sw_lpa & LPA_10FULL) - full = 1; - else - full = 0; - } else { - /* Forcing a link mode. */ - ip->sw_bmcr = mii_read(ip, MII_BMCR); - if (ip->sw_bmcr & BMCR_FULLDPLX) - full = 1; - else - full = 0; - } - - if (full) + if (ip->mii.full_duplex) { + ioc3_w_etcsr(ETCSR_FD); ip->emcr |= EMCR_DUPLEX; - else + } else { + ioc3_w_etcsr(ETCSR_HD); ip->emcr &= ~EMCR_DUPLEX; - - ioc3->emcr = ip->emcr; - ioc3->emcr; - - return 0; - -no_response: - - return 1; -} - -static int is_lucent_phy(struct ioc3_private *ip) -{ - unsigned short mr2, mr3; - int ret = 0; - - mr2 = mii_read(ip, MII_PHYSID1); - mr3 = mii_read(ip, MII_PHYSID2); - if ((mr2 & 0xffff) == 0x0180 && ((mr3 & 0xffff) >> 10) == 0x1d) { - ret = 1; } - - return ret; + ioc3_w_emcr(ip->emcr); } static void ioc3_timer(unsigned long data) { struct ioc3_private *ip = (struct ioc3_private *) data; - int restart_timer = 0; - - ip->timer_ticks++; - switch (ip->timer_state) { - case arbwait: - /* - * Only allow for 5 ticks, thats 10 seconds and much too - * long to wait for arbitration to complete. - */ - if (ip->timer_ticks >= 10) { - /* Enter force mode. */ - do_force_mode: - ip->sw_bmcr = mii_read(ip, MII_BMCR); - printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," - " trying force link mode\n", ip->dev->name); - ip->sw_bmcr = BMCR_SPEED100; - mii_write(ip, MII_BMCR, ip->sw_bmcr); - - if (!is_lucent_phy(ip)) { - /* - * OK, seems we need do disable the transceiver - * for the first tick to make sure we get an - * accurate link state at the second tick. - */ - ip->sw_csconfig = mii_read(ip, MII_CSCONFIG); - ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB); - mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); - } - ip->timer_state = ltrywait; - ip->timer_ticks = 0; - restart_timer = 1; - } else { - /* Anything interesting happen? */ - ip->sw_bmsr = mii_read(ip, MII_BMSR); - if (ip->sw_bmsr & BMSR_ANEGCOMPLETE) { - int ret; - - /* Just what we've been waiting for... */ - ret = ioc3_set_link_modes(ip); - if (ret) { - /* Ooops, something bad happened, go to - * force mode. - * - * XXX Broken hubs which don't support - * XXX 802.3u auto-negotiation make this - * XXX happen as well. - */ - goto do_force_mode; - } - - /* - * Success, at least so far, advance our state - * engine. - */ - ip->timer_state = lupwait; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - case lupwait: - /* - * Auto negotiation was successful and we are awaiting a - * link up status. I have decided to let this timer run - * forever until some sort of error is signalled, reporting - * a message to the user at 10 second intervals. - */ - ip->sw_bmsr = mii_read(ip, MII_BMSR); - if (ip->sw_bmsr & BMSR_LSTATUS) { - /* - * Wheee, it's up, display the link mode in use and put - * the timer to sleep. - */ - ioc3_display_link_mode(ip); - ip->timer_state = asleep; - restart_timer = 0; - } else { - if (ip->timer_ticks >= 10) { - printk(KERN_NOTICE "%s: Auto negotiation successful, link still " - "not completely up.\n", ip->dev->name); - ip->timer_ticks = 0; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; + /* Print the link status if it has changed */ + mii_check_media(&ip->mii, 1, 0); + ioc3_setup_duplex(ip); - case ltrywait: - /* - * Making the timeout here too long can make it take - * annoyingly long to attempt all of the link mode - * permutations, but then again this is essentially - * error recovery code for the most part. - */ - ip->sw_bmsr = mii_read(ip, MII_BMSR); - ip->sw_csconfig = mii_read(ip, MII_CSCONFIG); - if (ip->timer_ticks == 1) { - if (!is_lucent_phy(ip)) { - /* - * Re-enable transceiver, we'll re-enable the - * transceiver next tick, then check link state - * on the following tick. - */ - ip->sw_csconfig |= CSCONFIG_TCVDISAB; - mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); - } - restart_timer = 1; - break; - } - if (ip->timer_ticks == 2) { - if (!is_lucent_phy(ip)) { - ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB); - mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); - } - restart_timer = 1; - break; - } - if (ip->sw_bmsr & BMSR_LSTATUS) { - /* Force mode selection success. */ - ioc3_display_forced_link_mode(ip); - ioc3_set_link_modes(ip); /* XXX error? then what? */ - ip->timer_state = asleep; - restart_timer = 0; - } else { - if (ip->timer_ticks >= 4) { /* 6 seconds or so... */ - int ret; - - ret = ioc3_try_next_permutation(ip); - if (ret == -1) { - /* - * Aieee, tried them all, reset the - * chip and try all over again. - */ - printk(KERN_NOTICE "%s: Link down, " - "cable problem?\n", - ip->dev->name); - - ioc3_init(ip); - return; - } - if (!is_lucent_phy(ip)) { - ip->sw_csconfig = mii_read(ip, - MII_CSCONFIG); - ip->sw_csconfig |= CSCONFIG_TCVDISAB; - mii_write(ip, MII_CSCONFIG, - ip->sw_csconfig); - } - ip->timer_ticks = 0; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - - case asleep: - default: - /* Can't happens.... */ - printk(KERN_ERR "%s: Aieee, link timer is asleep but we got " - "one anyways!\n", ip->dev->name); - restart_timer = 0; - ip->timer_ticks = 0; - ip->timer_state = asleep; /* foo on you */ - break; - }; - - if (restart_timer) { - ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */ - add_timer(&ip->ioc3_timer); - } -} - -static void -ioc3_start_auto_negotiation(struct ioc3_private *ip, struct ethtool_cmd *ep) -{ - int timeout; - - /* Read all of the registers we are interested in now. */ - ip->sw_bmsr = mii_read(ip, MII_BMSR); - ip->sw_bmcr = mii_read(ip, MII_BMCR); - ip->sw_physid1 = mii_read(ip, MII_PHYSID1); - ip->sw_physid2 = mii_read(ip, MII_PHYSID2); - - /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */ - - ip->sw_advertise = mii_read(ip, MII_ADVERTISE); - if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { - /* Advertise everything we can support. */ - if (ip->sw_bmsr & BMSR_10HALF) - ip->sw_advertise |= ADVERTISE_10HALF; - else - ip->sw_advertise &= ~ADVERTISE_10HALF; - - if (ip->sw_bmsr & BMSR_10FULL) - ip->sw_advertise |= ADVERTISE_10FULL; - else - ip->sw_advertise &= ~ADVERTISE_10FULL; - if (ip->sw_bmsr & BMSR_100HALF) - ip->sw_advertise |= ADVERTISE_100HALF; - else - ip->sw_advertise &= ~ADVERTISE_100HALF; - if (ip->sw_bmsr & BMSR_100FULL) - ip->sw_advertise |= ADVERTISE_100FULL; - else - ip->sw_advertise &= ~ADVERTISE_100FULL; - mii_write(ip, MII_ADVERTISE, ip->sw_advertise); - - /* - * XXX Currently no IOC3 card I know off supports 100BaseT4, - * XXX and this is because the DP83840 does not support it, - * XXX changes XXX would need to be made to the tx/rx logic in - * XXX the driver as well so I completely skip checking for it - * XXX in the BMSR for now. - */ - -#ifdef AUTO_SWITCH_DEBUG - ASD(("%s: Advertising [ ", ip->dev->name)); - if (ip->sw_advertise & ADVERTISE_10HALF) - ASD(("10H ")); - if (ip->sw_advertise & ADVERTISE_10FULL) - ASD(("10F ")); - if (ip->sw_advertise & ADVERTISE_100HALF) - ASD(("100H ")); - if (ip->sw_advertise & ADVERTISE_100FULL) - ASD(("100F ")); -#endif - - /* Enable Auto-Negotiation, this is usually on already... */ - ip->sw_bmcr |= BMCR_ANENABLE; - mii_write(ip, MII_BMCR, ip->sw_bmcr); - - /* Restart it to make sure it is going. */ - ip->sw_bmcr |= BMCR_ANRESTART; - mii_write(ip, MII_BMCR, ip->sw_bmcr); - - /* BMCR_ANRESTART self clears when the process has begun. */ - - timeout = 64; /* More than enough. */ - while (--timeout) { - ip->sw_bmcr = mii_read(ip, MII_BMCR); - if (!(ip->sw_bmcr & BMCR_ANRESTART)) - break; /* got it. */ - udelay(10); - } - if (!timeout) { - printk(KERN_ERR "%s: IOC3 would not start auto " - "negotiation BMCR=0x%04x\n", - ip->dev->name, ip->sw_bmcr); - printk(KERN_NOTICE "%s: Performing force link " - "detection.\n", ip->dev->name); - goto force_link; - } else { - ip->timer_state = arbwait; - } - } else { -force_link: - /* - * Force the link up, trying first a particular mode. Either - * we are here at the request of ethtool or because the IOC3 - * would not start to autoneg. - */ - - /* - * Disable auto-negotiation in BMCR, enable the duplex and - * speed setting, init the timer state machine, and fire it off. - */ - if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { - ip->sw_bmcr = BMCR_SPEED100; - } else { - if (ep->speed == SPEED_100) - ip->sw_bmcr = BMCR_SPEED100; - else - ip->sw_bmcr = 0; - if (ep->duplex == DUPLEX_FULL) - ip->sw_bmcr |= BMCR_FULLDPLX; - } - mii_write(ip, MII_BMCR, ip->sw_bmcr); - - if (!is_lucent_phy(ip)) { - /* - * OK, seems we need do disable the transceiver for the - * first tick to make sure we get an accurate link - * state at the second tick. - */ - ip->sw_csconfig = mii_read(ip, MII_CSCONFIG); - ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB); - mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); - } - ip->timer_state = ltrywait; - } - - del_timer(&ip->ioc3_timer); - ip->timer_ticks = 0; - ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ - ip->ioc3_timer.data = (unsigned long) ip; - ip->ioc3_timer.function = &ioc3_timer; + ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */ add_timer(&ip->ioc3_timer); } +/* + * Try to find a PHY. There is no apparent relation between the MII addresses + * in the SGI documentation and what we find in reality, so we simply probe + * for the PHY. It seems IOC3 PHYs usually live on address 31. One of my + * onboard IOC3s has the special oddity that probing doesn't seem to find it + * yet the interface seems to work fine, so if probing fails we for now will + * simply default to PHY 31 instead of bailing out. + */ static int ioc3_mii_init(struct ioc3_private *ip) { - int i, found; + struct net_device *dev = priv_netdev(ip); + int i, found = 0, res = 0; + int ioc3_phy_workaround = 1; u16 word; - found = 0; - spin_lock_irq(&ip->ioc3_lock); for (i = 0; i < 32; i++) { - ip->phy = i; - word = mii_read(ip, 2); - if ((word != 0xffff) && (word != 0x0000)) { + word = ioc3_mdio_read(dev, i, MII_PHYSID1); + + if (word != 0xffff && word != 0x0000) { found = 1; break; /* Found a PHY */ } } + if (!found) { - spin_unlock_irq(&ip->ioc3_lock); - return -ENODEV; + if (ioc3_phy_workaround) + i = 31; + else { + ip->mii.phy_id = -1; + res = -ENODEV; + goto out; + } } - ioc3_start_auto_negotiation(ip, NULL); // XXX ethtool - - spin_unlock_irq(&ip->ioc3_lock); + ip->mii.phy_id = i; + ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ + ip->ioc3_timer.data = (unsigned long) ip; + ip->ioc3_timer.function = &ioc3_timer; + add_timer(&ip->ioc3_timer); - return 0; +out: + return res; } -static inline void -ioc3_clean_rx_ring(struct ioc3_private *ip) +static inline void ioc3_clean_rx_ring(struct ioc3_private *ip) { struct sk_buff *skb; int i; @@ -1130,8 +846,7 @@ } } -static inline void -ioc3_clean_tx_ring(struct ioc3_private *ip) +static inline void ioc3_clean_tx_ring(struct ioc3_private *ip) { struct sk_buff *skb; int i; @@ -1148,8 +863,7 @@ ip->tx_ci = 0; } -static void -ioc3_free_rings(struct ioc3_private *ip) +static void ioc3_free_rings(struct ioc3_private *ip) { struct sk_buff *skb; int rx_entry, n_entry; @@ -1176,10 +890,9 @@ } } -static void -ioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip, - struct ioc3 *ioc3) +static void ioc3_alloc_rings(struct net_device *dev) { + struct ioc3_private *ip = netdev_priv(dev); struct ioc3_erxbuf *rxb; unsigned long *rxr; int i; @@ -1209,8 +922,7 @@ /* Because we reserve afterwards. */ skb_put(skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) skb->data; - rxr[i] = cpu_to_be64((0xa5UL << 56) | - ((unsigned long) rxb & TO_PHYS_MASK)); + rxr[i] = cpu_to_be64(ioc3_map(rxb, 1)); skb_reserve(skb, RX_OFFSET); } ip->rx_ci = 0; @@ -1227,39 +939,38 @@ } } -static void -ioc3_init_rings(struct net_device *dev, struct ioc3_private *ip, - struct ioc3 *ioc3) +static void ioc3_init_rings(struct net_device *dev) { + struct ioc3_private *ip = netdev_priv(dev); + struct ioc3 *ioc3 = ip->regs; unsigned long ring; ioc3_free_rings(ip); - ioc3_alloc_rings(dev, ip, ioc3); + ioc3_alloc_rings(dev); ioc3_clean_rx_ring(ip); ioc3_clean_tx_ring(ip); /* Now the rx ring base, consume & produce registers. */ - ring = (0xa5UL << 56) | ((unsigned long)ip->rxr & TO_PHYS_MASK); - ioc3->erbr_h = ring >> 32; - ioc3->erbr_l = ring & 0xffffffff; - ioc3->ercir = (ip->rx_ci << 3); - ioc3->erpir = (ip->rx_pi << 3) | ERPIR_ARM; + ring = ioc3_map(ip->rxr, 0); + ioc3_w_erbr_h(ring >> 32); + ioc3_w_erbr_l(ring & 0xffffffff); + ioc3_w_ercir(ip->rx_ci << 3); + ioc3_w_erpir((ip->rx_pi << 3) | ERPIR_ARM); - ring = (0xa5UL << 56) | ((unsigned long)ip->txr & TO_PHYS_MASK); + ring = ioc3_map(ip->txr, 0); ip->txqlen = 0; /* nothing queued */ /* Now the tx ring base, consume & produce registers. */ - ioc3->etbr_h = ring >> 32; - ioc3->etbr_l = ring & 0xffffffff; - ioc3->etpir = (ip->tx_pi << 7); - ioc3->etcir = (ip->tx_ci << 7); - ioc3->etcir; /* Flush */ + ioc3_w_etbr_h(ring >> 32); + ioc3_w_etbr_l(ring & 0xffffffff); + ioc3_w_etpir(ip->tx_pi << 7); + ioc3_w_etcir(ip->tx_ci << 7); + (void) ioc3_r_etcir(); /* Flush */ } -static inline void -ioc3_ssram_disc(struct ioc3_private *ip) +static inline void ioc3_ssram_disc(struct ioc3_private *ip) { struct ioc3 *ioc3 = ip->regs; volatile u32 *ssram0 = &ioc3->ssram[0x0000]; @@ -1267,7 +978,7 @@ unsigned int pattern = 0x5555; /* Assume the larger size SSRAM and enable parity checking */ - ioc3->emcr |= (EMCR_BUFSIZ | EMCR_RAMPAR); + ioc3_w_emcr(ioc3_r_emcr() | (EMCR_BUFSIZ | EMCR_RAMPAR)); *ssram0 = pattern; *ssram1 = ~pattern & IOC3_SSRAM_DM; @@ -1276,62 +987,63 @@ (*ssram1 & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) { /* set ssram size to 64 KB */ ip->emcr = EMCR_RAMPAR; - ioc3->emcr &= ~EMCR_BUFSIZ; - } else { + ioc3_w_emcr(ioc3_r_emcr() & ~EMCR_BUFSIZ); + } else ip->emcr = EMCR_BUFSIZ | EMCR_RAMPAR; - } } -static void ioc3_init(struct ioc3_private *ip) +static void ioc3_init(struct net_device *dev) { - struct net_device *dev = ip->dev; + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; del_timer(&ip->ioc3_timer); /* Kill if running */ - ioc3->emcr = EMCR_RST; /* Reset */ - ioc3->emcr; /* Flush WB */ + ioc3_w_emcr(EMCR_RST); /* Reset */ + (void) ioc3_r_emcr(); /* Flush WB */ udelay(4); /* Give it time ... */ - ioc3->emcr = 0; - ioc3->emcr; + ioc3_w_emcr(0); + (void) ioc3_r_emcr(); /* Misc registers */ - ioc3->erbar = 0; - ioc3->etcsr = (17<etcdc; /* Clear on read */ - ioc3->ercsr = 15; /* RX low watermark */ - ioc3->ertr = 0; /* Interrupt immediately */ - ioc3->emar_h = (dev->dev_addr[5] << 8) | dev->dev_addr[4]; - ioc3->emar_l = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | - (dev->dev_addr[1] << 8) | dev->dev_addr[0]; - ioc3->ehar_h = ip->ehar_h; - ioc3->ehar_l = ip->ehar_l; - ioc3->ersr = 42; /* XXX should be random */ +#ifdef CONFIG_SGI_IP27 + ioc3_w_erbar(PCI64_ATTR_BAR >> 32); /* Barrier on last store */ +#else + ioc3_w_erbar(0); /* Let PCI API get it right */ +#endif + (void) ioc3_r_etcdc(); /* Clear on read */ + ioc3_w_ercsr(15); /* RX low watermark */ + ioc3_w_ertr(0); /* Interrupt immediately */ + ioc3_w_emar_h((dev->dev_addr[5] << 8) | dev->dev_addr[4]); + ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | + (dev->dev_addr[1] << 8) | dev->dev_addr[0]); + ioc3_w_ehar_h(ip->ehar_h); + ioc3_w_ehar_l(ip->ehar_l); + ioc3_w_ersr(42); /* XXX should be random */ - ioc3_init_rings(ip->dev, ip, ioc3); + ioc3_init_rings(dev); ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN | - EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN; - ioc3->emcr = ip->emcr; - ioc3->eier = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | - EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO | - EISR_TXEXPLICIT | EISR_TXMEMERR; - ioc3->eier; + EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN | EMCR_PADEN; + ioc3_w_emcr(ip->emcr); + ioc3_w_eier(EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | + EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO | + EISR_TXEXPLICIT | EISR_TXMEMERR); + (void) ioc3_r_eier(); } static inline void ioc3_stop(struct ioc3_private *ip) { struct ioc3 *ioc3 = ip->regs; - ioc3->emcr = 0; /* Shutup */ - ioc3->eier = 0; /* Disable interrupts */ - ioc3->eier; /* Flush */ + ioc3_w_emcr(0); /* Shutup */ + ioc3_w_eier(0); /* Disable interrupts */ + (void) ioc3_r_eier(); /* Flush */ } -static int -ioc3_open(struct net_device *dev) +static int ioc3_open(struct net_device *dev) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); if (request_irq(dev->irq, ioc3_interrupt, SA_SHIRQ, ioc3_str, dev)) { printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); @@ -1341,16 +1053,15 @@ ip->ehar_h = 0; ip->ehar_l = 0; - ioc3_init(ip); + ioc3_init(dev); netif_start_queue(dev); return 0; } -static int -ioc3_close(struct net_device *dev) +static int ioc3_close(struct net_device *dev) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); del_timer(&ip->ioc3_timer); @@ -1389,6 +1100,34 @@ && dev->device == PCI_DEVICE_ID_SGI_IOC3; } +/* + * Note about serial ports and consoles: + * For console output, everyone uses the IOC3 UARTA (offset 0x178) + * connected to the master node (look in ip27_setup_console() and + * ip27prom_console_write()). + * + * For serial (/dev/ttyS0 etc), we can not have hardcoded serial port + * addresses on a partitioned machine. Since we currently use the ioc3 + * serial ports, we use dynamic serial port discovery that the serial.c + * driver uses for pci/pnp ports (there is an entry for the SGI ioc3 + * boards in pci_boards[]). Unfortunately, UARTA's pio address is greater + * than UARTB's, although UARTA on o200s has traditionally been known as + * port 0. So, we just use one serial port from each ioc3 (since the + * serial driver adds addresses to get to higher ports). + * + * The first one to do a register_console becomes the preferred console + * (if there is no kernel command line console= directive). /dev/console + * (ie 5, 1) is then "aliased" into the device number returned by the + * "device" routine referred to in this console structure + * (ip27prom_console_dev). + * + * Also look in ip27-pci.c:pci_fixuop_ioc3() for some comments on working + * around ioc3 oddities in this respect. + * + * The IOC3 serials use a 22MHz clock rate with an additional divider by 3. + * (IOC3_BAUD = (22000000 / (3*16))) + */ + static inline void ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) { @@ -1425,6 +1164,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + unsigned int sw_physid1, sw_physid2; struct net_device *dev = NULL; struct ioc3_private *ip; struct ioc3 *ioc3; @@ -1443,8 +1183,7 @@ SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - ip = dev->priv; - ip->dev = dev; + ip = netdev_priv(dev); dev->irq = pdev->irq; @@ -1464,14 +1203,22 @@ #endif spin_lock_init(&ip->ioc3_lock); + init_timer(&ip->ioc3_timer); ioc3_stop(ip); - ioc3_init(ip); + ioc3_init(dev); + + ip->pdev = pdev; + + ip->mii.phy_id_mask = 0x1f; + ip->mii.reg_num_mask = 0x1f; + ip->mii.dev = dev; + ip->mii.mdio_read = ioc3_mdio_read; + ip->mii.mdio_write = ioc3_mdio_write; - init_timer(&ip->ioc3_timer); ioc3_mii_init(ip); - if (ip->phy == -1) { + if (ip->mii.phy_id == -1) { printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n", pci_name(pdev)); err = -ENODEV; @@ -1490,16 +1237,26 @@ dev->get_stats = ioc3_get_stats; dev->do_ioctl = ioc3_ioctl; dev->set_multicast_list = ioc3_set_multicast_list; + dev->ethtool_ops = &ioc3_ethtool_ops; +#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM + dev->features = NETIF_F_IP_CSUM; +#endif + + ioc3_setup_duplex(ip); + sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); + sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); err = register_netdev(dev); if (err) goto out_stop; - vendor = (ip->sw_physid1 << 12) | (ip->sw_physid2 >> 4); - model = (ip->sw_physid2 >> 4) & 0x3f; - rev = ip->sw_physid2 & 0xf; + mii_check_media(&ip->mii, 1, 1); + + vendor = (sw_physid1 << 12) | (sw_physid2 >> 4); + model = (sw_physid2 >> 4) & 0x3f; + rev = sw_physid2 & 0xf; printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, " - "rev %d.\n", dev->name, ip->phy, vendor, model, rev); + "rev %d.\n", dev->name, ip->mii.phy_id, vendor, model, rev); printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name, ip->emcr & EMCR_BUFSIZ ? 128 : 64); @@ -1507,7 +1264,6 @@ out_stop: ioc3_stop(ip); - free_irq(dev->irq, dev); ioc3_free_rings(ip); out_res: pci_release_regions(pdev); @@ -1519,7 +1275,7 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; unregister_netdev(dev); @@ -1551,16 +1307,66 @@ pci_unregister_driver(&ioc3_driver); } -static int -ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long data; - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; unsigned int len; struct ioc3_etxd *desc; + uint32_t w0 = 0; int produce; +#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM + /* + * IOC3 has a fairly simple minded checksumming hardware which simply + * adds up the 1's complement checksum for the entire packet and + * inserts it at an offset which can be specified in the descriptor + * into the transmit packet. This means we have to compensate for the + * MAC header which should not be summed and the TCP/UDP pseudo headers + * manually. + */ + if (skb->ip_summed == CHECKSUM_HW) { + int proto = ntohs(skb->nh.iph->protocol); + unsigned int csoff; + struct iphdr *ih = skb->nh.iph; + uint32_t csum, ehsum; + uint16_t *eh; + + /* The MAC header. skb->mac.ethernet seem the logic approach + to find the MAC header - except it's a NULL pointer ... */ + eh = (uint16_t *) skb->data; + + /* Sum up dest addr, src addr and protocol */ + ehsum = eh[0] + eh[1] + eh[2] + eh[3] + eh[4] + eh[5] + eh[6]; + + /* Fold ehsum. can't use csum_fold which negates also ... */ + ehsum = (ehsum & 0xffff) + (ehsum >> 16); + ehsum = (ehsum & 0xffff) + (ehsum >> 16); + + /* Skip IP header; it's sum is always zero and was + already filled in by ip_output.c */ + csum = csum_tcpudp_nofold(ih->saddr, ih->daddr, + ih->tot_len - (ih->ihl << 2), + proto, 0xffff ^ ehsum); + + csum = (csum & 0xffff) + (csum >> 16); /* Fold again */ + csum = (csum & 0xffff) + (csum >> 16); + + csoff = ETH_HLEN + (ih->ihl << 2); + if (proto == IPPROTO_UDP) { + csoff += offsetof(struct udphdr, check); + skb->h.uh->check = csum; + } + if (proto == IPPROTO_TCP) { + csoff += offsetof(struct tcphdr, check); + skb->h.th->check = csum; + } + + w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); + } +#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */ + spin_lock_irq(&ip->ioc3_lock); data = (unsigned long) skb->data; @@ -1577,29 +1383,24 @@ memset(desc->data + len, 0, ETH_ZLEN - len); len = ETH_ZLEN; } - desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V); + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V | w0); desc->bufcnt = cpu_to_be32(len); - } else if ((data ^ (data + len)) & 0x4000) { - unsigned long b2, s1, s2; - - b2 = (data | 0x3fffUL) + 1UL; - s1 = b2 - data; - s2 = data + len - b2; + } else if ((data ^ (data + len - 1)) & 0x4000) { + unsigned long b2 = (data | 0x3fffUL) + 1UL; + unsigned long s1 = b2 - data; + unsigned long s2 = data + len - b2; desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | - ETXD_B1V | ETXD_B2V); - desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) - | (s2 << ETXD_B2CNT_SHIFT)); - desc->p1 = cpu_to_be64((0xa5UL << 56) | - (data & TO_PHYS_MASK)); - desc->p2 = cpu_to_be64((0xa5UL << 56) | - (data & TO_PHYS_MASK)); + ETXD_B1V | ETXD_B2V | w0); + desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) | + (s2 << ETXD_B2CNT_SHIFT)); + desc->p1 = cpu_to_be64(ioc3_map(skb->data, 1)); + desc->p2 = cpu_to_be64(ioc3_map((void *) b2, 1)); } else { /* Normal sized packet that doesn't cross a page boundary. */ - desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V); + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V | w0); desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT); - desc->p1 = cpu_to_be64((0xa5UL << 56) | - (data & TO_PHYS_MASK)); + desc->p1 = cpu_to_be64(ioc3_map(skb->data, 1)); } BARRIER(); @@ -1608,11 +1409,11 @@ ip->tx_skbs[produce] = skb; /* Remember skb */ produce = (produce + 1) & 127; ip->tx_pi = produce; - ioc3->etpir = produce << 7; /* Fire ... */ + ioc3_w_etpir(produce << 7); /* Fire ... */ ip->txqlen++; - if (ip->txqlen > 127) + if (ip->txqlen >= 127) netif_stop_queue(dev); spin_unlock_irq(&ip->ioc3_lock); @@ -1622,15 +1423,18 @@ static void ioc3_timeout(struct net_device *dev) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + spin_lock_irq(&ip->ioc3_lock); + ioc3_stop(ip); - ioc3_init(ip); + ioc3_init(dev); ioc3_mii_init(ip); - dev->trans_start = jiffies; + spin_unlock_irq(&ip->ioc3_lock); + netif_wake_queue(dev); } @@ -1639,11 +1443,9 @@ * address's bit index in the logical address filter mask */ -static inline unsigned int -ioc3_hash(const unsigned char *addr) +static inline unsigned int ioc3_hash(const unsigned char *addr) { unsigned int temp = 0; - unsigned char byte; u32 crc; int bits; @@ -1659,132 +1461,89 @@ return temp; } +static void ioc3_get_drvinfo (struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct ioc3_private *ip = netdev_priv(dev); + + strcpy (info->driver, IOC3_NAME); + strcpy (info->version, IOC3_VERSION); + strcpy (info->bus_info, pci_name(ip->pdev)); +} -/* We provide both the mii-tools and the ethtool ioctls. */ -static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int ioc3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct ioc3_private *ip = dev->priv; - struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data; - u16 *data = (u16 *)&rq->ifr_data; - struct ioc3 *ioc3 = ip->regs; - struct ethtool_cmd ecmd; + struct ioc3_private *ip = netdev_priv(dev); + int rc; - switch (cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - if (ip->phy == -1) - return -ENODEV; - data[0] = ip->phy; - return 0; - - case SIOCGMIIREG: { /* Read a PHY register. */ - unsigned int phy = data[0]; - unsigned int reg = data[1]; - - if (phy > 0x1f || reg > 0x1f) - return -EINVAL; - - spin_lock_irq(&ip->ioc3_lock); - while (ioc3->micr & MICR_BUSY); - ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG; - while (ioc3->micr & MICR_BUSY); - data[3] = (ioc3->midr_r & MIDR_DATA_MASK); - spin_unlock_irq(&ip->ioc3_lock); - - return 0; - - case SIOCSMIIREG: /* Write a PHY register. */ - phy = data[0]; - reg = data[1]; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (phy > 0x1f || reg > 0x1f) - return -EINVAL; - - spin_lock_irq(&ip->ioc3_lock); - while (ioc3->micr & MICR_BUSY); - ioc3->midr_w = data[2]; - ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg; - while (ioc3->micr & MICR_BUSY); - spin_unlock_irq(&ip->ioc3_lock); + spin_lock_irq(&ip->ioc3_lock); + rc = mii_ethtool_gset(&ip->mii, cmd); + spin_unlock_irq(&ip->ioc3_lock); - return 0; - } - case SIOCETHTOOL: - if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) - return -EFAULT; - - if (ecmd.cmd == ETHTOOL_GSET) { - ecmd.supported = - (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | - SUPPORTED_TP | SUPPORTED_MII); - - ecmd.port = PORT_TP; - ecmd.transceiver = XCVR_INTERNAL; - ecmd.phy_address = ip->phy; - - /* Record PHY settings. */ - spin_lock_irq(&ip->ioc3_lock); - ip->sw_bmcr = mii_read(ip, MII_BMCR); - ip->sw_lpa = mii_read(ip, MII_LPA); - spin_unlock_irq(&ip->ioc3_lock); - if (ip->sw_bmcr & BMCR_ANENABLE) { - ecmd.autoneg = AUTONEG_ENABLE; - ecmd.speed = (ip->sw_lpa & - (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (ecmd.speed == SPEED_100) - ecmd.duplex = (ip->sw_lpa & (LPA_100FULL)) ? - DUPLEX_FULL : DUPLEX_HALF; - else - ecmd.duplex = (ip->sw_lpa & (LPA_10FULL)) ? - DUPLEX_FULL : DUPLEX_HALF; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = (ip->sw_bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; - ecmd.duplex = (ip->sw_bmcr & BMCR_FULLDPLX) ? - DUPLEX_FULL : DUPLEX_HALF; - } - if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) - return -EFAULT; - return 0; - } else if (ecmd.cmd == ETHTOOL_SSET) { - /* 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; - - /* Ok, do it to it. */ - del_timer(&ip->ioc3_timer); - spin_lock_irq(&ip->ioc3_lock); - ioc3_start_auto_negotiation(ip, &ecmd); - spin_unlock_irq(&ip->ioc3_lock); + return rc; +} - return 0; - } else - default: - return -EOPNOTSUPP; - } +static int ioc3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ioc3_private *ip = netdev_priv(dev); + int rc; + + spin_lock_irq(&ip->ioc3_lock); + rc = mii_ethtool_sset(&ip->mii, cmd); + spin_unlock_irq(&ip->ioc3_lock); + + return rc; +} + +static int ioc3_nway_reset(struct net_device *dev) +{ + struct ioc3_private *ip = netdev_priv(dev); + int rc; + + spin_lock_irq(&ip->ioc3_lock); + rc = mii_nway_restart(&ip->mii); + spin_unlock_irq(&ip->ioc3_lock); + + return rc; +} + +static u32 ioc3_get_link(struct net_device *dev) +{ + struct ioc3_private *ip = netdev_priv(dev); + int rc; + + spin_lock_irq(&ip->ioc3_lock); + rc = mii_link_ok(&ip->mii); + spin_unlock_irq(&ip->ioc3_lock); + + return rc; +} + +static struct ethtool_ops ioc3_ethtool_ops = { + .get_drvinfo = ioc3_get_drvinfo, + .get_settings = ioc3_get_settings, + .set_settings = ioc3_set_settings, + .nway_reset = ioc3_nway_reset, + .get_link = ioc3_get_link, +}; + +static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; + struct ioc3_private *ip = netdev_priv(dev); + int rc; + + spin_lock_irq(&ip->ioc3_lock); + rc = generic_mii_ioctl(&ip->mii, data, cmd, NULL); + spin_unlock_irq(&ip->ioc3_lock); - return -EOPNOTSUPP; + return rc; } static void ioc3_set_multicast_list(struct net_device *dev) { struct dev_mc_list *dmi = dev->mc_list; - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; u64 ehar = 0; int i; @@ -1795,12 +1554,12 @@ /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); ip->emcr |= EMCR_PROMISC; - ioc3->emcr = ip->emcr; - ioc3->emcr; + ioc3_w_emcr(ip->emcr); + (void) ioc3_r_emcr(); } else { ip->emcr &= ~EMCR_PROMISC; - ioc3->emcr = ip->emcr; /* Clear promiscuous. */ - ioc3->emcr; + ioc3_w_emcr(ip->emcr); /* Clear promiscuous. */ + (void) ioc3_r_emcr(); if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { /* Too many for hashing to make sense or we want all @@ -1821,14 +1580,14 @@ ip->ehar_h = ehar >> 32; ip->ehar_l = ehar & 0xffffffff; } - ioc3->ehar_h = ip->ehar_h; - ioc3->ehar_l = ip->ehar_l; + ioc3_w_ehar_h(ip->ehar_h); + ioc3_w_ehar_l(ip->ehar_l); } netif_wake_queue(dev); /* Let us get going again. */ } -MODULE_AUTHOR("Ralf Baechle "); +MODULE_AUTHOR("Ralf Baechle "); MODULE_DESCRIPTION("SGI IOC3 Ethernet driver"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c --- a/drivers/net/irda/au1k_ir.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/irda/au1k_ir.c Sun Apr 25 22:39:31 2004 @@ -1,13 +1,10 @@ /* - * * Alchemy Semi Au1000 IrDA driver * * Copyright 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. * ppopov@mvista.com or source@mvista.com * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -20,17 +17,7 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * */ - -#ifndef __mips__ -#error This driver only works with MIPS architectures! -#endif - - #include #include #include @@ -46,7 +33,13 @@ #include #include #include +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) #include +#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) +#include +#else +#error au1k_ir: unsupported board +#endif #include #include @@ -71,10 +64,14 @@ static int qos_mtt_bits = 0x07; /* 1 ms or more */ static struct net_device *ir_devs[NUM_IR_IFF]; static char version[] __devinitdata = - "au1k_ircc:1.0 ppopov@mvista.com\n"; + "au1k_ircc:1.2 ppopov@mvista.com\n"; #define RUN_AT(x) (jiffies + (x)) +#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) +static BCSR * const bcsr = (BCSR *)0xAE000000; +#endif + static spinlock_t ir_lock = SPIN_LOCK_UNLOCKED; /* @@ -128,7 +125,7 @@ if (ret != NULL) { memset(ret, 0, size); *dma_handle = virt_to_bus(ret); - ret = KSEG0ADDR(ret); + ret = (void *)KSEG0ADDR(ret); } return ret; } @@ -136,7 +133,7 @@ static void dma_free(void *vaddr, size_t size) { - vaddr = KSEG0ADDR(vaddr); + vaddr = (void *)KSEG0ADDR(vaddr); free_pages((unsigned long) vaddr, get_order(size)); } @@ -180,7 +177,7 @@ return 0; out1: - aup = dev->priv; + aup = netdev_priv(dev); dma_free((void *)aup->db[0].vaddr, MAX_BUF_SIZE * 2*NUM_IR_DESC); dma_free((void *)aup->rx_ring[0], @@ -205,10 +202,10 @@ static int au1k_irda_net_init(struct net_device *dev) { - struct au1k_private *aup = dev->priv; + struct au1k_private *aup = netdev_priv(dev); int i, retval = 0, err; db_dest_t *pDB, *pDBfree; - unsigned long temp; + dma_addr_t temp; err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); if (err) @@ -281,6 +278,14 @@ aup->tx_ring[i]->flags = 0; aup->tx_db_inuse[i] = pDB; } + +#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) + /* power on */ + bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK; + bcsr->resets |= BCSR_RESETS_IRDA_MODE_FULL; + au_sync(); +#endif + return 0; out3: @@ -296,7 +301,7 @@ static int au1k_init(struct net_device *dev) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); int i; u32 control; u32 ring_address; @@ -340,13 +345,10 @@ { int retval; char hwname[32]; - struct au1k_private *aup = (struct au1k_private *) dev->priv; - - MOD_INC_USE_COUNT; + struct au1k_private *aup = netdev_priv(dev); if ((retval = au1k_init(dev))) { printk(KERN_ERR "%s: error in au1k_init\n", dev->name); - MOD_DEC_USE_COUNT; return retval; } @@ -354,7 +356,6 @@ 0, dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; return retval; } if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt, @@ -362,7 +363,6 @@ free_irq(AU1000_IRDA_TX_INT, dev); printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; return retval; } @@ -380,7 +380,7 @@ static int au1k_irda_stop(struct net_device *dev) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); /* disable interrupts */ writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2); @@ -399,14 +399,13 @@ /* disable the interrupt */ free_irq(AU1000_IRDA_TX_INT, dev); free_irq(AU1000_IRDA_RX_INT, dev); - MOD_DEC_USE_COUNT; return 0; } static void __exit au1k_irda_exit(void) { struct net_device *dev = ir_devs[0]; - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); unregister_netdev(dev); @@ -422,7 +421,7 @@ static inline void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); struct net_device_stats *ps = &aup->stats; ps->tx_packets++; @@ -437,7 +436,7 @@ static void au1k_tx_ack(struct net_device *dev) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); volatile ring_dest_t *ptxd; ptxd = aup->tx_ring[aup->tx_tail]; @@ -480,7 +479,7 @@ */ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); int speed = irda_get_next_speed(skb); volatile ring_dest_t *ptxd; u32 len; @@ -505,13 +504,13 @@ flags = ptxd->flags; if (flags & AU_OWN) { - printk(KERN_INFO "%s: tx_full\n", dev->name); + printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; return 1; } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { - printk(KERN_INFO "%s: tx_full\n", dev->name); + printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; return 1; @@ -531,6 +530,7 @@ memcpy((void *)pDB->vaddr, skb->data, skb->len); ptxd->count_0 = skb->len & 0xff; ptxd->count_1 = (skb->len >> 8) & 0xff; + } else { /* SIR */ @@ -538,6 +538,7 @@ ptxd->count_0 = len & 0xff; ptxd->count_1 = (len >> 8) & 0xff; ptxd->flags |= IR_DIS_CRC; + au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c); } ptxd->flags |= AU_OWN; au_sync(); @@ -556,7 +557,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status, u32 count) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); struct net_device_stats *ps = &aup->stats; ps->rx_packets++; @@ -579,7 +580,7 @@ */ static int au1k_irda_rx(struct net_device *dev) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); struct sk_buff *skb; volatile ring_dest_t *prxd; u32 flags, count; @@ -650,7 +651,7 @@ static void au1k_tx_timeout(struct net_device *dev) { u32 speed; - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); printk(KERN_ERR "%s: tx timeout\n", dev->name); speed = aup->speed; @@ -668,10 +669,13 @@ au1k_irda_set_speed(struct net_device *dev, int speed) { unsigned long flags; - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); u32 control; int ret = 0, timeout = 10, i; volatile ring_dest_t *ptxd; +#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) + unsigned long irda_resets; +#endif if (speed == aup->speed) return ret; @@ -717,10 +721,20 @@ ptxd->flags = AU_OWN; } - if (speed == 4000000) + if (speed == 4000000) { +#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) + bcsr->resets |= BCSR_RESETS_FIR_SEL; +#else /* Pb1000 and Pb1100 */ writel(1<<13, CPLD_AUX1); - else +#endif + } + else { +#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) + bcsr->resets &= ~BCSR_RESETS_FIR_SEL; +#else /* Pb1000 and Pb1100 */ writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1); +#endif + } switch (speed) { case 9600: @@ -766,15 +780,15 @@ } else { if (control & (1<<11)) - printk(KERN_INFO "%s Valid SIR config\n", dev->name); + printk(KERN_DEBUG "%s Valid SIR config\n", dev->name); if (control & (1<<12)) - printk(KERN_INFO "%s Valid MIR config\n", dev->name); + printk(KERN_DEBUG "%s Valid MIR config\n", dev->name); if (control & (1<<13)) - printk(KERN_INFO "%s Valid FIR config\n", dev->name); + printk(KERN_DEBUG "%s Valid FIR config\n", dev->name); if (control & (1<<10)) - printk(KERN_INFO "%s TX enabled\n", dev->name); + printk(KERN_DEBUG "%s TX enabled\n", dev->name); if (control & (1<<9)) - printk(KERN_INFO "%s RX enabled\n", dev->name); + printk(KERN_DEBUG "%s RX enabled\n", dev->name); } spin_unlock_irqrestore(&ir_lock, flags); @@ -785,7 +799,7 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) { struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct au1k_private *aup = dev->priv; + struct au1k_private *aup = netdev_priv(dev); int ret = -EOPNOTSUPP; switch (cmd) { @@ -826,14 +840,12 @@ static struct net_device_stats *au1k_irda_stats(struct net_device *dev) { - struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct au1k_private *aup = netdev_priv(dev); return &aup->stats; } -#ifdef MODULE MODULE_AUTHOR("Pete Popov "); MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); module_init(au1k_irda_init); module_exit(au1k_irda_exit); -#endif /* MODULE */ diff -Nru a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c --- a/drivers/net/iseries_veth.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/iseries_veth.c Sun Apr 25 22:39:31 2004 @@ -61,7 +61,6 @@ #include #include #include -#include #include #include #include @@ -78,10 +77,11 @@ #include #include #include +#include #include "iseries_veth.h" -extern struct pci_dev *iSeries_veth_dev; +extern struct vio_dev *iSeries_veth_dev; MODULE_AUTHOR("Kyle Lucke "); MODULE_DESCRIPTION("iSeries Virtual ethernet driver"); @@ -895,10 +895,10 @@ } dma_length = skb->len; - dma_address = pci_map_single(iSeries_veth_dev, skb->data, - dma_length, PCI_DMA_TODEVICE); + dma_address = vio_map_single(iSeries_veth_dev, skb->data, + dma_length, DMA_TO_DEVICE); - if (pci_dma_mapping_error(dma_address)) + if (dma_mapping_error(dma_address)) goto recycle_and_drop; /* Is it really necessary to check the length and address @@ -1016,8 +1016,8 @@ dma_address = msg->data.addr[0]; dma_length = msg->data.len[0]; - pci_unmap_single(iSeries_veth_dev, dma_address, dma_length, - PCI_DMA_TODEVICE); + vio_unmap_single(iSeries_veth_dev, dma_address, dma_length, + DMA_TO_DEVICE); if (msg->skb) { dev_kfree_skb_any(msg->skb); diff -Nru a/drivers/net/meth.c b/drivers/net/meth.c --- a/drivers/net/meth.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/meth.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* * meth.c -- O2 Builtin 10/100 Ethernet driver * - * Copyright (C) 2001 Ilya Volynets + * Copyright (C) 2001-2003 Ilya Volynets * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,9 +18,10 @@ #include /* error codes */ #include /* size_t */ #include /* mark_bh */ -#include #include +#include +#include /* struct device, et al */ #include /* struct device, and other headers */ #include /* eth_type_trans */ #include /* struct iphdr */ @@ -28,21 +29,22 @@ #include #include /*MII definitions */ -#include #include #include -#include "meth.h" - -#include +#include #include +#include +#include + +#include "meth.h" #ifndef MFE_DEBUG #define MFE_DEBUG 0 #endif #if MFE_DEBUG>=1 -#define DPRINTK(str,args...) printk (KERN_DEBUG "meth(%ld): %s: " str, jiffies, __FUNCTION__ , ## args) +#define DPRINTK(str,args...) printk(KERN_DEBUG "meth: %s: " str, __FUNCTION__ , ## args) #define MFE_RX_DEBUG 2 #else #define DPRINTK(str,args...) @@ -50,15 +52,10 @@ #endif -static const char *version="meth.c: Ilya Volynets (ilya@theIlya.com)"; static const char *meth_str="SGI O2 Fast Ethernet"; -MODULE_AUTHOR("Ilya Volynets"); +MODULE_AUTHOR("Ilya Volynets "); MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver"); -/* This is a load-time options */ -/*static int eth = 0; -MODULE_PARM(eth, "i");*/ - #define HAVE_TX_TIMEOUT /* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */ #define TX_TIMEOUT (400*HZ/1000) @@ -68,133 +65,95 @@ MODULE_PARM(timeout, "i"); #endif -int meth_eth; - /* * This structure is private to each device. It is used to pass * packets in and out, so there is place for a packet */ - -typedef struct meth_private { - struct net_device_stats stats; - volatile struct meth_regs *regs; - u64 mode; /* in-memory copy of MAC control register */ - int phy_addr; /* address of phy, used by mdio_* functions, initialized in mdio_probe*/ +struct meth_private { + struct net_device_stats stats; + /* in-memory copy of MAC Control register */ + unsigned long mac_ctrl; + /* in-memory copy of DMA Control register */ + unsigned long dma_ctrl; + /* address of PHY, used by mdio_* functions, initialized in mdio_probe */ + unsigned long phy_addr; tx_packet *tx_ring; dma_addr_t tx_ring_dma; - int free_space; struct sk_buff *tx_skbs[TX_RING_ENTRIES]; - dma_addr_t tx_skb_dmas[TX_RING_ENTRIES]; - int tx_read,tx_write; - int tx_count; + dma_addr_t tx_skb_dmas[TX_RING_ENTRIES]; + unsigned long tx_read, tx_write, tx_count; rx_packet *rx_ring[RX_RING_ENTRIES]; dma_addr_t rx_ring_dmas[RX_RING_ENTRIES]; - int rx_write; + struct sk_buff *rx_skbs[RX_RING_ENTRIES]; + unsigned long rx_write; - spinlock_t meth_lock; -} meth_private; + spinlock_t meth_lock; +}; -void meth_tx_timeout (struct net_device *dev); -void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); +static void meth_tx_timeout(struct net_device *dev); +static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); /* global, initialized in ip32-setup.c */ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; -static inline void load_eaddr(struct net_device *dev, - volatile struct meth_regs *regs) +static inline void load_eaddr(struct net_device *dev) { int i; DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", (int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF, (int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF); - //memcpy(dev->dev_addr,o2meth_eaddr+2,6); - for (i=0; i<6; i++) - dev->dev_addr[i]=o2meth_eaddr[i]; - regs->mac_addr= //dev->dev_addr[0]|(dev->dev_addr[1]<<8)| - //dev->dev_addr[2]<<16|(dev->dev_addr[3]<<24)| - //dev->dev_addr[4]<<32|(dev->dev_addr[5]<<40); - (*(u64*)o2meth_eaddr)>>16; - DPRINTK("MAC, finally is %0lx\n",regs->mac_addr); + for (i = 0; i < 6; i++) + dev->dev_addr[i] = o2meth_eaddr[i]; + mace_eth_write((*(u64*)o2meth_eaddr)>>16, mac_addr); } /* - *Waits for BUSY status of mdio bus to clear - */ -#define WAIT_FOR_PHY(___regs, ___rval) \ - while((___rval=___regs->phy_data)&MDIO_BUSY){ \ - udelay(25); \ + * Waits for BUSY status of mdio bus to clear + */ +#define WAIT_FOR_PHY(___rval) \ + while ((___rval = mace_eth_read(phy_data)) & MDIO_BUSY) { \ + udelay(25); \ } /*read phy register, return value read */ -static int mdio_read(meth_private *priv,int phyreg) +static unsigned long mdio_read(struct meth_private *priv, unsigned long phyreg) { - volatile meth_regs* regs=priv->regs; - volatile u32 rval; - WAIT_FOR_PHY(regs,rval) - regs->phy_registers=(priv->phy_addr<<5)|(phyreg&0x1f); + unsigned long rval; + WAIT_FOR_PHY(rval); + mace_eth_write((priv->phy_addr << 5) | (phyreg & 0x1f), phy_regs); udelay(25); - regs->phy_trans_go=1; + mace_eth_write(1, phy_trans_go); udelay(25); - WAIT_FOR_PHY(regs,rval) + WAIT_FOR_PHY(rval); return rval&MDIO_DATA_MASK; } -/*write phy register */ -static void mdio_write(meth_private* priv,int pfyreg,int val) -{ - volatile meth_regs* regs=priv->regs; - int rval; -/// DPRINTK("Trying to write value %i to reguster %i\n",val, pfyreg); - spin_lock_irq(&priv->meth_lock); - WAIT_FOR_PHY(regs,rval) - regs->phy_registers=(priv->phy_addr<<5)|(pfyreg&0x1f); - regs->phy_data=val; - udelay(25); - WAIT_FOR_PHY(regs,rval) - spin_unlock_irq(&priv->meth_lock); -} - -/* Modify phy register using given mask and value */ -static void mdio_update(meth_private* priv,int phyreg, int val, int mask) +static int mdio_probe(struct meth_private *priv) { - int rval; - DPRINTK("RMW value %i to PHY register %i with mask %i\n",val,phyreg,mask); - rval=mdio_read(priv,phyreg); - rval=(rval&~mask)|(val&mask); - mdio_write(priv,phyreg,rval); -} - -/* handle errata data on MDIO bus */ -//static void mdio_errata(meth_private *priv) -//{ - /* Hmmm... what the hell is phyerrata? does it come from sys init parameters in IRIX */ -//} -static int mdio_probe(meth_private *priv) -{ - int i, p2, p3; - DPRINTK("Detecting PHY kind\n"); + int i; + unsigned long p2, p3; /* check if phy is detected already */ if(priv->phy_addr>=0&&priv->phy_addr<32) return 0; - spin_lock_irq(&priv->meth_lock); + spin_lock(&priv->meth_lock); for (i=0;i<32;++i){ - priv->phy_addr=(char)i; + priv->phy_addr=i; p2=mdio_read(priv,2); -#ifdef MFE_DEBUG p3=mdio_read(priv,3); +#if MFE_DEBUG>=2 switch ((p2<<12)|(p3>>4)){ - case PHY_QS6612X: - DPRINTK("PHY is QS6612X\n"); - break; - case PHY_ICS1889: - DPRINTK("PHY is ICS1889\n"); - break; - case PHY_ICS1890: - DPRINTK("PHY is ICS1890\n"); - break; - case PHY_DP83840: - DPRINTK("PHY is DP83840\n"); - break; + case PHY_QS6612X: + DPRINTK("PHY is QS6612X\n"); + break; + case PHY_ICS1889: + DPRINTK("PHY is ICS1889\n"); + break; + case PHY_ICS1890: + DPRINTK("PHY is ICS1890\n"); + break; + case PHY_DP83840: + DPRINTK("PHY is DP83840\n"); + break; } #endif if(p2!=0xffff&&p2!=0x0000){ @@ -202,7 +161,7 @@ break; } } - spin_unlock_irq(&priv->meth_lock); + spin_unlock(&priv->meth_lock); if(priv->phy_addr<32) { return 0; } @@ -214,99 +173,96 @@ static void meth_check_link(struct net_device *dev) { struct meth_private *priv = (struct meth_private *) dev->priv; - int mii_partner = mdio_read(priv, 5); - int mii_advertising = mdio_read(priv, 4); - int negotiated = mii_advertising & mii_partner; - int duplex, speed; + unsigned long mii_advertising = mdio_read(priv, 4); + unsigned long mii_partner = mdio_read(priv, 5); + unsigned long negotiated = mii_advertising & mii_partner; + unsigned long duplex, speed; if (mii_partner == 0xffff) return; - duplex = ((negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040)?METH_PHY_FDX:0; - speed = (negotiated & 0x0380)?METH_100MBIT:0; + speed = (negotiated & 0x0380) ? METH_100MBIT : 0; + duplex = ((negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040) ? + METH_PHY_FDX : 0; - if ((priv->mode & METH_PHY_FDX) ^ duplex) - { + if ((priv->mac_ctrl & METH_PHY_FDX) ^ duplex) { DPRINTK("Setting %s-duplex\n", duplex ? "full" : "half"); if (duplex) - priv->mode |= METH_PHY_FDX; + priv->mac_ctrl |= METH_PHY_FDX; else - priv->mode &= ~METH_PHY_FDX; - priv->regs->mac_ctrl = priv->mode; + priv->mac_ctrl &= ~METH_PHY_FDX; + mace_eth_write(priv->mac_ctrl, mac_ctrl); } - if ((priv->mode & METH_100MBIT) ^ speed) - { + if ((priv->mac_ctrl & METH_100MBIT) ^ speed) { DPRINTK("Setting %dMbs mode\n", speed ? 100 : 10); if (duplex) - priv->mode |= METH_100MBIT; + priv->mac_ctrl |= METH_100MBIT; else - priv->mode &= ~METH_100MBIT; - priv->regs->mac_ctrl = priv->mode; + priv->mac_ctrl &= ~METH_100MBIT; + mace_eth_write(priv->mac_ctrl, mac_ctrl); } } -static int meth_init_tx_ring(meth_private *priv) +static int meth_init_tx_ring(struct meth_private *priv) { /* Init TX ring */ - DPRINTK("Initializing TX ring\n"); - priv->tx_ring = (tx_packet *) pci_alloc_consistent(NULL,TX_RING_BUFFER_SIZE,&(priv->tx_ring_dma)); - if(!priv->tx_ring) + priv->tx_ring = dma_alloc_coherent(NULL, TX_RING_BUFFER_SIZE, + &priv->tx_ring_dma, GFP_ATOMIC); + if (!priv->tx_ring) return -ENOMEM; memset(priv->tx_ring, 0, TX_RING_BUFFER_SIZE); priv->tx_count = priv->tx_read = priv->tx_write = 0; - priv->regs->tx_ring_base = priv->tx_ring_dma; - priv->free_space = TX_RING_ENTRIES; + mace_eth_write(priv->tx_ring_dma, tx_ring_base); /* Now init skb save area */ memset(priv->tx_skbs,0,sizeof(priv->tx_skbs)); memset(priv->tx_skb_dmas,0,sizeof(priv->tx_skb_dmas)); - DPRINTK("Done with TX ring init\n"); return 0; } -static int meth_init_rx_ring(meth_private *priv) +static int meth_init_rx_ring(struct meth_private *priv) { int i; - DPRINTK("Initializing RX ring\n"); for(i=0;irx_ring[i]=get_free_page(GFP_KERNEL))) - return -ENOMEM; - DPRINTK("\t2:\t%i\n",i);*/ - priv->rx_ring[i]=(rx_packet*)pci_alloc_consistent(NULL,METH_RX_BUFF_SIZE,&(priv->rx_ring_dmas[i])); + priv->rx_skbs[i]=alloc_skb(METH_RX_BUFF_SIZE,0); + /* 8byte status vector+3quad padding + 2byte padding, + to put data on 64bit aligned boundary */ + skb_reserve(priv->rx_skbs[i],METH_RX_HEAD); + priv->rx_ring[i]=(rx_packet*)(priv->rx_skbs[i]->head); /* I'll need to re-sync it after each RX */ - DPRINTK("\t%p\n",priv->rx_ring[i]); - priv->regs->rx_fifo=priv->rx_ring_dmas[i]; + priv->rx_ring_dmas[i]=dma_map_single(NULL,priv->rx_ring[i], + METH_RX_BUFF_SIZE,DMA_FROM_DEVICE); + mace_eth_write(priv->rx_ring_dmas[i], rx_fifo); } - priv->rx_write = 0; - DPRINTK("Done with RX ring\n"); + priv->rx_write = 0; return 0; } -static void meth_free_tx_ring(meth_private *priv) +static void meth_free_tx_ring(struct meth_private *priv) { int i; /* Remove any pending skb */ for (i = 0; i < TX_RING_ENTRIES; i++) { - if (priv->tx_skbs[i]) - dev_kfree_skb(priv->tx_skbs[i]); + if (priv->tx_skbs[i]) + dev_kfree_skb(priv->tx_skbs[i]); priv->tx_skbs[i] = NULL; } - pci_free_consistent(NULL, - TX_RING_BUFFER_SIZE, - priv->tx_ring, - priv->tx_ring_dma); + dma_free_coherent(NULL, TX_RING_BUFFER_SIZE, priv->tx_ring, + priv->tx_ring_dma); } -static void meth_free_rx_ring(meth_private *priv) + +/* Presumes RX DMA engine is stopped, and RX fifo ring is reset */ +static void meth_free_rx_ring(struct meth_private *priv) { int i; - for(i=0;irx_ring[i], - priv->rx_ring_dmas[i]); + for(i=0;irx_ring_dmas[i],METH_RX_BUFF_SIZE,DMA_FROM_DEVICE); + priv->rx_ring[i]=0; + priv->rx_ring_dmas[i]=0; + kfree_skb(priv->rx_skbs[i]); + } } int meth_reset(struct net_device *dev) @@ -314,13 +270,12 @@ struct meth_private *priv = (struct meth_private *) dev->priv; /* Reset card */ - priv->regs->mac_ctrl = SGI_MAC_RESET; - priv->regs->mac_ctrl = 0; + mace_eth_write(SGI_MAC_RESET, mac_ctrl); + mace_eth_write(0, mac_ctrl); udelay(25); - DPRINTK("MAC control after reset: %016lx\n", priv->regs->mac_ctrl); /* Load ethernet address */ - load_eaddr(dev, priv->regs); + load_eaddr(dev); /* Should load some "errata", but later */ /* Check for device */ @@ -329,20 +284,21 @@ return -ENODEV; } - /* Initial mode -- 10|Half-duplex|Accept normal packets */ - priv->mode=METH_ACCEPT_MCAST|METH_DEFAULT_IPG; + /* Initial mode: 10 | Half-duplex | Accept normal packets */ + priv->mac_ctrl = METH_ACCEPT_MCAST | METH_DEFAULT_IPG; if(dev->flags | IFF_PROMISC) - priv->mode |= METH_PROMISC; - priv->regs->mac_ctrl = priv->mode; + priv->mac_ctrl |= METH_PROMISC; + mace_eth_write(priv->mac_ctrl, mac_ctrl); - /* Autonegociate speed and duplex mode */ + /* Autonegotiate speed and duplex mode */ meth_check_link(dev); /* Now set dma control, but don't enable DMA, yet */ - priv->regs->dma_ctrl= (4 << METH_RX_OFFSET_SHIFT) | - (RX_RING_ENTRIES << METH_RX_DEPTH_SHIFT); + priv->dma_ctrl= (4 << METH_RX_OFFSET_SHIFT) | + (RX_RING_ENTRIES << METH_RX_DEPTH_SHIFT); + mace_eth_write(priv->dma_ctrl, dma_ctrl); - return(0); + return 0; } /*============End Helper Routines=====================*/ @@ -350,110 +306,183 @@ /* * Open and close */ - -int meth_open(struct net_device *dev) +static int meth_open(struct net_device *dev) { - meth_private *priv=dev->priv; - volatile meth_regs *regs=priv->regs; + struct meth_private *priv = dev->priv; + int ret; - /* Start DMA */ - regs->dma_ctrl|= - METH_DMA_TX_EN|/*METH_DMA_TX_INT_EN|*/ - METH_DMA_RX_EN|METH_DMA_RX_INT_EN; + priv->phy_addr = -1; /* No PHY is known yet... */ - if(request_irq(dev->irq,meth_interrupt,SA_SHIRQ,meth_str,dev)){ + /* Initialize the hardware */ + ret = meth_reset(dev); + if (ret < 0) + return ret; + + /* Allocate the ring buffers */ + ret = meth_init_tx_ring(priv); + if (ret < 0) + return ret; + ret = meth_init_rx_ring(priv); + if (ret < 0) + goto out_free_tx_ring; + + ret = request_irq(dev->irq, meth_interrupt, 0, meth_str, dev); + if (ret) { printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); - return -EAGAIN; + goto out_free_rx_ring; } + + /* Start DMA */ + priv->dma_ctrl |= METH_DMA_TX_EN | /*METH_DMA_TX_INT_EN |*/ + METH_DMA_RX_EN | METH_DMA_RX_INT_EN; + mace_eth_write(priv->dma_ctrl, dma_ctrl); + + DPRINTK("About to start queue\n"); netif_start_queue(dev); - DPRINTK("Opened... DMA control=0x%08lx\n", regs->dma_ctrl); + return 0; + +out_free_rx_ring: + meth_free_rx_ring(priv); +out_free_tx_ring: + meth_free_tx_ring(priv); + + return ret; } -int meth_release(struct net_device *dev) +static int meth_release(struct net_device *dev) { - netif_stop_queue(dev); /* can't transmit any more */ - /* shut down dma */ - ((meth_private*)(dev->priv))->regs->dma_ctrl&= - ~(METH_DMA_TX_EN|METH_DMA_TX_INT_EN| - METH_DMA_RX_EN|METH_DMA_RX_INT_EN); + struct meth_private *priv = dev->priv; + + DPRINTK("Stopping queue\n"); + netif_stop_queue(dev); /* can't transmit any more */ + /* shut down DMA */ + priv->dma_ctrl &= ~(METH_DMA_TX_EN | METH_DMA_TX_INT_EN | + METH_DMA_RX_EN | METH_DMA_RX_INT_EN); + mace_eth_write(priv->dma_ctrl, dma_ctrl); free_irq(dev->irq, dev); - return 0; + meth_free_tx_ring(priv); + meth_free_rx_ring(priv); + + return 0; } /* * Configuration changes (passed on by ifconfig) */ -int meth_config(struct net_device *dev, struct ifmap *map) +static int meth_config(struct net_device *dev, struct ifmap *map) { - if (dev->flags & IFF_UP) /* can't act on a running interface */ - return -EBUSY; + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) { + printk(KERN_WARNING "meth: Can't change I/O address\n"); + return -EOPNOTSUPP; + } - /* Don't allow changing the I/O address */ - if (map->base_addr != dev->base_addr) { - printk(KERN_WARNING "meth: Can't change I/O address\n"); - return -EOPNOTSUPP; - } - - /* Allow changing the IRQ */ - if (map->irq != dev->irq) { - printk(KERN_WARNING "meth: Can't change IRQ\n"); - return -EOPNOTSUPP; - } + /* Don't allow changing the IRQ */ + if (map->irq != dev->irq) { + printk(KERN_WARNING "meth: Can't change IRQ\n"); + return -EOPNOTSUPP; + } DPRINTK("Configured\n"); - /* ignore other fields */ - return 0; + /* ignore other fields */ + return 0; } /* * Receive a packet: retrieve, encapsulate and pass over to upper levels */ -void meth_rx(struct net_device* dev) +static void meth_rx(struct net_device* dev, unsigned long int_status) { - struct sk_buff *skb; - struct meth_private *priv = (struct meth_private *) dev->priv; - rx_packet *rxb; - DPRINTK("RX...\n"); - // TEMP while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){ - while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){ - int len=rxb->status.parsed.rx_len - 4; /* omit CRC */ - DPRINTK("(%i)\n",priv->rx_write); - /* length sanity check */ - if(len < 60 || len > 1518) { - printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x.\n", - dev->name, priv->rx_write, rxb->status.raw); - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + struct sk_buff *skb; + struct meth_private *priv = (struct meth_private *) dev->priv; + unsigned long fifo_rptr=(int_status&METH_INT_RX_RPTR_MASK)>>8; + spin_lock(&priv->meth_lock); + priv->dma_ctrl&=~METH_DMA_RX_INT_EN; + mace_eth_write(priv->dma_ctrl, dma_ctrl); + spin_unlock(&priv->meth_lock); + + if (int_status & METH_INT_RX_UNDERFLOW){ + fifo_rptr=(fifo_rptr-1)&(0xF); + } + while(priv->rx_write != fifo_rptr) { + u64 status; + dma_unmap_single(NULL,priv->rx_ring_dmas[priv->rx_write], + METH_RX_BUFF_SIZE,DMA_FROM_DEVICE); + status=priv->rx_ring[priv->rx_write]->status.raw; +#if MFE_DEBUG + if(!(status&METH_RX_ST_VALID)) { + DPRINTK("Not received? status=%016lx\n",status); } - if(!(rxb->status.raw&METH_RX_STATUS_ERRORS)){ - skb=alloc_skb(len+2,GFP_ATOMIC);/* Should be atomic -- we are in interrupt */ - if(!skb){ - /* Ouch! No memory! Drop packet on the floor */ - DPRINTK("!!!>>>Ouch! Not enough Memory for RX buffer!\n"); - priv->stats.rx_dropped++; +#endif + if((!(status&METH_RX_STATUS_ERRORS))&&(status&METH_RX_ST_VALID)){ + int len=(status&0xFFFF) - 4; /* omit CRC */ + /* length sanity check */ + if(len < 60 || len > 1518) { + printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2lx.\n", + dev->name, priv->rx_write, + priv->rx_ring[priv->rx_write]->status.raw); + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; + skb=priv->rx_skbs[priv->rx_write]; } else { - skb_reserve(skb, 2); /* align IP on 16B boundary */ - memcpy(skb_put(skb, len), rxb->buf, len); - /* Write metadata, and then pass to the receive level */ - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - //skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ - - DPRINTK("passing packet\n"); - DPRINTK("len = %d rxb->status = %x\n", - len, rxb->status.raw); - netif_rx(skb); - dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes+=len; - DPRINTK("There we go... Whew...\n"); + skb=alloc_skb(METH_RX_BUFF_SIZE,GFP_ATOMIC|GFP_DMA); + if(!skb){ + /* Ouch! No memory! Drop packet on the floor */ + DPRINTK("No mem: dropping packet\n"); + priv->stats.rx_dropped++; + skb=priv->rx_skbs[priv->rx_write]; + } else { + struct sk_buff *skb_c=priv->rx_skbs[priv->rx_write]; + /* 8byte status vector+3quad padding + 2byte padding, + to put data on 64bit aligned boundary */ + skb_reserve(skb,METH_RX_HEAD); + /* Write metadata, and then pass to the receive level */ + skb_put(skb_c,len); + priv->rx_skbs[priv->rx_write]=skb; + skb_c->dev = dev; + skb_c->protocol = eth_type_trans(skb_c, dev); + dev->last_rx = jiffies; + priv->stats.rx_packets++; + priv->stats.rx_bytes+=len; + netif_rx(skb_c); + } } + } else { + priv->stats.rx_errors++; + skb=priv->rx_skbs[priv->rx_write]; +#if MFE_DEBUG>0 + printk(KERN_WARNING "meth: RX error: status=0x%016lx\n",status); + if(status&METH_RX_ST_RCV_CODE_VIOLATION) + printk(KERN_WARNING "Receive Code Violation\n"); + if(status&METH_RX_ST_CRC_ERR) + printk(KERN_WARNING "CRC error\n"); + if(status&METH_RX_ST_INV_PREAMBLE_CTX) + printk(KERN_WARNING "Invalid Preamble Context\n"); + if(status&METH_RX_ST_LONG_EVT_SEEN) + printk(KERN_WARNING "Long Event Seen...\n"); + if(status&METH_RX_ST_BAD_PACKET) + printk(KERN_WARNING "Bad Packet\n"); + if(status&METH_RX_ST_CARRIER_EVT_SEEN) + printk(KERN_WARNING "Carrier Event Seen\n"); +#endif } - priv->regs->rx_fifo=priv->rx_ring_dmas[priv->rx_write]; - rxb->status.raw=0; - priv->rx_write=(priv->rx_write+1)&(RX_RING_ENTRIES-1); + priv->rx_ring[priv->rx_write]=(rx_packet*)skb->head; + priv->rx_ring[priv->rx_write]->status.raw=0; + priv->rx_ring_dmas[priv->rx_write]=dma_map_single(NULL,priv->rx_ring[priv->rx_write], + METH_RX_BUFF_SIZE,DMA_FROM_DEVICE); + mace_eth_write(priv->rx_ring_dmas[priv->rx_write], rx_fifo); + ADVANCE_RX_PTR(priv->rx_write); } + spin_lock(&priv->meth_lock); + /* In case there was underflow, and Rx DMA was disabled */ + priv->dma_ctrl|=METH_DMA_RX_INT_EN|METH_DMA_RX_EN; + mace_eth_write(priv->dma_ctrl, dma_ctrl); + mace_eth_write(METH_INT_RX_THRESHOLD, int_stat); + spin_unlock(&priv->meth_lock); } static int meth_tx_full(struct net_device *dev) @@ -463,29 +492,56 @@ return(priv->tx_count >= TX_RING_ENTRIES-1); } -void meth_tx_cleanup(struct net_device* dev, int rptr) +static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) { - meth_private *priv=dev->priv; - tx_packet* status; + struct meth_private *priv = dev->priv; + u64 status; struct sk_buff *skb; + unsigned long rptr=(int_status&TX_INFO_RPTR)>>16; spin_lock(&priv->meth_lock); - /* Stop DMA */ - priv->regs->dma_ctrl &= ~(METH_DMA_TX_INT_EN); + /* Stop DMA notification */ + priv->dma_ctrl &= ~(METH_DMA_TX_INT_EN); + mace_eth_write(priv->dma_ctrl, dma_ctrl); while(priv->tx_read != rptr){ skb = priv->tx_skbs[priv->tx_read]; - status = &priv->tx_ring[priv->tx_read]; - if(!status->header.res.sent) + status = priv->tx_ring[priv->tx_read].header.raw; +#if MFE_DEBUG>=1 + if(priv->tx_read==priv->tx_write) + DPRINTK("Auchi! tx_read=%d,tx_write=%d,rptr=%d?\n",priv->tx_read,priv->tx_write,rptr); +#endif + if(status & METH_TX_ST_DONE) { + if(status & METH_TX_ST_SUCCESS){ + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_errors++; +#if MFE_DEBUG>=1 + DPRINTK("TX error: status=%016lx <",status); + if(status & METH_TX_ST_SUCCESS) + printk(" SUCCESS"); + if(status & METH_TX_ST_TOOLONG) + printk(" TOOLONG"); + if(status & METH_TX_ST_UNDERRUN) + printk(" UNDERRUN"); + if(status & METH_TX_ST_EXCCOLL) + printk(" EXCCOLL"); + if(status & METH_TX_ST_DEFER) + printk(" DEFER"); + if(status & METH_TX_ST_LATECOLL) + printk(" LATECOLL"); + printk(" >\n"); +#endif + } + } else { + DPRINTK("RPTR points us here, but packet not done?\n"); break; - if(status->header.raw & METH_TX_STATUS_DONE) { - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; } dev_kfree_skb_irq(skb); priv->tx_skbs[priv->tx_read] = NULL; - status->header.raw = 0; + priv->tx_ring[priv->tx_read].header.raw = 0; priv->tx_read = (priv->tx_read+1)&(TX_RING_ENTRIES-1); priv->tx_count --; } @@ -495,94 +551,100 @@ netif_wake_queue(dev); } - spin_unlock(priv->meth_lock); + mace_eth_write(METH_INT_TX_EMPTY | METH_INT_TX_PKT, int_stat); + spin_unlock(&priv->meth_lock); +} + +static void meth_error(struct net_device* dev, u32 status) +{ + struct meth_private *priv = (struct meth_private *) dev->priv; + + printk(KERN_WARNING "meth: error status: 0x%08x\n",status); + /* check for errors too... */ + if (status & (METH_INT_TX_LINK_FAIL)) + printk(KERN_WARNING "meth: link failure\n"); + /* Should I do full reset in this case? */ + if (status & (METH_INT_MEM_ERROR)) + printk(KERN_WARNING "meth: memory error\n"); + if (status & (METH_INT_TX_ABORT)) + printk(KERN_WARNING "meth: aborted\n"); + if (status & (METH_INT_RX_OVERFLOW)) + printk(KERN_WARNING "meth: Rx overflow\n"); + if (status & (METH_INT_RX_UNDERFLOW)) { + printk(KERN_WARNING "meth: Rx underflow\n"); + spin_lock(&priv->meth_lock); + mace_eth_write(METH_INT_RX_UNDERFLOW, int_stat); + /* more underflow interrupts will be delivered, + effectively throwing us into an infinite loop. + Thus I stop processing Rx in this case. + */ + priv->dma_ctrl&=~METH_DMA_RX_EN; + mace_eth_write(priv->dma_ctrl, dma_ctrl); + DPRINTK("Disabled meth Rx DMA temporarily\n"); + spin_unlock(&priv->meth_lock); + } + mace_eth_write(METH_INT_ERROR, int_stat); } /* * The typical interrupt entry point */ -void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs) +static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs) { - struct meth_private *priv; - union { - u32 reg; /*Whole status register */ - struct { - u32 : 2, - rx_seq : 5, - tx_read : 9, - - rx_read : 8, - int_mask: 8; - } parsed; - } status; - /* - * As usual, check the "device" pointer for shared handlers. - * Then assign "struct device *dev" - */ struct net_device *dev = (struct net_device *)dev_id; - /* ... and check with hw if it's really ours */ - - if (!dev /*paranoid*/ ) return; - - /* Lock the device */ - priv = (struct meth_private *) dev->priv; + struct meth_private *priv = (struct meth_private *) dev->priv; + unsigned long status; - status.reg = priv->regs->int_flags; - - DPRINTK("Interrupt, status %08x...\n",status.reg); - if (status.parsed.int_mask & METH_INT_RX_THRESHOLD) { - /* send it to meth_rx for handling */ - meth_rx(dev); + status = mace_eth_read(int_stat); + while (status & 0xFF) { + /* First handle errors - if we get Rx underflow, + Rx DMA will be disabled, and Rx handler will reenable + it. I don't think it's possible to get Rx underflow, + without getting Rx interrupt */ + if (status & METH_INT_ERROR) { + meth_error(dev, status); + } + if (status & (METH_INT_TX_EMPTY | METH_INT_TX_PKT)) { + /* a transmission is over: free the skb */ + meth_tx_cleanup(dev, status); + } + if (status & METH_INT_RX_THRESHOLD) { + if (!(priv->dma_ctrl & METH_DMA_RX_INT_EN)) + break; + /* send it to meth_rx for handling */ + meth_rx(dev, status); + } + status = mace_eth_read(int_stat); } - if (status.parsed.int_mask & (METH_INT_TX_EMPTY|METH_INT_TX_PKT)) { - /* a transmission is over: free the skb */ - meth_tx_cleanup(dev, status.parsed.tx_read); - } - /* check for errors too... */ - if (status.parsed.int_mask & (METH_INT_TX_LINK_FAIL)) - printk(KERN_WARNING "meth: link failure\n"); - if (status.parsed.int_mask & (METH_INT_MEM_ERROR)) - printk(KERN_WARNING "meth: memory error\n"); - if (status.parsed.int_mask & (METH_INT_TX_ABORT)) - printk(KERN_WARNING "meth: aborted\n"); - DPRINTK("Interrupt handling done...\n"); - - priv->regs->int_flags=status.reg&0xff; /* clear interrupts */ + return IRQ_HANDLED; } /* * Transmits packets that fit into TX descriptor (are <=120B) */ -static void meth_tx_short_prepare(meth_private* priv, struct sk_buff* skb) +static void meth_tx_short_prepare(struct meth_private *priv, + struct sk_buff *skb) { tx_packet *desc=&priv->tx_ring[priv->tx_write]; int len = (skb->lenlen; - DPRINTK("preparing short packet\n"); + desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16); /* maybe I should set whole thing to 0 first... */ memcpy(desc->data.dt+(120-len),skb->data,skb->len); if(skb->len < len) memset(desc->data.dt+120-len+skb->len,0,len-skb->len); - desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16); - DPRINTK("desc=%016lx\n",desc->header.raw); } #define TX_CATBUF1 BIT(25) -static void meth_tx_1page_prepare(meth_private* priv, struct sk_buff* skb) +static void meth_tx_1page_prepare(struct meth_private *priv, + struct sk_buff *skb) { tx_packet *desc=&priv->tx_ring[priv->tx_write]; - void *buffer_data = (void *)(((u64)skb->data + 7ULL) & (~7ULL)); - int unaligned_len = (int)((u64)buffer_data - (u64)skb->data); + void *buffer_data = (void *)(((unsigned long)skb->data + 7) & ~7); + int unaligned_len = (int)((unsigned long)buffer_data - (unsigned long)skb->data); int buffer_len = skb->len - unaligned_len; dma_addr_t catbuf; - DPRINTK("preparing 1 page...\n"); - DPRINTK("length=%d data=%p\n", skb->len, skb->data); - DPRINTK("unaligned_len=%d\n", unaligned_len); - DPRINTK("buffer_data=%p buffer_len=%d\n", - buffer_data, - buffer_len); - desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|(skb->len-1); /* unaligned part */ @@ -593,37 +655,23 @@ } /* first page */ - catbuf = pci_map_single(NULL, - buffer_data, - buffer_len, - PCI_DMA_TODEVICE); - DPRINTK("catbuf=%x\n", catbuf); + catbuf = dma_map_single(NULL, buffer_data, buffer_len, + DMA_TO_DEVICE); desc->data.cat_buf[0].form.start_addr = catbuf >> 3; desc->data.cat_buf[0].form.len = buffer_len-1; - DPRINTK("desc=%016lx\n",desc->header.raw); - DPRINTK("cat_buf[0].raw=%016lx\n",desc->data.cat_buf[0].raw); } #define TX_CATBUF2 BIT(26) -static void meth_tx_2page_prepare(meth_private* priv, struct sk_buff* skb) +static void meth_tx_2page_prepare(struct meth_private *priv, + struct sk_buff *skb) { tx_packet *desc=&priv->tx_ring[priv->tx_write]; - void *buffer1_data = (void *)(((u64)skb->data + 7ULL) & (~7ULL)); - void *buffer2_data = (void *)PAGE_ALIGN((u64)skb->data); - int unaligned_len = (int)((u64)buffer1_data - (u64)skb->data); - int buffer1_len = (int)((u64)buffer2_data - (u64)buffer1_data); + void *buffer1_data = (void *)(((unsigned long)skb->data + 7) & ~7); + void *buffer2_data = (void *)PAGE_ALIGN((unsigned long)skb->data); + int unaligned_len = (int)((unsigned long)buffer1_data - (unsigned long)skb->data); + int buffer1_len = (int)((unsigned long)buffer2_data - (unsigned long)buffer1_data); int buffer2_len = skb->len - buffer1_len - unaligned_len; dma_addr_t catbuf1, catbuf2; - DPRINTK("preparing 2 pages... \n"); - DPRINTK("length=%d data=%p\n", skb->len, skb->data); - DPRINTK("unaligned_len=%d\n", unaligned_len); - DPRINTK("buffer1_data=%p buffer1_len=%d\n", - buffer1_data, - buffer1_len); - DPRINTK("buffer2_data=%p buffer2_len=%d\n", - buffer2_data, - buffer2_len); - desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|TX_CATBUF2|(skb->len-1); /* unaligned part */ if(unaligned_len){ @@ -633,70 +681,64 @@ } /* first page */ - catbuf1 = pci_map_single(NULL, - buffer1_data, - buffer1_len, - PCI_DMA_TODEVICE); - DPRINTK("catbuf1=%x\n", catbuf1); + catbuf1 = dma_map_single(NULL, buffer1_data, buffer1_len, + DMA_TO_DEVICE); desc->data.cat_buf[0].form.start_addr = catbuf1 >> 3; desc->data.cat_buf[0].form.len = buffer1_len-1; /* second page */ - catbuf2 = pci_map_single(NULL, - buffer2_data, - buffer2_len, - PCI_DMA_TODEVICE); - DPRINTK("catbuf2=%x\n", catbuf2); + catbuf2 = dma_map_single(NULL, buffer2_data, buffer2_len, + DMA_TO_DEVICE); desc->data.cat_buf[1].form.start_addr = catbuf2 >> 3; desc->data.cat_buf[1].form.len = buffer2_len-1; - DPRINTK("desc=%016lx\n",desc->header.raw); - DPRINTK("cat_buf[0].raw=%016lx\n",desc->data.cat_buf[0].raw); - DPRINTK("cat_buf[1].raw=%016lx\n",desc->data.cat_buf[1].raw); } - -void meth_add_to_tx_ring(meth_private *priv, struct sk_buff* skb) +static void meth_add_to_tx_ring(struct meth_private *priv, struct sk_buff *skb) { - DPRINTK("Transmitting data...\n"); + /* Remember the skb, so we can free it at interrupt time */ + priv->tx_skbs[priv->tx_write] = skb; if(skb->len <= 120) { /* Whole packet fits into descriptor */ meth_tx_short_prepare(priv,skb); - } else if(PAGE_ALIGN((u64)skb->data) != - PAGE_ALIGN((u64)skb->data+skb->len-1)) { + } else if(PAGE_ALIGN((unsigned long)skb->data) != + PAGE_ALIGN((unsigned long)skb->data+skb->len-1)) { /* Packet crosses page boundary */ meth_tx_2page_prepare(priv,skb); } else { /* Packet is in one page */ meth_tx_1page_prepare(priv,skb); } - - /* Remember the skb, so we can free it at interrupt time */ - priv->tx_skbs[priv->tx_write] = skb; priv->tx_write = (priv->tx_write+1) & (TX_RING_ENTRIES-1); - priv->regs->tx_info.wptr = priv->tx_write; + mace_eth_write(priv->tx_write, tx_info); priv->tx_count ++; - /* Enable DMA transfer */ - priv->regs->dma_ctrl |= METH_DMA_TX_INT_EN; } /* * Transmit a packet (called by the kernel) */ -int meth_tx(struct sk_buff *skb, struct net_device *dev) +static int meth_tx(struct sk_buff *skb, struct net_device *dev) { struct meth_private *priv = (struct meth_private *) dev->priv; + unsigned long flags; - spin_lock_irq(&priv->meth_lock); + spin_lock_irqsave(&priv->meth_lock,flags); + /* Stop DMA notification */ + priv->dma_ctrl &= ~(METH_DMA_TX_INT_EN); + mace_eth_write(priv->dma_ctrl, dma_ctrl); meth_add_to_tx_ring(priv, skb); dev->trans_start = jiffies; /* save the timestamp */ /* If TX ring is full, tell the upper layer to stop sending packets */ if (meth_tx_full(dev)) { - DPRINTK("TX full: stopping\n"); + printk(KERN_DEBUG "TX full: stopping\n"); netif_stop_queue(dev); } - spin_unlock_irq(&priv->meth_lock); + /* Restart DMA notification */ + priv->dma_ctrl |= METH_DMA_TX_INT_EN; + mace_eth_write(priv->dma_ctrl, dma_ctrl); + + spin_unlock_irqrestore(&priv->meth_lock,flags); return 0; } @@ -704,17 +746,17 @@ /* * Deal with a transmit timeout. */ - -void meth_tx_timeout (struct net_device *dev) +static void meth_tx_timeout(struct net_device *dev) { struct meth_private *priv = (struct meth_private *) dev->priv; - + unsigned long flags; + printk(KERN_WARNING "%s: transmit timed out\n", dev->name); /* Protect against concurrent rx interrupts */ - spin_lock_irq(&priv->meth_lock); + spin_lock_irqsave(&priv->meth_lock,flags); - /* Try to reset the adaptor. */ + /* Try to reset the interface. */ meth_reset(dev); priv->stats.tx_errors++; @@ -726,10 +768,11 @@ meth_init_rx_ring(priv); /* Restart dma */ - priv->regs->dma_ctrl|=METH_DMA_TX_EN|METH_DMA_RX_EN|METH_DMA_RX_INT_EN; + priv->dma_ctrl|=METH_DMA_TX_EN|METH_DMA_RX_EN|METH_DMA_RX_INT_EN; + mace_eth_write(priv->dma_ctrl, dma_ctrl); /* Enable interrupt */ - spin_unlock_irq(&priv->meth_lock); + spin_unlock_irqrestore(&priv->meth_lock,flags); dev->trans_start = jiffies; netif_wake_queue(dev); @@ -740,29 +783,28 @@ /* * Ioctl commands */ -int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - - DPRINTK("ioctl\n"); - return 0; + DPRINTK("ioctl\n"); + return 0; } /* * Return statistics to the caller */ -struct net_device_stats *meth_stats(struct net_device *dev) +static struct net_device_stats *meth_stats(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; - return &priv->stats; + struct meth_private *priv = (struct meth_private *) dev->priv; + return &priv->stats; } /* - * The init function (sometimes called probe). + * The init function. */ -static struct net_device *meth_init(struct net_device *dev) +static struct net_device *meth_init(void) { struct net_device *dev; - meth_private *priv; + struct meth_private *priv; int ret; dev = alloc_etherdev(sizeof(struct meth_private)); @@ -779,62 +821,26 @@ dev->tx_timeout = meth_tx_timeout; dev->watchdog_timeo = timeout; #endif - dev->irq = MACE_ETHERNET_IRQ; - SET_MODULE_OWNER(dev); + dev->irq = MACE_ETHERNET_IRQ; + dev->base_addr = (unsigned long)&mace->eth; - priv = dev->priv; + priv = (struct meth_private *) dev->priv; spin_lock_init(&priv->meth_lock); - /* - * Make the usual checks: check_region(), probe irq, ... -ENODEV - * should be returned if no device found. No resource should be - * grabbed: this is done on open(). - */ - priv->regs=(meth_regs*)SGI_MFE; - dev->base_addr=SGI_MFE; - priv->phy_addr = -1; /* No phy is known yet... */ - - /* Initialize the hardware */ - ret = meth_reset(dev); - if (ret < 0) - goto out; - - /* Allocate the ring buffers */ - ret = meth_init_tx_ring(priv); - if (ret < 0) - goto out; - - ret = meth_init_rx_ring(priv); - if (ret < 0) - goto out1; ret = register_netdev(dev); - if (ret) - goto out2; - - printk("SGI O2 Fast Ethernet rev. %ld\n", priv->regs->mac_ctrl >> 29); - - return ret; + if (ret) { + free_netdev(dev); + return ERR_PTR(ret); + } -out2: - meth_free_rx_ring(priv); -out1: - meth_free_tx_ring(priv); -out: - free_netdev(dev); - return ERR_PTR(ret); + printk(KERN_INFO "%s: SGI MACE Ethernet rev. %d\n", + dev->name, (unsigned int)mace_eth_read(mac_ctrl) >> 29); + return 0; } -/* - * The devices - */ - -struct net_device *meth_dev; - -/* - * Finally, the module stuff - */ +static struct net_device *meth_dev; -int meth_init_module(void) +static int __init meth_init_module(void) { meth_dev = meth_init(); if (IS_ERR(meth_dev)) @@ -842,14 +848,11 @@ return 0; } -void meth_cleanup(void) +static void __exit meth_exit_module(void) { - meth_private *priv = meth_dev->priv; unregister_netdev(meth_dev); - meth_free_rx_ring(priv); - meth_free_tx_ring(priv); free_netdev(meth_dev); } module_init(meth_init_module); -module_exit(meth_cleanup); +module_exit(meth_exit_module); diff -Nru a/drivers/net/meth.h b/drivers/net/meth.h --- a/drivers/net/meth.h Sun Apr 25 22:39:31 2004 +++ b/drivers/net/meth.h Sun Apr 25 22:39:31 2004 @@ -16,9 +16,6 @@ /* version dependencies have been confined to a separate file */ -#define SGI_MFE (MACE_BASE+MACE_ENET) -/* (0xBF280000)*/ - /* Tunable parameters */ #define TX_RING_ENTRIES 64 /* 64-512?*/ @@ -27,10 +24,12 @@ #define TX_RING_BUFFER_SIZE (TX_RING_ENTRIES*sizeof(tx_packet)) #define RX_BUFFER_SIZE 1546 /* ethenet packet size */ #define METH_RX_BUFF_SIZE 4096 +#define METH_RX_HEAD 34 /* status + 3 quad garbage-fill + 2 byte zero-pad */ #define RX_BUFFER_OFFSET (sizeof(rx_status_vector)+2) /* staus vector + 2 bytes of padding */ #define RX_BUCKET_SIZE 256 - +#undef BIT +#define BIT(x) (1 << (x)) /* For more detailed explanations of what each field menas, see Nick's great comments to #defines below (or docs, if @@ -85,7 +84,7 @@ } tx_packet; typedef union rx_status_vector { - struct { + volatile struct { u64 pad1:1;/*fill it with ones*/ u64 pad2:15;/*fill with 0*/ u64 ip_chk_sum:16; @@ -103,7 +102,7 @@ u64 rx_code_violation:1; u64 rx_len:16; } parsed; - u64 raw; + volatile u64 raw; } rx_status_vector; typedef struct rx_packet { @@ -113,50 +112,8 @@ char buf[METH_RX_BUFF_SIZE-sizeof(rx_status_vector)-3*sizeof(u64)-sizeof(u16)];/* data */ } rx_packet; -typedef struct meth_regs { - u64 mac_ctrl; /*0x00,rw,31:0*/ - u64 int_flags; /*0x08,rw,30:0*/ - u64 dma_ctrl; /*0x10,rw,15:0*/ - u64 timer; /*0x18,rw,5:0*/ - u64 int_tx; /*0x20,wo,0:0*/ - u64 int_rx; /*0x28,wo,9:4*/ - struct { - u32 tx_info_pad; - u32 rptr:16,wptr:16; - } tx_info; /*0x30,rw,31:0*/ - u64 tx_info_al; /*0x38,rw,31:0*/ - struct { - u32 rx_buff_pad1; - u32 rx_buff_pad2:8, - wptr:8, - rptr:8, - depth:8; - } rx_buff; /*0x40,ro,23:0*/ - u64 rx_buff_al1; /*0x48,ro,23:0*/ - u64 rx_buff_al2; /*0x50,ro,23:0*/ - u64 int_update; /*0x58,wo,31:0*/ - u32 phy_data_pad; - u32 phy_data; /*0x60,rw,16:0*/ - u32 phy_reg_pad; - u32 phy_registers; /*0x68,rw,9:0*/ - u64 phy_trans_go; /*0x70,wo,0:0*/ - u64 backoff_seed; /*0x78,wo,10:0*/ - u64 imq_reserved[4];/*0x80,ro,64:0(x4)*/ - /*===================================*/ - u64 mac_addr; /*0xA0,rw,47:0, I think it's MAC address, but I'm not sure*/ - u64 mcast_addr; /*0xA8,rw,47:0, This seems like secondary MAC address*/ - u64 mcast_filter; /*0xB0,rw,63:0*/ - u64 tx_ring_base; /*0xB8,rw,31:13*/ - /* Following are read-only debugging info register */ - u64 tx_pkt1_hdr; /*0xC0,ro,63:0*/ - u64 tx_pkt1_ptr[3]; /*0xC8,ro,63:0(x3)*/ - u64 tx_pkt2_hdr; /*0xE0,ro,63:0*/ - u64 tx_pkt2_ptr[3]; /*0xE8,ro,63:0(x3)*/ - /*===================================*/ - u32 rx_pad; - u32 rx_fifo; - u64 reserved[31]; -}meth_regs; +#define TX_INFO_RPTR 0x00FF0000 +#define TX_INFO_WPTR 0x000000FF /* Bits in METH_MAC */ @@ -203,9 +160,14 @@ #define METH_DMA_RX_EN BIT(15) /* Enable RX */ #define METH_DMA_RX_INT_EN BIT(9) /* Enable interrupt on RX packet */ +/* RX FIFO MCL Info bits */ +#define METH_RX_FIFO_WPTR(x) (((x)>>16)&0xf) +#define METH_RX_FIFO_RPTR(x) (((x)>>8)&0xf) +#define METH_RX_FIFO_DEPTH(x) ((x)&0x1f) /* RX status bits */ +#define METH_RX_ST_VALID BIT(63) #define METH_RX_ST_RCV_CODE_VIOLATION BIT(16) #define METH_RX_ST_DRBL_NBL BIT(17) #define METH_RX_ST_CRC_ERR BIT(18) @@ -240,25 +202,34 @@ #define METH_INT_RX_UNDERFLOW BIT(6) /* 0: No interrupt pending, 1: FIFO was empty, packet could not be queued */ #define METH_INT_RX_OVERFLOW BIT(7) /* 0: No interrupt pending, 1: DMA FIFO Overflow, DMA stopped, FATAL */ -#define METH_INT_RX_RPTR_MASK 0x0001F00 /* Bits 8 through 12 alias of RX read-pointer */ +/*#define METH_INT_RX_RPTR_MASK 0x0001F00*/ /* Bits 8 through 12 alias of RX read-pointer */ +#define METH_INT_RX_RPTR_MASK 0x0000F00 /* Bits 8 through 11 alias of RX read-pointer - so, is Rx FIFO 16 or 32 entry?*/ /* Bits 13 through 15 are always 0. */ -#define METH_INT_TX_RPTR_MASK 0x1FF0000 /* Bits 16 through 24 alias of TX read-pointer */ +#define METH_INT_TX_RPTR_MASK 0x1FF0000 /* Bits 16 through 24 alias of TX read-pointer */ + +#define METH_INT_RX_SEQ_MASK 0x2E000000 /* Bits 25 through 29 are the starting seq number for the message at the */ -#define METH_INT_SEQ_MASK 0x2E000000 /* Bits 25 through 29 are the starting seq number for the message at the */ /* top of the queue */ -#define METH_ERRORS ( \ - METH_INT_RX_OVERFLOW| \ - METH_INT_RX_UNDERFLOW| \ - METH_INT_MEM_ERROR| \ - METH_INT_TX_ABORT) +#define METH_INT_ERROR (METH_INT_TX_LINK_FAIL| \ + METH_INT_MEM_ERROR| \ + METH_INT_TX_ABORT| \ + METH_INT_RX_OVERFLOW| \ + METH_INT_RX_UNDERFLOW) #define METH_INT_MCAST_HASH BIT(30) /* If RX DMA is enabled the hash select logic output is latched here */ /* TX status bits */ -#define METH_TX_STATUS_DONE BIT(23) /* Packet was transmitted successfully */ +#define METH_TX_ST_DONE BIT(63) /* TX complete */ +#define METH_TX_ST_SUCCESS BIT(23) /* Packet was transmitted successfully */ +#define METH_TX_ST_TOOLONG BIT(24) /* TX abort due to excessive length */ +#define METH_TX_ST_UNDERRUN BIT(25) /* TX abort due to underrun (?) */ +#define METH_TX_ST_EXCCOLL BIT(26) /* TX abort due to excess collisions */ +#define METH_TX_ST_DEFER BIT(27) /* TX abort due to excess deferals */ +#define METH_TX_ST_LATECOLL BIT(28) /* TX abort due to late collision */ + /* Tx command header bits */ #define METH_TX_CMD_INT_EN BIT(24) /* Generate TX interrupt when packet is sent */ @@ -271,3 +242,5 @@ #define PHY_ICS1889 0x0015F41 /* ICS FX */ #define PHY_ICS1890 0x0015F42 /* ICS TX */ #define PHY_DP83840 0x20005C0 /* National TX */ + +#define ADVANCE_RX_PTR(x) x=(x+1)&(RX_RING_ENTRIES-1) diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c --- a/drivers/net/pcmcia/3c574_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/3c574_cs.c Sun Apr 25 22:39:31 2004 @@ -384,6 +384,8 @@ #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) +static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + static void tc574_config(dev_link_t *link) { client_handle_t handle = link->handle; @@ -396,6 +398,7 @@ ioaddr_t ioaddr; u16 *phys_addr; char *cardname; + union wn3_config config; phys_addr = (u16 *)dev->dev_addr; @@ -431,15 +434,7 @@ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (register_netdev(dev) != 0) { - printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); - goto failed; - } - ioaddr = dev->base_addr; - strcpy(lp->node.dev_name, dev->name); - link->dev = &lp->node; - link->state &= ~DEV_CONFIG_PENDING; /* The 3c574 normally uses an EEPROM for configuration info, including the hardware address. The future products may include a modem chip @@ -467,24 +462,14 @@ } else cardname = "3Com 3c574"; - printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ", - dev->name, cardname, dev->base_addr, dev->irq); - - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n")); - { - u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - union wn3_config config; + u_char mcr; outw(2<<11, ioaddr + RunnerRdCtrl); mcr = inb(ioaddr + 2); outw(0<<11, ioaddr + RunnerRdCtrl); printk(KERN_INFO " ASIC rev %d,", mcr>>3); EL3WINDOW(3); config.i = inl(ioaddr + Wn3_Config); - printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", - 8 << config.u.ram_size, ram_split[config.u.ram_split], - config.u.autoselect ? "autoselect " : ""); lp->default_media = config.u.xcvr; lp->autoselect = config.u.autoselect; } @@ -530,6 +515,25 @@ mdio_write(ioaddr, lp->phys, 4, lp->advertising); } } + + link->state &= ~DEV_CONFIG_PENDING; + link->dev = &lp->node; + + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); + link->dev = NULL; + goto failed; + } + + strcpy(lp->node.dev_name, dev->name); + + printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ", + dev->name, cardname, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n")); + printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", + 8 << config.u.ram_size, ram_split[config.u.ram_split], + config.u.autoselect ? "autoselect " : ""); return; diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c --- a/drivers/net/pcmcia/3c589_cs.c Sun Apr 25 22:39:32 2004 +++ b/drivers/net/pcmcia/3c589_cs.c Sun Apr 25 22:39:32 2004 @@ -308,7 +308,7 @@ tuple_t tuple; cisparse_t parse; u16 buf[32], *phys_addr; - int last_fn, last_ret, i, j, multi = 0; + int last_fn, last_ret, i, j, multi = 0, fifo; ioaddr_t ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; @@ -357,11 +357,6 @@ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (register_netdev(dev) != 0) { - printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); - goto failed; - } - ioaddr = dev->base_addr; EL3WINDOW(0); @@ -382,13 +377,10 @@ } } - strcpy(lp->node.dev_name, dev->name); - link->dev = &lp->node; - link->state &= ~DEV_CONFIG_PENDING; - /* The address and resource configuration register aren't loaded from the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ outw(0x3f00, ioaddr + 8); + fifo = inl(ioaddr); /* The if_port symbol can be set when the module is loaded */ if ((if_port >= 0) && (if_port <= 3)) @@ -396,14 +388,24 @@ else printk(KERN_ERR "3c589_cs: invalid if_port requested\n"); + link->dev = &lp->node; + link->state &= ~DEV_CONFIG_PENDING; + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); + link->dev = NULL; + goto failed; + } + + strcpy(lp->node.dev_name, dev->name); + printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ", dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - i = inl(ioaddr); printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", - (i & 7) ? 32 : 8, ram_split[(i >> 16) & 3], + (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); return; diff -Nru a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c --- a/drivers/net/pcmcia/axnet_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/axnet_cs.c Sun Apr 25 22:39:31 2004 @@ -430,19 +430,11 @@ ei_status.block_input = &block_input; ei_status.block_output = &block_output; - strcpy(info->node.dev_name, dev->name); - if (inb(dev->base_addr + AXNET_TEST) != 0) info->flags |= IS_AX88790; else info->flags |= IS_AX88190; - printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ", - dev->name, ((info->flags & IS_AX88790) ? 7 : 1), - dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - if (info->flags & IS_AX88790) outb(0x10, dev->base_addr + AXNET_GPIO); /* select Internal PHY */ @@ -463,19 +455,27 @@ } info->phy_id = (i < 32) ? i : -1; - if (i < 32) { - DEBUG(0, " MII transceiver at index %d, status %x.\n", i, j); - } else { - printk(KERN_NOTICE " No MII transceivers found!\n"); - } + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); + link->dev = NULL; goto failed; } - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; + strcpy(info->node.dev_name, dev->name); + + printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ", + dev->name, ((info->flags & IS_AX88790) ? 7 : 1), + dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + if (info->phy_id != -1) { + DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j); + } else { + printk(KERN_NOTICE " No MII transceivers found!\n"); + } return; cs_failed: diff -Nru a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c --- a/drivers/net/pcmcia/com20020_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/com20020_cs.c Sun Apr 25 22:39:31 2004 @@ -141,7 +141,6 @@ typedef struct com20020_dev_t { struct net_device *dev; - int dev_configured; dev_node_t node; } com20020_dev_t; @@ -277,13 +276,10 @@ dev = info->dev; if (dev) { - if (info->dev_configured) + if (link->dev) { DEBUG(1,"unregister...\n"); - if (netif_running(dev)) - dev->stop(dev); - unregister_netdev(dev); /* @@ -398,17 +394,18 @@ lp->card_name = "PCMCIA COM20020"; lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + i = com20020_found(dev, 0); /* calls register_netdev */ if (i != 0) { DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n"); + link->dev = NULL; goto failed; } - info->dev_configured = 1; strcpy(info->node.dev_name, dev->name); - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n", dev->name, dev->base_addr, dev->irq); diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c --- a/drivers/net/pcmcia/fmvj18x_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/fmvj18x_cs.c Sun Apr 25 22:39:31 2004 @@ -510,10 +510,6 @@ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (register_netdev(dev) != 0) { - printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); - goto failed; - } if (link->io.BasePort2 != 0) fmvj18x_setup_mfc(link); @@ -575,7 +571,6 @@ /* Read MACID from Buggy CIS */ if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) { printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n"); - unregister_netdev(dev); goto failed; } for (i = 0 ; i < 6; i++) { @@ -592,10 +587,18 @@ break; } - strcpy(lp->node.dev_name, dev->name); + lp->cardtype = cardtype; link->dev = &lp->node; + link->state &= ~DEV_CONFIG_PENDING; + + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); + link->dev = NULL; + goto failed; + } + + strcpy(lp->node.dev_name, dev->name); - lp->cardtype = cardtype; /* print current configuration */ printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", @@ -603,7 +606,6 @@ for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/ibmtr_cs.c Sun Apr 25 22:39:31 2004 @@ -317,13 +317,10 @@ /* Try PRIMARY card at 0xA20-0xA23 */ link->io.BasePort1 = 0xA20; i = pcmcia_request_io(link->handle, &link->io); - if (i == CS_SUCCESS) { - memcpy(info->node.dev_name, "tr0\0", 4); - } else { + if (i != CS_SUCCESS) { /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ link->io.BasePort1 = 0xA24; CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); - memcpy(info->node.dev_name, "tr1\0", 4); } dev->base_addr = link->io.BasePort1; @@ -367,15 +364,17 @@ Adapters Technical Reference" SC30-3585 for this info. */ ibmtr_hw_setup(dev, mmiobase); + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + i = ibmtr_probe_card(dev); - if (i != 0) { printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); + link->dev = NULL; goto failed; } - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; + strcpy(info->node.dev_name, dev->name); printk(KERN_INFO "%s: port %#3lx, irq %d,", dev->name, dev->base_addr, dev->irq); diff -Nru a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c --- a/drivers/net/pcmcia/nmclan_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/nmclan_cs.c Sun Apr 25 22:39:31 2004 @@ -734,11 +734,6 @@ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - i = register_netdev(dev); - if (i != 0) { - printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); - goto failed; - } ioaddr = dev->base_addr; @@ -777,9 +772,17 @@ else printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n"); - strcpy(lp->node.dev_name, dev->name); link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + + i = register_netdev(dev); + if (i != 0) { + printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); + link->dev = NULL; + goto failed; + } + + strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ", dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c --- a/drivers/net/pcmcia/smc91c92_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/smc91c92_cs.c Sun Apr 25 22:39:31 2004 @@ -901,6 +901,7 @@ char *name; int i, j, rev; ioaddr_t ioaddr; + u_long mir; DEBUG(0, "smc91c92_config(0x%p)\n", link); @@ -952,11 +953,6 @@ else printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n"); - if (register_netdev(dev) != 0) { - printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); - goto config_undo; - } - switch (smc->manfid) { case MANFID_OSITECH: case MANFID_PSION: @@ -977,8 +973,6 @@ goto config_undo; } - strcpy(smc->node.dev_name, dev->name); - link->dev = &smc->node; smc->duplex = 0; smc->rx_ovrn = 0; @@ -993,25 +987,16 @@ case 8: name = "100-FD"; break; case 9: name = "110"; break; } - printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " - "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr, - dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); ioaddr = dev->base_addr; if (rev > 0) { - u_long mir, mcr; + u_long mcr; SMC_SELECT_BANK(0); mir = inw(ioaddr + MEMINFO) & 0xff; if (mir == 0xff) mir++; /* Get scale factor for memory size */ mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200; mir *= 128 * (1<<((mcr >> 9) & 7)); - if (mir & 0x3ff) - printk(KERN_INFO " %lu byte", mir); - else - printk(KERN_INFO " %lu kb", mir>>10); SMC_SELECT_BANK(1); smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC; @@ -1019,9 +1004,8 @@ smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0; if ((rev >> 4) >= 7) smc->cfg |= CFG_MII_SELECT; - printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ? - "MII" : if_names[dev->if_port]); - } + } else + mir = 0; if (smc->cfg & CFG_MII_SELECT) { SMC_SELECT_BANK(3); @@ -1031,16 +1015,45 @@ if ((j != 0) && (j != 0xffff)) break; } smc->mii_if.phy_id = (i < 32) ? i : -1; - if (i < 32) { - DEBUG(0, " MII transceiver at index %d, status %x.\n", i, j); - } else { - printk(KERN_NOTICE " No MII transceivers found!\n"); - } SMC_SELECT_BANK(0); } + link->dev = &smc->node; link->state &= ~DEV_CONFIG_PENDING; + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); + link->dev = NULL; + goto config_undo; + } + + strcpy(smc->node.dev_name, dev->name); + + printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " + "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr, + dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + + if (rev > 0) { + if (mir & 0x3ff) + printk(KERN_INFO " %lu byte", mir); + else + printk(KERN_INFO " %lu kb", mir>>10); + printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ? + "MII" : if_names[dev->if_port]); + } + + if (smc->cfg & CFG_MII_SELECT) { + if (smc->mii_if.phy_id != -1) { + DEBUG(0, " MII transceiver at index %d, status %x.\n", + smc->mii_if.phy_id, j); + } else { + printk(KERN_NOTICE " No MII transceivers found!\n"); + } + } + return; config_undo: diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Sun Apr 25 22:39:31 2004 @@ -1114,17 +1114,20 @@ /* we can now register the device with the net subsystem */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; + + if (local->dingo) + do_reset(dev, 1); /* a kludge to make the cem56 work */ + + link->dev = &local->node; + link->state &= ~DEV_CONFIG_PENDING; + if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); + link->dev = NULL; goto config_error; } strcpy(local->node.dev_name, dev->name); - link->dev = &local->node; - link->state &= ~DEV_CONFIG_PENDING; - - if (local->dingo) - do_reset(dev, 1); /* a kludge to make the cem56 work */ /* give some infos about the hardware */ printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr", diff -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c --- a/drivers/net/sb1250-mac.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/sb1250-mac.c Sun Apr 25 22:39:31 2004 @@ -113,7 +113,6 @@ #include #include #include -#include /********************************************************************** @@ -147,8 +146,8 @@ #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) -#define SBMAC_READCSR(t) in64((unsigned long)t) -#define SBMAC_WRITECSR(t,v) out64(v, (unsigned long)t) +#define SBMAC_READCSR(t) __raw_readq((unsigned long)t) +#define SBMAC_WRITECSR(t,v) __raw_writeq(v, (unsigned long)t) #define SBMAC_MAX_TXDESCR 32 @@ -468,14 +467,17 @@ { int cnt; uint64_t bits; + int mac_mdio_genc; + + mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - SBMAC_WRITECSR(s->sbm_mdio,bits); + SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); for (cnt = 0; cnt < 32; cnt++) { - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC); - SBMAC_WRITECSR(s->sbm_mdio,bits); + SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); + SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); } } @@ -496,9 +498,12 @@ int i; uint64_t bits; unsigned int curmask; + int mac_mdio_genc; + + mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT; - SBMAC_WRITECSR(s->sbm_mdio,bits); + SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); curmask = 1 << (bitcnt - 1); @@ -506,9 +511,9 @@ if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; - SBMAC_WRITECSR(s->sbm_mdio,bits); - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC); - SBMAC_WRITECSR(s->sbm_mdio,bits); + SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); + SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); curmask >>= 1; } } @@ -534,7 +539,8 @@ int idx; int error; int regval; - + int mac_mdio_genc; + /* * Synchronize ourselves so that the PHY knows the next * thing coming down is a command @@ -555,17 +561,20 @@ sbmac_mii_senddata(s,phyaddr, 5); sbmac_mii_senddata(s,regidx, 5); + mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + /* * Switch the port around without a clock transition. */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); /* * Send out a clock pulse to signal we want the status */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + SBMAC_WRITECSR(s->sbm_mdio, + M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); /* * If an error occurred, the PHY will signal '1' back @@ -576,8 +585,9 @@ * Issue an 'idle' clock pulse, but keep the direction * the same. */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + SBMAC_WRITECSR(s->sbm_mdio, + M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); regval = 0; @@ -589,12 +599,14 @@ regval |= 1; } - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + SBMAC_WRITECSR(s->sbm_mdio, + M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc); + SBMAC_WRITECSR(s->sbm_mdio, + M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); } /* Switch back to output */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); if (error == 0) return regval; @@ -620,7 +632,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, unsigned int regval) { - + int mac_mdio_genc; + sbmac_mii_sync(s); sbmac_mii_senddata(s,MII_COMMAND_START,2); @@ -629,8 +642,10 @@ sbmac_mii_senddata(s,regidx, 5); sbmac_mii_senddata(s,MII_COMMAND_ACK,2); sbmac_mii_senddata(s,regval,16); - - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT); + + mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); } @@ -672,47 +687,47 @@ s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; #endif - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0); - SBMAC_WRITECSR(KSEG1ADDR( + SBMAC_WRITECSR(IOADDR( A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0); /* @@ -1212,25 +1227,21 @@ /* * Buffer has been replaced on the * receive ring. Pass the buffer to - * the kernel */ + * the kernel + */ sc->sbm_stats.rx_bytes += len; sc->sbm_stats.rx_packets++; sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev); + /* Check hw IPv4/TCP checksum if supported */ if (sc->rx_hw_checksum == ENABLE) { - /* if the ip checksum is good - indicate in skb. else set - CHECKSUM_NONE as device - failed to checksum the - packet */ - - if (((dsc->dscr_b) |M_DMA_ETHRX_BADTCPCS) || - ((dsc->dscr_a)| M_DMA_ETHRX_BADIP4CS)) { - sb->ip_summed = CHECKSUM_NONE; - } else { - printk(KERN_DEBUG "hw checksum fail .\n"); + if (!((dsc->dscr_a) & M_DMA_ETHRX_BADIP4CS) && + !((dsc->dscr_a) & M_DMA_ETHRX_BADTCPCS)) { sb->ip_summed = CHECKSUM_UNNECESSARY; + /* don't need to set sb->csum */ + } else { + sb->ip_summed = CHECKSUM_NONE; } - } /* rx_hw_checksum */ + } netif_rx(sb); } @@ -1295,35 +1306,9 @@ */ curidx = d->sbdma_remptr - d->sbdma_dscrtable; - { - /* XXX This is gross, ugly, and only here - * because justin hacked it in to fix a - * problem without really understanding it. - * - * It seems that, for whatever reason, this - * routine is invoked immediately upon the - * enabling of interrupts. So then the Read - * below returns zero, making hwidx a negative - * number, and anti-hilarity ensues. - * - * I'm guessing there's a proper fix involving - * clearing out interrupt state from old - * packets before enabling interrupts, but I'm - * not sure. - * - * Anyways, this hack seems to work, and is - * Good Enough for 11 PM. :) - * - * -Justin - */ + hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); - uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr); - if (!tmp) { - break; - } - hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) - - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); - } /* * If they're the same, that means we've processed all * of the descriptors up to (but not including) the one that @@ -2378,7 +2363,7 @@ /* Determine controller base address */ - sc->sbm_base = KSEG1ADDR(dev->base_addr); + sc->sbm_base = IOADDR(dev->base_addr); sc->sbm_dev = dev; sc->sbe_idx = idx; @@ -2414,17 +2399,6 @@ sbmac_initctx(sc); - - /* - * Display Ethernet address (this is called during the config - * process so we need to finish off the config message that - * was being displayed) - */ - printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n", - dev->name, dev->base_addr, - eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); - /* * Set up Linux device callins */ @@ -2447,7 +2421,24 @@ err = register_netdev(dev); if (err) - sbmac_uninitctx(sc); + goto out_uninit; + + /* + * Display Ethernet address (this is called during the config + * process so we need to finish off the config message that + * was being displayed) + */ + printk(KERN_INFO + "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, dev->base_addr, + eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); + + + return 0; + +out_uninit: + sbmac_uninitctx(sc); + return err; } @@ -2461,12 +2452,15 @@ } /* - * map/route interrupt + * map/route interrupt (clear status first, in case something + * weird is pending; we haven't initialized the mac registers + * yet) */ - + + SBMAC_READCSR(sc->sbm_isr); if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) return -EBUSY; - + /* * Configure default speed */ @@ -2803,8 +2797,8 @@ port = A_MAC_CHANNEL_BASE(chan); sbmac_parse_hwaddr(addr,eaddr); val = sbmac_addr2reg(eaddr); - SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR),val); - val = SBMAC_READCSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR)); + SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),val); + val = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); } #endif @@ -2869,7 +2863,7 @@ * If we find a zero, skip this MAC. */ - sbmac_orig_hwaddr[idx] = SBMAC_READCSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR)); + sbmac_orig_hwaddr[idx] = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); if (sbmac_orig_hwaddr[idx] == 0) { printk(KERN_DEBUG "sbmac: not configuring MAC at " "%lx\n", port); @@ -2905,17 +2899,19 @@ static void __exit sbmac_cleanup_module(void) { - int idx; struct net_device *dev; sbmac_port_t port; + int idx; + for (idx = 0; idx < MAX_UNITS; idx++) { dev = dev_sbmac[idx]; - if (!dev) { - struct sbmac_softc *sc = netdev_priv(dev); - unregister_netdev(dev); - sbmac_uninitctx(sc); - free_netdev(dev); - } + if (!dev) + continue; + + struct sbmac_softc *sc = netdev_priv(dev); + unregister_netdev(dev); + sbmac_uninitctx(sc); + free_netdev(dev); } } diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c --- a/drivers/net/sgiseeq.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/sgiseeq.c Sun Apr 25 22:39:31 2004 @@ -5,17 +5,17 @@ */ #include #include +#include #include #include #include #include +#include #include #include #include -#include #include #include -#include #include #include #include @@ -32,19 +32,18 @@ #include "sgiseeq.h" -static char *version = - "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n"; +static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n"; static char *sgiseeqstr = "SGI Seeq8003"; -/* If you want speed, you do something silly, it always has worked - * for me. So, with that in mind, I've decided to make this driver - * look completely like a stupid Lance from a driver architecture - * perspective. Only difference is that here our "ring buffer" looks - * and acts like a real Lance one does but is layed out like how the - * HPC DMA and the Seeq want it to. You'd be surprised how a stupid - * idea like this can pay off in performance, not to mention making - * this driver 2,000 times easier to write. ;-) +/* + * If you want speed, you do something silly, it always has worked for me. So, + * with that in mind, I've decided to make this driver look completely like a + * stupid Lance from a driver architecture perspective. Only difference is that + * here our "ring buffer" looks and acts like a real Lance one does but is + * layed out like how the HPC DMA and the Seeq want it to. You'd be surprised + * how a stupid idea like this can pay off in performance, not to mention + * making this driver 2,000 times easier to write. ;-) */ /* Tune these if we tend to run out often etc. */ @@ -74,9 +73,10 @@ signed int buf_vaddr; }; -/* Warning: This structure is layed out in a certain way because - * HPC dma descriptors must be 8-byte aligned. So don't - * touch this without some care. +/* + * Warning: This structure is layed out in a certain way because HPC dma + * descriptors must be 8-byte aligned. So don't touch this without + * some care. */ struct sgiseeq_init_block { /* Note the name ;-) */ /* Ptrs to the descriptors in KSEG1 uncached space. */ @@ -105,6 +105,7 @@ struct net_device_stats stats; struct net_device *next_module; + spinlock_t tx_lock; }; /* A list of all installed seeq devices, for removing the driver module. */ @@ -112,7 +113,7 @@ static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs) { - hregs->rx_reset = (HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ); + hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ; udelay(20); hregs->rx_reset = 0; } @@ -169,16 +170,16 @@ /* Setup tx ring. */ for(i = 0; i < SEEQ_TX_BUFFERS; i++) { - if(!ib->tx_desc[i].tdma.pbuf) { + if (!ib->tx_desc[i].tdma.pbuf) { unsigned long buffer; buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); if (!buffer) return -ENOMEM; ib->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer); - ib->tx_desc[i].tdma.pbuf = PHYSADDR(buffer); + ib->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer); } - ib->tx_desc[i].tdma.cntinfo = (TCNTINFO_INIT); + ib->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT; } /* And now the rx ring. */ @@ -190,11 +191,11 @@ if (!buffer) return -ENOMEM; ib->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer); - ib->rx_desc[i].rdma.pbuf = PHYSADDR(buffer); + ib->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer); } - ib->rx_desc[i].rdma.cntinfo = (RCNTINFO_INIT); + ib->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT; } - ib->rx_desc[i - 1].rdma.cntinfo |= (HPCDMA_EOR); + ib->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR; return 0; } @@ -210,7 +211,7 @@ struct hpc3_ethregs *hregs = gpriv->hregs; int i; - if(once) + if (once) return; once++; printk("RING DUMP:\n"); @@ -258,17 +259,17 @@ /* Setup to field the proper interrupt types. */ if (sp->is_edlc) { - sregs->tstat = (TSTAT_INIT_EDLC); + sregs->tstat = TSTAT_INIT_EDLC; sregs->rw.wregs.control = sp->control; sregs->rw.wregs.frame_gap = 0; } else { - sregs->tstat = (TSTAT_INIT_SEEQ); + sregs->tstat = TSTAT_INIT_SEEQ; } hregs->rx_dconfig |= RDMACFG_INIT; - hregs->rx_ndptr = PHYSADDR(&sp->srings.rx_desc[0]); - hregs->tx_ndptr = PHYSADDR(&sp->srings.tx_desc[0]); + hregs->rx_ndptr = CPHYSADDR(sp->srings.rx_desc); + hregs->tx_ndptr = CPHYSADDR(sp->srings.tx_desc); seeq_go(sp, hregs, sregs); return 0; @@ -293,7 +294,7 @@ struct sgiseeq_regs *sregs) { if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) { - hregs->rx_ndptr = PHYSADDR(&sp->srings.rx_desc[sp->rx_new]); + hregs->rx_ndptr = CPHYSADDR(sp->srings.rx_desc + sp->rx_new); seeq_go(sp, hregs, sregs); } } @@ -315,7 +316,7 @@ /* Service every received packet. */ for_each_rx(rd, sp) { - len = (PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3); + len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3; pkt_pointer = (unsigned char *)(long)rd->buf_vaddr; pkt_status = pkt_pointer[len + 2]; @@ -345,7 +346,7 @@ } /* Return the entry to the ring pool. */ - rd->rdma.cntinfo = (RCNTINFO_INIT); + rd->rdma.cntinfo = RCNTINFO_INIT; sp->rx_new = NEXT_RX(sp->rx_new); } sp->srings.rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR); @@ -375,7 +376,7 @@ (HPCDMA_XIU | HPCDMA_ETXD)) td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext); if (td->tdma.cntinfo & HPCDMA_XIU) { - hregs->tx_ndptr = PHYSADDR(td); + hregs->tx_ndptr = CPHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } } @@ -407,8 +408,8 @@ if (!(td->tdma.cntinfo & (HPCDMA_XIU))) break; if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) { - if(!(status & HPC3_ETXCTRL_ACTIVE)) { - hregs->tx_ndptr = PHYSADDR(td); + if (!(status & HPC3_ETXCTRL_ACTIVE)) { + hregs->tx_ndptr = CPHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } break; @@ -427,6 +428,8 @@ struct hpc3_ethregs *hregs = sp->hregs; struct sgiseeq_regs *sregs = sp->sregs; + spin_lock(&sp->tx_lock); + /* Ack the IRQ and set software state. */ hregs->rx_reset = HPC3_ERXRST_CLRIRQ; @@ -440,6 +443,8 @@ if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) { netif_wake_queue(dev); } + spin_unlock(&sp->tx_lock); + return IRQ_HANDLED; } @@ -500,7 +505,7 @@ struct sgiseeq_tx_desc *td; int skblen, len, entry; - local_irq_save(flags); + spin_lock_irqsave(&sp->tx_lock, flags); /* Setup... */ skblen = skb->len; @@ -526,12 +531,12 @@ if (len != skblen) memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen); td->tdma.cntinfo = (len & HPCDMA_BCNT) | - (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX); + HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX; if (sp->tx_old != sp->tx_new) { struct sgiseeq_tx_desc *backend; backend = &sp->srings.tx_desc[PREV_TX(sp->tx_new)]; - backend->tdma.cntinfo &= ~(HPCDMA_EOX); + backend->tdma.cntinfo &= ~HPCDMA_EOX; } sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */ @@ -544,7 +549,7 @@ if (!TX_BUFFS_AVAIL(sp)) netif_stop_queue(dev); - local_irq_restore(flags); + spin_unlock_irqrestore(&sp->tx_lock, flags); return 0; } @@ -574,11 +579,11 @@ int i = 0; while (i < (nbufs - 1)) { - buf[i].tdma.pnext = PHYSADDR(&buf[i + 1]); + buf[i].tdma.pnext = CPHYSADDR(buf + i + 1); buf[i].tdma.pbuf = 0; i++; } - buf[i].tdma.pnext = PHYSADDR(&buf[0]); + buf[i].tdma.pnext = CPHYSADDR(buf); } static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) @@ -586,12 +591,12 @@ int i = 0; while (i < (nbufs - 1)) { - buf[i].rdma.pnext = PHYSADDR(&buf[i + 1]); + buf[i].rdma.pnext = CPHYSADDR(buf + i + 1); buf[i].rdma.pbuf = 0; i++; } buf[i].rdma.pbuf = 0; - buf[i].rdma.pnext = PHYSADDR(&buf[0]); + buf[i].rdma.pnext = CPHYSADDR(buf); } #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) @@ -600,45 +605,36 @@ { struct net_device *dev; struct sgiseeq_private *sp; - int err = -ENOMEM; - int i; - - sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL); - if (!sp) { - printk (KERN_ERR - "Seeq8003: Could not allocate private data.\n"); - return -ENOMEM; - } + int err, i; dev = alloc_etherdev(0); if (!dev) { - printk (KERN_ERR - "Seeq8003: Could not allocate memory for device.\n"); - goto out; + printk(KERN_ERR "Sgiseeq: Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; + goto err_out; + } + /* Make private data page aligned */ + sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL); + if (!sp) { + printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n"); + err = -ENOMEM; + goto err_out_free_dev; } if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { - printk(KERN_ERR "Seeq8003: Can't get irq %d\n", irq); + printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq); err = -EAGAIN; - goto out1; + goto err_out_free_page; } - printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); - #define EADDR_NVOFS 250 for (i = 0; i < 3; i++) { unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i); - printk("%2.2x:%2.2x%c", - dev->dev_addr[2 * i] = tmp >> 8, - dev->dev_addr[2 * i + 1] = tmp & 0xff, - i == 2 ? ' ' : ':'); + dev->dev_addr[2 * i] = tmp >> 8; + dev->dev_addr[2 * i + 1] = tmp & 0xff; } - printk("\n"); - SET_MODULE_OWNER(dev); - - dev->priv = sp; #ifdef DEBUG gpriv = sp; gdev = dev; @@ -648,11 +644,11 @@ sp->name = sgiseeqstr; sp->srings.rx_desc = (struct sgiseeq_rx_desc *) - (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0]))); + KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0])); dma_cache_wback_inv((unsigned long)&sp->srings.rxvector, sizeof(sp->srings.rxvector)); sp->srings.tx_desc = (struct sgiseeq_tx_desc *) - (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0]))); + KSEG1ADDR(ALIGNED(&sp->srings.txvector[0])); dma_cache_wback_inv((unsigned long)&sp->srings.txvector, sizeof(sp->srings.txvector)); @@ -665,34 +661,45 @@ sp->is_edlc = !(sp->sregs->rw.rregs.collision_tx[0] & 0xff); if (sp->is_edlc) - sp->control = (SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT | - SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT | - SEEQ_CTRL_ENCARR); - - dev->open = sgiseeq_open; - dev->stop = sgiseeq_close; - dev->hard_start_xmit = sgiseeq_start_xmit; - dev->tx_timeout = timeout; - dev->watchdog_timeo = (200 * HZ) / 1000; - dev->get_stats = sgiseeq_get_stats; - dev->set_multicast_list = sgiseeq_set_multicast; - dev->irq = irq; - dev->dma = 0; + sp->control = SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT | + SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT | + SEEQ_CTRL_ENCARR; + + dev->open = sgiseeq_open; + dev->stop = sgiseeq_close; + dev->hard_start_xmit = sgiseeq_start_xmit; + dev->tx_timeout = timeout; + dev->watchdog_timeo = (200 * HZ) / 1000; + dev->get_stats = sgiseeq_get_stats; + dev->set_multicast_list = sgiseeq_set_multicast; + dev->irq = irq; + dev->dma = 0; + dev->priv = sp; + + if (register_netdev(dev)) { + printk(KERN_ERR "Sgiseeq: Cannot register net device, " + "aborting.\n"); + err = -ENODEV; + goto err_out_free_irq; + } - err = register_netdev(dev); - if (err) - goto out2; + printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); sp->next_module = root_sgiseeq_dev; root_sgiseeq_dev = dev; return 0; -out2: - free_irq(dev->irq, dev); -out1: - free_netdev(dev); -out: + +err_out_free_irq: + free_irq(irq, dev); +err_out_free_page: free_page((unsigned long) sp); +err_out_free_dev: + kfree(dev); + +err_out: return err; } @@ -706,17 +713,18 @@ static void __exit sgiseeq_exit(void) { + struct net_device *next, *dev; struct sgiseeq_private *sp; - struct net_device *next, *dev = root_sgiseeq_dev; + int irq; - while (dev) { - sp = dev->priv; + for (dev = root_sgiseeq_dev; dev; dev = next) { + sp = (struct sgiseeq_private *) dev->priv; next = sp->next_module; + irq = dev->irq; unregister_netdev(dev); - free_irq(dev->irq, dev); - free_page((unsigned long) sp); + free_irq(irq, dev); + free_page((unsigned long) dev->priv); free_netdev(dev); - dev = next; } } diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/tulip/tulip_core.c Sun Apr 25 22:39:31 2004 @@ -1761,11 +1761,11 @@ return; tp = netdev_priv(dev); + unregister_netdev(dev); pci_free_consistent (pdev, sizeof (struct tulip_rx_desc) * RX_RING_SIZE + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, tp->rx_ring, tp->rx_ring_dma); - unregister_netdev (dev); if (tp->mtable) kfree (tp->mtable); #ifndef USE_IO_OPS diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c --- a/drivers/net/wireless/atmel.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/wireless/atmel.c Sun Apr 25 22:39:31 2004 @@ -3,7 +3,7 @@ Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. Copyright 2000-2001 ATMEL Corporation. - Copyright 2003 Simon Kelley. + Copyright 2003-2004 Simon Kelley. This code was developed from version 2.1.1 of the Atmel drivers, released by Atmel corp. under the GPL in December 2002. It also @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ #include "ieee802_11.h" #define DRIVER_MAJOR 0 -#define DRIVER_MINOR 91 +#define DRIVER_MINOR 96 MODULE_AUTHOR("Simon Kelley"); MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); @@ -519,7 +520,6 @@ } host_info; enum { - STATION_STATE_INITIALIZING, STATION_STATE_SCANNING, STATION_STATE_JOINNING, STATION_STATE_AUTHENTICATING, @@ -527,15 +527,14 @@ STATION_STATE_READY, STATION_STATE_REASSOCIATING, STATION_STATE_DOWN, - STATION_STATE_NO_CARD, - STATION_STATE_MGMT_ERROR + STATION_STATE_MGMT_ERROR } station_state; int operating_mode, power_mode; time_t last_qual; int beacons_this_sec; int channel; - int reg_domain; + int reg_domain, config_reg_domain; int tx_rate; int auto_tx_rate; int rts_threshold; @@ -578,6 +577,19 @@ static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16}; +static const struct { + int reg_domain; + int min, max; + char *name; +} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, + { REG_DOMAIN_DOC, 1, 11, "Canada" }, + { REG_DOMAIN_ETSI, 1, 13, "Europe" }, + { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, + { REG_DOMAIN_FRANCE, 10, 13, "France" }, + { REG_DOMAIN_MKK, 14, 14, "MKK" }, + { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, + { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; + static void build_wpa_mib(struct atmel_private *priv); static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len); @@ -606,8 +618,9 @@ static void atmel_smooth_qual(struct atmel_private *priv); static void atmel_writeAR(struct net_device *dev, u16 data); static int probe_atmel_card(struct net_device *dev); -int reset_atmel_card(struct net_device *dev ); +static int reset_atmel_card(struct net_device *dev ); static void atmel_enter_state(struct atmel_private *priv, int new_state); +int atmel_open (struct net_device *dev); static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) { @@ -649,7 +662,6 @@ outw(data, dev->base_addr + offset); } - static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) { atmel_writeAR(priv->dev, pos); @@ -802,14 +814,14 @@ u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; - if (priv->station_state != STATION_STATE_READY) { + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) { priv->stats.tx_errors++; dev_kfree_skb(skb); return 0; } - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) { + if (priv->station_state != STATION_STATE_READY) { priv->stats.tx_errors++; dev_kfree_skb(skb); return 0; @@ -872,8 +884,8 @@ } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee802_11_hdr *header, - u8 *body, int body_len) + struct ieee802_11_hdr *header, + u8 *body, int body_len) { u16 buff; int len = MGMT_FRAME_BODY_OFFSET + body_len; @@ -1153,82 +1165,112 @@ } } -static void reset_irq_status(struct atmel_private *priv, u8 mask) -{ - u8 isr; - - atmel_lock_mac(priv); - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - isr ^= mask; - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); -} - static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct atmel_private *priv = netdev_priv(dev); u8 isr; - + int i = -1; + static u8 irq_order[] = { + ISR_OUT_OF_RANGE, + ISR_RxCOMPLETE, + ISR_TxCOMPLETE, + ISR_RxFRAMELOST, + ISR_FATAL_ERROR, + ISR_COMMAND_COMPLETE, + ISR_IBSS_MERGE, + ISR_GENERIC_IRQ + }; + + if (priv->card && priv->present_callback && !(*priv->present_callback)(priv->card)) return IRQ_HANDLED; + + /* In this state upper-level code assumes it can mess with + the card unhampered by interrupts which may change register state. + Note that even though the card shouldn't generate interrupts + the inturrupt line may be shared. This allows card setup + to go on without disabling interrupts for a long time. */ + if (priv->station_state == STATION_STATE_DOWN) + return IRQ_NONE; atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ - + while (1) { if (!atmel_lock_mac(priv)) { - printk(KERN_ALERT "%s: MAC gone away in ISR.\n", dev->name); - /* bad things - don't re-enable interrupts */ + /* failed to contact card */ + printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); return IRQ_HANDLED; } - + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - if (isr) - atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ - else - break; /* no pending irqs */ - - if (isr & ISR_OUT_OF_RANGE) { - reset_irq_status(priv, ISR_OUT_OF_RANGE); - if(priv->operating_mode == IW_MODE_INFRA && - priv->station_state == STATION_STATE_READY) { + + if (!isr) { + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return i == -1 ? IRQ_NONE : IRQ_HANDLED; + } + + atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ + + for (i = 0; i < sizeof(irq_order)/sizeof(u8); i++) + if (isr & irq_order[i]) + break; + + if (!atmel_lock_mac(priv)) { + /* failed to contact card */ + printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); + return IRQ_HANDLED; + } + + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + isr ^= irq_order[i]; + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + + switch (irq_order[i]) { + + case ISR_OUT_OF_RANGE: + if (priv->operating_mode == IW_MODE_INFRA && + priv->station_state == STATION_STATE_READY) { priv->station_is_associated = 0; atmel_scan(priv, 1); } - } else if (isr & ISR_RxCOMPLETE) { - reset_irq_status(priv, ISR_RxCOMPLETE); + break; + + case ISR_RxFRAMELOST: + priv->wstats.discard.misc++; + /* fall through */ + case ISR_RxCOMPLETE: rx_done_irq(priv); - } else if (isr & ISR_TxCOMPLETE) { - reset_irq_status(priv, ISR_TxCOMPLETE); + break; + + case ISR_TxCOMPLETE: tx_done_irq(priv); - } else if (isr & ISR_RxFRAMELOST) { - reset_irq_status(priv, ISR_RxFRAMELOST); - priv->wstats.discard.misc++; - rx_done_irq(priv); - } else if (isr & ISR_FATAL_ERROR) { - reset_irq_status(priv, ISR_FATAL_ERROR); + break; + + case ISR_FATAL_ERROR: printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - } else if (isr & ISR_COMMAND_COMPLETE) { - reset_irq_status(priv, ISR_COMMAND_COMPLETE); - atmel_command_irq(priv); - } else if (isr & ISR_IBSS_MERGE) { - reset_irq_status(priv, ISR_IBSS_MERGE); + break; + + case ISR_COMMAND_COMPLETE: + atmel_command_irq(priv); + break; + + case ISR_IBSS_MERGE: atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, priv->CurrentBSSID, 6); /* The WPA stuff cares about the current AP address */ if (priv->use_wpa) build_wpa_mib(priv); - } else if (isr & ISR_GENERIC_IRQ) { - reset_irq_status(priv, ISR_GENERIC_IRQ); + break; + case ISR_GENERIC_IRQ: printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name); + break; } } - - atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ - return IRQ_HANDLED; } @@ -1256,8 +1298,8 @@ priv->wstats.qual.noise = 0; priv->wstats.qual.updated = 7; } else { - // Quality levels cannot be determined in ad-hoc mode, - // because we can 'hear' more that one remote station. + /* Quality levels cannot be determined in ad-hoc mode, + because we can 'hear' more that one remote station. */ priv->wstats.qual.qual = 0; priv->wstats.qual.level = 0; priv->wstats.qual.noise = 0; @@ -1281,18 +1323,62 @@ struct sockaddr *addr = p; memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); - reset_atmel_card(dev); - return 0; + return atmel_open(dev); } -static int atmel_open (struct net_device *dev) +EXPORT_SYMBOL(atmel_open); + +int atmel_open (struct net_device *dev) { struct atmel_private *priv = netdev_priv(dev); - priv->station_state = STATION_STATE_INITIALIZING; - if (!reset_atmel_card(dev)) { - priv->station_state = STATION_STATE_DOWN; + int i, channel; + + /* any scheduled timer is no longer needed and might screw things up.. */ + del_timer_sync(&priv->management_timer); + + /* Interrupts will not touch the card once in this state... */ + priv->station_state = STATION_STATE_DOWN; + + if (priv->new_SSID_size) { + memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); + priv->SSID_size = priv->new_SSID_size; + priv->new_SSID_size = 0; + } + priv->BSS_list_entries = 0; + + priv->AuthenticationRequestRetryCnt = 0; + priv->AssociationRequestRetryCnt = 0; + priv->ReAssociationRequestRetryCnt = 0; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + priv->ExpectedAuthentTransactionSeqNum = 0x0002; + + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->station_is_associated = 0; + + if (!reset_atmel_card(dev)) return -EAGAIN; + + if (priv->config_reg_domain) { + priv->reg_domain = priv->config_reg_domain; + atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); + } else { + priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) + if (priv->reg_domain == channel_table[i].reg_domain) + break; + if (i == sizeof(channel_table)/sizeof(channel_table[0])) { + priv->reg_domain = REG_DOMAIN_MKK1; + printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); + } } + + if ((channel = atmel_validate_channel(priv, priv->channel))) + priv->channel = channel; + + /* this moves station_state on.... */ + atmel_scan(priv, 1); + + atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ return 0; } @@ -1300,19 +1386,34 @@ { struct atmel_private *priv = netdev_priv(dev); - netif_carrier_off(dev); - if (netif_running(dev)) - netif_stop_queue(dev); + atmel_enter_state(priv, STATION_STATE_DOWN); - priv->station_state = STATION_STATE_DOWN; if (priv->bus_type == BUS_TYPE_PCCARD) atmel_write16(dev, GCR, 0x0060); atmel_write16(dev, GCR, 0x0040); return 0; } +static int atmel_validate_channel(struct atmel_private *priv, int channel) +{ + /* check that channel is OK, if so return zero, + else return suitable default channel */ + int i; + + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) + if (priv->reg_domain == channel_table[i].reg_domain) { + if (channel >= channel_table[i].min && + channel <= channel_table[i].max) + return 0; + else + return channel_table[i].min; + } + return 0; +} + static int atmel_proc_output (char *buf, struct atmel_private *priv) { + int i; char *p = buf; char *s, *r, *c; @@ -1338,17 +1439,12 @@ default: c = ""; } - switch (priv->reg_domain) { - case REG_DOMAIN_FCC: r = "USA"; break; - case REG_DOMAIN_DOC: r = "Canada"; break; - case REG_DOMAIN_ETSI: r = "Europe"; break; - case REG_DOMAIN_SPAIN: r = "Spain"; break; - case REG_DOMAIN_FRANCE: r = "France"; break; - case REG_DOMAIN_MKK: r = "Japan (MKK)"; break; - case REG_DOMAIN_MKK1: r = "Japan (MKK1)"; break; - case REG_DOMAIN_ISRAEL: r = "Israel"; break; - default: r = ""; - } + + r = ""; + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) + if (priv->reg_domain == channel_table[i].reg_domain) + r = channel_table[i].name; + p += sprintf(p, "MAC memory type:\t%s\n", c); p += sprintf(p, "Regulatory domain:\t%s\n", r); p += sprintf(p, "Host CRC checking:\t%s\n", @@ -1358,14 +1454,12 @@ } switch(priv->station_state) { - case STATION_STATE_INITIALIZING: s = "Initialising"; break; case STATION_STATE_SCANNING: s = "Scanning"; break; case STATION_STATE_JOINNING: s = "Joining"; break; case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break; case STATION_STATE_ASSOCIATING: s = "Associating"; break; case STATION_STATE_READY: s = "Ready"; break; case STATION_STATE_REASSOCIATING: s = "Reassociating"; break; - case STATION_STATE_NO_CARD: s = "No card"; break; case STATION_STATE_MGMT_ERROR: s = "Management error"; break; case STATION_STATE_DOWN: s = "Down"; break; default: s = ""; @@ -1441,6 +1535,8 @@ priv->preamble = LONG_PREAMBLE; priv->operating_mode = IW_MODE_INFRA; priv->connect_to_any_BSS = 0; + priv->config_reg_domain = 0; + priv->reg_domain = 0; priv->tx_rate = 3; priv->auto_tx_rate = 1; priv->channel = 4; @@ -1547,36 +1643,6 @@ EXPORT_SYMBOL(stop_atmel_card); -static const struct { - int reg_domain; - int min, max; -} channel_table[] = { { REG_DOMAIN_FCC, 1, 11}, - { REG_DOMAIN_DOC, 1, 11}, - { REG_DOMAIN_ETSI, 1, 13}, - { REG_DOMAIN_SPAIN, 10, 11}, - { REG_DOMAIN_FRANCE, 10, 13}, - { REG_DOMAIN_MKK, 14, 14}, - { REG_DOMAIN_MKK1, 1, 14}, - { REG_DOMAIN_ISRAEL, 9} }; - - -static int atmel_validate_channel(struct atmel_private *priv, int channel) -{ - /* check that channel is OK, if so return zero, - else return suitable default channel */ - int i; - - for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) - if (priv->reg_domain == channel_table[i].reg_domain) { - if (channel >= channel_table[i].min && - channel <= channel_table[i].max) - return 0; - else - return channel_table[i].min; - } - return 1; -} - static int atmel_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, @@ -1613,7 +1679,7 @@ struct atmel_private *priv = netdev_priv(dev); /* Get the current SSID */ - if (priv->SSID_size == 0) { + if (priv->new_SSID_size != 0) { memcpy(extra, priv->new_SSID, priv->new_SSID_size); extra[priv->new_SSID_size] = '\0'; dwrq->length = priv->new_SSID_size + 1; @@ -2037,6 +2103,7 @@ char *extra) { struct atmel_private *priv = netdev_priv(dev); + unsigned long flags; /* Note : you may have realised that, as this is a SET operation, * this is privileged and therefore a normal user can't @@ -2045,8 +2112,7 @@ * traffic doesn't flow, so it's a perfect DoS... * Jean II */ - if (priv->station_state == STATION_STATE_DOWN || - priv->station_state == STATION_STATE_NO_CARD) + if (priv->station_state == STATION_STATE_DOWN) return -EAGAIN; /* Timeout old surveys. */ @@ -2057,14 +2123,14 @@ /* Initiate a scan command */ if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) return -EBUSY; + + del_timer_sync(&priv->management_timer); + spin_lock_irqsave(&priv->irqlock, flags); priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; - - atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ - del_timer_sync(&priv->management_timer); priv->fast_scan = 0; atmel_scan(priv, 0); - atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + spin_unlock_irqrestore(&priv->irqlock, flags); return 0; } @@ -2116,7 +2182,7 @@ /* Length of data */ dwrq->length = (current_ev - extra); - dwrq->flags = 0; /* todo */ + dwrq->flags = 0; return 0; } @@ -2196,15 +2262,16 @@ struct atmel_private *priv = netdev_priv(dev); int i; static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; - + unsigned long flags; + if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; if (memcmp(bcast, awrq->sa_data, 6) == 0) { - atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ del_timer_sync(&priv->management_timer); + spin_lock_irqsave(&priv->irqlock, flags); atmel_scan(priv, 1); - atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + spin_unlock_irqrestore(&priv->irqlock, flags); return 0; } @@ -2214,9 +2281,13 @@ return -EINVAL; } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { return -EINVAL; - } else - atmel_join_bss(priv, i); - return 0; + } else { + del_timer_sync(&priv->management_timer); + spin_lock_irqsave(&priv->irqlock, flags); + atmel_join_bss(priv, i); + spin_unlock_irqrestore(&priv->irqlock, flags); + return 0; + } } } @@ -2228,8 +2299,7 @@ void *zwrq, /* NULL */ char *extra) /* NULL */ { - reset_atmel_card(dev); - return 0; + return atmel_open(dev); } static const iw_handler atmel_handler[] = @@ -2297,12 +2367,15 @@ #define ATMELFWL SIOCIWFIRSTPRIV #define ATMELIDIFC ATMELFWL + 1 +#define ATMELRD ATMELFWL + 2 #define ATMELMAGIC 0x51807 +#define REGDOMAINSZ 20 static const struct iw_priv_args atmel_private_args[] = { /*{ cmd, set_args, get_args, name } */ { ATMELFWL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (atmel_priv_ioctl), IW_PRIV_TYPE_NONE, "atmelfwl" }, { ATMELIDIFC, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "atmelidifc" }, + { ATMELRD, IW_PRIV_TYPE_CHAR | REGDOMAINSZ, IW_PRIV_TYPE_NONE, "regdomain" }, }; static const struct iw_handler_def atmel_handler_def = @@ -2317,11 +2390,12 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - int rc = 0; + int i, rc = 0; struct atmel_private *priv = netdev_priv(dev); atmel_priv_ioctl com; struct iwreq *wrq = (struct iwreq *) rq; unsigned char *new_firmware; + char domain[REGDOMAINSZ+1]; switch (cmd) { case SIOCGIWPRIV: @@ -2371,6 +2445,39 @@ priv->firmware_id[31] = '\0'; break; + case ATMELRD: + if (copy_from_user(domain, rq->ifr_data, REGDOMAINSZ)) { + rc = -EFAULT; + break; + } + + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + domain[REGDOMAINSZ] = 0; + rc = -EINVAL; + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) { + /* strcasecmp doesn't exist in the library */ + char *a = channel_table[i].name; + char *b = domain; + while (*a) { + char c1 = *a++; + char c2 = *b++; + if (tolower(c1) != tolower(c2)) + break; + } + if (!*a && !*b) { + priv->config_reg_domain = channel_table[i].reg_domain; + rc = 0; + } + } + + if (rc == 0 && priv->station_state != STATION_STATE_DOWN) + rc = atmel_open(dev); + break; + default: rc = -EOPNOTSUPP; } @@ -2390,10 +2497,12 @@ static void atmel_enter_state(struct atmel_private *priv, int new_state) { int old_state = priv->station_state; - + if (new_state == old_state) return; - + + priv->station_state = new_state; + if (new_state == STATION_STATE_READY) { netif_start_queue(priv->dev); netif_carrier_on(priv->dev); @@ -2401,12 +2510,10 @@ if (old_state == STATION_STATE_READY) { netif_carrier_off(priv->dev); - netif_stop_queue(priv->dev); + if (netif_running(priv->dev)) + netif_stop_queue(priv->dev); priv->last_beacon_timestamp = 0; } - - priv->station_state = new_state; - } static void atmel_scan(struct atmel_private *priv, int specific_ssid) @@ -2423,8 +2530,6 @@ u8 SSID_size; } cmd; - atmel_enter_state(priv, STATION_STATE_SCANNING); - memset(cmd.BSSID, 0xff, 6); if (priv->fast_scan) { @@ -2450,6 +2555,10 @@ BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); + + /* This must come after all hardware access to avoid being messed up + by stuff happening in interrupt context after we leave STATE_DOWN */ + atmel_enter_state(priv, STATION_STATE_SCANNING); } static void join(struct atmel_private *priv, int type) @@ -3060,16 +3169,12 @@ if (priv->card && priv->present_callback && !(*priv->present_callback)(priv->card)) return; - - if (priv->station_state == STATION_STATE_NO_CARD) - return; - + spin_lock_irqsave(&priv->irqlock, flags); switch (priv->station_state) { case STATION_STATE_AUTHENTICATING: - if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); priv->station_is_associated = 0; @@ -3085,7 +3190,6 @@ break; case STATION_STATE_ASSOCIATING: - if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); priv->station_is_associated = 0; @@ -3100,7 +3204,6 @@ break; case STATION_STATE_REASSOCIATING: - if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); priv->station_is_associated = 0; @@ -3113,7 +3216,7 @@ } break; - + default: break; } @@ -3203,7 +3306,7 @@ struct host_info_struct *iface = &priv->host_info; u16 mr1, mr3; int i; - + if (priv->card_type == CARD_TYPE_SPI_FLASH) atmel_set_gcr(priv->dev, GCR_REMAP); @@ -3233,7 +3336,6 @@ if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); - priv->station_state = STATION_STATE_NO_CARD; return 0; } @@ -3271,10 +3373,10 @@ printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); return 0; } - + atmel_copy_to_host(priv->dev, (unsigned char *)iface, priv->host_info_base, sizeof(*iface)); - + iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); @@ -3323,7 +3425,6 @@ printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); } else { atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); - /* got address, now squash it again until the network interface is opened */ if (priv->bus_type == BUS_TYPE_PCCARD) @@ -3469,7 +3570,7 @@ atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); } -int reset_atmel_card(struct net_device *dev) +static int reset_atmel_card(struct net_device *dev) { /* do everything necessary to wake up the hardware, including waiting for the lightning strike and throwing the knife switch.... @@ -3485,7 +3586,6 @@ including a copy of the firmware's hostinfo stucture which is the route into the rest of the firmare datastructures. */ - int channel; struct atmel_private *priv = netdev_priv(dev); u8 configuration; @@ -3497,37 +3597,14 @@ "", NULL }; - - if (priv->station_state == STATION_STATE_NO_CARD || - priv->station_state == STATION_STATE_DOWN) - return 0; - + /* reset pccard */ if (priv->bus_type == BUS_TYPE_PCCARD) atmel_write16(priv->dev, GCR, 0x0060); /* stop card , disable interrupts */ atmel_write16(priv->dev, GCR, 0x0040); - - /* any scheduled timer is no longer needed and might screw things up.. */ - del_timer_sync(&priv->management_timer); - if (priv->new_SSID_size) { - memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); - priv->SSID_size = priv->new_SSID_size; - priv->new_SSID_size = 0; - } - priv->BSS_list_entries = 0; - - priv->AuthenticationRequestRetryCnt = 0; - priv->AssociationRequestRetryCnt = 0; - priv->ReAssociationRequestRetryCnt = 0; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - priv->ExpectedAuthentTransactionSeqNum = 0x0002; - - priv->station_state = STATION_STATE_INITIALIZING; - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->station_is_associated = 0; - + if (priv->card_type == CARD_TYPE_EEPROM) { /* copy in firmware if needed */ const struct firmware *fw_entry = NULL; @@ -3573,7 +3650,7 @@ len = fw_entry->size; } - if (len <= 0x6000) { + if (len <= 0x6000) { atmel_write16(priv->dev, BSR, BSS_IRAM); atmel_copy_to_card(priv->dev, 0, fw, len); atmel_set_gcr(priv->dev, GCR_REMAP); @@ -3628,29 +3705,14 @@ configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), configuration | FUNC_CTRL_RxENABLE); - - priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); - if (priv->reg_domain != REG_DOMAIN_FCC && - priv->reg_domain != REG_DOMAIN_DOC && - priv->reg_domain != REG_DOMAIN_ETSI && - priv->reg_domain != REG_DOMAIN_SPAIN && - priv->reg_domain != REG_DOMAIN_FRANCE && - priv->reg_domain != REG_DOMAIN_MKK && - priv->reg_domain != REG_DOMAIN_MKK1 && - priv->reg_domain != REG_DOMAIN_ISRAEL) { - priv->reg_domain = REG_DOMAIN_MKK1; - printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); - } - if ((channel = atmel_validate_channel(priv, priv->channel))) - priv->channel = channel; - + if (!priv->radio_on_broken) { if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == CMD_STATUS_REJECTED_RADIO_OFF) { printk(KERN_INFO "%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n", dev->name); - return 0; + return 0; } } @@ -3674,15 +3736,9 @@ else build_wep_mib(priv); - atmel_scan(priv, 1); - - atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ - return 1; } -EXPORT_SYMBOL(reset_atmel_card); - static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size) { if (cmd) @@ -3698,16 +3754,17 @@ int i, status; atmel_send_command(priv, command, cmd, cmd_size); - - for (i = LOOP_RETRY_LIMIT; i; i--) { + + for (i = 5000; i; i--) { status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); if (status != CMD_STATUS_IDLE && status != CMD_STATUS_IN_PROGRESS) break; + udelay(20); } - + if (i == 0) { - printk(KERN_ALERT "%s: command %d failed to complete.\n", priv->dev->name, command); + printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); status = CMD_STATUS_HOST_ERROR; } else { if (command != CMD_EnableRadio) @@ -3835,9 +3892,13 @@ static int atmel_lock_mac(struct atmel_private *priv) { - int i, j = 100; + int i, j = 20; retry: - for (i = LOOP_RETRY_LIMIT ; atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET)) && i ; i--); + for (i = 5000; i; i--) { + if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) + break; + udelay(20); + } if (!i) return 0; /* timed out */ diff -Nru a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c --- a/drivers/net/wireless/atmel_cs.c Sun Apr 25 22:39:31 2004 +++ b/drivers/net/wireless/atmel_cs.c Sun Apr 25 22:39:31 2004 @@ -54,7 +54,6 @@ #include #include #include -#include /* @@ -104,7 +103,7 @@ struct net_device *init_atmel_card(int, int, char *, struct device *, int (*present_func)(void *), void * ); void stop_atmel_card( struct net_device *, int ); -int reset_atmel_card( struct net_device * ); +int atmel_open( struct net_device * ); static void atmel_config(dev_link_t *link); static void atmel_release(dev_link_t *link); @@ -335,7 +334,7 @@ { 0, 0, "ATMEL/AT76C504A", "atmel_at76c504a_2958%s.bin", "NoName-504a-2958" }, { 0, 0, "ATMEL/AT76C504_R", "atmel_at76c504_2958%s.bin", "NoName-504-2958" }, { MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRWE62092B" }, - { MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRSHPW_96" }, + { MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRSHPW196" }, { 0, 0, "SMC/2632W-V2", "atmel_at76c502%s.bin", "SMC 2632W-V2" }, { 0, 0, "SMC/2632W", "atmel_at76c502d%s.bin", "SMC 2632W-V3" }, { 0xd601, 0x0007, NULL, "atmel_at76c502%s.bin", "Sitecom WLAN-011" }, @@ -661,7 +660,7 @@ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); - reset_atmel_card(local->eth_dev); + atmel_open(local->eth_dev); netif_device_attach(local->eth_dev); } break; diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile --- a/drivers/pci/Makefile Sun Apr 25 22:39:31 2004 +++ b/drivers/pci/Makefile Sun Apr 25 22:39:31 2004 @@ -24,8 +24,7 @@ obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC64) += setup-bus.o -obj-$(CONFIG_SGI_IP27) += setup-irq.o -obj-$(CONFIG_SGI_IP32) += setup-irq.o +obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_PCI_USE_VECTOR) += msi.o diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c --- a/drivers/s390/block/dasd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/block/dasd.c Sun Apr 25 22:39:31 2004 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.136 $ + * $Revision: 1.139 $ */ #include @@ -74,6 +74,8 @@ if (device == NULL) return ERR_PTR(-ENOMEM); memset(device, 0, sizeof (struct dasd_device)); + /* open_count = 0 means device online but not in use */ + atomic_set(&device->open_count, -1); /* Get two pages for normal block device operations. */ device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); @@ -549,6 +551,7 @@ } strncpy((char *) &cqr->magic, magic, 4); ASCEBC((char *) &cqr->magic, 4); + set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; } @@ -597,6 +600,7 @@ } strncpy((char *) &cqr->magic, magic, 4); ASCEBC((char *) &cqr->magic, 4); + set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; } @@ -688,9 +692,10 @@ rc = ccw_device_clear(device->cdev, (long) cqr); switch (rc) { case 0: /* termination successful */ - if (cqr->retries > 0) + if (cqr->retries > 0) { + cqr->retries--; cqr->status = DASD_CQR_QUEUED; - else + } else cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); break; @@ -982,6 +987,8 @@ irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) era = dasd_era_none; + else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) + era = dasd_era_fatal; /* don't recover this request */ else if (irb->esw.esw0.erw.cons) era = device->discipline->examine_error(cqr, irb); else @@ -1875,7 +1882,7 @@ * the blkdev_get in dasd_scan_partitions. We are only interested * in the other openers. */ - max_count = device->bdev ? 1 : 0; + max_count = device->bdev ? 0 : -1; if (atomic_read(&device->open_count) > max_count) { printk (KERN_WARNING "Can't offline dasd device with open" " count = %i.\n", diff -Nru a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c --- a/drivers/s390/block/dasd_3990_erp.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/block/dasd_3990_erp.c Sun Apr 25 22:39:31 2004 @@ -5,7 +5,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * - * $Revision: 1.28 $ + * $Revision: 1.30 $ */ #include @@ -1763,6 +1763,7 @@ erp->magic = default_erp->magic; erp->expires = 0; erp->retries = 256; + cqr->buildclk = get_clock(); erp->status = DASD_CQR_FILLED; /* remove the default erp */ diff -Nru a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c --- a/drivers/s390/block/dasd_eckd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/block/dasd_eckd.c Sun Apr 25 22:39:31 2004 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.53 $ + * $Revision: 1.54 $ */ #include @@ -1130,6 +1130,7 @@ cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); @@ -1173,6 +1174,7 @@ cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); @@ -1215,6 +1217,7 @@ cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h --- a/drivers/s390/block/dasd_int.h Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/block/dasd_int.h Sun Apr 25 22:39:31 2004 @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.56 $ + * $Revision: 1.57 $ */ #ifndef DASD_INT_H @@ -159,6 +159,7 @@ struct ccw1 *cpaddr; /* address of channel program */ char status; /* status of this request */ short retries; /* A retry counter */ + unsigned long flags; /* flags of this request */ /* ... and how */ unsigned long starttime; /* jiffies time of request start */ @@ -191,6 +192,9 @@ #define DASD_CQR_DONE 0x03 /* request is completed successfully */ #define DASD_CQR_ERROR 0x04 /* request is completed with error */ #define DASD_CQR_FAILED 0x05 /* request is finally failed */ + +/* per dasd_ccw_req flags */ +#define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ /* Signature for error recovery functions. */ typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); diff -Nru a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c --- a/drivers/s390/char/raw3270.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/char/raw3270.c Sun Apr 25 22:39:31 2004 @@ -381,6 +381,8 @@ return; /* Sucessfully restarted. */ break; case RAW3270_IO_STOP: + if (!rq) + break; raw3270_halt_io_nolock(rp, rq); rq->rc = -EIO; break; @@ -881,7 +883,7 @@ if (rc) { /* Didn't work. Try to reactivate the old view. */ rp->view = oldview; - if (oldview->fn->activate(oldview) != 0) { + if (!oldview || oldview->fn->activate(oldview) != 0) { /* Didn't work as well. Try any other view. */ list_for_each_entry(nv, &rp->view_list, list) if (nv != view && nv != oldview) { diff -Nru a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c --- a/drivers/s390/cio/cio.c Sun Apr 25 22:39:32 2004 +++ b/drivers/s390/cio/cio.c Sun Apr 25 22:39:32 2004 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.117 $ + * $Revision: 1.121 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -783,3 +783,68 @@ } #endif +static inline int +__disable_subchannel_easy(unsigned int schid, struct schib *schib) +{ + int retry, cc; + + cc = 0; + for (retry=0;retry<3;retry++) { + schib->pmcw.ena = 0; + cc = msch(schid, schib); + if (cc) + return (cc==3?-ENODEV:-EBUSY); + stsch(schid, schib); + if (!schib->pmcw.ena) + return 0; + } + return -EBUSY; /* uhm... */ +} + +static inline int +__clear_subchannel_easy(unsigned int schid) +{ + int retry; + + if (csch(schid)) + return -ENODEV; + for (retry=0;retry<20;retry++) { + struct tpi_info ti; + + if (tpi(&ti)) { + tsch(schid, (struct irb *)__LC_IRB); + return 0; + } + udelay(100); + } + return -EBUSY; +} + +extern void do_reipl(unsigned long devno); +/* Make sure all subchannels are quiet before we re-ipl an lpar. */ +void +reipl(unsigned long devno) +{ + unsigned int schid; + + local_irq_disable(); + for (schid=0;schid<=highest_subchannel;schid++) { + struct schib schib; + if (stsch(schid, &schib)) + goto out; + if (!schib.pmcw.ena) + continue; + switch(__disable_subchannel_easy(schid, &schib)) { + case 0: + case -ENODEV: + break; + default: /* -EBUSY */ + if (__clear_subchannel_easy(schid)) + break; /* give up... */ + stsch(schid, &schib); + __disable_subchannel_easy(schid, &schib); + } + } +out: + do_reipl(devno); +} diff -Nru a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c --- a/drivers/s390/cio/device_fsm.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/cio/device_fsm.c Sun Apr 25 22:39:31 2004 @@ -440,12 +440,14 @@ if (!ret) { if (get_device(&sch->dev)) { /* Driver doesn't want to keep device. */ + cio_disable_subchannel(sch); device_unregister(&sch->dev); sch->schib.pmcw.intparm = 0; cio_modify(sch); put_device(&sch->dev); } } else { + cio_disable_subchannel(sch); ccw_device_set_timeout(cdev, 0); cdev->private->state = DEV_STATE_DISCONNECTED; wake_up(&cdev->private->wait_q); @@ -787,6 +789,7 @@ struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); + ccw_device_set_timeout(cdev, 0); /* OK, i/o is dead now. Call interrupt handler. */ cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) diff -Nru a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c --- a/drivers/s390/cio/qdio.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/cio/qdio.c Sun Apr 25 22:39:31 2004 @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.79 $" +#define VERSION_QDIO_C "$Revision: 1.80 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -461,12 +461,12 @@ switch(slsb[f_mod_no]) { - /* the hydra has not fetched the output yet */ + /* the adapter has not fetched the output yet */ case SLSB_CU_OUTPUT_PRIMED: QDIO_DBF_TEXT5(0,trace,"outpprim"); break; - /* the hydra got it */ + /* the adapter got it */ case SLSB_P_OUTPUT_EMPTY: atomic_dec(&q->number_of_buffers_used); f++; @@ -919,7 +919,7 @@ no_used=atomic_read(&q->number_of_buffers_used); /* - * we need that one for synchronization with Hydra, as Hydra + * we need that one for synchronization with the adapter, as it * does a kind of PCI avoidance */ SYNC_MEMORY; @@ -1069,7 +1069,7 @@ } /* * maybe we have to do work on our outbound queues... at least - * we have to check Hydra outbound-int-capable thinint-capable + * we have to check the outbound-int-capable thinint-capable * queues */ if (q->hydra_gives_outbound_pcis) { @@ -2027,7 +2027,7 @@ goto exit; } - /* Check for hydra thin interrupts (bit 67). */ + /* Check for OSA/FCP thin interrupts (bit 67). */ hydra_thinints = ((scsc_area->general_char[2] & 0x10000000) == 0x10000000); sprintf(dbf_text,"hydrati%1x", hydra_thinints); diff -Nru a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c --- a/drivers/s390/net/iucv.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/net/iucv.c Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* - * $Id: iucv.c,v 1.27 2004/03/22 07:43:43 braunu Exp $ + * $Id: iucv.c,v 1.28 2004/04/15 06:34:58 braunu Exp $ * * IUCV network driver * @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.27 $ + * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.28 $ * */ @@ -351,7 +351,7 @@ static void iucv_banner(void) { - char vbuf[] = "$Revision: 1.27 $"; + char vbuf[] = "$Revision: 1.28 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { @@ -800,6 +800,7 @@ if (iucv_pathid_table == NULL) { printk(KERN_WARNING "%s: iucv_pathid_table storage " "allocation failed\n", __FUNCTION__); + kfree(new_handler); return NULL; } memset (iucv_pathid_table, 0, max_connections * sizeof(handler *)); diff -Nru a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c --- a/drivers/s390/net/netiucv.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/net/netiucv.c Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.48 2004/04/01 13:42:09 braunu Exp $ + * $Id: netiucv.c,v 1.49 2004/04/15 06:37:54 braunu Exp $ * * IUCV network driver * @@ -30,7 +30,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.48 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.49 $ * */ @@ -601,11 +601,12 @@ if ((skb = skb_dequeue(&conn->commit_queue))) { atomic_dec(&skb->users); dev_kfree_skb_any(skb); - } - if (privptr) { - privptr->stats.tx_packets++; - privptr->stats.tx_bytes += - (skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); + if (privptr) { + privptr->stats.tx_packets++; + privptr->stats.tx_bytes += + (skb->len - NETIUCV_HDRLEN + - NETIUCV_HDRLEN); + } } } conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; @@ -1078,6 +1079,7 @@ "%s: Could not allocate tx_skb\n", conn->netdev->name); rc = -ENOMEM; + return rc; } else { skb_reserve(nskb, NETIUCV_HDRLEN); memcpy(skb_put(nskb, skb->len), @@ -1880,7 +1882,7 @@ static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.48 $"; + char vbuf[] = "$Revision: 1.49 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff -Nru a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h --- a/drivers/s390/net/qeth.h Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/net/qeth.h Sun Apr 25 22:39:31 2004 @@ -23,7 +23,7 @@ #include "qeth_mpc.h" -#define VERSION_QETH_H "$Revision: 1.98 $" +#define VERSION_QETH_H "$Revision: 1.100 $" #ifdef CONFIG_QETH_IPV6 #define QETH_VERSION_IPV6 ":IPv6" @@ -423,14 +423,12 @@ struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q]; int queue_no; struct qeth_card *card; - struct tasklet_struct tasklet; spinlock_t lock; volatile int do_pack; /* * index of buffer to be filled by driver; state EMPTY or PACKING */ volatile int next_buf_to_fill; - volatile int next_buf_to_flush; /* * number of buffers that are currently filled (PRIMED) * -> these buffers are hardware-owned @@ -447,7 +445,6 @@ struct qeth_qdio_buffer_pool in_buf_pool; struct qeth_qdio_buffer_pool init_pool; int in_buf_size; - struct tasklet_struct in_tasklet; /* output */ int no_out_queues; diff -Nru a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c --- a/drivers/s390/net/qeth_main.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/net/qeth_main.c Sun Apr 25 22:39:31 2004 @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.77 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.82 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier * - * $Revision: 1.77 $ $Date: 2004/04/06 14:38:19 $ + * $Revision: 1.82 $ $Date: 2004/04/21 08:27:21 $ * * 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 @@ -78,7 +78,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -#define VERSION_QETH_C "$Revision: 1.77 $" +#define VERSION_QETH_C "$Revision: 1.82 $" static const char *version = "qeth S/390 OSA-Express driver (" VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; @@ -486,6 +486,7 @@ list_del(&card->list); write_unlock_irqrestore(&qeth_card_list.rwlock, flags); unregister_netdev(card->dev); + qeth_remove_device_attributes(&cgdev->dev); qeth_free_card(card); cgdev->dev.driver_data = NULL; put_device(&cgdev->dev); @@ -822,7 +823,7 @@ struct qeth_card *card; card = (struct qeth_card *) ptr; - daemonize("getmcaddr"); + daemonize("qeth_reg_mcaddrs"); QETH_DBF_TEXT(trace,4,"regmcth1"); if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD)) return 0; @@ -843,7 +844,7 @@ struct qeth_card *card; card = (struct qeth_card *) ptr; - daemonize("regip"); + daemonize("qeth_reg_ip"); QETH_DBF_TEXT(trace,4,"regipth1"); if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD)) return 0; @@ -860,7 +861,7 @@ int rc = 0; card = (struct qeth_card *) ptr; - daemonize("recover"); + daemonize("qeth_recover"); QETH_DBF_TEXT(trace,2,"recover1"); QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) @@ -1969,45 +1970,6 @@ return rc; } -static void -qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, - unsigned int qdio_err, unsigned int siga_err, - unsigned int queue, int first_element, int count, - unsigned long card_ptr) -{ - struct net_device *net_dev; - struct qeth_card *card; - struct qeth_qdio_buffer *buffer; - int i; - - QETH_DBF_TEXT(trace, 6, "qdinput"); - card = (struct qeth_card *) card_ptr; - net_dev = card->dev; -#ifdef CONFIG_QETH_PERF_STATS - card->perf_stats.inbound_start_time = qeth_get_micros(); -#endif - if (status & QDIO_STATUS_LOOK_FOR_ERROR) { - if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ - QETH_DBF_TEXT(trace, 1,"qdinchk"); - QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card)); - QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count); - QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status); - qeth_schedule_recovery(card); - return; - } - } - for (i = first_element; i < (first_element + count); ++i) { - buffer = &card->qdio.in_q->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - if ((status == QDIO_STATUS_LOOK_FOR_ERROR) && - qeth_check_for_inbound_error(buffer, qdio_err, siga_err)) - buffer->state = QETH_QDIO_BUF_ERROR; - else - buffer->state = QETH_QDIO_BUF_PRIMED; - } - - tasklet_schedule(&card->qdio.in_tasklet); -} - static inline struct sk_buff * qeth_get_skb(unsigned int length) { @@ -2127,7 +2089,6 @@ return htons(ETH_P_802_2); } - static inline void qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) @@ -2193,7 +2154,6 @@ #endif /* CONFIG_QETH_VLAN */ } - static inline void qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) @@ -2241,6 +2201,38 @@ qeth_rebuild_skb_vlan(card, skb, hdr); } +static inline void +qeth_process_inbound_buffer(struct qeth_card *card, + struct qeth_qdio_buffer *buf, int index) +{ + struct qdio_buffer_element *element; + int offset; + struct sk_buff *skb; + struct qeth_hdr *hdr; + int rxrc; + + /* get first element of current buffer */ + element = (struct qdio_buffer_element *)&buf->buffer->element[0]; + offset = 0; +#ifdef CONFIG_QETH_PERF_STATS + card->perf_stats.bufs_rec++; +#endif + while((skb = qeth_get_next_skb(card, buf->buffer, &element, + &offset, &hdr))){ + qeth_rebuild_skb(card, skb, hdr); + +#ifdef CONFIG_QETH_PERF_STATS + card->perf_stats.inbound_time += qeth_get_micros() - + card->perf_stats.inbound_start_time; + card->perf_stats.inbound_cnt++; +#endif + skb->dev = card->dev; + rxrc = netif_rx(skb); + card->dev->last_rx = jiffies; + card->stats.rx_packets++; + card->stats.rx_bytes += skb->len; + } +} static inline struct qeth_buffer_pool_entry * qeth_get_buffer_pool_entry(struct qeth_card *card) @@ -2284,7 +2276,7 @@ buf->state = QETH_QDIO_BUF_EMPTY; } -static void +static inline void qeth_clear_output_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf) { @@ -2355,61 +2347,43 @@ } static void -qeth_qdio_input_tasklet(unsigned long data) +qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, + unsigned int qdio_err, unsigned int siga_err, + unsigned int queue, int first_element, int count, + unsigned long card_ptr) { - struct qeth_card *card = (struct qeth_card *) data; - int current_buf = card->qdio.in_q->next_buf_to_process; - struct qeth_qdio_buffer *buf; - struct qdio_buffer_element *element; - int offset; - struct sk_buff *skb; - struct qeth_hdr *hdr; - int rxrc; - - QETH_DBF_TEXT(trace,6,"qdintlet"); - buf = &card->qdio.in_q->bufs[current_buf]; - while((buf->state == QETH_QDIO_BUF_PRIMED) || - (buf->state == QETH_QDIO_BUF_ERROR)){ - if (buf->state == QETH_QDIO_BUF_ERROR) - goto clear_buffer; - if (netif_queue_stopped(card->dev)) - goto clear_buffer; - /* get first element of current buffer */ - element = (struct qdio_buffer_element *) - &buf->buffer->element[0]; - offset = 0; -#ifdef CONFIG_QETH_PERF_STATS - card->perf_stats.bufs_rec++; -#endif - while((skb = qeth_get_next_skb(card, buf->buffer, &element, - &offset, &hdr))){ + struct net_device *net_dev; + struct qeth_card *card; + struct qeth_qdio_buffer *buffer; + int index; + int i; - qeth_rebuild_skb(card, skb, hdr); + QETH_DBF_TEXT(trace, 6, "qdinput"); + card = (struct qeth_card *) card_ptr; + net_dev = card->dev; #ifdef CONFIG_QETH_PERF_STATS - card->perf_stats.inbound_time += qeth_get_micros() - - card->perf_stats.inbound_start_time; - card->perf_stats.inbound_cnt++; + card->perf_stats.inbound_start_time = qeth_get_micros(); #endif - skb->dev = card->dev; - if (netif_queue_stopped(card->dev)) { - dev_kfree_skb_irq(skb); - card->stats.rx_dropped++; - } else { - rxrc = netif_rx(skb); - card->dev->last_rx = jiffies; - card->stats.rx_packets++; - card->stats.rx_bytes += skb->len; - } + if (status & QDIO_STATUS_LOOK_FOR_ERROR) { + if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ + QETH_DBF_TEXT(trace, 1,"qdinchk"); + QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card)); + QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count); + QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status); + qeth_schedule_recovery(card); + return; } -clear_buffer: - qeth_put_buffer_pool_entry(card, buf->pool_entry); - /* give buffer back to hardware */ - qeth_queue_input_buffer(card, current_buf); - current_buf = (current_buf + 1) % QDIO_MAX_BUFFERS_PER_Q; - buf = &card->qdio.in_q->bufs[current_buf]; } - /* set index for next time the tasklet is scheduled */ - card->qdio.in_q->next_buf_to_process = current_buf; + for (i = first_element; i < (first_element + count); ++i) { + index = i % QDIO_MAX_BUFFERS_PER_Q; + buffer = &card->qdio.in_q->bufs[index]; + if (!((status == QDIO_STATUS_LOOK_FOR_ERROR) && + qeth_check_for_inbound_error(buffer, qdio_err, siga_err))) + qeth_process_inbound_buffer(card, buffer, index); + /* clear buffer and give back to hardware */ + qeth_put_buffer_pool_entry(card, buffer->pool_entry); + qeth_queue_input_buffer(card, index); + } } static inline int @@ -2524,10 +2498,11 @@ * switches between PACKING and non-PACKING state if needed. * has to be called holding queue->lock */ -static inline void +static inline int qeth_switch_packing_state(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; + int flush_count = 0; QETH_DBF_TEXT(trace, 6, "swipack"); if (!queue->do_pack) { @@ -2554,6 +2529,7 @@ BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); if (buffer->next_element_to_fill > 0) { buffer->state = QETH_QDIO_BUF_PRIMED; + flush_count++; atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % @@ -2561,6 +2537,25 @@ } } } + return flush_count; +} + +static inline void +qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue, int under_int) +{ + struct qeth_qdio_out_buffer *buffer; + + buffer = &queue->bufs[queue->next_buf_to_fill]; + BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); + if (buffer->next_element_to_fill > 0){ + /* it's a packing buffer */ + buffer->state = QETH_QDIO_BUF_PRIMED; + atomic_inc(&queue->used_buffers); + qeth_flush_buffers(queue, under_int, queue->next_buf_to_fill, + 1); + queue->next_buf_to_fill = + (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; + } } static void @@ -2603,58 +2598,12 @@ atomic_dec(&queue->set_pci_flags_count); qeth_clear_output_buffer(card, buffer); + atomic_dec(&queue->used_buffers); } - atomic_sub(count, &queue->used_buffers); - - //if (!atomic_read(&queue->set_pci_flags_count)) - tasklet_schedule(&queue->tasklet); netif_wake_queue(card->dev); } -static void -qeth_qdio_output_tasklet(unsigned long data) -{ - struct qeth_qdio_out_q *queue = (struct qeth_qdio_out_q *) data; - struct qeth_qdio_out_buffer *buffer; - int index; - int count; - - QETH_DBF_TEXT(trace, 6, "outtlet"); - - /* flush all PRIMED buffers */ - index = queue->next_buf_to_flush; - count = 0; - while (queue->bufs[index].state == QETH_QDIO_BUF_PRIMED) { - count++; - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - } - qeth_flush_buffers(queue, 0, queue->next_buf_to_flush, count); - queue->next_buf_to_flush = index; - - /* flush a buffer with data, if no more PCIs are - * outstanding */ - if (!atomic_read(&queue->set_pci_flags_count)){ - spin_lock(&queue->lock); - buffer = &queue->bufs[index]; - if (buffer->state == QETH_QDIO_BUF_PRIMED){ - qeth_flush_buffers(queue, 0, index, 1); - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - queue->next_buf_to_flush = index; - } else if (buffer->next_element_to_fill > 0){ - /* it's a packing buffer */ - BUG_ON(index != queue->next_buf_to_fill); - buffer->state = QETH_QDIO_BUF_PRIMED; - atomic_inc(&queue->used_buffers); - qeth_flush_buffers(queue, 0, index, 1); - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - queue->next_buf_to_flush = index; - queue->next_buf_to_fill = index; - } - spin_unlock(&queue->lock); - } -} - static char* qeth_create_qib_param_field(struct qeth_card *card) { @@ -2858,8 +2807,6 @@ card->qdio.in_buf_pool.buf_count = card->qdio.init_pool.buf_count; INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list); INIT_LIST_HEAD(&card->qdio.init_pool.entry_list); - card->qdio.in_tasklet.data = (unsigned long) card; - card->qdio.in_tasklet.func = qeth_qdio_input_tasklet; /* outbound */ card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; @@ -2903,13 +2850,9 @@ } card->qdio.out_qs[i]->card = card; card->qdio.out_qs[i]->next_buf_to_fill = 0; - card->qdio.out_qs[i]->next_buf_to_flush = 0; card->qdio.out_qs[i]->do_pack = 0; atomic_set(&card->qdio.out_qs[i]->used_buffers,0); atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0); - card->qdio.out_qs[i]->tasklet.data = - (unsigned long) card->qdio.out_qs[i]; - card->qdio.out_qs[i]->tasklet.func = qeth_qdio_output_tasklet; spin_lock_init(&card->qdio.out_qs[i]->lock); } return 0; @@ -3653,6 +3596,8 @@ struct qeth_hdr *hdr; struct qeth_qdio_out_buffer *buffer; int elements_needed; + int start_index; + int flush_count = 0; int rc; QETH_DBF_TEXT(trace, 6, "dosndpkt"); @@ -3671,9 +3616,7 @@ } spin_lock(&queue->lock); - /* check if we need to switch packing state of this queue */ - if (card->info.type != QETH_CARD_TYPE_IQD) - qeth_switch_packing_state(queue); + start_index = queue->next_buf_to_fill; buffer = &queue->bufs[queue->next_buf_to_fill]; BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); if (queue->do_pack){ @@ -3682,6 +3625,7 @@ < elements_needed){ /* ... no -> set state PRIMED */ buffer->state = QETH_QDIO_BUF_PRIMED; + flush_count++; atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % @@ -3695,18 +3639,24 @@ PRINT_WARN("qeth_do_send_packet: error during " "qeth_fill_buffer."); card->stats.tx_dropped++; - spin_unlock(&queue->lock); - return rc; - } - if (buffer->state == QETH_QDIO_BUF_PRIMED){ + } else if (buffer->state == QETH_QDIO_BUF_PRIMED){ /* next time fill the next buffer */ + flush_count++; atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; } - spin_unlock(&queue->lock); + /* check if we need to switch packing state of this queue */ + if (card->info.type != QETH_CARD_TYPE_IQD) + flush_count += qeth_switch_packing_state(queue); + + if (flush_count) + qeth_flush_buffers(queue, 0, start_index, flush_count); - tasklet_schedule(&queue->tasklet); + if (!atomic_read(&queue->set_pci_flags_count)) + qeth_flush_buffers_on_no_pci(queue, 0); + + spin_unlock(&queue->lock); return rc; } @@ -4424,6 +4374,10 @@ if (!ipm->is_multicast) continue; iptodo = qeth_get_addr_buffer(ipm->proto); + if (!iptodo) { + QETH_DBF_TEXT(trace, 2, "dmcnomem"); + continue; + } memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr)); iptodo->users = iptodo->users * -1; if (!__qeth_insert_ip_todo(card, iptodo, 0)) @@ -4694,14 +4648,14 @@ if (addr->proto == QETH_PROT_IPV4) { QETH_DBF_TEXT(trace, 2,"setaddr4"); - QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, sizeof(int)); + QETH_DBF_HEX(trace, 3, &addr->u.a4.addr, sizeof(int)); } else if (addr->proto == QETH_PROT_IPV6) { QETH_DBF_TEXT(trace, 2, "setaddr6"); - QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4); - QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); + QETH_DBF_HEX(trace,3,&addr->u.a6.addr,8); + QETH_DBF_HEX(trace,3,((char *)&addr->u.a6.addr)+8,8); } else { QETH_DBF_TEXT(trace, 2, "setaddr?"); - QETH_DBF_HEX(trace, 4, addr, sizeof(struct qeth_ipaddr)); + QETH_DBF_HEX(trace, 3, addr, sizeof(struct qeth_ipaddr)); } do { if (addr->is_multicast) @@ -4732,14 +4686,14 @@ if (addr->proto == QETH_PROT_IPV4) { QETH_DBF_TEXT(trace, 2,"deladdr4"); - QETH_DBF_HEX(trace, 2, &addr->u.a4.addr, sizeof(int)); + QETH_DBF_HEX(trace, 3, &addr->u.a4.addr, sizeof(int)); } else if (addr->proto == QETH_PROT_IPV6) { QETH_DBF_TEXT(trace, 2, "deladdr6"); - QETH_DBF_HEX(trace, 2, &addr->u.a6.addr, - sizeof(struct in6_addr)); + QETH_DBF_HEX(trace,3,&addr->u.a6.addr,8); + QETH_DBF_HEX(trace,3,((char *)&addr->u.a6.addr)+8,8); } else { QETH_DBF_TEXT(trace, 2, "deladdr?"); - QETH_DBF_HEX(trace, 2, addr, sizeof(struct qeth_ipaddr)); + QETH_DBF_HEX(trace, 3, addr, sizeof(struct qeth_ipaddr)); } if (addr->is_multicast) rc = qeth_send_setdelmc(card, addr, IPA_CMD_DELIPM); @@ -6515,26 +6469,24 @@ addr->u.a4.addr = ifa->ifa_address; addr->u.a4.mask = ifa->ifa_mask; addr->type = QETH_IP_TYPE_NORMAL; - } + } else + goto out; + switch(event) { case NETDEV_UP: - if (addr) { - if (!qeth_add_ip(card, addr)) - kfree(addr); - } + if (!qeth_add_ip(card, addr)) + kfree(addr); break; case NETDEV_DOWN: - if (addr) { - if (!qeth_delete_ip(card, addr)) - kfree(addr); - } + if (!qeth_delete_ip(card, addr)) + kfree(addr); break; default: break; } qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD); schedule_work(&card->kernel_thread_starter); - +out: return NOTIFY_DONE; } @@ -6570,26 +6522,24 @@ memcpy(&addr->u.a6.addr, &ifa->addr, sizeof(struct in6_addr)); addr->u.a6.pfxlen = ifa->prefix_len; addr->type = QETH_IP_TYPE_NORMAL; - } + } else + goto out; + switch(event) { case NETDEV_UP: - if (addr){ - if (!qeth_add_ip(card, addr)) - kfree(addr); - } + if (!qeth_add_ip(card, addr)) + kfree(addr); break; case NETDEV_DOWN: - if (addr){ - if (!qeth_delete_ip(card, addr)) - kfree(addr); - } + if (!qeth_delete_ip(card, addr)) + kfree(addr); break; default: break; } qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD); schedule_work(&card->kernel_thread_starter); - +out: return NOTIFY_DONE; } diff -Nru a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c --- a/drivers/s390/scsi/zfcp_aux.c Sun Apr 25 22:39:32 2004 +++ b/drivers/s390/scsi/zfcp_aux.c Sun Apr 25 22:39:32 2004 @@ -29,7 +29,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_AUX_REVISION "$Revision: 1.105 $" +#define ZFCP_AUX_REVISION "$Revision: 1.107 $" #include "zfcp_ext.h" @@ -1078,17 +1078,6 @@ { char dbf_name[20]; - /* debug feature area which records fsf request sequence numbers */ - sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s", - zfcp_get_busid_by_adapter(adapter)); - adapter->req_dbf = debug_register(dbf_name, - ZFCP_REQ_DBF_INDEX, - ZFCP_REQ_DBF_AREAS, - ZFCP_REQ_DBF_LENGTH); - debug_register_view(adapter->req_dbf, &debug_hex_ascii_view); - debug_set_level(adapter->req_dbf, ZFCP_REQ_DBF_LEVEL); - debug_text_event(adapter->req_dbf, 1, "zzz"); - /* debug feature area which records SCSI command failures (hostbyte) */ rwlock_init(&adapter->cmd_dbf_lock); sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s", @@ -1131,7 +1120,7 @@ debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view); debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL); - if (adapter->req_dbf && adapter->cmd_dbf && adapter->abort_dbf && + if (adapter->cmd_dbf && adapter->abort_dbf && adapter->in_els_dbf && adapter->erp_dbf) return 0; @@ -1147,7 +1136,6 @@ zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) { debug_unregister(adapter->erp_dbf); - debug_unregister(adapter->req_dbf); debug_unregister(adapter->cmd_dbf); debug_unregister(adapter->abort_dbf); debug_unregister(adapter->in_els_dbf); diff -Nru a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h --- a/drivers/s390/scsi/zfcp_def.h Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/scsi/zfcp_def.h Sun Apr 25 22:39:31 2004 @@ -33,7 +33,7 @@ #define ZFCP_DEF_H /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_DEF_REVISION "$Revision: 1.71 $" +#define ZFCP_DEF_REVISION "$Revision: 1.72 $" /*************************** INCLUDES *****************************************/ @@ -450,19 +450,12 @@ #define ZFCP_ERP_DBF_LEVEL 3 #define ZFCP_ERP_DBF_NAME "zfcperp" -#define ZFCP_REQ_DBF_INDEX 1 -#define ZFCP_REQ_DBF_AREAS 1 -#define ZFCP_REQ_DBF_LENGTH 8 -#define ZFCP_REQ_DBF_LEVEL 1 -#define ZFCP_REQ_DBF_NAME "zfcpreq" - #define ZFCP_CMD_DBF_INDEX 2 #define ZFCP_CMD_DBF_AREAS 1 #define ZFCP_CMD_DBF_LENGTH 8 #define ZFCP_CMD_DBF_LEVEL 3 #define ZFCP_CMD_DBF_NAME "zfcpcmd" - #define ZFCP_ABORT_DBF_INDEX 2 #define ZFCP_ABORT_DBF_AREAS 1 #define ZFCP_ABORT_DBF_LENGTH 8 @@ -475,11 +468,6 @@ #define ZFCP_IN_ELS_DBF_LEVEL 6 #define ZFCP_IN_ELS_DBF_NAME "zfcpels" -#define ZFCP_ADAPTER_REQ_DBF_INDEX 4 -#define ZFCP_ADAPTER_REQ_DBF_AREAS 1 -#define ZFCP_ADAPTER_REQ_DBF_LENGTH 8 -#define ZFCP_ADAPTER_REQ_DBF_LEVEL 6 - /******************** LOGGING MACROS AND DEFINES *****************************/ /* @@ -986,7 +974,6 @@ struct zfcp_port *nameserver_port; /* adapter's nameserver */ debug_info_t *erp_dbf; /* S/390 debug features */ debug_info_t *abort_dbf; - debug_info_t *req_dbf; debug_info_t *in_els_dbf; debug_info_t *cmd_dbf; rwlock_t cmd_dbf_lock; diff -Nru a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c --- a/drivers/s390/scsi/zfcp_erp.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/scsi/zfcp_erp.c Sun Apr 25 22:39:31 2004 @@ -31,7 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_ERP_REVISION "$Revision: 1.49 $" +#define ZFCP_ERP_REVISION "$Revision: 1.51 $" #include "zfcp_ext.h" @@ -1865,6 +1865,7 @@ case ZFCP_ERP_FAILED : atomic_inc(&port->erp_counter); if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) + zfcp_erp_port_failed(port); break; case ZFCP_ERP_EXIT : /* nothing */ @@ -1874,7 +1875,6 @@ if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */ result = ZFCP_ERP_EXIT; - zfcp_erp_port_failed(port); } return result; @@ -2397,8 +2397,6 @@ ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed " "(retval=%d)\n", retval_cleanup); } - else - debug_text_event(adapter->req_dbf, 1, "q_clean"); failed_qdio_establish: atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); @@ -2468,10 +2466,8 @@ ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed on " "adapter %s\n", zfcp_get_busid_by_adapter(adapter)); - } else { + } else ZFCP_LOG_DEBUG("queues cleaned up\n"); - debug_text_event(adapter->req_dbf, 1, "q_clean"); - } /* * First we had to stop QDIO operation. @@ -2834,9 +2830,10 @@ /* nameserver port may live again */ atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &adapter->nameserver_port->status); - zfcp_erp_port_reopen(adapter->nameserver_port, 0); - erp_action->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; - retval = ZFCP_ERP_CONTINUES; + if (zfcp_erp_port_reopen(adapter->nameserver_port, 0) >= 0) { + erp_action->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; + retval = ZFCP_ERP_CONTINUES; + } else retval = ZFCP_ERP_FAILED; break; } /* else nameserver port is already open, fall through */ @@ -2972,6 +2969,10 @@ debug_text_event(adapter->erp_dbf, 3, "p_pstnsw_w"); debug_event(adapter->erp_dbf, 3, &erp_action->port->wwpn, sizeof (wwn_t)); + if (atomic_test_mask( + ZFCP_STATUS_COMMON_ERP_FAILED, + &adapter->nameserver_port->status)) + zfcp_erp_port_failed(erp_action->port); zfcp_erp_action_ready(erp_action); } } @@ -3357,7 +3358,7 @@ struct zfcp_adapter *adapter, struct zfcp_port *port, struct zfcp_unit *unit) { - int retval = -1; + int retval = 1; struct zfcp_erp_action *erp_action = NULL; int stronger_action = 0; u32 status = 0; @@ -3376,7 +3377,7 @@ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status)) - goto out; + return -EIO; debug_event(adapter->erp_dbf, 4, &action, sizeof (int)); /* check whether we really need this */ diff -Nru a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c --- a/drivers/s390/scsi/zfcp_fsf.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/scsi/zfcp_fsf.c Sun Apr 25 22:39:31 2004 @@ -29,7 +29,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_FSF_C_REVISION "$Revision: 1.43 $" +#define ZFCP_FSF_C_REVISION "$Revision: 1.45 $" #include "zfcp_ext.h" @@ -379,13 +379,6 @@ zfcp_get_busid_by_adapter(adapter), fsf_req->qtcb->prefix.prot_status_qual. sequence_error.exp_req_seq_no); - debug_text_event(adapter->req_dbf, 1, "exp_seq!"); - debug_event(adapter->req_dbf, 1, - &fsf_req->qtcb->prefix.prot_status_qual. - sequence_error.exp_req_seq_no, 4); - debug_text_event(adapter->req_dbf, 1, "qtcb_seq!"); - debug_exception(adapter->req_dbf, 1, - &fsf_req->qtcb->prefix.req_seq_no, 4); debug_text_exception(adapter->erp_dbf, 0, "prot_seq_err"); /* restart operation on this adapter */ zfcp_erp_adapter_reopen(adapter, 0); @@ -891,7 +884,6 @@ ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n", zfcp_get_busid_by_adapter(adapter)); - debug_text_event(adapter->req_dbf, 1, "unso"); goto out; failed_req_send: @@ -1277,10 +1269,6 @@ case FSF_FCP_COMMAND_DOES_NOT_EXIST: ZFCP_LOG_FLAGS(2, "FSF_FCP_COMMAND_DOES_NOT_EXIST\n"); retval = 0; - debug_text_event(new_fsf_req->adapter->req_dbf, 3, "no_exist"); - debug_event(new_fsf_req->adapter->req_dbf, 3, - &new_fsf_req->qtcb->bottom.support.req_handle, - sizeof (unsigned long)); debug_text_event(new_fsf_req->adapter->erp_dbf, 3, "fsf_s_no_exist"); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; @@ -3373,10 +3361,6 @@ * (need this for look up on normal command completion) */ fsf_req->data.send_fcp_command_task.scsi_cmnd = scsi_cmnd; - debug_text_event(adapter->req_dbf, 3, "fsf/sc"); - debug_event(adapter->req_dbf, 3, &fsf_req, sizeof (unsigned long)); - debug_event(adapter->req_dbf, 3, &scsi_cmnd, sizeof (unsigned long)); - fsf_req->data.send_fcp_command_task.start_jiffies = jiffies; fsf_req->data.send_fcp_command_task.unit = unit; ZFCP_LOG_DEBUG("unit=%p, fcp_lun=0x%016Lx\n", unit, unit->fcp_lun); @@ -3517,12 +3501,9 @@ send_failed: no_fit: failed_scsi_cmnd: - /* dequeue new FSF request previously enqueued */ - debug_text_event(adapter->req_dbf, 3, "fail_sc"); - debug_event(adapter->req_dbf, 3, &scsi_cmnd, sizeof (unsigned long)); - zfcp_fsf_req_free(fsf_req); fsf_req = NULL; + scsi_cmnd->host_scribble = NULL; success: failed_req_create: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); @@ -4267,14 +4248,9 @@ * the new eh */ /* always call back */ - debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:"); - debug_event(fsf_req->adapter->req_dbf, 2, &scpnt, - sizeof (unsigned long)); - debug_event(fsf_req->adapter->req_dbf, 2, &scpnt->scsi_done, - sizeof (unsigned long)); - debug_event(fsf_req->adapter->req_dbf, 2, &fsf_req, - sizeof (unsigned long)); + (scpnt->scsi_done) (scpnt); + /* * We must hold this lock until scsi_done has been called. * Otherwise we may call scsi_done after abort regarding this @@ -4954,15 +4930,6 @@ "to request queue.\n"); } else { req_queue->distance_from_int = new_distance_from_int; - debug_text_event(adapter->req_dbf, 1, "o:a/seq"); - debug_event(adapter->req_dbf, 1, &fsf_req, - sizeof (unsigned long)); - if (likely(inc_seq_no)) { - debug_event(adapter->req_dbf, 1, - &adapter->fsf_req_seq_no, sizeof (u32)); - } else { - debug_text_event(adapter->req_dbf, 1, "nocb"); - } /* * increase FSF sequence counter - * this must only be done for request successfully enqueued to diff -Nru a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c --- a/drivers/s390/scsi/zfcp_qdio.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/scsi/zfcp_qdio.c Sun Apr 25 22:39:31 2004 @@ -28,7 +28,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_QDIO_C_REVISION "$Revision: 1.16 $" +#define ZFCP_QDIO_C_REVISION "$Revision: 1.18 $" #include "zfcp_ext.h" @@ -485,10 +485,6 @@ struct zfcp_fsf_req *fsf_req; int retval = 0; - /* Note: seq is entered later */ - debug_text_event(adapter->req_dbf, 1, "i:a/seq"); - debug_event(adapter->req_dbf, 1, &sbale_addr, sizeof (unsigned long)); - /* invalid (per convention used in this driver) */ if (unlikely(!sbale_addr)) { ZFCP_LOG_NORMAL("bug: invalid reqid\n"); @@ -505,11 +501,6 @@ fsf_req, fsf_req->adapter, adapter); retval = -EINVAL; goto out; - } - /* debug feature stuff (test for QTCB: remember new unsol. status!) */ - if (likely(fsf_req->qtcb)) { - debug_event(adapter->req_dbf, 1, - &fsf_req->qtcb->prefix.req_seq_no, sizeof (u32)); } ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb); diff -Nru a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c --- a/drivers/s390/scsi/zfcp_scsi.c Sun Apr 25 22:39:31 2004 +++ b/drivers/s390/scsi/zfcp_scsi.c Sun Apr 25 22:39:31 2004 @@ -31,7 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_SCSI_REVISION "$Revision: 1.59 $" +#define ZFCP_SCSI_REVISION "$Revision: 1.60 $" #include @@ -297,10 +297,6 @@ if (unlikely(tmp < 0)) { ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); retval = SCSI_MLQUEUE_HOST_BUSY; - } else { - debug_text_event(adapter->req_dbf, 3, "q_scpnt"); - debug_event(adapter->req_dbf, 3, &scpnt, - sizeof (unsigned long)); } out: diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Sun Apr 25 22:39:31 2004 +++ b/drivers/scsi/ide-scsi.c Sun Apr 25 22:39:31 2004 @@ -146,7 +146,7 @@ idescsi_discard_data (drive, bcount); return; } - count = IDE_MIN (pc->sg->length - pc->b_count, bcount); + count = min(pc->sg->length - pc->b_count, bcount); buf = page_address(pc->sg->page) + pc->sg->offset; atapi_input_bytes (drive, buf + pc->b_count, count); bcount -= count; pc->b_count += count; @@ -168,7 +168,7 @@ idescsi_output_zeros (drive, bcount); return; } - count = IDE_MIN (pc->sg->length - pc->b_count, bcount); + count = min(pc->sg->length - pc->b_count, bcount); buf = page_address(pc->sg->page) + pc->sg->offset; atapi_output_bytes (drive, buf + pc->b_count, count); bcount -= count; pc->b_count += count; @@ -396,7 +396,7 @@ if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) { printk(", rst = "); scsi_buf = pc->scsi_cmd->request_buffer; - hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen)); + hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen)); } else printk("\n"); } } @@ -413,7 +413,7 @@ static inline unsigned long get_timeout(idescsi_pc_t *pc) { - return IDE_MAX(WAIT_CMD, pc->timeout - jiffies); + return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies); } static int idescsi_expiry(ide_drive_t *drive) @@ -580,7 +580,7 @@ scsi->pc=pc; /* Set the current packet command */ pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ + bcount.all = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ feature.all = 0; if (drive->using_dma && rq->bio) { diff -Nru a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c --- a/drivers/scsi/qla2xxx/qla_os.c Sun Apr 25 22:39:32 2004 +++ b/drivers/scsi/qla2xxx/qla_os.c Sun Apr 25 22:39:32 2004 @@ -402,6 +402,7 @@ .attr = { .name = "fw_dump", .mode = S_IRUSR | S_IWUSR, + .owner = THIS_MODULE, }, .size = 0, .read = qla2x00_sysfs_read_fw_dump, @@ -415,6 +416,7 @@ .attr = { .name = "nvram", .mode = S_IRUSR | S_IWUSR, + .owner = THIS_MODULE, }, .size = sizeof(nvram_t), .read = qla2x00_sysfs_read_nvram, diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig --- a/drivers/serial/Kconfig Sun Apr 25 22:39:31 2004 +++ b/drivers/serial/Kconfig Sun Apr 25 22:39:31 2004 @@ -205,7 +205,7 @@ depends on ARM_AMBA select SERIAL_CORE help - This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have + This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M here. diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/class/cdc-acm.c Sun Apr 25 22:39:31 2004 @@ -573,53 +573,61 @@ struct usb_device *dev; struct acm *acm; struct usb_host_config *cfacm; - struct usb_interface *data; - struct usb_host_interface *ifcom, *ifdata; - struct usb_endpoint_descriptor *epctrl, *epread, *epwrite; + struct usb_interface *data = NULL; + struct usb_host_interface *ifcom, *ifdata = NULL; + struct usb_endpoint_descriptor *epctrl = NULL; + struct usb_endpoint_descriptor *epread = NULL; + struct usb_endpoint_descriptor *epwrite = NULL; int readsize, ctrlsize, minor, j; unsigned char *buf; dev = interface_to_usbdev (intf); - cfacm = dev->actconfig; - - for (j = 0; j < cfacm->desc.bNumInterfaces - 1; j++) { - - if (usb_interface_claimed(cfacm->interface[j]) || - usb_interface_claimed(cfacm->interface[j + 1])) - continue; + cfacm = dev->actconfig; + + /* We know we're probe()d with the control interface. */ + ifcom = intf->cur_altsetting; - /* We know we're probe()d with the control interface. - * FIXME ACM doesn't guarantee the data interface is + /* ACM doesn't guarantee the data interface is * adjacent to the control interface, or that if one - * is there it's not for call management ... so use - * the cdc union descriptor whenever there is one. + * is there it's not for call management ... so find + * it */ - ifcom = intf->cur_altsetting; - if (intf == cfacm->interface[j]) { - ifdata = cfacm->interface[j + 1]->cur_altsetting; - data = cfacm->interface[j + 1]; - } else if (intf == cfacm->interface[j + 1]) { + for (j = 0; j < cfacm->desc.bNumInterfaces; j++) { ifdata = cfacm->interface[j]->cur_altsetting; data = cfacm->interface[j]; - } else - continue; - if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) - continue; + if (ifdata->desc.bInterfaceClass == 10 && + ifdata->desc.bNumEndpoints == 2) { + epctrl = &ifcom->endpoint[0].desc; + epread = &ifdata->endpoint[0].desc; + epwrite = &ifdata->endpoint[1].desc; + + if ((epctrl->bEndpointAddress & 0x80) != 0x80 || + (epctrl->bmAttributes & 3) != 3 || + (epread->bmAttributes & 3) != 2 || + (epwrite->bmAttributes & 3) != 2 || + ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) + goto next_interface; + + if ((epread->bEndpointAddress & 0x80) != 0x80) { + epread = &ifdata->endpoint[1].desc; + epwrite = &ifdata->endpoint[0].desc; + } + dbg("found data interface at %d\n", j); + break; + } else { +next_interface: + ifdata = NULL; + data = NULL; + } + } + + /* there's been a problem */ + if (!ifdata) { + dbg("interface not found (%p)\n", ifdata); + return -ENODEV; - epctrl = &ifcom->endpoint[0].desc; - epread = &ifdata->endpoint[0].desc; - epwrite = &ifdata->endpoint[1].desc; - - if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || - (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || - ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) - continue; - - if ((epread->bEndpointAddress & 0x80) != 0x80) { - epread = &ifdata->endpoint[1].desc; - epwrite = &ifdata->endpoint[0].desc; } for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); @@ -696,16 +704,21 @@ acm->line.databits = 8; acm_set_line(acm, &acm->line); - usb_driver_claim_interface(&acm_driver, data, acm); + if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) { + err("claim failed"); + usb_free_urb(acm->ctrlurb); + usb_free_urb(acm->readurb); + usb_free_urb(acm->writeurb); + kfree(acm); + kfree(buf); + return j; + } tty_register_device(acm_tty_driver, minor, &intf->dev); acm_table[minor] = acm; usb_set_intfdata (intf, acm); return 0; - } - - return -EIO; } static void acm_disconnect(struct usb_interface *intf) diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/core/hcd-pci.c Sun Apr 25 22:39:31 2004 @@ -284,6 +284,11 @@ dev_dbg (hcd->self.controller, "suspend D%d --> D%d\n", dev->current_state, state); + if (pci_find_capability(dev, PCI_CAP_ID_PM)) { + dev_dbg(hcd->self.controller, "No PM capability\n"); + return 0; + } + switch (hcd->state) { case USB_STATE_HALT: dev_dbg (hcd->self.controller, "halted; hcd not suspended\n"); diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Sun Apr 25 22:39:32 2004 +++ b/drivers/usb/gadget/ether.c Sun Apr 25 22:39:32 2004 @@ -120,6 +120,7 @@ unsigned long todo; #define WORK_RX_MEMORY 0 int rndis_config; + u8 host_mac [ETH_ALEN]; }; /* This version autoconfigures as much as possible at run-time. @@ -159,9 +160,8 @@ /* For hardware that can talk RNDIS and either of the above protocols, * use this ID ... the windows INF files will know it. Unless it's - * used with CDC Ethernet, Linux hosts will need updates to choose the - * non-MSFT configuration, either in the kernel (2.4) or else from a - * hotplug script (2.6). + * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose + * the non-RNDIS configuration. */ #define RNDIS_VENDOR_NUM 0x0525 /* NetChip */ #define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ @@ -1334,8 +1334,10 @@ struct eth_dev *dev = ep->driver_data; /* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */ + spin_lock(&dev->lock); if (rndis_msg_parser (dev->rndis_config, (u8 *) req->buf)) ERROR(dev, "%s: rndis parse error\n", __FUNCTION__ ); + spin_unlock(&dev->lock); } #endif /* RNDIS */ @@ -1486,14 +1488,14 @@ || !dev->config || ctrl->wIndex > 1) break; - if (!dev->cdc && ctrl->wIndex != 0) + if (!(dev->cdc || dev->rndis) && ctrl->wIndex != 0) break; - /* if carrier is on, data interface is active. */ - *(u8 *)req->buf = - ((ctrl->wIndex == 1) && netif_carrier_ok (dev->net)) - ? 1 - : 0, + /* for CDC, iff carrier is on, data interface is active. */ + if (dev->rndis || ctrl->wIndex != 1) + *(u8 *)req->buf = 0; + else + *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; value = min (ctrl->wLength, (u16) 1); break; @@ -1552,6 +1554,7 @@ memcpy (req->buf, buf, value); req->complete = rndis_response_complete; } + /* else stalls ... spec says to avoid that */ } break; #endif /* RNDIS */ @@ -1590,6 +1593,8 @@ eth_reset_config (dev); spin_unlock_irqrestore (&dev->lock, flags); + /* FIXME RNDIS should enter RNDIS_UNINITIALIZED */ + /* next we may get setup() calls to enumerate new connections; * or an unbind() during shutdown (including removing module). */ @@ -2376,19 +2381,19 @@ */ random_ether_addr(net->dev_addr); -#ifdef DEV_CONFIG_CDC /* ... another address for the host, on the other end of the * link, gets exported through CDC (see CDC spec table 41) + * and RNDIS. */ - if (cdc) { - u8 node_id [ETH_ALEN]; - - random_ether_addr(node_id); + if (cdc || rndis) { + random_ether_addr(dev->host_mac); +#ifdef DEV_CONFIG_CDC snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - node_id [0], node_id [1], node_id [2], - node_id [3], node_id [4], node_id [5]); - } + dev->host_mac [0], dev->host_mac [1], + dev->host_mac [2], dev->host_mac [3], + dev->host_mac [4], dev->host_mac [5]); #endif + } if (rndis) { status = rndis_init(); @@ -2448,10 +2453,11 @@ net->dev_addr [2], net->dev_addr [3], net->dev_addr [4], net->dev_addr [5]); -#ifdef DEV_CONFIG_CDC - if (cdc) - INFO (dev, "CDC host enet %s\n", ethaddr); -#endif + if (cdc || rndis) + INFO (dev, "HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->host_mac [0], dev->host_mac [1], + dev->host_mac [2], dev->host_mac [3], + dev->host_mac [4], dev->host_mac [5]); #ifdef CONFIG_USB_ETH_RNDIS if (rndis) { @@ -2468,6 +2474,7 @@ } /* these set up a lot of the OIDs that RNDIS needs */ + rndis_set_host_mac (dev->rndis_config, dev->host_mac); if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats)) goto fail0; diff -Nru a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c --- a/drivers/usb/gadget/rndis.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/gadget/rndis.c Sun Apr 25 22:39:31 2004 @@ -37,6 +37,16 @@ #include "rndis.h" +/* The driver for your USB chip needs to support ep0 OUT to work with + * RNDIS, plus the same three descriptors as CDC Ethernet. + * + * Windows hosts need an INF file like Documentation/usb/linux.inf + */ + +#ifndef __LITTLE_ENDIAN +#warning this code is missing all cpu_to_leXX() calls ... +#endif + #if 0 #define DEBUG if (rndis_debug) printk static int rndis_debug = 0; @@ -89,8 +99,12 @@ static void currentFilter2devFlags (u32 currentFilter, struct net_device *dev) { + /* FIXME the filter is supposed to control what gets + * forwarded from gadget to host; but dev->flags controls + * reporting from host to gadget ... + */ +#if 0 if (!dev) return; - if (currentFilter & NDIS_PACKET_TYPE_MULTICAST) dev->flags |= IFF_MULTICAST; if (currentFilter & NDIS_PACKET_TYPE_BROADCAST) @@ -99,8 +113,13 @@ dev->flags |= IFF_ALLMULTI; if (currentFilter & NDIS_PACKET_TYPE_PROMISCUOUS) dev->flags |= IFF_PROMISC; +#endif } +/* FIXME OMITTED OIDs, that RNDIS-on-USB "must" support, include + * - power management (OID_PNP_CAPABILITIES, ...) + * - network wakeup (OID_PNP_ENABLE_WAKE_UP, ...) + */ /* NDIS Functions */ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) @@ -114,8 +133,6 @@ if (!resp) return -ENOMEM; - if (!resp) return -ENOMEM; - switch (OID) { /* mandatory */ case OID_GEN_SUPPORTED_LIST: @@ -178,7 +195,8 @@ case OID_GEN_LINK_SPEED: DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); length = 4; - if (rndis_per_dev_params [configNr].media_state) + if (rndis_per_dev_params [configNr].media_state + == NDIS_MEDIA_STATE_DISCONNECTED) *((u32 *) resp + 6) = 0; else *((u32 *) resp + 6) = rndis_per_dev_params [configNr].speed; @@ -611,15 +629,10 @@ case OID_802_3_PERMANENT_ADDRESS: DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 6; + length = ETH_ALEN; memcpy ((u8 *) resp + 24, - rndis_per_dev_params [configNr].dev->dev_addr, + rndis_per_dev_params [configNr].host_mac, length); - /* - * we need a MAC address and hope that - * (our MAC + 1) is not in use - */ - *((u8 *) resp + 29) += 1; retval = 0; } else { *((u32 *) resp + 6) = 0; @@ -631,15 +644,10 @@ case OID_802_3_CURRENT_ADDRESS: DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 6; + length = ETH_ALEN; memcpy ((u8 *) resp + 24, - rndis_per_dev_params [configNr].dev->dev_addr, + rndis_per_dev_params [configNr].host_mac, length); - /* - * we need a MAC address and hope that - * (our MAC + 1) is not in use - */ - *((u8 *) resp + 29) += 1; retval = 0; } break; @@ -746,22 +754,38 @@ rndis_set_cmplt_type *resp; int i, retval = -ENOTSUPP; struct rndis_config_parameter *param; - - if (!r) return -ENOMEM; + struct rndis_params *params; + u8 *cp; + + if (!r) + return -ENOMEM; resp = (rndis_set_cmplt_type *) r->buf; - - if (!resp) return -ENOMEM; - + if (!resp) + return -ENOMEM; + + cp = (u8 *)resp; + switch (OID) { case OID_GEN_CURRENT_PACKET_FILTER: DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); - currentFilter2devFlags ((u32) ((u8 *) resp + 28), - rndis_per_dev_params [configNr].dev); + params = &rndis_per_dev_params [configNr]; + currentFilter2devFlags(cp[28], params->dev); retval = 0; - if ((u32) ((u8 *) resp + 28)) - rndis_per_dev_params [configNr].state = RNDIS_INITIALIZED; - else - rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + + /* this call has a significant side effect: it's + * what makes the packet flow start and stop, like + * activating the CDC Ethernet altsetting. + */ + if (cp[28]) { + params->state = RNDIS_DATA_INITIALIZED; + netif_carrier_on(params->dev); + if (netif_running(params->dev)) + netif_wake_queue (params->dev); + } else { + params->state = RNDIS_INITIALIZED; + netif_carrier_off (params->dev); + netif_stop_queue (params->dev); + } break; case OID_802_3_MULTICAST_LIST: @@ -937,10 +961,9 @@ { rndis_keepalive_cmplt_type *resp; rndis_resp_t *r; - - /* respond only in RNDIS_INITIALIZED state */ - if (rndis_per_dev_params [configNr].state != RNDIS_INITIALIZED) - return 0; + + /* host "should" check only in RNDIS_DATA_INITIALIZED state */ + r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type)); resp = (rndis_keepalive_cmplt_type *) r->buf; if (!resp) return -ENOMEM; @@ -1004,35 +1027,48 @@ RNDIS_STATUS_MEDIA_DISCONNECT); } +void rndis_set_host_mac (int configNr, const u8 *addr) +{ + rndis_per_dev_params [configNr].host_mac = addr; +} + /* * Message Parser */ int rndis_msg_parser (u8 configNr, u8 *buf) { u32 MsgType, MsgLength, *tmp; + struct rndis_params *params; - if (!buf) return -ENOMEM; + if (!buf) + return -ENOMEM; tmp = (u32 *) buf; MsgType = *tmp; MsgLength = *(tmp + 1); - if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; + if (configNr >= RNDIS_MAX_CONFIGS) + return -ENOTSUPP; + params = &rndis_per_dev_params [configNr]; + /* For USB: responses may take up to 10 seconds */ switch (MsgType) { - case REMOTE_NDIS_INIZIALIZE_MSG: - DEBUG(KERN_INFO "%s: REMOTE_NDIS_INIZIALIZE_MSG\n", + case REMOTE_NDIS_INITIALIZE_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); - rndis_per_dev_params [configNr].state = RNDIS_INITIALIZED; + params->state = RNDIS_INITIALIZED; return rndis_init_response (configNr, (rndis_init_msg_type *) buf); - break; case REMOTE_NDIS_HALT_MSG: DEBUG(KERN_INFO "%s: REMOTE_NDIS_HALT_MSG\n", __FUNCTION__ ); - rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + params->state = RNDIS_UNINITIALIZED; + if (params->dev) { + netif_carrier_off (params->dev); + netif_stop_queue (params->dev); + } return 0; case REMOTE_NDIS_QUERY_MSG: @@ -1040,29 +1076,26 @@ __FUNCTION__ ); return rndis_query_response (configNr, (rndis_query_msg_type *) buf); - break; case REMOTE_NDIS_SET_MSG: DEBUG(KERN_INFO "%s: REMOTE_NDIS_SET_MSG\n", __FUNCTION__ ); return rndis_set_response (configNr, (rndis_set_msg_type *) buf); - break; case REMOTE_NDIS_RESET_MSG: DEBUG(KERN_INFO "%s: REMOTE_NDIS_RESET_MSG\n", __FUNCTION__ ); return rndis_reset_response (configNr, (rndis_reset_msg_type *) buf); - break; case REMOTE_NDIS_KEEPALIVE_MSG: + /* For USB: host does this every 5 seconds */ DEBUG(KERN_INFO "%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __FUNCTION__ ); return rndis_keepalive_response (configNr, (rndis_keepalive_msg_type *) buf); - break; default: printk (KERN_ERR "%s: unknown RNDIS Message Type 0x%08X\n", @@ -1240,9 +1273,15 @@ "vendor ID : 0x%08X\n" "vendor : %s\n", param->confignr, (param->used) ? "y" : "n", - (param->state) - ? "RNDIS_INITIALIZED" - : "RNDIS_UNINITIALIZED", + ({ char *s = "?"; + switch (param->state) { + case RNDIS_UNINITIALIZED: + s = "RNDIS_UNINITIALIZED"; break; + case RNDIS_INITIALIZED: + s = "RNDIS_INITIALIZED"; break; + case RNDIS_DATA_INITIALIZED: + s = "RNDIS_DATA_INITIALIZED"; break; + }; s; }), param->medium, (param->media_state) ? 0 : param->speed*100, (param->media_state) ? "disconnected" : "connected", @@ -1353,7 +1392,7 @@ return 0; } -void __exit rndis_exit (void) +void rndis_exit (void) { u8 i; char name [4]; diff -Nru a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h --- a/drivers/usb/gadget/rndis.h Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/gadget/rndis.h Sun Apr 25 22:39:31 2004 @@ -38,7 +38,7 @@ */ /* Message Set for Connectionless (802.3) Devices */ -#define REMOTE_NDIS_INIZIALIZE_MSG 0x00000002U /* Initialize device */ +#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */ #define REMOTE_NDIS_HALT_MSG 0x00000003U #define REMOTE_NDIS_QUERY_MSG 0x00000004U #define REMOTE_NDIS_SET_MSG 0x00000005U @@ -280,6 +280,7 @@ u32 medium; u32 speed; u32 media_state; + const u8 *host_mac; struct net_device *dev; struct net_device_stats *stats; u32 vendorID; @@ -301,11 +302,13 @@ int rndis_rm_hdr (u8 *buf, u32 *length); u8 *rndis_get_next_response (int configNr, u32 *length); void rndis_free_response (int configNr, u8 *buf); + int rndis_signal_connect (int configNr); int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); +extern void rndis_set_host_mac (int configNr, const u8 *addr); int __init rndis_init (void); -void __exit rndis_exit (void); +void rndis_exit (void); #endif /* _LINUX_RNDIS_H */ diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/host/ehci-hcd.c Sun Apr 25 22:39:31 2004 @@ -330,6 +330,7 @@ { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; + unsigned count = 256/4; spin_lock_init (&ehci->lock); @@ -345,16 +346,21 @@ temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); else temp = 0; - while (temp) { + while (temp && count--) { u32 cap; - pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), temp, &cap); + pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), + temp, &cap); ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp); switch (cap & 0xff) { case 1: /* BIOS/SMM/... handoff */ if (bios_handoff (ehci, temp, cap) != 0) return -EOPNOTSUPP; break; + case 0x0a: /* appendix C */ + ehci_dbg (ehci, "debug registers, BAR %d offset %d\n", + (cap >> 29) & 0x07, (cap >> 16) & 0x0fff); + break; case 0: /* illegal reserved capability */ ehci_warn (ehci, "illegal capability!\n"); cap = 0; @@ -364,6 +370,10 @@ } temp = (cap >> 8) & 0xff; } + if (!count) { + ehci_err (ehci, "bogus capabilities ... PCI problems!\n"); + return -EIO; + } #endif /* cache this readonly data; minimize PCI reads */ @@ -577,7 +587,8 @@ /* root hub is shut down separately (first, when possible) */ spin_lock_irq (&ehci->lock); - ehci_work (ehci, NULL); + if (ehci->async) + ehci_work (ehci, NULL); spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c --- a/drivers/usb/host/ehci-hub.c Sun Apr 25 22:39:32 2004 +++ b/drivers/usb/host/ehci-hub.c Sun Apr 25 22:39:32 2004 @@ -252,14 +252,18 @@ /* force reset to complete */ writel (temp & ~PORT_RESET, &ehci->regs->port_status [wIndex]); - do { - temp = readl ( - &ehci->regs->port_status [wIndex]); - udelay (10); - } while (temp & PORT_RESET); + retval = handshake ( + &ehci->regs->port_status [wIndex], + PORT_RESET, 0, 500); + if (retval != 0) { + ehci_err (ehci, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } /* see what we found out */ - temp = check_reset_complete (ehci, wIndex, temp); + temp = check_reset_complete (ehci, wIndex, + readl (&ehci->regs->port_status [wIndex])); } // don't show wPortStatus if it's owned by a companion hc diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/host/uhci-hcd.c Sun Apr 25 22:39:31 2004 @@ -382,6 +382,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; + __u32 newlink; if (!qh) return; @@ -390,8 +391,24 @@ * Only go through the hoops if it's actually linked in */ if (!list_empty(&qh->list)) { - pqh = list_entry(qh->list.prev, struct uhci_qh, list); + /* If our queue is nonempty, make the next URB the head */ + if (!list_empty(&qh->urbp->queue_list)) { + struct urb_priv *nurbp; + + nurbp = list_entry(qh->urbp->queue_list.next, + struct urb_priv, queue_list); + nurbp->queued = 0; + list_add(&nurbp->qh->list, &qh->list); + newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; + } else + newlink = qh->link; + + /* Fix up the previous QH's queue to link to either + * the new head of this queue or the start of the + * next endpoint's queue. */ + pqh = list_entry(qh->list.prev, struct uhci_qh, list); + pqh->link = newlink; if (pqh->urbp) { struct list_head *head, *tmp; @@ -403,28 +420,19 @@ tmp = tmp->next; - turbp->qh->link = qh->link; + turbp->qh->link = newlink; } } - - pqh->link = qh->link; mb(); + /* Leave qh->link in case the HC is on the QH now, it will */ /* continue the rest of the schedule */ qh->element = UHCI_PTR_TERM; - /* If our queue is nonempty, make the next URB the head */ - if (!list_empty(&qh->urbp->queue_list)) { - struct urb_priv *nurbp; - - nurbp = list_entry(qh->urbp->queue_list.next, - struct urb_priv, queue_list); - nurbp->queued = 0; - list_add_tail(&nurbp->qh->list, &qh->list); - } list_del_init(&qh->list); } + list_del_init(&qh->urbp->queue_list); qh->urbp = NULL; /* Check to see if the remove list is empty. Set the IOC bit */ @@ -579,7 +587,7 @@ pltd->link = UHCI_PTR_TERM; } - list_del_init(&urbp->queue_list); + /* urbp->queue_list is handled in uhci_remove_qh() */ } static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c --- a/drivers/usb/misc/tiglusb.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/misc/tiglusb.c Sun Apr 25 22:39:31 2004 @@ -3,7 +3,7 @@ * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver. * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org). * - * Copyright (C) 2001-2002: + * Copyright (C) 2001-2004: * Romain Lievin * Julien BLACHE * under the terms of the GNU General Public License. @@ -20,6 +20,8 @@ * 1.04, Julien: clean-up & fixes; Romain: 2.4 backport. * 1.05, Randy Dunlap: bug fix with the timeout parameter (divide-by-zero). * 1.06, Romain: synched with 2.5, version/firmware changed (confusing). + * 1.07, Romain: fixed bad use of usb_clear_halt (invalid argument); + * timeout argument checked in ioctl + clean-up. */ #include @@ -38,8 +40,8 @@ /* * Version Information */ -#define DRIVER_VERSION "1.06" -#define DRIVER_AUTHOR "Romain Lievin & Julien Blache " +#define DRIVER_VERSION "1.07" +#define DRIVER_AUTHOR "Romain Lievin & Julien Blache " #define DRIVER_DESC "TI-GRAPH LINK USB (aka SilverLink) driver" #define DRIVER_LICENSE "GPL" @@ -72,15 +74,15 @@ { unsigned int pipe; - pipe = usb_sndbulkpipe (dev, 1); - if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) { - err ("clear_pipe (r), request failed"); + pipe = usb_sndbulkpipe (dev, 2); + if (usb_clear_halt (dev, pipe)) { + err ("clear_pipe (w), request failed"); return -1; } - pipe = usb_sndbulkpipe (dev, 2); - if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) { - err ("clear_pipe (w), request failed"); + pipe = usb_rcvbulkpipe (dev, 1); + if (usb_clear_halt (dev, pipe)) { + err ("clear_pipe (r), request failed"); return -1; } @@ -181,17 +183,16 @@ pipe = usb_rcvbulkpipe (s->dev, 1); result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read, - &bytes_read, HZ * 10 / timeout); + &bytes_read, (HZ * timeout) / 10); if (result == -ETIMEDOUT) { /* NAK */ - ret = result; - if (!bytes_read) { + if (!bytes_read) dbg ("quirk !"); - } warn ("tiglusb_read, NAK received."); + ret = result; goto out; } else if (result == -EPIPE) { /* STALL -- shouldn't happen */ warn ("clear_halt request to remove STALL condition."); - if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe))) + if (usb_clear_halt (s->dev, pipe)) err ("clear_halt, request failed"); clear_device (s->dev); ret = result; @@ -243,7 +244,7 @@ pipe = usb_sndbulkpipe (s->dev, 2); result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write, - &bytes_written, HZ * 10 / timeout); + &bytes_written, (HZ * timeout) / 10); if (result == -ETIMEDOUT) { /* NAK */ warn ("tiglusb_write, NAK received."); @@ -251,7 +252,7 @@ goto out; } else if (result == -EPIPE) { /* STALL -- shouldn't happen */ warn ("clear_halt request to remove STALL condition."); - if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe))) + if (usb_clear_halt (s->dev, pipe)) err ("clear_halt, request failed"); clear_device (s->dev); ret = result; @@ -292,15 +293,16 @@ switch (cmd) { case IOCTL_TIUSB_TIMEOUT: - timeout = arg; // timeout value in tenth of seconds + if (arg > 0) + timeout = arg; + else + ret = -EINVAL; break; case IOCTL_TIUSB_RESET_DEVICE: - dbg ("IOCTL_TIGLUSB_RESET_DEVICE"); if (clear_device (s->dev)) ret = -EIO; break; case IOCTL_TIUSB_RESET_PIPES: - dbg ("IOCTL_TIGLUSB_RESET_PIPES"); if (clear_pipes (s->dev)) ret = -EIO; break; @@ -447,7 +449,7 @@ #ifndef MODULE /* - * You can use 'tiusb=timeout' + * You can use 'tiusb=timeout' to set timeout. */ static int __init tiglusb_setup (char *str) @@ -457,10 +459,11 @@ str = get_options (str, ARRAY_SIZE (ints), ints); if (ints[0] > 0) { - timeout = ints[1]; + if (ints[1] > 0) + timeout = ints[1]; + else + info ("tiglusb: wrong timeout value (0), using default value."); } - if (timeout <= 0) - timeout = TIMAXTIME; return 1; } @@ -501,9 +504,6 @@ } info (DRIVER_DESC ", version " DRIVER_VERSION); - - if (timeout <= 0) - timeout = TIMAXTIME; return 0; } diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/net/usbnet.c Sun Apr 25 22:39:31 2004 @@ -2107,8 +2107,12 @@ static int pl_reset (struct usbnet *dev) { - return pl_set_QuickLink_features (dev, + /* some units seem to need this reset, others reject it utterly. + * FIXME be more like "naplink" or windows drivers. + */ + (void) pl_set_QuickLink_features (dev, PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); + return 0; } static const struct driver_info prolific_info = { diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/serial/ftdi_sio.c Sun Apr 25 22:39:31 2004 @@ -463,8 +463,6 @@ { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { } /* Terminating entry */ }; @@ -566,6 +564,8 @@ { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { } /* Terminating entry */ }; diff -Nru a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c --- a/drivers/usb/storage/dpcm.c Sun Apr 25 22:39:31 2004 +++ b/drivers/usb/storage/dpcm.c Sun Apr 25 22:39:31 2004 @@ -56,7 +56,8 @@ /* * LUN 0 corresponds to the CompactFlash card reader. */ - return usb_stor_CB_transport(srb, us); + ret = usb_stor_CB_transport(srb, us); + break; #ifdef CONFIG_USB_STORAGE_SDDR09 case 1: @@ -71,12 +72,14 @@ srb->device->lun = 0; us->srb->device->lun = 0; ret = sddr09_transport(srb, us); srb->device->lun = 1; us->srb->device->lun = 1; + break; - return ret; #endif default: US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun); - return USB_STOR_TRANSPORT_ERROR; + ret = USB_STOR_TRANSPORT_ERROR; + break; } + return ret; } diff -Nru a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c --- a/drivers/video/fbcmap.c Sun Apr 25 22:39:31 2004 +++ b/drivers/video/fbcmap.c Sun Apr 25 22:39:31 2004 @@ -207,7 +207,7 @@ /** * fb_set_cmap - set the colormap * @cmap: frame buffer colormap structure - * @kspc: boolean, 0 copy local, 1 get_user() function + * @kspc: boolean, 1 copy local, 0 get_user() function * @info: frame buffer info structure * * Sets the colormap @cmap for a screen of device @info. diff -Nru a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt --- a/fs/Kconfig.binfmt Sun Apr 25 22:39:31 2004 +++ b/fs/Kconfig.binfmt Sun Apr 25 22:39:31 2004 @@ -44,7 +44,7 @@ config BINFMT_AOUT tristate "Kernel support for a.out and ECOFF binaries" - depends on (X86 && !X86_64) || ALPHA || ARM || M68K || MIPS || SPARC32 + depends on (X86 && !X86_64) || ALPHA || ARM || M68K || SPARC32 ---help--- A.out (Assembler.OUTput) is a set of formats for libraries and executables used in the earliest versions of UNIX. Linux used diff -Nru a/fs/block_dev.c b/fs/block_dev.c --- a/fs/block_dev.c Sun Apr 25 22:39:32 2004 +++ b/fs/block_dev.c Sun Apr 25 22:39:32 2004 @@ -251,6 +251,7 @@ { memset(bdev, 0, sizeof(*bdev)); sema_init(&bdev->bd_sem, 1); + sema_init(&bdev->bd_mount_sem, 1); INIT_LIST_HEAD(&bdev->bd_inodes); INIT_LIST_HEAD(&bdev->bd_list); inode_init_once(&ei->vfs_inode); diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c Sun Apr 25 22:39:31 2004 +++ b/fs/buffer.c Sun Apr 25 22:39:31 2004 @@ -227,6 +227,77 @@ return sync_blockdev(bdev); } +/** + * freeze_bdev -- lock a filesystem and force it into a consistent state + * @bdev: blockdevice to lock + * + * This takes the block device bd_mount_sem to make sure no new mounts + * happen on bdev until thaw_bdev() is called. + * If a superblock is found on this device, we take the s_umount semaphore + * on it to make sure nobody unmounts until the snapshot creation is done. + */ +struct super_block *freeze_bdev(struct block_device *bdev) +{ + struct super_block *sb; + + down(&bdev->bd_mount_sem); + sb = get_super(bdev); + if (sb && !(sb->s_flags & MS_RDONLY)) { + sb->s_frozen = SB_FREEZE_WRITE; + wmb(); + + sync_inodes_sb(sb, 0); + DQUOT_SYNC(sb); + + lock_super(sb); + if (sb->s_dirt && sb->s_op->write_super) + sb->s_op->write_super(sb); + unlock_super(sb); + + if (sb->s_op->sync_fs) + sb->s_op->sync_fs(sb, 1); + + sync_blockdev(sb->s_bdev); + sync_inodes_sb(sb, 1); + + sb->s_frozen = SB_FREEZE_TRANS; + wmb(); + + sync_blockdev(sb->s_bdev); + + if (sb->s_op->write_super_lockfs) + sb->s_op->write_super_lockfs(sb); + } + + sync_blockdev(bdev); + return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ +} +EXPORT_SYMBOL(freeze_bdev); + +/** + * thaw_bdev -- unlock filesystem + * @bdev: blockdevice to unlock + * @sb: associated superblock + * + * Unlocks the filesystem and marks it writeable again after freeze_bdev(). + */ +void thaw_bdev(struct block_device *bdev, struct super_block *sb) +{ + if (sb) { + BUG_ON(sb->s_bdev != bdev); + + if (sb->s_op->unlockfs) + sb->s_op->unlockfs(sb); + sb->s_frozen = SB_UNFROZEN; + wmb(); + wake_up(&sb->s_wait_unfrozen); + drop_super(sb); + } + + up(&bdev->bd_mount_sem); +} +EXPORT_SYMBOL(thaw_bdev); + /* * sync everything. Start out by waking pdflush, because that writes back * all queues in parallel. @@ -1755,7 +1826,7 @@ if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { lock_buffer(bh); } else if (test_set_buffer_locked(bh)) { - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); continue; } if (test_clear_buffer_dirty(bh)) { diff -Nru a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS --- a/fs/cifs/AUTHORS Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/AUTHORS Sun Apr 25 22:39:31 2004 @@ -26,5 +26,6 @@ ------------------------------------- Thanks to those in the community who have submitted detailed bug reports and debug of problems they have found: Jochen Dolze, David Blaine, -Rene Scharfe, Martin Josefsson, Alexander Wild and others. +Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, +Urban Widmark, Massimiliano Ferrero, Howard Owen and others. diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/CHANGES Sun Apr 25 22:39:31 2004 @@ -1,3 +1,108 @@ +Version 1.10 +------------ +Fix reconnection (and certain failed mounts) to properly wake up the +blocked users thread so it does not seem hung (in some cases was blocked +until the cifs receive timeout expired). Fix spurious error logging +to kernel log when application with open network files killed. + +Version 1.09 +------------ +Fix /proc/fs module unload warning message (that could be logged +to the kernel log). Fix intermittent failure in connectathon +test7 (hardlink count not immediately refreshed in case in which +inode metadata can be incorrectly kept cached when time near zero) + +Version 1.08 +------------ +Allow file_mode and dir_mode (specified at mount time) to be enforced +locally (the server already enforced its own ACLs too) for servers +that do not report the correct mode (do not support the +CIFS Unix Extensions). + +Version 1.07 +------------ +Fix some small memory leaks in some unmount error paths. Fix major leak +of cache pages in readpages causing multiple read oriented stress +testcases (including fsx, and even large file copy) to fail over time. + +Version 1.06 +------------ +Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. +This allows files that differ only in case and improves performance of file +creation and file open to such servers. Fix semaphore conflict which causes +slow delete of open file to Samba (which unfortunately can cause an oplock +break to self while vfs_unlink held i_sem) which can hang for 20 seconds. + +Version 1.05 +------------ +fixes to cifs_readpages for fsx test case + +Version 1.04 +------------ +Fix caching data integrity bug when extending file size especially when no +oplock on file. Fix spurious logging of valid already parsed mount options +that are parsed outside of the cifs vfs such as nosuid. + + +Version 1.03 +------------ +Connect to server when port number override not specified, and tcp port +unitialized. Reset search to restart at correct file when kernel routine +filldir returns error during large directory searches (readdir). + +Version 1.02 +------------ +Fix caching problem when files opened by multiple clients in which +page cache could contain stale data, and write through did +not occur often enough while file was still open when read ahead +(read oplock) not allowed. Treat "sep=" when first mount option +as an overrride of comma as the default separator between mount +options. + +Version 1.01 +------------ +Allow passwords longer than 16 bytes. Allow null password string. + +Version 1.00 +------------ +Gracefully clean up failed mounts when attempting to mount to servers such as +Windows 98 that terminate tcp sessions during prototocol negotiation. Handle +embedded commas in mount parsing of passwords. + +Version 0.99 +------------ +Invalidate local inode cached pages on oplock break and when last file +instance is closed so that the client does not continue using stale local +copy rather than later modified server copy of file. Do not reconnect +when server drops the tcp session prematurely before negotiate +protocol response. Fix oops in roepen_file when dentry freed. Allow +the support for CIFS Unix Extensions to be disabled via proc interface. + +Version 0.98 +------------ +Fix hang in commit_write during reconnection of open files under heavy load. +Fix unload_nls oops in a mount failure path. Serialize writes to same socket +which also fixes any possible races when cifs signatures are enabled in SMBs +being sent out of signature sequence number order. + +Version 0.97 +------------ +Fix byte range locking bug (endian problem) causing bad offset and +length. + +Version 0.96 +------------ +Fix oops (in send_sig) caused by CIFS unmount code trying to +wake up the demultiplex thread after it had exited. Do not log +error on harmless oplock release of closed handle. + +Version 0.95 +------------ +Fix unsafe global variable usage and password hash failure on gcc 3.3.1 +Fix problem reconnecting secondary mounts to same server after session +failure. Fix invalid dentry - race in mkdir when directory gets created +by another client between the lookup and mkdir. + Version 0.94 ------------ Fix to list processing in reopen_files. Fix reconnection when server hung diff -Nru a/fs/cifs/Makefile b/fs/cifs/Makefile --- a/fs/cifs/Makefile Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/Makefile Sun Apr 25 22:39:31 2004 @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o diff -Nru a/fs/cifs/README b/fs/cifs/README --- a/fs/cifs/README Sun Apr 25 22:39:32 2004 +++ b/fs/cifs/README Sun Apr 25 22:39:32 2004 @@ -1,30 +1,30 @@ -The CIFS VFS support for Linux supports many advanced network filesystem -features such as heirarchical dfs like namespace, hardlinks, locking and more. -It was designed to comply with the SNIA CIFS Technical Reference (which supersedes -the 1992 X/Open SMB Standard) as well as to perform best practice practical -interoperability with Windows 2000, Windows XP, Samba and equivalent +The CIFS VFS support for Linux supports many advanced network filesystem +features such as heirarchical dfs like namespace, hardlinks, locking and more. +It was designed to comply with the SNIA CIFS Technical Reference (which +supersedes the 1992 X/Open SMB Standard) as well as to perform best practice +practical interoperability with Windows 2000, Windows XP, Samba and equivalent servers. -For questions or bug reports please contact sfrench@samba.org (sfrench@us.ibm.com) +For questions or bug reports please contact: + sfrench@samba.org (sfrench@us.ibm.com) Build instructions: ================== For Linux 2.4: -1a) Get the linux kernel source with cifs vfs already in it -from bitkeeper via bk://cifs.bkbits.net/linux-2.4 -or -1b) Get the kernel source (e.g.from http://www.kernel.org) +1) Get the kernel source (e.g.from http://www.kernel.org) and download the cifs vfs source (see the project page at http://us1.samba.org/samba/Linux_CIFS_client.html) and change directory into the top of the kernel directory then patch the kernel (e.g. "patch -p1 < cifs_24.patch") to add the cifs vfs to your kernel configure options if it has not already been added (e.g. current SuSE and UL -users do not need to do not need that patch since the cifs vfs is +users do not need to apply the cifs_24.patch since the cifs vfs is already in the kernel configure menu) and then mkdir linux/fs/cifs and then copy the current cifs vfs files from the cifs download to your kernel build directory e.g. + cp /fs/cifs/* to /fs/cifs + 2) make menuconfig (or make xconfig) 3) select cifs from within the network filesystem choices 4) save and exit @@ -53,56 +53,105 @@ If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on the CIFS VFS web site) copy it to the same directory in which mount.smbfs and -similar files reside (usually /sbin). Although the helper software is required, -mount.cifs is recommended. Eventually the Samba 3.0 utility program "net" -may also be helpful since it may someday provide easier mount syntax for users used -to Windows e.g. - net use -Note that running Winbind on all of your Linux clients is useful in -in mapping Uids and Gids consistently to the proper network user. - -Samba Considerations -==================== -To get the maximum benefit from the CIFS VFS, we recommend using a server that -supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or -Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. -Note that uid, gid and file permissions will display default values if you do -not have a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or -later). To enable the Unix CIFS Extensions in the Samba server, add the line: +similar files reside (usually /sbin). Although the helper software is not +required, mount.cifs is recommended. Eventually the Samba 3.0 utility program +"net" may also be helpful since it may someday provide easier mount syntax for +users who are used to Windows e.g. net use +Note that running the Winbind pam/nss module (logon service) on all of your +Linux clients is useful in mapping Uids and Gids consistently across the +domain to the proper network user. The mount.cifs mount helper can be +trivially built from Samba 3.0 or later source e.g. by executing: + + gcc samba/source/client/mount.cifs.c -o mount.cifs + +Note that when the mount.cifs utility is run suid (allowing user mounts), +in order to reduce risks, the "nosuid" mount flag is passed in on mount to +disallow execution of an suid program mounted on the remote target. +When mount is executed as root, nosuid is not passed in by default, +and execution of suid programs on the remote target would be enabled +by default. This can be changed, as with nfs and other filesystems, +by simply specifying "nosuid" among the mount options. For user mounts +though to be able to pass the suid flag to mount requires rebuilding +mount.cifs with the following flag: + + gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs + +There is a corresponding manual page for cifs mounting in the Samba 3.0 and +later source tree in docs/manpages/mount.cifs.8 + +Samba Considerations +==================== +To get the maximum benefit from the CIFS VFS, we recommend using a server that +supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or +Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba +2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add +the line: + unix extensions = yes -to your smb.conf file on the server. Note that the following smb.conf settings are -also useful (on the Samba server) when the majority of clients are Unix -or Linux: + +to your smb.conf file on the server. Note that the following smb.conf settings +are also useful (on the Samba server) when the majority of clients are Unix or +Linux: + case sensitive = yes - delete readonly = yes -Some administrators also change the "map archive" and the "create mask" parameters -from their default values. Creating special devices (mknod) remotely may require -specifying a mkdev function to Samba. For more information on these see the manual -pages ("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the -smbfs vfs, does not read the smb.conf on the client system (the few optional settings -are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later -includes a fix that allows the CIFS VFS to delete open files (required for strict -POSIX compliance). Windows Servers already supported this feature. + delete readonly = yes + +Some administrators also change the "map archive" and the "create mask" +parameters from their default values. Creating special devices (mknod) remotely +may require specifying a mkdev function to Samba. For more information on these +see the manual pages ("man smb.conf") on the Samba server system. Note that the +cifs vfs, unlike the smbfs vfs, does not read the smb.conf on the client system +(the few optional settings are passed in on mount via -o parameters instead). +Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete +open files (required for strict POSIX compliance). Windows Servers already +supported this feature. Use instructions: ================ -Once the CIFS VFS support is built into the kernel or installed as a module (cifs.o), -you can use mount syntax like the following to access Samba or Windows servers: +Once the CIFS VFS support is built into the kernel or installed as a module +(cifs.o), you can use mount syntax like the following to access Samba or Windows +servers: + mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword -after -o the following cifs vfs specific options are supported: + +Before -o the option -v may be specified to make the mount.cifs +mount helper display the mount steps more verbosely. +After -o the following commonly used cifs vfs specific options +are supported: + user= pass= domain= -TCP names (in addition to ip addresses) will be available when the mount helper -(mount.cifs) is complete + +Other cifs mount options are described below. Use of TCP names (in addition to +ip addresses) is available if the mount helper (mount.cifs) is installed. If +you do not trust the server to which are mounted, or if you do not have +cifs signing enabled (and the physical network is insecure), consider use +of the standard mount options "noexec" and "nosuid" to reduce the risk of +running an altered binary on your local system (downloaded from a hostile server +or altered by a hostile router). + +When using the mount helper mount.cifs, passwords may be specified via alternate +mechanisms, instead of specifying it after -o using the normal "pass=" syntax +on the command line: +1) By including it in a credential file. Specify credentials=filename as one +of the mount options. Credential files contain two lines + username=someuser + password=your_password +2) By specifying the password in the PASSWD environment variable (similarly +the user name can be taken from the USER environment variable). + +If no password is provided, mount.cifs will prompt for password entry Restrictions ============ -Servers must support the NTLM SMB dialect (which is the most recent, supported by Samba -and Windows NT, 2000 and XP and many other SMB/CIFS servers) and servers must support -either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 1001/1002 support for -"Netbios-Over-TCP/IP." Neither of these is likely to be a problem as most servers -support this. IPv6 support is planned for the future. +Servers must support the NTLM SMB dialect (which is the most recent, supported +by Samba and Windows NT, 2000 and XP and many other SMB/CIFS servers) and +servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC +1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a +problem as most servers support this. IPv6 support is planned for the future. CIFS VFS Mount Options ====================== @@ -141,54 +190,97 @@ ro mount network share read-only version used to distinguish different versions of the mount helper utility (not typically needed) + sep if first mount option (after the -o), overrides + the comma as the separator between the mount + parms. e.g. + -o user=myname,password=mypassword,domain=mydom + could be passed instead with period as the separator by + -o sep=.user=myname.password=mypassword.domain=mydom + this might be useful when comma is contained within username + or password or domain. This option is less important + when the cifs mount helper cifs.mount (version 1.1 or later) + is used. + nosuid Do not allow remote executables with the suid bit + program to be executed. This is only meaningful for mounts + to servers such as Samba which support the CIFS Unix Extensions. + If you do not trust the servers in your network (your mount + targets) it is recommended that you specify this option for + greater security. + suid Allow remote files on this mountpoint with suid enabled to + be executed (default for mounts when executed as root, + nosuid is default for user mounts). + credentials Although ignored by the cifs kernel component, it is used by + the mount helper, mount.cifs. When mount.cifs is installed it + opens and reads the credential file specified in order + to obtain the userid and password arguments which are passed to + the cifs vfs. + guest Although ignored by the kernel component, the mount.cifs + mount helper will not prompt the user for a password + if guest is specified on the mount options. If no + password is specified a null password will be used. Misc /proc/fs/cifs Flags and Debug Info ======================================= Informational pseudo-files: - DebugData Displays information about active CIFS sessions - SimultaneousOps Counter which holds maximum number of +DebugData Displays information about active CIFS sessions +SimultaneousOps Counter which holds maximum number of simultaneous outstanding SMB/CIFS requests. - Stats Lists summary resource usage information +Stats Lists summary resource usage information Configuration pseudo-files: - MultiuserMount If set to one, more than one CIFS session to +MultiuserMount If set to one, more than one CIFS session to the same server ip address can be established if more than one uid accesses the same mount point and if the uids user/password mapping information is available. (default is 0) - PacketSigningEnabled If set to one, cifs packet signing is enabled +PacketSigningEnabled If set to one, cifs packet signing is enabled and will be used if the server requires it. If set to two, cifs packet signing is required even if the server considers packet signing optional. (default 1) - cifsFYI If set to one, additional debug information is +cifsFYI If set to one, additional debug information is logged to the system error log. (default 0) - ExtendedSecurity If set to one, SPNEGO session establishment +ExtendedSecurity If set to one, SPNEGO session establishment is allowed which enables more advanced secure CIFS session establishment (default 0) - NTLMV2Enabled If set to one, more secure password hashes +NTLMV2Enabled If set to one, more secure password hashes are used when the server supports them and when kerberos is not negotiated (default 0) - traceSMB If set to one, debug information is logged to the +traceSMB If set to one, debug information is logged to the system error log with the start of smb requests and responses (default 0) - LookupCacheEnable If set to one, inode information is kept cached +LookupCacheEnable If set to one, inode information is kept cached for one second improving performance of lookups (default 1) - OplockEnabled If set to one, safe distributed caching enabled. +OplockEnabled If set to one, safe distributed caching enabled. (default 1) +LinuxExtensionsEnabled If set to one then the client will attempt to + use the CIFS "UNIX" extensions which are optional + protocol enhancements that allow CIFS servers + to return accurate UID/GID information as well + as support symbolic links. If you use servers + such as Samba that support the CIFS Unix + extensions but do not want to use symbolic link + support and want to map the uid and gid fields + to values supplied at mount (rather than the + actual values, then set this to zero. (default 1) + +These experimental features and tracing can be enabled by changing flags in +/proc/fs/cifs (after the cifs module has been installed or built into the +kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable +tracing to the kernel message log type: -These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs -(after the cifs module has been installed or built into the kernel, e.g. insmod cifs). -To enable a feature set it to 1 e.g. to enable tracing to the kernel message log -type: echo 1 > /proc/fs/cifs/cifsFYI + and for more extensive tracing including the start of smb requests and responses + echo 1 > /proc/fs/cifs/traceSMB -Also note that "cat /proc/fs/cifs/DebugData" will display some information about the -active sessions and the shares that are mounted. NTLMv2 enablement and packet -signing will not work since they the implementation is not quite complete. Do not enable -these flags unless you are doing specific testing. Enabling extended security works to -Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not -usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which -support is not complete in the CIFS VFS yet). + +Also note that "cat /proc/fs/cifs/DebugData" will display some information about +the active sessions and the shares that are mounted. Note: NTLMv2 enablement +will not work since they its implementation is not quite complete yet. +Do not alter these configuration values unless you are doing specific testing. +Enabling extended security works to Windows 2000 Workstations and XP but not to +Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" +(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not +complete in the CIFS VFS yet). diff -Nru a/fs/cifs/TODO b/fs/cifs/TODO --- a/fs/cifs/TODO Sun Apr 25 22:39:32 2004 +++ b/fs/cifs/TODO Sun Apr 25 22:39:32 2004 @@ -1,4 +1,4 @@ -version 0.8.1 July 4th, 2003 +version 1.0.2 January 29, 2004 A Partial List of Known Problems and Missing Features ===================================================== @@ -27,8 +27,8 @@ f) Directory entry caching relies on a 1 second timer, rather than using FindNotify or equivalent. - (started) -g) There may be a few additional changes that could be done to take advantage -of recent 2.5 kernel improvements in byte-range locking +g) A few byte range testcases fail due to POSIX vs. Windows/CIFS +style byte range lock differences h) quota support @@ -36,8 +36,6 @@ which will allow us to expose dos attributes as well as real ACLs -j) finish off the mount helper, mount.cifs - (started) - k) finish writepages support (multi-page write behind for improved performance) and syncpage @@ -56,17 +54,15 @@ at a time when 8 pages or more are requested. -KNOWN BUGS (updated July 4th, 2003) +KNOWN BUGS (updated January 30, 2004) ==================================== 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that support the CIFS Unix extensions but Samba has a bug currently handling symlink text beginning with slash -2) delete of file with read-only attribute set will fail (may be ok) -3) mount helper syntax not quite matching man page -4) follow_link and readdir code does not follow dfs junctions +2) follow_link and readdir code does not follow dfs junctions but recognizes them -5) create of new files to FAT partitions on Windows servers can +3) create of new files to FAT partitions on Windows servers can succeed but still return access denied (appears to be Windows not client problem). NTFS partitions do not have this problem. diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c --- a/fs/cifs/cifs_debug.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifs_debug.c Sun Apr 25 22:39:31 2004 @@ -88,9 +88,26 @@ i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus); buf += length; - if(ses->server) + if(ses->server) { buf += sprintf(buf, "\n\tLocal Users To Same Server: %d SecMode: 0x%x", atomic_read(&ses->server->socketUseCount),ses->server->secMode); + + /* length = sprintf(buf, "\nMIDs: \n"); + buf += length; + + spin_lock(&GlobalMid_Lock); + list_for_each(tmp1, &ses->server->pending_mid_q) { + mid_entry = list_entry(tmp1, struct + mid_q_entry, + qhead); + if(mid_entry) { + length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk); + buf += length; + } + } + spin_unlock(&GlobalMid_Lock); */ + } + } read_unlock(&GlobalSMBSeslock); sprintf(buf, "\n"); @@ -127,8 +144,10 @@ buf += sprintf(buf, "\tDISCONNECTED "); } read_unlock(&GlobalSMBSeslock); + length = sprintf(buf, "\n"); buf += length; + *eof = 1; /* BB add code to dump additional info such as TCP session info now */ /* @@ -177,6 +196,9 @@ item_length = sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter); length += item_length; + buf += item_length; + item_length = sprintf(buf,"%d sessions and %d shares reconnected after failure\n",tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); + length += item_length; return length; } @@ -201,6 +223,8 @@ static write_proc_t packet_signing_enabled_write; static read_proc_t quotaEnabled_read; static write_proc_t quotaEnabled_write; +static read_proc_t linuxExtensionsEnabled_read; +static write_proc_t linuxExtensionsEnabled_write; void cifs_proc_init(void) @@ -213,62 +237,67 @@ proc_fs_cifs->owner = THIS_MODULE; create_proc_read_entry("DebugData", 0, proc_fs_cifs, - cifs_debug_data_read, 0); + cifs_debug_data_read, 0); create_proc_read_entry("SimultaneousOps", 0, proc_fs_cifs, - cifs_total_xid_read, 0); + cifs_total_xid_read, 0); create_proc_read_entry("Stats", 0, proc_fs_cifs, - cifs_stats_read, 0); + cifs_stats_read, 0); pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, - cifsFYI_read, 0); + cifsFYI_read, 0); if (pde) pde->write_proc = cifsFYI_write; pde = create_proc_read_entry("traceSMB", 0, proc_fs_cifs, - traceSMB_read, 0); + traceSMB_read, 0); if (pde) pde->write_proc = traceSMB_write; pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, - oplockEnabled_read, 0); + oplockEnabled_read, 0); if (pde) pde->write_proc = oplockEnabled_write; - pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, - quotaEnabled_read, 0); - if (pde) - pde->write_proc = quotaEnabled_write; + pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, + quotaEnabled_read, 0); + if (pde) + pde->write_proc = quotaEnabled_write; + + pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, + linuxExtensionsEnabled_read, 0); + if (pde) + pde->write_proc = linuxExtensionsEnabled_write; pde = create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, - multiuser_mount_read, 0); + multiuser_mount_read, 0); if (pde) pde->write_proc = multiuser_mount_write; pde = create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, - extended_security_read, 0); + extended_security_read, 0); if (pde) pde->write_proc = extended_security_write; pde = - create_proc_read_entry("LookupCacheEnable", 0, proc_fs_cifs, - lookupFlag_read, 0); + create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, + lookupFlag_read, 0); if (pde) pde->write_proc = lookupFlag_write; pde = create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, - ntlmv2_enabled_read, 0); + ntlmv2_enabled_read, 0); if (pde) pde->write_proc = ntlmv2_enabled_write; pde = create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, - packet_signing_enabled_read, 0); + packet_signing_enabled_read, 0); if (pde) pde->write_proc = packet_signing_enabled_write; } @@ -281,14 +310,17 @@ remove_proc_entry("DebugData", proc_fs_cifs); remove_proc_entry("cifsFYI", proc_fs_cifs); - remove_proc_entry("TraceSMB", proc_fs_cifs); + remove_proc_entry("traceSMB", proc_fs_cifs); remove_proc_entry("SimultaneousOps", proc_fs_cifs); - remove_proc_entry("TotalOps", proc_fs_cifs); + remove_proc_entry("Stats", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); remove_proc_entry("ExtendedSecurity",proc_fs_cifs); remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); + remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); + remove_proc_entry("QuotaEnabled",proc_fs_cifs); + remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); remove_proc_entry("cifs", proc_root_fs); } @@ -406,6 +438,46 @@ quotaEnabled = 0; else if (c == '1' || c == 'y' || c == 'Y') quotaEnabled = 1; + + return count; +} + +static int +linuxExtensionsEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", linuxExtEnabled); +/* could also check if quotas are enabled in kernel + as a whole first */ + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +linuxExtensionsEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + linuxExtEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + linuxExtEnabled = 1; return count; } diff -Nru a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c --- a/fs/cifs/cifs_unicode.c Sun Apr 25 22:39:32 2004 +++ b/fs/cifs/cifs_unicode.c Sun Apr 25 22:39:32 2004 @@ -25,25 +25,6 @@ #include "cifs_debug.h" /* - * NAME: toUpper() - * - * FUNCTION: Upper case ASCII string (in place) using the current codepage - * - */ - -void -toUpper(const struct nls_table *n, char *mixed_string) -{ - unsigned int i; - char temp; - - for (i = 0; i < strlen(mixed_string); i++) { - temp = mixed_string[i]; - mixed_string[i] = n->charset2upper[(int) temp]; - } -} - -/* * NAME: cifs_strfromUCS() * * FUNCTION: Convert little-endian unicode string to character string @@ -104,28 +85,3 @@ return i; } -/* - * NAME: get_UCSname2() - * - * FUNCTION: Allocate and translate to unicode string - * - */ -/*int -get_UCSname2(struct component_name *uniName, struct dentry *dentry, - struct nls_table *nls_tab) -{ - int length = dentry->d_name.len; - - if (length > 255) - return ENAMETOOLONG; - - uniName->name = kmalloc((length + 1) * sizeof (wchar_t), GFP_KERNEL); - - if (uniName->name == NULL) - return ENOSPC; - - uniName->namlen = cifs_strtoUCS(uniName->name, dentry->d_name.name, - length, nls_tab); - - return 0; -} */ diff -Nru a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h --- a/fs/cifs/cifs_unicode.h Sun Apr 25 22:39:32 2004 +++ b/fs/cifs/cifs_unicode.h Sun Apr 25 22:39:32 2004 @@ -58,25 +58,10 @@ extern struct UniCaseRange UniLowerRange[]; #endif /* UNIUPR_NOLOWER */ -/* - * directory entry argument - */ -struct component_name { - int namlen; - wchar_t *name; -}; - #ifdef __KERNEL__ int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); - -int cifs_UCSname(struct component_name *, struct dentry *, - const struct nls_table *); - -void toUpper(const struct nls_table *, char *); #endif - -#define free_UCSname(COMP) kfree((COMP)->name) /* * UniStrcat: Concatenate the second string to the first diff -Nru a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c --- a/fs/cifs/cifsencrypt.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifsencrypt.c Sun Apr 25 22:39:31 2004 @@ -74,7 +74,7 @@ rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); if(rc) - memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); @@ -88,15 +88,15 @@ char server_response_sig[8]; char what_we_think_sig_should_be[20]; - if((cifs_pdu == NULL) || (mac_key == NULL)) - return -EINVAL; + if((cifs_pdu == NULL) || (mac_key == NULL)) + return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) return 0; if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; - if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) + if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) return 0; } @@ -113,10 +113,10 @@ its signature against what the server sent */ memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); - cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; - cifs_pdu->Signature.Sequence.Reserved = 0; + cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.Reserved = 0; - rc = cifs_calculate_signature(cifs_pdu, mac_key, + rc = cifs_calculate_signature(cifs_pdu, mac_key, what_we_think_sig_should_be); if(rc) @@ -136,7 +136,7 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password) { char temp_key[16]; - if ((key == NULL) || (rn == NULL) || (password == NULL)) + if ((key == NULL) || (rn == NULL)) return -EINVAL; E_md4hash(password, temp_key); @@ -156,7 +156,7 @@ if(ses) return -EINVAL; - E_md4hash(ses->password_with_pad, temp_hash); + E_md4hash(ses->password, temp_hash); hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); user_name_len = strlen(ses->userName); @@ -165,22 +165,21 @@ dom_name_len = strlen(ses->domainName); if(dom_name_len > MAX_USERNAME_SIZE) return -EINVAL; - - + ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); - unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); - + unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); + for(i=0;icharset2upper[(int)ses->userName[i]]; ucase_buf[i] = 0; - user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); unicode_buf[user_name_len] = 0; user_name_len++; - for(i=0;icharset2upper[(int)ses->domainName[i]]; - ucase_buf[i] = 0; - dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + for(i=0;icharset2upper[(int)ses->domainName[i]]; + ucase_buf[i] = 0; + dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); unicode_buf[user_name_len + dom_name_len] = 0; hmac_md5_update((const unsigned char *) unicode_buf, @@ -200,7 +199,6 @@ hmac_md5_update(ses->server->cryptKey,8,&context); /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ - hmac_md5_final(v2_session_response,&context); } diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifsfs.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.c * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * Common Internet FileSystem (CIFS) client @@ -52,6 +52,7 @@ int traceSMB = 0; unsigned int oplockEnabled = 1; unsigned int quotaEnabled = 0; +unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; unsigned int extended_security = 0; @@ -82,6 +83,9 @@ cifs_sb = CIFS_SB(sb); if(cifs_sb == NULL) return -ENOMEM; + else + memset(cifs_sb,0,sizeof(struct cifs_sb_info)); + rc = cifs_mount(sb, cifs_sb, data, devname); @@ -123,14 +127,15 @@ iput(inode); out_mount_failed: - if(cifs_sb->local_nls) - unload_nls(cifs_sb->local_nls); - if(cifs_sb) + if(cifs_sb) { + if(cifs_sb->local_nls) + unload_nls(cifs_sb->local_nls); kfree(cifs_sb); + } return rc; } -void +static void cifs_put_super(struct super_block *sb) { int rc = 0; @@ -151,7 +156,7 @@ return; } -int +static int cifs_statfs(struct super_block *sb, struct kstatfs *buf) { int xid, rc; @@ -186,8 +191,21 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) { - /* the server does permission checks, we do not need to do it here */ - return 0; + struct cifs_sb_info *cifs_sb; + + cifs_sb = CIFS_SB(inode->i_sb); + + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { + /* the server supports the Unix-like mode bits and does its + own permission checks, and therefore we do not allow the file + mode to be overriden on these mounts - so do not do perm + check on client side */ + return 0; + } else /* file mode might have been restricted at mount time + on the client (above and beyond ACL on servers) for + servers which do not support setting and viewing mode bits, + so allowing client to check permissions is useful */ + return vfs_permission(inode, mask); } static kmem_cache_t *cifs_inode_cachep; @@ -402,24 +420,58 @@ return sb; } -ssize_t +static ssize_t cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, loff_t * poffset) { - if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { return generic_file_read(file,read_data,read_size,poffset); - else - return cifs_read(file,read_data,read_size,poffset); + } else { + /* BB do we need to lock inode from here until after invalidate? */ +/* if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); + filemap_fdatawait(file->f_dentry->d_inode->i_mapping); + }*/ +/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ + + /* BB we should make timer configurable - perhaps + by simply calling cifs_revalidate here */ + /* invalidate_remote_inode(file->f_dentry->d_inode);*/ + return generic_file_read(file,read_data,read_size,poffset); + } } -ssize_t +static ssize_t cifs_write_wrapper(struct file * file, const char *write_data, size_t write_size, loff_t * poffset) { - if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) /* check caching for write */ - return generic_file_write(file,write_data, write_size,poffset); - else - return cifs_write(file,write_data,write_size,poffset); + ssize_t written; + + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); + + /* check whether we can cache writes locally */ + written = generic_file_write(file,write_data,write_size,poffset); + if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { + if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); + } + } + return written; } @@ -476,8 +528,8 @@ }; struct file_operations cifs_file_ops = { - .read = generic_file_read, - .write = generic_file_write, + .read = cifs_read_wrapper, + .write = cifs_write_wrapper, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -485,12 +537,18 @@ .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, +#ifdef CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif }; struct file_operations cifs_dir_ops = { .readdir = cifs_readdir, .release = cifs_closedir, .read = generic_read_dir, +#ifdef CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif }; static void @@ -505,7 +563,7 @@ } } -int +static int cifs_init_inodecache(void) { cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", @@ -518,14 +576,14 @@ return 0; } -void +static void cifs_destroy_inodecache(void) { if (kmem_cache_destroy(cifs_inode_cachep)) printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); } -int +static int cifs_init_request_bufs(void) { cifs_req_cachep = kmem_cache_create("cifs_request", @@ -538,7 +596,7 @@ return 0; } -void +static void cifs_destroy_request_bufs(void) { if (kmem_cache_destroy(cifs_req_cachep)) @@ -546,7 +604,7 @@ "cifs_destroy_request_cache: error not all structures were freed\n"); } -int +static int cifs_init_mids(void) { cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", @@ -565,7 +623,7 @@ return 0; } -void +static void cifs_destroy_mids(void) { if (kmem_cache_destroy(cifs_mid_cachep)) @@ -591,32 +649,51 @@ do { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(39*HZ); + schedule_timeout(1*HZ); spin_lock(&GlobalMid_Lock); if(list_empty(&GlobalOplock_Q)) { spin_unlock(&GlobalMid_Lock); + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(39*HZ); } else { oplock_item = list_entry(GlobalOplock_Q.next, struct oplock_q_entry, qhead); if(oplock_item) { + cFYI(1,("found oplock item to write out")); pTcon = oplock_item->tcon; inode = oplock_item->pinode; netfid = oplock_item->netfid; spin_unlock(&GlobalMid_Lock); DeleteOplockQEntry(oplock_item); - if (S_ISREG(inode->i_mode)) + /* can not grab inode sem here since it would + deadlock when oplock received on delete + since vfs_unlink holds the i_sem across + the call */ + /* down(&inode->i_sem);*/ + if (S_ISREG(inode->i_mode)) { rc = filemap_fdatawrite(inode->i_mapping); - else + if(CIFS_I(inode)->clientCanCacheRead == 0) + invalidate_remote_inode(inode); + } else rc = 0; + /* up(&inode->i_sem);*/ if (rc) CIFS_I(inode)->write_behind_rc = rc; cFYI(1,("Oplock flush inode %p rc %d",inode,rc)); - rc = CIFSSMBLock(0, pTcon, netfid, - 0 /* len */ , 0 /* offset */, 0, - 0, LOCKING_ANDX_OPLOCK_RELEASE, - 0 /* wait flag */); - cFYI(1,("Oplock release rc = %d ",rc)); + + /* releasing a stale oplock after recent reconnection + of smb session using a now incorrect file + handle is not a data integrity issue but do + not bother sending an oplock release if session + to server still is disconnected since oplock + already released by the server in that case */ + if(pTcon->tidStatus != CifsNeedReconnect) { + rc = CIFSSMBLock(0, pTcon, netfid, + 0 /* len */ , 0 /* offset */, 0, + 0, LOCKING_ANDX_OPLOCK_RELEASE, + 0 /* wait flag */); + cFYI(1,("Oplock release rc = %d ",rc)); + } } else spin_unlock(&GlobalMid_Lock); } @@ -640,6 +717,9 @@ */ atomic_set(&sesInfoAllocCount, 0); atomic_set(&tconInfoAllocCount, 0); + atomic_set(&tcpSesReconnectCount, 0); + atomic_set(&tconInfoReconnectCount, 0); + atomic_set(&bufAllocCount, 0); atomic_set(&midCount, 0); GlobalCurrentXid = 0; diff -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h --- a/fs/cifs/cifsfs.h Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifsfs.h Sun Apr 25 22:39:31 2004 @@ -60,8 +60,6 @@ extern int cifs_setattr(struct dentry *, struct iattr *); extern struct inode_operations cifs_file_inode_ops; -extern void cifs_truncate_file(struct inode *); - extern struct inode_operations cifs_symlink_inode_ops; /* Functions related to files and directories */ @@ -80,6 +78,7 @@ extern struct file_operations cifs_dir_ops; extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); +extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *); /* Functions related to dir entries */ extern struct dentry_operations cifs_dentry_ops; diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h --- a/fs/cifs/cifsglob.h Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifsglob.h Sun Apr 25 22:39:31 2004 @@ -16,6 +16,7 @@ * */ #include +#include #include "cifs_fs_sb.h" /* * The sizes of various internal tables and strings @@ -55,6 +56,10 @@ #define TRUE 1 #endif +#ifndef XATTR_DOS_ATTRIB +#define XATTR_DOS_ATTRIB "user.DOSATTRIB" +#endif + /* * This information is kept on every Server we know about. * @@ -83,6 +88,13 @@ Kerberos /* Kerberos via SPNEGO */ }; +enum protocolEnum { + IPV4 = 0, + IPV6, + SCTP + /* Netbios frames protocol not supported at this time */ +}; + /* ***************************************************************** * Except the CIFS PDUs themselves all the @@ -94,13 +106,16 @@ char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ struct socket *ssocket; - struct sockaddr_in sockAddr; + union { + struct sockaddr_in sockAddr; + struct sockaddr_in6 sockAddr6; + } addr; wait_queue_head_t response_q; struct list_head pending_mid_q; void *Server_NlsInfo; /* BB - placeholder for future NLS info */ unsigned short server_codepage; /* codepage for the server */ unsigned long ip_address; /* IP addr for the server if known */ - unsigned long svType; /* computer type */ + enum protocolEnum protocolType; char versionMajor; char versionMinor; int svlocal:1; /* local server or remote */ @@ -161,7 +176,7 @@ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ char userName[MAX_USERNAME_SIZE + 1]; char domainName[MAX_USERNAME_SIZE + 1]; - char password_with_pad[CIFS_ENCPWD_SIZE]; + char * password; }; /* @@ -175,13 +190,14 @@ struct cifsSesInfo *ses; /* pointer to session associated with */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ char *nativeFileSystem; - __u16 tid; /* The 2 byte transaction id */ + __u16 tid; /* The 2 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; - atomic_t useCount; /* how many mounts (explicit or implicit refer to this share */ + atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ FILE_SYSTEM_DEVICE_INFO fsDevInfo; - FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* note file system name may be truncated - but very unlikely */ + FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; + int retry:1; /* BB add field for back pointer to sb struct? */ }; @@ -213,6 +229,7 @@ int closePend:1; /* file is marked to close */ int emptyDir:1; int invalidHandle:1; /* file closed via session abend */ + struct semaphore fh_sem; /* prevents reopen race after dead ses*/ char * search_resume_name; unsigned int resume_name_length; __u32 resume_key; @@ -274,6 +291,7 @@ #define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_SUBMITTED 2 #define MID_RESPONSE_RECEIVED 4 +#define MID_RETRY_NEEDED 8 /* session closed while this request out */ struct servers_not_supported { /* @z4a */ struct servers_not_supported *next1; /* @z4a */ @@ -313,7 +331,7 @@ * ---------- * sesSem operations on smb session * tconSem operations on tree connection - * i_sem inode operations + * fh_sem file handle reconnection operations * ****************************************************************************/ @@ -358,6 +376,9 @@ GLOBAL_EXTERN atomic_t sesInfoAllocCount; GLOBAL_EXTERN atomic_t tconInfoAllocCount; +GLOBAL_EXTERN atomic_t tcpSesReconnectCount; +GLOBAL_EXTERN atomic_t tconInfoReconnectCount; + /* Various Debug counters to remove someday (BB) */ GLOBAL_EXTERN atomic_t bufAllocCount; GLOBAL_EXTERN atomic_t midCount; @@ -374,4 +395,6 @@ with more secure ntlmssp2 challenge/resp */ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ +GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ + diff -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h --- a/fs/cifs/cifspdu.h Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifspdu.h Sun Apr 25 22:39:31 2004 @@ -727,8 +727,10 @@ typedef struct locking_andx_range { __u16 Pid; __u16 Pad; - __u64 Offset; - __u64 Length; + __u32 OffsetHigh; + __u32 OffsetLow; + __u32 LengthHigh; + __u32 LengthLow; } LOCKING_ANDX_RANGE; #define LOCKING_ANDX_SHARED_LOCK 0x01 @@ -1101,10 +1103,10 @@ } TRANSACTION2_SPI_RSP; struct set_file_rename { - __u32 overwrite; /* 1 = overwrite dest */ - __u32 root_fid; /* zero */ + __u32 overwrite; /* 1 = overwrite dest */ + __u32 root_fid; /* zero */ __u32 target_name_len; - char target_name[0]; /* Must be unicode */ + char target_name[0]; /* Must be unicode */ }; struct smb_com_transaction2_sfi_req { diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifsproto.h Sun Apr 25 22:39:31 2004 @@ -30,8 +30,8 @@ ***************************************************************** */ -extern struct smb_hdr *buf_get(void); -extern void buf_release(void *); +extern struct smb_hdr *cifs_buf_get(void); +extern void cifs_buf_release(void *); extern int smb_send(struct socket *, struct smb_hdr *, unsigned int /* length */ , struct sockaddr *); extern unsigned int _GetXid(void); @@ -41,7 +41,6 @@ extern char *build_path_from_dentry(struct dentry *); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern void renew_parental_timestamps(struct dentry *direntry); -extern void *kcalloc(size_t mem, int type); extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , @@ -61,12 +60,6 @@ void DeleteOplockQEntry(struct oplock_q_entry *); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(struct timespec); -extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName); -extern void Ucode_to_RevUcode(char *Unicode, char *revUnicodeName); -extern void RevUcode_to_Ucode_with_Len(char *revUnicode, char *UnicodeName, - int Len); -extern void Ucode_to_RevUcode_with_Len(char *Unicode, char *revUnicodeName, - int Len); extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO * pfile_info, @@ -75,21 +68,9 @@ const unsigned char *search_path, struct super_block *sb); -extern int reopen_files(struct cifsTconInfo *, struct nls_table *); -extern int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, +extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); -extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *ntlm_session_key, const struct nls_table *); -extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *SecurityBlob,int SecurityBlobLength, - const struct nls_table *); -extern int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, - struct cifsSesInfo *ses, int *ntlmv2_flag, - const struct nls_table *); -extern int CIFSNTLMSSPAuthSessSetup(unsigned int xid, - struct cifsSesInfo *ses, char *ntlm_session_key, - int ntlmv2_flag, const struct nls_table *); extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const char *tree, struct cifsTconInfo *tcon, @@ -224,7 +205,6 @@ extern struct cifsTconInfo *tconInfoAlloc(void); extern void tconInfoFree(struct cifsTconInfo *); -extern int cifs_demultiplex_thread(struct TCP_Server_Info *); extern int cifs_reconnect(struct TCP_Server_Info *server); extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c --- a/fs/cifs/cifssmb.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/cifssmb.c Sun Apr 25 22:39:31 2004 @@ -21,7 +21,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ + /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ + /* These are mostly routines that operate on a pathname, or on a tree id */ + /* (mounted volume), but there are eight handle based routines which must be */ + /* treated slightly different for reconnection purposes since we never want */ + /* to reuse a stale file handle and the caller knows the file handle */ #include #include @@ -37,38 +41,108 @@ int index; char *name; } protocols[] = { - { - CIFS_PROT, "\2NT LM 0.12"}, { - BAD_PROT, "\2"} + {CIFS_PROT, "\2NT LM 0.12"}, + {BAD_PROT, "\2"} }; -int + +/* Mark as invalid, all open files on tree connections since they + were closed when session to server was lost */ +static void mark_open_files_invalid(struct cifsTconInfo * pTcon) +{ + struct cifsFileInfo *open_file = NULL; + struct list_head * tmp; + struct list_head * tmp1; + +/* list all files open on tree connection and mark them invalid */ + write_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, tlist); + if(open_file) { + open_file->invalidHandle = TRUE; + } + } + write_unlock(&GlobalSMBSeslock); + /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ +} + +static int smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, void **request_buf /* returned */ , void **response_buf /* returned */ ) { int rc = 0; - if(tcon && (tcon->tidStatus == CifsNeedReconnect)) { - rc = -EIO; - if(tcon->ses) { - struct nls_table *nls_codepage = load_nls_default(); + /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so + check for tcp and smb session status done differently + for those three - in the calling routine */ + if(tcon) { + if((tcon->ses) && (tcon->ses->server)){ + struct nls_table *nls_codepage; + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ + while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + wait_event_interruptible_timeout(tcon->ses->server->response_q, + (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); + if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + /* on "soft" mounts we wait once */ + if((tcon->retry == FALSE) || + (tcon->ses->status == CifsExiting)) { + cFYI(1,("gave up waiting on reconnect in smb_init")); + return -EHOSTDOWN; + } /* else "hard" mount - keep retrying until + process is killed or server comes back up */ + } else /* TCP session is reestablished now */ + break; + + } + + nls_codepage = load_nls_default(); + /* need to prevent multiple threads trying to + simultaneously reconnect the same SMB session */ + down(&tcon->ses->sesSem); if(tcon->ses->status == CifsNeedReconnect) - rc = setup_session(0, tcon->ses, nls_codepage); - if(!rc) { + rc = cifs_setup_session(0, tcon->ses, nls_codepage); + if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { + mark_open_files_invalid(tcon); rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); + up(&tcon->ses->sesSem); + if(rc == 0) + atomic_inc(&tconInfoReconnectCount); + cFYI(1, ("reconnect tcon rc = %d", rc)); - if(!rc) - reopen_files(tcon,nls_codepage); + /* Removed call to reopen open files here - + it is safer (and faster) to reopen files + one at a time as needed in read and write */ + + /* Check if handle based operation so we + know whether we can continue or not without + returning to caller to reset file handle */ + switch(smb_command) { + case SMB_COM_READ_ANDX: + case SMB_COM_WRITE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_FIND_CLOSE2: + case SMB_COM_LOCKING_ANDX: { + unload_nls(nls_codepage); + return -EAGAIN; + } + } + } else { + up(&tcon->ses->sesSem); } unload_nls(nls_codepage); + + } else { + return -EIO; } } if(rc) return rc; - *request_buf = buf_get(); + *request_buf = cifs_buf_get(); if (request_buf == 0) { return -ENOMEM; } @@ -98,7 +172,6 @@ rc = -EIO; return rc; } - rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ , (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -120,11 +193,11 @@ if (rc == 0) { server->secMode = pSMBr->SecurityMode; server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ - /* one byte - no need to convert this or EncryptionKeyLen from le,*/ + /* one byte - no need to convert this or EncryptionKeyLen from le,*/ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); /* probably no need to store and check maxvcs */ server->maxBuf = - min(le32_to_cpu(pSMBr->MaxBufferSize), + min(le32_to_cpu(pSMBr->MaxBufferSize), (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE); server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); @@ -172,7 +245,6 @@ pSMBr->ByteCount - 16, &server->secType); } - } else server->capabilities &= ~CAP_EXTENDED_SECURITY; if(sign_CIFS_PDUs == FALSE) { @@ -187,7 +259,7 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); return rc; } @@ -218,12 +290,19 @@ return -EBUSY; } + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if(tcon->tidStatus == CifsNeedReconnect) { + up(&tcon->tconSem); + return 0; + } + /* BB remove (from server) list of shares - but with smp safety BB */ /* BB is ses active - do we need to check here - but how? BB */ - if((tcon->ses == 0) || (tcon->ses->server == 0)) { - up(&tcon->tconSem); - return -EIO; - } + if((tcon->ses == 0) || (tcon->ses->server == 0)) { + up(&tcon->tconSem); + return -EIO; + } rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **) &smb_buffer, (void **) &smb_buffer_response); @@ -237,8 +316,14 @@ cFYI(1, (" Tree disconnect failed %d", rc)); if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); up(&tcon->tconSem); + + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if (rc == -EAGAIN) + rc = 0; + return rc; } @@ -251,9 +336,8 @@ int length; cFYI(1, ("In SMBLogoff for session disconnect")); - if (ses) - down(&ses->sesSem); /* check this sem more places */ + down(&ses->sesSem); else return -EIO; @@ -266,8 +350,8 @@ rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */, (void **) &pSMB, (void **) &smb_buffer_response); - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (rc) { up(&ses->sesSem); @@ -285,8 +369,14 @@ ses->server->tcpStatus = CifsExiting; } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); up(&ses->sesSem); + + /* if session dead then we do not need to do ulogoff, + since server closed smb session, no sense reporting + error */ + if (rc == -EAGAIN) + rc = 0; return rc; } @@ -300,6 +390,7 @@ int bytes_returned; int name_len; +DelFileRetry: rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -329,7 +420,10 @@ cFYI(1, ("Error in RMFile = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto DelFileRetry; + return rc; } @@ -344,7 +438,7 @@ int name_len; cFYI(1, ("In CIFSSMBRmDir")); - +RmDirRetry: rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -372,7 +466,9 @@ cFYI(1, ("Error in RMDir = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto RmDirRetry; return rc; } @@ -387,7 +483,7 @@ int name_len; cFYI(1, ("In CIFSSMBMkDir")); - +MkDirRetry: rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -415,8 +511,9 @@ cFYI(1, ("Error in Mkdir = %d", rc)); } if (pSMB) - buf_release(pSMB); - + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto MkDirRetry; return rc; } @@ -433,6 +530,7 @@ int bytes_returned; int name_len; +openRetry: rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -464,8 +562,14 @@ } pSMB->DesiredAccess = cpu_to_le32(access_flags); pSMB->AllocationSize = 0; - pSMB->FileAttributes = ATTR_NORMAL; /* XP does not handle ATTR_POSIX_SEMANTICS */ - /*if ((omode & S_IWUGO) == 0) + pSMB->FileAttributes = ATTR_NORMAL; + /* XP does not handle ATTR_POSIX_SEMANTICS */ + /* but it helps speed up case sensitive checks for other + servers such as Samba */ + if (tcon->ses->capabilities & CAP_UNIX) + pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS; + + /* if ((omode & S_IWUGO) == 0) pSMB->FileAttributes |= ATTR_READONLY;*/ /* Above line causes problems due to vfs splitting create into two pieces - need to set mode after file created not while it is @@ -501,8 +605,9 @@ } } if (pSMB) - buf_release(pSMB); - + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto openRetry; return rc; } @@ -527,9 +632,9 @@ if (rc) return rc; - /* tcon and ses pointer are checked in smb_init */ - if (tcon->ses->server == NULL) - return -ECONNABORTED; + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = netfid; @@ -567,10 +672,13 @@ } if (pSMB) { if(*buf) - buf_release(pSMB); + cifs_buf_release(pSMB); else *buf = (char *)pSMB; } + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ return rc; } @@ -623,7 +731,10 @@ *nbytes = le16_to_cpu(pSMBr->Count); if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ return rc; } @@ -639,9 +750,9 @@ LOCK_RSP *pSMBr = NULL; int bytes_returned; int timeout = 0; + __u64 temp; - cFYI(1, ("In CIFSSMBLock")); - + cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -649,6 +760,12 @@ if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { timeout = -1; /* no response expected */ + pSMB->Timeout = 0; + } else if (waitFlag == TRUE) { + timeout = 3; /* blocking operation, no timeout */ + pSMB->Timeout = -1; /* blocking - do not time out */ + } else { + pSMB->Timeout = 0; } pSMB->NumberOfLocks = cpu_to_le32(numLock); @@ -658,8 +775,12 @@ pSMB->Fid = smb_file_id; /* netfid stays le */ pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); - pSMB->Locks[0].Length = cpu_to_le64(len); - pSMB->Locks[0].Offset = cpu_to_le64(offset); + temp = cpu_to_le64(len); + pSMB->Locks[0].LengthLow = (__u32)(len & 0xFFFFFFFF); + pSMB->Locks[0].LengthHigh = (__u32)(len>>32); + temp = cpu_to_le64(offset); + pSMB->Locks[0].OffsetLow = (__u32)(offset & 0xFFFFFFFF); + pSMB->Locks[0].OffsetHigh = (__u32)(offset>>32); pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); @@ -671,8 +792,10 @@ cERROR(1, ("Send error in Lock = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ return rc; } @@ -685,8 +808,11 @@ int bytes_returned; cFYI(1, ("In CIFSSMBClose")); +/* do not retry on dead session on close */ rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB, (void **) &pSMBr); + if(rc == -EAGAIN) + return 0; if (rc) return rc; @@ -696,10 +822,17 @@ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cERROR(1, ("Send error in Close = %d", rc)); + if(rc!=-EINTR) { + /* EINTR is expected when user ctl-c to kill app */ + cERROR(1, ("Send error in Close = %d", rc)); + } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Since session is dead, file will be closed on server already */ + if(rc == -EAGAIN) + rc = 0; return rc; } @@ -716,7 +849,7 @@ int name_len, name_len2; cFYI(1, ("In CIFSSMBRename")); - +renameRetry: rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -766,7 +899,10 @@ cFYI(1, ("Send error in rename = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto renameRetry; return rc; } @@ -774,44 +910,43 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, int netfid, char * target_name, const struct nls_table * nls_codepage) { - struct smb_com_transaction2_sfi_req *pSMB = NULL; - struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + struct smb_com_transaction2_sfi_req *pSMB = NULL; + struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct set_file_rename * rename_info; - char *data_offset; + char *data_offset; char dummy_string[30]; - int rc = 0; - int bytes_returned = 0; + int rc = 0; + int bytes_returned = 0; int len_of_str; - cFYI(1, ("Rename to File by handle")); + cFYI(1, ("Rename to File by handle")); + rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; - rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->ParameterCount = 6; - pSMB->MaxSetupCount = 0; - pSMB->Reserved = 0; - pSMB->Flags = 0; - pSMB->Timeout = 0; - pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, - Fid) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + pSMB->ParameterCount = 6; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, + Fid) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; - data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; rename_info = (struct set_file_rename *) data_offset; - pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ - pSMB->SetupCount = 1; - pSMB->Reserved3 = 0; - pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); - pSMB->TotalParameterCount = pSMB->ParameterCount; - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* construct random name ".cifs_tmp" */ rename_info->overwrite = cpu_to_le32(1); rename_info->root_fid = 0; @@ -836,11 +971,15 @@ rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cFYI(1,("Send error in Rename (by file handle) = %d", rc)); + cFYI(1,("Send error in Rename (by file handle) = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -859,7 +998,7 @@ int bytes_returned = 0; cFYI(1, ("In Symlink Unix style")); - +createSymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -929,7 +1068,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto createSymLinkRetry; + return rc; } @@ -947,7 +1090,7 @@ int bytes_returned = 0; cFYI(1, ("In Create Hard link Unix style")); - +createHardLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1014,7 +1157,10 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto createHardLinkRetry; + return rc; } @@ -1030,6 +1176,7 @@ int name_len, name_len2; cFYI(1, ("In CIFSCreateHardLink")); +winCreateHardLinkRetry: rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1081,7 +1228,9 @@ cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto winCreateHardLinkRetry; return rc; } @@ -1100,6 +1249,8 @@ int name_len; cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); + +querySymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1174,7 +1325,9 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto querySymLinkRetry; return rc; } @@ -1256,7 +1409,11 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -1274,6 +1431,7 @@ int name_len; cFYI(1, ("In QPathInfo path %s", searchName)); +QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1334,7 +1492,10 @@ rc = -ENOMEM; } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QPathInfoRetry; + return rc; } @@ -1352,6 +1513,7 @@ int name_len; cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); +UnixQPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1413,7 +1575,10 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto UnixQPathInfoRetry; + return rc; } @@ -1430,6 +1595,7 @@ int name_len; cFYI(1, ("In FindUnique")); +findUniqueRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1487,7 +1653,10 @@ /* BB fill in */ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto findUniqueRetry; + return rc; } @@ -1507,6 +1676,7 @@ int name_len; cFYI(1, ("In FindFirst")); +findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1590,7 +1760,11 @@ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto findFirstRetry; + return rc; } @@ -1608,6 +1782,7 @@ int bytes_returned; cFYI(1, ("In FindNext")); + if(resume_file_name == NULL) { return -EIO; } @@ -1690,7 +1865,11 @@ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -1701,10 +1880,14 @@ FINDCLOSE_REQ *pSMB = NULL; CLOSE_RSP *pSMBr = NULL; int bytes_returned; - cFYI(1, ("In CIFSSMBFindClose")); + cFYI(1, ("In CIFSSMBFindClose")); rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB, (void **) &pSMBr); + /* no sense returning error if session restarted + file handle has been closed */ + if(rc == -EAGAIN) + return 0; if (rc) return rc; @@ -1716,7 +1899,11 @@ cERROR(1, ("Send error in FindClose = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Since session is dead, search handle closed on server already */ + if (rc == -EAGAIN) + rc = 0; return rc; } @@ -1743,7 +1930,7 @@ cFYI(1, ("In GetDFSRefer the path %s", searchName)); if (ses == NULL) return -ENODEV; - +getDFSRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, 0, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1874,7 +2061,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto getDFSRetry; + return rc; } @@ -1890,7 +2081,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSInfo")); - +QFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1951,7 +2142,11 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSInfoRetry; + return rc; } @@ -1967,6 +2162,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSAttributeInfo")); +QFSAttributeRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2013,7 +2209,11 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSAttributeRetry; + return rc; } @@ -2029,7 +2229,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSDeviceInfo")); - +QFSDeviceRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2078,7 +2278,12 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSDeviceRetry; + + return rc; } @@ -2094,6 +2299,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSUnixInfo")); +QFSUnixRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2140,7 +2346,12 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSUnixRetry; + + return rc; } @@ -2162,7 +2373,7 @@ int bytes_returned = 0; cFYI(1, ("In SetEOF")); - +SetEOFRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2232,7 +2443,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetEOFRetry; + return rc; } @@ -2248,8 +2463,7 @@ int bytes_returned = 0; __u32 tmp; - cFYI(1, ("SetFileSize (via SetFileInfo)")); - + cFYI(1, ("SetFileSize (via SetFileInfo) %lld",size)); rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2318,7 +2532,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -2335,6 +2553,7 @@ cFYI(1, ("In SetTimes")); +SetTimesRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2392,7 +2611,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetry; + return rc; } @@ -2409,7 +2632,7 @@ FILE_UNIX_BASIC_INFO *data_offset; cFYI(1, ("In SetUID/GID/Mode")); - +setPermsRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2470,6 +2693,8 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto setPermsRetry; return rc; } diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/connect.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* * fs/cifs/connect.c * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -36,6 +36,7 @@ #include "cifs_fs_sb.h" #include "ntlmssp.h" #include "nterr.h" +#include "rfc1002pdu.h" #define CIFS_PORT 445 #define RFC1001_PORT 139 @@ -44,7 +45,7 @@ unsigned char *p24); extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -extern int inet_addr(char *); +extern int cifs_inet_pton(int, const char *, void *dst); struct smb_vol { char *username; @@ -58,7 +59,8 @@ gid_t linux_gid; mode_t file_mode; mode_t dir_mode; - int rw; + int rw:1; + int retry:1; unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -66,13 +68,14 @@ }; int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket); +int ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket); /* * cifs tcp session reconnection * * mark tcp session as reconnecting so temporarily locked - * mark all smb sessions as reconnecting for tcp session (TBD BB) + * mark all smb sessions as reconnecting for tcp session * reconnect tcp session * wake up waiters on reconnection? - (not needed currently) */ @@ -84,6 +87,7 @@ struct list_head *tmp; struct cifsSesInfo *ses; struct cifsTconInfo *tcon; + struct mid_q_entry * mid_entry; if(server->tcpStatus == CifsExiting) return rc; @@ -123,13 +127,35 @@ server->ssocket = NULL; } + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct + mid_q_entry, + qhead); + if(mid_entry) { + if(mid_entry->midState == MID_REQUEST_SUBMITTED) { + /* Mark other intransit requests as needing retry so + we do not immediately mark the session bad again + (ie after we reconnect below) as they timeout too */ + mid_entry->midState = MID_RETRY_NEEDED; + } + } + } + spin_unlock(&GlobalMid_Lock); + + while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) { - rc = ipv4_connect(&server->sockAddr, &server->ssocket); + if(server->protocolType == IPV6) { + rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); + } else { + rc = ipv4_connect(&server->addr.sockAddr, &server->ssocket); + } if(rc) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(3 * HZ); } else { + atomic_inc(&tcpSesReconnectCount); server->tcpStatus = CifsGood; wake_up(&server->response_q); } @@ -138,7 +164,7 @@ return rc; } -int +static int cifs_demultiplex_thread(struct TCP_Server_Info *server) { int length; @@ -165,7 +191,7 @@ while (server->tcpStatus != CifsExiting) { if (smb_buffer == NULL) - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); else memset(smb_buffer, 0, sizeof (struct smb_hdr)); @@ -193,43 +219,81 @@ } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1,("Reconnecting after server stopped responding")); cifs_reconnect(server); + cFYI(1,("call to reconnect done")); csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ continue; } else if (length <= 0) { + if(server->tcpStatus == CifsNew) { + cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); + /* some servers kill tcp session rather than returning + smb negprot error in which case reconnecting here is + not going to help - return error to mount */ + server->tcpStatus = CifsExiting; + wake_up(&server->response_q); + break; + } + cFYI(1,("Reconnecting after unexpected rcvmsg error ")); cifs_reconnect(server); csocket = server->ssocket; + wake_up(&server->response_q); continue; } pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); + /* Ony read pdu_length after below checks for too short (due + to e.g. int overflow) and too long ie beyond end of buf */ cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length)); temp = (char *) smb_buffer; if (length > 3) { - if (temp[0] == (char) 0x85) { + if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { iov.iov_base = smb_buffer; iov.iov_len = 4; length = sock_recvmsg(csocket, &smb_msg, 4, 0); - cFYI(0, - ("Received 4 byte keep alive packet ")); - } else if ((temp[0] == (char) 0x83) + cFYI(0,("Received 4 byte keep alive packet")); + } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { + iov.iov_base = smb_buffer; + iov.iov_len = 4; + length = sock_recvmsg(csocket, &smb_msg, 4, 0); + cFYI(1,("Good RFC 1002 session rsp")); + } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) && (length == 5)) { /* we get this from Windows 98 instead of error on SMB negprot response */ - cERROR(1, - ("Negative RFC 1002 Session response. Error = 0x%x", - temp[4])); - break; - + cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + if(server->tcpStatus == CifsNew) { + /* if nack on negprot (rather than + ret of smb negprot error) reconnecting + not going to help, ret error to mount */ + server->tcpStatus = CifsExiting; + /* wake up thread doing negprot */ + wake_up(&server->response_q); + break; + } else { + /* give server a second to + clean up before reconnect attempt */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + /* always try 445 first on reconnect + since we get NACK on some if we ever + connected to port 139 (the NACK is + since we do not begin with RFC1001 + session initialize frame) */ + server->addr.sockAddr.sin_port = CIFS_PORT; + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } } else if (temp[0] != (char) 0) { - cERROR(1, - ("Unknown RFC 1001 frame received not 0x00 nor 0x85")); - cifs_dump_mem(" Received Data is: ", temp, length); + cERROR(1,("Unknown RFC 1002 frame")); + cifs_dump_mem(" Received Data: ", temp, length); cifs_reconnect(server); csocket = server->ssocket; continue; @@ -257,8 +321,9 @@ length = 0; iov.iov_base = smb_buffer; iov.iov_len = pdu_length; - for (total_read = 0; total_read < pdu_length; total_read += length) { - /* Should improve check for buffer overflow with bad pdu_length */ + for (total_read = 0; + total_read < pdu_length; + total_read += length) { length = sock_recvmsg(csocket, &smb_msg, pdu_length - total_read, 0); if (length == 0) { @@ -286,7 +351,7 @@ mid_q_entry, qhead); - if (mid_entry->mid == smb_buffer->Mid) { + if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { cFYI(1, (" Mid 0x%x matched - waking up ",mid_entry->mid)); task_to_wake = mid_entry->tsk; @@ -302,6 +367,7 @@ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); } } } else { @@ -316,14 +382,16 @@ } } } - /* BB add code to lock SMB sessions while releasing */ + + server->tcpStatus = CifsExiting; + server->tsk = NULL; if(server->ssocket) { sock_release(csocket); - server->ssocket = NULL; + server->ssocket = NULL; } set_fs(temp_fs); if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { @@ -337,39 +405,85 @@ ses->server = NULL; } } - kfree(server); - } else /* BB need to more gracefully handle the rare negative session - response case because response will be still outstanding */ - cERROR(1, ("Active MIDs in queue while exiting - can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!")); - /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ - /* BB Need to fix bug in error path above - perhaps wait until smb requests - time out and then free the tcp per server struct BB */ - read_unlock(&GlobalSMBSeslock); + read_unlock(&GlobalSMBSeslock); + } else { + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + if (mid_entry->midState == MID_REQUEST_SUBMITTED) { + cFYI(1, + (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); + task_to_wake = mid_entry->tsk; + if(task_to_wake) { + wake_up_process(task_to_wake); + } + } + } + spin_unlock(&GlobalMid_Lock); + read_unlock(&GlobalSMBSeslock); + set_current_state(TASK_INTERRUPTIBLE); + /* 1/8th of sec should be more than enough time for them to exit */ + schedule_timeout(HZ/8); + } + + if (list_empty(&server->pending_mid_q)) { + /* mpx threads have not exited yet give them + at least the smb send timeout time for long ops */ + cFYI(1, ("Wait for exit from demultiplex thread")); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(46 * HZ); + /* if threads still have not exited they are probably never + coming home not much else we can do but free the memory */ + } + kfree(server); cFYI(1, ("About to exit from demultiplex thread")); return 0; } -int -parse_mount_options(char *options, const char *devname, struct smb_vol *vol) +static void * +cifs_kcalloc(size_t size, int type) +{ + void *addr; + addr = kmalloc(size, type); + if (addr) + memset(addr, 0, size); + return addr; +} + +static int +cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) { char *value; char *data; - int temp_len; + int temp_len, i, j; + char separator[2]; + + separator[0] = ','; + separator[1] = 0; - memset(vol,0,sizeof(struct smb_vol)); vol->linux_uid = current->uid; /* current->euid instead? */ vol->linux_gid = current->gid; vol->dir_mode = S_IRWXUGO; /* 2767 perms indicate mandatory locking support */ vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; if (!options) return 1; - while ((data = strsep(&options, ",")) != NULL) { + if(strncmp(options,"sep=",4) == 0) { + if(options[4] != 0) { + separator[0] = options[4]; + options += 5; + } else { + cFYI(1,("Null separator not allowed")); + } + } + + while ((data = strsep(&options, separator)) != NULL) { if (!*data) continue; if ((value = strchr(data, '=')) != NULL) @@ -389,11 +503,54 @@ } else if (strnicmp(data, "pass", 4) == 0) { if (!value || !*value) { vol->password = NULL; - } else if (strnlen(value, 17) < 17) { - vol->password = value; + continue; + } + temp_len = strlen(value); + /* removed password length check, NTLM passwords + can be arbitrarily long */ + + /* if comma in password, the string will be + prematurely null terminated. Commas in password are + specified across the cifs mount interface by a double + comma ie ,, and a comma used as in other cases ie ',' + as a parameter delimiter/separator is single and due + to the strsep above is temporarily zeroed. */ + + /* NB: password legally can have multiple commas and + the only illegal character in a password is null */ + + if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { + /* reinsert comma */ + value[temp_len] = separator[0]; + temp_len+=2; /* move after the second comma */ + while(value[temp_len] != 0) { + if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) { + /* single comma indicating start of next parm */ + break; + } + temp_len++; + } + if(value[temp_len] == 0) { + options = NULL; + } else { + value[temp_len] = 0; + /* move options to point to start of next parm */ + options = value + temp_len + 1; + } + /* go from value to (value + temp_len) condensing double commas to singles */ + vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); + for(i=0,j=0;ipassword[j] = value[i]; + if(value[i] == separator[0] && value[i+1] == separator[0]) { + /* skip second comma */ + i++; + } + } + /* value[temp_len] is zeroed above so + vol->password[temp_len] guaranteed to be null */ } else { - printk(KERN_WARNING "CIFS: password too long\n"); - return 1; + vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); + strcpy(vol->password, value); } } else if (strnicmp(data, "ip", 2) == 0) { if (!value || !*value) { @@ -506,8 +663,29 @@ /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; + } else if ((strnicmp(data, "suid", 4) == 0) || + (strnicmp(data, "nosuid", 6) == 0) || + (strnicmp(data, "exec", 4) == 0) || + (strnicmp(data, "noexec", 6) == 0) || + (strnicmp(data, "nodev", 5) == 0) || + (strnicmp(data, "dev", 3) == 0)) { + /* The mount tool or mount.cifs helper (if present) + uses these opts to set flags, and the flags are read + by the kernel vfs layer before we get here (ie + before read super) so there is no point trying to + parse these options again and set anything and it + is ok to just ignore them */ + continue; } else if (strnicmp(data, "ro", 2) == 0) { vol->rw = FALSE; + } else if (strnicmp(data, "hard", 4) == 0) { + vol->retry = 1; + } else if (strnicmp(data, "soft", 4) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nohard", 6) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nosoft", 6) == 0) { + vol->retry = 1; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); } @@ -537,8 +715,8 @@ return 0; } -struct cifsSesInfo * -find_tcp_session(__u32 new_target_ip_addr, +static struct cifsSesInfo * +cifs_find_tcp_session(__u32 new_target_ip_addr, char *userName, struct TCP_Server_Info **psrvTcp) { struct list_head *tmp; @@ -549,7 +727,7 @@ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server) { - if (ses->server->sockAddr.sin_addr.s_addr == + if (ses->server->addr.sockAddr.sin_addr.s_addr == new_target_ip_addr) { /* BB lock server and tcp session and increment use count here?? */ *psrvTcp = ses->server; /* found a match on the TCP session */ @@ -568,7 +746,7 @@ return NULL; } -struct cifsTconInfo * +static struct cifsTconInfo * find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) { struct list_head *tmp; @@ -582,9 +760,9 @@ if (tcon->ses->server) { cFYI(1, (" old ip addr: %x == new ip %x ?", - tcon->ses->server->sockAddr.sin_addr. + tcon->ses->server->addr.sockAddr.sin_addr. s_addr, new_target_ip_addr)); - if (tcon->ses->server->sockAddr.sin_addr. + if (tcon->ses->server->addr.sockAddr.sin_addr. s_addr == new_target_ip_addr) { /* BB lock tcon and server and tcp session and increment use count here? */ /* found a match on the TCP session */ @@ -628,7 +806,8 @@ the helper that resolves tcp names, mount to it, try to tcon to it unmount it if fail */ - /* BB free memory for referrals string BB */ + if(referrals) + kfree(referrals); return rc; } @@ -666,95 +845,12 @@ return rc; } -int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) -{ - int rc = 0; - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; - int ntlmv2_flag = FALSE; - - /* what if server changes its buffer size after dropping the session? */ - if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ - rc = CIFSSMBNegotiate(xid, pSesInfo); - pSesInfo->capabilities = pSesInfo->server->capabilities; - pSesInfo->sequence_number = 0; - if (!rc) { - cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", - pSesInfo->server->secMode, - pSesInfo->server->capabilities, - pSesInfo->server->timeZone)); - if (extended_security - && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) - && (pSesInfo->server->secType == NTLMSSP)) { - cFYI(1, ("New style sesssetup ")); - rc = CIFSSpnegoSessSetup(xid, pSesInfo, - NULL /* security blob */, - 0 /* blob length */, - nls_info); - } else if (extended_security - && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) - && (pSesInfo->server->secType == RawNTLMSSP)) { - cFYI(1, ("NTLMSSP sesssetup ")); - rc = CIFSNTLMSSPNegotiateSessSetup(xid, - pSesInfo, - &ntlmv2_flag, - nls_info); - if (!rc) { - if(ntlmv2_flag) { - char * v2_response; - cFYI(1,("Can use more secure NTLM version 2 password hash")); - CalcNTLMv2_partial_mac_key(pSesInfo, - nls_info); - v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); - if(v2_response) { - CalcNTLMv2_response(pSesInfo,v2_response); -/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ - kfree(v2_response); - /* BB Put dummy sig in SessSetup PDU? */ - } else - rc = -ENOMEM; - - } else { - SMBNTencrypt(pSesInfo->password_with_pad, - pSesInfo->server->cryptKey, - ntlm_session_key); - - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, - pSesInfo->password_with_pad); - } - /* for better security the weaker lanman hash not sent - in AuthSessSetup so we no longer calculate it */ - - rc = CIFSNTLMSSPAuthSessSetup(xid, - pSesInfo, - ntlm_session_key, - ntlmv2_flag, - nls_info); - } - } else { /* old style NTLM 0.12 session setup */ - SMBNTencrypt(pSesInfo->password_with_pad, - pSesInfo->server->cryptKey, - ntlm_session_key); - - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, pSesInfo->password_with_pad); - rc = CIFSSessSetup(xid, pSesInfo, - ntlm_session_key, nls_info); - } - if (rc) { - cERROR(1,("Send error in SessSetup = %d",rc)); - } else { - cFYI(1,("CIFS Session Established successfully")); - pSesInfo->status = CifsGood; - } - } - return rc; -} - int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket) { int rc = 0; + int connected = 0; + unsigned short int orig_port = 0; if(*csocket == NULL) { rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); @@ -769,39 +865,53 @@ } psin_server->sin_family = AF_INET; + if(psin_server->sin_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in),0); - if (rc >= 0) { - return rc; - } - } - - /* do not retry on the same port we just failed on */ - if(psin_server->sin_port != htons(CIFS_PORT)) { - psin_server->sin_port = htons(CIFS_PORT); + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* save original port so we can retry user specified port + later if fall back ports fail this time */ + orig_port = psin_server->sin_port; + + /* do not retry on the same port we just failed on */ + if(psin_server->sin_port != htons(CIFS_PORT)) { + psin_server->sin_port = htons(CIFS_PORT); - rc = (*csocket)->ops->connect(*csocket, + rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } } - if (rc < 0) { + if (!connected) { psin_server->sin_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in),0); - if (rc < 0) { - cFYI(1, ("Error connecting to socket. %d", rc)); - sock_release(*csocket); - *csocket = NULL; - return rc; - } + if (rc >= 0) + connected = 1; } + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + if(orig_port) + psin_server->sin_port = orig_port; + cFYI(1,("Error %d connecting to server via ipv4",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } /* Eventually check for other socket options to change from the default. sock_setsockopt not used because it expects user space buffer */ - (*csocket)->sk->sk_rcvtimeo = 8 * HZ; + (*csocket)->sk->sk_rcvtimeo = 7 * HZ; return rc; } @@ -810,49 +920,63 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) { int rc = 0; + int connected = 0; - rc = sock_create(PF_INET6, SOCK_STREAM, - IPPROTO_TCP /* IPPROTO_IPV6 ? */ , csocket); - if (rc < 0) { - cERROR(1, ("Error creating socket. Aborting operation")); - return rc; + if(*csocket == NULL) { + rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); + if (rc < 0) { + cERROR(1, ("Error %d creating ipv6 socket",rc)); + *csocket = NULL; + return rc; + } else { + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1,("ipv6 Socket created")); + } } psin_server->sin6_family = AF_INET6; + if(psin_server->sin6_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in6),0); - if (rc >= 0) { - /* BB other socket options to set KEEPALIVE, timeouts? NODELAY? */ - return rc; - } - } + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* do not retry on the same port we just failed on */ + if(psin_server->sin6_port != htons(CIFS_PORT)) { + psin_server->sin6_port = htons(CIFS_PORT); - /* do not retry on the same port we just failed on */ - if(psin_server->sin6_port != htons(CIFS_PORT)) { - psin_server->sin6_port = htons(CIFS_PORT); - - rc = (*csocket)->ops->connect(*csocket, - (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); -/* BB fix the timeout to be shorter above - and check flags */ + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } } - if (rc < 0) { + if (!connected) { psin_server->sin6_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, - sizeof (struct sockaddr_in6), 0); - if (rc < 0) { - cFYI(1, - ("Error connecting to socket (via ipv6). %d", - rc)); - sock_release(*csocket); - *csocket = NULL; - return rc; - } + psin_server, sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; } + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + cFYI(1,("Error %d connecting to server via ipv6",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } + /* Eventually check for other socket options to change from + the default. sock_setsockopt not used because it expects + user space buffer */ + (*csocket)->sk->sk_rcvtimeo = 7 * HZ; + return rc; } @@ -864,7 +988,7 @@ int xid; struct socket *csocket = NULL; struct sockaddr_in sin_server; -/* struct sockaddr_in6 sin_server6; */ + struct sockaddr_in6 sin_server6; struct smb_vol volume_info; struct cifsSesInfo *pSesInfo = NULL; struct cifsSesInfo *existingCifsSes = NULL; @@ -872,11 +996,16 @@ struct TCP_Server_Info *srvTcp = NULL; xid = GetXid(); - cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); - if (parse_mount_options(mount_data, devname, &volume_info)) { +/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ + + memset(&volume_info,0,sizeof(struct smb_vol)); + + if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { if(volume_info.UNC) kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -888,17 +1017,45 @@ cifserror("No username specified "); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } - if (volume_info.UNC) { - sin_server.sin_addr.s_addr = inet_addr(volume_info.UNCip); - cFYI(1, ("UNC: %s ", volume_info.UNC)); - } else { - /* BB we could connect to the DFS root? but which server do we ask? */ + if (volume_info.UNCip && volume_info.UNC) { + rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); + + if(rc == 0) { + /* not ipv4 address, try ipv6 */ + rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); + } + + if(rc != 1) { + /* we failed translating address */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); + /* success */ + rc = 0; + } else if (volume_info.UNCip){ + /* BB using ip addr as server name connect to the DFS root below */ + cERROR(1,("Connecting to DFS root not implemented yet")); + } else /* which servers DFS root would we conect to */ { cERROR(1, ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -911,19 +1068,25 @@ cifs_sb->local_nls = load_nls(volume_info.iocharset); if(cifs_sb->local_nls == NULL) { cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -ELIBACC; } } existingCifsSes = - find_tcp_session(sin_server.sin_addr.s_addr, + cifs_find_tcp_session(sin_server.sin_addr.s_addr, volume_info.username, &srvTcp); if (srvTcp) { cFYI(1, ("Existing tcp session with server found ")); } else { /* create socket */ if(volume_info.port) sin_server.sin_port = htons(volume_info.port); + else + sin_server.sin_port = 0; rc = ipv4_connect(&sin_server, &csocket); if (rc < 0) { cERROR(1, @@ -932,6 +1095,8 @@ sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return rc; } @@ -942,16 +1107,20 @@ sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return rc; } else { memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); - memcpy(&srvTcp->sockAddr, &sin_server, sizeof (struct sockaddr_in)); + memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; + srvTcp->protocolType = IPV4; init_waitqueue_head(&srvTcp->response_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q); - srvTcp->tcpStatus = CifsGood; + srvTcp->tcpStatus = CifsNew; + init_MUTEX(&srvTcp->tcpSem); kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, CLONE_FS | CLONE_FILES | CLONE_VM); } @@ -960,6 +1129,8 @@ if (existingCifsSes) { pSesInfo = existingCifsSes; cFYI(1, ("Existing smb sess found ")); + if(volume_info.password) + kfree(volume_info.password); } else if (!rc) { cFYI(1, ("Existing smb sess not found ")); pSesInfo = sesInfoAlloc(); @@ -973,8 +1144,7 @@ if (!rc){ if (volume_info.password) - strncpy(pSesInfo->password_with_pad, - volume_info.password,CIFS_ENCPWD_SIZE); + pSesInfo->password = volume_info.password; if (volume_info.username) strncpy(pSesInfo->userName, volume_info.username,MAX_USERNAME_SIZE); @@ -982,11 +1152,14 @@ strncpy(pSesInfo->domainName, volume_info.domainname,MAX_USERNAME_SIZE); pSesInfo->linux_uid = volume_info.linux_uid; - - rc = setup_session(xid,pSesInfo, cifs_sb->local_nls); + down(&pSesInfo->sesSem); + rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); + up(&pSesInfo->sesSem); if(!rc) atomic_inc(&srvTcp->socketUseCount); - } + } else + if(volume_info.password) + kfree(volume_info.password); } /* search for existing tcon to this server share */ @@ -1013,6 +1186,11 @@ volume_info.username); if (tcon) { cFYI(1, ("Found match on UNC path ")); + /* we can have only one retry value for a connection + to a share so for resources mounted more than once + to the same server share the last value passed in + for the retry flag is used */ + tcon->retry = volume_info.retry; } else { tcon = tconInfoAlloc(); if (tcon == NULL) @@ -1039,8 +1217,10 @@ tcon, cifs_sb->local_nls); cFYI(1, ("CIFS Tcon rc = %d", rc)); } - if (!rc) + if (!rc) { atomic_inc(&pSesInfo->inUse); + tcon->retry = volume_info.retry; + } } } } @@ -1064,8 +1244,6 @@ CIFSSMBLogoff(xid, pSesInfo); if(pSesInfo->server->tsk) send_sig(SIGKILL,pSesInfo->server->tsk,1); - else - cFYI(1,("Can not wake captive thread on cleanup of failed mount")); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 4); /* give captive thread time to exit */ } else @@ -1091,7 +1269,7 @@ return rc; } -int +static int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, char session_key[CIFS_SESSION_KEY_SIZE], const struct nls_table *nls_codepage) @@ -1110,7 +1288,7 @@ cFYI(1, ("In sesssetup ")); - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -1162,9 +1340,10 @@ } if(user == NULL) bytes_returned = 0; /* skill null user */ - else - bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ if (domain == NULL) @@ -1257,7 +1436,7 @@ /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ - ses->serverOS = kcalloc(2 * (len + 1), GFP_KERNEL); + ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1268,7 +1447,7 @@ len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words - 1); - ses->serverNOS =kcalloc(2 * (len + 1),GFP_KERNEL); + ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1279,7 +1458,7 @@ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - kcalloc(2*(len+1),GFP_KERNEL); + cifs_kcalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1288,20 +1467,20 @@ } /* else no more room so create dummy domain string */ else ses->serverDomain = - kcalloc(2, + cifs_kcalloc(2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); ses->serverNOS = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -1309,14 +1488,14 @@ bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = kcalloc(len + 1,GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -1341,12 +1520,12 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -int +static int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *SecurityBlob,int SecurityBlobLength, const struct nls_table *nls_codepage) @@ -1365,7 +1544,7 @@ cFYI(1, ("In spnego sesssetup ")); - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -1511,7 +1690,7 @@ the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -1525,7 +1704,7 @@ remaining_words - 1); ses->serverNOS = - kcalloc(2 * (len + 1), + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr, @@ -1538,7 +1717,7 @@ if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ - ses->serverDomain = kcalloc(2*(len+1),GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr, len, @@ -1549,10 +1728,10 @@ } /* else no more room so create dummy domain string */ else ses->serverDomain = - kcalloc(2,GFP_KERNEL); + cifs_kcalloc(2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = kcalloc(2, GFP_KERNEL); - ses->serverNOS = kcalloc(2, GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ @@ -1560,7 +1739,7 @@ if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = kcalloc(len + 1, GFP_KERNEL); + ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); bcc_ptr += len; @@ -1568,14 +1747,14 @@ bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = kcalloc(len + 1, GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -1600,12 +1779,12 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -int +static int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, struct cifsSesInfo *ses, int * pNTLMv2_flag, const struct nls_table *nls_codepage) @@ -1626,7 +1805,7 @@ cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); *pNTLMv2_flag = FALSE; - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -1822,7 +2001,7 @@ the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -1837,7 +2016,7 @@ remaining_words - 1); ses->serverNOS = - kcalloc(2 * (len + 1), + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -1854,7 +2033,7 @@ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - kcalloc(2 * + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); @@ -1880,13 +2059,13 @@ } /* else no more room so create dummy domain string */ else ses->serverDomain = - kcalloc(2, + cifs_kcalloc(2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); ses->serverNOS = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); @@ -1894,7 +2073,7 @@ pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { ses->serverOS = - kcalloc(len + 1, + cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); @@ -1905,7 +2084,7 @@ len = strnlen(bcc_ptr, 1024); ses->serverNOS = - kcalloc(len + 1, + cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; @@ -1914,7 +2093,7 @@ len = strnlen(bcc_ptr, 1024); ses->serverDomain = - kcalloc(len + 1, + cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; @@ -1940,12 +2119,12 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -int +static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *ntlm_session_key, int ntlmv2_flag, const struct nls_table *nls_codepage) @@ -1966,7 +2145,7 @@ cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -2215,7 +2394,7 @@ the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2230,7 +2409,7 @@ remaining_words - 1); ses->serverNOS = - kcalloc(2 * (len + 1), + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -2246,7 +2425,7 @@ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ ses->serverDomain = - kcalloc(2 * + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); @@ -2271,17 +2450,17 @@ = 0; } /* else no more room so create dummy domain string */ else - ses->serverDomain = kcalloc(2,GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = kcalloc(2, GFP_KERNEL); - ses->serverNOS = kcalloc(2, GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -2289,14 +2468,14 @@ bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = kcalloc(len+1,GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = kcalloc(len+1,GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -2321,7 +2500,7 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2342,7 +2521,7 @@ if (ses == NULL) return -EIO; - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -2404,8 +2583,10 @@ if (((long) bcc_ptr + (2 * length)) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - kcalloc(length + 2, GFP_KERNEL); + cifs_kcalloc(length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, (wchar_t *) bcc_ptr, length, nls_codepage); @@ -2420,8 +2601,10 @@ if (((long) bcc_ptr + length) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - kcalloc(length + 1, GFP_KERNEL); + cifs_kcalloc(length + 1, GFP_KERNEL); strncpy(tcon->nativeFileSystem, bcc_ptr, length); } @@ -2435,7 +2618,7 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2472,7 +2655,7 @@ } else cFYI(1, ("No session or bad tcon")); } - /* BB future check active count of tcon and then free if needed BB */ + cifs_sb->tcon = NULL; if (ses) { set_current_state(TASK_INTERRUPTIBLE); @@ -2484,3 +2667,100 @@ FreeXid(xid); return rc; /* BB check if we should always return zero here */ } + +int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, + struct nls_table * nls_info) +{ + int rc = 0; + char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + int ntlmv2_flag = FALSE; + + /* what if server changes its buffer size after dropping the session? */ + if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) /* retry only once on 1st time connection */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + } + if(rc == 0) + pSesInfo->server->tcpStatus = CifsGood; + } + if (!rc) { + pSesInfo->capabilities = pSesInfo->server->capabilities; + if(linuxExtEnabled == 0) + pSesInfo->capabilities &= (~CAP_UNIX); + pSesInfo->sequence_number = 0; + cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", + pSesInfo->server->secMode, + pSesInfo->server->capabilities, + pSesInfo->server->timeZone)); + if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == NTLMSSP)) { + cFYI(1, ("New style sesssetup ")); + rc = CIFSSpnegoSessSetup(xid, pSesInfo, + NULL /* security blob */, + 0 /* blob length */, + nls_info); + } else if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == RawNTLMSSP)) { + cFYI(1, ("NTLMSSP sesssetup ")); + rc = CIFSNTLMSSPNegotiateSessSetup(xid, + pSesInfo, + &ntlmv2_flag, + nls_info); + if (!rc) { + if(ntlmv2_flag) { + char * v2_response; + cFYI(1,("Can use more secure NTLM version 2 password hash")); + CalcNTLMv2_partial_mac_key(pSesInfo, + nls_info); + v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); + if(v2_response) { + CalcNTLMv2_response(pSesInfo,v2_response); +/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + kfree(v2_response); + /* BB Put dummy sig in SessSetup PDU? */ + } else + rc = -ENOMEM; + + } else { + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, + pSesInfo->password); + } + /* for better security the weaker lanman hash not sent + in AuthSessSetup so we no longer calculate it */ + + rc = CIFSNTLMSSPAuthSessSetup(xid, + pSesInfo, + ntlm_session_key, + ntlmv2_flag, + nls_info); + } + } else { /* old style NTLM 0.12 session setup */ + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, pSesInfo->password); + rc = CIFSSessSetup(xid, pSesInfo, + ntlm_session_key, nls_info); + } + if (rc) { + cERROR(1,("Send error in SessSetup = %d",rc)); + } else { + cFYI(1,("CIFS Session Established successfully")); + pSesInfo->status = CifsGood; + } + } + return rc; +} + diff -Nru a/fs/cifs/dir.c b/fs/cifs/dir.c --- a/fs/cifs/dir.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/dir.c Sun Apr 25 22:39:31 2004 @@ -125,7 +125,7 @@ int rc = -ENOENT; int xid; int oplock = 0; - int desiredAccess = GENERIC_ALL; + int desiredAccess = GENERIC_READ | GENERIC_WRITE; __u16 fileHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; @@ -147,11 +147,15 @@ cFYI(1,("In create for inode %p dentry->inode %p nd flags = 0x%x for %s",inode, direntry->d_inode, nd->flags,full_path)); if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) - desiredAccess = GENERIC_READ; + desiredAccess = GENERIC_READ; else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) desiredAccess = GENERIC_WRITE; - else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) - desiredAccess = GENERIC_ALL; + else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) disposition = FILE_CREATE; @@ -220,6 +224,7 @@ pCifsFile->pInode = newinode; pCifsFile->invalidHandle = FALSE; pCifsFile->closePend = FALSE; + init_MUTEX(&pCifsFile->fh_sem); /* pCifsFile->pfile = file; */ /* put in at open time */ write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist,&pTcon->openFileList); @@ -282,19 +287,19 @@ full_path, mode, current->euid, current->egid, device_number, cifs_sb->local_nls); if(!rc) { - rc = cifs_get_inode_info_unix(&newinode, full_path, - inode->i_sb); + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb); direntry->d_op = &cifs_dentry_ops; if(rc == 0) d_instantiate(direntry, newinode); } } - if (full_path) - kfree(full_path); - FreeXid(xid); + if (full_path) + kfree(full_path); + FreeXid(xid); - return rc; + return rc; } diff -Nru a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/cifs/fcntl.c Sun Apr 25 22:39:32 2004 @@ -0,0 +1,97 @@ +/* + * fs/cifs/fcntl.c + * + * vfs operations that deal with the file control API + * + * Copyright (C) International Business Machines Corp., 2003,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" + +int cifs_directory_notify(unsigned long arg, struct file * file) +{ + int xid; + int rc = -EINVAL; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + full_path = build_path_from_dentry(file->f_dentry); + cFYI(1,("cifs dir notify on file %s",full_path)); + /* CIFSSMBNotify */ + FreeXid(xid); + return rc; +} + + +long cifs_fcntl(int file_desc, unsigned int command, unsigned long arg, + struct file * file) +{ + /* Few few file control functions need to be specially mapped. So far + only: + F_NOTIFY (for directory change notification) + And eventually: + F_GETLEASE + F_SETLEASE + need to be mapped here. The others either already are mapped downstream + or do not need to go to the server (client only sideeffects): + F_DUPFD: + F_GETFD: + F_SETFD: + F_GETFL: + F_SETFL: + F_GETLK: + F_SETLK: + F_SETLKW: + F_GETOWN: + F_SETOWN: + F_GETSIG: + F_SETSIG: + */ + long rc = 0; + + cFYI(1,("cifs_fcntl: command %d with arg %lx",command,arg)); /* BB removeme BB */ + + switch (command) { + case F_NOTIFY: + /* let the local call have a chance to fail first */ + rc = generic_file_fcntl(file_desc,command,arg,file); + if(rc) + return rc; + else { + /* local call succeeded try to do remote notify to + pick up changes from other clients to server file */ + cifs_directory_notify(arg, file); + /* BB add case to long and return rc from above */ + return rc; + } + break; + default: + break; + } + return generic_file_fcntl(file_desc,command,arg,file); +} + diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c --- a/fs/cifs/file.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/file.c Sun Apr 25 22:39:31 2004 @@ -47,7 +47,7 @@ struct list_head * tmp; char *full_path = NULL; int desiredAccess = 0x20197; - int disposition = FILE_OPEN; + int disposition; __u16 netfid; FILE_ALL_INFO * buf = NULL; @@ -57,27 +57,27 @@ pTcon = cifs_sb->tcon; if (file->f_flags & O_CREAT) { - /* search inode for this file and fill in file->private_data = */ - pCifsInode = CIFS_I(file->f_dentry->d_inode); - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &pCifsInode->openFileList) { - pCifsFile = list_entry(tmp,struct cifsFileInfo, flist); - if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){ - /* set mode ?? */ - pCifsFile->pfile = file; /* needed for writepage */ - file->private_data = pCifsFile; - break; - } - } - read_unlock(&GlobalSMBSeslock); - if(file->private_data != NULL) { - rc = 0; - FreeXid(xid); - return rc; - } else { - if(file->f_flags & O_EXCL) - cERROR(1,("could not find file instance for new file %p ",file)); - } + /* search inode for this file and fill in file->private_data = */ + pCifsInode = CIFS_I(file->f_dentry->d_inode); + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &pCifsInode->openFileList) { + pCifsFile = list_entry(tmp,struct cifsFileInfo, flist); + if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){ + /* set mode ?? */ + pCifsFile->pfile = file; /* needed for writepage */ + file->private_data = pCifsFile; + break; + } + } + read_unlock(&GlobalSMBSeslock); + if(file->private_data != NULL) { + rc = 0; + FreeXid(xid); + return rc; + } else { + if(file->f_flags & O_EXCL) + cERROR(1,("could not find file instance for new file %p ",file)); + } } full_path = build_path_from_dentry(file->f_dentry); @@ -87,29 +87,45 @@ desiredAccess = GENERIC_READ; else if ((file->f_flags & O_ACCMODE) == O_WRONLY) desiredAccess = GENERIC_WRITE; - else if ((file->f_flags & O_ACCMODE) == O_RDWR) - desiredAccess = GENERIC_ALL; - -/* BB check other flags carefully to find equivalent NTCreateX flags */ - -/* -#define O_CREAT 0100 -#define O_EXCL 0200 -#define O_NOCTTY 0400 -#define O_TRUNC 01000 -#define O_APPEND 02000 -#define O_NONBLOCK 04000 -#define O_NDELAY O_NONBLOCK -#define O_SYNC 010000 -#define FASYNC 020000 -#define O_DIRECT 040000 -#define O_LARGEFILE 0100000 -#define O_DIRECTORY 0200000 -#define O_NOFOLLOW 0400000 -#define O_ATOMICLOOKUP 01000000 */ - - if (file->f_flags & O_CREAT) - disposition = FILE_OVERWRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } + +/********************************************************************* + * open flag mapping table: + * + * POSIX Flag CIFS Disposition + * ---------- ---------------- + * O_CREAT FILE_OPEN_IF + * O_CREAT | O_EXCL FILE_CREATE + * O_CREAT | O_TRUNC FILE_OVERWRITE_IF + * O_TRUNC FILE_OVERWRITE + * none of the above FILE_OPEN + * + * Note that there is not a direct match between disposition + * FILE_SUPERSEDE (ie create whether or not file exists although + * O_CREAT | O_TRUNC is similar but truncates the existing + * file rather than creating a new file as FILE_SUPERSEDE does + * (which uses the attributes / metadata passed in on open call) + *? + *? O_SYNC is a reasonable match to CIFS writethrough flag + *? and the read write flags match reasonably. O_LARGEFILE + *? is irrelevant because largefile support is always used + *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, + * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation + *********************************************************************/ + + if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + disposition = FILE_CREATE; + else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) + disposition = FILE_OVERWRITE_IF; + else if((file->f_flags & O_CREAT) == O_CREAT) + disposition = FILE_OPEN_IF; + else + disposition = FILE_OPEN; if (oplockEnabled) oplock = REQ_OPLOCK; @@ -121,7 +137,7 @@ /* Also refresh inode by passing in file_info buf returned by SMBOpen and calling get_inode_info with returned buf (at least helps non-Unix server case */ - buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); if(buf==0) { if (full_path) kfree(full_path); @@ -134,14 +150,16 @@ cFYI(1, ("cifs_open returned 0x%x ", rc)); cFYI(1, ("oplock: %d ", oplock)); } else { + if(file->private_data) + kfree(file->private_data); file->private_data = - kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); if (file->private_data) { - memset(file->private_data, 0, - sizeof (struct cifsFileInfo)); + memset(file->private_data, 0, sizeof(struct cifsFileInfo)); pCifsFile = (struct cifsFileInfo *) file->private_data; pCifsFile->netfid = netfid; pCifsFile->pid = current->pid; + init_MUTEX(&pCifsFile->fh_sem); pCifsFile->pfile = file; /* needed for writepage */ pCifsFile->pInode = inode; pCifsFile->invalidHandle = FALSE; @@ -154,8 +172,27 @@ list_add(&pCifsFile->flist,&pCifsInode->openFileList); write_unlock(&GlobalSMBSeslock); write_unlock(&file->f_owner.lock); + if(pCifsInode->clientCanCacheRead) { + /* we have the inode open somewhere else + no need to discard cache data */ + } else { + if(buf) { + /* BB need same check in cifs_create too? */ - if (pTcon->ses->capabilities & CAP_UNIX) + /* if not oplocked, invalidate inode pages if mtime + or file size changed */ + struct timespec temp; + temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); + if(timespec_equal(&file->f_dentry->d_inode->i_mtime,&temp) && + (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) { + cFYI(1,("inode unchanged on server")); + } else { + cFYI(1,("invalidating remote inode since open detected it changed")); + invalidate_remote_inode(file->f_dentry->d_inode); + } + } + } + if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, full_path, inode->i_sb); else @@ -200,162 +237,119 @@ /* Try to reaquire byte range locks that were released when session */ /* to server was lost */ -int relock_files(struct cifsFileInfo * cifsFile) +static int cifs_relock_file(struct cifsFileInfo * cifsFile) { int rc = 0; -/* list all locks open on this file */ +/* BB list all locks open on this file and relock */ + return rc; } static int cifs_reopen_file(struct inode *inode, struct file *file) { - int rc = -EACCES; - int xid, oplock; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - struct cifsFileInfo *pCifsFile; - struct cifsInodeInfo *pCifsInode; - char *full_path = NULL; - int desiredAccess = 0x20197; - int disposition = FILE_OPEN; - __u16 netfid; - FILE_ALL_INFO * buf = NULL; - - xid = GetXid(); - - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - - full_path = build_path_from_dentry(file->f_dentry); - - cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - desiredAccess = GENERIC_READ; - else if ((file->f_flags & O_ACCMODE) == O_WRONLY) - desiredAccess = GENERIC_WRITE; - else if ((file->f_flags & O_ACCMODE) == O_RDWR) - desiredAccess = GENERIC_ALL; - if (oplockEnabled) - oplock = REQ_OPLOCK; - else - oplock = FALSE; - - /* BB pass O_SYNC flag through on file attributes .. BB */ - - /* Also refresh inode by passing in file_info buf returned by SMBOpen - and calling get_inode_info with returned buf (at least - helps non-Unix server case */ - buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); - if(buf==0) { - if (full_path) - kfree(full_path); - FreeXid(xid); - return -ENOMEM; - } - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, - CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); - if (rc) { - cFYI(1, ("cifs_open returned 0x%x ", rc)); - cFYI(1, ("oplock: %d ", oplock)); - } else { - if (file->private_data) { - pCifsFile = (struct cifsFileInfo *) file->private_data; + int rc = -EACCES; + int xid, oplock; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; + char *full_path = NULL; + int desiredAccess = 0x20197; + int disposition = FILE_OPEN; + __u16 netfid; + FILE_ALL_INFO * buf = NULL; - pCifsFile->netfid = netfid; - pCifsFile->invalidHandle = FALSE; - pCifsInode = CIFS_I(file->f_dentry->d_inode); - if(pCifsInode) { - if (pTcon->ses->capabilities & CAP_UNIX) - rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, - full_path, inode->i_sb); - else - rc = cifs_get_inode_info(&file->f_dentry->d_inode, - full_path, buf, inode->i_sb); - - if(oplock == OPLOCK_EXCLUSIVE) { - pCifsInode->clientCanCacheAll = TRUE; - pCifsInode->clientCanCacheRead = TRUE; - cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); - } else if(oplock == OPLOCK_READ) { - pCifsInode->clientCanCacheRead = TRUE; - pCifsInode->clientCanCacheAll = FALSE; - } else { - pCifsInode->clientCanCacheRead = FALSE; - pCifsInode->clientCanCacheAll = FALSE; - } - } - } else - rc = -EBADF; - } + if(inode == NULL) + return -EBADF; + if (file->private_data) { + pCifsFile = (struct cifsFileInfo *) file->private_data; + } else + return -EBADF; - if (buf) - kfree(buf); - if (full_path) - kfree(full_path); - FreeXid(xid); - return rc; -} + xid = GetXid(); + down(&pCifsFile->fh_sem); + if(pCifsFile->invalidHandle == FALSE) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return 0; + } -/* Try to reopen files that were closed when session to server was lost */ -int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) -{ - int rc = 0; - struct cifsFileInfo *open_file = NULL; - struct file * file = NULL; - struct list_head invalid_file_list; - struct list_head * tmp; - struct list_head * tmp1; - - INIT_LIST_HEAD(&invalid_file_list); - -/* list all files open on tree connection and mark them invalid */ - write_lock(&GlobalSMBSeslock); - list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { - open_file = list_entry(tmp,struct cifsFileInfo, tlist); - if(open_file) { - open_file->invalidHandle = TRUE; - list_move(&open_file->tlist,&invalid_file_list); - } + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + full_path = build_path_from_dentry(file->f_dentry); + + cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + desiredAccess = GENERIC_READ; + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + desiredAccess = GENERIC_WRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; } - /* reopen files */ - list_for_each_safe(tmp,tmp1, &invalid_file_list) { - /* BB need to fix above to check list end and skip entries we do not need to reopen */ - open_file = list_entry(tmp,struct cifsFileInfo, tlist); - if(open_file == NULL) { - break; - } else { - if((open_file->invalidHandle == FALSE) && - (open_file->closePend == FALSE)) { - list_move(&open_file->tlist,&pTcon->openFileList); - continue; - } - file = open_file->pfile; - if(file->f_dentry == 0) { - cFYI(1,("Null dentry for file %p",file)); + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = FALSE; + + /* BB pass O_SYNC flag through on file attributes .. BB */ + + /* Also refresh inode by passing in file_info buf returned by SMBOpen + and calling get_inode_info with returned buf (at least + helps non-Unix server case */ + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf==0) { + up(&pCifsFile->fh_sem); + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); + if (rc) { + up(&pCifsFile->fh_sem); + cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("oplock: %d ", oplock)); + } else { + pCifsFile->netfid = netfid; + pCifsFile->invalidHandle = FALSE; + up(&pCifsFile->fh_sem); + pCifsInode = CIFS_I(inode); + if(pCifsInode) { + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&inode, + full_path, inode->i_sb); + else + rc = cifs_get_inode_info(&inode, + full_path, buf, inode->i_sb); + + if(oplock == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if(oplock == OPLOCK_READ) { + pCifsInode->clientCanCacheRead = TRUE; + pCifsInode->clientCanCacheAll = FALSE; } else { - write_unlock(&GlobalSMBSeslock); - rc = cifs_reopen_file(file->f_dentry->d_inode,file); - write_lock(&GlobalSMBSeslock); - if(file->private_data == NULL) { - tmp = invalid_file_list.next; - tmp1 = tmp->next; - continue; - } - - list_move(&open_file->tlist,&pTcon->openFileList); - if(rc) { - cFYI(1,("reconnecting file %s failed with %d", - file->f_dentry->d_name.name,rc)); - } else { - cFYI(1,("reconnection of %s succeeded", - file->f_dentry->d_name.name)); - } + pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->clientCanCacheAll = FALSE; } + cifs_relock_file(pCifsFile); } } - write_unlock(&GlobalSMBSeslock); + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); return rc; } @@ -437,6 +431,7 @@ __u32 numLock = 0; __u32 numUnlock = 0; __u64 length; + int wait_flag = FALSE; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; length = 1 + pfLock->fl_end - pfLock->fl_start; @@ -454,14 +449,16 @@ cFYI(1, ("Posix ")); if (pfLock->fl_flags & FL_FLOCK) cFYI(1, ("Flock ")); - if (pfLock->fl_flags & FL_SLEEP) + if (pfLock->fl_flags & FL_SLEEP) { cFYI(1, ("Blocking lock ")); + wait_flag = TRUE; + } if (pfLock->fl_flags & FL_ACCESS) - cFYI(1, ("Process suspended by mandatory locking ")); + cFYI(1, ("Process suspended by mandatory locking - not implemented yet ")); if (pfLock->fl_flags & FL_LEASE) - cFYI(1, ("Lease on file ")); - if (pfLock->fl_flags & 0xFFD0) - cFYI(1, ("Unknown lock flags ")); + cFYI(1, ("Lease on file - not implemented yet")); + if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) + cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags)); if (pfLock->fl_type == F_WRLCK) { cFYI(1, ("F_WRLCK ")); @@ -509,7 +506,7 @@ pfLock->fl_type = F_UNLCK; if (rc != 0) cERROR(1, - ("Error unlocking previously locked range %d during test of lock ", + ("Error unlocking previously locked range %d during test of lock ", rc)); rc = 0; @@ -526,7 +523,7 @@ ((struct cifsFileInfo *) file->private_data)-> netfid, length, pfLock->fl_start, numUnlock, numLock, lockType, - 0 /* wait flag */ ); + wait_flag); FreeXid(xid); return rc; } @@ -541,6 +538,7 @@ struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid, long_op; + struct cifsFileInfo * open_file; xid = GetXid(); @@ -555,20 +553,30 @@ FreeXid(xid); return -EBADF; } + open_file = (struct cifsFileInfo *) file->private_data; + if (*poffset > file->f_dentry->d_inode->i_size) - long_op = 2; /* writes past end of file can take a long time */ + long_op = 2; /* writes past end of file can take a long time */ else long_op = 1; for (total_written = 0; write_size > total_written; total_written += bytes_written) { - rc = CIFSSMBWrite(xid, pTcon, - ((struct cifsFileInfo *) file-> - private_data)->netfid, + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + + rc = CIFSSMBWrite(xid, pTcon, + open_file->netfid, write_size - total_written, *poffset, &bytes_written, write_data + total_written, long_op); + } if (rc || (bytes_written == 0)) { if (total_written) break; @@ -580,10 +588,11 @@ *poffset += bytes_written; long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ } - file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = + CURRENT_TIME; if (bytes_written > 0) { if (*poffset > file->f_dentry->d_inode->i_size) - file->f_dentry->d_inode->i_size = *poffset; + i_size_write(file->f_dentry->d_inode, *poffset); } mark_inode_dirty_sync(file->f_dentry->d_inode); FreeXid(xid); @@ -605,24 +614,18 @@ struct cifsFileInfo *open_file = NULL; struct list_head *tmp; struct list_head *tmp1; - int xid; - - xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; /* figure out which file struct to use if (file->private_data == NULL) { - FreeXid(xid); return -EBADF; } */ if (!mapping) { - FreeXid(xid); return -EFAULT; } else if(!mapping->host) { - FreeXid(xid); return -EFAULT; } @@ -632,14 +635,12 @@ if((to > PAGE_CACHE_SIZE) || (from > to)) { kunmap(page); - FreeXid(xid); return -EIO; } /* racing with truncate? */ if(offset > mapping->host->i_size) { kunmap(page); - FreeXid(xid); return 0; /* don't care */ } @@ -683,7 +684,6 @@ } kunmap(page); - FreeXid(xid); return rc; } @@ -727,23 +727,38 @@ int rc = 0; struct inode *inode = page->mapping->host; loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - struct cifsFileInfo *open_file; - struct cifs_sb_info *cifs_sb; + /* struct cifsFileInfo *open_file; + struct cifs_sb_info *cifs_sb; */ xid = GetXid(); - + cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to)); if (position > inode->i_size){ - inode->i_size = position; - if (file->private_data == NULL) { + i_size_write(inode, position); + /*if (file->private_data == NULL) { rc = -EBADF; } else { - cifs_sb = CIFS_SB(inode->i_sb); open_file = (struct cifsFileInfo *)file->private_data; - rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, position, - open_file->netfid,open_file->pid,FALSE); + cifs_sb = CIFS_SB(inode->i_sb); + rc = -EAGAIN; + while(rc == -EAGAIN) { + if((open_file->invalidHandle) && + (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + if(!open_file->closePend) { + rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, + position, open_file->netfid, + open_file->pid,FALSE); + } else { + rc = -EBADF; + break; + } + } cFYI(1,(" SetEOF (commit write) rc = %d",rc)); - } - } + }*/ + } set_page_dirty(page); FreeXid(xid); @@ -769,7 +784,7 @@ return rc; } -static int +/* static int cifs_sync_page(struct page *page) { struct address_space *mapping; @@ -784,17 +799,17 @@ return 0; inode = mapping->host; if (!inode) - return 0; + return 0;*/ /* fill in rpages then result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */ - cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); +/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); if (rc < 0) return rc; return 0; -} +} */ /* * As file closes, flush all cached write data for this inode checking @@ -837,6 +852,7 @@ struct cifsTconInfo *pTcon; int xid; char * current_offset; + struct cifsFileInfo * open_file; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -846,15 +862,24 @@ FreeXid(xid); return -EBADF; } + open_file = (struct cifsFileInfo *)file->private_data; for (total_read = 0,current_offset=read_data; read_size > total_read; total_read += bytes_read,current_offset+=bytes_read) { current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); - rc = CIFSSMBRead(xid, pTcon, - ((struct cifsFileInfo *) file-> - private_data)->netfid, + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, current_read_size, *poffset, &bytes_read, ¤t_offset); + } if (rc || (bytes_read == 0)) { if (total_read) { break; @@ -862,8 +887,9 @@ FreeXid(xid); return rc; } - } else + } else { *poffset += bytes_read; + } } FreeXid(xid); @@ -899,7 +925,6 @@ break; page = list_entry(pages->prev, struct page, lru); - list_del(&page->lru); if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { @@ -908,24 +933,24 @@ continue; } - page_cache_get(page); target = kmap_atomic(page,KM_USER0); if(PAGE_CACHE_SIZE > bytes_read) { memcpy(target,data,bytes_read); + /* zero the tail end of this partial page */ + memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read); bytes_read = 0; } else { memcpy(target,data,PAGE_CACHE_SIZE); bytes_read -= PAGE_CACHE_SIZE; } + kunmap_atomic(target,KM_USER0); - if (!pagevec_add(plru_pvec, page)) - __pagevec_lru_add(plru_pvec); flush_dcache_page(page); SetPageUptodate(page); - kunmap_atomic(target,KM_USER0); unlock_page(page); - page_cache_release(page); + if (!pagevec_add(plru_pvec, page)) + __pagevec_lru_add(plru_pvec); data += PAGE_CACHE_SIZE; } return; @@ -947,46 +972,78 @@ char * smb_read_data = 0; struct smb_com_read_rsp * pSMBr; struct pagevec lru_pvec; + struct cifsFileInfo * open_file; xid = GetXid(); if (file->private_data == NULL) { FreeXid(xid); return -EBADF; } - + open_file = (struct cifsFileInfo *)file->private_data; cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; pagevec_init(&lru_pvec, 0); for(i = 0;iprev, struct page, lru); offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + /* count adjacent pages that we will read into */ + contig_pages = 0; + expected_index = list_entry(page_list->prev,struct page,lru)->index; + list_for_each_entry_reverse(tmp_page,page_list,lru) { + if(tmp_page->index == expected_index) { + contig_pages++; + expected_index++; + } else { + break; + } + } + if(contig_pages + i > num_pages) { + contig_pages = num_pages - i; + } + /* for reads over a certain size could initiate async read ahead */ - cFYI(0,("Read %d pages into cache at offset %ld ", - num_pages-i, (unsigned long) offset)); - - read_size = (num_pages - i) * PAGE_CACHE_SIZE; + read_size = contig_pages * PAGE_CACHE_SIZE; /* Read size needs to be in multiples of one page */ read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK); - rc = CIFSSMBRead(xid, pTcon, - ((struct cifsFileInfo *) file-> - private_data)->netfid, - read_size, offset, - &bytes_read, &smb_read_data); + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + read_size, offset, + &bytes_read, &smb_read_data); + /* BB need to check return code here */ + if(rc== -EAGAIN) { + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = 0; + } + } + } if ((rc < 0) || (smb_read_data == NULL)) { cFYI(1,("Read error in readpages: %d",rc)); /* clean up remaing pages off list */ - while (!list_empty(page_list) && (i < num_pages)) { - page = list_entry(page_list->prev, - struct page, lru); + page = list_entry(page_list->prev, struct page, lru); list_del(&page->lru); + page_cache_release(page); } break; } else if (bytes_read > 0) { @@ -994,24 +1051,37 @@ cifs_copy_cache_pages(mapping, page_list, bytes_read, smb_read_data + 4 /* RFC1000 hdr */ + le16_to_cpu(pSMBr->DataOffset), &lru_pvec); + i += bytes_read >> PAGE_CACHE_SHIFT; - if((bytes_read & PAGE_CACHE_MASK) != bytes_read) { + + if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); - break; + + i++; /* account for partial page */ + + /* server copy of file can have smaller size than client */ + /* BB do we need to verify this common case ? this case is ok - + if we are at server EOF we will hit it on next read */ + + /* while(!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev,struct page, list); + list_del(&page->list); + page_cache_release(page); + } + break; */ } } else { - cFYI(1,("No bytes read cleaning remaining pages off readahead list")); + cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); /* BB turn off caching and do new lookup on file size at server? */ while (!list_empty(page_list) && (i < num_pages)) { - page = list_entry(page_list->prev, - struct page, lru); + page = list_entry(page_list->prev, struct page, lru); list_del(&page->lru); + page_cache_release(page); /* BB removeme - replace with zero of page? */ } - break; } if(smb_read_data) { - buf_release(smb_read_data); + cifs_buf_release(smb_read_data); smb_read_data = 0; } bytes_read = 0; @@ -1019,6 +1089,12 @@ pagevec_lru_add(&lru_pvec); +/* need to free smb_read_data buf before exit */ + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = 0; + } + FreeXid(xid); return rc; } @@ -1122,7 +1198,7 @@ }/* could add code here - to validate if device or weird share type? */ /* can not fill in nlink here as in qpathinfo version and Unx search */ - tmp_inode->i_size = pfindData->EndOfFile; + i_size_write(tmp_inode,pfindData->EndOfFile); tmp_inode->i_blocks = (tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits; if (pfindData->AllocationSize < pfindData->EndOfFile) @@ -1196,7 +1272,7 @@ pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - tmp_inode->i_size = pfindData->EndOfFile; + i_size_write(tmp_inode,pfindData->EndOfFile); tmp_inode->i_blocks = (tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits; @@ -1220,7 +1296,7 @@ } } -void +static void construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { @@ -1244,6 +1320,11 @@ } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); + if(tmp_dentry == NULL) { + cERROR(1,("Failed allocating dentry")); + return; + } + *ptmp_inode = new_inode(file->f_dentry->d_sb); tmp_dentry->d_op = &cifs_dentry_ops; cFYI(0, (" instantiate dentry 0x%p with inode 0x%p ", @@ -1256,13 +1337,44 @@ *pnew_dentry = tmp_dentry; } -void +static void reset_resume_key(struct file * dir_file, + unsigned char * filename, + unsigned int len,int Unicode,struct nls_table * nls_tab) { + struct cifsFileInfo *cifsFile; + + cifsFile = (struct cifsFileInfo *)dir_file->private_data; + if(cifsFile == NULL) + return; + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + } + + if(Unicode) + len *= 2; + cifsFile->resume_name_length = len; + + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + + if(Unicode) + cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, + filename, len, nls_tab); + else + memcpy(cifsFile->search_resume_name, filename, + cifsFile->resume_name_length); + cFYI(1,("Reset resume key to: %s with len %d",filename,len)); + return; +} + + + +static int cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, struct file *file, filldir_t filldir, void *direntry) { struct inode *tmp_inode; struct dentry *tmp_dentry; - int object_type; + int object_type,rc; pqstring->name = pfindData->FileName; pqstring->len = pfindData->FileNameLength; @@ -1270,19 +1382,25 @@ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); fill_in_inode(tmp_inode, pfindData, &object_type); - filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, + rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); + } dput(tmp_dentry); + return rc; } -void +static int cifs_filldir_unix(struct qstr *pqstring, FILE_UNIX_INFO * pUnixFindData, struct file *file, filldir_t filldir, void *direntry) { struct inode *tmp_inode; struct dentry *tmp_dentry; - int object_type; + int object_type, rc; pqstring->name = pUnixFindData->FileName; pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); @@ -1290,9 +1408,15 @@ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); - filldir(direntry, pUnixFindData->FileName, pqstring->len, + rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); + } dput(tmp_dentry); + return rc; } int @@ -1378,8 +1502,7 @@ searchHandle = findParms.SearchHandle; if(file->private_data == NULL) file->private_data = - kmalloc(sizeof(struct cifsFileInfo), - GFP_KERNEL); + kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); if (file->private_data) { memset(file->private_data, 0, sizeof (struct cifsFileInfo)); @@ -1387,6 +1510,7 @@ (struct cifsFileInfo *) file->private_data; cifsFile->netfid = searchHandle; cifsFile->invalidHandle = FALSE; + init_MUTEX(&cifsFile->fh_sem); } else { rc = -ENOMEM; break; @@ -1471,10 +1595,18 @@ FileName[0] != '.') || (pfindData-> FileName[1] != '.'))) { - cifs_filldir(&qstring, + if(cifs_filldir(&qstring, pfindData, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode, cifs_sb->local_nls); + findParms.EndofSearch = 0; + break; + } file->f_pos++; } } else { /* UnixSearch */ @@ -1501,11 +1633,19 @@ FileName[0] != '.') || (pfindDataUnix-> FileName[1] != '.'))) { - cifs_filldir_unix(&qstring, + if(cifs_filldir_unix(&qstring, pfindDataUnix, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findParms.EndofSearch = 0; + reset_resume_key(file, pfindDataUnix->FileName, + qstring.len,Unicode,cifs_sb->local_nls); + break; + } file->f_pos++; } } @@ -1573,6 +1713,11 @@ rc = -ENOMEM; break; } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); cifsFile->search_resume_name = kmalloc(cifsFile->resume_name_length, GFP_KERNEL); cFYI(1,("Last file: %s with name %d bytes long", @@ -1603,6 +1748,11 @@ rc = -ENOMEM; break; } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); cifsFile->search_resume_name = kmalloc(cifsFile->resume_name_length, GFP_KERNEL); cFYI(1,("fnext last file: %s with name %d bytes long", @@ -1634,11 +1784,19 @@ || (pfindData->FileName[0] != '.') || (pfindData->FileName[1] != '.'))) { - cifs_filldir + if(cifs_filldir (&qstring, pfindData, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } file->f_pos++; } } else { /* UnixSearch */ @@ -1668,11 +1826,19 @@ || (pfindDataUnix-> FileName[1] != '.'))) { - cifs_filldir_unix + if(cifs_filldir_unix (&qstring, pfindDataUnix, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + reset_resume_key(file, pfindDataUnix->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } file->f_pos++; } } @@ -1696,34 +1862,31 @@ return rc; } +int cifs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + cFYI(1,("prepare write for page %p from %d to %d",page,from,to)); + if (!PageUptodate(page)) { + if (to - from != PAGE_CACHE_SIZE) { + void *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr, 0, from); + memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + } + SetPageUptodate(page); + } + return 0; +} -struct address_space_operations cifs_addr_ops = { - .readpage = cifs_readpage, - .readpages = cifs_readpages, - .writepage = cifs_writepage, - .prepare_write = simple_prepare_write, - .commit_write = cifs_commit_write, - .sync_page = cifs_sync_page, - /*.direct_IO = */ -}; - -struct address_space_operations cifs_addr_ops_writethrough = { - .readpage = cifs_readpage, - .readpages = cifs_readpages, - .writepage = cifs_writepage, - .prepare_write = simple_prepare_write, - .commit_write = cifs_commit_write, - .sync_page = cifs_sync_page, - /*.direct_IO = */ -}; -struct address_space_operations cifs_addr_ops_nocache = { +struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, - .prepare_write = simple_prepare_write, + .prepare_write = simple_prepare_write, /* BB fixme BB */ +/* .prepare_write = cifs_prepare_write, */ /* BB removeme BB */ .commit_write = cifs_commit_write, - .sync_page = cifs_sync_page, + /* .sync_page = cifs_sync_page, */ /*.direct_IO = */ }; - diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c --- a/fs/cifs/inode.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/inode.c Sun Apr 25 22:39:31 2004 @@ -125,7 +125,7 @@ inode->i_nlink = le64_to_cpu(findData.Nlinks); findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); findData.EndOfFile = le64_to_cpu(findData.EndOfFile); - inode->i_size = findData.EndOfFile; + i_size_write(inode,findData.EndOfFile); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize will match */ /* inode->i_blksize = @@ -204,10 +204,10 @@ strnlen(search_path, MAX_PATHCONF) + 1, GFP_KERNEL); if (tmp_path == NULL) { - if(buf) - kfree(buf); - FreeXid(xid); - return -ENOMEM; + if(buf) + kfree(buf); + FreeXid(xid); + return -ENOMEM; } strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); @@ -218,10 +218,10 @@ kfree(tmp_path); /* BB fix up inode etc. */ } else if (rc) { - if(buf) - kfree(buf); - FreeXid(xid); - return rc; + if(buf) + kfree(buf); + FreeXid(xid); + return rc; } } else { struct cifsInodeInfo *cifsInfo; @@ -272,10 +272,10 @@ inode->i_mode &= ~(S_IWUGO); /* BB add code here - validate if device or weird share or device type? */ } - inode->i_size = le64_to_cpu(pfindData->EndOfFile); + i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); inode->i_blocks = - (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits; + (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits; inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); @@ -380,8 +380,8 @@ __u16 netfid; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, - CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, - &netfid, &oplock, NULL, cifs_sb->local_nls); + CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, + &netfid, &oplock, NULL, cifs_sb->local_nls); if(rc==0) { CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls); CIFSSMBClose(xid, pTcon, netfid); @@ -426,6 +426,7 @@ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); + d_drop(direntry); } else { inode->i_nlink++; if (pTcon->ses->capabilities & CAP_UNIX) @@ -479,7 +480,7 @@ if (!rc) { inode->i_nlink--; - direntry->d_inode->i_size = 0; + i_size_write(direntry->d_inode,0); direntry->d_inode->i_nlink = 0; } @@ -530,17 +531,17 @@ } if((rc == -EIO)||(rc == -EEXIST)) { - int oplock = FALSE; - __u16 netfid; + int oplock = FALSE; + __u16 netfid; - rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, - CREATE_NOT_DIR, - &netfid, &oplock, NULL, cifs_sb_source->local_nls); - if(rc==0) { - CIFSSMBRenameOpenFile(xid,pTcon,netfid, - toName, cifs_sb_source->local_nls); - CIFSSMBClose(xid, pTcon, netfid); - } + rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, + &netfid, &oplock, NULL, cifs_sb_source->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid, + toName, cifs_sb_source->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + } } if (fromName) kfree(fromName); @@ -559,6 +560,21 @@ char *full_path; struct cifs_sb_info *cifs_sb; struct cifsInodeInfo *cifsInode; + loff_t local_size; + struct timespec local_mtime; + int invalidate_inode = FALSE; + + if(direntry->d_inode == NULL) + return -ENOENT; + + cifsInode = CIFS_I(direntry->d_inode); + + if(cifsInode == NULL) + return -ENOENT; + + /* no sense revalidating inode info on file that no one can write */ + if(CIFS_I(direntry->d_inode)->clientCanCacheRead) + return rc; xid = GetXid(); @@ -566,16 +582,14 @@ full_path = build_path_from_dentry(direntry); cFYI(1, - ("Revalidate full path: %s for inode 0x%p with count %d dentry: 0x%p d_time %ld at time %ld ", + ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld", full_path, direntry->d_inode, direntry->d_inode->i_count.counter, direntry, direntry->d_time, jiffies)); - - cifsInode = CIFS_I(direntry->d_inode); - /* BB add check - do not need to revalidate oplocked files */ - - if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { + if (cifsInode->time == 0){ + /* was set to zero previously to force revalidate */ + } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { if((S_ISREG(direntry->d_inode->i_mode) == 0) || (direntry->d_inode->i_nlink == 1)) { if (full_path) @@ -586,6 +600,10 @@ cFYI(1,("Have to revalidate file due to hardlinks")); } } + + /* save mtime and size */ + local_mtime = direntry->d_inode->i_mtime; + local_size = direntry->d_inode->i_size; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, @@ -606,8 +624,43 @@ } /* should we remap certain errors, access denied?, to zero */ - /* BB if not oplocked, invalidate inode pages if mtime has changed */ + /* if not oplocked, we invalidate inode pages if mtime + or file size had changed on server */ + + if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && + (local_size == direntry->d_inode->i_size)) { + cFYI(1,("cifs_revalidate - inode unchanged")); + } else { + /* file may have changed on server */ + if(cifsInode->clientCanCacheRead) { + /* no need to invalidate inode pages since we were + the only ones who could have modified the file and + the server copy is staler than ours */ + } else { + invalidate_inode = TRUE; + } + } + + /* need to write out dirty pages here */ + down(&direntry->d_inode->i_sem); + if(direntry->d_inode->i_mapping) { + /* do we need to lock inode until after invalidate completes below? */ + filemap_fdatawrite(direntry->d_inode->i_mapping); + } + if(invalidate_inode) { + filemap_fdatawait(direntry->d_inode->i_mapping); + /* may eventually have to do this for open files too */ + if(list_empty(&(cifsInode->openFileList))) { + /* Has changed on server - flush read ahead pages */ + cFYI(1,("Invalidating read ahead data on closed file")); + invalidate_remote_inode(direntry->d_inode); + } + } + + + up(&direntry->d_inode->i_sem); + if (full_path) kfree(full_path); FreeXid(xid); @@ -623,78 +676,25 @@ return err; } -void -cifs_truncate_file(struct inode *inode) -{ /* BB remove - may not need this function after all BB */ - int xid; +static int cifs_truncate_page(struct address_space *mapping, loff_t from) +{ + pgoff_t index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + struct page *page; + char *kaddr; int rc = 0; - struct cifsFileInfo *open_file = NULL; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - struct cifsInodeInfo *cifsInode; - struct dentry *dirent; - char *full_path = NULL; - - xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - - if (list_empty(&inode->i_dentry)) { - cERROR(1, - ("Can not get pathname from empty dentry in inode 0x%p ", - inode)); - FreeXid(xid); - return; - } - dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias); - if (dirent) { - full_path = build_path_from_dentry(dirent); - rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE, - cifs_sb->local_nls); - cFYI(1,(" SetEOF (truncate) rc = %d",rc)); - if(rc == -ETXTBSY) { - cifsInode = CIFS_I(inode); - if(!list_empty(&(cifsInode->openFileList))) { - open_file = list_entry(cifsInode->openFileList.next, - struct cifsFileInfo, flist); - /* We could check if file is open for writing first */ - rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, - open_file->netfid,open_file->pid,FALSE); - } else { - cFYI(1,(" No open files to get file handle from")); - } - } - if (!rc) - CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls); - /* allocation size setting seems optional so ignore return code */ - } - if (full_path) - kfree(full_path); - FreeXid(xid); - return; -} - -static int cifs_trunc_page(struct address_space *mapping, loff_t from) -{ - pgoff_t index = from >> PAGE_CACHE_SHIFT; - unsigned offset = from & (PAGE_CACHE_SIZE-1); - struct page *page; - char *kaddr; - int rc = 0; - - page = grab_cache_page(mapping, index); - if (!page) - return -ENOMEM; - - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - set_page_dirty(page); - unlock_page(page); - page_cache_release(page); - return rc; + page = grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + unlock_page(page); + page_cache_release(page); + return rc; } int @@ -705,6 +705,7 @@ struct cifsTconInfo *pTcon; char *full_path = NULL; int rc = -EACCES; + int found = FALSE; struct cifsFileInfo *open_file = NULL; FILE_BASIC_INFO time_buf; int set_time = FALSE; @@ -712,6 +713,7 @@ __u64 uid = 0xFFFFFFFFFFFFFFFFULL; __u64 gid = 0xFFFFFFFFFFFFFFFFULL; struct cifsInodeInfo *cifsInode; + struct list_head * tmp; xid = GetXid(); @@ -726,32 +728,63 @@ /* BB check if we need to refresh inode from server now ? BB */ - cFYI(1, (" Changing attributes 0x%x", attrs->ia_valid)); + /* need to flush data before changing file size on server */ + filemap_fdatawrite(direntry->d_inode->i_mapping); + filemap_fdatawait(direntry->d_inode->i_mapping); if (attrs->ia_valid & ATTR_SIZE) { - rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, - cifs_sb->local_nls); - cFYI(1,(" SetEOF (setattrs) rc = %d",rc)); + read_lock(&GlobalSMBSeslock); + /* To avoid spurious oplock breaks from server, in the case + of inodes that we already have open, avoid doing path + based setting of file size if we can do it by handle. + This keeps our caching token (oplock) and avoids + timeouts when the local oplock break takes longer to flush + writebehind data than the SMB timeout for the SetPathInfo + request would allow */ + list_for_each(tmp, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + /* We check if file is open for writing first */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + if(open_file->invalidHandle == FALSE) { + /* we found a valid, writeable network file + handle to use to try to set the file size */ + __u16 nfid = open_file->netfid; + __u32 npid = open_file->pid; + read_unlock(&GlobalSMBSeslock); + found = TRUE; + rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, + nfid,npid,FALSE); + cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc)); + /* Do not need reopen and retry on EAGAIN since we will + retry by pathname below */ - if(rc == -ETXTBSY) { - if(!list_empty(&(cifsInode->openFileList))) { - open_file = list_entry(cifsInode->openFileList.next, - struct cifsFileInfo, flist); - /* We could check if file is open for writing first */ - rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, - open_file->netfid,open_file->pid,FALSE); - } else { - cFYI(1,(" No open files to get file handle from")); + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } } } - /* For Allocation Size - do not need to call the following - it did not hurt if it fails but why bother */ - /* CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/ + if(found == FALSE) { + read_unlock(&GlobalSMBSeslock); + } + + + if(rc != 0) { + /* Set file size by pathname rather than by handle either + because no valid, writeable file handle for it was found or + because there was an error setting it by handle */ + rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, + cifs_sb->local_nls); + cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc)); + } + + /* Server is ok setting allocation size implicitly - no need to call: */ + /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/ + if (rc == 0) { rc = vmtruncate(direntry->d_inode, attrs->ia_size); - cifs_trunc_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); - -/* cFYI(1,("truncate_page to 0x%lx \n",direntry->d_inode->i_size)); */ + cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); } } if (attrs->ia_valid & ATTR_UID) { @@ -816,6 +849,8 @@ /* BB what if setting one attribute fails (such as size) but time setting works */ time_buf.CreationTime = 0; /* do not change */ + /* In the future we should experiment - try setting timestamps + via Handle (SetFileInfo) instead of by path */ rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, cifs_sb->local_nls); } @@ -831,8 +866,7 @@ void cifs_delete_inode(struct inode *inode) { - /* Note: called without the big kernel filelock - remember spinlocks! */ cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); - /* may have to add back in when safe distributed caching of - directories via e.g. FindNotify added */ + /* may have to add back in if and when safe distributed caching of + directories added e.g. via FindNotify */ } diff -Nru a/fs/cifs/link.c b/fs/cifs/link.c --- a/fs/cifs/link.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/link.c Sun Apr 25 22:39:31 2004 @@ -96,6 +96,8 @@ pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); if(target_path == NULL) { + if (full_path) + kfree(full_path); FreeXid(xid); return -ENOMEM; } @@ -212,6 +214,8 @@ len = buflen; tmpbuffer = kmalloc(len,GFP_KERNEL); if(tmpbuffer == NULL) { + if (full_path) + kfree(full_path); FreeXid(xid); return -ENOMEM; } @@ -251,10 +255,11 @@ cFYI(1,("num referral: %d",num_referrals)); if(referrals) { cFYI(1,("referral string: %s ",referrals)); - strncpy(tmpbuffer, referrals, len-1); + strncpy(tmpbuffer, referrals, len-1); } } - + if(referrals) + kfree(referrals); kfree(tmp_path); if(referrals) { kfree(referrals); diff -Nru a/fs/cifs/md4.c b/fs/cifs/md4.c --- a/fs/cifs/md4.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/md4.c Sun Apr 25 22:39:31 2004 @@ -3,7 +3,7 @@ Version 1.9. a implementation of MD4 designed for use in the SMB authentication protocol Copyright (C) Andrew Tridgell 1997-1998. - Modified by Steve French (sfrench@us.ibm.com) 2002 + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 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 @@ -21,13 +21,7 @@ */ #include #include - -/* NOTE: This code makes no attempt to be fast! - - It assumes that a int is at least 32 bits long -*/ - -static __u32 A, B, C, D; +/* NOTE: This code makes no attempt to be fast! */ static __u32 F(__u32 X, __u32 Y, __u32 Z) @@ -54,25 +48,26 @@ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); } -#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) -#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (__u32)0x5A827999,s) -#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (__u32)0x6ED9EBA1,s) +#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) /* this applies md4 to 64 byte chunks */ static void -mdfour64(__u32 * M) +mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D) { int j; __u32 AA, BB, CC, DD; __u32 X[16]; + for (j = 0; j < 16; j++) X[j] = M[j]; - AA = A; - BB = B; - CC = C; - DD = D; + AA = *A; + BB = *B; + CC = *C; + DD = *D; ROUND1(A, B, C, D, 0, 3); ROUND1(D, A, B, C, 1, 7); @@ -125,15 +120,15 @@ ROUND3(C, D, A, B, 7, 11); ROUND3(B, C, D, A, 15, 15); - A += AA; - B += BB; - C += CC; - D += DD; - - A &= 0xFFFFFFFF; - B &= 0xFFFFFFFF; - C &= 0xFFFFFFFF; - D &= 0xFFFFFFFF; + *A += AA; + *B += BB; + *C += CC; + *D += DD; + + *A &= 0xFFFFFFFF; + *B &= 0xFFFFFFFF; + *C &= 0xFFFFFFFF; + *D &= 0xFFFFFFFF; for (j = 0; j < 16; j++) X[j] = 0; @@ -166,15 +161,14 @@ __u32 M[16]; __u32 b = n * 8; int i; - - A = 0x67452301; - B = 0xefcdab89; - C = 0x98badcfe; - D = 0x10325476; + __u32 A = 0x67452301; + __u32 B = 0xefcdab89; + __u32 C = 0x98badcfe; + __u32 D = 0x10325476; while (n > 64) { copy64(M, in); - mdfour64(M); + mdfour64(M,&A,&B, &C, &D); in += 64; n -= 64; } @@ -187,13 +181,13 @@ if (n <= 55) { copy4(buf + 56, b); copy64(M, buf); - mdfour64(M); + mdfour64(M, &A, &B, &C, &D); } else { copy4(buf + 120, b); copy64(M, buf); - mdfour64(M); + mdfour64(M, &A, &B, &C, &D); copy64(M, buf + 64); - mdfour64(M); + mdfour64(M, &A, &B, &C, &D); } for (i = 0; i < 128; i++) diff -Nru a/fs/cifs/misc.c b/fs/cifs/misc.c --- a/fs/cifs/misc.c Sun Apr 25 22:39:32 2004 +++ b/fs/cifs/misc.c Sun Apr 25 22:39:32 2004 @@ -25,6 +25,8 @@ #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" +#include "smberr.h" +#include "nterr.h" extern kmem_cache_t *cifs_req_cachep; extern struct task_struct * oplockThread; @@ -99,6 +101,8 @@ kfree(buf_to_free->serverDomain); if (buf_to_free->serverNOS) kfree(buf_to_free->serverNOS); + if (buf_to_free->password) + kfree(buf_to_free->password); kfree(buf_to_free); } @@ -139,20 +143,10 @@ kfree(buf_to_free); } -void * -kcalloc(size_t size, int type) -{ - void *addr; - addr = kmalloc(size, type); - if (addr) - memset(addr, 0, size); - return addr; -} - struct smb_hdr * -buf_get(void) +cifs_buf_get(void) { - struct smb_hdr *ret_buf; + struct smb_hdr *ret_buf = 0; /* We could use negotiated size instead of max_msgsize - but it may be more efficient to always alloc same size @@ -171,11 +165,11 @@ } void -buf_release(void *buf_to_free) +cifs_buf_release(void *buf_to_free) { if (buf_to_free == NULL) { - cFYI(1, ("Null buffer passed to buf_release")); + cFYI(1, ("Null buffer passed to cifs_buf_release")); return; } kmem_cache_free(cifs_req_cachep, buf_to_free); @@ -267,7 +261,7 @@ buffer->Uid = ses->Suid; break; } else { - /* BB eventually call setup_session here */ + /* BB eventually call cifs_setup_session here */ cFYI(1,("local UID found but smb sess with this server does not exist")); } } @@ -324,8 +318,8 @@ ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, ntohl(smb->smb_buf_length))); if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) - || (4 + ntohl(smb->smb_buf_length) > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)) { + || (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) { if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) @@ -333,8 +327,8 @@ return 0; /* some error cases do not return wct and bcc */ } - if (4 + ntohl(smb->smb_buf_length) > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) + if (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) cERROR(1, ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... ")); cERROR(1, @@ -369,8 +363,22 @@ cFYI(1,("Checking for oplock break")); if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) return FALSE; - if(pSMB->hdr.Flags & SMBFLG_RESPONSE) - return FALSE; /* server sends us "request" here */ + if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { + /* no sense logging error on invalid handle on oplock + break - harmless race between close request and oplock + break response is expected from time to time writing out + large dirty files cached on the client */ + if ((NT_STATUS_INVALID_HANDLE) == + le32_to_cpu(pSMB->hdr.Status.CifsError)) { + cFYI(1,("invalid handle on oplock break")); + return TRUE; + } else if (ERRbadfid == + le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { + return TRUE; + } else { + return FALSE; /* on valid oplock brk we get "request" */ + } + } if(pSMB->hdr.WordCount != 8) return FALSE; @@ -387,8 +395,6 @@ netfile = list_entry(tmp1,struct cifsFileInfo,tlist); if(pSMB->Fid == netfile->netfid) { struct cifsInodeInfo *pCifsInode; - /* BB Add following logic to mark inode for write through - inode->i_data.a_ops = &cifs_addr_ops_writethrough; */ read_unlock(&GlobalSMBSeslock); cFYI(1,("Matching file id, processing oplock break")); pCifsInode = diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/netmisc.c Sun Apr 25 22:39:31 2004 @@ -125,10 +125,10 @@ /* Convert string containing dotted ip address to binary form */ /* returns 0 if invalid address */ -/* BB add address family, change rc to status flag and return *//* also see inet_pton */ -/* To identify v4 vs. v6 - 1) check for colon (v6 only) 2) then call inet_pton to parse for bad address */ +/* BB add address family, change rc to status flag and return union or for ipv6 */ +/* will need parent to call something like inet_pton to convert ipv6 address BB */ int -inet_addr(char *cp) +cifs_inet_pton(int address_family, char *cp,void *dst) { struct in_addr address; int value; @@ -140,6 +140,9 @@ static const int addr_class_max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + if(address_family != AF_INET) + return -EAFNOSUPPORT; + for (i = 0; i < 4; i++) { bytes[i] = 0; } @@ -166,6 +169,9 @@ return 0; *end++ = value; temp = *++cp; + } else if (temp == ':') { + cFYI(1,("IPv6 addresses not supported for CIFS mounts yet")); + return -1; } else break; } @@ -182,8 +188,8 @@ return 0; address.s_addr = *((int *) bytes) | htonl(value); - return address.s_addr; - + *((int *)dst) = address.s_addr; + return 1; /* success */ } /***************************************************************************** diff -Nru a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/cifs/rfc1002pdu.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,75 @@ +/* + * fs/cifs/rfc1002pdu.h + * + * Protocol Data Unit definitions for RFC 1001/1002 support + * + * Copyright (c) International Business Machines Corp., 2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma pack(1) + +/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ + + /* RFC 1002 session packet types */ +#define RFC1002_SESSION_MESASAGE 0x00 +#define RFC1002_SESSION_REQUEST 0x81 +#define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 +#define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 +#define RFC1002_RETARGET_SESSION_RESPONSE 0x83 +#define RFC1002_SESSION_KEEP_ALIVE 0x85 + + /* RFC 1002 flags (only one defined */ +#define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */ + +struct rfc1002_session_packet { + __u8 type; + __u8 flags; + __u16 length; + union { + struct { + __u8 called_name[16]; + __u8 calling_name[16]; + } session_req; + struct { + __u32 retarget_ip_addr; + __u16 port; + } retarget_resp; + __u8 neg_ses_resp_error_code; + /* POSITIVE_SESSION_RESPONSE packet does not include trailer. + SESSION_KEEP_ALIVE packet also does not include a trailer. + Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ + } trailer; +}; + +/* Negative Session Response error codes */ +#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ +#define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */ +#define RFC1002_NOT_PRESENT 0x82 /* called name not present */ +#define RFC1002_INSUFFICIENT_RESOURCE 0x83 +#define RFC1002_UNSPECIFIED_ERROR 0x8F + +/* RFC 1002 Datagram service packets are not defined here as they +are not needed for the network filesystem client unless we plan on +implementing broadcast resolution of the server ip address (from +server netbios name). Currently server names are resolved only via DNS +(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ + +#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " + +#pragma pack() /* resume default structure packing */ + diff -Nru a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c --- a/fs/cifs/smbencrypt.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/smbencrypt.c Sun Apr 25 22:39:31 2004 @@ -23,8 +23,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -extern int DEBUGLEVEL; - #include #include #include @@ -45,9 +43,7 @@ /* following came from the other byteorder.h to avoid include conflicts */ #define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) -#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16)) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) -#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((__u32)(val))) /*The following definitions come from lib/md4.c */ @@ -96,12 +92,6 @@ SMBOWFencrypt(p21, c8, p24); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBencrypt: lm#, challenge, response\n")); - dump_data(100, (char *) p21, 16); - dump_data(100, (char *) c8, 8); - dump_data(100, (char *) p24, 24); -#endif memset(p14,0,15); memset(p21,0,21); } @@ -151,12 +141,17 @@ __u16 wpwd[129]; /* Password cannot be longer than 128 characters */ - len = strlen((char *) passwd); - if (len > 128) - len = 128; - /* Password must be converted to NT unicode */ - _my_mbstowcs(wpwd, passwd, len); - wpwd[len] = 0; /* Ensure string is null terminated */ + if(passwd) { + len = strlen((char *) passwd); + if (len > 128) { + len = 128; + } + /* Password must be converted to NT unicode */ + _my_mbstowcs(wpwd, passwd, len); + } else + len = 0; + + wpwd[len] = 0; /* Ensure string is null terminated */ /* Calculate length in bytes */ len = _my_wcslen(wpwd) * sizeof (__u16); @@ -179,12 +174,6 @@ memset(nt_p16, '\0', 16); E_md4hash(passwd, nt_p16); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("nt_lm_owf_gen: pwd, nt#\n")); - dump_data(120, passwd, strlen(passwd)); - dump_data(100, (char *) nt_p16, 16); -#endif - /* Mangle the passwords into Lanman format */ passwd[14] = '\0'; /* strupper(passwd); */ @@ -194,11 +183,6 @@ memset(p16, '\0', 16); E_P16((unsigned char *) passwd, (unsigned char *) p16); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("nt_lm_owf_gen: pwd, lm#\n")); - dump_data(120, passwd, strlen(passwd)); - dump_data(100, (char *) p16, 16); -#endif /* clear out local copy of user's password (just being paranoid). */ memset(passwd, '\0', sizeof (passwd)); } @@ -235,13 +219,6 @@ hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); hmac_md5_final(kr_buf, &ctx); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n")); - dump_data(100, user_u, user_l * 2); - dump_data(100, dom_u, domain_l * 2); - dump_data(100, owf, 16); - dump_data(100, kr_buf, 16); -#endif kfree(user_u); } @@ -270,12 +247,6 @@ memset(p21 + 8, 0xbd, 8); E_P24(p21, ntlmchalresp, p24); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("NTLMSSPOWFencrypt: p21, c8, p24\n")); - dump_data(100, (char *) p21, 21); - dump_data(100, (char *) ntlmchalresp, 8); - dump_data(100, (char *) p24, 24); -#endif } /* Does the NT MD4 hash then des encryption. */ @@ -289,13 +260,6 @@ E_md4hash(passwd, p21); SMBOWFencrypt(p21, c8, p24); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBNTencrypt: nt#, challenge, response\n")); - dump_data(100, (char *) p21, 16); - dump_data(100, (char *) c8, 8); - dump_data(100, (char *) p24, 24); -#endif } /* Does the md5 encryption from the NT hash for NTLMv2. */ @@ -310,37 +274,6 @@ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); hmac_md5_final(resp_buf, &ctx); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); - dump_data(100, srv_chal->data, srv_chal->length); - dump_data(100, cli_chal->data, cli_chal->length); - dump_data(100, resp_buf, 16); -#endif -} - -static struct data_blob LMv2_generate_response(const unsigned char ntlm_v2_hash[16], - const struct data_blob * server_chal) -{ - unsigned char lmv2_response[16]; - struct data_blob lmv2_client_data/* = data_blob(NULL, 8)*/; /* BB Fix BB */ - struct data_blob final_response /* = data_blob(NULL, 24)*/; /* BB Fix BB */ - - /* LMv2 */ - /* client-supplied random data */ - get_random_bytes(lmv2_client_data.data, lmv2_client_data.length); - /* Given that data, and the challenge from the server, generate a response */ - SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response); - memcpy(final_response.data, lmv2_response, sizeof(lmv2_response)); - - /* after the first 16 bytes is the random data we generated above, - so the server can verify us with it */ - memcpy(final_response.data+sizeof(lmv2_response), - lmv2_client_data.data, lmv2_client_data.length); - -/* data_blob_free(&lmv2_client_data); */ /* BB fix BB */ - - return final_response; } void @@ -352,11 +285,6 @@ hmac_md5_init_limK_to_64(kr, 16, &ctx); hmac_md5_update(nt_resp, 16, &ctx); hmac_md5_final((unsigned char *) sess_key, &ctx); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_ntv2:\n")); - dump_data(100, sess_key, 16); -#endif } void @@ -364,66 +292,4 @@ const unsigned char *nt_resp, __u8 sess_key[16]) { mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_ntv1:\n")); - dump_data(100, sess_key, 16); -#endif -} - -/*********************************************************** - encode a password buffer. The caller gets to figure out - what to put in it. -************************************************************/ -int -encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length) -{ - get_random_bytes(buffer, sizeof (buffer)); - - memcpy(&buffer[512 - new_pw_length], new_pw, new_pw_length); - - /* - * The length of the new password is in the last 4 bytes of - * the data buffer. - */ - SIVAL(buffer, 512, new_pw_length); - - return TRUE; -} - -int SMBNTLMv2encrypt(const char *user, const char *domain, const char *password, - const struct data_blob *server_chal, - const struct data_blob *names_blob, - struct data_blob *lm_response, struct data_blob *nt_response, - struct data_blob *nt_session_key,struct nls_table * nls_codepage) -{ - unsigned char nt_hash[16]; - unsigned char ntlm_v2_hash[16]; - E_md4hash(password, nt_hash); - - /* We don't use the NT# directly. Instead we use it mashed up with - the username and domain. - This prevents username swapping during the auth exchange - */ - ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash,nls_codepage); - - if (nt_response) { -/* *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, - names_blob); */ /* BB fix BB */ - if (nt_session_key) { -/* *nt_session_key = data_blob(NULL, 16); */ /* BB fix BB */ - - /* The NTLMv2 calculations also provide a session key, for signing etc later */ - /* use only the first 16 bytes of nt_response for session key */ - SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data); - } - } - - /* LMv2 */ - - if (lm_response) { - *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal); - } - - return TRUE; } diff -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c --- a/fs/cifs/transport.c Sun Apr 25 22:39:31 2004 +++ b/fs/cifs/transport.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* * fs/cifs/transport.c * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -29,7 +29,7 @@ #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" - + extern kmem_cache_t *cifs_mid_cachep; extern kmem_cache_t *cifs_oplock_cachep; @@ -37,7 +37,6 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) { struct mid_q_entry *temp; - int timeout = 10 * HZ; if (ses == NULL) { cERROR(1, ("Null session passed in to AllocMidQEntry ")); @@ -63,25 +62,11 @@ temp->tsk = current; } - while ((ses->server->tcpStatus != CifsGood) && (timeout > 0)){ - /* Give the tcp thread up to 10 seconds to reconnect */ - /* Should we wake up tcp thread first? BB */ - timeout = wait_event_interruptible_timeout(ses->server->response_q, - (ses->server->tcpStatus == CifsGood), timeout); - } - - if (ses->server->tcpStatus == CifsGood) { - spin_lock(&GlobalMid_Lock); - list_add_tail(&temp->qhead, &ses->server->pending_mid_q); - atomic_inc(&midCount); - temp->midState = MID_REQUEST_ALLOCATED; - spin_unlock(&GlobalMid_Lock); - } else { - cERROR(1,("Need to reconnect after session died to server")); - if (temp) - kmem_cache_free(cifs_mid_cachep, temp); - return NULL; - } + spin_lock(&GlobalMid_Lock); + list_add_tail(&temp->qhead, &ses->server->pending_mid_q); + atomic_inc(&midCount); + temp->midState = MID_REQUEST_ALLOCATED; + spin_unlock(&GlobalMid_Lock); return temp; } @@ -93,7 +78,7 @@ list_del(&midEntry->qhead); atomic_dec(&midCount); spin_unlock(&GlobalMid_Lock); - buf_release(midEntry->resp_buf); + cifs_buf_release(midEntry->resp_buf); kmem_cache_free(cifs_mid_cachep, midEntry); } @@ -166,6 +151,7 @@ set_fs(get_ds()); rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); while((rc == -ENOSPC) || (rc == -EAGAIN)) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/2); rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); } @@ -190,10 +176,35 @@ long timeout; struct mid_q_entry *midQ; + if ((ses == NULL) || (ses->server == NULL)) { + cERROR(1,("Null tcp session or smb session: %p",ses)); + return -EIO; + } + + if (ses->server->tcpStatus == CifsExiting) { + return -ENOENT; + } else if (ses->server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("tcp session dead - return to caller to retry")); + return -EAGAIN; + } else if (ses->status != CifsGood) { + /* check if SMB session is bad because we are setting it up */ + if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && + (in_buf->Command != SMB_COM_NEGOTIATE)) { + return -EAGAIN; + } /* else ok - we are setting up session */ + } + /* make sure that we sign in the same order that we send on this socket + and avoid races inside tcp sendmsg code that could cause corruption + of smb data */ + down(&ses->server->tcpSem); midQ = AllocMidQEntry(in_buf, ses); - if (midQ == NULL) + if (midQ == NULL) { + up(&ses->server->tcpSem); return -EIO; + } + if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) { + up(&ses->server->tcpSem); cERROR(1, ("Illegal length, greater than maximum frame, %d ", in_buf->smb_buf_length)); @@ -201,52 +212,84 @@ return -EIO; } - if (in_buf->smb_buf_length > 12) - in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); + if (in_buf->smb_buf_length > 12) + in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); - rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, - (struct sockaddr *) &(ses->server->sockAddr)); - + (struct sockaddr *) &(ses->server->addr.sockAddr)); + up(&ses->server->tcpSem); if (long_op == -1) goto cifs_no_response_exit; - if (long_op > 1) /* writes past end of file can take looooong time */ + else if (long_op == 2) /* writes past end of file can take looooong time */ timeout = 300 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ - else + else if (long_op > 2) { + timeout = MAX_SCHEDULE_TIMEOUT; + } else timeout = 15 * HZ; /* wait for 15 seconds or until woken up due to response arriving or due to last connection to this server being unmounted */ - - timeout = wait_event_interruptible_timeout(ses->server->response_q, - midQ-> - midState & MID_RESPONSE_RECEIVED, - timeout); if (signal_pending(current)) { - cERROR(1, ("CIFS: caught signal")); + /* if signal pending do not hold up user for full smb timeout + but we still give response a change to complete */ + if(midQ->midState & MID_REQUEST_SUBMITTED) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(2 * HZ); + } + } else { /* using normal timeout */ + /* timeout = wait_event_interruptible_timeout(ses->server->response_q, + (midQ->midState & MID_RESPONSE_RECEIVED) || + ((ses->server->tcpStatus != CifsGood) && + (ses->server->tcpStatus != CifsNew)), + timeout); */ + /* Can not allow user interrupts- wreaks havoc with performance */ + if(midQ->midState & MID_REQUEST_SUBMITTED) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } + } + if (signal_pending(current)) { + if (midQ->resp_buf == NULL) + rc = -EINTR; /* BB are we supposed to return -ERESTARTSYS ? */ DeleteMidQEntry(midQ); - return -EINTR; - } else { - if (midQ->resp_buf) + return rc; /* why bother returning an error if it succeeded */ + } else { /* BB spinlock protect this against races with demux thread */ + spin_lock(&GlobalMid_Lock); + if (midQ->resp_buf) { + spin_unlock(&GlobalMid_Lock); receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); - else { + } else { cFYI(1,("No response buffer")); + if(midQ->midState == MID_REQUEST_SUBMITTED) { + if(ses->server->tcpStatus == CifsExiting) + rc = -EHOSTDOWN; + else { + ses->server->tcpStatus = CifsNeedReconnect; + midQ->midState = MID_RETRY_NEEDED; + } + } + + if (rc != -EHOSTDOWN) { + if(midQ->midState == MID_RETRY_NEEDED) { + rc = -EAGAIN; + cFYI(1,("marking request for retry")); + } else { + rc = -EIO; + } + } + spin_unlock(&GlobalMid_Lock); DeleteMidQEntry(midQ); - ses->server->tcpStatus = CifsNeedReconnect; - return -EIO; + return rc; } } - if (timeout == 0) { - cFYI(1, - ("Timeout on receive. Assume response SMB is invalid.")); - rc = -ETIMEDOUT; - } else if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { + if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); diff -Nru a/fs/compat.c b/fs/compat.c --- a/fs/compat.c Sun Apr 25 22:39:31 2004 +++ b/fs/compat.c Sun Apr 25 22:39:31 2004 @@ -235,7 +235,7 @@ return error; } -/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64 */ +/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */ #define IOCTL_HASHSIZE 256 struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; diff -Nru a/fs/compat_ioctl.c b/fs/compat_ioctl.c --- a/fs/compat_ioctl.c Sun Apr 25 22:39:32 2004 +++ b/fs/compat_ioctl.c Sun Apr 25 22:39:32 2004 @@ -70,8 +70,10 @@ #include /* siocdevprivate_ioctl */ #include -#include #include +#include + +#include #include /* Ugly hack. */ diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c Sun Apr 25 22:39:31 2004 +++ b/fs/exec.c Sun Apr 25 22:39:31 2004 @@ -870,15 +870,6 @@ EXPORT_SYMBOL(flush_old_exec); -/* - * We mustn't allow tracing of suid binaries, unless - * the tracer has the capability to trace anything.. - */ -static inline int must_not_trace_exec(struct task_struct * p) -{ - return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP); -} - /* * Fill the binprm structure from the inode. * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes @@ -945,27 +936,7 @@ void compute_creds(struct linux_binprm *bprm) { - task_lock(current); - if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { - current->mm->dumpable = 0; - - if (must_not_trace_exec(current) - || atomic_read(¤t->fs->count) > 1 - || atomic_read(¤t->files->count) > 1 - || atomic_read(¤t->sighand->count) > 1) { - if(!capable(CAP_SETUID)) { - bprm->e_uid = current->uid; - bprm->e_gid = current->gid; - } - } - } - - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; - - task_unlock(current); - - security_bprm_compute_creds(bprm); + security_bprm_apply_creds(bprm); } EXPORT_SYMBOL(compute_creds); diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Sun Apr 25 22:39:31 2004 +++ b/fs/ext3/inode.c Sun Apr 25 22:39:31 2004 @@ -1393,7 +1393,7 @@ return ret; out_fail: - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); unlock_page(page); return ret; } @@ -1422,7 +1422,7 @@ return ret; out_fail: - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); unlock_page(page); return ret; } @@ -1478,7 +1478,7 @@ return ret; no_write: - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); out_unlock: unlock_page(page); goto out; diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c --- a/fs/jbd/journal.c Sun Apr 25 22:39:31 2004 +++ b/fs/jbd/journal.c Sun Apr 25 22:39:31 2004 @@ -599,6 +599,7 @@ return NULL; bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + memset(bh->b_data, 0, journal->j_blocksize); bh->b_state |= (1 << BH_Dirty); BUFFER_TRACE(bh, "return this buffer"); return journal_add_journal_head(bh); diff -Nru a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c --- a/fs/nfs/nfsroot.c Sun Apr 25 22:39:31 2004 +++ b/fs/nfs/nfsroot.c Sun Apr 25 22:39:31 2004 @@ -117,11 +117,16 @@ ***************************************************************************/ enum { + /* Options that take integer arguments */ Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin, - Opt_acregmax, Opt_acdirmin, Opt_acdirmax, Opt_soft, Opt_hard, Opt_intr, + Opt_acregmax, Opt_acdirmin, Opt_acdirmax, + /* Options that take no arguments */ + Opt_soft, Opt_hard, Opt_intr, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, - Opt_broken_suid, Opt_err, + Opt_broken_suid, + /* Error token */ + Opt_err }; static match_table_t __initdata tokens = { @@ -146,9 +151,13 @@ {Opt_noac, "noac"}, {Opt_lock, "lock"}, {Opt_nolock, "nolock"}, + {Opt_v2, "nfsvers=2"}, {Opt_v2, "v2"}, + {Opt_v3, "nfsvers=3"}, {Opt_v3, "v3"}, + {Opt_udp, "proto=udp"}, {Opt_udp, "udp"}, + {Opt_tcp, "proto=tcp"}, {Opt_tcp, "tcp"}, {Opt_broken_suid, "broken_suid"}, {Opt_err, NULL} @@ -169,18 +178,19 @@ if (!name) return 1; - if (name[0] && strcmp(name, "default")){ - strlcpy(buf, name, NFS_MAXPATHLEN); - return 1; - } + /* Set the NFS remote path */ + p = strsep(&name, ","); + if (p[0] != '\0' && strcmp(p, "default") != 0) + strlcpy(buf, p, NFS_MAXPATHLEN); + while ((p = strsep (&name, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, tokens, args); - /* %u tokens only */ - if (match_int(&args[0], &option)) + /* %u tokens only. Beware if you add new tokens! */ + if (token < Opt_soft && match_int(&args[0], &option)) return 0; switch (token) { case Opt_port: @@ -265,6 +275,7 @@ return 0; } } + return 1; } @@ -273,7 +284,7 @@ */ static int __init root_nfs_name(char *name) { - static char buf[NFS_MAXPATHLEN]; + static char buf[NFS_MAXPATHLEN] __initdata; char *cp; /* Set some default values */ @@ -283,9 +294,6 @@ nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; - nfs_data.bsize = 0; - nfs_data.timeo = 7; - nfs_data.retrans = 3; nfs_data.acregmin = 3; nfs_data.acregmax = 60; nfs_data.acdirmin = 30; diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog --- a/fs/ntfs/ChangeLog Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/ChangeLog Sun Apr 25 22:39:31 2004 @@ -1,6 +1,5 @@ ToDo: - Find and fix bugs. - - Enable NFS exporting of NTFS. - Implement aops->set_page_dirty() in order to take control of buffer dirtying. Not having it means if page_has_buffers(), all buffers will be dirtied with the page. And if not they won't be. That is @@ -20,6 +19,26 @@ sufficient for synchronisation here. We then just need to make sure ntfs_readpage/writepage/truncate interoperate properly with us. +2.1.7 - Enable NFS exporting of mounted NTFS volumes. + + - Set i_generation in the VFS inode from the seq_no of the NTFS inode. + - Make ntfs_lookup() NFS export safe, i.e. use d_splice_alias(), etc. + - Implement ->get_dentry() in fs/ntfs/namei.c::ntfs_get_dentry() as the + default doesn't allow inode number 0 which is a valid inode on NTFS + and even if it did allow that it uses iget() instead of ntfs_iget() + which makes it useless for us. + - Implement ->get_parent() in fs/ntfs/namei.c::ntfs_get_parent() as the + default just returns -EACCES which is not very useful. + - Define export operations (->s_export_op) for NTFS (ntfs_export_ops) + and set them up in the super block at mount time (super.c) this + allows mounted NTFS volumes to be exported via NFS. + - Add missing return -EOPNOTSUPP; in + fs/ntfs/aops.c::ntfs_commit_nonresident_write(). + - Enforce no atime and no dir atime updates at mount/remount time as + they are not implemented yet anyway. + - Move a few assignments in fs/ntfs/attrib.c::load_attribute_list() to + after a NULL check. Thanks to Dave Jones for pointing this out. + 2.1.6 - Fix minor bug in handling of compressed directories. - Fix bug in handling of compressed directories. A compressed @@ -60,6 +79,10 @@ - Reduce function local stack usage from 0x3d4 bytes to just noise in fs/ntfs/upcase.c. (Randy Dunlap ) - Remove compiler warnings for newer gcc. + - Pages are no longer kmapped by mm/filemap.c::generic_file_write() + around calls to ->{prepare,commit}_write. Adapt NTFS appropriately + in fs/ntfs/aops.c::ntfs_prepare_nonresident_write() by using + kmap_atomic(KM_USER0). 2.1.0 - First steps towards write support: implement file overwrite. diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile --- a/fs/ntfs/Makefile Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/Makefile Sun Apr 25 22:39:31 2004 @@ -5,7 +5,7 @@ ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \ mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.6\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.7\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c --- a/fs/ntfs/aops.c Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/aops.c Sun Apr 25 22:39:31 2004 @@ -1,8 +1,8 @@ /** * aops.c - NTFS kernel address space operations and page cache handling. - * Part of the Linux-NTFS project. + * Part of the Linux-NTFS project. * - * Copyright (c) 2001-2003 Anton Altaparmakov + * Copyright (c) 2001-2004 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -10,13 +10,13 @@ * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program/include file is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS + * along with this program (in the main directory of the Linux-NTFS * distribution in the file COPYING); if not, write to the Free Software * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -458,7 +458,7 @@ * * Based on ntfs_read_block() and __block_write_full_page(). */ -static int ntfs_write_block(struct page *page) +static int ntfs_write_block(struct writeback_control *wbc, struct page *page) { VCN vcn; LCN lcn; @@ -499,10 +499,7 @@ * Put the page back on mapping->dirty_pages, but leave its * buffer's dirty state as-is. */ - // FIXME: Once Andrew's -EAGAIN patch goes in, remove the - // __set_page_dirty_nobuffers(page) and return -EAGAIN instead - // of zero. - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); unlock_page(page); return 0; } @@ -575,11 +572,11 @@ // Again for each page do: // - wait_on_page_locked() // - Check (PageUptodate(page) && - // !PageError(page)) + // !PageError(page)) // Update initialized size in the attribute and // in the inode. // Again, for each page do: - // __set_page_dirty_buffers(); + // __set_page_dirty_buffers(); // page_cache_release() // We don't need to wait on the writes. // Update iblock. @@ -733,10 +730,7 @@ * Put the page back on mapping->dirty_pages, but * leave its buffer's dirty state as-is. */ - // FIXME: Once Andrew's -EAGAIN patch goes in, remove - // the __set_page_dirty_nobuffers(page) and set err to - // -EAGAIN instead of zero. - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); err = 0; } else SetPageError(page); @@ -869,7 +863,7 @@ } /* Normal data stream. */ - return ntfs_write_block(page); + return ntfs_write_block(wbc, page); } /* @@ -986,10 +980,7 @@ * Put the page back on mapping->dirty_pages, but leave its * buffer's dirty state as-is. */ - // FIXME: Once Andrew's -EAGAIN patch goes in, remove the - // __set_page_dirty_nobuffers(page) and set err to -EAGAIN - // instead of zero. - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); err = 0; } else { ntfs_error(vi->i_sb, "Resident attribute write failed with " @@ -1121,11 +1112,11 @@ // Again for each page do: // - wait_on_page_locked() // - Check (PageUptodate(page) && - // !PageError(page)) + // !PageError(page)) // Update initialized size in the attribute and // in the inode. // Again, for each page do: - // __set_page_dirty_buffers(); + // __set_page_dirty_buffers(); // page_cache_release() // We don't need to wait on the writes. // Update iblock. @@ -1197,7 +1188,7 @@ // TODO: Instantiate the hole. // clear_buffer_new(bh); // unmap_underlying_metadata(bh->b_bdev, - // bh->b_blocknr); + // bh->b_blocknr); // For non-uptodate buffers, need to // zero out the region outside the // request in this bh or all bhs, @@ -1288,7 +1279,7 @@ if (PageUptodate(page)) { if (!buffer_uptodate(bh)) set_buffer_uptodate(bh); - continue; + continue; } /* * The page is not uptodate. The buffer is mapped. If it is not @@ -1534,6 +1525,7 @@ if (pos > vi->i_size) { ntfs_error(vi->i_sb, "Writing beyond the existing file size is " "not supported yet. Sorry."); + return -EOPNOTSUPP; // vi->i_size = pos; // mark_inode_dirty(vi); } @@ -1717,7 +1709,7 @@ /* * Bring the out of bounds area(s) uptodate by copying data * from the mft record to the page. - */ + */ if (from > 0) memcpy(kaddr, kattr, from); if (to < bytes) diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c --- a/fs/ntfs/attrib.c Sun Apr 25 22:39:32 2004 +++ b/fs/ntfs/attrib.c Sun Apr 25 22:39:32 2004 @@ -1235,11 +1235,11 @@ u8 *al_end = al + initialized_size; run_list_element *rl; struct buffer_head *bh; - struct super_block *sb = vol->sb; - unsigned long block_size = sb->s_blocksize; + struct super_block *sb; + unsigned long block_size; unsigned long block, max_block; int err = 0; - unsigned char block_size_bits = sb->s_blocksize_bits; + unsigned char block_size_bits; ntfs_debug("Entering."); if (!vol || !run_list || !al || size <= 0 || initialized_size < 0 || @@ -1249,6 +1249,9 @@ memset(al, 0, size); return 0; } + sb = vol->sb; + block_size = sb->s_blocksize; + block_size_bits = sb->s_blocksize_bits; down_read(&run_list->lock); rl = run_list->rl; /* Read all clusters specified by the run list one run at a time. */ diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c --- a/fs/ntfs/dir.c Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/dir.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /** * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2003 Anton Altaparmakov + * Copyright (c) 2001-2004 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -200,7 +200,8 @@ "and if that doesn't find any " "errors please report you saw " "this message to " - "linux-ntfs-dev@lists.sf.net."); + "linux-ntfs-dev@lists." + "sourceforge.net."); goto dir_err_out; } @@ -457,7 +458,8 @@ "and if that doesn't find any " "errors please report you saw " "this message to " - "linux-ntfs-dev@lists.sf.net."); + "linux-ntfs-dev@lists." + "sourceforge.net."); ntfs_unmap_page(page); goto dir_err_out; } diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/inode.c Sun Apr 25 22:39:31 2004 @@ -196,7 +196,7 @@ } /* * There is no point in keeping bad inodes around if the failure was - * due to ENOMEM. We want to be able to retry again layer. + * due to ENOMEM. We want to be able to retry again later. */ if (err == -ENOMEM) { iput(vi); @@ -533,7 +533,7 @@ } /* Transfer information from mft record into vfs and ntfs inodes. */ - ni->seq_no = le16_to_cpu(m->sequence_number); + vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); /* * FIXME: Keep in mind that link_count is two for files which have both @@ -1109,7 +1109,7 @@ vi->i_mtime = base_vi->i_mtime; vi->i_ctime = base_vi->i_ctime; vi->i_atime = base_vi->i_atime; - ni->seq_no = base_ni->seq_no; + vi->i_generation = ni->seq_no = base_ni->seq_no; /* Set inode type to zero but preserve permissions. */ vi->i_mode = base_vi->i_mode & ~S_IFMT; @@ -1137,7 +1137,8 @@ "the attribute is resident (mft_no " "0x%lx, type 0x%x, name_len %i). " "Please report you saw this message " - "to linux-ntfs-dev@lists.sf.net", + "to linux-ntfs-dev@lists." + "sourceforge.net", vi->i_ino, ni->type, ni->name_len); goto unm_err_out; } @@ -1157,8 +1158,9 @@ "type 0x%x, name_len %i). " "Please report you saw this " "message to linux-ntfs-dev@" - "lists.sf.net", vi->i_ino, - ni->type, ni->name_len); + "lists.sourceforge.net", + vi->i_ino, ni->type, + ni->name_len); goto unm_err_out; } NInoSetCompressed(ni); @@ -1169,7 +1171,8 @@ "(mft_no 0x%lx, type 0x%x, " "name_len %i). Please report " "you saw this message to " - "linux-ntfs-dev@lists.sf.net", + "linux-ntfs-dev@lists." + "sourceforge.net", vi->i_ino, ni->type, ni->name_len); goto unm_err_out; @@ -1224,8 +1227,9 @@ "type 0x%x, name_len %i). " "Please report you saw this " "message to linux-ntfs-dev@" - "lists.sf.net", vi->i_ino, - ni->type, ni->name_len); + "lists.sourceforge.net", + vi->i_ino, ni->type, + ni->name_len); goto unm_err_out; } NInoSetEncrypted(ni); @@ -1238,8 +1242,9 @@ "type 0x%x, name_len %i). " "Please report you saw this " "message to linux-ntfs-dev@" - "lists.sf.net", vi->i_ino, - ni->type, ni->name_len); + "lists.sourceforge.net", + vi->i_ino, ni->type, + ni->name_len); goto unm_err_out; } NInoSetSparse(ni); @@ -1414,7 +1419,7 @@ } /* Need this to sanity check attribute list references to $MFT. */ - ni->seq_no = le16_to_cpu(m->sequence_number); + vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); /* Provides readpage() and sync_page() for map_mft_record(). */ vi->i_mapping->a_ops = &ntfs_mft_aops; @@ -1541,7 +1546,8 @@ "of $MFT is not in the base " "mft record. Please report " "you saw this message to " - "linux-ntfs-dev@lists.sf.net"); + "linux-ntfs-dev@lists." + "sourceforge.net"); goto put_err_out; } else { /* Sequence numbers must match. */ @@ -1662,7 +1668,8 @@ "Run chkdsk and if no errors " "are found, please report you " "saw this message to " - "linux-ntfs-dev@lists.sf.net"); + "linux-ntfs-dev@lists." + "sourceforge.net"); put_attr_search_ctx(ctx); /* Revert to the safe super operations. */ sb->s_op = &ntfs_mount_sops; diff -Nru a/fs/ntfs/layout.h b/fs/ntfs/layout.h --- a/fs/ntfs/layout.h Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/layout.h Sun Apr 25 22:39:31 2004 @@ -2,7 +2,7 @@ * layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS * project. * - * Copyright (c) 2001-2003 Anton Altaparmakov + * Copyright (c) 2001-2004 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -941,7 +941,7 @@ modified. */ /* 18*/ s64 last_mft_change_time; /* Time this mft record was last modified. */ -/* 20*/ s64 last_access_time; /* Last time this mft record was +/* 20*/ s64 last_access_time; /* Time this mft record was last accessed. */ /* 28*/ s64 allocated_size; /* Byte size of allocated space for the data attribute. NOTE: Is a multiple diff -Nru a/fs/ntfs/namei.c b/fs/ntfs/namei.c --- a/fs/ntfs/namei.c Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/namei.c Sun Apr 25 22:39:31 2004 @@ -2,7 +2,7 @@ * namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS * project. * - * Copyright (c) 2001-2003 Anton Altaparmakov + * Copyright (c) 2001-2004 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -21,6 +21,7 @@ */ #include +#include #include "ntfs.h" #include "dir.h" @@ -41,16 +42,17 @@ * @dir_ino looking for the converted Unicode name. If the name is found in the * directory, the corresponding inode is loaded by calling ntfs_iget() on its * inode number and the inode is associated with the dentry @dent via a call to - * d_add(). + * d_splice_alias(). * * If the name is not found in the directory, a NULL inode is inserted into the - * dentry @dent. The dentry is then termed a negative dentry. + * dentry @dent via a call to d_add(). The dentry is then termed a negative + * dentry. * * Only if an actual error occurs, do we return an error via ERR_PTR(). * * In order to handle the case insensitivity issues of NTFS with regards to the * dcache and the dcache requiring only one dentry per directory, we deal with - * dentry aliases that only differ in case in ->ntfs_lookup() while maintining + * dentry aliases that only differ in case in ->ntfs_lookup() while maintaining * a case sensitive dcache. This means that we get the full benefit of dcache * speed when the file/directory is looked up with the same case as returned by * ->ntfs_readdir() but that a lookup for any other case (or for the short file @@ -70,15 +72,18 @@ * 1) @dent perfectly matches (i.e. including case) a directory entry with a * file name in the WIN32 or POSIX namespaces. In this case * ntfs_lookup_inode_by_name() will return with name set to NULL and we - * just d_add() @dent. + * just d_splice_alias() @dent. * 2) @dent matches (not including case) a directory entry with a file name in * the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return * with name set to point to a kmalloc()ed ntfs_name structure containing * the properly cased little endian Unicode name. We convert the name to the * current NLS code page, search if a dentry with this name already exists - * and if so return that instead of @dent. The VFS will then destroy the old - * @dent and use the one we returned. If a dentry is not found, we allocate - * a new one, d_add() it, and return it as above. + * and if so return that instead of @dent. At this point things are + * complicated by the possibility of 'disconnected' dentries due to NFS + * which we deal with appropriately (see the code comments). The VFS will + * then destroy the old @dent and use the one we returned. If a dentry is + * not found, we allocate a new one, d_splice_alias() it, and return it as + * above. * 3) @dent matches either perfectly or not (i.e. we don't care about case) a * directory entry with a file name in the DOS namespace. In this case * ntfs_lookup_inode_by_name() will return with name set to point to a @@ -88,7 +93,8 @@ * name. We then convert the name to the current NLS code page, and proceed * searching for a dentry with this name, etc, as in case 2), above. */ -static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, struct nameidata *nd) +static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, + struct nameidata *nd) { ntfs_volume *vol = NTFS_SB(dir_ino->i_sb); struct inode *dent_inode; @@ -120,9 +126,8 @@ dent_ino == FILE_MFT) { /* Perfect WIN32/POSIX match. -- Case 1. */ if (!name) { - d_add(dent, dent_inode); ntfs_debug("Done."); - return NULL; + return d_splice_alias(dent_inode, dent); } /* * We are too indented. Handle imperfect @@ -132,7 +137,7 @@ } ntfs_error(vol->sb, "Found stale reference to inode " "0x%lx (reference sequence number = " - "0x%x, inode sequence number = 0x%x, " + "0x%x, inode sequence number = 0x%x), " "returning -EIO. Run chkdsk.", dent_ino, MSEQNO(mref), NTFS_I(dent_inode)->seq_no); @@ -162,7 +167,7 @@ // TODO: Consider moving this lot to a separate function! (AIA) handle_name: { - struct dentry *real_dent; + struct dentry *real_dent, *new_dent; MFT_RECORD *m; attr_search_context *ctx; ntfs_inode *ni = NTFS_I(dent_inode); @@ -173,8 +178,7 @@ if (name->type != FILE_NAME_DOS) { /* Case 2. */ nls_name.len = (unsigned)ntfs_ucstonls(vol, (uchar_t*)&name->name, name->len, - (unsigned char**)&nls_name.name, - name->len * 3 + 1); + (unsigned char**)&nls_name.name, 0); kfree(name); } else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */ FILE_NAME_ATTR *fn; @@ -225,8 +229,7 @@ /* Convert the found WIN32 name to current NLS code page. */ nls_name.len = (unsigned)ntfs_ucstonls(vol, (uchar_t*)&fn->file_name, fn->file_name_length, - (unsigned char**)&nls_name.name, - fn->file_name_length * 3 + 1); + (unsigned char**)&nls_name.name, 0); put_attr_search_ctx(ctx); unmap_mft_record(ni); @@ -256,8 +259,12 @@ err = -ENOMEM; goto err_out; } - d_add(real_dent, dent_inode); - return real_dent; + new_dent = d_splice_alias(dent_inode, real_dent); + if (new_dent) + dput(real_dent); + else + new_dent = real_dent; + return new_dent; } kfree(nls_name.name); /* Matching dentry exists, check if it is negative. */ @@ -266,14 +273,54 @@ /* * Already have the inode and the dentry attached, decrement * the reference count to balance the ntfs_iget() we did - * earlier on. + * earlier on. We found the dentry using d_lookup() so it + * cannot be disconnected and thus we do not need to worry + * about any NFS/disconnectedness issues here. */ iput(dent_inode); return real_dent; } - /* Negative dentry: instantiate it. */ - d_instantiate(real_dent, dent_inode); - return real_dent; + /* + * Negative dentry: instantiate it unless the inode is a directory and + * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED), + * in which case d_move() that in place of the found dentry. + */ + if (!S_ISDIR(dent_inode->i_mode)) { + /* Not a directory; everything is easy. */ + d_instantiate(real_dent, dent_inode); + return real_dent; + } + spin_lock(&dcache_lock); + if (list_empty(&dent_inode->i_dentry)) { + /* + * Directory without a 'disconnected' dentry; we need to do + * d_instantiate() by hand because it takes dcache_lock which + * we already hold. + */ + list_add(&real_dent->d_alias, &dent_inode->i_dentry); + real_dent->d_inode = dent_inode; + spin_unlock(&dcache_lock); + security_d_instantiate(real_dent, dent_inode); + return real_dent; + } + /* + * Directory with a 'disconnected' dentry; get a reference to the + * 'disconnected' dentry. + */ + new_dent = list_entry(dent_inode->i_dentry.next, struct dentry, + d_alias); + dget_locked(new_dent); + spin_unlock(&dcache_lock); + /* Do security vodoo. */ + security_d_instantiate(real_dent, dent_inode); + /* Move new_dent in place of real_dent. */ + d_move(new_dent, real_dent); + /* Balance the ntfs_iget() we did above. */ + iput(dent_inode); + /* Throw away real_dent. */ + dput(real_dent); + /* Use new_dent as the actual dentry. */ + return new_dent; eio_err_out: ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk."); @@ -288,10 +335,139 @@ } } -/* +/** * Inode operations for directories. */ struct inode_operations ntfs_dir_inode_ops = { .lookup = ntfs_lookup, /* VFS: Lookup directory. */ }; +/** + * ntfs_get_parent - find the dentry of the parent of a given directory dentry + * @child_dent: dentry of the directory whose parent directory to find + * + * Find the dentry for the parent directory of the directory specified by the + * dentry @child_dent. This function is called from + * fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the + * default ->decode_fh() which is export_decode_fh() in the same file. + * + * The code is based on the ext3 ->get_parent() implementation found in + * fs/ext3/namei.c::ext3_get_parent(). + * + * Note: ntfs_get_parent() is called with @child_dent->d_inode->i_sem down. + * + * Return the dentry of the parent directory on success or the error code on + * error (IS_ERR() is true). + */ +struct dentry *ntfs_get_parent(struct dentry *child_dent) +{ + struct inode *vi = child_dent->d_inode; + ntfs_inode *ni = NTFS_I(vi); + MFT_RECORD *mrec; + attr_search_context *ctx; + ATTR_RECORD *attr; + FILE_NAME_ATTR *fn; + struct inode *parent_vi; + struct dentry *parent_dent; + unsigned long parent_ino; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + /* Get the mft record of the inode belonging to the child dentry. */ + mrec = map_mft_record(ni); + if (unlikely(IS_ERR(mrec))) + return (struct dentry *)mrec; + /* Find the first file name attribute in the mft record. */ + ctx = get_attr_search_ctx(ni, mrec); + if (unlikely(!ctx)) { + unmap_mft_record(ni); + return ERR_PTR(-ENOMEM); + } +try_next: + if (unlikely(!lookup_attr(AT_FILE_NAME, NULL, 0, IGNORE_CASE, 0, + NULL, 0, ctx))) { + put_attr_search_ctx(ctx); + unmap_mft_record(ni); + ntfs_error(vi->i_sb, "Inode 0x%lx does not have a file name " + "attribute. Run chkdsk.", vi->i_ino); + return ERR_PTR(-ENOENT); + } + attr = ctx->attr; + if (unlikely(attr->non_resident)) + goto try_next; + fn = (FILE_NAME_ATTR *)((u8 *)attr + + le16_to_cpu(attr->data.resident.value_offset)); + if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) > + (u8*)attr + le32_to_cpu(attr->length))) + goto try_next; + /* Get the inode number of the parent directory. */ + parent_ino = MREF_LE(fn->parent_directory); + /* Release the search context and the mft record of the child. */ + put_attr_search_ctx(ctx); + unmap_mft_record(ni); + /* Get the inode of the parent directory. */ + parent_vi = ntfs_iget(vi->i_sb, parent_ino); + if (unlikely(IS_ERR(parent_vi) || is_bad_inode(parent_vi))) { + if (!IS_ERR(parent_vi)) + iput(parent_vi); + ntfs_error(vi->i_sb, "Failed to get parent directory inode " + "0x%lx of child inode 0x%lx.", parent_ino, + vi->i_ino); + return ERR_PTR(-EACCES); + } + /* Finally get a dentry for the parent directory and return it. */ + parent_dent = d_alloc_anon(parent_vi); + if (unlikely(!parent_dent)) { + iput(parent_vi); + return ERR_PTR(-ENOMEM); + } + ntfs_debug("Done for inode 0x%lx.", vi->i_ino); + return parent_dent; +} + +/** + * ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment + * @sb: super block identifying the mounted ntfs volume + * @fh: the file handle sub-fragment + * + * Find a dentry for the inode given a file handle sub-fragment. This function + * is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is + * called from the default ->decode_fh() which is export_decode_fh() in the + * same file. The code is closely based on the default ->get_dentry() helper + * fs/exportfs/expfs.c::get_object(). + * + * The @fh contains two 32-bit unsigned values, the first one is the inode + * number and the second one is the inode generation. + * + * Return the dentry on success or the error code on error (IS_ERR() is true). + */ +struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh) +{ + struct inode *vi; + struct dentry *dent; + unsigned long ino = ((u32 *)fh)[0]; + u32 gen = ((u32 *)fh)[1]; + + ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen); + vi = ntfs_iget(sb, ino); + if (unlikely(IS_ERR(vi))) { + ntfs_error(sb, "Failed to get inode 0x%lx.", ino); + return (struct dentry *)vi; + } + if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) { + /* We didn't find the right inode. */ + ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x " + "0x%x.", vi->i_ino, vi->i_nlink, + atomic_read(&vi->i_count), vi->i_generation, + gen); + iput(vi); + return ERR_PTR(-ESTALE); + } + /* Now find a dentry. If possible, get a well-connected one. */ + dent = d_alloc_anon(vi); + if (unlikely(!dent)) { + iput(vi); + return ERR_PTR(-ENOMEM); + } + ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen); + return dent; +} diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c --- a/fs/ntfs/super.c Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/super.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2003 Anton Altaparmakov + * Copyright (c) 2001-2004 Anton Altaparmakov * Copyright (c) 2001,2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -323,6 +323,9 @@ return -EROFS; } } + // TODO: For now we enforce no atime and dir atime updates as they are + // not implemented. + *flags |= MS_NOATIME | MS_NODIRATIME; #endif // FIXME/TODO: If left like this we will have problems with rw->ro and @@ -1338,6 +1341,40 @@ .show_options = ntfs_show_options, /* Show mount options in proc. */ }; + +/** + * Declarations for NTFS specific export operations (fs/ntfs/namei.c). + */ +extern struct dentry *ntfs_get_parent(struct dentry *child_dent); +extern struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh); + +/** + * Export operations allowing NFS exporting of mounted NTFS partitions. + * + * We use the default ->decode_fh() and ->encode_fh() for now. Note that they + * use 32 bits to store the inode number which is an unsigned long so on 64-bit + * architectures is usually 64 bits so it would all fail horribly on huge + * volumes. I guess we need to define our own encode and decode fh functions + * that store 64-bit inode numbers at some point but for now we will ignore the + * problem... + * + * We also use the default ->get_name() helper (used by ->decode_fh() via + * fs/exportfs/expfs.c::find_exported_dentry()) as that is completely fs + * independent. + * + * The default ->get_parent() just returns -EACCES so we have to provide our + * own and the default ->get_dentry() is incompatible with NTFS due to not + * allowing the inode number 0 which is used in NTFS for the system file $MFT + * and due to using iget() whereas NTFS needs ntfs_iget(). + */ +static struct export_operations ntfs_export_ops = { + .get_parent = ntfs_get_parent, /* Find the parent of a given + directory. */ + .get_dentry = ntfs_get_dentry, /* Find a dentry for the inode + given a file handle + sub-fragment. */ +}; + /** * ntfs_fill_super - mount an ntfs files system * @sb: super block of ntfs file system to mount @@ -1366,6 +1403,10 @@ ntfs_debug("Entering."); #ifndef NTFS_RW sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; +#else + // TODO: For now we enforce no atime and dir atime updates as they are + // not implemented. + sb->s_flags |= MS_NOATIME | MS_NODIRATIME; #endif /* Allocate a new ntfs_volume and place it in sb->s_fs_info. */ sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS); @@ -1544,6 +1585,7 @@ default_upcase = NULL; } up(&ntfs_lock); + sb->s_export_op = &ntfs_export_ops; return 0; } ntfs_error(sb, "Failed to allocate root directory."); @@ -1788,13 +1830,13 @@ printk(KERN_CRIT "NTFS: This causes memory to leak! There is " "probably a BUG in the driver! Please report " "you saw this message to " - "linux-ntfs-dev@lists.sf.net\n"); + "linux-ntfs-dev@lists.sourceforge.net\n"); /* Unregister the ntfs sysctls. */ ntfs_sysctl(0); } MODULE_AUTHOR("Anton Altaparmakov "); -MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2003 Anton Altaparmakov"); +MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2004 Anton Altaparmakov"); MODULE_LICENSE("GPL"); #ifdef DEBUG MODULE_PARM(debug_msgs, "i"); diff -Nru a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c --- a/fs/ntfs/unistr.c Sun Apr 25 22:39:31 2004 +++ b/fs/ntfs/unistr.c Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2003 Anton Altaparmakov + * Copyright (c) 2001-2004 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -305,8 +305,9 @@ * Convert the input little endian, 2-byte Unicode string @ins, of length * @ins_len into the string format dictated by the loaded NLS. * - * If @outs is NULL, this function allocates the string and the caller is - * responsible for calling kfree(@outs); when finished with it. + * If *@outs is NULL, this function allocates the string and the caller is + * responsible for calling kfree(*@outs); when finished with it. In this case + * @outs_len is ignored and can be 0. * * On success the function returns the number of bytes written to the output * string *@outs (>= 0), not counting the terminating NULL byte. If the output diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c --- a/fs/reiserfs/inode.c Sun Apr 25 22:39:31 2004 +++ b/fs/reiserfs/inode.c Sun Apr 25 22:39:31 2004 @@ -2112,7 +2112,7 @@ lock_buffer(bh); } else { if (test_set_buffer_locked(bh)) { - __set_page_dirty_nobuffers(page); + redirty_page_for_writepage(wbc, page); continue; } } diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c --- a/fs/reiserfs/super.c Sun Apr 25 22:39:31 2004 +++ b/fs/reiserfs/super.c Sun Apr 25 22:39:31 2004 @@ -86,7 +86,7 @@ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); reiserfs_block_writes(&th) ; - journal_end(&th, s, 1) ; + journal_end_sync(&th, s, 1) ; } s->s_dirt = 0; reiserfs_write_unlock(s); diff -Nru a/fs/super.c b/fs/super.c --- a/fs/super.c Sun Apr 25 22:39:31 2004 +++ b/fs/super.c Sun Apr 25 22:39:31 2004 @@ -77,6 +77,7 @@ sema_init(&s->s_dquot.dqio_sem, 1); sema_init(&s->s_dquot.dqonoff_sem, 1); init_rwsem(&s->s_dquot.dqptr_sem); + init_waitqueue_head(&s->s_wait_unfrozen); s->s_maxbytes = MAX_NON_LFS; s->dq_op = sb_dquot_ops; s->s_qcop = sb_quotactl_ops; @@ -623,7 +624,14 @@ if (IS_ERR(bdev)) return (struct super_block *)bdev; + /* + * once the super is inserted into the list by sget, s_umount + * will protect the lockfs code from trying to start a snapshot + * while we are mounting + */ + down(&bdev->bd_mount_sem); s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); + up(&bdev->bd_mount_sem); if (IS_ERR(s)) goto out; diff -Nru a/fs/sysfs/bin.c b/fs/sysfs/bin.c --- a/fs/sysfs/bin.c Sun Apr 25 22:39:31 2004 +++ b/fs/sysfs/bin.c Sun Apr 25 22:39:31 2004 @@ -101,19 +101,27 @@ if (!kobj || !attr) goto Done; + /* Grab the module reference for this attribute if we have one */ + error = -ENODEV; + if (!try_module_get(attr->attr.owner)) + goto Done; + error = -EACCES; if ((file->f_mode & FMODE_WRITE) && !attr->write) - goto Done; + goto Error; if ((file->f_mode & FMODE_READ) && !attr->read) - goto Done; + goto Error; error = -ENOMEM; file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!file->private_data) - goto Done; + goto Error; error = 0; + goto Done; + Error: + module_put(attr->attr.owner); Done: if (error && kobj) kobject_put(kobj); @@ -123,10 +131,12 @@ static int release(struct inode * inode, struct file * file) { struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; + struct bin_attribute * attr = file->f_dentry->d_fsdata; u8 * buffer = file->private_data; if (kobj) kobject_put(kobj); + module_put(attr->attr.owner); kfree(buffer); return 0; } diff -Nru a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c --- a/fs/sysfs/symlink.c Sun Apr 25 22:39:31 2004 +++ b/fs/sysfs/symlink.c Sun Apr 25 22:39:31 2004 @@ -42,7 +42,7 @@ struct kobject * p = kobj; int length = 1; do { - length += strlen(p->name) + 1; + length += strlen(kobject_name(p)) + 1; p = p->parent; } while (p); return length; @@ -54,11 +54,11 @@ --length; for (p = kobj; p; p = p->parent) { - int cur = strlen(p->name); + int cur = strlen(kobject_name(p)); /* back up enough to print this bus id with '/' */ length -= cur; - strncpy(buffer + length,p->name,cur); + strncpy(buffer + length,kobject_name(p),cur); *(buffer + --length) = '/'; } } diff -Nru a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c --- a/fs/xfs/linux/xfs_ioctl.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/linux/xfs_ioctl.c Sun Apr 25 22:39:31 2004 @@ -825,13 +825,14 @@ case XFS_IOC_FREEZE: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - xfs_fs_freeze(mp); + + freeze_bdev(inode->i_sb->s_bdev); return 0; case XFS_IOC_THAW: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - xfs_fs_thaw(mp); + thaw_bdev(inode->i_sb->s_bdev, inode->i_sb); return 0; case XFS_IOC_GOINGDOWN: { diff -Nru a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c --- a/fs/xfs/linux/xfs_lrw.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/linux/xfs_lrw.c Sun Apr 25 22:39:31 2004 @@ -682,8 +682,6 @@ io = &xip->i_iocore; mp = io->io_mount; - xfs_check_frozen(mp, bdp, XFS_FREEZE_WRITE); - if (XFS_FORCED_SHUTDOWN(mp)) { return -EIO; } diff -Nru a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c --- a/fs/xfs/linux/xfs_super.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/linux/xfs_super.c Sun Apr 25 22:39:31 2004 @@ -589,28 +589,7 @@ linvfs_freeze_fs( struct super_block *sb) { - vfs_t *vfsp = LINVFS_GET_VFS(sb); - vnode_t *vp; - int error; - - if (sb->s_flags & MS_RDONLY) - return; - VFS_ROOT(vfsp, &vp, error); - VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_FREEZE, 0, error); - VN_RELE(vp); -} - -STATIC void -linvfs_unfreeze_fs( - struct super_block *sb) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - vnode_t *vp; - int error; - - VFS_ROOT(vfsp, &vp, error); - VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_THAW, 0, error); - VN_RELE(vp); + VFS_FREEZE(LINVFS_GET_VFS(sb)); } STATIC struct dentry * @@ -850,7 +829,6 @@ .write_super = linvfs_write_super, .sync_fs = linvfs_sync_super, .write_super_lockfs = linvfs_freeze_fs, - .unlockfs = linvfs_unfreeze_fs, .statfs = linvfs_statfs, .remount_fs = linvfs_remount, .show_options = linvfs_show_options, diff -Nru a/fs/xfs/linux/xfs_vfs.c b/fs/xfs/linux/xfs_vfs.c --- a/fs/xfs/linux/xfs_vfs.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/linux/xfs_vfs.c Sun Apr 25 22:39:31 2004 @@ -230,6 +230,18 @@ ((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line)); } +void +vfs_freeze( + struct bhv_desc *bdp) +{ + struct bhv_desc *next = bdp; + + ASSERT(next); + while (! (bhvtovfsops(next))->vfs_freeze) + next = BHV_NEXT(next); + ((*bhvtovfsops(next)->vfs_freeze)(next)); +} + vfs_t * vfs_allocate( void ) { diff -Nru a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h --- a/fs/xfs/linux/xfs_vfs.h Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/linux/xfs_vfs.h Sun Apr 25 22:39:31 2004 @@ -112,6 +112,7 @@ typedef void (*vfs_init_vnode_t)(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); +typedef void (*vfs_freeze_t)(bhv_desc_t *); typedef struct vfsops { bhv_position_t vf_position; /* behavior chain position */ @@ -128,6 +129,7 @@ vfs_quotactl_t vfs_quotactl; /* disk quota */ vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ + vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ } vfsops_t; /* @@ -147,6 +149,7 @@ #define VFS_QUOTACTL(v, c,id,p, rv) ((rv) = vfs_quotactl(VHEAD(v), c,id,p)) #define VFS_INIT_VNODE(v, vp,b,ul) ( vfs_init_vnode(VHEAD(v), vp,b,ul) ) #define VFS_FORCE_SHUTDOWN(v, fl,f,l) ( vfs_force_shutdown(VHEAD(v), fl,f,l) ) +#define VFS_FREEZE(v) ( vfs_freeze(VHEAD(v)) ) /* * PVFS's. Operates on behavior descriptor pointers. @@ -164,6 +167,7 @@ #define PVFS_QUOTACTL(b, c,id,p, rv) ((rv) = vfs_quotactl(b, c,id,p)) #define PVFS_INIT_VNODE(b, vp,b2,ul) ( vfs_init_vnode(b, vp,b2,ul) ) #define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( vfs_force_shutdown(b, fl,f,l) ) +#define PVFS_FREEZE(b) ( vfs_freeze(b) ) extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); @@ -178,6 +182,7 @@ extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t); extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); +extern void vfs_freeze(bhv_desc_t *); typedef struct bhv_vfsops { struct vfsops bhv_common; diff -Nru a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c --- a/fs/xfs/xfs_fsops.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/xfs_fsops.c Sun Apr 25 22:39:31 2004 @@ -582,63 +582,25 @@ } int -xfs_fs_freeze( - xfs_mount_t *mp) -{ - vfs_t *vfsp; - /*REFERENCED*/ - int error; - - vfsp = XFS_MTOVFS(mp); - - /* Stop new writers */ - xfs_start_freeze(mp, XFS_FREEZE_WRITE); - - /* Flush the refcache */ - xfs_refcache_purge_mp(mp); - - /* Flush delalloc and delwri data */ - VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error); - - /* Pause transaction subsystem */ - xfs_start_freeze(mp, XFS_FREEZE_TRANS); - - /* Flush any remaining inodes into buffers */ - VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error); - - /* Push all buffers out to disk */ - xfs_binval(mp->m_ddev_targp); - if (mp->m_rtdev_targp) { - xfs_binval(mp->m_rtdev_targp); - } - - /* Push the superblock and write an unmount record */ - xfs_log_unmount_write(mp); - xfs_unmountfs_writesb(mp); - - return 0; -} - -int -xfs_fs_thaw( - xfs_mount_t *mp) -{ - xfs_finish_freeze(mp); - return 0; -} - -int xfs_fs_goingdown( xfs_mount_t *mp, __uint32_t inflags) { - switch (inflags) - { - case XFS_FSOP_GOING_FLAGS_DEFAULT: - xfs_fs_freeze(mp); - xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); - xfs_fs_thaw(mp); + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (inflags) { + case XFS_FSOP_GOING_FLAGS_DEFAULT: { + struct vfs *vfsp = XFS_MTOVFS(mp); + struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); + + if (sb) { + xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); + thaw_bdev(sb->s_bdev, sb); + } + break; + } case XFS_FSOP_GOING_FLAGS_LOGFLUSH: xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); break; diff -Nru a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h --- a/fs/xfs/xfs_fsops.h Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/xfs_fsops.h Sun Apr 25 22:39:31 2004 @@ -60,14 +60,6 @@ xfs_fsop_resblks_t *outval); int -xfs_fs_freeze( - xfs_mount_t *mp); - -int -xfs_fs_thaw( - xfs_mount_t *mp); - -int xfs_fs_goingdown( xfs_mount_t *mp, __uint32_t inflags); diff -Nru a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c --- a/fs/xfs/xfs_log.c Sun Apr 25 22:39:32 2004 +++ b/fs/xfs/xfs_log.c Sun Apr 25 22:39:32 2004 @@ -820,7 +820,7 @@ xlog_t *log = mp->m_log; vfs_t *vfsp = XFS_MTOVFS(mp); - if (mp->m_frozen || XFS_FORCED_SHUTDOWN(mp) || + if (vfsp->vfs_super->s_frozen || XFS_FORCED_SHUTDOWN(mp) || (vfsp->vfs_flag & VFS_RDONLY)) return 0; diff -Nru a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c --- a/fs/xfs/xfs_mount.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/xfs_mount.c Sun Apr 25 22:39:31 2004 @@ -140,9 +140,6 @@ */ xfs_trans_ail_init(mp); - /* Init freeze sync structures */ - spinlock_init(&mp->m_freeze_lock, "xfs_freeze"); - init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0); atomic_set(&mp->m_active_trans, 0); return mp; @@ -192,8 +189,6 @@ VFS_REMOVEBHV(vfsp, &mp->m_bhv); } - spinlock_destroy(&mp->m_freeze_lock); - sv_destroy(&mp->m_wait_unfreeze); kmem_free(mp, sizeof(xfs_mount_t)); } @@ -1585,60 +1580,4 @@ } xfs_mod_sb(tp, fields); xfs_trans_commit(tp, 0, NULL); -} - -/* Functions to lock access out of the filesystem for forced - * shutdown or snapshot. - */ - -void -xfs_start_freeze( - xfs_mount_t *mp, - int level) -{ - unsigned long s = mutex_spinlock(&mp->m_freeze_lock); - - mp->m_frozen = level; - mutex_spinunlock(&mp->m_freeze_lock, s); - - if (level == XFS_FREEZE_TRANS) { - while (atomic_read(&mp->m_active_trans) > 0) - delay(100); - } -} - -void -xfs_finish_freeze( - xfs_mount_t *mp) -{ - unsigned long s = mutex_spinlock(&mp->m_freeze_lock); - - if (mp->m_frozen) { - mp->m_frozen = 0; - sv_broadcast(&mp->m_wait_unfreeze); - } - - mutex_spinunlock(&mp->m_freeze_lock, s); -} - -void -xfs_check_frozen( - xfs_mount_t *mp, - bhv_desc_t *bdp, - int level) -{ - unsigned long s; - - if (mp->m_frozen) { - s = mutex_spinlock(&mp->m_freeze_lock); - - if (mp->m_frozen < level) { - mutex_spinunlock(&mp->m_freeze_lock, s); - } else { - sv_wait(&mp->m_wait_unfreeze, 0, &mp->m_freeze_lock, s); - } - } - - if (level == XFS_FREEZE_TRANS) - atomic_inc(&mp->m_active_trans); } diff -Nru a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h --- a/fs/xfs/xfs_mount.h Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/xfs_mount.h Sun Apr 25 22:39:31 2004 @@ -379,10 +379,6 @@ struct xfs_dmops m_dm_ops; /* vector of DMI ops */ struct xfs_qmops m_qm_ops; /* vector of XQM ops */ struct xfs_ioops m_io_ops; /* vector of I/O ops */ - lock_t m_freeze_lock; /* Lock for m_frozen */ - uint m_frozen; /* FS frozen for shutdown or - * snapshot */ - sv_t m_wait_unfreeze;/* waiting to unfreeze */ atomic_t m_active_trans; /* number trans frozen */ } xfs_mount_t; @@ -557,16 +553,6 @@ extern void xfs_initialize_perag(xfs_mount_t *, int); extern void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); - -/* - * Flags for freeze operations. - */ -#define XFS_FREEZE_WRITE 1 -#define XFS_FREEZE_TRANS 2 - -extern void xfs_start_freeze(xfs_mount_t *, int); -extern void xfs_finish_freeze(xfs_mount_t *); -extern void xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int); extern struct vfsops xfs_vfsops; extern struct vnodeops xfs_vnodeops; diff -Nru a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c --- a/fs/xfs/xfs_trans.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/xfs_trans.c Sun Apr 25 22:39:31 2004 @@ -131,7 +131,9 @@ xfs_mount_t *mp, uint type) { - xfs_check_frozen(mp, NULL, XFS_FREEZE_TRANS); + vfs_check_frozen(XFS_MTOVFS(mp)->vfs_super, SB_FREEZE_TRANS); + atomic_inc(&mp->m_active_trans); + return (_xfs_trans_alloc(mp, type)); } diff -Nru a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c --- a/fs/xfs/xfs_vfsops.c Sun Apr 25 22:39:31 2004 +++ b/fs/xfs/xfs_vfsops.c Sun Apr 25 22:39:31 2004 @@ -1858,6 +1858,20 @@ return 0; } +STATIC void +xfs_freeze( + bhv_desc_t *bdp) +{ + xfs_mount_t *mp = XFS_BHVTOM(bdp); + + while (atomic_read(&mp->m_active_trans) > 0) + delay(100); + + /* Push the superblock and write an unmount record */ + xfs_log_unmount_write(mp); + xfs_unmountfs_writesb(mp); +} + vfsops_t xfs_vfsops = { BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS), @@ -1874,4 +1888,5 @@ .vfs_quotactl = (vfs_quotactl_t)fs_nosys, .vfs_init_vnode = xfs_initialize_vnode, .vfs_force_shutdown = xfs_do_force_shutdown, + .vfs_freeze = xfs_freeze, }; diff -Nru a/include/asm-arm/arch-versatile/dma.h b/include/asm-arm/arch-versatile/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/dma.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-versatile/dma.h + * + * Copyright (C) 2003 ARM Limited. + * Copyright (C) 1997,1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ diff -Nru a/include/asm-arm/arch-versatile/hardware.h b/include/asm-arm/arch-versatile/hardware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/hardware.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,45 @@ +/* + * linux/include/asm-arm/arch-versatile/hardware.h + * + * This file contains the hardware definitions of the Versatile PB board. + * + * Copyright (C) 2003 ARM Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +// FIXME = PCI settings need to be fixed!!!!! + +/* + * Similar to above, but for PCI addresses (memory, IO, Config and the + * V3 chip itself). WARNING: this has to mirror definitions in platform.h + */ +#define PCI_MEMORY_VADDR 0xe8000000 +#define PCI_CONFIG_VADDR 0xec000000 +#define PCI_V3_VADDR 0xed000000 +#define PCI_IO_VADDR 0xee000000 + +#define PCIO_BASE PCI_IO_VADDR +#define PCIMEM_BASE PCI_MEMORY_VADDR + +/* macro to get at IO space when running virtually */ +#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) + +#endif diff -Nru a/include/asm-arm/arch-versatile/io.h b/include/asm-arm/arch-versatile/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/io.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-versatile/io.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffff + +#define __io(a) ((a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#endif diff -Nru a/include/asm-arm/arch-versatile/irqs.h b/include/asm-arm/arch-versatile/irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/irqs.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,211 @@ +/* + * linux/include/asm-arm/arch-versatile/irqs.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +/* + * IRQ interrupts definitions are the same the INT definitions + * held within platform.h + */ +#define IRQ_VIC_START 0 +#define IRQ_WDOGINT (IRQ_VIC_START + INT_WDOGINT) +#define IRQ_SOFTINT (IRQ_VIC_START + INT_SOFTINT) +#define IRQ_COMMRx (IRQ_VIC_START + INT_COMMRx) +#define IRQ_COMMTx (IRQ_VIC_START + INT_COMMTx) +#define IRQ_TIMERINT0_1 (IRQ_VIC_START + INT_TIMERINT0_1) +#define IRQ_TIMERINT2_3 (IRQ_VIC_START + INT_TIMERINT2_3) +#define IRQ_GPIOINT0 (IRQ_VIC_START + INT_GPIOINT0) +#define IRQ_GPIOINT1 (IRQ_VIC_START + INT_GPIOINT1) +#define IRQ_GPIOINT2 (IRQ_VIC_START + INT_GPIOINT2) +#define IRQ_GPIOINT3 (IRQ_VIC_START + INT_GPIOINT3) +#define IRQ_RTCINT (IRQ_VIC_START + INT_RTCINT) +#define IRQ_SSPINT (IRQ_VIC_START + INT_SSPINT) +#define IRQ_UARTINT0 (IRQ_VIC_START + INT_UARTINT0) +#define IRQ_UARTINT1 (IRQ_VIC_START + INT_UARTINT1) +#define IRQ_UARTINT2 (IRQ_VIC_START + INT_UARTINT2) +#define IRQ_SCIINT (IRQ_VIC_START + INT_SCIINT) +#define IRQ_CLCDINT (IRQ_VIC_START + INT_CLCDINT) +#define IRQ_DMAINT (IRQ_VIC_START + INT_DMAINT) +#define IRQ_PWRFAILINT (IRQ_VIC_START + INT_PWRFAILINT) +#define IRQ_MBXINT (IRQ_VIC_START + INT_MBXINT) +#define IRQ_GNDINT (IRQ_VIC_START + INT_GNDINT) +#define IRQ_VICSOURCE21 (IRQ_VIC_START + INT_VICSOURCE21) +#define IRQ_VICSOURCE22 (IRQ_VIC_START + INT_VICSOURCE22) +#define IRQ_VICSOURCE23 (IRQ_VIC_START + INT_VICSOURCE23) +#define IRQ_VICSOURCE24 (IRQ_VIC_START + INT_VICSOURCE24) +#define IRQ_VICSOURCE25 (IRQ_VIC_START + INT_VICSOURCE25) +#define IRQ_VICSOURCE26 (IRQ_VIC_START + INT_VICSOURCE26) +#define IRQ_VICSOURCE27 (IRQ_VIC_START + INT_VICSOURCE27) +#define IRQ_VICSOURCE28 (IRQ_VIC_START + INT_VICSOURCE28) +#define IRQ_VICSOURCE29 (IRQ_VIC_START + INT_VICSOURCE29) +#define IRQ_VICSOURCE30 (IRQ_VIC_START + INT_VICSOURCE30) +#define IRQ_VICSOURCE31 (IRQ_VIC_START + INT_VICSOURCE31) +#define IRQ_VIC_END (IRQ_VIC_START + 31) + +#define IRQMASK_WDOGINT INTMASK_WDOGINT +#define IRQMASK_SOFTINT INTMASK_SOFTINT +#define IRQMASK_COMMRx INTMASK_COMMRx +#define IRQMASK_COMMTx INTMASK_COMMTx +#define IRQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1 +#define IRQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3 +#define IRQMASK_GPIOINT0 INTMASK_GPIOINT0 +#define IRQMASK_GPIOINT1 INTMASK_GPIOINT1 +#define IRQMASK_GPIOINT2 INTMASK_GPIOINT2 +#define IRQMASK_GPIOINT3 INTMASK_GPIOINT3 +#define IRQMASK_RTCINT INTMASK_RTCINT +#define IRQMASK_SSPINT INTMASK_SSPINT +#define IRQMASK_UARTINT0 INTMASK_UARTINT0 +#define IRQMASK_UARTINT1 INTMASK_UARTINT1 +#define IRQMASK_UARTINT2 INTMASK_UARTINT2 +#define IRQMASK_SCIINT INTMASK_SCIINT +#define IRQMASK_CLCDINT INTMASK_CLCDINT +#define IRQMASK_DMAINT INTMASK_DMAINT +#define IRQMASK_PWRFAILINT INTMASK_PWRFAILINT +#define IRQMASK_MBXINT INTMASK_MBXINT +#define IRQMASK_GNDINT INTMASK_GNDINT +#define IRQMASK_VICSOURCE21 INTMASK_VICSOURCE21 +#define IRQMASK_VICSOURCE22 INTMASK_VICSOURCE22 +#define IRQMASK_VICSOURCE23 INTMASK_VICSOURCE23 +#define IRQMASK_VICSOURCE24 INTMASK_VICSOURCE24 +#define IRQMASK_VICSOURCE25 INTMASK_VICSOURCE25 +#define IRQMASK_VICSOURCE26 INTMASK_VICSOURCE26 +#define IRQMASK_VICSOURCE27 INTMASK_VICSOURCE27 +#define IRQMASK_VICSOURCE28 INTMASK_VICSOURCE28 +#define IRQMASK_VICSOURCE29 INTMASK_VICSOURCE29 +#define IRQMASK_VICSOURCE30 INTMASK_VICSOURCE30 +#define IRQMASK_VICSOURCE31 INTMASK_VICSOURCE31 + +/* + * FIQ interrupts definitions are the same the INT definitions. + */ +#define FIQ_WDOGINT INT_WDOGINT +#define FIQ_SOFTINT INT_SOFTINT +#define FIQ_COMMRx INT_COMMRx +#define FIQ_COMMTx INT_COMMTx +#define FIQ_TIMERINT0_1 INT_TIMERINT0_1 +#define FIQ_TIMERINT2_3 INT_TIMERINT2_3 +#define FIQ_GPIOINT0 INT_GPIOINT0 +#define FIQ_GPIOINT1 INT_GPIOINT1 +#define FIQ_GPIOINT2 INT_GPIOINT2 +#define FIQ_GPIOINT3 INT_GPIOINT3 +#define FIQ_RTCINT INT_RTCINT +#define FIQ_SSPINT INT_SSPINT +#define FIQ_UARTINT0 INT_UARTINT0 +#define FIQ_UARTINT1 INT_UARTINT1 +#define FIQ_UARTINT2 INT_UARTINT2 +#define FIQ_SCIINT INT_SCIINT +#define FIQ_CLCDINT INT_CLCDINT +#define FIQ_DMAINT INT_DMAINT +#define FIQ_PWRFAILINT INT_PWRFAILINT +#define FIQ_MBXINT INT_MBXINT +#define FIQ_GNDINT INT_GNDINT +#define FIQ_VICSOURCE21 INT_VICSOURCE21 +#define FIQ_VICSOURCE22 INT_VICSOURCE22 +#define FIQ_VICSOURCE23 INT_VICSOURCE23 +#define FIQ_VICSOURCE24 INT_VICSOURCE24 +#define FIQ_VICSOURCE25 INT_VICSOURCE25 +#define FIQ_VICSOURCE26 INT_VICSOURCE26 +#define FIQ_VICSOURCE27 INT_VICSOURCE27 +#define FIQ_VICSOURCE28 INT_VICSOURCE28 +#define FIQ_VICSOURCE29 INT_VICSOURCE29 +#define FIQ_VICSOURCE30 INT_VICSOURCE30 +#define FIQ_VICSOURCE31 INT_VICSOURCE31 + + +#define FIQMASK_WDOGINT INTMASK_WDOGINT +#define FIQMASK_SOFTINT INTMASK_SOFTINT +#define FIQMASK_COMMRx INTMASK_COMMRx +#define FIQMASK_COMMTx INTMASK_COMMTx +#define FIQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1 +#define FIQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3 +#define FIQMASK_GPIOINT0 INTMASK_GPIOINT0 +#define FIQMASK_GPIOINT1 INTMASK_GPIOINT1 +#define FIQMASK_GPIOINT2 INTMASK_GPIOINT2 +#define FIQMASK_GPIOINT3 INTMASK_GPIOINT3 +#define FIQMASK_RTCINT INTMASK_RTCINT +#define FIQMASK_SSPINT INTMASK_SSPINT +#define FIQMASK_UARTINT0 INTMASK_UARTINT0 +#define FIQMASK_UARTINT1 INTMASK_UARTINT1 +#define FIQMASK_UARTINT2 INTMASK_UARTINT2 +#define FIQMASK_SCIINT INTMASK_SCIINT +#define FIQMASK_CLCDINT INTMASK_CLCDINT +#define FIQMASK_DMAINT INTMASK_DMAINT +#define FIQMASK_PWRFAILINT INTMASK_PWRFAILINT +#define FIQMASK_MBXINT INTMASK_MBXINT +#define FIQMASK_GNDINT INTMASK_GNDINT +#define FIQMASK_VICSOURCE21 INTMASK_VICSOURCE21 +#define FIQMASK_VICSOURCE22 INTMASK_VICSOURCE22 +#define FIQMASK_VICSOURCE23 INTMASK_VICSOURCE23 +#define FIQMASK_VICSOURCE24 INTMASK_VICSOURCE24 +#define FIQMASK_VICSOURCE25 INTMASK_VICSOURCE25 +#define FIQMASK_VICSOURCE26 INTMASK_VICSOURCE26 +#define FIQMASK_VICSOURCE27 INTMASK_VICSOURCE27 +#define FIQMASK_VICSOURCE28 INTMASK_VICSOURCE28 +#define FIQMASK_VICSOURCE29 INTMASK_VICSOURCE29 +#define FIQMASK_VICSOURCE30 INTMASK_VICSOURCE30 +#define FIQMASK_VICSOURCE31 INTMASK_VICSOURCE31 + +/* + * Secondary interrupt controller + */ +#define IRQ_SIC_START 32 +#define IRQ_SIC_MMCI0B (IRQ_SIC_START + SIC_INT_MMCI0B) +#define IRQ_SIC_MMCI1B (IRQ_SIC_START + SIC_INT_MMCI1B) +#define IRQ_SIC_KMI0 (IRQ_SIC_START + SIC_INT_KMI0) +#define IRQ_SIC_KMI1 (IRQ_SIC_START + SIC_INT_KMI1) +#define IRQ_SIC_SCI3 (IRQ_SIC_START + SIC_INT_SCI3) +#define IRQ_SIC_UART3 (IRQ_SIC_START + SIC_INT_UART3) +#define IRQ_SIC_CLCD (IRQ_SIC_START + SIC_INT_CLCD) +#define IRQ_SIC_TOUCH (IRQ_SIC_START + SIC_INT_TOUCH) +#define IRQ_SIC_KEYPAD (IRQ_SIC_START + SIC_INT_KEYPAD) +#define IRQ_SIC_DoC (IRQ_SIC_START + SIC_INT_DoC) +#define IRQ_SIC_MMCI0A (IRQ_SIC_START + SIC_INT_MMCI0A) +#define IRQ_SIC_MMCI1A (IRQ_SIC_START + SIC_INT_MMCI1A) +#define IRQ_SIC_AACI (IRQ_SIC_START + SIC_INT_AACI) +#define IRQ_SIC_ETH (IRQ_SIC_START + SIC_INT_ETH) +#define IRQ_SIC_USB (IRQ_SIC_START + SIC_INT_USB) +#define IRQ_SIC_PCI0 (IRQ_SIC_START + SIC_INT_PCI0) +#define IRQ_SIC_PCI1 (IRQ_SIC_START + SIC_INT_PCI1) +#define IRQ_SIC_PCI2 (IRQ_SIC_START + SIC_INT_PCI2) +#define IRQ_SIC_PCI3 (IRQ_SIC_START + SIC_INT_PCI3) +#define IRQ_SIC_END 63 + +#define SIC_IRQMASK_MMCI0B SIC_INTMASK_MMCI0B +#define SIC_IRQMASK_MMCI1B SIC_INTMASK_MMCI1B +#define SIC_IRQMASK_KMI0 SIC_INTMASK_KMI0 +#define SIC_IRQMASK_KMI1 SIC_INTMASK_KMI1 +#define SIC_IRQMASK_SCI3 SIC_INTMASK_SCI3 +#define SIC_IRQMASK_UART3 SIC_INTMASK_UART3 +#define SIC_IRQMASK_CLCD SIC_INTMASK_CLCD +#define SIC_IRQMASK_TOUCH SIC_INTMASK_TOUCH +#define SIC_IRQMASK_KEYPAD SIC_INTMASK_KEYPAD +#define SIC_IRQMASK_DoC SIC_INTMASK_DoC +#define SIC_IRQMASK_MMCI0A SIC_INTMASK_MMCI0A +#define SIC_IRQMASK_MMCI1A SIC_INTMASK_MMCI1A +#define SIC_IRQMASK_AACI SIC_INTMASK_AACI +#define SIC_IRQMASK_ETH SIC_INTMASK_ETH +#define SIC_IRQMASK_USB SIC_INTMASK_USB +#define SIC_IRQMASK_PCI0 SIC_INTMASK_PCI0 +#define SIC_IRQMASK_PCI1 SIC_INTMASK_PCI1 +#define SIC_IRQMASK_PCI2 SIC_INTMASK_PCI2 +#define SIC_IRQMASK_PCI3 SIC_INTMASK_PCI3 + +#define NR_IRQS 64 diff -Nru a/include/asm-arm/arch-versatile/memory.h b/include/asm-arm/arch-versatile/memory.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/memory.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,61 @@ +/* + * linux/include/asm-arm/arch-versatile/memory.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_MMU_H +#define __ASM_ARCH_MMU_H + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xbf000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (0x40000000) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) +#define PHYS_OFFSET (0x00000000UL) + +/* + * On Versatile PB, the dram is contiguous + */ +#define __virt_to_phys__is_a_macro +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) +#define __phys_to_virt__is_a_macro +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) ((x) - PAGE_OFFSET) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) ((x) + PAGE_OFFSET) + +#endif diff -Nru a/include/asm-arm/arch-versatile/param.h b/include/asm-arm/arch-versatile/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/param.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/arch-versatile/param.h + * + * Copyright (C) 2002 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ diff -Nru a/include/asm-arm/arch-versatile/platform.h b/include/asm-arm/arch-versatile/platform.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/platform.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,488 @@ +/* + * linux/include/asm-arm/arch-versatile/platform.h + * + * Copyright (c) ARM Limited 2003. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __address_h +#define __address_h 1 + +/* + * Memory definitions + */ +#define VERSATILE_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)...*/ +#define VERSATILE_BOOT_ROM_HI 0x30000000 +#define VERSATILE_BOOT_ROM_BASE VERSATILE_BOOT_ROM_HI /* Normal position */ +#define VERSATILE_BOOT_ROM_SIZE SZ_64M + +#define VERSATILE_SSRAM_BASE /* VERSATILE_SSMC_BASE ? */ +#define VERSATILE_SSRAM_SIZE SZ_2M + +#define VERSATILE_FLASH_BASE 0x34000000 +#define VERSATILE_FLASH_SIZE SZ_64M + +/* + * SDRAM + */ +#define VERSATILE_SDRAM_BASE 0x00000000 + +/* + * Logic expansion modules + * + */ + + +/* ------------------------------------------------------------------------ + * Versatile PB Registers + * ------------------------------------------------------------------------ + * + */ +#define VERSATILE_SYS_ID_OFFSET 0x00 +#define VERSATILE_SYS_SW_OFFSET 0x04 +#define VERSATILE_SYS_LED_OFFSET 0x08 +#define VERSATILE_SYS_OSC0_OFFSET 0x0C +#define VERSATILE_SYS_OSC1_OFFSET 0x10 +#define VERSATILE_SYS_OSC2_OFFSET 0x14 +#define VERSATILE_SYS_OSC3_OFFSET 0x18 +#define VERSATILE_SYS_OSC4_OFFSET 0x1C +#define VERSATILE_SYS_LOCK_OFFSET 0x20 +#define VERSATILE_SYS_100HZ_OFFSET 0x24 +#define VERSATILE_SYS_CFGDATA1_OFFSET 0x28 +#define VERSATILE_SYS_CFGDATA2_OFFSET 0x2C +#define VERSATILE_SYS_FLAGS_OFFSET 0x30 +#define VERSATILE_SYS_FLAGSSET_OFFSET 0x30 +#define VERSATILE_SYS_FLAGSCLR_OFFSET 0x34 +#define VERSATILE_SYS_NVFLAGS_OFFSET 0x38 +#define VERSATILE_SYS_NVFLAGSSET_OFFSET 0x38 +#define VERSATILE_SYS_NVFLAGSCLR_OFFSET 0x3C +#define VERSATILE_SYS_RESETCTL_OFFSET 0x40 +#define VERSATILE_SYS_PICCTL_OFFSET 0x44 +#define VERSATILE_SYS_MCI_OFFSET 0x48 +#define VERSATILE_SYS_FLASH_OFFSET 0x4C +#define VERSATILE_SYS_CLCD_OFFSET 0x50 +#define VERSATILE_SYS_CLCDSER_OFFSET 0x54 +#define VERSATILE_SYS_BOOTCS_OFFSET 0x58 +#define VERSATILE_SYS_24MHz_OFFSET 0x5C +#define VERSATILE_SYS_MISC_OFFSET 0x60 +#define VERSATILE_SYS_TEST_OSC0_OFFSET 0x80 +#define VERSATILE_SYS_TEST_OSC1_OFFSET 0x84 +#define VERSATILE_SYS_TEST_OSC2_OFFSET 0x88 +#define VERSATILE_SYS_TEST_OSC3_OFFSET 0x8C +#define VERSATILE_SYS_TEST_OSC4_OFFSET 0x90 + +#define VERSATILE_SYS_BASE 0x10000000 +#define VERSATILE_SYS_ID (VERSATILE_SYS_BASE + VERSATILE_SYS_ID_OFFSET) +#define VERSATILE_SYS_SW (VERSATILE_SYS_BASE + VERSATILE_SYS_SW_OFFSET) +#define VERSATILE_SYS_LED (VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET) +#define VERSATILE_SYS_OSC0 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC0_OFFSET) +#define VERSATILE_SYS_OSC1 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC1_OFFSET) +#define VERSATILE_SYS_OSC2 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC2_OFFSET) +#define VERSATILE_SYS_OSC3 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC3_OFFSET) +#define VERSATILE_SYS_OSC4 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC4_OFFSET) +#define VERSATILE_SYS_LOCK (VERSATILE_SYS_BASE + VERSATILE_SYS_LOCK_OFFSET) +#define VERSATILE_SYS_100HZ (VERSATILE_SYS_BASE + VERSATILE_SYS_100HZ_OFFSET) +#define VERSATILE_SYS_CFGDATA1 (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA1_OFFSET) +#define VERSATILE_SYS_CFGDATA2 (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA2_OFFSET) +#define VERSATILE_SYS_FLAGS (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGS_OFFSET) +#define VERSATILE_SYS_FLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGSSET_OFFSET) +#define VERSATILE_SYS_FLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGSCLR_OFFSET) +#define VERSATILE_SYS_NVFLAGS (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGS_OFFSET) +#define VERSATILE_SYS_NVFLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSSET_OFFSET) +#define VERSATILE_SYS_NVFLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSCLR_OFFSET) +#define VERSATILE_SYS_RESETCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_RESETCTL_OFFSET) +#define VERSATILE_SYS_PICCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_PICCTL_OFFSET) +#define VERSATILE_SYS_MCI (VERSATILE_SYS_BASE + VERSATILE_SYS_MCI_OFFSET) +#define VERSATILE_SYS_FLASH (VERSATILE_SYS_BASE + VERSATILE_SYS_FLASH_OFFSET) +#define VERSATILE_SYS_CLCD (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCD_OFFSET) +#define VERSATILE_SYS_CLCDSER (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCDSER_OFFSET) +#define VERSATILE_SYS_BOOTCS (VERSATILE_SYS_BASE + VERSATILE_SYS_BOOTCS_OFFSET) +#define VERSATILE_SYS_24MHz (VERSATILE_SYS_BASE + VERSATILE_SYS_24MHz_OFFSET) +#define VERSATILE_SYS_MISC (VERSATILE_SYS_BASE + VERSATILE_SYS_MISC_OFFSET) +#define VERSATILE_SYS_TEST_OSC0 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC0_OFFSET) +#define VERSATILE_SYS_TEST_OSC1 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC1_OFFSET) +#define VERSATILE_SYS_TEST_OSC2 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC2_OFFSET) +#define VERSATILE_SYS_TEST_OSC3 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC3_OFFSET) +#define VERSATILE_SYS_TEST_OSC4 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC4_OFFSET) + +/* + * Values for VERSATILE_SYS_RESET_CTRL + */ +#define VERSATILE_SYS_CTRL_RESET_CONFIGCLR 0x01 +#define VERSATILE_SYS_CTRL_RESET_CONFIGINIT 0x02 +#define VERSATILE_SYS_CTRL_RESET_DLLRESET 0x03 +#define VERSATILE_SYS_CTRL_RESET_PLLRESET 0x04 +#define VERSATILE_SYS_CTRL_RESET_POR 0x05 +#define VERSATILE_SYS_CTRL_RESET_DoC 0x06 + +#define VERSATILE_SYS_CTRL_LED (1 << 0) + + +/* ------------------------------------------------------------------------ + * Versatile PB control registers + * ------------------------------------------------------------------------ + */ + +/* + * VERSATILE_IDFIELD + * + * 31:24 = manufacturer (0x41 = ARM) + * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus) + * 15:12 = FPGA (0x3 = XVC600 or XVC600E) + * 11:4 = build value + * 3:0 = revision number (0x1 = rev B (AHB)) + */ + +/* + * VERSATILE_SYS_LOCK + * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL, + * SYS_CLD, SYS_BOOTCS + */ +#define VERSATILE_SYS_LOCK_LOCKED (1 << 16) +#define VERSATILE_SYS_LOCKVAL_MASK 0xFFFF /* write 0xA05F to enable write access */ + +/* + * VERSATILE_SYS_FLASH + */ +#define VERSATILE_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */ + +/* + * VERSATILE_INTREG + * - used to acknowledge and control MMCI and UART interrupts + */ +#define VERSATILE_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */ +#define VERSATILE_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */ +#define VERSATILE_INTREG_CARDIN 0x08 /* MMCI card in detect */ + /* write 1 to acknowledge and clear */ +#define VERSATILE_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */ +#define VERSATILE_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */ + +/* + * VERSATILE peripheral addresses + */ +#define VERSATILE_PCI_CORE_BASE 0x10001000 /* PCI core control */ +#define VERSATILE_I2C_BASE 0x10002000 /* I2C control */ +#define VERSATILE_SIC_BASE 0x10003000 /* Secondary interrupt controller */ +#define VERSATILE_AACI_BASE 0x10004000 /* Audio */ +#define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */ +#define VERSATILE_KMI0_BASE 0x10006000 /* KMI interface */ +#define VERSATILE_KMI1_BASE 0x10007000 /* KMI 2nd interface */ +#define VERSATILE_CHAR_LCD_BASE 0x10008000 /* Character LCD */ +#define VERSATILE_UART3_BASE 0x10009000 /* UART 3 */ +#define VERSATILE_SCI1_BASE 0x1000A000 +#define VERSATILE_MMCI1_BASE 0x1000B000 /* MMC Interface */ + /* 0x1000C000 - 0x1000CFFF = reserved */ +#define VERSATILE_ETH_BASE 0x10010000 /* Ethernet */ +#define VERSATILE_USB_BASE 0x10020000 /* USB */ + /* 0x10030000 - 0x100FFFFF = reserved */ +#define VERSATILE_SMC_BASE 0x10100000 /* SMC */ +#define VERSATILE_MPMC_BASE 0x10110000 /* MPMC */ +#define VERSATILE_CLCD_BASE 0x10120000 /* CLCD */ +#define VERSATILE_DMAC_BASE 0x10130000 /* DMA controller */ +#define VERSATILE_VIC_BASE 0x10140000 /* Vectored interrupt controller */ +#define VERSATILE_PERIPH_BASE 0x10150000 /* off-chip peripherals alias from */ + /* 0x10000000 - 0x100FFFFF */ +#define VERSATILE_AHBM_BASE 0x101D0000 /* AHB monitor */ +#define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */ +#define VERSATILE_WATCHDOG_BASE 0x101E1000 /* Watchdog */ +#define VERSATILE_TIMER0_1_BASE 0x101E2000 /* Timer 0 and 1 */ +#define VERSATILE_TIMER2_3_BASE 0x101E3000 /* Timer 2 and 3 */ +#define VERSATILE_GPIO0_BASE 0x101E4000 /* GPIO port 0 */ +#define VERSATILE_GPIO1_BASE 0x101E5000 /* GPIO port 1 */ +#define VERSATILE_GPIO2_BASE 0x101E6000 /* GPIO port 2 */ +#define VERSATILE_GPIO3_BASE 0x101E7000 /* GPIO port 3 */ +#define VERSATILE_RTC_BASE 0x101E8000 /* Real Time Clock */ + /* 0x101E9000 - reserved */ +#define VERSATILE_SCI_BASE 0x101F0000 /* Smart card controller */ +#define VERSATILE_UART0_BASE 0x101F1000 /* Uart 0 */ +#define VERSATILE_UART1_BASE 0x101F2000 /* Uart 1 */ +#define VERSATILE_UART2_BASE 0x101F3000 /* Uart 2 */ +#define VERSATILE_SSP_BASE 0x101F4000 /* Synchronous Serial Port */ + +#define VERSATILE_SSMC_BASE 0x20000000 /* SSMC */ +#define VERSATILE_MBX_BASE 0x40000000 /* MBX */ +#define VERSATILE_PCI_BASE 0x41000000 /* PCI Interface */ +#define VERSATILE_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */ +#define VERSATILE_LT_BASE 0x80000000 /* Logic Tile expansion */ + +/* + * Disk on Chip + */ +#define VERSATILE_DOC_BASE 0x2C000000 +#define VERSATILE_DOC_SIZE (16 << 20) +#define VERSATILE_DOC_PAGE_SIZE 512 +#define VERSATILE_DOC_TOTAL_PAGES (DOC_SIZE / PAGE_SIZE) + +#define ERASE_UNIT_PAGES 32 +#define START_PAGE 0x80 + +/* + * LED settings, bits [7:0] + */ +#define VERSATILE_SYS_LED0 (1 << 0) +#define VERSATILE_SYS_LED1 (1 << 1) +#define VERSATILE_SYS_LED2 (1 << 2) +#define VERSATILE_SYS_LED3 (1 << 3) +#define VERSATILE_SYS_LED4 (1 << 4) +#define VERSATILE_SYS_LED5 (1 << 5) +#define VERSATILE_SYS_LED6 (1 << 6) +#define VERSATILE_SYS_LED7 (1 << 7) + +#define ALL_LEDS 0xFF + +#define LED_BANK VERSATILE_SYS_LED + +/* + * Control registers + */ +#define VERSATILE_IDFIELD_OFFSET 0x0 /* Versatile build information */ +#define VERSATILE_FLASHPROG_OFFSET 0x4 /* Flash devices */ +#define VERSATILE_INTREG_OFFSET 0x8 /* Interrupt control */ +#define VERSATILE_DECODE_OFFSET 0xC /* Fitted logic modules */ + + +/* ------------------------------------------------------------------------ + * Versatile PB Interrupt Controller - control registers + * ------------------------------------------------------------------------ + * + * Offsets from interrupt controller base + * + * System Controller interrupt controller base is + * + * VERSATILE_IC_BASE + * + * Core Module interrupt controller base is + * + * VERSATILE_SYS_IC + * + */ +#define VIC_IRQ_STATUS 0 +#define VIC_FIQ_STATUS 0x04 +#define VIC_IRQ_RAW_STATUS 0x08 +#define VIC_INT_SELECT 0x0C /* 1 = FIQ, 0 = IRQ */ +#define VIC_IRQ_ENABLE 0x10 /* 1 = enable, 0 = disable */ +#define VIC_IRQ_ENABLE_CLEAR 0x14 +#define VIC_IRQ_SOFT 0x18 +#define VIC_IRQ_SOFT_CLEAR 0x1C +#define VIC_PROTECT 0x20 +#define VIC_VECT_ADDR 0x30 +#define VIC_DEF_VECT_ADDR 0x34 +#define VIC_VECT_ADDR0 0x100 /* 0 to 15 */ +#define VIC_VECT_CNTL0 0x200 /* 0 to 15 */ +#define VIC_ITCR 0x300 /* VIC test control register */ + +#define VIC_FIQ_RAW_STATUS 0x08 +#define VIC_FIQ_ENABLE 0x10 /* 1 = enable, 0 = disable */ +#define VIC_FIQ_ENABLE_CLEAR 0x14 +#define VIC_FIQ_SOFT 0x18 +#define VIC_FIQ_SOFT_CLEAR 0x1C + +#define SIC_IRQ_STATUS 0 +#define SIC_IRQ_RAW_STATUS 0x04 +#define SIC_IRQ_ENABLE 0x08 +#define SIC_IRQ_ENABLE_SET 0x08 +#define SIC_IRQ_ENABLE_CLEAR 0x0C +#define SIC_INT_SOFT_SET 0x10 +#define SIC_INT_SOFT_CLEAR 0x14 +#define SIC_INT_PIC_ENABLE 0x20 /* read status of pass through mask */ +#define SIC_INT_PIC_ENABLES 0x20 /* set interrupt pass through bits */ +#define SIC_INT_PIC_ENABLEC 0x24 /* Clear interrupt pass through bits */ + +#define VICVectCntl_Enable (1 << 5) + +/* ------------------------------------------------------------------------ + * Interrupts - bit assignment (primary) + * ------------------------------------------------------------------------ + */ + +#define INT_WDOGINT 0 /* Watchdog timer */ +#define INT_SOFTINT 1 /* Software interrupt */ +#define INT_COMMRx 2 /* Debug Comm Rx interrupt */ +#define INT_COMMTx 3 /* Debug Comm Tx interrupt */ +#define INT_TIMERINT0_1 4 /* Timer 0 and 1 */ +#define INT_TIMERINT2_3 5 /* Timer 2 and 3 */ +#define INT_GPIOINT0 6 /* GPIO 0 */ +#define INT_GPIOINT1 7 /* GPIO 1 */ +#define INT_GPIOINT2 8 /* GPIO 2 */ +#define INT_GPIOINT3 9 /* GPIO 3 */ +#define INT_RTCINT 10 /* Real Time Clock */ +#define INT_SSPINT 11 /* Synchronous Serial Port */ +#define INT_UARTINT0 12 /* UART 0 on development chip */ +#define INT_UARTINT1 13 /* UART 1 on development chip */ +#define INT_UARTINT2 14 /* UART 2 on development chip */ +#define INT_SCIINT 15 /* Smart Card Interface */ +#define INT_CLCDINT 16 /* CLCD controller */ +#define INT_DMAINT 17 /* DMA controller */ +#define INT_PWRFAILINT 18 /* Power failure */ +#define INT_MBXINT 19 /* Graphics processor */ +#define INT_GNDINT 20 /* Reserved */ + /* External interrupt signals from logic tiles or secondary controller */ +#define INT_VICSOURCE21 21 /* Disk on Chip */ +#define INT_VICSOURCE22 22 /* MCI0A */ +#define INT_VICSOURCE23 23 /* MCI1A */ +#define INT_VICSOURCE24 24 /* AACI */ +#define INT_VICSOURCE25 25 /* Ethernet */ +#define INT_VICSOURCE26 26 /* USB */ +#define INT_VICSOURCE27 27 /* PCI 0 */ +#define INT_VICSOURCE28 28 /* PCI 1 */ +#define INT_VICSOURCE29 29 /* PCI 2 */ +#define INT_VICSOURCE30 30 /* PCI 3 */ +#define INT_VICSOURCE31 31 /* SIC source */ + +/* + * Interrupt bit positions + * + */ +#define INTMASK_WDOGINT (1 << INT_WDOGINT) +#define INTMASK_SOFTINT (1 << INT_SOFTINT) +#define INTMASK_COMMRx (1 << INT_COMMRx) +#define INTMASK_COMMTx (1 << INT_COMMTx) +#define INTMASK_TIMERINT0_1 (1 << INT_TIMERINT0_1) +#define INTMASK_TIMERINT2_3 (1 << INT_TIMERINT2_3) +#define INTMASK_GPIOINT0 (1 << INT_GPIOINT0) +#define INTMASK_GPIOINT1 (1 << INT_GPIOINT1) +#define INTMASK_GPIOINT2 (1 << INT_GPIOINT2) +#define INTMASK_GPIOINT3 (1 << INT_GPIOINT3) +#define INTMASK_RTCINT (1 << INT_RTCINT) +#define INTMASK_SSPINT (1 << INT_SSPINT) +#define INTMASK_UARTINT0 (1 << INT_UARTINT0) +#define INTMASK_UARTINT1 (1 << INT_UARTINT1) +#define INTMASK_UARTINT2 (1 << INT_UARTINT2) +#define INTMASK_SCIINT (1 << INT_SCIINT) +#define INTMASK_CLCDINT (1 << INT_CLCDINT) +#define INTMASK_DMAINT (1 << INT_DMAINT) +#define INTMASK_PWRFAILINT (1 << INT_PWRFAILINT) +#define INTMASK_MBXINT (1 << INT_MBXINT) +#define INTMASK_GNDINT (1 << INT_GNDINT) +#define INTMASK_VICSOURCE21 (1 << INT_VICSOURCE21) +#define INTMASK_VICSOURCE22 (1 << INT_VICSOURCE22) +#define INTMASK_VICSOURCE23 (1 << INT_VICSOURCE23) +#define INTMASK_VICSOURCE24 (1 << INT_VICSOURCE24) +#define INTMASK_VICSOURCE25 (1 << INT_VICSOURCE25) +#define INTMASK_VICSOURCE26 (1 << INT_VICSOURCE26) +#define INTMASK_VICSOURCE27 (1 << INT_VICSOURCE27) +#define INTMASK_VICSOURCE28 (1 << INT_VICSOURCE28) +#define INTMASK_VICSOURCE29 (1 << INT_VICSOURCE29) +#define INTMASK_VICSOURCE30 (1 << INT_VICSOURCE30) +#define INTMASK_VICSOURCE31 (1 << INT_VICSOURCE31) + + +#define VERSATILE_SC_VALID_INT 0x003FFFFF + +#define MAXIRQNUM 31 +#define MAXFIQNUM 31 +#define MAXSWINUM 31 + +/* ------------------------------------------------------------------------ + * Interrupts - bit assignment (secondary) + * ------------------------------------------------------------------------ + */ +#define SIC_INT_MMCI0B 1 /* Multimedia Card 0B */ +#define SIC_INT_MMCI1B 2 /* Multimedia Card 1B */ +#define SIC_INT_KMI0 3 /* Keyboard/Mouse port 0 */ +#define SIC_INT_KMI1 4 /* Keyboard/Mouse port 1 */ +#define SIC_INT_SCI3 5 /* Smart Card interface */ +#define SIC_INT_UART3 6 /* UART 3 empty or data available */ +#define SIC_INT_CLCD 7 /* Character LCD */ +#define SIC_INT_TOUCH 8 /* Touchscreen */ +#define SIC_INT_KEYPAD 9 /* Key pressed on display keypad */ + /* 10:20 - reserved */ +#define SIC_INT_DoC 21 /* Disk on Chip memory controller */ +#define SIC_INT_MMCI0A 22 /* MMC 0A */ +#define SIC_INT_MMCI1A 23 /* MMC 1A */ +#define SIC_INT_AACI 24 /* Audio Codec */ +#define SIC_INT_ETH 25 /* Ethernet controller */ +#define SIC_INT_USB 26 /* USB controller */ +#define SIC_INT_PCI0 27 +#define SIC_INT_PCI1 28 +#define SIC_INT_PCI2 29 +#define SIC_INT_PCI3 30 + + +#define SIC_INTMASK_MMCI0B (1 << SIC_INT_MMCI0B) +#define SIC_INTMASK_MMCI1B (1 << SIC_INT_MMCI1B) +#define SIC_INTMASK_KMI0 (1 << SIC_INT_KMI0) +#define SIC_INTMASK_KMI1 (1 << SIC_INT_KMI1) +#define SIC_INTMASK_SCI3 (1 << SIC_INT_SCI3) +#define SIC_INTMASK_UART3 (1 << SIC_INT_UART3) +#define SIC_INTMASK_CLCD (1 << SIC_INT_CLCD) +#define SIC_INTMASK_TOUCH (1 << SIC_INT_TOUCH) +#define SIC_INTMASK_KEYPAD (1 << SIC_INT_KEYPAD) +#define SIC_INTMASK_DoC (1 << SIC_INT_DoC) +#define SIC_INTMASK_MMCI0A (1 << SIC_INT_MMCI0A) +#define SIC_INTMASK_MMCI1A (1 << SIC_INT_MMCI1A) +#define SIC_INTMASK_AACI (1 << SIC_INT_AACI) +#define SIC_INTMASK_ETH (1 << SIC_INT_ETH) +#define SIC_INTMASK_USB (1 << SIC_INT_USB) +#define SIC_INTMASK_PCI0 (1 << SIC_INT_PCI0) +#define SIC_INTMASK_PCI1 (1 << SIC_INT_PCI1) +#define SIC_INTMASK_PCI2 (1 << SIC_INT_PCI2) +#define SIC_INTMASK_PCI3 (1 << SIC_INT_PCI3) +/* + * Application Flash + * + */ +#define FLASH_BASE VERSATILE_FLASH_BASE +#define FLASH_SIZE VERSATILE_FLASH_SIZE +#define FLASH_END (FLASH_BASE + FLASH_SIZE - 1) +#define FLASH_BLOCK_SIZE SZ_128K + +/* + * Boot Flash + * + */ +#define EPROM_BASE VERSATILE_BOOT_ROM_HI +#define EPROM_SIZE VERSATILE_BOOT_ROM_SIZE +#define EPROM_END (EPROM_BASE + EPROM_SIZE - 1) + +/* + * Clean base - dummy + * + */ +#define CLEAN_BASE EPROM_BASE + +/* + * System controller bit assignment + */ +#define VERSATILE_REFCLK 0 +#define VERSATILE_TIMCLK 1 + +#define VERSATILE_TIMER1_EnSel 15 +#define VERSATILE_TIMER2_EnSel 17 +#define VERSATILE_TIMER3_EnSel 19 +#define VERSATILE_TIMER4_EnSel 21 + + +#define MAX_TIMER 2 +#define MAX_PERIOD 699050 +#define TICKS_PER_uSEC 1 + +/* + * These are useconds NOT ticks. + * + */ +#define mSEC_1 1000 +#define mSEC_5 (mSEC_1 * 5) +#define mSEC_10 (mSEC_1 * 10) +#define mSEC_25 (mSEC_1 * 25) +#define SEC_1 (mSEC_1 * 1000) + +#define VERSATILE_CSR_BASE 0x10000000 +#define VERSATILE_CSR_SIZE 0x10000000 + +#endif + +/* END */ diff -Nru a/include/asm-arm/arch-versatile/serial.h b/include/asm-arm/arch-versatile/serial.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/serial.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-versatile/serial.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +/* + * This assumes you have a 14.7456 MHz clock UART. + */ +#define BASE_BAUD 115200 + + /* UART CLK PORT IRQ FLAGS */ +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS2 */ \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS3 */ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif diff -Nru a/include/asm-arm/arch-versatile/system.h b/include/asm-arm/arch-versatile/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/system.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,51 @@ +/* + * linux/include/asm-arm/arch-versatile/system.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include +#include + +static inline void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + unsigned int hdr_ctrl = (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_RESETCTL_OFFSET); + unsigned int val; + + /* + * To reset, we hit the on-board reset register + * in the system FPGA + */ + val = __raw_readl(hdr_ctrl); + val |= VERSATILE_SYS_CTRL_RESET_CONFIGCLR; + __raw_writel(val, hdr_ctrl); +} + +#endif diff -Nru a/include/asm-arm/arch-versatile/time.h b/include/asm-arm/arch-versatile/time.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/time.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,158 @@ +/* + * linux/include/asm-arm/arch-versatile/time.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) +#define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) +#define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) +#define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) +#define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ +#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ +#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TIMER_RELOAD (TIMER_INTERVAL) +#define TIMER_CTRL 0x80 /* Enable */ +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ + +/* + * What does it look like? + */ +typedef struct TimerStruct { + unsigned long TimerLoad; + unsigned long TimerValue; + unsigned long TimerControl; + unsigned long TimerClear; +} TimerStruct_t; + +extern unsigned long (*gettimeoffset)(void); + +/* + * Returns number of ms since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +static unsigned long versatile_gettimeoffset(void) +{ + volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE; + unsigned long ticks1, ticks2, status; + + /* + * Get the current number of ticks. Note that there is a race + * condition between us reading the timer and checking for + * an interrupt. We get around this by ensuring that the + * counter has not reloaded between our two reads. + */ + ticks2 = timer0->TimerValue & 0xffff; + do { + ticks1 = ticks2; + status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); + ticks2 = timer0->TimerValue & 0xffff; + } while (ticks2 > ticks1); + + /* + * Number of ticks since last interrupt. + */ + ticks1 = TIMER_RELOAD - ticks2; + + /* + * Interrupt pending? If so, we've reloaded once already. + * + * FIXME: Need to check this is effectively timer 0 that expires + */ + if (status & IRQMASK_TIMERINT0_1) + ticks1 += TIMER_RELOAD; + + /* + * Convert the ticks to usecs + */ + return TICKS2USECS(ticks1); +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + + // ...clear the interrupt + timer0->TimerClear = 1; + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init time_init(void) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; + volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE; + + /* + * set clock frequency: + * VERSATILE_REFCLK is 32KHz + * VERSATILE_TIMCLK is 1MHz + */ + *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= + ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | + (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel)); + + timer_irq.handler = versatile_timer_interrupt; + + /* + * Initialise to a known state (all timers off) + */ + timer0->TimerControl = 0; + timer1->TimerControl = 0; + timer2->TimerControl = 0; + timer3->TimerControl = 0; + + timer0->TimerLoad = TIMER_RELOAD; + timer0->TimerValue = TIMER_RELOAD; + timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */ + + /* + * Make irqs happen for the system timer + */ + setup_irq(IRQ_TIMERINT0_1, &timer_irq); + gettimeoffset = versatile_gettimeoffset; +} diff -Nru a/include/asm-arm/arch-versatile/timex.h b/include/asm-arm/arch-versatile/timex.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/timex.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-versatile/timex.h + * + * Versatile PB architecture timex specifications + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define CLOCK_TICK_RATE (50000000 / 16) diff -Nru a/include/asm-arm/arch-versatile/uncompress.h b/include/asm-arm/arch-versatile/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/uncompress.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,54 @@ +/* + * linux/include/asm-arm/arch-versatile/uncompress.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#define AMBA_UART_DR (*(volatile unsigned char *)0x101F1000) +#define AMBA_UART_LCRH (*(volatile unsigned char *)0x101F102C) +#define AMBA_UART_CR (*(volatile unsigned char *)0x101F1030) +#define AMBA_UART_FR (*(volatile unsigned char *)0x101F1018) + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = *s; + + if (*s == '\n') { + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = '\r'; + } + s++; + } + while (AMBA_UART_FR & (1 << 3)) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff -Nru a/include/asm-arm/arch-versatile/vmalloc.h b/include/asm-arm/arch-versatile/vmalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-versatile/vmalloc.h Sun Apr 25 22:39:32 2004 @@ -0,0 +1,33 @@ +/* + * linux/include/asm-arm/arch-versatile/vmalloc.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x18000000) diff -Nru a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h --- a/include/asm-arm/atomic.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-arm/atomic.h Sun Apr 25 22:39:31 2004 @@ -44,7 +44,7 @@ : "cc"); } -static inline void atomic_add(int i, volatile atomic_t *v) +static inline void atomic_add(int i, atomic_t *v) { unsigned long tmp, tmp2; @@ -59,7 +59,7 @@ : "cc"); } -static inline void atomic_sub(int i, volatile atomic_t *v) +static inline void atomic_sub(int i, atomic_t *v) { unsigned long tmp, tmp2; @@ -77,7 +77,7 @@ #define atomic_inc(v) atomic_add(1, v) #define atomic_dec(v) atomic_sub(1, v) -static inline int atomic_dec_and_test(volatile atomic_t *v) +static inline int atomic_dec_and_test(atomic_t *v) { unsigned long tmp; int result; @@ -95,7 +95,7 @@ return result == 0; } -static inline int atomic_add_negative(int i, volatile atomic_t *v) +static inline int atomic_add_negative(int i, atomic_t *v) { unsigned long tmp; int result; @@ -138,7 +138,7 @@ #define atomic_set(v,i) (((v)->counter) = (i)) -static inline void atomic_add(int i, volatile atomic_t *v) +static inline void atomic_add(int i, atomic_t *v) { unsigned long flags; @@ -147,7 +147,7 @@ local_irq_restore(flags); } -static inline void atomic_sub(int i, volatile atomic_t *v) +static inline void atomic_sub(int i, atomic_t *v) { unsigned long flags; @@ -156,7 +156,7 @@ local_irq_restore(flags); } -static inline void atomic_inc(volatile atomic_t *v) +static inline void atomic_inc(atomic_t *v) { unsigned long flags; @@ -165,7 +165,7 @@ local_irq_restore(flags); } -static inline void atomic_dec(volatile atomic_t *v) +static inline void atomic_dec(atomic_t *v) { unsigned long flags; @@ -174,7 +174,7 @@ local_irq_restore(flags); } -static inline int atomic_dec_and_test(volatile atomic_t *v) +static inline int atomic_dec_and_test(atomic_t *v) { unsigned long flags; int val; @@ -187,7 +187,7 @@ return val == 0; } -static inline int atomic_add_negative(int i, volatile atomic_t *v) +static inline int atomic_add_negative(int i, atomic_t *v) { unsigned long flags; int val; diff -Nru a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h --- a/include/asm-arm/bitops.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-arm/bitops.h Sun Apr 25 22:39:31 2004 @@ -212,6 +212,8 @@ extern int _test_and_change_bit_le(int nr, volatile unsigned long * p); extern int _find_first_zero_bit_le(void * p, unsigned size); extern int _find_next_zero_bit_le(void * p, int size, int offset); +extern int _find_first_bit_le(const unsigned long *p, unsigned size); +extern int _find_next_bit_le(const unsigned long *p, int size, int offset); /* * Big endian assembly bitops. nr = 0 -> byte 3 bit 0. @@ -224,7 +226,8 @@ extern int _test_and_change_bit_be(int nr, volatile unsigned long * p); extern int _find_first_zero_bit_be(void * p, unsigned size); extern int _find_next_zero_bit_be(void * p, int size, int offset); - +extern int _find_first_bit_be(const unsigned long *p, unsigned size); +extern int _find_next_bit_be(unsigned long *p, int size, int offset); /* * The __* form of bitops are non-atomic and may be reordered. @@ -255,6 +258,8 @@ #define test_bit(nr,p) __test_bit(nr,p) #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) +#define find_first_bit(p,sz) _find_first_bit_le(p,sz) +#define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off) #define WORD_BITOFF_TO_LE(x) ((x)) @@ -272,6 +277,8 @@ #define test_bit(nr,p) __test_bit(nr,p) #define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) +#define find_first_bit(p,sz) _find_first_bit_be(p,sz) +#define find_next_bit(p,sz,off) _find_next_bit_be(p,sz,off) #define WORD_BITOFF_TO_LE(x) ((x) ^ 0x18) diff -Nru a/include/asm-arm/div64.h b/include/asm-arm/div64.h --- a/include/asm-arm/div64.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-arm/div64.h Sun Apr 25 22:39:31 2004 @@ -1,6 +1,8 @@ #ifndef __ASM_ARM_DIV64 #define __ASM_ARM_DIV64 +#include + /* * The semantics of do_div() are: * @@ -31,7 +33,11 @@ register unsigned long long __n asm("r0") = n; \ register unsigned long long __res asm("r2"); \ register unsigned int __rem asm(__xh); \ - asm("bl __do_div64" \ + asm( __asmeq("%0", __xh) \ + __asmeq("%1", "r2") \ + __asmeq("%2", "r0") \ + __asmeq("%3", "r4") \ + "bl __do_div64" \ : "=r" (__rem), "=r" (__res) \ : "r" (__n), "r" (__base) \ : "ip", "lr", "cc"); \ diff -Nru a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h --- a/include/asm-arm/dma-mapping.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-arm/dma-mapping.h Sun Apr 25 22:39:31 2004 @@ -17,29 +17,6 @@ extern void consistent_sync(void *kaddr, size_t size, int rw); /* - * For SA-1111 these functions are "magic" and utilize bounce - * bufferes as needed to work around SA-1111 DMA bugs. - */ -dma_addr_t sa1111_map_single(struct device *dev, void *, size_t, enum dma_data_direction); -void sa1111_unmap_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); -int sa1111_map_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction); -void sa1111_unmap_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction); -void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); -void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); -void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *, int, enum dma_data_direction); -void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *, int, enum dma_data_direction); - -#ifdef CONFIG_SA1111 - -extern struct bus_type sa1111_bus_type; - -#define dmadev_is_sa1111(dev) ((dev)->bus == &sa1111_bus_type) - -#else -#define dmadev_is_sa1111(dev) (0) -#endif - -/* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits * during bus mastering, then you would pass 0x00ffffff as the mask @@ -70,6 +47,14 @@ return 0; } +/* + * DMA errors are defined by all-bits-set in the DMA address. + */ +static inline int dma_mapping_error(dma_addr_t dma_addr) +{ + return dma_addr == ~0; +} + /** * dma_alloc_coherent - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -118,6 +103,7 @@ #define dma_free_writecombine(dev,size,cpu_addr,handle) \ dma_free_coherent(dev,size,cpu_addr,handle) + /** * dma_map_single - map a single buffer for streaming DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -132,16 +118,17 @@ * can regain ownership by calling dma_unmap_single() or * dma_sync_single_for_cpu(). */ +#ifndef CONFIG_DMABOUNCE static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { - if (dmadev_is_sa1111(dev)) - return sa1111_map_single(dev, cpu_addr, size, dir); - consistent_sync(cpu_addr, size, dir); return __virt_to_bus((unsigned long)cpu_addr); } +#else +extern dma_addr_t dma_map_single(struct device *,void *, size_t, enum dma_data_direction); +#endif /** * dma_map_page - map a portion of a page for streaming DMA @@ -180,15 +167,16 @@ * After this call, reads by the CPU to the buffer are guaranteed to see * whatever the device wrote there. */ +#ifndef CONFIG_DMABOUNCE static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - if (dmadev_is_sa1111(dev)) - sa1111_unmap_single(dev, handle, size, dir); - /* nothing to do */ } +#else +extern void dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction); +#endif /** * dma_unmap_page - unmap a buffer previously mapped through dma_map_page() @@ -233,15 +221,13 @@ * Device ownership issues as mentioned above for dma_map_single are * the same here. */ +#ifndef CONFIG_DMABOUNCE static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir) { int i; - if (dmadev_is_sa1111(dev)) - return sa1111_map_sg(dev, sg, nents, dir); - for (i = 0; i < nents; i++, sg++) { char *virt; @@ -252,6 +238,9 @@ return nents; } +#else +extern int dma_map_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); +#endif /** * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg @@ -264,17 +253,18 @@ * Again, CPU read rules concerning calls here are the same as for * dma_unmap_single() above. */ +#ifndef CONFIG_DMABOUNCE static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir) { - if (dmadev_is_sa1111(dev)) { - sa1111_unmap_sg(dev, sg, nents, dir); - return; - } /* nothing to do */ } +#else +extern void dma_unmap_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); +#endif + /** * dma_sync_single_for_cpu @@ -293,15 +283,11 @@ * must first the perform a dma_sync_for_device, and then the * device again owns the buffer. */ +#ifndef CONFIG_DMABOUNCE static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - if (dmadev_is_sa1111(dev)) { - sa1111_dma_sync_single_for_cpu(dev, handle, size, dir); - return; - } - consistent_sync((void *)__bus_to_virt(handle), size, dir); } @@ -309,13 +295,13 @@ dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - if (dmadev_is_sa1111(dev)) { - sa1111_dma_sync_single_for_device(dev, handle, size, dir); - return; - } - consistent_sync((void *)__bus_to_virt(handle), size, dir); } +#else +extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction); +extern void dma_sync_single_for_device(struct device*, dma_addr_t, size_t, enum dma_data_direction); +#endif + /** * dma_sync_sg_for_cpu @@ -330,17 +316,13 @@ * The same as dma_sync_single_for_* but for a scatter-gather list, * same rules and usage. */ +#ifndef CONFIG_DMABOUNCE static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir) { int i; - if (dmadev_is_sa1111(dev)) { - sa1111_dma_sync_sg_for_cpu(dev, sg, nents, dir); - return; - } - for (i = 0; i < nents; i++, sg++) { char *virt = page_address(sg->page) + sg->offset; consistent_sync(virt, sg->length, dir); @@ -353,24 +335,73 @@ { int i; - if (dmadev_is_sa1111(dev)) { - sa1111_dma_sync_sg_for_device(dev, sg, nents, dir); - return; - } - for (i = 0; i < nents; i++, sg++) { char *virt = page_address(sg->page) + sg->offset; consistent_sync(virt, sg->length, dir); } } +#else +extern void dma_sync_sg_for_cpu(struct device*, struct scatterlist*, int, enum dma_data_direction); +extern void dma_sync_sg_for_device(struct device*, struct scatterlist*, int, enum dma_data_direction); +#endif +#ifdef CONFIG_DMABOUNCE /* - * DMA errors are defined by all-bits-set in the DMA address. + * For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic" + * and utilize bounce buffers as needed to work around limited DMA windows. + * + * On the SA-1111, a bug limits DMA to only certain regions of RAM. + * On the IXP425, the PCI inbound window is 64MB (256MB total RAM) + * On some ADI engineering sytems, PCI inbound window is 32MB (12MB total RAM) + * + * The following are helper functions used by the dmabounce subystem + * */ -static inline int dma_mapping_error(dma_addr_t dma_addr) -{ - return dma_addr == ~0; -} + +/** + * dmabounce_register_dev + * + * @dev: valid struct device pointer + * @small_buf_size: size of buffers to use with small buffer pool + * @large_buf_size: size of buffers to use with large buffer pool (can be 0) + * + * This function should be called by low-level platform code to register + * a device as requireing DMA buffer bouncing. The function will allocate + * appropriate DMA pools for the device. + * + */ +extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long); + +/** + * dmabounce_unregister_dev + * + * @dev: valid struct device pointer + * + * This function should be called by low-level platform code when device + * that was previously registered with dmabounce_register_dev is removed + * from the system. + * + */ +extern void dmabounce_unregister_dev(struct device *); + +/** + * dma_needs_bounce + * + * @dev: valid struct device pointer + * @dma_handle: dma_handle of unbounced buffer + * @size: size of region being mapped + * + * Platforms that utilize the dmabounce mechanism must implement + * this function. + * + * The dmabounce routines call this function whenever a dma-mapping + * is requested to determine whether a given buffer needs to be bounced + * or not. The function must return 0 if the the buffer is OK for + * DMA access and 1 if the buffer needs to be bounced. + * + */ +extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); +#endif /* CONFIG_DMABOUNCE */ #endif /* __KERNEL__ */ #endif diff -Nru a/include/asm-arm/system.h b/include/asm-arm/system.h --- a/include/asm-arm/system.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-arm/system.h Sun Apr 25 22:39:31 2004 @@ -42,6 +42,15 @@ #define CR_XP (1 << 23) /* Extended page tables */ #define CR_VE (1 << 24) /* Vectored interrupts */ +/* + * This is used to ensure the compiler did actually allocate the register we + * asked it for some inline assembly sequences. Apparently we can't trust + * the compiler from one version to another so a bit of paranoia won't hurt. + * This string is meant to be concatenated with the inline asm string and + * will cause compilation to stop on mismatch. + */ +#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" + #ifndef __ASSEMBLY__ #include diff -Nru a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h --- a/include/asm-arm/uaccess.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-arm/uaccess.h Sun Apr 25 22:39:31 2004 @@ -15,6 +15,7 @@ #include #include #include +#include #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -107,7 +108,9 @@ extern int __get_user_bad(void); #define __get_user_x(__r1,__p,__e,__s,__i...) \ - __asm__ __volatile__ ("bl __get_user_" #__s \ + __asm__ __volatile__ ( \ + __asmeq("%0", "r0") __asmeq("%1", "r1") \ + "bl __get_user_" #__s \ : "=&r" (__e), "=r" (__r1) \ : "0" (__p) \ : __i, "cc") @@ -223,7 +226,9 @@ extern int __put_user_bad(void); #define __put_user_x(__r1,__p,__e,__s) \ - __asm__ __volatile__ ("bl __put_user_" #__s \ + __asm__ __volatile__ ( \ + __asmeq("%0", "r0") __asmeq("%2", "r1") \ + "bl __put_user_" #__s \ : "=&r" (__e) \ : "0" (__p), "r" (__r1) \ : "ip", "lr", "cc") diff -Nru a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h --- a/include/asm-ia64/ia32.h Sun Apr 25 22:39:32 2004 +++ b/include/asm-ia64/ia32.h Sun Apr 25 22:39:32 2004 @@ -6,7 +6,7 @@ #include #include -#define IA32_NR_syscalls 275 /* length of syscall table */ +#define IA32_NR_syscalls 283 /* length of syscall table */ #ifndef __ASSEMBLY__ diff -Nru a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h --- a/include/asm-ia64/siginfo.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-ia64/siginfo.h Sun Apr 25 22:39:31 2004 @@ -136,8 +136,6 @@ memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); } -extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from); - #endif /* __KERNEL__ */ #endif /* _ASM_IA64_SIGINFO_H */ diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h --- a/include/asm-ia64/unistd.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-ia64/unistd.h Sun Apr 25 22:39:31 2004 @@ -251,6 +251,12 @@ #define __NR_reserved1 1259 /* reserved for NUMA interface */ #define __NR_reserved2 1260 /* reserved for NUMA interface */ #define __NR_reserved3 1261 /* reserved for NUMA interface */ +#define __NR_mq_open 1262 +#define __NR_mq_unlink 1263 +#define __NR_mq_timedsend 1264 +#define __NR_mq_timedreceive 1265 +#define __NR_mq_notify 1266 +#define __NR_mq_getsetattr 1267 #ifdef __KERNEL__ diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h --- a/include/asm-ppc/processor.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-ppc/processor.h Sun Apr 25 22:39:31 2004 @@ -121,6 +121,8 @@ #endif /* CONFIG_ALTIVEC */ }; +#define ARCH_MIN_TASKALIGN 16 + #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) #define INIT_THREAD { \ diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h --- a/include/asm-ppc64/processor.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-ppc64/processor.h Sun Apr 25 22:39:31 2004 @@ -553,6 +553,8 @@ #endif /* CONFIG_ALTIVEC */ }; +#define ARCH_MIN_TASKALIGN 16 + #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) #define INIT_THREAD { \ diff -Nru a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h --- a/include/asm-sparc64/siginfo.h Sun Apr 25 22:39:31 2004 +++ b/include/asm-sparc64/siginfo.h Sun Apr 25 22:39:31 2004 @@ -37,8 +37,10 @@ /* POSIX.1b timers */ struct { - unsigned int _timer1; - unsigned int _timer2; + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t32 _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ } _timer; /* POSIX.1b signals */ diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h --- a/include/linux/buffer_head.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/buffer_head.h Sun Apr 25 22:39:31 2004 @@ -157,6 +157,8 @@ wait_queue_head_t *bh_waitq_head(struct buffer_head *bh); void wake_up_buffer(struct buffer_head *bh); int fsync_bdev(struct block_device *); +struct super_block *freeze_bdev(struct block_device *); +void thaw_bdev(struct block_device *, struct super_block *); int fsync_super(struct super_block *); int fsync_no_super(struct block_device *); struct buffer_head *__find_get_block(struct block_device *, sector_t, int); diff -Nru a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h --- a/include/linux/compat_ioctl.h Sun Apr 25 22:39:32 2004 +++ b/include/linux/compat_ioctl.h Sun Apr 25 22:39:32 2004 @@ -597,7 +597,7 @@ COMPATIBLE_IOCTL(RNDADDENTROPY) COMPATIBLE_IOCTL(RNDZAPENTCNT) COMPATIBLE_IOCTL(RNDCLEARPOOL) -/* Bluetooth ioctls */ +/* Bluetooth */ COMPATIBLE_IOCTL(HCIDEVUP) COMPATIBLE_IOCTL(HCIDEVDOWN) COMPATIBLE_IOCTL(HCIDEVRESET) @@ -631,6 +631,20 @@ COMPATIBLE_IOCTL(CMTPCONNDEL) COMPATIBLE_IOCTL(CMTPGETCONNLIST) COMPATIBLE_IOCTL(CMTPGETCONNINFO) +/* CAPI */ +COMPATIBLE_IOCTL(CAPI_REGISTER) +COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER) +COMPATIBLE_IOCTL(CAPI_GET_VERSION) +COMPATIBLE_IOCTL(CAPI_GET_SERIAL) +COMPATIBLE_IOCTL(CAPI_GET_PROFILE) +COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD) +COMPATIBLE_IOCTL(CAPI_GET_ERRCODE) +COMPATIBLE_IOCTL(CAPI_INSTALLED) +COMPATIBLE_IOCTL(CAPI_GET_FLAGS) +COMPATIBLE_IOCTL(CAPI_SET_FLAGS) +COMPATIBLE_IOCTL(CAPI_CLR_FLAGS) +COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT) +COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT) /* Misc. */ COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/fs.h Sun Apr 25 22:39:31 2004 @@ -345,6 +345,7 @@ struct inode * bd_inode; /* will die */ int bd_openers; struct semaphore bd_sem; /* open/close mutex */ + struct semaphore bd_mount_sem; /* mount mutex */ struct list_head bd_inodes; void * bd_holder; int bd_holders; @@ -749,6 +750,9 @@ struct list_head s_instances; struct quota_info s_dquot; /* Diskquota specific options */ + int s_frozen; + wait_queue_head_t s_wait_unfrozen; + char s_id[32]; /* Informational name */ void *s_fs_info; /* Filesystem private info */ @@ -759,6 +763,18 @@ */ struct semaphore s_vfs_rename_sem; /* Kludge */ }; + +/* + * Snapshotting support. + */ +enum { + SB_UNFROZEN = 0, + SB_FREEZE_WRITE = 1, + SB_FREEZE_TRANS = 2, +}; + +#define vfs_check_frozen(sb, level) \ + wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) /* * Superblock locking. diff -Nru a/include/linux/ide.h b/include/linux/ide.h --- a/include/linux/ide.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/ide.h Sun Apr 25 22:39:31 2004 @@ -215,8 +215,6 @@ #define SECTOR_SIZE 512 #define SECTOR_WORDS (SECTOR_SIZE / 4) /* number of 32bit words per sector */ #define IDE_LARGE_SEEK(b1,b2,t) (((b1) > (b2) + (t)) || ((b2) > (b1) + (t))) -#define IDE_MIN(a,b) ((a)<(b) ? (a):(b)) -#define IDE_MAX(a,b) ((a)>(b) ? (a):(b)) /* * Timeouts for various operations: diff -Nru a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/mm.h Sun Apr 25 22:39:31 2004 @@ -486,6 +486,8 @@ int __set_page_dirty_buffers(struct page *page); int __set_page_dirty_nobuffers(struct page *page); +int redirty_page_for_writepage(struct writeback_control *wbc, + struct page *page); int FASTCALL(set_page_dirty(struct page *page)); int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/pci_ids.h Sun Apr 25 22:39:31 2004 @@ -1383,6 +1383,9 @@ #define PCI_DEVICE_ID_SBE_WANXL400 0x0104 #define PCI_VENDOR_ID_TOSHIBA 0x1179 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0103 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0105 #define PCI_DEVICE_ID_TOSHIBA_601 0x0601 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a #define PCI_DEVICE_ID_TOSHIBA_TOPIC95_A 0x0603 diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h --- a/include/linux/proc_fs.h Sun Apr 25 22:39:32 2004 +++ b/include/linux/proc_fs.h Sun Apr 25 22:39:32 2004 @@ -24,8 +24,6 @@ PROC_ROOT_INO = 1, }; -/* Finally, the dynamically allocatable proc entries are reserved: */ - #define PROC_SUPER_MAGIC 0x9fa0 /* diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/sched.h Sun Apr 25 22:39:31 2004 @@ -151,7 +151,6 @@ extern void show_state(void); extern void show_regs(struct pt_regs *); -extern void show_trace_task(task_t *tsk); /* * TASK is a pointer to the task whose backtrace we want to see (or NULL for current diff -Nru a/include/linux/sctp.h b/include/linux/sctp.h --- a/include/linux/sctp.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/sctp.h Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * (C) Copyright IBM Corp. 2001, 2003 + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. @@ -93,6 +93,9 @@ SCTP_CID_ECN_CWR = 13, SCTP_CID_SHUTDOWN_COMPLETE = 14, + /* PR-SCTP Sec 3.2 */ + SCTP_CID_FWD_TSN = 0xC0, + /* Use hex, as defined in ADDIP sec. 3.1 */ SCTP_CID_ASCONF = 0xC1, SCTP_CID_ASCONF_ACK = 0x80, @@ -168,6 +171,9 @@ SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), + /* PR-SCTP Sec 3.1 */ + SCTP_PARAM_FWD_TSN_SUPPORT = __constant_htons(0xc000), + /* Add-IP Extension. Section 3.2 */ SCTP_PARAM_ADD_IP = __constant_htons(0xc001), SCTP_PARAM_DEL_IP = __constant_htons(0xc002), @@ -472,9 +478,67 @@ sctp_cwrhdr_t cwr_hdr; } __attribute__((packed)) sctp_cwr_chunk_t; -/* - * ADDIP Section 3.1 New Chunk Types +/* PR-SCTP + * 3.2 Forward Cumulative TSN Chunk Definition (FORWARD TSN) + * + * Forward Cumulative TSN chunk has the following format: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 192 | Flags = 0x00 | Length = Variable | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | New Cumulative TSN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Stream-1 | Stream Sequence-1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ / + * / \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Stream-N | Stream Sequence-N | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: + * + * Set to all zeros on transmit and ignored on receipt. + * + * New Cumulative TSN: 32 bit u_int + * + * This indicates the new cumulative TSN to the data receiver. Upon + * the reception of this value, the data receiver MUST consider + * any missing TSNs earlier than or equal to this value as received + * and stop reporting them as gaps in any subsequent SACKs. + * + * Stream-N: 16 bit u_int + * + * This field holds a stream number that was skipped by this + * FWD-TSN. + * + * Stream Sequence-N: 16 bit u_int + * This field holds the sequence number associated with the stream + * that was skipped. The stream sequence field holds the largest stream + * sequence number in this stream being skipped. The receiver of + * the FWD-TSN's can use the Stream-N and Stream Sequence-N fields + * to enable delivery of any stranded TSN's that remain on the stream + * re-ordering queues. This field MUST NOT report TSN's corresponding + * to DATA chunk that are marked as unordered. For ordered DATA + * chunks this field MUST be filled in. */ +struct sctp_fwdtsn_skip { + __u16 stream; + __u16 ssn; +} __attribute__((packed)); + +struct sctp_fwdtsn_hdr { + __u32 new_cum_tsn; + struct sctp_fwdtsn_skip skip[0]; +} __attribute((packed)); + +struct sctp_fwdtsn_chunk { + struct sctp_chunkhdr chunk_hdr; + struct sctp_fwdtsn_hdr fwdtsn_hdr; +} __attribute((packed)); + /* ADDIP * Section 3.1.1 Address Configuration Change Chunk (ASCONF) diff -Nru a/include/linux/security.h b/include/linux/security.h --- a/include/linux/security.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/security.h Sun Apr 25 22:39:31 2004 @@ -44,7 +44,7 @@ extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_bprm_set_security (struct linux_binprm *bprm); -extern void cap_bprm_compute_creds (struct linux_binprm *bprm); +extern void cap_bprm_apply_creds (struct linux_binprm *bprm); extern int cap_bprm_secureexec(struct linux_binprm *bprm); extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags); extern int cap_inode_removexattr(struct dentry *dentry, char *name); @@ -102,7 +102,7 @@ * @bprm_free_security: * @bprm contains the linux_binprm structure to be modified. * Deallocate and clear the @bprm->security field. - * @bprm_compute_creds: + * @bprm_apply_creds: * Compute and set the security attributes of a process being transformed * by an execve operation based on the old attributes (current->security) * and the information saved in @bprm->security by the set_security hook. @@ -115,7 +115,7 @@ * @bprm contains the linux_binprm structure. * @bprm_set_security: * Save security information in the bprm->security field, typically based - * on information about the bprm->file, for later use by the compute_creds + * on information about the bprm->file, for later use by the apply_creds * hook. This hook may also optionally check permissions (e.g. for * transitions between security domains). * This hook may be called multiple times during a single execve, e.g. for @@ -924,7 +924,7 @@ * Check permission before allowing the @parent process to trace the * @child process. * Security modules may also want to perform a process tracing check - * during an execve in the set_security or compute_creds hooks of + * during an execve in the set_security or apply_creds hooks of * binprm_security_ops if the process is being traced and its security * attributes would be changed by the execve. * @parent contains the task_struct structure for parent process. @@ -1026,7 +1026,7 @@ int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); - void (*bprm_compute_creds) (struct linux_binprm * bprm); + void (*bprm_apply_creds) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_check_security) (struct linux_binprm * bprm); int (*bprm_secureexec) (struct linux_binprm * bprm); @@ -1290,9 +1290,9 @@ { security_ops->bprm_free_security (bprm); } -static inline void security_bprm_compute_creds (struct linux_binprm *bprm) +static inline void security_bprm_apply_creds (struct linux_binprm *bprm) { - security_ops->bprm_compute_creds (bprm); + security_ops->bprm_apply_creds (bprm); } static inline int security_bprm_set (struct linux_binprm *bprm) { @@ -1962,9 +1962,9 @@ static inline void security_bprm_free (struct linux_binprm *bprm) { } -static inline void security_bprm_compute_creds (struct linux_binprm *bprm) +static inline void security_bprm_apply_creds (struct linux_binprm *bprm) { - cap_bprm_compute_creds (bprm); + cap_bprm_apply_creds (bprm); } static inline int security_bprm_set (struct linux_binprm *bprm) diff -Nru a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h --- a/include/linux/sunrpc/svcauth_gss.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/sunrpc/svcauth_gss.h Sun Apr 25 22:39:31 2004 @@ -20,6 +20,7 @@ #include int gss_svc_init(void); +void gss_svc_shutdown(void); int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); #endif /* __KERNEL__ */ diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/sysctl.h Sun Apr 25 22:39:31 2004 @@ -326,6 +326,11 @@ NET_IPV4_IPFRAG_SECRET_INTERVAL=94, NET_TCP_WESTWOOD=95, NET_IPV4_IGMP_MAX_MSF=96, + NET_TCP_NO_METRICS_SAVE=97, + NET_TCP_VEGAS=98, + NET_TCP_VEGAS_ALPHA=99, + NET_TCP_VEGAS_BETA=100, + NET_TCP_VEGAS_GAMMA=101, }; enum { @@ -602,8 +607,7 @@ NET_SCTP_PRESERVE_ENABLE = 11, NET_SCTP_MAX_BURST = 12, NET_SCTP_ADDIP_ENABLE = 13, - NET_SCTP_RMEM = 14, - NET_SCTP_WMEM = 15, + NET_SCTP_PRSCTP_ENABLE = 14, }; /* /proc/sys/net/bridge */ diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h --- a/include/linux/tcp.h Sun Apr 25 22:39:31 2004 +++ b/include/linux/tcp.h Sun Apr 25 22:39:31 2004 @@ -255,6 +255,10 @@ __u8 retransmits; /* Number of unrecovered RTO timeouts. */ __u8 reordering; /* Packet reordering metric. */ + __u8 frto_counter; /* Number of new acks after RTO */ + __u32 frto_highmark; /* snd_nxt when RTO occurred */ + + __u8 unused_pad; __u8 queue_shrunk; /* Write queue has been shrunk recently.*/ __u8 defer_accept; /* User waits for some data after accept() */ @@ -370,9 +374,6 @@ unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; - int frto_counter; /* Number of new acks after RTO */ - __u32 frto_highmark; /* snd_nxt when RTO occurred */ - unsigned long last_synq_overflow; /* TCP Westwood structure */ @@ -387,6 +388,18 @@ __u32 rtt; __u32 rtt_min; /* minimum observed RTT */ } westwood; + +/* Vegas variables */ + struct { + __u32 beg_snd_nxt; /* right edge during last RTT */ + __u32 beg_snd_una; /* left edge during last RTT */ + __u32 beg_snd_cwnd; /* saves the size of the cwnd */ + __u8 do_vegas; /* do vegas for this connection */ + __u8 doing_vegas_now;/* if true, do vegas for this RTT */ + __u16 cntRTT; /* # of RTTs measured within last RTT */ + __u32 minRTT; /* min of RTTs measured within last RTT (in usec) */ + __u32 baseRTT; /* the min of all Vegas RTT measurements seen (in usec) */ + } vegas; }; /* WARNING: don't change the layout of the members in tcp_sock! */ diff -Nru a/include/net/sctp/command.h b/include/net/sctp/command.h --- a/include/net/sctp/command.h Sun Apr 25 22:39:32 2004 +++ b/include/net/sctp/command.h Sun Apr 25 22:39:32 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * (C) Copyright IBM Corp. 2001, 2003 + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (C) 1999-2001 Cisco, Motorola * * This file is part of the SCTP kernel reference Implementation @@ -29,6 +29,7 @@ * La Monte H.P. Yarroll * Karl Knutson * Ardelle Fan + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -90,6 +91,8 @@ SCTP_CMD_RENEGE, /* Renege data on an association. */ SCTP_CMD_SETUP_T4, /* ADDIP, setup T4 RTO timer parms. */ SCTP_CMD_PROCESS_OPERR, /* Process an ERROR chunk. */ + SCTP_CMD_REPORT_FWDTSN, /* Report new cumulative TSN Ack. */ + SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */ SCTP_CMD_LAST } sctp_verb_t; diff -Nru a/include/net/sctp/constants.h b/include/net/sctp/constants.h --- a/include/net/sctp/constants.h Sun Apr 25 22:39:31 2004 +++ b/include/net/sctp/constants.h Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * (C) Copyright IBM Corp. 2001, 2003 + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. @@ -57,15 +57,6 @@ enum { SCTP_DEFAULT_OUTSTREAMS = 10 }; enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM }; -/* Define the amount of space to reserve for SCTP, IP, LL. - * There is a little bit of waste that we are always allocating - * for ipv6 headers, but this seems worth the simplicity. - */ - -#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\ - + sizeof(struct ipv6hdr)\ - + MAX_HEADER)) - /* Since CIDs are sparse, we need all four of the following * symbols. CIDs are dense through SCTP_CID_BASE_MAX. */ @@ -77,6 +68,8 @@ #define SCTP_NUM_ADDIP_CHUNK_TYPES 2 +#define SCTP_NUM_PRSCTP_CHUNK_TYPES 1 + /* These are the different flavours of event. */ typedef enum { @@ -355,7 +348,6 @@ SCTP_XMIT_OK, SCTP_XMIT_PMTU_FULL, SCTP_XMIT_RWND_FULL, - SCTP_XMIT_MUST_FRAG, SCTP_XMIT_NAGLE_DELAY, } sctp_xmit_t; diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h --- a/include/net/sctp/sctp.h Sun Apr 25 22:39:31 2004 +++ b/include/net/sctp/sctp.h Sun Apr 25 22:39:31 2004 @@ -437,12 +437,15 @@ static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu) { int frag = pmtu; - frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); - frag -= sizeof(struct sctp_sack_chunk); + + frag -= sp->pf->af->net_header_len; + frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk); if (sp->user_frag) frag = min_t(int, frag, sp->user_frag); + frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN); + return frag; } @@ -471,6 +474,14 @@ WORD_ROUND(ntohs(err->length));\ err = (sctp_errhdr_t *)((void *)err + \ WORD_ROUND(ntohs(err->length)))) + +#define sctp_walk_fwdtsn(pos, chunk)\ +_sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk)) + +#define _sctp_walk_fwdtsn(pos, chunk, end)\ +for (pos = chunk->subh.fwdtsn_hdr->skip;\ + (void *)pos <= (void *)chunk->subh.fwdtsn_hdr->skip + end - sizeof(struct sctp_fwdtsn_skip);\ + pos++) /* Round an int up to the next multiple of 4. */ #define WORD_ROUND(s) (((s)+3)&~3) diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h --- a/include/net/sctp/sm.h Sun Apr 25 22:39:31 2004 +++ b/include/net/sctp/sm.h Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * (C) Copyright IBM Corp. 2001, 2003 + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. @@ -141,6 +141,9 @@ sctp_state_fn_t sctp_sf_do_5_2_6_stale; sctp_state_fn_t sctp_sf_do_asconf; sctp_state_fn_t sctp_sf_do_asconf_ack; +sctp_state_fn_t sctp_sf_do_9_2_reshutack; +sctp_state_fn_t sctp_sf_eat_fwd_tsn; +sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; /* Prototypes for primitive event state functions. */ sctp_state_fn_t sctp_sf_do_prm_asoc; @@ -170,25 +173,6 @@ sctp_state_fn_t sctp_sf_do_6_2_sack; sctp_state_fn_t sctp_sf_autoclose_timer_expire; - -/* These are state functions which are either obsolete or not in use yet. - * If any of these functions needs to be revived, it should be renamed with - * the "sctp_sf_xxx" prefix, and be moved to the above prototype groups. - */ - -/* Prototypes for chunk state functions. Not in use. */ -sctp_state_fn_t sctp_sf_do_9_2_reshutack; -sctp_state_fn_t sctp_sf_do_9_2_reshut; -sctp_state_fn_t sctp_sf_do_9_2_shutack; - -/* Prototypes for timeout event state functions. Not in use. */ -sctp_state_fn_t sctp_do_4_2_reinit; -sctp_state_fn_t sctp_do_4_3_reecho; -sctp_state_fn_t sctp_do_9_2_reshut; -sctp_state_fn_t sctp_do_9_2_reshutack; -sctp_state_fn_t sctp_do_8_3_hb_err; -sctp_state_fn_t sctp_heartoff; - /* Prototypes for utility support functions. */ __u8 sctp_get_chunk_type(struct sctp_chunk *chunk); const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t, @@ -277,6 +261,9 @@ struct sctp_chunk *asconf); int sctp_process_asconf_ack(struct sctp_association *asoc, struct sctp_chunk *asconf_ack); +struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, + __u32 new_cum_tsn, size_t nstreams, + struct sctp_fwdtsn_skip *skiplist); void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_ssn(struct sctp_chunk *); diff -Nru a/include/net/sctp/structs.h b/include/net/sctp/structs.h --- a/include/net/sctp/structs.h Sun Apr 25 22:39:32 2004 +++ b/include/net/sctp/structs.h Sun Apr 25 22:39:32 2004 @@ -193,6 +193,9 @@ /* Flag to indicate if addip is enabled. */ int addip_enable; + + /* Flag to indicate if PR-SCTP is enabled. */ + int prsctp_enable; } sctp_globals; #define sctp_rto_initial (sctp_globals.rto_initial) @@ -221,6 +224,7 @@ #define sctp_local_addr_list (sctp_globals.local_addr_list) #define sctp_local_addr_lock (sctp_globals.local_addr_lock) #define sctp_addip_enable (sctp_globals.addip_enable) +#define sctp_prsctp_enable (sctp_globals.prsctp_enable) /* SCTP Socket type: UDP or TCP style. */ typedef enum { @@ -317,6 +321,8 @@ /* This holds the originating address of the INIT packet. */ union sctp_addr peer_addr; + __u8 prsctp_capable; + /* This is a shim for my peer's INIT packet, followed by * a copy of the raw address list of the association. * The length of the raw address list is saved in the @@ -413,6 +419,13 @@ return stream->ssn[id]++; } +/* Skip over this ssn and all below. */ +static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id, + __u16 ssn) +{ + stream->ssn[id] = ssn+1; +} + /* * Pointers to address related SCTP functions. * (i.e. things that depend on the address family.) @@ -514,8 +527,8 @@ /* Did the messenge fail to send? */ int send_error; char send_failed; - /* Control whether fragments from this message can expire. */ - char can_expire; + /* Control whether chunks from this message can be abandoned. */ + char can_abandon; }; struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, @@ -527,8 +540,8 @@ void sctp_datamsg_free(struct sctp_datamsg *); void sctp_datamsg_track(struct sctp_chunk *); void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *); -void sctp_datamsg_fail(struct sctp_chunk *, int error); -int sctp_datamsg_expires(struct sctp_chunk *); +void sctp_chunk_fail(struct sctp_chunk *, int error); +int sctp_chunk_abandoned(struct sctp_chunk *); /* RFC2960 1.4 Key Terms @@ -583,6 +596,7 @@ struct sctp_cwrhdr *ecn_cwr_hdr; struct sctp_errhdr *err_hdr; struct sctp_addiphdr *addip_hdr; + struct sctp_fwdtsn_hdr *fwdtsn_hdr; } subh; __u8 *chunk_end; @@ -667,6 +681,9 @@ /* This contains the payload chunks. */ struct sk_buff_head chunks; + + /* This is the overhead of the sctp and ip headers. */ + size_t overhead; /* This is the total size of all chunks INCLUDING padding. */ size_t size; @@ -676,16 +693,6 @@ */ struct sctp_transport *transport; - /* Allow a callback for getting a high priority chunk - * bundled early into the packet (This is used for ECNE). - */ - sctp_packet_phandler_t *get_prepend_chunk; - - /* This packet should advertise ECN capability to the network - * via the ECT bit. - */ - char ecn_capable; - /* This packet contains a COOKIE-ECHO chunk. */ char has_cookie_echo; @@ -698,29 +705,21 @@ int malloced; }; -typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *); -typedef int (sctp_outq_ehandler_t)(struct sctp_outq *); -typedef struct sctp_packet *(sctp_outq_ohandler_init_t) - (struct sctp_packet *, - struct sctp_transport *, - __u16 sport, - __u16 dport); -typedef struct sctp_packet *(sctp_outq_ohandler_config_t) - (struct sctp_packet *, - __u32 vtag, - int ecn_capable, - sctp_packet_phandler_t *get_prepend_chunk); -typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *, - struct sctp_chunk *); -typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *); - -sctp_outq_ohandler_init_t sctp_packet_init; -sctp_outq_ohandler_config_t sctp_packet_config; -sctp_outq_ohandler_t sctp_packet_append_chunk; -sctp_outq_ohandler_t sctp_packet_transmit_chunk; -sctp_outq_ohandler_force_t sctp_packet_transmit; +struct sctp_packet *sctp_packet_init(struct sctp_packet *, + struct sctp_transport *, + __u16 sport, __u16 dport); +struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int); +sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *, + struct sctp_chunk *); +sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *, + struct sctp_chunk *); +int sctp_packet_transmit(struct sctp_packet *); void sctp_packet_free(struct sctp_packet *); +static inline int sctp_packet_empty(struct sctp_packet *packet) +{ + return (packet->size == packet->overhead); +} /* This represents a remote transport address. * For local transport addresses, we just use union sctp_addr. @@ -905,7 +904,7 @@ /* A flag which indicates the occurrence of a changeover */ char changeover_active; - /* A glag which indicates whether the change of primary is + /* A flag which indicates whether the change of primary is * the first switch to this destination address during an * active switch. */ @@ -1008,15 +1007,10 @@ */ struct list_head retransmit; - /* Call these functions to send chunks down to the next lower - * layer. This is always sctp_packet, but we separate the two - * structures to make testing simpler. - */ - sctp_outq_ohandler_init_t *init_output; - sctp_outq_ohandler_config_t *config_output; - sctp_outq_ohandler_t *append_output; - sctp_outq_ohandler_t *build_output; - sctp_outq_ohandler_force_t *force_output; + /* Put chunks on this list to save them for FWD TSN processing as + * they were abandoned. + */ + struct list_head abandoned; /* How many unackd bytes do we have in-flight? */ __u32 outstanding_bytes; @@ -1039,12 +1033,6 @@ int sctp_outq_flush(struct sctp_outq *, int); int sctp_outq_sack(struct sctp_outq *, struct sctp_sackhdr *); int sctp_outq_is_empty(const struct sctp_outq *); -int sctp_outq_set_output_handlers(struct sctp_outq *, - sctp_outq_ohandler_init_t init, - sctp_outq_ohandler_config_t config, - sctp_outq_ohandler_t append, - sctp_outq_ohandler_t build, - sctp_outq_ohandler_force_t force); void sctp_outq_restart(struct sctp_outq *); void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, @@ -1387,16 +1375,25 @@ struct sctp_tsnmap tsn_map; __u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)]; - /* Do we need to sack the peer? */ - __u8 sack_needed; + /* Ack State : This flag indicates if the next received + * : packet is to be responded to with a + * : SACK. This is initializedto 0. When a packet + * : is received it is incremented. If this value + * : reaches 2 or more, a SACK is sent and the + * : value is reset to 0. Note: This is used only + * : when no DATA chunks are received out of + * : order. When DATA chunks are out of order, + * : SACK's are not delayed (see Section 6). + */ + __u8 sack_needed; /* Do we need to sack the peer? */ + /* These are capabilities which our peer advertised. */ __u8 ecn_capable; /* Can peer do ECN? */ __u8 ipv4_address; /* Peer understands IPv4 addresses? */ __u8 ipv6_address; /* Peer understands IPv6 addresses? */ __u8 hostname_address;/* Peer understands DNS addresses? */ - - /* Does peer support ADDIP? */ - __u8 asconf_capable; + __u8 asconf_capable; /* Does peer support ADDIP? */ + __u8 prsctp_capable; /* Can peer do PR-SCTP? */ /* This mask is used to disable sending the ASCONF chunk * with specified parameter to peer. @@ -1489,6 +1486,9 @@ __u32 ctsn_ack_point; + /* PR-SCTP Advanced.Peer.Ack.Point */ + __u32 adv_peer_ack_point; + /* Highest TSN that is acknowledged by incoming SACKs. */ __u32 highest_sacked; @@ -1529,19 +1529,7 @@ /* The message size at which SCTP fragmentation will occur. */ __u32 frag_point; - /* Ack State : This flag indicates if the next received - * : packet is to be responded to with a - * : SACK. This is initializedto 0. When a packet - * : is received it is incremented. If this value - * : reaches 2 or more, a SACK is sent and the - * : value is reset to 0. Note: This is used only - * : when no DATA chunks are received out of - * : order. When DATA chunks are out of order, - * : SACK's are not delayed (see Section 6). - */ - /* Do we need to send an ack? - * When counters[SctpCounterAckState] is above 1 we do! - */ + /* Currently only one counter is used to count INIT errors. */ int counters[SCTP_NUMBER_COUNTERS]; /* Default send parameters. */ diff -Nru a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h --- a/include/net/sctp/tsnmap.h Sun Apr 25 22:39:31 2004 +++ b/include/net/sctp/tsnmap.h Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * * This file is part of the SCTP kernel reference Implementation @@ -37,6 +37,7 @@ * Jon Grimm * La Monte H.P. Yarroll * Karl Knutson + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -144,6 +145,9 @@ /* Mark this TSN as seen. */ void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn); + +/* Mark this TSN and all lower as seen. */ +void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn); /* Retrieve the Cumulative TSN ACK Point. */ static inline __u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map) diff -Nru a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h --- a/include/net/sctp/ulpqueue.h Sun Apr 25 22:39:31 2004 +++ b/include/net/sctp/ulpqueue.h Sun Apr 25 22:39:31 2004 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll @@ -38,6 +38,7 @@ * Written or modified by: * Jon Grimm * La Monte H.P. Yarroll + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -78,6 +79,9 @@ /* Clear the partial data delivery condition on this socket. */ int sctp_clear_pd(struct sock *sk); + +/* Skip over an SSN. */ +void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn); #endif /* __sctp_ulpqueue_h__ */ diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Sun Apr 25 22:39:31 2004 +++ b/include/net/tcp.h Sun Apr 25 22:39:31 2004 @@ -583,6 +583,11 @@ extern int sysctl_tcp_frto; extern int sysctl_tcp_low_latency; extern int sysctl_tcp_westwood; +extern int sysctl_tcp_vegas_cong_avoid; +extern int sysctl_tcp_vegas_alpha; +extern int sysctl_tcp_vegas_beta; +extern int sysctl_tcp_vegas_gamma; +extern int sysctl_tcp_nometrics_save; extern atomic_t tcp_memory_allocated; extern atomic_t tcp_sockets_allocated; @@ -1211,6 +1216,59 @@ return max(tp->snd_cwnd >> 1U, 2U); } +/* Stop taking Vegas samples for now. */ +#define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0) + +/* Is this TCP connection using Vegas (regardless of whether it is taking + * Vegas measurements at the current time)? + */ +#define tcp_is_vegas(__tp) ((__tp)->vegas.do_vegas) + +static inline void tcp_vegas_enable(struct tcp_opt *tp) +{ + /* There are several situations when we must "re-start" Vegas: + * + * o when a connection is established + * o after an RTO + * o after fast recovery + * o when we send a packet and there is no outstanding + * unacknowledged data (restarting an idle connection) + * + * In these circumstances we cannot do a Vegas calculation at the + * end of the first RTT, because any calculation we do is using + * stale info -- both the saved cwnd and congestion feedback are + * stale. + * + * Instead we must wait until the completion of an RTT during + * which we actually receive ACKs. + */ + + /* Begin taking Vegas samples next time we send something. */ + tp->vegas.doing_vegas_now = 1; + + /* Set the beginning of the next send window. */ + tp->vegas.beg_snd_nxt = tp->snd_nxt; + + tp->vegas.cntRTT = 0; + tp->vegas.minRTT = 0x7fffffff; +} + +/* Should we be taking Vegas samples right now? */ +#define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now) + +extern void tcp_vegas_init(struct tcp_opt *tp); + +static inline void tcp_set_ca_state(struct tcp_opt *tp, u8 ca_state) +{ + if (tcp_is_vegas(tp)) { + if (ca_state == TCP_CA_Open) + tcp_vegas_enable(tp); + else + tcp_vegas_disable(tp); + } + tp->ca_state = ca_state; +} + /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. * The exception is rate halving phase, when cwnd is decreasing towards * ssthresh. @@ -1270,7 +1328,7 @@ tp->prior_ssthresh = 0; if (tp->ca_state < TCP_CA_CWR) { __tcp_enter_cwr(tp); - tp->ca_state = TCP_CA_CWR; + tcp_set_ca_state(tp, TCP_CA_CWR); } } diff -Nru a/init/Kconfig b/init/Kconfig --- a/init/Kconfig Sun Apr 25 22:39:31 2004 +++ b/init/Kconfig Sun Apr 25 22:39:31 2004 @@ -149,7 +149,7 @@ config AUDITSYSCALL bool "Enable system-call auditing support" - depends on AUDIT && (X86 || PPC64) + depends on AUDIT && (X86 || PPC64 || ARCH_S390) default y if SECURITY_SELINUX default n help diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Sun Apr 25 22:39:31 2004 +++ b/init/main.c Sun Apr 25 22:39:31 2004 @@ -89,6 +89,7 @@ extern void free_initmem(void); extern void populate_rootfs(void); extern void driver_init(void); +extern void prepare_namespace(void); #ifdef CONFIG_TC extern void tc_init(void); @@ -471,7 +472,6 @@ signals_init(); /* rootfs populating might need page-writeback */ page_writeback_init(); - populate_rootfs(); #ifdef CONFIG_PROC_FS proc_root_init(); #endif @@ -577,8 +577,6 @@ execve(init_filename, argv_init, envp_init); } -extern void prepare_namespace(void); - static int init(void * unused) { lock_kernel(); @@ -600,14 +598,15 @@ smp_init(); do_basic_setup(); - /* - * check if there is an early userspace init, if yes - * let it do all the work - */ - if (sys_access("/init", 0) == 0) - execute_command = "/init"; - else - prepare_namespace(); + populate_rootfs(); + /* + * check if there is an early userspace init. If yes, let it do all + * the work + */ + if (sys_access("/init", 0) == 0) + execute_command = "/init"; + else + prepare_namespace(); /* * Ok, we have completed the initial bootup, and diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c --- a/mm/page-writeback.c Sun Apr 25 22:39:31 2004 +++ b/mm/page-writeback.c Sun Apr 25 22:39:31 2004 @@ -580,6 +580,18 @@ EXPORT_SYMBOL(__set_page_dirty_nobuffers); /* + * When a writepage implementation decides that it doesn't want to write this + * page for some reason, it should redirty the locked page via + * redirty_page_for_writepage() and it should then unlock the page and return 0 + */ +int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page) +{ + wbc->pages_skipped++; + return __set_page_dirty_nobuffers(page); +} +EXPORT_SYMBOL(redirty_page_for_writepage); + +/* * If the mapping doesn't provide a set_page_dirty a_op, then * just fall through and assume that it wants buffer_heads. */ diff -Nru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c --- a/net/ipv4/ip_sockglue.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/ip_sockglue.c Sun Apr 25 22:39:31 2004 @@ -800,7 +800,7 @@ goto mc_msf_out; } if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { - err = EINVAL; + err = -EINVAL; goto mc_msf_out; } msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); diff -Nru a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c --- a/net/ipv4/netfilter/ipt_MASQUERADE.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c Sun Apr 25 22:39:31 2004 @@ -116,6 +116,7 @@ if (net_ratelimit()) printk("MASQUERADE:" " Route sent us somewhere else.\n"); + ip_rt_put(rt); return NF_DROP; } } diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c --- a/net/ipv4/sysctl_net_ipv4.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/sysctl_net_ipv4.c Sun Apr 25 22:39:31 2004 @@ -594,9 +594,49 @@ .strategy = &sysctl_jiffies }, { + .ctl_name = NET_TCP_NO_METRICS_SAVE, + .procname = "tcp_no_metrics_save", + .data = &sysctl_tcp_nometrics_save, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = NET_TCP_WESTWOOD, .procname = "tcp_westwood", .data = &sysctl_tcp_westwood, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_TCP_VEGAS, + .procname = "tcp_vegas_cong_avoid", + .data = &sysctl_tcp_vegas_cong_avoid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_TCP_VEGAS_ALPHA, + .procname = "tcp_vegas_alpha", + .data = &sysctl_tcp_vegas_alpha, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_TCP_VEGAS_BETA, + .procname = "tcp_vegas_beta", + .data = &sysctl_tcp_vegas_beta, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_TCP_VEGAS_GAMMA, + .procname = "tcp_vegas_gamma", + .data = &sysctl_tcp_vegas_gamma, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/tcp.c Sun Apr 25 22:39:31 2004 @@ -2158,7 +2158,7 @@ tp->packets_out = 0; tp->snd_ssthresh = 0x7fffffff; tp->snd_cwnd_cnt = 0; - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); tcp_clear_retrans(tp); tcp_delack_init(tp); tp->send_head = NULL; diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/tcp_input.c Sun Apr 25 22:39:31 2004 @@ -86,7 +86,17 @@ int sysctl_tcp_rfc1337; int sysctl_tcp_max_orphans = NR_FILE; int sysctl_tcp_frto; +int sysctl_tcp_nometrics_save; int sysctl_tcp_westwood; +int sysctl_tcp_vegas_cong_avoid; + +/* Default values of the Vegas variables, in fixed-point representation + * with V_PARAM_SHIFT bits to the right of the binary point. + */ +#define V_PARAM_SHIFT 1 +int sysctl_tcp_vegas_alpha = 1<vegas.do_vegas = 1; + tp->vegas.baseRTT = 0x7fffffff; + tcp_vegas_enable(tp); + } else + tcp_vegas_disable(tp); +} + +/* Do RTT sampling needed for Vegas. + * Basically we: + * o min-filter RTT samples from within an RTT to get the current + * propagation delay + queuing delay (we are min-filtering to try to + * avoid the effects of delayed ACKs) + * o min-filter RTT samples from a much longer window (forever for now) + * to find the propagation delay (baseRTT) + */ +static inline void vegas_rtt_calc(struct tcp_opt *tp, __u32 rtt) +{ + __u32 vrtt = rtt + 1; /* Never allow zero rtt or baseRTT */ + + /* Filter to find propagation delay: */ + if (vrtt < tp->vegas.baseRTT) + tp->vegas.baseRTT = vrtt; + + /* Find the min RTT during the last RTT to find + * the current prop. delay + queuing delay: + */ + tp->vegas.minRTT = min(tp->vegas.minRTT, vrtt); + tp->vegas.cntRTT++; +} + /* Called to compute a smoothed rtt estimate. The data fed to this * routine either comes from timestamps, or from segments that were * known _not_ to have been retransmitted [see Karn/Partridge @@ -416,6 +462,9 @@ { long m = mrtt; /* RTT */ + if (tcp_vegas_enabled(tp)) + vegas_rtt_calc(tp, mrtt); + /* The following amusing code comes from Jacobson's * article in SIGCOMM '88. Note that rtt and mdev * are scaled versions of rtt and mean deviation. @@ -518,6 +567,9 @@ struct tcp_opt *tp = tcp_sk(sk); struct dst_entry *dst = __sk_dst_get(sk); + if (sysctl_tcp_nometrics_save) + return; + dst_confirm(dst); if (dst && (dst->flags&DST_HOST)) { @@ -999,7 +1051,7 @@ } tcp_sync_left_out(tp); - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); tp->frto_highmark = tp->snd_nxt; } @@ -1045,7 +1097,7 @@ tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering); - tp->ca_state = TCP_CA_Loss; + tcp_set_ca_state(tp, TCP_CA_Loss); tp->high_seq = tp->frto_highmark; TCP_ECN_queue_cwr(tp); } @@ -1108,7 +1160,7 @@ tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering); - tp->ca_state = TCP_CA_Loss; + tcp_set_ca_state(tp, TCP_CA_Loss); tp->high_seq = tp->snd_nxt; TCP_ECN_queue_cwr(tp); } @@ -1485,7 +1537,7 @@ tcp_moderate_cwnd(tp); return 1; } - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); return 0; } @@ -1545,7 +1597,7 @@ tp->retransmits = 0; tp->undo_marker = 0; if (!IsReno(tp)) - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); return 1; } return 0; @@ -1579,7 +1631,7 @@ state = TCP_CA_Disorder; if (tp->ca_state != state) { - tp->ca_state = state; + tcp_set_ca_state(tp, state); tp->high_seq = tp->snd_nxt; } tcp_moderate_cwnd(tp); @@ -1654,7 +1706,7 @@ * is ACKed for CWR bit to reach receiver. */ if (tp->snd_una != tp->high_seq) { tcp_complete_cwr(tp); - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); } break; @@ -1665,7 +1717,7 @@ * catching for all duplicate ACKs. */ IsReno(tp) || tp->snd_una != tp->high_seq) { tp->undo_marker = 0; - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); } break; @@ -1739,7 +1791,7 @@ } tp->snd_cwnd_cnt = 0; - tp->ca_state = TCP_CA_Recovery; + tcp_set_ca_state(tp, TCP_CA_Recovery); } if (is_dupack || tcp_head_timedout(sk, tp)) @@ -1806,11 +1858,10 @@ else if (seq_rtt >= 0) tcp_ack_no_tstamp(tp, seq_rtt, flag); } - /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ -static __inline__ void tcp_cong_avoid(struct tcp_opt *tp) +static __inline__ void reno_cong_avoid(struct tcp_opt *tp) { if (tp->snd_cwnd <= tp->snd_ssthresh) { /* In "safe" area, increase. */ @@ -1830,6 +1881,236 @@ tp->snd_cwnd_stamp = tcp_time_stamp; } +/* This is based on the congestion detection/avoidance scheme described in + * Lawrence S. Brakmo and Larry L. Peterson. + * "TCP Vegas: End to end congestion avoidance on a global internet." + * IEEE Journal on Selected Areas in Communication, 13(8):1465--1480, + * October 1995. Available from: + * ftp://ftp.cs.arizona.edu/xkernel/Papers/jsac.ps + * + * See http://www.cs.arizona.edu/xkernel/ for their implementation. + * The main aspects that distinguish this implementation from the + * Arizona Vegas implementation are: + * o We do not change the loss detection or recovery mechanisms of + * Linux in any way. Linux already recovers from losses quite well, + * using fine-grained timers, NewReno, and FACK. + * o To avoid the performance penalty imposed by increasing cwnd + * only every-other RTT during slow start, we increase during + * every RTT during slow start, just like Reno. + * o Largely to allow continuous cwnd growth during slow start, + * we use the rate at which ACKs come back as the "actual" + * rate, rather than the rate at which data is sent. + * o To speed convergence to the right rate, we set the cwnd + * to achieve the right ("actual") rate when we exit slow start. + * o To filter out the noise caused by delayed ACKs, we use the + * minimum RTT sample observed during the last RTT to calculate + * the actual rate. + * o When the sender re-starts from idle, it waits until it has + * received ACKs for an entire flight of new data before making + * a cwnd adjustment decision. The original Vegas implementation + * assumed senders never went idle. + */ +static void vegas_cong_avoid(struct tcp_opt *tp, u32 ack, u32 seq_rtt) +{ + /* The key players are v_beg_snd_una and v_beg_snd_nxt. + * + * These are so named because they represent the approximate values + * of snd_una and snd_nxt at the beginning of the current RTT. More + * precisely, they represent the amount of data sent during the RTT. + * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt, + * we will calculate that (v_beg_snd_nxt - v_beg_snd_una) outstanding + * bytes of data have been ACKed during the course of the RTT, giving + * an "actual" rate of: + * + * (v_beg_snd_nxt - v_beg_snd_una) / (rtt duration) + * + * Unfortunately, v_beg_snd_una is not exactly equal to snd_una, + * because delayed ACKs can cover more than one segment, so they + * don't line up nicely with the boundaries of RTTs. + * + * Another unfortunate fact of life is that delayed ACKs delay the + * advance of the left edge of our send window, so that the number + * of bytes we send in an RTT is often less than our cwnd will allow. + * So we keep track of our cwnd separately, in v_beg_snd_cwnd. + */ + + if (after(ack, tp->vegas.beg_snd_nxt)) { + /* Do the Vegas once-per-RTT cwnd adjustment. */ + u32 old_wnd, old_snd_cwnd; + + + /* Here old_wnd is essentially the window of data that was + * sent during the previous RTT, and has all + * been acknowledged in the course of the RTT that ended + * with the ACK we just received. Likewise, old_snd_cwnd + * is the cwnd during the previous RTT. + */ + old_wnd = (tp->vegas.beg_snd_nxt - tp->vegas.beg_snd_una) / + tp->mss_cache; + old_snd_cwnd = tp->vegas.beg_snd_cwnd; + + /* Save the extent of the current window so we can use this + * at the end of the next RTT. + */ + tp->vegas.beg_snd_una = tp->vegas.beg_snd_nxt; + tp->vegas.beg_snd_nxt = tp->snd_nxt; + tp->vegas.beg_snd_cwnd = tp->snd_cwnd; + + /* Take into account the current RTT sample too, to + * decrease the impact of delayed acks. This double counts + * this sample since we count it for the next window as well, + * but that's not too awful, since we're taking the min, + * rather than averaging. + */ + vegas_rtt_calc(tp, seq_rtt); + + /* We do the Vegas calculations only if we got enough RTT + * samples that we can be reasonably sure that we got + * at least one RTT sample that wasn't from a delayed ACK. + * If we only had 2 samples total, + * then that means we're getting only 1 ACK per RTT, which + * means they're almost certainly delayed ACKs. + * If we have 3 samples, we should be OK. + */ + + if (tp->vegas.cntRTT <= 2) { + /* We don't have enough RTT samples to do the Vegas + * calculation, so we'll behave like Reno. + */ + if (tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd++; + } else { + u32 rtt, target_cwnd, diff; + + /* We have enough RTT samples, so, using the Vegas + * algorithm, we determine if we should increase or + * decrease cwnd, and by how much. + */ + + /* Pluck out the RTT we are using for the Vegas + * calculations. This is the min RTT seen during the + * last RTT. Taking the min filters out the effects + * of delayed ACKs, at the cost of noticing congestion + * a bit later. + */ + rtt = tp->vegas.minRTT; + + /* Calculate the cwnd we should have, if we weren't + * going too fast. + * + * This is: + * (actual rate in segments) * baseRTT + * We keep it as a fixed point number with + * V_PARAM_SHIFT bits to the right of the binary point. + */ + target_cwnd = ((old_wnd * tp->vegas.baseRTT) + << V_PARAM_SHIFT) / rtt; + + /* Calculate the difference between the window we had, + * and the window we would like to have. This quantity + * is the "Diff" from the Arizona Vegas papers. + * + * Again, this is a fixed point number with + * V_PARAM_SHIFT bits to the right of the binary + * point. + */ + diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd; + + if (tp->snd_cwnd < tp->snd_ssthresh) { + /* Slow start. */ + if (diff > sysctl_tcp_vegas_gamma) { + /* Going too fast. Time to slow down + * and switch to congestion avoidance. + */ + tp->snd_ssthresh = 2; + + /* Set cwnd to match the actual rate + * exactly: + * cwnd = (actual rate) * baseRTT + * Then we add 1 because the integer + * truncation robs us of full link + * utilization. + */ + tp->snd_cwnd = min(tp->snd_cwnd, + (target_cwnd >> + V_PARAM_SHIFT)+1); + + } + } else { + /* Congestion avoidance. */ + u32 next_snd_cwnd; + + /* Figure out where we would like cwnd + * to be. + */ + if (diff > sysctl_tcp_vegas_beta) { + /* The old window was too fast, so + * we slow down. + */ + next_snd_cwnd = old_snd_cwnd - 1; + } else if (diff < sysctl_tcp_vegas_alpha) { + /* We don't have enough extra packets + * in the network, so speed up. + */ + next_snd_cwnd = old_snd_cwnd + 1; + } else { + /* Sending just as fast as we + * should be. + */ + next_snd_cwnd = old_snd_cwnd; + } + + /* Adjust cwnd upward or downward, toward the + * desired value. + */ + if (next_snd_cwnd > tp->snd_cwnd) + tp->snd_cwnd++; + else if (next_snd_cwnd < tp->snd_cwnd) + tp->snd_cwnd--; + } + } + + /* Wipe the slate clean for the next RTT. */ + tp->vegas.cntRTT = 0; + tp->vegas.minRTT = 0x7fffffff; + } + + /* The following code is executed for every ack we receive, + * except for conditions checked in should_advance_cwnd() + * before the call to tcp_cong_avoid(). Mainly this means that + * we only execute this code if the ack actually acked some + * data. + */ + + /* If we are in slow start, increase our cwnd in response to this ACK. + * (If we are not in slow start then we are in congestion avoidance, + * and adjust our congestion window only once per RTT. See the code + * above.) + */ + if (tp->snd_cwnd <= tp->snd_ssthresh) + tp->snd_cwnd++; + + /* to keep cwnd from growing without bound */ + tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp); + + /* Make sure that we are never so timid as to reduce our cwnd below + * 2 MSS. + * + * Going below 2 MSS would risk huge delayed ACKs from our receiver. + */ + tp->snd_cwnd = max(tp->snd_cwnd, 2U); + + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +static inline void tcp_cong_avoid(struct tcp_opt *tp, u32 ack, u32 seq_rtt) +{ + if (tcp_vegas_enabled(tp)) + vegas_cong_avoid(tp, ack, seq_rtt); + else + reno_cong_avoid(tp); +} + /* Restart timer after forward progress on connection. * RFC2988 recommends to restart timer to now+rto. */ @@ -1844,7 +2125,7 @@ } /* Remove acknowledged frames from the retransmission queue. */ -static int tcp_clean_rtx_queue(struct sock *sk) +static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb; @@ -1930,6 +2211,7 @@ } } #endif + *seq_rtt_p = seq_rtt; return acked; } @@ -2298,6 +2580,7 @@ u32 ack_seq = TCP_SKB_CB(skb)->seq; u32 ack = TCP_SKB_CB(skb)->ack_seq; u32 prior_in_flight; + s32 seq_rtt; int prior_packets; /* If the ack is newer than sent or older than previous acks @@ -2349,7 +2632,7 @@ prior_in_flight = tcp_packets_in_flight(tp); /* See if we can take anything off of the retransmit queue. */ - flag |= tcp_clean_rtx_queue(sk); + flag |= tcp_clean_rtx_queue(sk, &seq_rtt); if (tp->frto_counter) tcp_process_frto(sk, prior_snd_una); @@ -2357,13 +2640,14 @@ if (tcp_ack_is_dubious(tp, flag)) { /* Advanve CWND, if state allows this. */ if ((flag & FLAG_DATA_ACKED) && - prior_in_flight >= tp->snd_cwnd && + (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd) && tcp_may_raise_cwnd(tp, flag)) - tcp_cong_avoid(tp); + tcp_cong_avoid(tp, ack, seq_rtt); tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); } else { - if ((flag & FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd) - tcp_cong_avoid(tp); + if ((flag & FLAG_DATA_ACKED) && + (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd)) + tcp_cong_avoid(tp, ack, seq_rtt); } if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP)) diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/tcp_minisocks.c Sun Apr 25 22:39:31 2004 @@ -769,7 +769,7 @@ newtp->frto_counter = 0; newtp->frto_highmark = 0; - newtp->ca_state = TCP_CA_Open; + tcp_set_ca_state(newtp, TCP_CA_Open); tcp_init_xmit_timers(newsk); skb_queue_head_init(&newtp->out_of_order_queue); newtp->send_head = NULL; @@ -841,6 +841,7 @@ if (newtp->ecn_flags&TCP_ECN_OK) newsk->sk_no_largesend = 1; + tcp_vegas_init(newtp); TCP_INC_STATS_BH(TcpPassiveOpens); } return newsk; diff -Nru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c --- a/net/ipv4/tcp_output.c Sun Apr 25 22:39:31 2004 +++ b/net/ipv4/tcp_output.c Sun Apr 25 22:39:31 2004 @@ -106,6 +106,9 @@ u32 restart_cwnd = tcp_init_cwnd(tp, dst); u32 cwnd = tp->snd_cwnd; + if (tcp_is_vegas(tp)) + tcp_vegas_enable(tp); + tp->snd_ssthresh = tcp_current_ssthresh(tp); restart_cwnd = min(restart_cwnd, cwnd); @@ -225,6 +228,19 @@ tcp_header_size += (TCPOLEN_SACK_BASE_ALIGNED + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); } + + /* + * If the connection is idle and we are restarting, + * then we don't want to do any Vegas calculations + * until we get fresh RTT samples. So when we + * restart, we reset our Vegas state to a clean + * slate. After we get acks for this flight of + * packets, _then_ we can make Vegas calculations + * again. + */ + if (tcp_is_vegas(tp) && tcp_packets_in_flight(tp) == 0) + tcp_vegas_enable(tp); + th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; skb_set_owner_w(skb, sk); @@ -869,7 +885,7 @@ tp->snd_ssthresh = tcp_current_ssthresh(tp); tp->prior_ssthresh = 0; tp->undo_marker = 0; - tp->ca_state = TCP_CA_Loss; + tcp_set_ca_state(tp, TCP_CA_Loss); } tcp_xmit_retransmit_queue(sk); } @@ -1268,6 +1284,7 @@ tp->window_clamp = dst_metric(dst, RTAX_WINDOW); tp->advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(sk); + tcp_vegas_init(tp); tcp_select_initial_window(tcp_full_space(sk), tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), @@ -1318,6 +1335,7 @@ TCP_SKB_CB(buff)->end_seq = tp->write_seq; tp->snd_nxt = tp->write_seq; tp->pushed_seq = tp->write_seq; + tcp_vegas_init(tp); /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c --- a/net/sctp/associola.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/associola.c Sun Apr 25 22:39:31 2004 @@ -210,6 +210,7 @@ asoc->next_tsn = asoc->c.initial_tsn; asoc->ctsn_ack_point = asoc->next_tsn - 1; + asoc->adv_peer_ack_point = asoc->ctsn_ack_point; asoc->highest_sacked = asoc->ctsn_ack_point; asoc->last_cwr_tsn = asoc->ctsn_ack_point; asoc->unack_data = 0; @@ -261,12 +262,6 @@ /* Create an output queue. */ sctp_outq_init(asoc, &asoc->outqueue); - sctp_outq_set_output_handlers(&asoc->outqueue, - sctp_packet_init, - sctp_packet_config, - sctp_packet_append_chunk, - sctp_packet_transmit_chunk, - sctp_packet_transmit); if (!sctp_ulpq_init(&asoc->ulpq, asoc)) goto fail_init; @@ -482,10 +477,8 @@ /* The asoc->peer.port might not be meaningful yet, but * initialize the packet structure anyway. */ - (asoc->outqueue.init_output)(&peer->packet, - peer, - asoc->base.bind_addr.port, - asoc->peer.port); + sctp_packet_init(&peer->packet, peer, asoc->base.bind_addr.port, + asoc->peer.port); /* 7.2.1 Slow-Start * @@ -967,6 +960,7 @@ asoc->next_tsn = new->next_tsn; asoc->ctsn_ack_point = new->ctsn_ack_point; + asoc->adv_peer_ack_point = new->adv_peer_ack_point; /* Reinitialize SSN for both local streams * and peer's streams. @@ -975,6 +969,7 @@ } else { asoc->ctsn_ack_point = asoc->next_tsn - 1; + asoc->adv_peer_ack_point = asoc->ctsn_ack_point; if (!asoc->ssnmap) { /* Move the ssnmap. */ asoc->ssnmap = new->ssnmap; diff -Nru a/net/sctp/chunk.c b/net/sctp/chunk.c --- a/net/sctp/chunk.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/chunk.c Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * Copyright (c) 2003 International Business Machines Corp. + * (C) Copyright IBM Corp. 2003, 2004 * * This file is part of the SCTP kernel reference Implementation * @@ -31,6 +31,7 @@ * * Written or modified by: * Jon Grimm + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -55,7 +56,8 @@ atomic_set(&msg->refcnt, 1); msg->send_failed = 0; msg->send_error = 0; - msg->can_expire = 0; + msg->can_abandon = 0; + msg->expires_at = 0; INIT_LIST_HEAD(&msg->chunks); } @@ -182,34 +184,17 @@ * have the same expiration. */ if (sinfo->sinfo_timetolive) { - struct timeval tv; - __u32 ttl = sinfo->sinfo_timetolive; - /* sinfo_timetolive is in milliseconds */ - tv.tv_sec = ttl / 1000; - tv.tv_usec = ttl % 1000 * 1000; - msg->expires_at = jiffies + timeval_to_jiffies(&tv); - msg->can_expire = 1; + msg->expires_at = jiffies + + MSECS_TO_JIFFIES(sinfo->sinfo_timetolive); + msg->can_abandon = 1; + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n", + __FUNCTION__, msg, msg->expires_at, jiffies); } - /* What is a reasonable fragmentation point right now? */ - max = asoc->pmtu; - if (max < SCTP_MIN_PMTU) - max = SCTP_MIN_PMTU; - max -= SCTP_IP_OVERHEAD; - - /* Make sure not beyond maximum chunk size. */ - if (max > SCTP_MAX_CHUNK_LEN) - max = SCTP_MAX_CHUNK_LEN; + max = asoc->frag_point; - /* Subtract out the overhead of a data chunk header. */ - max -= sizeof(struct sctp_data_chunk); whole = 0; - - /* If user has specified smaller fragmentation, make it so. */ - if (sctp_sk(asoc->base.sk)->user_frag) - max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag); - first_len = max; /* Encourage Cookie-ECHO bundling. */ @@ -303,14 +288,11 @@ } /* Check whether this message has expired. */ -int sctp_datamsg_expires(struct sctp_chunk *chunk) +int sctp_chunk_abandoned(struct sctp_chunk *chunk) { struct sctp_datamsg *msg = chunk->msg; - /* FIXME: When PR-SCTP is supported we can make this - * check more lenient. - */ - if (!msg->can_expire) + if (!msg->can_abandon) return 0; if (time_after(jiffies, msg->expires_at)) @@ -320,7 +302,7 @@ } /* This chunk (and consequently entire message) has failed in its sending. */ -void sctp_datamsg_fail(struct sctp_chunk *chunk, int error) +void sctp_chunk_fail(struct sctp_chunk *chunk, int error) { chunk->msg->send_failed = 1; chunk->msg->send_error = error; diff -Nru a/net/sctp/debug.c b/net/sctp/debug.c --- a/net/sctp/debug.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/debug.c Sun Apr 25 22:39:31 2004 @@ -1,8 +1,8 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -43,6 +43,7 @@ * Xingang Guo * Jon Grimm * Daisy Chang + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -87,6 +88,9 @@ case SCTP_CID_ASCONF_ACK: return "ASCONF_ACK"; + + case SCTP_CID_FWD_TSN: + return "FWD_TSN"; default: return "unknown chunk"; diff -Nru a/net/sctp/output.c b/net/sctp/output.c --- a/net/sctp/output.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/output.c Sun Apr 25 22:39:31 2004 @@ -62,29 +62,35 @@ #include /* Forward declarations for private helpers. */ -static void sctp_packet_reset(struct sctp_packet *packet); static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, struct sctp_chunk *chunk); /* Config a packet. - * This appears to be a followup set of initializations.) + * This appears to be a followup set of initializations. */ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, - __u32 vtag, int ecn_capable, - sctp_packet_phandler_t *prepend_handler) + __u32 vtag, int ecn_capable) { - int packet_empty = (packet->size == SCTP_IP_OVERHEAD); + struct sctp_chunk *chunk = NULL; + + SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__, + packet, vtag); packet->vtag = vtag; - packet->ecn_capable = ecn_capable; - packet->get_prepend_chunk = prepend_handler; packet->has_cookie_echo = 0; packet->has_sack = 0; packet->ipfragok = 0; - /* We might need to call the prepend_handler right away. */ - if (packet_empty) - sctp_packet_reset(packet); + if (ecn_capable && sctp_packet_empty(packet)) { + chunk = sctp_get_ecne_prepend(packet->transport->asoc); + + /* If there a is a prepend chunk stick it on the list before + * any other chunks get appended. + */ + if (chunk) + sctp_packet_append_chunk(packet, chunk); + } + return packet; } @@ -93,19 +99,30 @@ struct sctp_transport *transport, __u16 sport, __u16 dport) { + struct sctp_association *asoc = transport->asoc; + size_t overhead; + + SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__, + packet, transport); + packet->transport = transport; packet->source_port = sport; packet->destination_port = dport; skb_queue_head_init(&packet->chunks); - packet->size = SCTP_IP_OVERHEAD; + if (asoc) { + struct sctp_opt *sp = sctp_sk(asoc->base.sk); + overhead = sp->pf->af->net_header_len; + } else { + overhead = sizeof(struct ipv6hdr); + } + overhead += sizeof(struct sctphdr); + packet->overhead = overhead; + packet->size = overhead; packet->vtag = 0; - packet->ecn_capable = 0; - packet->get_prepend_chunk = NULL; packet->has_cookie_echo = 0; packet->has_sack = 0; packet->ipfragok = 0; packet->malloced = 0; - sctp_packet_reset(packet); return packet; } @@ -114,6 +131,8 @@ { struct sctp_chunk *chunk; + SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) sctp_chunk_free(chunk); @@ -134,6 +153,9 @@ sctp_xmit_t retval; int error = 0; + SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, + packet, chunk); + switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { case SCTP_XMIT_PMTU_FULL: if (!packet->has_cookie_echo) { @@ -148,7 +170,6 @@ } break; - case SCTP_XMIT_MUST_FRAG: case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_OK: case SCTP_XMIT_NAGLE_DELAY: @@ -201,6 +222,9 @@ size_t pmtu; int too_big; + SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet, + chunk); + retval = sctp_packet_bundle_sack(packet, chunk); psize = packet->size; @@ -215,17 +239,14 @@ /* Decide if we need to fragment or resubmit later. */ if (too_big) { - int packet_empty = (packet->size == SCTP_IP_OVERHEAD); - /* Both control chunks and data chunks with TSNs are * non-fragmentable. */ - if (packet_empty || !sctp_chunk_is_data(chunk)) { + if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk)) { /* We no longer do re-fragmentation. * Just fragment at the IP layer, if we * actually hit this condition */ - packet->ipfragok = 1; goto append; @@ -233,9 +254,6 @@ retval = SCTP_XMIT_PMTU_FULL; goto finish; } - } else { - /* The chunk fits in the packet. */ - goto append; } append: @@ -260,6 +278,7 @@ /* It is OK to send this chunk. */ __skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); packet->size += chunk_len; + chunk->transport = packet->transport; finish: return retval; } @@ -283,6 +302,8 @@ __u8 has_data = 0; struct dst_entry *dst; + SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); + /* Do NOT generate a chunkless packet. */ chunk = (struct sctp_chunk *)skb_peek(&packet->chunks); if (unlikely(!chunk)) @@ -297,7 +318,7 @@ goto nomem; /* Make sure the outbound skb has enough header room reserved. */ - skb_reserve(nskb, SCTP_IP_OVERHEAD); + skb_reserve(nskb, packet->overhead); /* Set the owning socket so that we know where to get the * destination IP address. @@ -471,7 +492,7 @@ (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok); out: - packet->size = SCTP_IP_OVERHEAD; + packet->size = packet->overhead; return err; no_route: kfree_skb(nskb); @@ -497,7 +518,6 @@ goto out; nomem: err = -ENOMEM; - printk("%s alloc_skb failed.\n", __FUNCTION__); goto err; } @@ -505,25 +525,6 @@ * 2nd Level Abstractions ********************************************************************/ -/* - * This private function resets the packet to a fresh state. - */ -static void sctp_packet_reset(struct sctp_packet *packet) -{ - struct sctp_chunk *chunk = NULL; - - packet->size = SCTP_IP_OVERHEAD; - - if (packet->get_prepend_chunk) - chunk = packet->get_prepend_chunk(packet->transport->asoc); - - /* If there a is a prepend chunk stick it on the list before - * any other chunks get appended. - */ - if (chunk) - sctp_packet_append_chunk(packet, chunk); -} - /* This private function handles the specifics of appending DATA chunks. */ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, struct sctp_chunk *chunk) @@ -609,7 +610,7 @@ * if any previously transmitted data on the connection remains * unacknowledged. */ - if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && + if (!sp->nodelay && sctp_packet_empty(packet) && q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { unsigned len = datasize + q->out_qlen; @@ -617,7 +618,7 @@ * data will fit or delay in hopes of bundling a full * sized packet. */ - if (len < asoc->pmtu - SCTP_IP_OVERHEAD) { + if (len < asoc->pmtu - packet->overhead) { retval = SCTP_XMIT_NAGLE_DELAY; goto finish; } @@ -637,7 +638,8 @@ asoc->peer.rwnd = rwnd; /* Has been accepted for transmission. */ - chunk->msg->can_expire = 0; + if (!asoc->peer.prsctp_capable) + chunk->msg->can_abandon = 0; finish: return retval; diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c --- a/net/sctp/outqueue.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/outqueue.c Sun Apr 25 22:39:31 2004 @@ -1,8 +1,8 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 Intel Corp. - * Copyright (c) 2001-2003 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -69,6 +69,8 @@ __u32 highest_new_tsn, int count_of_newacks); +static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn); + /* Add data to the front of the queue. */ static inline void sctp_outq_head_data(struct sctp_outq *q, struct sctp_chunk *ch) @@ -222,12 +224,7 @@ skb_queue_head_init(&q->control); INIT_LIST_HEAD(&q->retransmit); INIT_LIST_HEAD(&q->sacked); - - q->init_output = NULL; - q->config_output = NULL; - q->append_output = NULL; - q->build_output = NULL; - q->force_output = NULL; + INIT_LIST_HEAD(&q->abandoned); q->outstanding_bytes = 0; q->empty = 1; @@ -252,7 +249,7 @@ chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); /* Mark as part of a failed message. */ - sctp_datamsg_fail(chunk, q->error); + sctp_chunk_fail(chunk, q->error); sctp_chunk_free(chunk); } } @@ -262,7 +259,7 @@ list_del_init(lchunk); chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); - sctp_datamsg_fail(chunk, q->error); + sctp_chunk_fail(chunk, q->error); sctp_chunk_free(chunk); } @@ -271,7 +268,16 @@ list_del_init(lchunk); chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); - sctp_datamsg_fail(chunk, q->error); + sctp_chunk_fail(chunk, q->error); + sctp_chunk_free(chunk); + } + + /* Throw away any chunks that are in the abandoned queue. */ + list_for_each_safe(lchunk, temp, &q->abandoned) { + list_del_init(lchunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_chunk_fail(chunk, q->error); sctp_chunk_free(chunk); } @@ -279,7 +285,7 @@ while ((chunk = sctp_outq_dequeue_data(q))) { /* Mark as send failure. */ - sctp_datamsg_fail(chunk, q->error); + sctp_chunk_fail(chunk, q->error); sctp_chunk_free(chunk); } @@ -363,32 +369,30 @@ return error; } -/* Insert a chunk into the retransmit queue. Chunks on the retransmit - * queue are kept in order, based on the TSNs. +/* Insert a chunk into the sorted list based on the TSNs. The retransmit list + * and the abandoned list are in ascending order. */ -void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q) +void sctp_insert_list(struct list_head *head, struct list_head *new) { - struct list_head *rlchunk; - struct sctp_chunk *tchunk, *rchunk; - __u32 ttsn, rtsn; + struct list_head *pos; + struct sctp_chunk *nchunk, *lchunk; + __u32 ntsn, ltsn; int done = 0; - tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list); - ttsn = ntohl(tchunk->subh.data_hdr->tsn); + nchunk = list_entry(new, struct sctp_chunk, transmitted_list); + ntsn = ntohl(nchunk->subh.data_hdr->tsn); - list_for_each(rlchunk, &q->retransmit) { - rchunk = list_entry(rlchunk, struct sctp_chunk, - transmitted_list); - rtsn = ntohl(rchunk->subh.data_hdr->tsn); - if (TSN_lt(ttsn, rtsn)) { - list_add(tlchunk, rlchunk->prev); + list_for_each(pos, head) { + lchunk = list_entry(pos, struct sctp_chunk, transmitted_list); + ltsn = ntohl(lchunk->subh.data_hdr->tsn); + if (TSN_lt(ntsn, ltsn)) { + list_add(new, pos->prev); done = 1; break; } } - if (!done) { - list_add_tail(tlchunk, &q->retransmit); - } + if (!done) + list_add_tail(new, head); } /* Mark all the eligible packets on a transport for retransmission. */ @@ -404,6 +408,13 @@ chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); + /* If the chunk is abandoned, move it to abandoned list. */ + if (sctp_chunk_abandoned(chunk)) { + list_del_init(lchunk); + sctp_insert_list(&q->abandoned, lchunk); + continue; + } + /* If we are doing retransmission due to a fast retransmit, * only the chunk's that are marked for fast retransmit * should be added to the retransmit queue. If we are doing @@ -444,10 +455,10 @@ } /* Move the chunk to the retransmit queue. The chunks - * on the retransmit queue is always kept in order. + * on the retransmit queue are always kept in order. */ list_del_init(lchunk); - sctp_retransmit_insert(lchunk, q); + sctp_insert_list(&q->retransmit, lchunk); } } @@ -490,6 +501,12 @@ sctp_retransmit_mark(q, transport, fast_retransmit); + /* PR-SCTP A5) Any time the T3-rtx timer expires, on any destination, + * the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by + * following the procedures outlined in C1 - C5. + */ + sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point); + error = sctp_outq_flush(q, /* rtx_timeout */ 1); if (error) @@ -552,12 +569,12 @@ } /* Attempt to append this chunk to the packet. */ - status = (*q->append_output)(pkt, chunk); + status = sctp_packet_append_chunk(pkt, chunk); switch (status) { case SCTP_XMIT_PMTU_FULL: /* Send this packet. */ - if ((error = (*q->force_output)(pkt)) == 0) + if ((error = sctp_packet_transmit(pkt)) == 0) *start_timer = 1; /* If we are retransmitting, we should only @@ -573,7 +590,7 @@ case SCTP_XMIT_RWND_FULL: /* Send this packet. */ - if ((error = (*q->force_output)(pkt)) == 0) + if ((error = sctp_packet_transmit(pkt)) == 0) *start_timer = 1; /* Stop sending DATA as there is no more room @@ -583,6 +600,16 @@ lchunk = NULL; break; + case SCTP_XMIT_NAGLE_DELAY: + /* Send this packet. */ + if ((error = sctp_packet_transmit(pkt)) == 0) + *start_timer = 1; + + /* Stop sending DATA because of nagle delay. */ + list_add(lchunk, lqueue); + lchunk = NULL; + break; + default: /* The append was successful, so add this chunk to * the transmitted list. @@ -625,13 +652,9 @@ struct sctp_packet *packet; struct sctp_packet singleton; struct sctp_association *asoc = q->asoc; - int ecn_capable = asoc->peer.ecn_capable; __u16 sport = asoc->base.bind_addr.port; __u16 dport = asoc->peer.port; __u32 vtag = asoc->peer.i.init_tag; - /* This is the ECNE handler for singleton packets. */ - sctp_packet_phandler_t *s_ecne_handler = NULL; - sctp_packet_phandler_t *ecne_handler = NULL; struct sk_buff_head *queue; struct sctp_transport *transport = NULL; struct sctp_transport *new_transport; @@ -656,10 +679,6 @@ * within a SCTP packet in increasing order of TSN. * ... */ - if (ecn_capable) { - s_ecne_handler = &sctp_get_no_prepend; - ecne_handler = &sctp_get_ecne_prepend; - } queue = &q->control; while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { @@ -686,8 +705,8 @@ &transport_list); } packet = &transport->packet; - (*q->config_output)(packet, vtag, - ecn_capable, ecne_handler); + sctp_packet_config(packet, vtag, + asoc->peer.ecn_capable); } switch (chunk->chunk_hdr->type) { @@ -700,11 +719,10 @@ case SCTP_CID_INIT: case SCTP_CID_INIT_ACK: case SCTP_CID_SHUTDOWN_COMPLETE: - (*q->init_output)(&singleton, transport, sport, dport); - (*q->config_output)(&singleton, vtag, ecn_capable, - s_ecne_handler); - (void) (*q->build_output)(&singleton, chunk); - error = (*q->force_output)(&singleton); + sctp_packet_init(&singleton, transport, sport, dport); + sctp_packet_config(&singleton, vtag, 0); + sctp_packet_append_chunk(&singleton, chunk); + error = sctp_packet_transmit(&singleton); if (error < 0) return error; break; @@ -720,12 +738,10 @@ case SCTP_CID_COOKIE_ACK: case SCTP_CID_ECN_ECNE: case SCTP_CID_ECN_CWR: - (void) (*q->build_output)(packet, chunk); - break; - case SCTP_CID_ASCONF: case SCTP_CID_ASCONF_ACK: - (void) (*q->build_output)(packet, chunk); + case SCTP_CID_FWD_TSN: + sctp_packet_transmit_chunk(packet, chunk); break; default: @@ -770,8 +786,8 @@ } packet = &transport->packet; - (*q->config_output)(packet, vtag, - ecn_capable, ecne_handler); + sctp_packet_config(packet, vtag, + asoc->peer.ecn_capable); retran: error = sctp_outq_flush_rtx(q, packet, rtx_timeout, &start_timer); @@ -803,15 +819,15 @@ if (chunk->sinfo.sinfo_stream >= asoc->c.sinit_num_ostreams) { - /* Mark as s failed send. */ - sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM); + /* Mark as failed send. */ + sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); sctp_chunk_free(chunk); continue; } /* Has this chunk expired? */ - if (sctp_datamsg_expires(chunk)) { - sctp_datamsg_fail(chunk, 0); + if (sctp_chunk_abandoned(chunk)) { + sctp_chunk_fail(chunk, 0); sctp_chunk_free(chunk); continue; } @@ -836,11 +852,11 @@ } packet = &transport->packet; - (*q->config_output)(packet, vtag, - ecn_capable, ecne_handler); + sctp_packet_config(packet, vtag, + asoc->peer.ecn_capable); } - SCTP_DEBUG_PRINTK("sctp_transmit_packet(%p, %p[%s]), ", + SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ", q, chunk, chunk && chunk->chunk_hdr ? sctp_cname(SCTP_ST_CHUNK( @@ -855,7 +871,7 @@ atomic_read(&chunk->skb->users) : -1); /* Add the chunk to the packet. */ - status = (*q->build_output)(packet, chunk); + status = sctp_packet_transmit_chunk(packet, chunk); switch (status) { case SCTP_XMIT_PMTU_FULL: @@ -879,7 +895,7 @@ BUG(); } - /* BUG: We assume that the (*q->force_output()) + /* BUG: We assume that the sctp_packet_transmit() * call below will succeed all the time and add the * chunk to the transmitted list and restart the * timers. @@ -922,33 +938,14 @@ struct sctp_transport *t = list_entry(ltransport, struct sctp_transport, send_ready); - if (t != transport) - transport = t; - - packet = &transport->packet; - if (packet->size != SCTP_IP_OVERHEAD) - error = (*q->force_output)(packet); + packet = &t->packet; + if (!sctp_packet_empty(packet)) + error = sctp_packet_transmit(packet); } return error; } -/* Set the various output handling callbacks. */ -int sctp_outq_set_output_handlers(struct sctp_outq *q, - sctp_outq_ohandler_init_t init, - sctp_outq_ohandler_config_t config, - sctp_outq_ohandler_t append, - sctp_outq_ohandler_t build, - sctp_outq_ohandler_force_t force) -{ - q->init_output = init; - q->config_output = config; - q->append_output = append; - q->build_output = build; - q->force_output = force; - return 0; -} - /* Update unack_data based on the incoming SACK chunk */ static void sctp_sack_update_unack_data(struct sctp_association *assoc, struct sctp_sackhdr *sack) @@ -1007,7 +1004,7 @@ { struct sctp_association *asoc = q->asoc; struct sctp_transport *transport; - struct sctp_chunk *tchunk; + struct sctp_chunk *tchunk = NULL; struct list_head *lchunk, *transport_list, *pos, *temp; sctp_sack_variable_t *frags = sack->variable; __u32 sack_ctsn, ctsn, tsn; @@ -1110,11 +1107,6 @@ ctsn = asoc->ctsn_ack_point; - SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", - __FUNCTION__, sack_ctsn); - SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association " - "%p is 0x%x.\n", __FUNCTION__, asoc, ctsn); - /* Throw away stuff rotting on the sack queue. */ list_for_each_safe(lchunk, temp, &q->sacked) { tchunk = list_entry(lchunk, struct sctp_chunk, @@ -1139,10 +1131,19 @@ asoc->peer.rwnd = sack_a_rwnd; + sctp_generate_fwdtsn(q, sack_ctsn); + + SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", + __FUNCTION__, sack_ctsn); + SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, " + "%p is 0x%x. Adv peer ack point: 0x%x\n", + __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point); + /* See if all chunks are acked. * Make sure the empty queue handler will get run later. */ - q->empty = skb_queue_empty(&q->out) && list_empty(&q->retransmit); + q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) && + list_empty(&q->retransmit); if (!q->empty) goto finish; @@ -1218,6 +1219,12 @@ tchunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); + if (sctp_chunk_abandoned(tchunk)) { + /* Move the chunk to abandoned list. */ + sctp_insert_list(&q->abandoned, lchunk); + continue; + } + tsn = ntohl(tchunk->subh.data_hdr->tsn); if (sctp_acked(sack, tsn)) { /* If this queue is the retransmit queue, the @@ -1598,4 +1605,124 @@ return 0; pass: return 1; +} + +static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist, + int nskips, __u16 stream) +{ + int i; + + for (i = 0; i < nskips; i++) { + if (skiplist[i].stream == stream) + return i; + } + return i; +} + +/* Create and add a fwdtsn chunk to the outq's control queue if needed. */ +static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) +{ + struct sctp_association *asoc = q->asoc; + struct sctp_chunk *ftsn_chunk = NULL; + struct sctp_fwdtsn_skip ftsn_skip_arr[10]; + int nskips = 0; + int skip_pos = 0; + __u32 tsn; + struct sctp_chunk *chunk; + struct list_head *lchunk, *temp; + + /* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the + * received SACK. + * + * If (Advanced.Peer.Ack.Point < SackCumAck), then update + * Advanced.Peer.Ack.Point to be equal to SackCumAck. + */ + if (TSN_lt(asoc->adv_peer_ack_point, ctsn)) + asoc->adv_peer_ack_point = ctsn; + + /* PR-SCTP C2) Try to further advance the "Advanced.Peer.Ack.Point" + * locally, that is, to move "Advanced.Peer.Ack.Point" up as long as + * the chunk next in the out-queue space is marked as "abandoned" as + * shown in the following example: + * + * Assuming that a SACK arrived with the Cumulative TSN ACK 102 + * and the Advanced.Peer.Ack.Point is updated to this value: + * + * out-queue at the end of ==> out-queue after Adv.Ack.Point + * normal SACK processing local advancement + * ... ... + * Adv.Ack.Pt-> 102 acked 102 acked + * 103 abandoned 103 abandoned + * 104 abandoned Adv.Ack.P-> 104 abandoned + * 105 105 + * 106 acked 106 acked + * ... ... + * + * In this example, the data sender successfully advanced the + * "Advanced.Peer.Ack.Point" from 102 to 104 locally. + */ + list_for_each_safe(lchunk, temp, &q->abandoned) { + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + tsn = ntohl(chunk->subh.data_hdr->tsn); + + /* Remove any chunks in the abandoned queue that are acked by + * the ctsn. + */ + if (TSN_lte(tsn, ctsn)) { + list_del_init(lchunk); + if (!chunk->tsn_gap_acked) { + chunk->transport->flight_size -= + sctp_data_size(chunk); + q->outstanding_bytes -= sctp_data_size(chunk); + } + sctp_chunk_free(chunk); + } else { + if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) { + asoc->adv_peer_ack_point = tsn; + if (chunk->chunk_hdr->flags & + SCTP_DATA_UNORDERED) + continue; + skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0], + nskips, + chunk->subh.data_hdr->stream); + ftsn_skip_arr[skip_pos].stream = + chunk->subh.data_hdr->stream; + ftsn_skip_arr[skip_pos].ssn = + chunk->subh.data_hdr->ssn; + if (skip_pos == nskips) + nskips++; + if (nskips == 10) + break; + } else + break; + } + } + + /* PR-SCTP C3) If, after step C1 and C2, the "Advanced.Peer.Ack.Point" + * is greater than the Cumulative TSN ACK carried in the received + * SACK, the data sender MUST send the data receiver a FORWARD TSN + * chunk containing the latest value of the + * "Advanced.Peer.Ack.Point". + * + * C4) For each "abandoned" TSN the sender of the FORWARD TSN SHOULD + * list each stream and sequence number in the forwarded TSN. This + * information will enable the receiver to easily find any + * stranded TSN's waiting on stream reorder queues. Each stream + * SHOULD only be reported once; this means that if multiple + * abandoned messages occur in the same stream then only the + * highest abandoned stream sequence number is reported. If the + * total size of the FORWARD TSN does NOT fit in a single MTU then + * the sender of the FORWARD TSN SHOULD lower the + * Advanced.Peer.Ack.Point to the last TSN that will fit in a + * single MTU. + */ + if (asoc->adv_peer_ack_point > ctsn) + ftsn_chunk = sctp_make_fwdtsn(asoc, asoc->adv_peer_ack_point, + nskips, &ftsn_skip_arr[0]); + + if (ftsn_chunk) { + __skb_queue_tail(&q->control, (struct sk_buff *)ftsn_chunk); + SCTP_INC_STATS(SctpOutCtrlChunks); + } } diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c --- a/net/sctp/protocol.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/protocol.c Sun Apr 25 22:39:31 2004 @@ -1004,7 +1004,9 @@ goto err_init_mibs; /* Initialize proc fs directory. */ - sctp_proc_init(); + status = sctp_proc_init(); + if (status) + goto err_init_proc; /* Initialize object count debugging. */ sctp_dbg_objcnt_init(); @@ -1127,6 +1129,9 @@ /* Disable ADDIP by default. */ sctp_addip_enable = 0; + /* Enable PR-SCTP by default. */ + sctp_prsctp_enable = 1; + sctp_sysctl_register(); INIT_LIST_HEAD(&sctp_address_families); @@ -1171,6 +1176,7 @@ sizeof(struct sctp_hashbucket))); err_ahash_alloc: sctp_dbg_objcnt_exit(); +err_init_proc: sctp_proc_exit(); cleanup_sctp_mibs(); err_init_mibs: diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c --- a/net/sctp/sm_make_chunk.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/sm_make_chunk.c Sun Apr 25 22:39:31 2004 @@ -6,10 +6,6 @@ * * This file is part of the SCTP kernel reference Implementation * - * This file includes part of the implementation of the add-IP extension, - * based on June 29, 2001, - * for the SCTP kernel reference Implementation. - * * These functions work with the state functions in sctp_sm_statefuns.c * to implement the state operations. These functions implement the * steps which require modifying existing data structures. @@ -89,11 +85,13 @@ * Note 2: The ECN capable field is reserved for future use of * Explicit Congestion Notification. */ -static const sctp_ecn_capable_param_t ecap_param = { - { - SCTP_PARAM_ECN_CAPABLE, - __constant_htons(sizeof(sctp_ecn_capable_param_t)), - } +static const struct sctp_paramhdr ecap_param = { + SCTP_PARAM_ECN_CAPABLE, + __constant_htons(sizeof(struct sctp_paramhdr)), +}; +static const struct sctp_paramhdr prsctp_param = { + SCTP_PARAM_FWD_TSN_SUPPORT, + __constant_htons(sizeof(struct sctp_paramhdr)), }; /* A helper to initialize to initialize an op error inside a @@ -196,6 +194,8 @@ chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); chunksize += sizeof(ecap_param); + if (sctp_prsctp_enable) + chunksize += sizeof(prsctp_param); chunksize += vparam_len; /* RFC 2960 3.3.2 Initiation (INIT) (1) @@ -232,6 +232,8 @@ sctp_addto_chunk(retval, num_types * sizeof(__u16), &types); sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + if (sctp_prsctp_enable) + sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); nodata: if (addrs.v) kfree(addrs.v); @@ -278,6 +280,10 @@ if (asoc->peer.ecn_capable) chunksize += sizeof(ecap_param); + /* Tell peer that we'll do PR-SCTP only if peer advertised. */ + if (asoc->peer.prsctp_capable) + chunksize += sizeof(prsctp_param); + /* Now allocate and fill out the chunk. */ retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); if (!retval) @@ -293,6 +299,8 @@ sctp_addto_chunk(retval, cookie_len, cookie); if (asoc->peer.ecn_capable) sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + if (asoc->peer.prsctp_capable) + sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); /* We need to remove the const qualifier at this point. */ retval->asoc = (struct sctp_association *) asoc; @@ -1286,6 +1294,9 @@ /* Save the raw address list length in the cookie. */ cookie->c.raw_addr_list_len = addrs_len; + /* Remember PR-SCTP capability. */ + cookie->c.prsctp_capable = asoc->peer.prsctp_capable; + /* Set an expiration time for the cookie. */ do_gettimeofday(&cookie->c.expiration); TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration); @@ -1442,6 +1453,8 @@ retval->next_tsn = retval->c.initial_tsn; retval->ctsn_ack_point = retval->next_tsn - 1; retval->addip_serial = retval->c.initial_tsn; + retval->adv_peer_ack_point = retval->ctsn_ack_point; + retval->peer.prsctp_capable = retval->c.prsctp_capable; /* The INIT stuff will be done by the side effects. */ return retval; @@ -1653,6 +1666,10 @@ case SCTP_PARAM_HOST_NAME_ADDRESS: /* Tell the peer, we won't support this param. */ return sctp_process_hn_param(asoc, param, chunk, err_chunk); + case SCTP_PARAM_FWD_TSN_SUPPORT: + if (sctp_prsctp_enable) + break; + /* Fall Through */ default: SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", ntohs(param.p->type), cid); @@ -1968,6 +1985,12 @@ asoc->peer.ecn_capable = 1; break; + case SCTP_PARAM_FWD_TSN_SUPPORT: + if (sctp_prsctp_enable) { + asoc->peer.prsctp_capable = 1; + break; + } + /* Fall Through */ default: /* Any unrecognized parameters should have been caught * and handled by sctp_verify_param() which should be @@ -2618,6 +2641,41 @@ sctp_chunk_free(asconf); else asoc->addip_last_asconf = asconf; + } + + return retval; +} + +/* Make a FWD TSN chunk. */ +struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, + __u32 new_cum_tsn, size_t nstreams, + struct sctp_fwdtsn_skip *skiplist) +{ + struct sctp_chunk *retval = NULL; + struct sctp_fwdtsn_chunk *ftsn_chunk; + struct sctp_fwdtsn_hdr ftsn_hdr; + struct sctp_fwdtsn_skip skip; + size_t hint; + int i; + + hint = (nstreams + 1) * sizeof(__u32); + + /* Maybe set the T-bit if we have no association. */ + retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint); + + if (!retval) + return NULL; + + ftsn_chunk = (struct sctp_fwdtsn_chunk *)retval->subh.fwdtsn_hdr; + + ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn); + retval->subh.fwdtsn_hdr = + sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr); + + for (i = 0; i < nstreams; i++) { + skip.stream = skiplist[i].stream; + skip.ssn = skiplist[i].ssn; + sctp_addto_chunk(retval, sizeof(skip), &skip); } return retval; diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c --- a/net/sctp/sm_sideeffect.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/sm_sideeffect.c Sun Apr 25 22:39:31 2004 @@ -579,7 +579,7 @@ /* Helper function to process the process SACK command. */ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, - sctp_sackhdr_t *sackh) + struct sctp_sackhdr *sackh) { int err; @@ -729,6 +729,19 @@ } } +/* Process variable FWDTSN chunk information. */ +static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq, + struct sctp_chunk *chunk) +{ + struct sctp_fwdtsn_skip *skip; + /* Walk through all the skipped SSNs */ + sctp_walk_fwdtsn(skip, chunk) { + sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn)); + } + + return; +} + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -903,7 +916,7 @@ struct timer_list *timer; unsigned long timeout; struct sctp_transport *t; - sctp_sackhdr_t sackh; + struct sctp_sackhdr sackh; int local_cork = 0; if (SCTP_EVENT_T_TIMEOUT != event_type) @@ -961,6 +974,18 @@ /* Record the arrival of a TSN. */ sctp_tsnmap_mark(&asoc->peer.tsn_map, cmd->obj.u32); break; + + case SCTP_CMD_REPORT_FWDTSN: + /* Move the Cumulattive TSN Ack ahead. */ + sctp_tsnmap_skip(&asoc->peer.tsn_map, cmd->obj.u32); + + /* Abort any in progress partial delivery. */ + sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); + break; + + case SCTP_CMD_PROCESS_FWDTSN: + sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.ptr); + break; case SCTP_CMD_GEN_SACK: /* Generate a Selective ACK. diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c --- a/net/sctp/sm_statefuns.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/sm_statefuns.c Sun Apr 25 22:39:31 2004 @@ -3205,6 +3205,143 @@ } /* + * PR-SCTP Section 3.6 Receiver Side Implementation of PR-SCTP + * + * When a FORWARD TSN chunk arrives, the data receiver MUST first update + * its cumulative TSN point to the value carried in the FORWARD TSN + * chunk, and then MUST further advance its cumulative TSN point locally + * if possible. + * After the above processing, the data receiver MUST stop reporting any + * missing TSNs earlier than or equal to the new cumulative TSN point. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *chunk = arg; + struct sctp_fwdtsn_hdr *fwdtsn_hdr; + __u16 len; + __u32 tsn; + + /* RFC 2960 8.5 Verification Tag + * + * When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data; + chunk->subh.fwdtsn_hdr = fwdtsn_hdr; + len = ntohs(chunk->chunk_hdr->length); + len -= sizeof(struct sctp_chunkhdr); + skb_pull(chunk->skb, len); + + tsn = ntohl(fwdtsn_hdr->new_cum_tsn); + SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn); + + /* The TSN is too high--silently discard the chunk and count on it + * getting retransmitted later. + */ + if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) + goto discard_noforce; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); + if (len > sizeof(struct sctp_fwdtsn_hdr)) + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, + SCTP_CHUNK(chunk)); + + /* Count this as receiving DATA. */ + if (asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + /* FIXME: For now send a SACK, but DATA processing may + * send another. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + /* Start the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + + return SCTP_DISPOSITION_CONSUME; + +discard_noforce: + return SCTP_DISPOSITION_DISCARD; +} + +sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *chunk = arg; + struct sctp_fwdtsn_hdr *fwdtsn_hdr; + __u16 len; + __u32 tsn; + + /* RFC 2960 8.5 Verification Tag + * + * When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data; + chunk->subh.fwdtsn_hdr = fwdtsn_hdr; + len = ntohs(chunk->chunk_hdr->length); + len -= sizeof(struct sctp_chunkhdr); + skb_pull(chunk->skb, len); + + tsn = ntohl(fwdtsn_hdr->new_cum_tsn); + SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn); + + /* The TSN is too high--silently discard the chunk and count on it + * getting retransmitted later. + */ + if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) + goto gen_shutdown; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); + if (len > sizeof(struct sctp_fwdtsn_hdr)) + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, + SCTP_CHUNK(chunk)); + + /* Go a head and force a SACK, since we are shutting down. */ +gen_shutdown: + /* Implementor's Guide. + * + * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately + * respond to each received packet containing one or more DATA chunk(s) + * with a SACK, a SHUTDOWN chunk, and restart the T2-shutdown timer + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + return SCTP_DISPOSITION_CONSUME; +} + +/* * Process an unknown chunk. * * Section: 3.2. Also, 2.1 in the implementor's guide. @@ -4671,28 +4808,20 @@ /* Make a transport for the bucket, Eliza... */ transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); - if (!transport) goto nomem; - /* Allocate a new packet for sending the response. */ - packet = t_new(struct sctp_packet, GFP_ATOMIC); - if (!packet) - goto nomem_packet; - /* Cache a route for the transport with the chunk's destination as * the source address. */ sctp_transport_route(transport, (union sctp_addr *)&chunk->dest, sctp_sk(sctp_get_ctl_sock())); - packet = sctp_packet_init(packet, transport, sport, dport); - packet = sctp_packet_config(packet, vtag, 0, NULL); + packet = sctp_packet_init(&transport->packet, transport, sport, dport); + packet = sctp_packet_config(packet, vtag, 0); return packet; -nomem_packet: - sctp_transport_free(transport); nomem: return NULL; } @@ -4701,7 +4830,6 @@ void sctp_ootb_pkt_free(struct sctp_packet *packet) { sctp_transport_free(packet->transport); - sctp_packet_free(packet); } /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */ diff -Nru a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c --- a/net/sctp/sm_statetable.c Sun Apr 25 22:39:32 2004 +++ b/net/sctp/sm_statetable.c Sun Apr 25 22:39:32 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * (C) Copyright IBM Corp. 2001, 2003 + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. @@ -40,6 +40,7 @@ * Hui Huang * Daisy Chang * Ardelle Fan + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -50,7 +51,7 @@ #include static const sctp_sm_table_entry_t bug = { - .fn = sctp_sf_bug, + .fn = sctp_sf_bug, .name = "sctp_sf_bug" }; @@ -73,7 +74,7 @@ return sctp_chunk_event_lookup(event_subtype.chunk, state); break; case SCTP_EVENT_T_TIMEOUT: - DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, + DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, timeout_event_table); break; @@ -486,6 +487,34 @@ TYPE_SCTP_ASCONF_ACK, }; /*state_fn_t addip_chunk_event_table[][] */ +#define TYPE_SCTP_FWD_TSN { \ + /* SCTP_STATE_EMPTY */ \ + {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {.fn = sctp_sf_eat_fwd_tsn, .name = "sctp_sf_eat_fwd_tsn"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {.fn = sctp_sf_eat_fwd_tsn, .name = "sctp_sf_eat_fwd_tsn"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {.fn = sctp_sf_eat_fwd_tsn_fast, .name = "sctp_sf_eat_fwd_tsn_fast"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_FWD_TSN */ + +/* The primary index for this table is the chunk type. + * The secondary index for this table is the state. + */ +const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_FWD_TSN, +}; /*state_fn_t prsctp_chunk_event_table[][] */ + static const sctp_sm_table_entry_t chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ @@ -923,6 +952,11 @@ if (cid >= 0 && cid <= SCTP_CID_BASE_MAX) return &chunk_event_table[cid][state]; + + if (sctp_prsctp_enable) { + if (cid == SCTP_CID_FWD_TSN) + return &prsctp_chunk_event_table[0][state]; + } if (sctp_addip_enable) { if (cid == SCTP_CID_ASCONF) diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- a/net/sctp/socket.c Sun Apr 25 22:39:32 2004 +++ b/net/sctp/socket.c Sun Apr 25 22:39:32 2004 @@ -1948,6 +1948,9 @@ */ static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen) { + struct sctp_association *asoc; + struct list_head *pos; + struct sctp_opt *sp = sctp_sk(sk); int val; if (optlen < sizeof(int)) @@ -1956,7 +1959,15 @@ return -EFAULT; if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) return -EINVAL; - sctp_sk(sk)->user_frag = val; + sp->user_frag = val; + + if (val) { + /* Update the frag_point of the existing associations. */ + list_for_each(pos, &(sp->ep->asocs)) { + asoc = list_entry(pos, struct sctp_association, asocs); + asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); + } + } return 0; } @@ -2531,10 +2542,6 @@ status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); status.sstat_instrms = asoc->c.sinit_max_instreams; status.sstat_outstrms = asoc->c.sinit_num_ostreams; - /* Just in time frag_point update. */ - if (sctp_sk(sk)->user_frag) - asoc->frag_point - = min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag); status.sstat_fragmentation_point = asoc->frag_point; status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, diff -Nru a/net/sctp/sysctl.c b/net/sctp/sysctl.c --- a/net/sctp/sysctl.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/sysctl.c Sun Apr 25 22:39:31 2004 @@ -1,5 +1,5 @@ /* SCTP kernel reference Implementation - * Copyright (c) 2002 International Business Machines Corp. + * (C) Copyright IBM Corp. 2002, 2004 * Copyright (c) 2002 Intel Corp. * * This file is part of the SCTP kernel reference Implementation @@ -35,6 +35,7 @@ * Jon Grimm * Ardelle Fan * Ryan Layer + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -166,6 +167,14 @@ .ctl_name = NET_SCTP_ADDIP_ENABLE, .procname = "addip_enable", .data = &sctp_addip_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_SCTP_PRSCTP_ENABLE, + .procname = "prsctp_enable", + .data = &sctp_prsctp_enable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec diff -Nru a/net/sctp/transport.c b/net/sctp/transport.c --- a/net/sctp/transport.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/transport.c Sun Apr 25 22:39:31 2004 @@ -118,7 +118,6 @@ INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); - sctp_packet_init(&peer->packet, peer, 0, 0); /* Set up the retransmission timer. */ init_timer(&peer->T3_rtx_timer); @@ -168,6 +167,8 @@ if (transport->asoc) sctp_association_put(transport->asoc); + + sctp_packet_free(&transport->packet); dst_release(transport->dst); kfree(transport); diff -Nru a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c --- a/net/sctp/tsnmap.c Sun Apr 25 22:39:32 2004 +++ b/net/sctp/tsnmap.c Sun Apr 25 22:39:32 2004 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * * This file is part of the SCTP kernel reference Implementation @@ -36,6 +36,7 @@ * La Monte H.P. Yarroll * Jon Grimm * Karl Knutson + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -251,6 +252,40 @@ } return ended; +} + +/* Mark this and any lower TSN as seen. */ +void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn) +{ + __s32 gap; + + /* Vacuously mark any TSN which precedes the map base or + * exceeds the end of the map. + */ + if (TSN_lt(tsn, map->base_tsn)) + return; + if (!TSN_lt(tsn, map->base_tsn + map->len + map->len)) + return; + + /* Bump the max. */ + if (TSN_lt(map->max_tsn_seen, tsn)) + map->max_tsn_seen = tsn; + + /* Assert: TSN is in range. */ + gap = tsn - map->base_tsn + 1; + + /* Mark the TSNs as received. */ + if (gap <= map->len) + memset(map->tsn_map, 0x01, gap); + else { + memset(map->tsn_map, 0x01, map->len); + memset(map->overflow_map, 0x01, (gap - map->len)); + } + + /* Go fixup any internal TSN mapping variables including + * cumulative_tsn_ack_point. + */ + sctp_tsnmap_update(map); } /******************************************************************** diff -Nru a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c --- a/net/sctp/ulpevent.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/ulpevent.c Sun Apr 25 22:39:31 2004 @@ -839,6 +839,9 @@ sctp_ulpevent_set_owner(event, asoc); sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); + if (!skb->data_len) + return; + /* Note: Not clearing the entire event struct as this is just a * fragment of the real event. However, we still need to do rwnd * accounting. @@ -867,6 +870,9 @@ skb = sctp_event2skb(event); sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb)); + if (!skb->data_len) + goto done; + /* Don't forget the fragments. */ for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { /* NOTE: skb_shinfos are recursive. Although IP returns @@ -875,6 +881,8 @@ */ sctp_ulpevent_release_data(sctp_skb2event(frag)); } + +done: sctp_ulpevent_release_owner(event); } diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c --- a/net/sctp/ulpqueue.c Sun Apr 25 22:39:31 2004 +++ b/net/sctp/ulpqueue.c Sun Apr 25 22:39:31 2004 @@ -680,6 +680,71 @@ return event; } +/* Helper function to gather skbs that have possibly become + * ordered by forward tsn skipping their dependencies. + */ +static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq) +{ + struct sk_buff *pos, *tmp; + struct sctp_ulpevent *cevent; + struct sctp_ulpevent *event = NULL; + struct sctp_stream *in; + struct sk_buff_head temp; + __u16 csid, cssn; + + in = &ulpq->asoc->ssnmap->in; + + /* We are holding the chunks by stream, by SSN. */ + sctp_skb_for_each(pos, &ulpq->lobby, tmp) { + cevent = (struct sctp_ulpevent *) pos->cb; + csid = cevent->stream; + cssn = cevent->ssn; + + if (cssn != sctp_ssn_peek(in, csid)) + break; + + /* Found it, so mark in the ssnmap. */ + sctp_ssn_next(in, csid); + + __skb_unlink(pos, pos->list); + if (!event) { + /* Create a temporary list to collect chunks on. */ + event = sctp_skb2event(pos); + skb_queue_head_init(&temp); + __skb_queue_tail(&temp, sctp_event2skb(event)); + } else { + /* Attach all gathered skbs to the event. */ + __skb_queue_tail(sctp_event2skb(event)->list, pos); + } + } + + /* Send event to the ULP. */ + if (event) + sctp_ulpq_tail_event(ulpq, event); +} + +/* Skip over an SSN. */ +void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) +{ + struct sctp_stream *in; + + /* Note: The stream ID must be verified before this routine. */ + in = &ulpq->asoc->ssnmap->in; + + /* Is this an old SSN? If so ignore. */ + if (SSN_lt(ssn, sctp_ssn_peek(in, sid))) + return; + + /* Mark that we are no longer expecting this SSN or lower. */ + sctp_ssn_skip(in, sid, ssn); + + /* Go find any other chunks that were waiting for + * ordering and deliver them if needed. + */ + sctp_ulpq_reap_ordered(ulpq); + return; +} + /* Renege 'needed' bytes from the ordering queue. */ static __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed) { diff -Nru a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c --- a/net/sunrpc/auth_gss/auth_gss.c Sun Apr 25 22:39:31 2004 +++ b/net/sunrpc/auth_gss/auth_gss.c Sun Apr 25 22:39:31 2004 @@ -984,6 +984,7 @@ static void __exit exit_rpcsec_gss(void) { + gss_svc_shutdown(); gss_mech_unregister_all(); rpcauth_unregister(&authgss_ops); } diff -Nru a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c --- a/net/sunrpc/auth_gss/svcauth_gss.c Sun Apr 25 22:39:31 2004 +++ b/net/sunrpc/auth_gss/svcauth_gss.c Sun Apr 25 22:39:31 2004 @@ -1063,3 +1063,10 @@ svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); return 0; } + +void +gss_svc_shutdown(void) +{ + cache_unregister(&rsc_cache); + cache_unregister(&rsi_cache); +} diff -Nru a/security/capability.c b/security/capability.c --- a/security/capability.c Sun Apr 25 22:39:31 2004 +++ b/security/capability.c Sun Apr 25 22:39:31 2004 @@ -35,7 +35,7 @@ .netlink_send = cap_netlink_send, .netlink_recv = cap_netlink_recv, - .bprm_compute_creds = cap_bprm_compute_creds, + .bprm_apply_creds = cap_bprm_apply_creds, .bprm_set_security = cap_bprm_set_security, .bprm_secureexec = cap_bprm_secureexec, diff -Nru a/security/commoncap.c b/security/commoncap.c --- a/security/commoncap.c Sun Apr 25 22:39:31 2004 +++ b/security/commoncap.c Sun Apr 25 22:39:31 2004 @@ -115,13 +115,15 @@ return 0; } -/* Copied from fs/exec.c */ static inline int must_not_trace_exec (struct task_struct *p) { - return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP); + return ((p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP)) + || atomic_read(&p->fs->count) > 1 + || atomic_read(&p->files->count) > 1 + || atomic_read(&p->sighand->count) > 1; } -void cap_bprm_compute_creds (struct linux_binprm *bprm) +void cap_bprm_apply_creds (struct linux_binprm *bprm) { /* Derived from fs/exec.c:compute_creds. */ kernel_cap_t new_permitted, working; @@ -132,18 +134,26 @@ new_permitted = cap_combine (new_permitted, working); task_lock(current); + + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { + current->mm->dumpable = 0; + + if (must_not_trace_exec(current) && !capable(CAP_SETUID)) { + bprm->e_uid = current->uid; + bprm->e_gid = current->gid; + } + } + + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + if (!cap_issubset (new_permitted, current->cap_permitted)) { current->mm->dumpable = 0; - if (must_not_trace_exec (current) - || atomic_read (¤t->fs->count) > 1 - || atomic_read (¤t->files->count) > 1 - || atomic_read (¤t->sighand->count) > 1) { - if (!capable (CAP_SETPCAP)) { - new_permitted = cap_intersect (new_permitted, - current-> - cap_permitted); - } + if (must_not_trace_exec (current) && !capable (CAP_SETPCAP)) { + new_permitted = cap_intersect (new_permitted, + current-> + cap_permitted); } } @@ -315,7 +325,7 @@ vm_acct_memory(pages); - /* + /* * Sometimes we want to use more memory than we have */ if (sysctl_overcommit_memory == 1) @@ -377,7 +387,7 @@ EXPORT_SYMBOL(cap_capset_check); EXPORT_SYMBOL(cap_capset_set); EXPORT_SYMBOL(cap_bprm_set_security); -EXPORT_SYMBOL(cap_bprm_compute_creds); +EXPORT_SYMBOL(cap_bprm_apply_creds); EXPORT_SYMBOL(cap_bprm_secureexec); EXPORT_SYMBOL(cap_inode_setxattr); EXPORT_SYMBOL(cap_inode_removexattr); diff -Nru a/security/dummy.c b/security/dummy.c --- a/security/dummy.c Sun Apr 25 22:39:31 2004 +++ b/security/dummy.c Sun Apr 25 22:39:31 2004 @@ -26,6 +26,8 @@ #include #include #include +#include +#include static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) { @@ -116,7 +118,7 @@ vm_acct_memory(pages); - /* + /* * Sometimes we want to use more memory than we have */ if (sysctl_overcommit_memory == 1) @@ -169,9 +171,30 @@ return; } -static void dummy_bprm_compute_creds (struct linux_binprm *bprm) +static inline int must_not_trace_exec (struct task_struct *p) { - return; + return ((p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP)) + || atomic_read(&p->fs->count) > 1 + || atomic_read(&p->files->count) > 1 + || atomic_read(&p->sighand->count) > 1; +} + +static void dummy_bprm_apply_creds (struct linux_binprm *bprm) +{ + task_lock(current); + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { + current->mm->dumpable = 0; + + if (must_not_trace_exec(current) && !capable(CAP_SETUID)) { + bprm->e_uid = current->uid; + bprm->e_gid = current->gid; + } + } + + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + + task_unlock(current); } static int dummy_bprm_set_security (struct linux_binprm *bprm) @@ -887,7 +910,7 @@ set_to_dummy_if_null(ops, vm_enough_memory); set_to_dummy_if_null(ops, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_free_security); - set_to_dummy_if_null(ops, bprm_compute_creds); + set_to_dummy_if_null(ops, bprm_apply_creds); set_to_dummy_if_null(ops, bprm_set_security); set_to_dummy_if_null(ops, bprm_check_security); set_to_dummy_if_null(ops, bprm_secureexec); diff -Nru a/security/root_plug.c b/security/root_plug.c --- a/security/root_plug.c Sun Apr 25 22:39:32 2004 +++ b/security/root_plug.c Sun Apr 25 22:39:32 2004 @@ -90,7 +90,7 @@ .capset_set = cap_capset_set, .capable = cap_capable, - .bprm_compute_creds = cap_bprm_compute_creds, + .bprm_apply_creds = cap_bprm_apply_creds, .bprm_set_security = cap_bprm_set_security, .task_post_setuid = cap_task_post_setuid, diff -Nru a/security/selinux/Kconfig b/security/selinux/Kconfig --- a/security/selinux/Kconfig Sun Apr 25 22:39:31 2004 +++ b/security/selinux/Kconfig Sun Apr 25 22:39:31 2004 @@ -24,6 +24,21 @@ If you are unsure how to answer this question, answer N. +config SECURITY_SELINUX_DISABLE + bool "NSA SELinux runtime disable" + depends on SECURITY_SELINUX + default n + help + This option enables writing to a selinuxfs node 'disable', which + allows SELinux to be disabled at runtime prior to the policy load. + SELinux will then remain disabled until the next boot. + This option is similar to the selinux=0 boot parameter, but is to + support runtime disabling of SELinux, e.g. from /sbin/init, for + portability across platforms where boot parameters are difficult + to employ. + + If you are unsure how to answer this question, answer N. + config SECURITY_SELINUX_DEVELOP bool "NSA SELinux Development Support" depends on SECURITY_SELINUX diff -Nru a/security/selinux/hooks.c b/security/selinux/hooks.c --- a/security/selinux/hooks.c Sun Apr 25 22:39:32 2004 +++ b/security/selinux/hooks.c Sun Apr 25 22:39:32 2004 @@ -1745,7 +1745,7 @@ spin_unlock(&files->file_lock); } -static void selinux_bprm_compute_creds(struct linux_binprm *bprm) +static void selinux_bprm_apply_creds(struct linux_binprm *bprm) { struct task_security_struct *tsec, *psec; struct bprm_security_struct *bsec; @@ -1755,7 +1755,7 @@ struct rlimit *rlim, *initrlim; int rc, i; - secondary_ops->bprm_compute_creds(bprm); + secondary_ops->bprm_apply_creds(bprm); tsec = current->security; @@ -2560,7 +2560,7 @@ /* Control the ability to change the hard limit (whether lowering or raising it), so that the hard limit can later be used as a safe reset point for the soft limit - upon context transitions. See selinux_bprm_compute_creds. */ + upon context transitions. See selinux_bprm_apply_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) return task_has_perm(current, current, PROCESS__SETRLIMIT); @@ -3971,7 +3971,7 @@ .bprm_alloc_security = selinux_bprm_alloc_security, .bprm_free_security = selinux_bprm_free_security, - .bprm_compute_creds = selinux_bprm_compute_creds, + .bprm_apply_creds = selinux_bprm_apply_creds, .bprm_set_security = selinux_bprm_set_security, .bprm_check_security = selinux_bprm_check_security, .bprm_secureexec = selinux_bprm_secureexec, @@ -4216,4 +4216,57 @@ __initcall(selinux_nf_ip_init); +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +static void selinux_nf_ip_exit(void) +{ + printk(KERN_INFO "SELinux: Unregistering netfilter hooks\n"); + + nf_unregister_hook(&selinux_ipv4_op); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + nf_unregister_hook(&selinux_ipv6_op); +#endif /* IPV6 */ +} +#endif + +#else /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */ + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +#define selinux_nf_ip_exit() +#endif + #endif /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */ + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +int selinux_disable(void) +{ + extern void exit_sel_fs(void); + static int selinux_disabled = 0; + + if (ss_initialized) { + /* Not permitted after initial policy load. */ + return -EINVAL; + } + + if (selinux_disabled) { + /* Only do this once. */ + return -EINVAL; + } + + printk(KERN_INFO "SELinux: Disabled at runtime.\n"); + + selinux_disabled = 1; + + /* Reset security_ops to the secondary module, dummy or capability. */ + security_ops = secondary_ops; + + /* Unregister netfilter hooks. */ + selinux_nf_ip_exit(); + + /* Unregister selinuxfs. */ + exit_sel_fs(); + + return 0; +} +#endif + + diff -Nru a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c --- a/security/selinux/selinuxfs.c Sun Apr 25 22:39:32 2004 +++ b/security/selinux/selinuxfs.c Sun Apr 25 22:39:32 2004 @@ -46,6 +46,8 @@ struct task_security_struct *tsec; tsec = tsk->security; + if (!tsec) + return -EACCES; return avc_has_perm(tsec->sid, SECINITSID_SECURITY, SECCLASS_SECURITY, perms, NULL, NULL); @@ -61,8 +63,9 @@ SEL_RELABEL, /* compute relabeling decision */ SEL_USER, /* compute reachable user contexts */ SEL_POLICYVERS, /* return policy version for this kernel */ - SEL_COMMIT_BOOLS, - SEL_MLS /* return if MLS policy is enabled */ + SEL_COMMIT_BOOLS, /* commit new boolean values */ + SEL_MLS, /* return if MLS policy is enabled */ + SEL_DISABLE /* disable SELinux until next reboot */ }; static ssize_t sel_read_enforce(struct file *filp, char *buf, @@ -151,6 +154,53 @@ .write = sel_write_enforce, }; +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +static ssize_t sel_write_disable(struct file * file, const char * buf, + size_t count, loff_t *ppos) + +{ + char *page; + ssize_t length; + int new_value; + extern int selinux_disable(void); + + if (count < 0 || count >= PAGE_SIZE) + return -ENOMEM; + if (*ppos != 0) { + /* No partial writes. */ + return -EINVAL; + } + page = (char*)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + memset(page, 0, PAGE_SIZE); + length = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + length = -EINVAL; + if (sscanf(page, "%d", &new_value) != 1) + goto out; + + if (new_value) { + length = selinux_disable(); + if (length < 0) + goto out; + } + + length = count; +out: + free_page((unsigned long) page); + return length; +} +#else +#define sel_write_disable NULL +#endif + +static struct file_operations sel_disable_ops = { + .write = sel_write_disable, +}; + static ssize_t sel_read_policyvers(struct file *filp, char *buf, size_t count, loff_t *ppos) { @@ -1005,6 +1055,7 @@ [SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO}, [SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR}, [SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO}, + [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR}, /* last one */ {""} }; ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); @@ -1054,3 +1105,10 @@ } __initcall(init_sel_fs); + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +void exit_sel_fs(void) +{ + unregister_filesystem(&sel_fs_type); +} +#endif diff -Nru a/security/selinux/ss/services.c b/security/selinux/ss/services.c --- a/security/selinux/ss/services.c Sun Apr 25 22:39:31 2004 +++ b/security/selinux/ss/services.c Sun Apr 25 22:39:31 2004 @@ -456,9 +456,7 @@ goto out; } } - printk(KERN_ERR "security_context_to_sid: called before " - "initial load_policy on unknown context %s\n", scontext); - rc = -EINVAL; + *sid = SECINITSID_KERNEL; goto out; } *sid = SECSID_NULL; @@ -1343,8 +1341,6 @@ if (!ebitmap_get_bit(&role->types, j)) continue; usercon.type = j+1; - if (usercon.type == fromcon->type) - continue; mls_for_user_ranges(user,usercon) { rc = context_struct_compute_av(fromcon, &usercon, SECCLASS_PROCESS,