]> git.neil.brown.name Git - history.git/commitdiff
- David Miller: sparc and net updates. Fix merge_segments. 2.4.0-test12
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:44 +0000 (15:40 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:44 +0000 (15:40 -0500)
- Dan Aloni: ISA PnP name parsing cleanup
- Mohammad Haque and others: hunt down tq initializations.
- Petr Vandrovec: ncpfs config changes
- Neil Brown: raid and md cleanups
- Pete Zaitcev: ymfpci update
- Alan Cox: sync (network driver MODULE_OWNER and cleanups)
- Martin Diehl: pirq router for VLSI 82C534 (HP OmniBook and others)
- Tigran Aivazian: ia32 microcode driver update
- Tim Waugh: parport fixes (ECP write, documentation)
- Richard Henderson: alpha update
- David Woodhouse: MTD update
- Trond Myklebust: index the NFS inode cache using the file handle.
  This makes NetApp snapshot directories do the right thing.

213 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/DMA-mapping.txt
Documentation/DocBook/videobook.tmpl
Documentation/cachetlb.txt
Documentation/ioctl-number.txt
Documentation/kbuild/makefiles.txt
MAINTAINERS
arch/alpha/kernel/core_cia.c
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/lib/Makefile
arch/alpha/lib/checksum.c
arch/alpha/lib/csum_partial_copy.c
arch/alpha/lib/ev6-memchr.S [new file with mode: 0644]
arch/alpha/lib/ev6-memcpy.S [new file with mode: 0644]
arch/alpha/lib/ev6-memset.S [new file with mode: 0644]
arch/alpha/lib/ev6-strcpy.S [deleted file]
arch/alpha/lib/ev6-strncpy.S [deleted file]
arch/alpha/lib/ev6-stxcpy.S [new file with mode: 0644]
arch/alpha/lib/ev6-stxncpy.S [new file with mode: 0644]
arch/alpha/lib/ev67-strchr.S
arch/alpha/lib/memcpy.c
arch/alpha/lib/memmove.S [new file with mode: 0644]
arch/alpha/lib/strcpy.S
arch/alpha/lib/strncpy.S
arch/alpha/lib/stxcpy.S
arch/alpha/lib/stxncpy.S
arch/i386/config.in
arch/i386/kernel/dmi_scan.c [new file with mode: 0644]
arch/i386/kernel/microcode.c
arch/i386/kernel/pci-irq.c
arch/sparc/boot/piggyback.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/mm/init.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/mm/init.c
drivers/atm/ambassador.c
drivers/block/ll_rw_blk.c
drivers/block/paride/pseudo.h
drivers/char/drm/gamma_dma.c
drivers/char/drm/i810_dma.c
drivers/char/drm/mga_dma.c
drivers/char/n_r3964.c
drivers/char/scan_keyb.c
drivers/char/sx.h
drivers/char/vt.c
drivers/i2o/i2o_lan.c
drivers/ieee1394/guid.c
drivers/ieee1394/ohci1394.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hysdn/boardergo.c
drivers/isdn/pcbit/drv.c
drivers/md/Makefile
drivers/md/linear.c
drivers/md/lvm.c
drivers/md/md.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid5.c
drivers/media/video/zr36120.h
drivers/mtd/Config.in
drivers/mtd/Makefile
drivers/mtd/doc2000.c
drivers/mtd/doc2001.c
drivers/mtd/docecc.c [new file with mode: 0644]
drivers/mtd/docprobe.c
drivers/mtd/map_ram.c
drivers/mtd/map_rom.c
drivers/mtd/mtdblock.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c [new file with mode: 0644]
drivers/mtd/nftl.c
drivers/mtd/nftlmount.c [new file with mode: 0644]
drivers/mtd/nora.c
drivers/mtd/octagon-5066.c
drivers/mtd/physmap.c
drivers/mtd/pnc2000.c
drivers/mtd/rpxlite.c
drivers/mtd/vmax301.c
drivers/net/acenic.c
drivers/net/aironet4500_core.c
drivers/net/eth16i.c
drivers/net/ethertap.c
drivers/net/ewrk3.c
drivers/net/fmv18x.c
drivers/net/hamachi.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/hdlcdrv.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/hp100.c
drivers/net/ibmlana.c
drivers/net/isa-skeleton.c
drivers/net/lne390.c
drivers/net/mvme147.c
drivers/net/natsemi.c
drivers/net/pcnet32.c
drivers/net/plip.c
drivers/net/pppoe.c
drivers/net/rclanmtl.c
drivers/net/sb1000.c
drivers/net/setup.c
drivers/net/sis900.c
drivers/net/sk_mca.c
drivers/net/smc-mca.c
drivers/net/smc-ultra.c
drivers/net/smc-ultra32.c
drivers/net/smc9194.c
drivers/net/sundance.c
drivers/net/sunhme.c
drivers/net/tlan.c
drivers/net/tulip/tulip_core.c
drivers/net/via-rhine.c
drivers/net/wan/comx-hw-mixcom.c
drivers/net/wan/comx.h
drivers/net/wan/sdlamain.c
drivers/net/wan/x25_asy.h
drivers/net/wd.c
drivers/net/winbond-840.c
drivers/net/yellowfin.c
drivers/parport/ChangeLog
drivers/parport/Makefile
drivers/parport/parport_gsc.c [new file with mode: 0644]
drivers/parport/parport_pc.c
drivers/pci/pci.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pnp/isapnp.c
drivers/s390/net/ctc.c
drivers/sbus/audio/dmy.c
drivers/sbus/char/aurora.c
drivers/sbus/char/sab82532.c
drivers/scsi/Makefile
drivers/scsi/imm.c
drivers/scsi/imm.h
drivers/scsi/ips.h
drivers/scsi/ppa.c
drivers/scsi/ppa.h
drivers/sound/vwsnd.c
drivers/sound/ymfpci.c
drivers/sound/ymfpci.h
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/video/mdacon.c
fs/buffer.c
fs/ncpfs/Config.in
fs/ncpfs/ioctl.c
fs/ncpfs/ncplib_kernel.h
fs/nfs/inode.c
fs/nfs/read.c
fs/proc/generic.c
fs/readdir.c
fs/smbfs/sock.c
include/asm-generic/pgtable.h
include/asm-i386/apic.h
include/asm-i386/msr.h
include/asm-i386/pgtable.h
include/asm-i386/processor.h
include/asm-sparc/hdreg.h
include/asm-sparc/processor.h
include/asm-sparc64/pgalloc.h
include/asm-sparc64/processor.h
include/linux/atmdev.h
include/linux/module.h
include/linux/mtd/doc2000.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/nand_ids.h [new file with mode: 0644]
include/linux/mtd/nftl.h
include/linux/mtd/partitions.h [new file with mode: 0644]
include/linux/nfs_fs.h
include/linux/raid/md_k.h
include/linux/raid/raid1.h
include/linux/skbuff.h
include/linux/spinlock.h
include/net/sock.h
kernel/Makefile
kernel/fork.c
mm/memory.c
mm/mmap.c
mm/mremap.c
net/atm/proc.c
net/core/dev.c
net/core/dv.c
net/core/skbuff.c
net/decnet/dn_nsp_in.c
net/decnet/dn_route.c
net/ipv4/devinet.c
net/ipv4/ip_fragment.c
net/ipv4/ip_input.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ipt_MIRROR.c
net/ipv4/tcp_ipv4.c
net/ipv6/ip6_input.c
net/ipv6/reassembly.c
net/ipv6/tcp_ipv6.c
net/packet/af_packet.c
net/x25/af_x25.c
scripts/kernel-doc

diff --git a/CREDITS b/CREDITS
index 287a21415ac1813eada880297dfb7f31033447ca..b2e00bf576fe4620a5f93df99840f720a7384c5e 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -41,7 +41,7 @@ N: Tigran A. Aivazian
 E: tigran@veritas.com
 W: http://www.ocston.org/~tigran
 D: BFS filesystem
-D: Intel P6 CPU microcode update support
+D: Intel IA32 CPU microcode update support
 D: Various kernel patches
 S: United Kingdom
 
index abcb21c6479cd3a609cdfdc61c04deeeac88cc51..ed3bfb6024eb9eb27c3b727ed40b64f7582069f2 100644 (file)
@@ -185,10 +185,10 @@ PCMCIA (PC Card) support is now partially implemented in the main
 kernel source.  Pay attention when you recompile your kernel ;-).
 Also, be sure to upgrade to the latest pcmcia-cs release.
 
-Intel P6 microcode
-------------------
+Intel IA32 microcode
+--------------------
 
-A driver has been added to allow updating of Intel P6 microcode,
+A driver has been added to allow updating of Intel IA32 microcode,
 accessible as both a devfs regular file and as a normal (misc)
 character device.  If you are not using devfs you may need to:
 
@@ -199,6 +199,13 @@ chmod 0644 /dev/cpu/microcode
 as root before you can use this.  You'll probably also want to
 get the user-space microcode_ctl utility to use with this.
 
+If you have compiled the driver as a module you may need to add
+the following line:
+
+alias char-major-10-184 microcode
+
+to your /etc/modules.conf file.
+
 Networking
 ==========
 
index 135426b104f3b4b0a4559e20bc5c1d0fee49422c..7ac3fdd28fda31b799f5802d1f23555cc31cceb6 100644 (file)
@@ -13442,13 +13442,13 @@ CONFIG_TOSHIBA
   Toshiba Linux utilities website at:
   http://www.buzzard.org.uk/toshiba/
 
-/dev/cpu/microcode - Intel P6 CPU microcode support
+/dev/cpu/microcode - Intel IA32 CPU microcode support
 CONFIG_MICROCODE
   If you say Y here and also to "/dev file system support" in the
   'File systems' section, you will be able to update the microcode on
-  Intel processors in the P6 family, e.g. Pentium Pro, Pentium II,
-  Pentium III, Xeon etc. You will obviously need the actual microcode
-  binary data itself which is not shipped with the Linux kernel.
+  Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
+  Pentium III, Pentium 4, Xeon etc. You will obviously need the actual 
+  microcode binary data itself which is not shipped with the Linux kernel.
 
   For latest news and information on obtaining all the required
   ingredients for this driver, check:
@@ -13457,7 +13457,9 @@ CONFIG_MICROCODE
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called microcode.o. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt.
+  a module, say M here and read Documentation/modules.txt. If you use
+  modprobe or kmod you may also want to add the line
+  'alias char-major-10-184 microcode' to your /etc/modules.conf file.
 
 /dev/cpu/*/msr - Model-specific register support
 CONFIG_X86_MSR
index 0ffccdee23617a59d600947e72f5646addc23b2c..b59a97dd102dd1f7c036d9176d8442ae340e0bb8 100644 (file)
@@ -341,7 +341,7 @@ to use the pci_dma_sync_*() interfaces.
                        struct my_card_header *hp;
 
                        /* Examine the header to see if we wish
-                        * to except the data.  But synchronize
+                        * to accept the data.  But synchronize
                         * the DMA transfer with the CPU first
                         * so that we see updated contents.
                         */
index 2174af67143044ad0be39997cae111b8b253f5f4..3798fc3108092680458893ae593fb74c9b4ebc6e 100644 (file)
@@ -66,7 +66,7 @@
         vertical blanking data interfaces are also provided.
   </para>
   </chapter>
-  <chapter>
+  <chapter id="radio">
         <title>Radio Devices</title>
   <para>
         There are a wide variety of radio interfaces available for PC's, and these
index 5201a2f546296b24c0f69c1c142ae879fde6383d..f3ae784979717e1bd13a04302b7e0426deb5d189 100644 (file)
@@ -257,7 +257,7 @@ the proper points in time.
 
 Here is the new interface:
 
-  void copy_user_page(void *from, void *to, unsigned long address)
+  void copy_user_page(void *to, void *from, unsigned long address)
   void clear_user_page(void *to, unsigned long address)
 
        These two routines store data in user anonymous or COW
index 0edc635ff2909393a87884ac0869e8a7b8e602de..4fd9a4b5af9637e6c6831853600b4a77201d3442 100644 (file)
@@ -74,8 +74,8 @@ Code  Seq#    Include File            Comments
 0x22   all     scsi/sg.h
 '1'    00-1F   <linux/timepps.h>       PPS kit from Ulrich Windl
                                        <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
-'6'    00-10   <asm-i386/processor.h>  Intel P6 microcode update driver
-                                       <tigran@veritas.com>
+'6'    00-10   <asm-i386/processor.h>  Intel IA32 microcode update driver
+                                       <mailto:tigran@veritas.com>
 '8'    all                             SNP8023 advanced NIC card
                                        <mailto:mcr@solidum.com>
 'A'    00-1F   linux/apm_bios.h
index 1b63892c61e2dfe76068b6aec9b8653da81ef9c4..ef789acf2ec6f36eb372e57cb20ca0a718da0709 100644 (file)
@@ -32,6 +32,8 @@ This document describes the Linux kernel Makefiles.
      7.6  Compilation flags
      7.7  Miscellaneous variables
   8  New-style variables
+     8.1  New variables
+     8.2  Converting to old-style
   9  Compatibility with Linux Kernel 2.2
  10  Credits
 
@@ -521,6 +523,8 @@ contains boilerplate code which converts from new-style variables to
 old-style variables.  This is because Rules.make processes only the
 old-style variables.
 
+See section 8.2 ("Converting to old-style") for examples.
+
 
 
 --- 6.4 Rules.make section
@@ -679,6 +683,25 @@ The public interface of Rules.make consists of the following variables:
        options still control whether or not its $(O_TARGET) goes into
        vmlinux.  See the $(M_OBJS) example below.
 
+       Sometimes the ordering of all $(OX_OBJS) files before all
+       $(O_OBJS) files can be a problem, particularly if both
+       $(O_OBJS) files and $(OX_OBJS) files contain __initcall
+       declarations where order is important.   To avoid this imposed
+       ordering, the use of $(OX_OBJS) can be dropped altogether and
+       $(MIX_OBJS) used instead.
+
+       If this approach is used, then:
+        - All objects to be linked into vmlinux should be listed in
+          $(O_OBJS) in the desired order.
+        - All objects to be created as modules should be listed in
+          $(M_OBJS)
+        - All objects that export symbols should also be listed in
+          $(MIX_OBJS).
+
+       This has the same effect as maintaining the
+       exported/non-exported split, except that there is more control
+       over the ordering of object files in vmlinux.
+       
 
 
 --- 7.3 Library file goals
@@ -865,6 +888,14 @@ The public interface of Rules.make consists of the following variables:
                        $(LD) -r -o $@ $(sb-objs)
 
 
+       As is mentioned in section 7.2 ("Object file goals"),
+       $(MIX_OBJS) can also be used simply to list all objects that
+       export any symbols.  If this approach is taken, then
+       $(O_OBJS), $(L_OBJS), $(M_OBJS) and $(MI_OBJS) should simply
+       lists all of the vmlinux object files, library object files,
+       module object files and intermediate module files
+       respectively.  Duplication between $(MI_OBJS) and $(MIX_OBJS)
+       is not a problem.
 
 --- 7.6 Compilation flags
 
@@ -993,6 +1024,8 @@ variables into old-style variables.  There is also some mixing, where
 people define most variables using "new style" but then fall back to
 "old style" for a few lines.
 
+--- 8.1 New variables
+
     obj-y obj-m obj-n obj-
 
        These variables replace $(O_OBJS), $(OX_OBJS), $(M_OBJS),
@@ -1184,6 +1217,41 @@ people define most variables using "new style" but then fall back to
        This means nls should be added to (subdir-y) and $(subdir-m) if
        CONFIG_NFS = y.
 
+--- 8.2 Converting to old-style
+
+       The following example is taken from drivers/usb/Makefile.
+       Note that this uses MIX_OBJS to avoid the need for OX_OBJS and
+       MX_OBJS and thus to maintain the ordering of objects in $(obj-y)
+
+               # Translate to Rules.make lists.
+               multi-used      := $(filter $(list-multi), $(obj-y) $(obj-m))
+               multi-objs      := $(foreach m, $(multi-used), $($(basename $(m))-objs))
+               active-objs     := $(sort $(multi-objs) $(obj-y) $(obj-m))
+
+               O_OBJS          := $(obj-y)
+               M_OBJS          := $(obj-m)
+               MIX_OBJS        := $(filter $(export-objs), $(active-objs))
+
+       An example for libraries from drivers/acorn/scsi/Makefile:
+
+               # Translate to Rules.make lists.
+
+               L_OBJS          := $(filter-out $(export-objs), $(obj-y))
+               LX_OBJS         := $(filter     $(export-objs), $(obj-y))
+               M_OBJS          := $(sort $(filter-out $(export-objs), $(obj-m)))
+               MX_OBJS         := $(sort $(filter     $(export-objs), $(obj-m)))
+
+       As ordering is not so important in libraries, this still uses
+       LX_OBJS and MX_OBJS, though (presumably) it could be changed to
+       use MIX_OBJS as follows:
+
+               active-objs     := $(sort $(obj-y) $(obj-m))
+               L_OBJS          := $(obj-y)
+               M_OBJS          := $(obj-m)
+               MIX_OBJS        := $(filter $(export-objs), $(active-objs))
+               
+
+       which is clearly shorted and arguably clearer.
 
 === 9 Compatibility with Linux Kernel 2.2
 
index 5fd8361cfac440614605eb7cffae862fcf1d26cc..16e3b02a6c6854fd65552bf9dbc20ad191fce4dd 100644 (file)
@@ -640,7 +640,7 @@ M:  jgarzik@mandrakesoft.com
 W:     http://sourceforge.net/projects/gkernel/
 S:     Maintained
 
-INTEL P6 MICROCODE UPDATE SUPPORT
+INTEL IA32 MICROCODE UPDATE SUPPORT
 P:     Tigran Aivazian
 M:     tigran@veritas.com
 S:     Maintained
index b736f9516ce898af2eb6a0561b763e5b0aa1aeab..6203b02476803664d1fa676a9355aa1268e23928 100644 (file)
@@ -700,11 +700,11 @@ do_init_arch(int is_pyxis)
 
        *(vip)CIA_IOC_PCI_W1_BASE = 0x40000000 | 1;
        *(vip)CIA_IOC_PCI_W1_MASK = (0x40000000 - 1) & 0xfff00000;
-       *(vip)CIA_IOC_PCI_T1_BASE = 0;
+       *(vip)CIA_IOC_PCI_T1_BASE = 0 >> 2;
 
        *(vip)CIA_IOC_PCI_W2_BASE = 0x80000000 | 1;
        *(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000;
-       *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000;
+       *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000 >> 2;
 
        *(vip)CIA_IOC_PCI_W3_BASE = 0;
 }
index e17cbcd7089235636bc37352482cac4794abbfa1..ddf3d9755ca19474a2b7d7330c4b65d6aa0cb6c1 100644 (file)
@@ -90,10 +90,8 @@ quirk_cypress_ide_ports(struct pci_dev *dev)
 {
        if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
                return;
-       dev->resource[1].start |= 2;
-       dev->resource[1].end = dev->resource[1].start;
-       pci_claim_resource(dev, 0);
-       pci_claim_resource(dev, 1);
+       dev->resource[0].flags = 0;
+       dev->resource[1].flags = 0;
 }
 
 static void __init
index 3b727631a6b48b8fc57be6c35981358665575efc..d4eb6a5d9876fbae2607d39cab0bc26ac52222da 100644 (file)
@@ -613,10 +613,10 @@ pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask)
        /* Check that we have a scatter-gather arena that fits.  */
        hose = pdev ? pdev->sysdata : pci_isa_hose;
        arena = hose->sg_isa;
-       if (arena && arena->dma_base + arena->size <= mask)
+       if (arena && arena->dma_base + arena->size - 1 <= mask)
                return 1;
        arena = hose->sg_pci;
-       if (arena && arena->dma_base + arena->size <= mask)
+       if (arena && arena->dma_base + arena->size - 1 <= mask)
                return 1;
 
        return 0;
index 5de58a6ad2addcccb4bf1746d756231b1af2f162..cb23a987d491d8173bd92136fb2070aa0221b132 100644 (file)
@@ -20,12 +20,30 @@ ifeq ($(CONFIG_ALPHA_EV67),y)
   ev67 := ev67-
 endif
 
-OBJS  = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \
-       checksum.o csum_partial_copy.o $(ev67)strlen.o \
-       $(ev67)strcat.o $(ev6)strcpy.o $(ev67)strncat.o $(ev6)strncpy.o \
-       stxcpy.o stxncpy.o $(ev67)strchr.o strrchr.o memchr.o \
-       $(ev6)copy_user.o $(ev6)clear_user.o $(ev6)strncpy_from_user.o \
-       $(ev67)strlen_user.o $(ev6)csum_ipv6_magic.o strcasecmp.o fpreg.o \
+OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \
+       $(ev6)memset.o \
+       $(ev6)memcpy.o \
+       memmove.o \
+       io.o \
+       checksum.o \
+       csum_partial_copy.o \
+       $(ev67)strlen.o \
+       $(ev67)strcat.o \
+       strcpy.o \
+       $(ev67)strncat.o \
+       strncpy.o \
+       $(ev6)stxcpy.o \
+       $(ev6)stxncpy.o \
+       $(ev67)strchr.o \
+       strrchr.o \
+       $(ev6)memchr.o \
+       $(ev6)copy_user.o \
+       $(ev6)clear_user.o \
+       $(ev6)strncpy_from_user.o \
+       $(ev67)strlen_user.o \
+       $(ev6)csum_ipv6_magic.o \
+       strcasecmp.o \
+       fpreg.o \
        callback_srm.o srm_puts.o srm_printk.o
 
 lib.a: $(OBJS)
index 5165279f0da2098e8e86779d86c2039a893bf861..7f29ac81c7f3a01e3ccb5092927862e6dc817294 100644 (file)
@@ -3,6 +3,10 @@
  *
  * This file contains network checksum routines that are better done
  * in an architecture-specific manner due to speed..
+ * Comments in other versions indicate that the algorithms are from RFC1071
+ *
+ * accellerated versions (and 21264 assembly versions ) contributed by
+ *     Rick Gorton     <rick.gorton@alpha-processor.com>
  */
  
 #include <linux/string.h>
 
 static inline unsigned short from64to16(unsigned long x)
 {
-       /* add up 32-bit words for 33 bits */
-       x = (x & 0xffffffff) + (x >> 32);
-       /* add up 16-bit and 17-bit words for 17+c bits */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up 16-bit and 2-bit for 16+c bit */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up carry.. */
-       x = (x & 0xffff) + (x >> 16);
-       return x;
+       /* Using extract instructions is a bit more efficient
+          than the original shift/bitmask version.  */
+
+       union {
+               unsigned long   ul;
+               unsigned int    ui[2];
+               unsigned short  us[4];
+       } in_v, tmp_v, out_v;
+
+       in_v.ul = x;
+       tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1];
+
+       /* Since the bits of tmp_v.sh[3] are going to always be zero,
+          we don't have to bother to add that in.  */
+       out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1]
+                       + (unsigned long) tmp_v.us[2];
+
+       /* Similarly, out_v.us[2] is always zero for the final add.  */
+       return out_v.us[0] + out_v.us[1];
 }
 
 /*
index 5638a1a0c5821f6f748c8be009a1c42551818ab9..f8129b5f50d32f44f2123c67b7e498e1c1735e03 100644 (file)
@@ -2,6 +2,8 @@
  * csum_partial_copy - do IP checksumming and copy
  *
  * (C) Copyright 1996 Linus Torvalds
+ * accellerated versions (and 21264 assembly versions ) contributed by
+ *     Rick Gorton     <rick.gorton@alpha-processor.com>
  *
  * Don't look at this too closely - you'll go mad. The things
  * we do for performance..
@@ -68,6 +70,31 @@ __asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
 })
 
 
+static inline unsigned short from64to16(unsigned long x)
+{
+       /* Using extract instructions is a bit more efficient
+          than the original shift/bitmask version.  */
+
+       union {
+               unsigned long   ul;
+               unsigned int    ui[2];
+               unsigned short  us[4];
+       } in_v, tmp_v, out_v;
+
+       in_v.ul = x;
+       tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1];
+
+       /* Since the bits of tmp_v.sh[3] are going to always be zero,
+          we don't have to bother to add that in.  */
+       out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1]
+                       + (unsigned long) tmp_v.us[2];
+
+       /* Similarly, out_v.us[2] is always zero for the final add.  */
+       return out_v.us[0] + out_v.us[1];
+}
+
+
+
 /*
  * Ok. This isn't fun, but this is the EASY case.
  */
@@ -335,13 +362,7 @@ do_csum_partial_copy_from_user(const char *src, char *dst, int len,
                                        soff, doff, len-8, checksum,
                                        partial_dest, errp);
                }
-               /* 64 -> 33 bits */
-               checksum = (checksum & 0xffffffff) + (checksum >> 32);
-               /* 33 -> < 32 bits */
-               checksum = (checksum & 0xffff) + (checksum >> 16);
-               /* 32 -> 16 bits */
-               checksum = (checksum & 0xffff) + (checksum >> 16);
-               checksum = (checksum & 0xffff) + (checksum >> 16);
+               checksum = from64to16 (checksum);
        }
        return checksum;
 }
diff --git a/arch/alpha/lib/ev6-memchr.S b/arch/alpha/lib/ev6-memchr.S
new file mode 100644 (file)
index 0000000..a8e843d
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * arch/alpha/lib/ev6-memchr.S
+ *
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * Finds characters in a memory area.  Optimized for the Alpha:
+ *
+ *    - memory accessed as aligned quadwords only
+ *    - uses cmpbge to compare 8 bytes in parallel
+ *    - does binary search to find 0 byte in last
+ *      quadword (HAKMEM needed 12 instructions to
+ *      do this instead of the 9 instructions that
+ *      binary search needs).
+ *
+ * For correctness consider that:
+ *
+ *    - only minimum number of quadwords may be accessed
+ *    - the third argument is an unsigned long
+ *
+ * Much of the information about 21264 scheduling/coding comes from:
+ *     Compiler Writer's Guide for the Alpha 21264
+ *     abbreviated as 'CWG' in other comments here
+ *     ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
+ * Scheduling notation:
+ *     E       - either cluster
+ *     U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
+ *     L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
+ * Try not to change the actual algorithm if possible for consistency.
+ */
+
+        .set noreorder
+        .set noat
+
+       .align  4
+       .globl memchr
+       .ent memchr
+memchr:
+       .frame $30,0,$26,0
+       .prologue 0
+
+       # Hack -- if someone passes in (size_t)-1, hoping to just
+       # search til the end of the address space, we will overflow
+       # below when we find the address of the last byte.  Given
+       # that we will never have a 56-bit address space, cropping
+       # the length is the easiest way to avoid trouble.
+       zap     $18, 0x80, $5   # U : Bound length
+       beq     $18, $not_found # U :
+        ldq_u   $1, 0($16)     # L : load first quadword Latency=3
+       and     $17, 0xff, $17  # E : L L U U : 00000000000000ch
+
+       insbl   $17, 1, $2      # U : 000000000000ch00
+       cmpult  $18, 9, $4      # E : small (< 1 quad) string?
+       or      $2, $17, $17    # E : 000000000000chch
+        lda     $3, -1($31)    # E : U L L U
+
+       sll     $17, 16, $2     # U : 00000000chch0000
+       addq    $16, $5, $5     # E : Max search address
+       or      $2, $17, $17    # E : 00000000chchchch
+       sll     $17, 32, $2     # U : U L L U : chchchch00000000
+
+       or      $2, $17, $17    # E : chchchchchchchch
+       extql   $1, $16, $7     # U : $7 is upper bits
+       beq     $4, $first_quad # U :
+       ldq_u   $6, -1($5)      # L : L U U L : eight or less bytes to search Latency=3
+
+       extqh   $6, $16, $6     # U : 2 cycle stall for $6
+       mov     $16, $0         # E :
+       nop                     # E :
+       or      $7, $6, $1      # E : L U L U $1 = quadword starting at $16
+
+       # Deal with the case where at most 8 bytes remain to be searched
+       # in $1.  E.g.:
+       #       $18 = 6
+       #       $1 = ????c6c5c4c3c2c1
+$last_quad:
+       negq    $18, $6         # E :
+        xor    $17, $1, $1     # E :
+       srl     $3, $6, $6      # U : $6 = mask of $18 bits set
+        cmpbge  $31, $1, $2    # E : L U L U
+
+       nop
+       nop
+       and     $2, $6, $2      # E :
+        beq     $2, $not_found # U : U L U L
+
+$found_it:
+#if defined(__alpha_fix__) && defined(__alpha_cix__)
+       /*
+        * Since we are guaranteed to have set one of the bits, we don't
+        * have to worry about coming back with a 0x40 out of cttz...
+        */
+       cttz    $2, $3          # U0 :
+       addq    $0, $3, $0      # E : All done
+       nop                     # E :
+       ret                     # L0 : L U L U
+#else
+       /*
+        * Slow and clunky.  It can probably be improved.
+        * An exercise left for others.
+        */
+        negq    $2, $3         # E :
+        and     $2, $3, $2     # E :
+        and     $2, 0x0f, $1   # E :
+        addq    $0, 4, $3      # E :
+
+        cmoveq  $1, $3, $0     # E : Latency 2, extra map cycle
+       nop                     # E : keep with cmov
+        and     $2, 0x33, $1   # E :
+        addq    $0, 2, $3      # E : U L U L : 2 cycle stall on $0
+
+        cmoveq  $1, $3, $0     # E : Latency 2, extra map cycle
+       nop                     # E : keep with cmov
+        and     $2, 0x55, $1   # E :
+        addq    $0, 1, $3      # E : U L U L : 2 cycle stall on $0
+
+        cmoveq  $1, $3, $0     # E : Latency 2, extra map cycle
+       nop
+       nop
+       ret                     # L0 : L U L U
+#endif
+
+       # Deal with the case where $18 > 8 bytes remain to be
+       # searched.  $16 may not be aligned.
+       .align 4
+$first_quad:
+       andnot  $16, 0x7, $0    # E :
+        insqh   $3, $16, $2    # U : $2 = 0000ffffffffffff ($16<0:2> ff)
+        xor    $1, $17, $1     # E :
+       or      $1, $2, $1      # E : U L U L $1 = ====ffffffffffff
+
+        cmpbge  $31, $1, $2    # E :
+        bne     $2, $found_it  # U :
+       # At least one byte left to process.
+       ldq     $1, 8($0)       # L :
+       subq    $5, 1, $18      # E : U L U L
+
+       addq    $0, 8, $0       # E :
+       # Make $18 point to last quad to be accessed (the
+       # last quad may or may not be partial).
+       andnot  $18, 0x7, $18   # E :
+       cmpult  $0, $18, $2     # E :
+       beq     $2, $final      # U : U L U L
+
+       # At least two quads remain to be accessed.
+
+       subq    $18, $0, $4     # E : $4 <- nr quads to be processed
+       and     $4, 8, $4       # E : odd number of quads?
+       bne     $4, $odd_quad_count # U :
+       # At least three quads remain to be accessed
+       mov     $1, $4          # E : L U L U : move prefetched value to correct reg
+
+       .align  4
+$unrolled_loop:
+       ldq     $1, 8($0)       # L : prefetch $1
+       xor     $17, $4, $2     # E :
+       cmpbge  $31, $2, $2     # E :
+       bne     $2, $found_it   # U : U L U L
+
+       addq    $0, 8, $0       # E :
+       nop                     # E :
+       nop                     # E :
+       nop                     # E :
+
+$odd_quad_count:
+       xor     $17, $1, $2     # E :
+       ldq     $4, 8($0)       # L : prefetch $4
+       cmpbge  $31, $2, $2     # E :
+       addq    $0, 8, $6       # E :
+
+       bne     $2, $found_it   # U :
+       cmpult  $6, $18, $6     # E :
+       addq    $0, 8, $0       # E :
+       nop                     # E :
+
+       bne     $6, $unrolled_loop # U :
+       mov     $4, $1          # E : move prefetched value into $1
+       nop                     # E :
+       nop                     # E :
+
+$final:        subq    $5, $0, $18     # E : $18 <- number of bytes left to do
+       nop                     # E :
+       nop                     # E :
+       bne     $18, $last_quad # U :
+
+$not_found:
+       mov     $31, $0         # E :
+       nop                     # E :
+       nop                     # E :
+       ret                     # L0 :
+
+        .end memchr
diff --git a/arch/alpha/lib/ev6-memcpy.S b/arch/alpha/lib/ev6-memcpy.S
new file mode 100644 (file)
index 0000000..7ebcbc2
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * arch/alpha/lib/ev6-memcpy.S
+ * 21264 version by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * Reasonably optimized memcpy() routine for the Alpha 21264
+ *
+ *     - memory accessed as aligned quadwords only
+ *     - uses bcmpge to compare 8 bytes in parallel
+ *
+ * Much of the information about 21264 scheduling/coding comes from:
+ *     Compiler Writer's Guide for the Alpha 21264
+ *     abbreviated as 'CWG' in other comments here
+ *     ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
+ * Scheduling notation:
+ *     E       - either cluster
+ *     U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
+ *     L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
+ *
+ * Temp usage notes:
+ *     $1,$2,          - scratch
+ */
+
+       .set noreorder
+       .set noat
+
+       .align  4
+       .globl memcpy
+       .ent memcpy
+memcpy:
+       .frame $30,0,$26,0
+       .prologue 0
+
+       mov     $16, $0                 # E : copy dest to return
+       ble     $18, $nomoredata        # U : done with the copy?
+       xor     $16, $17, $1            # E : are source and dest alignments the same?
+       and     $1, 7, $1               # E : are they the same mod 8?
+
+       bne     $1, $misaligned         # U : Nope - gotta do this the slow way
+       /* source and dest are same mod 8 address */
+       and     $16, 7, $1              # E : Are both 0mod8?
+       beq     $1, $both_0mod8         # U : Yes
+       nop                             # E :
+
+       /*
+        * source and dest are same misalignment.  move a byte at a time
+        * until a 0mod8 alignment for both is reached.
+        * At least one byte more to move
+        */
+
+$head_align:
+       ldbu    $1, 0($17)              # L : grab a byte
+       subq    $18, 1, $18             # E : count--
+       addq    $17, 1, $17             # E : src++
+       stb     $1, 0($16)              # L :
+       addq    $16, 1, $16             # E : dest++
+       and     $16, 7, $1              # E : Are we at 0mod8 yet?
+       ble     $18, $nomoredata        # U : done with the copy?
+       bne     $1, $head_align         # U :
+
+$both_0mod8:
+       cmple   $18, 127, $1            # E : Can we unroll the loop?
+       bne     $1, $no_unroll          # U :
+       and     $16, 63, $1             # E : get mod64 alignment
+       beq     $1, $do_unroll          # U : no single quads to fiddle
+
+$single_head_quad:
+       ldq     $1, 0($17)              # L : get 8 bytes
+       subq    $18, 8, $18             # E : count -= 8
+       addq    $17, 8, $17             # E : src += 8
+       nop                             # E :
+
+       stq     $1, 0($16)              # L : store
+       addq    $16, 8, $16             # E : dest += 8
+       and     $16, 63, $1             # E : get mod64 alignment
+       bne     $1, $single_head_quad   # U : still not fully aligned
+
+$do_unroll:
+       addq    $16, 64, $7             # E : Initial (+1 trip) wh64 address
+       cmple   $18, 63, $1             # E : Can we go through the unrolled loop?
+       bne     $1, $tail_quads         # U : Nope
+       nop                             # E : 
+
+$unroll_body:
+       wh64    ($7)                    # L1 : memory subsystem hint: 64 bytes at
+                                       # ($7) are about to be over-written
+       ldq     $6, 0($17)              # L0 : bytes 0..7
+       nop                             # E :
+       nop                             # E :
+
+       ldq     $4, 8($17)              # L : bytes 8..15
+       ldq     $5, 16($17)             # L : bytes 16..23
+       addq    $7, 64, $7              # E : Update next wh64 address
+       nop                             # E :
+
+       ldq     $3, 24($17)             # L : bytes 24..31
+       addq    $16, 64, $1             # E : fallback value for wh64
+       nop                             # E :
+       nop                             # E :
+
+       addq    $17, 32, $17            # E : src += 32 bytes
+       stq     $6, 0($16)              # L : bytes 0..7
+       nop                             # E :
+       nop                             # E :
+
+       stq     $4, 8($16)              # L : bytes 8..15
+       stq     $5, 16($16)             # L : bytes 16..23
+       subq    $18, 192, $2            # E : At least two more trips to go?
+       nop                             # E :
+
+       stq     $3, 24($16)             # L : bytes 24..31
+       addq    $16, 32, $16            # E : dest += 32 bytes
+       nop                             # E :
+       nop                             # E :
+
+       ldq     $6, 0($17)              # L : bytes 0..7
+       ldq     $4, 8($17)              # L : bytes 8..15
+       cmovlt  $2, $1, $7              # E : Latency 2, extra map slot - Use
+                                       # fallback wh64 address if < 2 more trips
+       nop                             # E :
+
+       ldq     $5, 16($17)             # L : bytes 16..23
+       ldq     $3, 24($17)             # L : bytes 24..31
+       addq    $16, 32, $16            # E : dest += 32
+       subq    $18, 64, $18            # E : count -= 64
+
+       addq    $17, 32, $17            # E : src += 32
+       stq     $6, -32($16)            # L : bytes 0..7
+       stq     $4, -24($16)            # L : bytes 8..15
+       cmple   $18, 63, $1             # E : At least one more trip?
+
+       stq     $5, -16($16)            # L : bytes 16..23
+       stq     $3, -8($16)             # L : bytes 24..31
+       nop                             # E :
+       beq     $1, $unroll_body
+
+$tail_quads:
+$no_unroll:
+       .align 4
+       subq    $18, 8, $18             # E : At least a quad left?
+       blt     $18, $less_than_8       # U : Nope
+       nop                             # E :
+       nop                             # E :
+
+$move_a_quad:
+       ldq     $1, 0($17)              # L : fetch 8
+       subq    $18, 8, $18             # E : count -= 8
+       addq    $17, 8, $17             # E : src += 8
+       nop                             # E :
+
+       stq     $1, 0($16)              # L : store 8
+       addq    $16, 8, $16             # E : dest += 8
+       bge     $18, $move_a_quad       # U :
+       nop                             # E :
+
+$less_than_8:
+       .align 4
+       addq    $18, 8, $18             # E : add back for trailing bytes
+       ble     $18, $nomoredata        # U : All-done
+       nop                             # E :
+       nop                             # E :
+
+       /* Trailing bytes */
+$tail_bytes:
+       subq    $18, 1, $18             # E : count--
+       ldbu    $1, 0($17)              # L : fetch a byte
+       addq    $17, 1, $17             # E : src++
+       nop                             # E :
+
+       stb     $1, 0($16)              # L : store a byte
+       addq    $16, 1, $16             # E : dest++
+       bgt     $18, $tail_bytes        # U : more to be done?
+       nop                             # E :
+
+       /* branching to exit takes 3 extra cycles, so replicate exit here */
+       ret     $31, ($26), 1           # L0 :
+       nop                             # E :
+       nop                             # E :
+       nop                             # E :
+
+$misaligned:
+       mov     $0, $4                  # E : dest temp
+       and     $0, 7, $1               # E : dest alignment mod8
+       beq     $1, $dest_0mod8         # U : life doesnt totally suck
+       nop
+
+$aligndest:
+       ble     $18, $nomoredata        # U :
+       ldbu    $1, 0($17)              # L : fetch a byte
+       subq    $18, 1, $18             # E : count--
+       addq    $17, 1, $17             # E : src++
+
+       stb     $1, 0($4)               # L : store it
+       addq    $4, 1, $4               # E : dest++
+       and     $4, 7, $1               # E : dest 0mod8 yet?
+       bne     $1, $aligndest          # U : go until we are aligned.
+
+       /* Source has unknown alignment, but dest is known to be 0mod8 */
+$dest_0mod8:
+       subq    $18, 8, $18             # E : At least a quad left?
+       blt     $18, $misalign_tail     # U : Nope
+       ldq_u   $3, 0($17)              # L : seed (rotating load) of 8 bytes
+       nop                             # E :
+
+$mis_quad:
+       ldq_u   $16, 8($17)             # L : Fetch next 8
+       extql   $3, $17, $3             # U : masking
+       extqh   $16, $17, $1            # U : masking
+       bis     $3, $1, $1              # E : merged bytes to store
+
+       subq    $18, 8, $18             # E : count -= 8
+       addq    $17, 8, $17             # E : src += 8
+       stq     $1, 0($4)               # L : store 8 (aligned)
+       mov     $16, $3                 # E : "rotate" source data
+
+       addq    $4, 8, $4               # E : dest += 8
+       bge     $18, $mis_quad          # U : More quads to move
+       nop
+       nop
+
+$misalign_tail:
+       addq    $18, 8, $18             # E : account for tail stuff
+       ble     $18, $nomoredata        # U :
+       nop
+       nop
+
+$misalign_byte:
+       ldbu    $1, 0($17)              # L : fetch 1
+       subq    $18, 1, $18             # E : count--
+       addq    $17, 1, $17             # E : src++
+       nop                             # E :
+
+       stb     $1, 0($4)               # L : store
+       addq    $4, 1, $4               # E : dest++
+       bgt     $18, $misalign_byte     # U : more to go?
+       nop
+
+
+$nomoredata:
+       ret     $31, ($26), 1           # L0 :
+       nop                             # E :
+       nop                             # E :
+       nop                             # E :
+
+       .end memcpy
+
+/* For backwards module compatability.  */
+__memcpy = memcpy
+.globl __memcpy
diff --git a/arch/alpha/lib/ev6-memset.S b/arch/alpha/lib/ev6-memset.S
new file mode 100644 (file)
index 0000000..626929f
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * arch/alpha/lib/ev6-memset.S
+ *
+ * This is an efficient (and relatively small) implementation of the C library
+ * "memset()" function for the 21264 implementation of Alpha.
+ *
+ * 21264 version  contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * Much of the information about 21264 scheduling/coding comes from:
+ *     Compiler Writer's Guide for the Alpha 21264
+ *     abbreviated as 'CWG' in other comments here
+ *     ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
+ * Scheduling notation:
+ *     E       - either cluster
+ *     U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
+ *     L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
+ * The algorithm for the leading and trailing quadwords remains the same,
+ * however the loop has been unrolled to enable better memory throughput,
+ * and the code has been replicated for each of the entry points: __memset
+ * and __memsetw to permit better scheduling to eliminate the stalling
+ * encountered during the mask replication.
+ * A future enhancement might be to put in a byte store loop for really
+ * small (say < 32 bytes) memset()s.  Whether or not that change would be
+ * a win in the kernel would depend upon the contextual usage.
+ * WARNING: Maintaining this is going to be more work than the above version,
+ * as fixes will need to be made in multiple places.  The performance gain
+ * is worth it.
+ */
+
+       .set noat
+       .set noreorder
+.text
+       .globl __memset
+       .globl __memsetw
+       .globl __constant_c_memset
+       .globl memset
+
+       .ent __memset
+.align 5
+__memset:
+memset:
+       .frame $30,0,$26,0
+       .prologue 0
+
+       /*
+        * Serious stalling happens.  The only way to mitigate this is to
+        * undertake a major re-write to interleave the constant materialization
+        * with other parts of the fall-through code.  This is important, even
+        * though it makes maintenance tougher.
+        * Do this later.
+        */
+       and $17,255,$1          # E : 00000000000000ch
+       insbl $17,1,$2          # U : 000000000000ch00
+       bis $16,$16,$0          # E : return value
+       ble $18,end_b           # U : zero length requested?
+
+       addq $18,$16,$6         # E : max address to write to
+       bis     $1,$2,$17       # E : 000000000000chch
+       insbl   $1,2,$3         # U : 0000000000ch0000
+       insbl   $1,3,$4         # U : 00000000ch000000
+
+       or      $3,$4,$3        # E : 00000000chch0000
+       inswl   $17,4,$5        # U : 0000chch00000000
+       xor     $16,$6,$1       # E : will complete write be within one quadword?
+       inswl   $17,6,$2        # U : chch000000000000
+
+       or      $17,$3,$17      # E : 00000000chchchch
+       or      $2,$5,$2        # E : chchchch00000000
+       bic     $1,7,$1         # E : fit within a single quadword?
+       and     $16,7,$3        # E : Target addr misalignment
+
+       or      $17,$2,$17      # E : chchchchchchchch
+       beq     $1,within_quad_b # U :
+       nop                     # E :
+       beq     $3,aligned_b    # U : target is 0mod8
+
+       /*
+        * Target address is misaligned, and won't fit within a quadword
+        */
+       ldq_u $4,0($16)         # L : Fetch first partial
+       bis $16,$16,$5          # E : Save the address
+       insql $17,$16,$2        # U : Insert new bytes
+       subq $3,8,$3            # E : Invert (for addressing uses)
+
+       addq $18,$3,$18         # E : $18 is new count ($3 is negative)
+       mskql $4,$16,$4         # U : clear relevant parts of the quad
+       subq $16,$3,$16         # E : $16 is new aligned destination
+       bis $2,$4,$1            # E : Final bytes
+
+       nop
+       stq_u $1,0($5)          # L : Store result
+       nop
+       nop
+
+.align 4
+aligned_b:
+       /*
+        * We are now guaranteed to be quad aligned, with at least
+        * one partial quad to write.
+        */
+
+       sra $18,3,$3            # U : Number of remaining quads to write
+       and $18,7,$18           # E : Number of trailing bytes to write
+       bis $16,$16,$5          # E : Save dest address
+       beq $3,no_quad_b        # U : tail stuff only
+
+       /*
+        * it's worth the effort to unroll this and use wh64 if possible
+        * Lifted a bunch of code from clear_user.S
+        * At this point, entry values are:
+        * $16  Current destination address
+        * $5   A copy of $16
+        * $6   The max quadword address to write to
+        * $18  Number trailer bytes
+        * $3   Number quads to write
+        */
+
+       and     $16, 0x3f, $2   # E : Forward work (only useful for unrolled loop)
+       subq    $3, 16, $4      # E : Only try to unroll if > 128 bytes
+       subq    $2, 0x40, $1    # E : bias counter (aligning stuff 0mod64)
+       blt     $4, loop_b      # U :
+
+       /*
+        * We know we've got at least 16 quads, minimum of one trip
+        * through unrolled loop.  Do a quad at a time to get us 0mod64
+        * aligned.
+        */
+
+       nop                     # E :
+       nop                     # E :
+       nop                     # E :
+       beq     $1, $bigalign_b # U :
+
+$alignmod64_b:
+       stq     $17, 0($5)      # L :
+       subq    $3, 1, $3       # E : For consistency later
+       addq    $1, 8, $1       # E : Increment towards zero for alignment
+       addq    $5, 8, $4       # E : Initial wh64 address (filler instruction)
+
+       nop
+       nop
+       addq    $5, 8, $5       # E : Inc address
+       blt     $1, $alignmod64_b # U :
+
+$bigalign_b:
+       /*
+        * $3 - number quads left to go
+        * $5 - target address (aligned 0mod64)
+        * $17 - mask of stuff to store
+        * Scratch registers available: $7, $2, $4, $1
+        * we know that we'll be taking a minimum of one trip through
+        * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle
+        * Assumes the wh64 needs to be for 2 trips through the loop in the future
+        * The wh64 is issued on for the starting destination address for trip +2
+        * through the loop, and if there are less than two trips left, the target
+        * address will be for the current trip.
+        */
+
+$do_wh64_b:
+       wh64    ($4)            # L1 : memory subsystem write hint
+       subq    $3, 24, $2      # E : For determining future wh64 addresses
+       stq     $17, 0($5)      # L :
+       nop                     # E :
+
+       addq    $5, 128, $4     # E : speculative target of next wh64
+       stq     $17, 8($5)      # L :
+       stq     $17, 16($5)     # L :
+       addq    $5, 64, $7      # E : Fallback address for wh64 (== next trip addr)
+
+       stq     $17, 24($5)     # L :
+       stq     $17, 32($5)     # L :
+       cmovlt  $2, $7, $4      # E : Latency 2, extra mapping cycle
+       nop
+
+       stq     $17, 40($5)     # L :
+       stq     $17, 48($5)     # L :
+       subq    $3, 16, $2      # E : Repeat the loop at least once more?
+       nop
+
+       stq     $17, 56($5)     # L :
+       addq    $5, 64, $5      # E :
+       subq    $3, 8, $3       # E :
+       bge     $2, $do_wh64_b  # U :
+
+       nop
+       nop
+       nop
+       beq     $3, no_quad_b   # U : Might have finished already
+
+.align 4
+       /*
+        * Simple loop for trailing quadwords, or for small amounts
+        * of data (where we can't use an unrolled loop and wh64)
+        */
+loop_b:
+       stq $17,0($5)           # L :
+       subq $3,1,$3            # E : Decrement number quads left
+       addq $5,8,$5            # E : Inc address
+       bne $3,loop_b           # U : more?
+
+no_quad_b:
+       /*
+        * Write 0..7 trailing bytes.
+        */
+       nop                     # E :
+       beq $18,end_b           # U : All done?
+       ldq $7,0($5)            # L :
+       mskqh $7,$6,$2          # U : Mask final quad
+
+       insqh $17,$6,$4         # U : New bits
+       bis $2,$4,$1            # E : Put it all together
+       stq $1,0($5)            # L : And back to memory
+       ret $31,($26),1         # L0 :
+
+within_quad_b:
+       ldq_u $1,0($16)         # L :
+       insql $17,$16,$2        # U : New bits
+       mskql $1,$16,$4         # U : Clear old
+       bis $2,$4,$2            # E : New result
+
+       mskql $2,$6,$4          # U :
+       mskqh $1,$6,$2          # U :
+       bis $2,$4,$1            # E :
+       stq_u $1,0($16)         # L :
+
+end_b:
+       nop
+       nop
+       nop
+       ret $31,($26),1         # L0 :
+       .end __memset
+
+       /*
+        * This is the original body of code, prior to replication and
+        * rescheduling.  Leave it here, as there may be calls to this
+        * entry point.
+        */
+.align 4
+       .ent __memset
+__constant_c_memset:
+       .frame $30,0,$26,0
+       .prologue 0
+
+       addq $18,$16,$6         # E : max address to write to
+       bis $16,$16,$0          # E : return value
+       xor $16,$6,$1           # E : will complete write be within one quadword?
+       ble $18,end             # U : zero length requested?
+
+       bic $1,7,$1             # E : fit within a single quadword
+       beq $1,within_one_quad  # U :
+       and $16,7,$3            # E : Target addr misalignment
+       beq $3,aligned          # U : target is 0mod8
+
+       /*
+        * Target address is misaligned, and won't fit within a quadword
+        */
+       ldq_u $4,0($16)         # L : Fetch first partial
+       bis $16,$16,$5          # E : Save the address
+       insql $17,$16,$2        # U : Insert new bytes
+       subq $3,8,$3            # E : Invert (for addressing uses)
+
+       addq $18,$3,$18         # E : $18 is new count ($3 is negative)
+       mskql $4,$16,$4         # U : clear relevant parts of the quad
+       subq $16,$3,$16         # E : $16 is new aligned destination
+       bis $2,$4,$1            # E : Final bytes
+
+       nop
+       stq_u $1,0($5)          # L : Store result
+       nop
+       nop
+
+.align 4
+aligned:
+       /*
+        * We are now guaranteed to be quad aligned, with at least
+        * one partial quad to write.
+        */
+
+       sra $18,3,$3            # U : Number of remaining quads to write
+       and $18,7,$18           # E : Number of trailing bytes to write
+       bis $16,$16,$5          # E : Save dest address
+       beq $3,no_quad          # U : tail stuff only
+
+       /*
+        * it's worth the effort to unroll this and use wh64 if possible
+        * Lifted a bunch of code from clear_user.S
+        * At this point, entry values are:
+        * $16  Current destination address
+        * $5   A copy of $16
+        * $6   The max quadword address to write to
+        * $18  Number trailer bytes
+        * $3   Number quads to write
+        */
+
+       and     $16, 0x3f, $2   # E : Forward work (only useful for unrolled loop)
+       subq    $3, 16, $4      # E : Only try to unroll if > 128 bytes
+       subq    $2, 0x40, $1    # E : bias counter (aligning stuff 0mod64)
+       blt     $4, loop        # U :
+
+       /*
+        * We know we've got at least 16 quads, minimum of one trip
+        * through unrolled loop.  Do a quad at a time to get us 0mod64
+        * aligned.
+        */
+
+       nop                     # E :
+       nop                     # E :
+       nop                     # E :
+       beq     $1, $bigalign   # U :
+
+$alignmod64:
+       stq     $17, 0($5)      # L :
+       subq    $3, 1, $3       # E : For consistency later
+       addq    $1, 8, $1       # E : Increment towards zero for alignment
+       addq    $5, 8, $4       # E : Initial wh64 address (filler instruction)
+
+       nop
+       nop
+       addq    $5, 8, $5       # E : Inc address
+       blt     $1, $alignmod64 # U :
+
+$bigalign:
+       /*
+        * $3 - number quads left to go
+        * $5 - target address (aligned 0mod64)
+        * $17 - mask of stuff to store
+        * Scratch registers available: $7, $2, $4, $1
+        * we know that we'll be taking a minimum of one trip through
+        * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle
+        * Assumes the wh64 needs to be for 2 trips through the loop in the future
+        * The wh64 is issued on for the starting destination address for trip +2
+        * through the loop, and if there are less than two trips left, the target
+        * address will be for the current trip.
+        */
+
+$do_wh64:
+       wh64    ($4)            # L1 : memory subsystem write hint
+       subq    $3, 24, $2      # E : For determining future wh64 addresses
+       stq     $17, 0($5)      # L :
+       nop                     # E :
+
+       addq    $5, 128, $4     # E : speculative target of next wh64
+       stq     $17, 8($5)      # L :
+       stq     $17, 16($5)     # L :
+       addq    $5, 64, $7      # E : Fallback address for wh64 (== next trip addr)
+
+       stq     $17, 24($5)     # L :
+       stq     $17, 32($5)     # L :
+       cmovlt  $2, $7, $4      # E : Latency 2, extra mapping cycle
+       nop
+
+       stq     $17, 40($5)     # L :
+       stq     $17, 48($5)     # L :
+       subq    $3, 16, $2      # E : Repeat the loop at least once more?
+       nop
+
+       stq     $17, 56($5)     # L :
+       addq    $5, 64, $5      # E :
+       subq    $3, 8, $3       # E :
+       bge     $2, $do_wh64    # U :
+
+       nop
+       nop
+       nop
+       beq     $3, no_quad     # U : Might have finished already
+
+.align 4
+       /*
+        * Simple loop for trailing quadwords, or for small amounts
+        * of data (where we can't use an unrolled loop and wh64)
+        */
+loop:
+       stq $17,0($5)           # L :
+       subq $3,1,$3            # E : Decrement number quads left
+       addq $5,8,$5            # E : Inc address
+       bne $3,loop             # U : more?
+
+no_quad:
+       /*
+        * Write 0..7 trailing bytes.
+        */
+       nop                     # E :
+       beq $18,end             # U : All done?
+       ldq $7,0($5)            # L :
+       mskqh $7,$6,$2          # U : Mask final quad
+
+       insqh $17,$6,$4         # U : New bits
+       bis $2,$4,$1            # E : Put it all together
+       stq $1,0($5)            # L : And back to memory
+       ret $31,($26),1         # L0 :
+
+within_one_quad:
+       ldq_u $1,0($16)         # L :
+       insql $17,$16,$2        # U : New bits
+       mskql $1,$16,$4         # U : Clear old
+       bis $2,$4,$2            # E : New result
+
+       mskql $2,$6,$4          # U :
+       mskqh $1,$6,$2          # U :
+       bis $2,$4,$1            # E :
+       stq_u $1,0($16)         # L :
+
+end:
+       nop
+       nop
+       nop
+       ret $31,($26),1         # L0 :
+       .end __constant_c_memset
+
+       /*
+        * This is a replicant of the __constant_c_memset code, rescheduled
+        * to mask stalls.  Note that entry point names also had to change
+        */
+       .align 5
+       .ent __memsetw
+
+__memsetw:
+       .frame $30,0,$26,0
+       .prologue 0
+
+       inswl $17,0,$5          # U : 000000000000c1c2
+       inswl $17,2,$2          # U : 00000000c1c20000
+       bis $16,$16,$0          # E : return value
+       addq    $18,$16,$6      # E : max address to write to
+
+       ble $18, end_w          # U : zero length requested?
+       inswl   $17,4,$3        # U : 0000c1c200000000
+       inswl   $17,6,$4        # U : c1c2000000000000
+       xor     $16,$6,$1       # E : will complete write be within one quadword?
+
+       or      $2,$5,$2        # E : 00000000c1c2c1c2
+       or      $3,$4,$17       # E : c1c2c1c200000000
+       bic     $1,7,$1         # E : fit within a single quadword
+       and     $16,7,$3        # E : Target addr misalignment
+
+       or      $17,$2,$17      # E : c1c2c1c2c1c2c1c2
+       beq $1,within_quad_w    # U :
+       nop
+       beq $3,aligned_w        # U : target is 0mod8
+
+       /*
+        * Target address is misaligned, and won't fit within a quadword
+        */
+       ldq_u $4,0($16)         # L : Fetch first partial
+       bis $16,$16,$5          # E : Save the address
+       insql $17,$16,$2        # U : Insert new bytes
+       subq $3,8,$3            # E : Invert (for addressing uses)
+
+       addq $18,$3,$18         # E : $18 is new count ($3 is negative)
+       mskql $4,$16,$4         # U : clear relevant parts of the quad
+       subq $16,$3,$16         # E : $16 is new aligned destination
+       bis $2,$4,$1            # E : Final bytes
+
+       nop
+       stq_u $1,0($5)          # L : Store result
+       nop
+       nop
+
+.align 4
+aligned_w:
+       /*
+        * We are now guaranteed to be quad aligned, with at least
+        * one partial quad to write.
+        */
+
+       sra $18,3,$3            # U : Number of remaining quads to write
+       and $18,7,$18           # E : Number of trailing bytes to write
+       bis $16,$16,$5          # E : Save dest address
+       beq $3,no_quad_w        # U : tail stuff only
+
+       /*
+        * it's worth the effort to unroll this and use wh64 if possible
+        * Lifted a bunch of code from clear_user.S
+        * At this point, entry values are:
+        * $16  Current destination address
+        * $5   A copy of $16
+        * $6   The max quadword address to write to
+        * $18  Number trailer bytes
+        * $3   Number quads to write
+        */
+
+       and     $16, 0x3f, $2   # E : Forward work (only useful for unrolled loop)
+       subq    $3, 16, $4      # E : Only try to unroll if > 128 bytes
+       subq    $2, 0x40, $1    # E : bias counter (aligning stuff 0mod64)
+       blt     $4, loop_w      # U :
+
+       /*
+        * We know we've got at least 16 quads, minimum of one trip
+        * through unrolled loop.  Do a quad at a time to get us 0mod64
+        * aligned.
+        */
+
+       nop                     # E :
+       nop                     # E :
+       nop                     # E :
+       beq     $1, $bigalign_w # U :
+
+$alignmod64_w:
+       stq     $17, 0($5)      # L :
+       subq    $3, 1, $3       # E : For consistency later
+       addq    $1, 8, $1       # E : Increment towards zero for alignment
+       addq    $5, 8, $4       # E : Initial wh64 address (filler instruction)
+
+       nop
+       nop
+       addq    $5, 8, $5       # E : Inc address
+       blt     $1, $alignmod64_w       # U :
+
+$bigalign_w:
+       /*
+        * $3 - number quads left to go
+        * $5 - target address (aligned 0mod64)
+        * $17 - mask of stuff to store
+        * Scratch registers available: $7, $2, $4, $1
+        * we know that we'll be taking a minimum of one trip through
+        * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle
+        * Assumes the wh64 needs to be for 2 trips through the loop in the future
+        * The wh64 is issued on for the starting destination address for trip +2
+        * through the loop, and if there are less than two trips left, the target
+        * address will be for the current trip.
+        */
+
+$do_wh64_w:
+       wh64    ($4)            # L1 : memory subsystem write hint
+       subq    $3, 24, $2      # E : For determining future wh64 addresses
+       stq     $17, 0($5)      # L :
+       nop                     # E :
+
+       addq    $5, 128, $4     # E : speculative target of next wh64
+       stq     $17, 8($5)      # L :
+       stq     $17, 16($5)     # L :
+       addq    $5, 64, $7      # E : Fallback address for wh64 (== next trip addr)
+
+       stq     $17, 24($5)     # L :
+       stq     $17, 32($5)     # L :
+       cmovlt  $2, $7, $4      # E : Latency 2, extra mapping cycle
+       nop
+
+       stq     $17, 40($5)     # L :
+       stq     $17, 48($5)     # L :
+       subq    $3, 16, $2      # E : Repeat the loop at least once more?
+       nop
+
+       stq     $17, 56($5)     # L :
+       addq    $5, 64, $5      # E :
+       subq    $3, 8, $3       # E :
+       bge     $2, $do_wh64_w  # U :
+
+       nop
+       nop
+       nop
+       beq     $3, no_quad_w   # U : Might have finished already
+
+.align 4
+       /*
+        * Simple loop for trailing quadwords, or for small amounts
+        * of data (where we can't use an unrolled loop and wh64)
+        */
+loop_w:
+       stq $17,0($5)           # L :
+       subq $3,1,$3            # E : Decrement number quads left
+       addq $5,8,$5            # E : Inc address
+       bne $3,loop_w           # U : more?
+
+no_quad_w:
+       /*
+        * Write 0..7 trailing bytes.
+        */
+       nop                     # E :
+       beq $18,end_w           # U : All done?
+       ldq $7,0($5)            # L :
+       mskqh $7,$6,$2          # U : Mask final quad
+
+       insqh $17,$6,$4         # U : New bits
+       bis $2,$4,$1            # E : Put it all together
+       stq $1,0($5)            # L : And back to memory
+       ret $31,($26),1         # L0 :
+
+within_quad_w:
+       ldq_u $1,0($16)         # L :
+       insql $17,$16,$2        # U : New bits
+       mskql $1,$16,$4         # U : Clear old
+       bis $2,$4,$2            # E : New result
+
+       mskql $2,$6,$4          # U :
+       mskqh $1,$6,$2          # U :
+       bis $2,$4,$1            # E :
+       stq_u $1,0($16)         # L :
+
+end_w:
+       nop
+       nop
+       nop
+       ret $31,($26),1         # L0 :
+
+       .end __memsetw
diff --git a/arch/alpha/lib/ev6-strcpy.S b/arch/alpha/lib/ev6-strcpy.S
deleted file mode 100644 (file)
index 8a6673d..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/alpha/lib/strcpy.S
- * Contributed by Richard Henderson (rth@tamu.edu)
- *
- * Copy a null-terminated string from SRC to DST.  Return a pointer
- * to the null-terminator in the source.
- */
-
-       .text
-
-       .align 4
-       .globl strcpy
-       .ent strcpy
-strcpy:
-       .frame $30, 0, $26
-       .prologue 0
-
-       mov     $16, $0         # set up return value
-       mov     $26, $23        # set up return address
-       br      __stxcpy        # do the copy
-       nop
-
-       .end strcpy
diff --git a/arch/alpha/lib/ev6-strncpy.S b/arch/alpha/lib/ev6-strncpy.S
deleted file mode 100644 (file)
index 053146b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/alpha/lib/strncpy.S
- * Contributed by Richard Henderson (rth@tamu.edu)
- *
- * Copy no more than COUNT bytes of the null-terminated string from
- * SRC to DST.  If SRC does not cover all of COUNT, the balance is
- * zeroed.
- *
- * Or, rather, if the kernel cared about that weird ANSI quirk.  This
- * version has cropped that bit o' nastiness as well as assuming that
- * __stxncpy is in range of a branch.
- */
-
-       .set noat
-       .set noreorder
-
-       .text
-
-       .align 4
-       .globl strncpy
-       .ent strncpy
-strncpy:
-       .frame $30, 0, $26
-       .prologue 0
-
-       mov     $16, $0         # set return value now
-       beq     $18, 0f
-       mov     $26, $23        # set return address
-       br      __stxncpy       # do the work of the copy
-
-0:     ret
-       nop
-       nop
-       nop
-
-       .end strncpy
diff --git a/arch/alpha/lib/ev6-stxcpy.S b/arch/alpha/lib/ev6-stxcpy.S
new file mode 100644 (file)
index 0000000..f5b409e
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * arch/alpha/lib/ev6-stxcpy.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * Copy a null-terminated string from SRC to DST.
+ *
+ * This is an internal routine used by strcpy, stpcpy, and strcat.
+ * As such, it uses special linkage conventions to make implementation
+ * of these public functions more efficient.
+ *
+ * On input:
+ *     t9 = return address
+ *     a0 = DST
+ *     a1 = SRC
+ *
+ * On output:
+ *     t12 = bitmask (with one bit set) indicating the last byte written
+ *     a0  = unaligned address of the last *word* written
+ *
+ * Furthermore, v0, a3-a5, t11, and t12 are untouched.
+ *
+ * Much of the information about 21264 scheduling/coding comes from:
+ *     Compiler Writer's Guide for the Alpha 21264
+ *     abbreviated as 'CWG' in other comments here
+ *     ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
+ * Scheduling notation:
+ *     E       - either cluster
+ *     U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
+ *     L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
+ * Try not to change the actual algorithm if possible for consistency.
+ */
+
+#include <alpha/regdef.h>
+
+       .set noat
+       .set noreorder
+
+       .text
+
+/* There is a problem with either gdb (as of 4.16) or gas (as of 2.7) that
+   doesn't like putting the entry point for a procedure somewhere in the
+   middle of the procedure descriptor.  Work around this by putting the
+   aligned copy in its own procedure descriptor */
+
+
+       .ent stxcpy_aligned
+       .align 4
+stxcpy_aligned:
+       .frame sp, 0, t9
+       .prologue 0
+
+       /* On entry to this basic block:
+          t0 == the first destination word for masking back in
+          t1 == the first source word.  */
+
+       /* Create the 1st output word and detect 0's in the 1st input word.  */
+       lda     t2, -1          # E : build a mask against false zero
+       mskqh   t2, a1, t2      # U :   detection in the src word (stall)
+       mskqh   t1, a1, t3      # U :
+       ornot   t1, t2, t2      # E : (stall)
+
+       mskql   t0, a1, t0      # U : assemble the first output word
+       cmpbge  zero, t2, t8    # E : bits set iff null found
+       or      t0, t3, t1      # E : (stall)
+       bne     t8, $a_eos      # U : (stall)
+
+       /* On entry to this basic block:
+          t0 == the first destination word for masking back in
+          t1 == a source word not containing a null.  */
+       /* Nops here to separate store quads from load quads */
+
+$a_loop:
+       stq_u   t1, 0(a0)       # L :
+       addq    a0, 8, a0       # E :
+       nop
+       nop
+
+       ldq_u   t1, 0(a1)       # L : Latency=3
+       addq    a1, 8, a1       # E :
+       cmpbge  zero, t1, t8    # E : (3 cycle stall)
+       beq     t8, $a_loop     # U : (stall for t8)
+
+       /* Take care of the final (partial) word store.
+          On entry to this basic block we have:
+          t1 == the source word containing the null
+          t8 == the cmpbge mask that found it.  */
+$a_eos:
+       negq    t8, t6          # E : find low bit set
+       and     t8, t6, t12     # E : (stall)
+       /* For the sake of the cache, don't read a destination word
+          if we're not going to need it.  */
+       and     t12, 0x80, t6   # E : (stall)
+       bne     t6, 1f          # U : (stall)
+
+       /* We're doing a partial word store and so need to combine
+          our source and original destination words.  */
+       ldq_u   t0, 0(a0)       # L : Latency=3
+       subq    t12, 1, t6      # E :
+       zapnot  t1, t6, t1      # U : clear src bytes >= null (stall)
+       or      t12, t6, t8     # E : (stall)
+
+       zap     t0, t8, t0      # E : clear dst bytes <= null
+       or      t0, t1, t1      # E : (stall)
+       nop
+       nop
+
+1:     stq_u   t1, 0(a0)       # L :
+       ret     (t9)            # L0 : Latency=3
+       nop
+       nop
+
+       .end stxcpy_aligned
+
+       .align 4
+       .ent __stxcpy
+       .globl __stxcpy
+__stxcpy:
+       .frame sp, 0, t9
+       .prologue 0
+
+       /* Are source and destination co-aligned?  */
+       xor     a0, a1, t0      # E :
+       unop                    # E :
+       and     t0, 7, t0       # E : (stall)
+       bne     t0, $unaligned  # U : (stall)
+
+       /* We are co-aligned; take care of a partial first word.  */
+       ldq_u   t1, 0(a1)               # L : load first src word
+       and     a0, 7, t0               # E : take care not to load a word ...
+       addq    a1, 8, a1               # E :
+       beq     t0, stxcpy_aligned      # U : ... if we wont need it (stall)
+
+       ldq_u   t0, 0(a0)       # L :
+       br      stxcpy_aligned  # L0 : Latency=3
+       nop
+       nop
+
+
+/* The source and destination are not co-aligned.  Align the destination
+   and cope.  We have to be very careful about not reading too much and
+   causing a SEGV.  */
+
+       .align 4
+$u_head:
+       /* We know just enough now to be able to assemble the first
+          full source word.  We can still find a zero at the end of it
+          that prevents us from outputting the whole thing.
+
+          On entry to this basic block:
+          t0 == the first dest word, for masking back in, if needed else 0
+          t1 == the low bits of the first source word
+          t6 == bytemask that is -1 in dest word bytes */
+
+       ldq_u   t2, 8(a1)       # L :
+       addq    a1, 8, a1       # E :
+       extql   t1, a1, t1      # U : (stall on a1)
+       extqh   t2, a1, t4      # U : (stall on a1)
+
+       mskql   t0, a0, t0      # U :
+       or      t1, t4, t1      # E :
+       mskqh   t1, a0, t1      # U : (stall on t1)
+       or      t0, t1, t1      # E : (stall on t1)
+
+       or      t1, t6, t6      # E :
+       cmpbge  zero, t6, t8    # E : (stall)
+       lda     t6, -1          # E : for masking just below
+       bne     t8, $u_final    # U : (stall)
+
+       mskql   t6, a1, t6              # U : mask out the bits we have
+       or      t6, t2, t2              # E :   already extracted before (stall)
+       cmpbge  zero, t2, t8            # E :   testing eos (stall)
+       bne     t8, $u_late_head_exit   # U : (stall)
+
+       /* Finally, we've got all the stupid leading edge cases taken care
+          of and we can set up to enter the main loop.  */
+
+       stq_u   t1, 0(a0)       # L : store first output word
+       addq    a0, 8, a0       # E :
+       extql   t2, a1, t0      # U : position ho-bits of lo word
+       ldq_u   t2, 8(a1)       # U : read next high-order source word
+
+       addq    a1, 8, a1       # E :
+       cmpbge  zero, t2, t8    # E : (stall for t2)
+       nop                     # E :
+       bne     t8, $u_eos      # U : (stall)
+
+       /* Unaligned copy main loop.  In order to avoid reading too much,
+          the loop is structured to detect zeros in aligned source words.
+          This has, unfortunately, effectively pulled half of a loop
+          iteration out into the head and half into the tail, but it does
+          prevent nastiness from accumulating in the very thing we want
+          to run as fast as possible.
+
+          On entry to this basic block:
+          t0 == the shifted high-order bits from the previous source word
+          t2 == the unshifted current source word
+
+          We further know that t2 does not contain a null terminator.  */
+
+       .align 3
+$u_loop:
+       extqh   t2, a1, t1      # U : extract high bits for current word
+       addq    a1, 8, a1       # E : (stall)
+       extql   t2, a1, t3      # U : extract low bits for next time (stall)
+       addq    a0, 8, a0       # E :
+
+       or      t0, t1, t1      # E : current dst word now complete
+       ldq_u   t2, 0(a1)       # L : Latency=3 load high word for next time
+       stq_u   t1, -8(a0)      # L : save the current word (stall)
+       mov     t3, t0          # E :
+
+       cmpbge  zero, t2, t8    # E : test new word for eos
+       beq     t8, $u_loop     # U : (stall)
+       nop
+       nop
+
+       /* We've found a zero somewhere in the source word we just read.
+          If it resides in the lower half, we have one (probably partial)
+          word to write out, and if it resides in the upper half, we
+          have one full and one partial word left to write out.
+
+          On entry to this basic block:
+          t0 == the shifted high-order bits from the previous source word
+          t2 == the unshifted current source word.  */
+$u_eos:
+       extqh   t2, a1, t1      # U :
+       or      t0, t1, t1      # E : first (partial) source word complete (stall)
+       cmpbge  zero, t1, t8    # E : is the null in this first bit? (stall)
+       bne     t8, $u_final    # U : (stall)
+
+$u_late_head_exit:
+       stq_u   t1, 0(a0)       # L : the null was in the high-order bits
+       addq    a0, 8, a0       # E :
+       extql   t2, a1, t1      # U :
+       cmpbge  zero, t1, t8    # E : (stall)
+
+       /* Take care of a final (probably partial) result word.
+          On entry to this basic block:
+          t1 == assembled source word
+          t8 == cmpbge mask that found the null.  */
+$u_final:
+       negq    t8, t6          # E : isolate low bit set
+       and     t6, t8, t12     # E : (stall)
+       and     t12, 0x80, t6   # E : avoid dest word load if we can (stall)
+       bne     t6, 1f          # U : (stall)
+
+       ldq_u   t0, 0(a0)       # E :
+       subq    t12, 1, t6      # E :
+       or      t6, t12, t8     # E : (stall)
+       zapnot  t1, t6, t1      # U : kill source bytes >= null (stall)
+
+       zap     t0, t8, t0      # U : kill dest bytes <= null (2 cycle data stall)
+       or      t0, t1, t1      # E : (stall)
+       nop
+       nop
+
+1:     stq_u   t1, 0(a0)       # L :
+       ret     (t9)            # L0 : Latency=3
+       nop
+       nop
+
+       /* Unaligned copy entry point.  */
+       .align 4
+$unaligned:
+
+       ldq_u   t1, 0(a1)       # L : load first source word
+       and     a0, 7, t4       # E : find dest misalignment
+       and     a1, 7, t5       # E : find src misalignment
+       /* Conditionally load the first destination word and a bytemask
+          with 0xff indicating that the destination byte is sacrosanct.  */
+       mov     zero, t0        # E :
+
+       mov     zero, t6        # E :
+       beq     t4, 1f          # U :
+       ldq_u   t0, 0(a0)       # L :
+       lda     t6, -1          # E :
+
+       mskql   t6, a0, t6      # U :
+       nop
+       nop
+       nop
+1:
+       subq    a1, t4, a1      # E : sub dest misalignment from src addr
+       /* If source misalignment is larger than dest misalignment, we need
+          extra startup checks to avoid SEGV.  */
+       cmplt   t4, t5, t12     # E :
+       beq     t12, $u_head    # U :
+       lda     t2, -1          # E : mask out leading garbage in source
+
+       mskqh   t2, t5, t2      # U :
+       ornot   t1, t2, t3      # E : (stall)
+       cmpbge  zero, t3, t8    # E : is there a zero? (stall)
+       beq     t8, $u_head     # U : (stall)
+
+       /* At this point we've found a zero in the first partial word of
+          the source.  We need to isolate the valid source data and mask
+          it into the original destination data.  (Incidentally, we know
+          that we'll need at least one byte of that original dest word.) */
+
+       ldq_u   t0, 0(a0)       # L :
+       negq    t8, t6          # E : build bitmask of bytes <= zero
+       and     t6, t8, t12     # E : (stall)
+       and     a1, 7, t5       # E :
+
+       subq    t12, 1, t6      # E :
+       or      t6, t12, t8     # E : (stall)
+       srl     t12, t5, t12    # U : adjust final null return value
+       zapnot  t2, t8, t2      # U : prepare source word; mirror changes (stall)
+
+       and     t1, t2, t1      # E : to source validity mask
+       extql   t2, a1, t2      # U :
+       extql   t1, a1, t1      # U : (stall)
+       andnot  t0, t2, t0      # .. e1 : zero place for source to reside (stall)
+
+       or      t0, t1, t1      # e1    : and put it there
+       stq_u   t1, 0(a0)       # .. e0 : (stall)
+       ret     (t9)            # e1    :
+       nop
+
+       .end __stxcpy
+
diff --git a/arch/alpha/lib/ev6-stxncpy.S b/arch/alpha/lib/ev6-stxncpy.S
new file mode 100644 (file)
index 0000000..7848b4c
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * arch/alpha/lib/ev6-stxncpy.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
+ *
+ * Copy no more than COUNT bytes of the null-terminated string from
+ * SRC to DST.
+ *
+ * This is an internal routine used by strncpy, stpncpy, and strncat.
+ * As such, it uses special linkage conventions to make implementation
+ * of these public functions more efficient.
+ *
+ * On input:
+ *     t9 = return address
+ *     a0 = DST
+ *     a1 = SRC
+ *     a2 = COUNT
+ *
+ * Furthermore, COUNT may not be zero.
+ *
+ * On output:
+ *     t0  = last word written
+ *     t10 = bitmask (with one bit set) indicating the byte position of
+ *           the end of the range specified by COUNT
+ *     t12 = bitmask (with one bit set) indicating the last byte written
+ *     a0  = unaligned address of the last *word* written
+ *     a2  = the number of full words left in COUNT
+ *
+ * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ *
+ * Much of the information about 21264 scheduling/coding comes from:
+ *     Compiler Writer's Guide for the Alpha 21264
+ *     abbreviated as 'CWG' in other comments here
+ *     ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
+ * Scheduling notation:
+ *     E       - either cluster
+ *     U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
+ *     L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
+ * Try not to change the actual algorithm if possible for consistency.
+ */
+
+#include <alpha/regdef.h>
+
+       .set noat
+       .set noreorder
+
+       .text
+
+/* There is a problem with either gdb (as of 4.16) or gas (as of 2.7) that
+   doesn't like putting the entry point for a procedure somewhere in the
+   middle of the procedure descriptor.  Work around this by putting the
+   aligned copy in its own procedure descriptor */
+
+
+       .ent stxncpy_aligned
+       .align 4
+stxncpy_aligned:
+       .frame sp, 0, t9, 0
+       .prologue 0
+
+       /* On entry to this basic block:
+          t0 == the first destination word for masking back in
+          t1 == the first source word.  */
+
+       /* Create the 1st output word and detect 0's in the 1st input word.  */
+       lda     t2, -1          # E : build a mask against false zero
+       mskqh   t2, a1, t2      # U :   detection in the src word (stall)
+       mskqh   t1, a1, t3      # U :
+       ornot   t1, t2, t2      # E : (stall)
+
+       mskql   t0, a1, t0      # U : assemble the first output word
+       cmpbge  zero, t2, t8    # E : bits set iff null found
+       or      t0, t3, t0      # E : (stall)
+       beq     a2, $a_eoc      # U :
+
+       bne     t8, $a_eos      # U :
+       nop
+       nop
+       nop
+
+       /* On entry to this basic block:
+          t0 == a source word not containing a null.  */
+
+       /*
+        * nops here to:
+        *      separate store quads from load quads
+        *      limit of 1 bcond/quad to permit training
+        */
+$a_loop:
+       stq_u   t0, 0(a0)       # L :
+       addq    a0, 8, a0       # E :
+       subq    a2, 1, a2       # E :
+       nop
+
+       ldq_u   t0, 0(a1)       # L :
+       addq    a1, 8, a1       # E :
+       cmpbge  zero, t0, t8    # E :
+       beq     a2, $a_eoc      # U :
+
+       beq     t8, $a_loop     # U :
+       nop
+       nop
+       nop
+
+       /* Take care of the final (partial) word store.  At this point
+          the end-of-count bit is set in t8 iff it applies.
+
+          On entry to this basic block we have:
+          t0 == the source word containing the null
+          t8 == the cmpbge mask that found it.  */
+
+$a_eos:
+       negq    t8, t12         # E : find low bit set
+       and     t8, t12, t12    # E : (stall)
+       /* For the sake of the cache, don't read a destination word
+          if we're not going to need it.  */
+       and     t12, 0x80, t6   # E : (stall)
+       bne     t6, 1f          # U : (stall)
+
+       /* We're doing a partial word store and so need to combine
+          our source and original destination words.  */
+       ldq_u   t1, 0(a0)       # L :
+       subq    t12, 1, t6      # E :
+       or      t12, t6, t8     # E : (stall)
+       zapnot  t0, t8, t0      # U : clear src bytes > null (stall)
+
+       zap     t1, t8, t1      # .. e1 : clear dst bytes <= null
+       or      t0, t1, t0      # e1    : (stall)
+       nop
+       nop
+
+1:     stq_u   t0, 0(a0)       # L :
+       ret     (t9)            # L0 : Latency=3
+       nop
+       nop
+
+       /* Add the end-of-count bit to the eos detection bitmask.  */
+$a_eoc:
+       or      t10, t8, t8     # E :
+       br      $a_eos          # L0 : Latency=3
+       nop
+       nop
+
+       .end stxncpy_aligned
+
+       .align 4
+       .ent __stxncpy
+       .globl __stxncpy
+__stxncpy:
+       .frame sp, 0, t9, 0
+       .prologue 0
+
+       /* Are source and destination co-aligned?  */
+       xor     a0, a1, t1      # E :
+       and     a0, 7, t0       # E : find dest misalignment
+       and     t1, 7, t1       # E : (stall)
+       addq    a2, t0, a2      # E : bias count by dest misalignment (stall)
+
+       subq    a2, 1, a2       # E :
+       and     a2, 7, t2       # E : (stall)
+       srl     a2, 3, a2       # U : a2 = loop counter = (count - 1)/8 (stall)
+       addq    zero, 1, t10    # E :
+
+       sll     t10, t2, t10    # U : t10 = bitmask of last count byte
+       bne     t1, $unaligned  # U :
+       /* We are co-aligned; take care of a partial first word.  */
+       ldq_u   t1, 0(a1)       # L : load first src word
+       addq    a1, 8, a1       # E :
+
+       beq     t0, stxncpy_aligned     # U : avoid loading dest word if not needed
+       ldq_u   t0, 0(a0)       # L :
+       nop
+       nop
+
+       br      stxncpy_aligned # .. e1 :
+       nop
+       nop
+       nop
+
+
+
+/* The source and destination are not co-aligned.  Align the destination
+   and cope.  We have to be very careful about not reading too much and
+   causing a SEGV.  */
+
+       .align 4
+$u_head:
+       /* We know just enough now to be able to assemble the first
+          full source word.  We can still find a zero at the end of it
+          that prevents us from outputting the whole thing.
+
+          On entry to this basic block:
+          t0 == the first dest word, unmasked
+          t1 == the shifted low bits of the first source word
+          t6 == bytemask that is -1 in dest word bytes */
+
+       ldq_u   t2, 8(a1)       # L : Latency=3 load second src word
+       addq    a1, 8, a1       # E :
+       mskql   t0, a0, t0      # U : mask trailing garbage in dst
+       extqh   t2, a1, t4      # U : (3 cycle stall on t2)
+
+       or      t1, t4, t1      # E : first aligned src word complete (stall)
+       mskqh   t1, a0, t1      # U : mask leading garbage in src (stall)
+       or      t0, t1, t0      # E : first output word complete (stall)
+       or      t0, t6, t6      # E : mask original data for zero test (stall)
+
+       cmpbge  zero, t6, t8    # E :
+       beq     a2, $u_eocfin   # U :
+       nop
+       nop
+
+       bne     t8, $u_final    # U :
+       lda     t6, -1          # E : mask out the bits we have
+       mskql   t6, a1, t6      # U :   already seen (stall)
+       stq_u   t0, 0(a0)       # L : store first output word
+
+       or      t6, t2, t2              # E :
+       cmpbge  zero, t2, t8            # E : find nulls in second partial (stall)
+       addq    a0, 8, a0               # E :
+       subq    a2, 1, a2               # E :
+
+       bne     t8, $u_late_head_exit   # U :
+       /* Finally, we've got all the stupid leading edge cases taken care
+          of and we can set up to enter the main loop.  */
+       extql   t2, a1, t1      # U : position hi-bits of lo word
+       ldq_u   t2, 8(a1)       # L : read next high-order source word
+       addq    a1, 8, a1       # E :
+
+       cmpbge  zero, t2, t8    # E : (stall)
+       beq     a2, $u_eoc      # U :
+       nop
+       nop
+
+       bne     t8, $u_eos      # e1    :
+       nop
+       nop
+       nop
+
+       /* Unaligned copy main loop.  In order to avoid reading too much,
+          the loop is structured to detect zeros in aligned source words.
+          This has, unfortunately, effectively pulled half of a loop
+          iteration out into the head and half into the tail, but it does
+          prevent nastiness from accumulating in the very thing we want
+          to run as fast as possible.
+
+          On entry to this basic block:
+          t1 == the shifted high-order bits from the previous source word
+          t2 == the unshifted current source word
+
+          We further know that t2 does not contain a null terminator.  */
+
+       .align 4
+$u_loop:
+       extqh   t2, a1, t0      # U : extract high bits for current word
+       addq    a1, 8, a1       # E :
+       extql   t2, a1, t3      # U : extract low bits for next time
+       addq    a0, 8, a0       # E :
+
+       or      t0, t1, t0      # E : current dst word now complete
+       ldq_u   t2, 0(a1)       # U : Latency=3 load high word for next time
+       stq_u   t0, -8(a0)      # U : save the current word (stall)
+       mov     t3, t1          # E :
+
+       subq    a2, 1, a2       # E :
+       cmpbge  zero, t2, t8    # E : test new word for eos (2 cycle stall for data)
+       beq     a2, $u_eoc      # U : (stall)
+       nop
+
+       beq     t8, $u_loop     # U :
+       nop
+       nop
+       nop
+
+       /* We've found a zero somewhere in the source word we just read.
+          If it resides in the lower half, we have one (probably partial)
+          word to write out, and if it resides in the upper half, we
+          have one full and one partial word left to write out.
+
+          On entry to this basic block:
+          t1 == the shifted high-order bits from the previous source word
+          t2 == the unshifted current source word.  */
+$u_eos:
+       extqh   t2, a1, t0      # U :
+       or      t0, t1, t0      # E : first (partial) source word complete (stall)
+       cmpbge  zero, t0, t8    # E : is the null in this first bit? (stall)
+       bne     t8, $u_final    # U : (stall)
+
+       stq_u   t0, 0(a0)       # L : the null was in the high-order bits
+       addq    a0, 8, a0       # E :
+       subq    a2, 1, a2       # E :
+       nop
+
+$u_late_head_exit:
+       extql   t2, a1, t0      # U :
+       cmpbge  zero, t0, t8    # E :
+       or      t8, t10, t6     # E : (stall)
+       cmoveq  a2, t6, t8      # E : Latency=2, extra map slot (stall)
+
+       /* Take care of a final (probably partial) result word.
+          On entry to this basic block:
+          t0 == assembled source word
+          t8 == cmpbge mask that found the null.  */
+$u_final:
+       negq    t8, t6          # E : isolate low bit set
+       and     t6, t8, t12     # E : (stall)
+       and     t12, 0x80, t6   # E : avoid dest word load if we can (stall)
+       bne     t6, 1f          # U : (stall)
+
+       ldq_u   t1, 0(a0)       # L :
+       subq    t12, 1, t6      # E :
+       or      t6, t12, t8     # E : (stall)
+       zapnot  t0, t8, t0      # U : kill source bytes > null
+
+       zap     t1, t8, t1      # U : kill dest bytes <= null
+       or      t0, t1, t0      # E : (stall)
+       nop
+       nop
+
+1:     stq_u   t0, 0(a0)       # L :
+       ret     (t9)            # L0 : Latency=3
+
+$u_eoc:                                # end-of-count
+       extqh   t2, a1, t0      # U :
+       or      t0, t1, t0      # E : (stall)
+       cmpbge  zero, t0, t8    # E : (stall)
+       nop
+
+$u_eocfin:                     # end-of-count, final word
+       or      t10, t8, t8     # E :
+       br      $u_final        # L0 : Latency=3
+       nop
+       nop
+
+       /* Unaligned copy entry point.  */
+       .align 4
+$unaligned:
+
+       ldq_u   t1, 0(a1)       # L : load first source word
+       and     a0, 7, t4       # E : find dest misalignment
+       and     a1, 7, t5       # E : find src misalignment
+       /* Conditionally load the first destination word and a bytemask
+          with 0xff indicating that the destination byte is sacrosanct.  */
+       mov     zero, t0        # E :
+
+       mov     zero, t6        # E :
+       beq     t4, 1f          # U :
+       ldq_u   t0, 0(a0)       # L :
+       lda     t6, -1          # E :
+
+       mskql   t6, a0, t6      # U :
+       nop
+       nop
+       nop
+1:
+       subq    a1, t4, a1      # E : sub dest misalignment from src addr
+
+       /* If source misalignment is larger than dest misalignment, we need
+          extra startup checks to avoid SEGV.  */
+
+       cmplt   t4, t5, t12     # E :
+       extql   t1, a1, t1      # U : shift src into place
+       lda     t2, -1          # E : for creating masks later
+       beq     t12, $u_head    # U : (stall)
+
+       mskqh   t2, t5, t2      # U : begin src byte validity mask
+       cmpbge  zero, t1, t8    # E : is there a zero?
+       extql   t2, a1, t2      # U :
+       or      t8, t10, t5     # E : test for end-of-count too
+
+       cmpbge  zero, t2, t3    # E :
+       cmoveq  a2, t5, t8      # E : Latency=2, extra map slot
+       nop                     # E : keep with cmoveq
+       andnot  t8, t3, t8      # E : (stall)
+
+       beq     t8, $u_head     # U :
+       /* At this point we've found a zero in the first partial word of
+          the source.  We need to isolate the valid source data and mask
+          it into the original destination data.  (Incidentally, we know
+          that we'll need at least one byte of that original dest word.) */
+       ldq_u   t0, 0(a0)       # L :
+       negq    t8, t6          # E : build bitmask of bytes <= zero
+       mskqh   t1, t4, t1      # U :
+
+       and     t6, t8, t12     # E :
+       subq    t12, 1, t6      # E : (stall)
+       or      t6, t12, t8     # E : (stall)
+       zapnot  t2, t8, t2      # U : prepare source word; mirror changes (stall)
+
+       zapnot  t1, t8, t1      # U : to source validity mask
+       andnot  t0, t2, t0      # E : zero place for source to reside
+       or      t0, t1, t0      # E : and put it there (stall both t0, t1)
+       stq_u   t0, 0(a0)       # L : (stall)
+
+       ret     (t9)            # L0 : Latency=3
+       nop
+       nop
+       nop
+
+       .end __stxncpy
+
index b817f82a0c73cf710f6c7d7f7782d94a0c2a14df..03c56d583bd61be900c6c226a27654c1e79687c6 100644 (file)
@@ -55,9 +55,9 @@ strchr:
        or      t2, t3, t0      # E : bits set iff char match or zero match
 
        andnot  t0, t4, t0      # E : clear garbage bits
-       cttz    t3, a2          # U0 : speculative (in case we get a match)
+       cttz    t0, a2          # U0 : speculative (in case we get a match)
        nop                     # E :
-       bne     t0, $found      # U : Stall on t0
+       bne     t0, $found      # U :
 
        /*
         * Yuk.  This loop is going to stall like crazy waiting for the
index d715f02195c3265fb65b48a163cfb6ddd5d11e60..64083fc732389419aa55e499532a278af4f8adab 100644 (file)
@@ -161,24 +161,3 @@ void * memcpy(void * dest, const void *src, size_t n)
 
 /* For backward modules compatibility, define __memcpy.  */
 asm("__memcpy = memcpy; .globl __memcpy");
-
-void *memmove (void *dest, const void *src, size_t n)
-{
-       if (dest <= src) {
-               if (!(((unsigned long) dest ^ (unsigned long) src) & 7))
-                       __memcpy_aligned_up ((unsigned long) dest,
-                                            (unsigned long) src, n);
-               else
-                       __memcpy_unaligned_up ((unsigned long) dest,
-                                              (unsigned long) src, n);
-       }
-       else {
-               if (!(((unsigned long) dest ^ (unsigned long) src) & 7))
-                       __memcpy_aligned_dn ((unsigned long) dest,
-                                            (unsigned long) src, n);
-               else
-                       __memcpy_unaligned_dn ((unsigned long) dest,
-                                              (unsigned long) src, n);
-       }
-       return dest;
-}
diff --git a/arch/alpha/lib/memmove.S b/arch/alpha/lib/memmove.S
new file mode 100644 (file)
index 0000000..3c8567e
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * arch/alpha/lib/memmove.S
+ *
+ * Barely optimized memmove routine for Alpha EV5.
+ *
+ * This is hand-massaged output from the original memcpy.c.  We defer to
+ * memcpy whenever possible; the backwards copy loops are not unrolled.
+ */
+        
+       .set noat
+       .set noreorder
+       .text
+
+       .align 4
+       .globl memmove
+       .ent memmove
+memmove:
+       addq $16,$18,$4
+       addq $17,$18,$5
+       cmpule $4,$17,$1                /*  dest + n <= src  */
+       cmpule $5,$16,$2                /*  dest >= src + n  */
+
+       bis $1,$2,$1
+       mov $16,$0
+       xor $16,$17,$2
+       bne $1,memcpy
+
+       and $2,7,$2                     /* Test for src/dest co-alignment.  */
+       bne $2,$misaligned
+
+       and $4,7,$1
+       beq $1,$skip_aligned_byte_loop_head
+
+$aligned_byte_loop_head:
+       lda $4,-1($4)
+       lda $5,-1($5)
+       unop
+       ble $18,$egress
+
+       ldq_u $3,0($5)
+       ldq_u $2,0($4)
+       lda $18,-1($18)
+       extbl $3,$5,$1
+
+       insbl $1,$4,$1
+       mskbl $2,$4,$2
+       bis $1,$2,$1
+       and $4,7,$6
+
+       stq_u $1,0($4)
+       bne $6,$aligned_byte_loop_head
+
+$skip_aligned_byte_loop_head:
+       lda $18,-8($18)
+       blt $18,$skip_aligned_word_loop
+
+$aligned_word_loop:
+       ldq $1,-8($5)
+       nop
+       lda $5,-8($5)
+       lda $18,-8($18)
+
+       stq $1,-8($4)
+       nop
+       lda $4,-8($4)
+       bge $18,$aligned_word_loop
+
+$skip_aligned_word_loop:
+       lda $18,8($18)
+       bgt $18,$byte_loop_tail
+       unop
+       ret $31,($26),1
+
+       .align 4
+$misaligned:
+       nop
+       fnop
+       unop
+       beq $18,$egress
+
+$byte_loop_tail:
+       ldq_u $3,-1($5)
+       ldq_u $2,-1($4)
+       lda $5,-1($5)
+       lda $4,-1($4)
+
+       lda $18,-1($18)
+       extbl $3,$5,$1
+       insbl $1,$4,$1
+       mskbl $2,$4,$2
+
+       bis $1,$2,$1
+       stq_u $1,0($4)
+       nop
+       bgt $18,$byte_loop_tail
+
+$egress:
+       ret $31,($26),1
+       nop
+       nop
+       nop
+
+       .end memmove
index dd21b5208f27e03a22188d1d8c686bd5adc354d7..e0728e4ad21fda604b166c9435637bd9c5af11fe 100644 (file)
@@ -17,6 +17,7 @@ strcpy:
 
        mov     $16, $0         # set up return value
        mov     $26, $23        # set up return address
+       unop
        br      __stxcpy        # do the copy
 
        .end strcpy
index dbc011c34a30478b5538c40cf5986bf43eab6e2e..7d64d21d5af35b80eca2544e653b1e578dfe6b5b 100644 (file)
@@ -27,6 +27,10 @@ strncpy:
        beq     $18, 0f
        mov     $26, $23        # set return address
        br      __stxncpy       # do the work of the copy
+
 0:     ret
+       nop
+       nop
+       nop
 
        .end strncpy
index b7b9da4829b6b4990470336ffb3e6b7ee6e233d7..5a427634d8253325f07a703d83910475502cb512 100644 (file)
@@ -1,4 +1,5 @@
-/* stxcpy.S
+/*
+ * arch/alpha/lib/stxcpy.S
  * Contributed by Richard Henderson (rth@tamu.edu)
  *
  * Copy a null-terminated string from SRC to DST.
index 5bab622e0134b01269e50fddb0789f52255ab765..d7cddb074fb20da2d26aea6b2e836dd7cae90a22 100644 (file)
@@ -1,4 +1,5 @@
-/* stxncpy.S
+/*
+ * arch/alpha/lib/stxncpy.S
  * Contributed by Richard Henderson (rth@tamu.edu)
  *
  * Copy no more than COUNT bytes of the null-terminated string from
index d6c63a8b83e7eb0a0c5b02a21804525e3fbceb9f..87fc106f87a75619d9f178e78b8d2fa33f1f5403 100644 (file)
@@ -140,7 +140,7 @@ if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
 fi
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
 
-tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE
 tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
 tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
 
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
new file mode 100644 (file)
index 0000000..b439568
--- /dev/null
@@ -0,0 +1,182 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/apm_bios.h>
+#include <asm/io.h>
+
+struct dmi_header
+{
+       u8      type;
+       u8      length;
+       u16     handle;
+};
+
+static char * __init dmi_string(struct dmi_header *dm, u8 s)
+{
+       u8 *bp=(u8 *)dm;
+       bp+=dm->length;
+       s--;
+       while(s>0)
+       {
+               bp+=strlen(bp);
+               bp++;
+               s--;
+       }
+       return bp;
+}
+
+static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
+{
+       u8 *buf;
+       struct dmi_header *dm;
+       u8 *data;
+       int i=1;
+       int last = 0;   
+               
+       buf = ioremap(base, len);
+       if(buf==NULL)
+               return -1;
+
+       data = buf;
+       while(i<num && (data - buf) < len)
+       {
+               dm=(struct dmi_header *)data;
+               if(dm->type < last)
+                       break;
+               last = dm->type;
+               decode(dm);             
+               data+=dm->length;
+               while(*data || data[1])
+                       data++;
+               data+=2;
+               i++;
+       }
+       iounmap(buf);
+       return 0;
+}
+
+
+int __init dmi_iterate(void (*decode)(struct dmi_header *))
+{
+       unsigned char buf[20];
+       long fp=0xE0000L;
+       fp -= 16;
+       
+       while( fp < 0xFFFFF)
+       {
+               fp+=16;
+               isa_memcpy_fromio(buf, fp, 20);
+               if(memcmp(buf, "_DMI_", 5)==0)
+               {
+                       u16 num=buf[13]<<8|buf[12];
+                       u16 len=buf[7]<<8|buf[6];
+                       u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+
+                       printk(KERN_INFO "DMI %d.%d present.\n",
+                               buf[14]>>4, buf[14]&0x0F);
+                       printk(KERN_INFO "%d structures occupying %d bytes.\n",
+                               buf[13]<<8|buf[12],
+                               buf[7]<<8|buf[6]);
+                       printk(KERN_INFO "DMI table at 0x%08X.\n",
+                               buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]);
+                       if(dmi_table(base,len, num, decode)==0)
+                               return 0;
+               }
+       }
+       return -1;
+}
+
+
+/*
+ *     Process a DMI table entry. Right now all we care about are the BIOS
+ *     and machine entries. For 2.4 we should pull the smbus controller info
+ *     out of here.
+ */
+
+static void __init dmi_decode(struct dmi_header *dm)
+{
+       u8 *data = (u8 *)dm;
+       char *p;
+       
+       switch(dm->type)
+       {
+               case  0:
+                       p=dmi_string(dm,data[4]);
+
+                       if(*p && *p!=' ')
+                       {
+                               printk("BIOS Vendor: %s\n", p);
+                               printk("BIOS Version: %s\n", 
+                                       dmi_string(dm, data[5]));
+                               printk("BIOS Release: %s\n",
+                                       dmi_string(dm, data[8]));
+                       }
+                               
+                       /*
+                        *  Check for clue free BIOS implementations who use
+                        *  the following QA technique
+                        *
+                        *      [ Write BIOS Code ]<------
+                        *               |                ^
+                        *      < Does it Compile >----N--
+                        *               |Y               ^
+                        *      < Does it Boot Win98 >-N--
+                        *               |Y
+                        *           [Ship It]
+                        *
+                        *      Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
+                        *      Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
+                        */
+                        
+                       if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0)
+                       {
+                               if(strcmp(dmi_string(dm, data[5]), "A04")==0 
+                                       && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0)
+                               {
+                                       apm_info.get_power_status_broken = 1;
+                                       printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
+                               }
+                       }
+                       break;
+               case 1:
+                       p=dmi_string(dm,data[4]);
+
+                       if(*p && *p!=' ')
+                       {
+                               printk("System Vendor: %s.\n",p);
+                               printk("Product Name: %s.\n",
+                                       dmi_string(dm, data[5]));
+                               printk("Version %s.\n",
+                                       dmi_string(dm, data[6]));
+                               printk("Serial Number %s.\n",
+                                       dmi_string(dm, data[7]));
+                       }
+                       break;
+               case 2:
+                       p=dmi_string(dm,data[4]);
+
+                       if(*p && *p!=' ')
+                       {
+                               printk("Board Vendor: %s.\n",p);
+                               printk("Board Name: %s.\n",
+                               dmi_string(dm, data[5]));
+                               printk("Board Version: %s.\n",
+                                       dmi_string(dm, data[6]));
+                       }
+                       break;
+               case 3:
+                       p=dmi_string(dm,data[8]);
+                       if(*p && *p!=' ')
+                               printk("Asset Tag: %s.\n", p);
+                       break;
+       }
+}
+
+static int __init dmi_scan_machine(void)
+{
+       return dmi_iterate(dmi_decode);
+}
+
+module_init(dmi_scan_machine);
index 5f99254952da4d8bd458f76f948f5810e778411a..f0a88c20e7f3ff2486cd3d14a9c02987b7d0063e 100644 (file)
@@ -4,13 +4,13 @@
  *     Copyright (C) 2000 Tigran Aivazian
  *
  *     This driver allows to upgrade microcode on Intel processors
- *     belonging to P6 family - PentiumPro, Pentium II, 
- *     Pentium III, Xeon etc.
+ *     belonging to IA-32 family - PentiumPro, Pentium II, 
+ *     Pentium III, Xeon, Pentium 4, etc.
  *
- *     Reference: Section 8.10 of Volume III, Intel Pentium III Manual, 
- *     Order Number 243192 or free download from:
+ *     Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, 
+ *     Order Number 245472 or free download from:
  *             
- *     http://developer.intel.com/design/pentiumii/manuals/243192.htm
+ *     http://developer.intel.com/design/pentium4/manuals/245472.htm
  *
  *     For more information, go to http://www.urbanmyth.org/microcode
  *
@@ -44,6 +44,9 @@
  *             to be 0 on my machine which is why it worked even when I
  *             disabled update by the BIOS)
  *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *                          Tigran Aivazian <tigran@veritas.com>
+ *             Intel Pentium 4 processor support and bugfixes.
  */
 
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#define MICROCODE_VERSION      "1.07"
+#define MICROCODE_VERSION      "1.08"
 
-MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
+MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
 EXPORT_NO_SYMBOLS;
 
+#define MICRO_DEBUG 0
+
+#if MICRO_DEBUG
+#define printf(x...) printk(##x)
+#else
+#define printf(x...)
+#endif
+
 /* VFS interface */
 static int microcode_open(struct inode *, struct file *);
 static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
@@ -81,6 +92,7 @@ static unsigned int microcode_num;  /* number of chunks in microcode */
 static char *mc_applied;            /* array of applied microcode blocks */
 static unsigned int mc_fsize;       /* file size of /dev/cpu/microcode */
 
+/* we share file_operations between misc and devfs mechanisms */
 static struct file_operations microcode_fops = {
        owner:          THIS_MODULE,
        read:           microcode_read,
@@ -99,23 +111,27 @@ static devfs_handle_t devfs_handle;
 
 static int __init microcode_init(void)
 {
-       int error = 0;
+       int error;
 
-       if (misc_register(&microcode_dev) < 0) {
+       error = misc_register(&microcode_dev);
+       if (error)
                printk(KERN_WARNING 
                        "microcode: can't misc_register on minor=%d\n",
                        MICROCODE_MINOR);
-               error = 1;
-       }
+
        devfs_handle = devfs_register(NULL, "cpu/microcode",
                        DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR, 
                        &microcode_fops, NULL);
        if (devfs_handle == NULL && error) {
                printk(KERN_ERR "microcode: failed to devfs_register()\n");
-               return -EINVAL;
+               goto out;
        }
-       printk(KERN_INFO "P6 Microcode Update Driver v%s\n", MICROCODE_VERSION);
-       return 0;
+       printk(KERN_INFO 
+               "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n", 
+               MICROCODE_VERSION);
+
+out:
+       return error;
 }
 
 static void __exit microcode_exit(void)
@@ -124,12 +140,12 @@ static void __exit microcode_exit(void)
        devfs_unregister(devfs_handle);
        if (mc_applied)
                kfree(mc_applied);
-       printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", 
+       printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", 
                        MICROCODE_VERSION);
 }
 
-module_init(microcode_init);
-module_exit(microcode_exit);
+module_init(microcode_init)
+module_exit(microcode_exit)
 
 static int microcode_open(struct inode *unused1, struct file *unused2)
 {
@@ -175,18 +191,19 @@ static void do_update_one(void *unused)
        unsigned int pf = 0, val[2], rev, sig;
        int i,found=0;
 
-       req->err = 1; /* assume the worst */
+       req->err = 1; /* assume update will fail on this cpu */
 
-       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 != 6){
-               printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num);
+       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+               test_bit(X86_FEATURE_IA64, &c->x86_capability)){
+               printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
                return;
        }
 
        sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
 
-       if (c->x86_model >= 5) {
-               /* get processor flags from BBL_CR_OVRD MSR (0x17) */
-               rdmsr(0x17, val[0], val[1]);
+       if ((c->x86_model >= 5) || (c->x86 > 6)) {
+               /* get processor flags from MSR 0x17 */
+               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
                pf = 1 << ((val[1] >> 18) & 7);
        }
 
@@ -195,9 +212,28 @@ static void do_update_one(void *unused)
                    microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
 
                        found=1;
-                       wrmsr(0x8B, 0, 0);
+
+                       printf("Microcode\n");
+                       printf("   Header Revision %d\n",microcode[i].hdrver);
+                       printf("   Date %x/%x/%x\n",
+                               ((microcode[i].date >> 24 ) & 0xff),
+                               ((microcode[i].date >> 16 ) & 0xff),
+                               (microcode[i].date & 0xFFFF));
+                       printf("   Type %x Family %x Model %x Stepping %x\n",
+                               ((microcode[i].sig >> 12) & 0x3),
+                               ((microcode[i].sig >> 8) & 0xf),
+                               ((microcode[i].sig >> 4) & 0xf),
+                               ((microcode[i].sig & 0xf)));
+                       printf("   Checksum %x\n",microcode[i].cksum);
+                       printf("   Loader Revision %x\n",microcode[i].ldrver);
+                       printf("   Processor Flags %x\n\n",microcode[i].pf);
+
+                       /* trick, to work even if there was no prior update by the BIOS */
+                       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
                        __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
-                       rdmsr(0x8B, val[0], rev);
+
+                       /* get current (on-cpu) revision into rev (ignore val[0]) */
+                       rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
                        if (microcode[i].rev < rev) {
                                printk(KERN_ERR 
                                        "microcode: CPU%d not 'upgrading' to earlier revision"
@@ -219,13 +255,20 @@ static void do_update_one(void *unused)
                                        break;
                                }
 
-                               wrmsr(0x79, (unsigned int)(m->bits), 0);
+                               /* write microcode via MSR 0x79 */
+                               wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
+
+                               /* serialize */
                                __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
-                               rdmsr(0x8B, val[0], val[1]);
 
+                               /* get the current revision from MSR 0x8B */
+                               rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+                               /* notify the caller of success on this cpu */
                                req->err = 0;
                                req->slot = i;
-                               printk(KERN_ERR "microcode: CPU%d updated from revision "
+
+                               printk(KERN_INFO "microcode: CPU%d updated from revision "
                                                "%d to %d, date=%08x\n", 
                                                cpu_num, rev, val[1], m->date);
                        }
@@ -239,18 +282,21 @@ static void do_update_one(void *unused)
 
 static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
 {
-       if (*ppos >= mc_fsize)
-               return 0;
+       ssize_t ret = 0;
+
        down_read(&microcode_rwsem);
+       if (*ppos >= mc_fsize)
+               goto out;
        if (*ppos + len > mc_fsize)
                len = mc_fsize - *ppos;
-       if (copy_to_user(buf, mc_applied + *ppos, len)) {
-               up_read(&microcode_rwsem);
-               return -EFAULT;
-       }
+       ret = -EFAULT;
+       if (copy_to_user(buf, mc_applied + *ppos, len))
+               goto out;
        *ppos += len;
+       ret = len;
+out:
        up_read(&microcode_rwsem);
-       return len;
+       return ret;
 }
 
 static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
@@ -267,8 +313,8 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l
                mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
                                GFP_KERNEL);
                if (!mc_applied) {
-                       printk(KERN_ERR "microcode: out of memory for saved microcode\n");
                        up_write(&microcode_rwsem);
+                       printk(KERN_ERR "microcode: out of memory for saved microcode\n");
                        return -ENOMEM;
                }
        }
@@ -307,10 +353,12 @@ static int microcode_ioctl(struct inode *inode, struct file *file,
                case MICROCODE_IOCFREE:
                        down_write(&microcode_rwsem);
                        if (mc_applied) {
+                               int bytes = smp_num_cpus * sizeof(struct microcode);
+
                                devfs_set_file_size(devfs_handle, 0);
                                kfree(mc_applied);
                                mc_applied = NULL;
-                               printk(KERN_INFO "microcode: freed %d bytes\n", mc_fsize);
+                               printk(KERN_INFO "microcode: freed %d bytes\n", bytes);
                                mc_fsize = 0;
                                up_write(&microcode_rwsem);
                                return 0;
index 58984fd080bcb189e61f0e7b2f449c3867f50795..cdf4fc8274880c7a0a2ebd6c2330e4256af13e02 100644 (file)
@@ -298,6 +298,33 @@ static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i
        return 1;
 }
 
+/*
+ * VLSI: nibble offset 0x74 - educated guess due to routing table and
+ *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
+ *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
+ *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
+ *       for the busbridge to the docking station.
+ */
+
+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       if (pirq > 8) {
+               printk("VLSI router pirq escape (%d)\n", pirq);
+               return 0;
+       }
+       return read_config_nybble(router, 0x74, pirq-1);
+}
+
+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       if (pirq > 8) {
+               printk("VLSI router pirq escape (%d)\n", pirq);
+               return 0;
+       }
+       write_config_nybble(router, 0x74, pirq-1, irq);
+       return 1;
+}
+
 #ifdef CONFIG_PCI_BIOS
 
 static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -329,6 +356,7 @@ static struct irq_router pirq_routers[] = {
 
        { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
        { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
+       { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
        { "default", 0, 0, NULL, NULL }
 };
 
@@ -374,7 +402,7 @@ static void __init pirq_find_router(void)
                pirq_router_dev->slot_name);
 }
 
-static struct irq_info *pirq_get_info(struct pci_dev *dev, int pin)
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
 {
        struct irq_routing_table *rt = pirq_table;
        int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
@@ -392,25 +420,28 @@ static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs
 
 static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
 {
+       u8 pin;
        struct irq_info *info;
-       int i, pirq, pin, newirq;
+       int i, pirq, newirq;
        int irq = 0;
        u32 mask;
        struct irq_router *r = pirq_router;
-       struct pci_dev *dev2, *d;
+       struct pci_dev *dev2;
        char *msg = NULL;
 
        if (!pirq_table)
                return 0;
 
        /* Find IRQ routing entry */
-       pin = pci_get_interrupt_pin(dev, &d);
-       if (pin < 0) {
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (!pin) {
                DBG(" -> no interrupt pin\n");
                return 0;
        }
-       DBG("IRQ for %s(%d) via %s", dev->slot_name, pin, d->slot_name);
-       info = pirq_get_info(d, pin);
+       pin = pin - 1;
+       
+       DBG("IRQ for %s:%d", dev->slot_name, pin);
+       info = pirq_get_info(dev);
        if (!info) {
                DBG(" -> not found in routing table\n");
                return 0;
@@ -443,7 +474,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
        DBG(" -> newirq=%d", newirq);
 
        /* Try to get current IRQ */
-       if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) {
+       if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {
                DBG(" -> got IRQ %d\n", irq);
                msg = "Found";
                /* We refuse to override the dev->irq information. Give a warning! */
@@ -453,7 +484,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
                }
        } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
                DBG(" -> assigning IRQ %d", newirq);
-               if (r->set(pirq_router_dev, d, pirq, newirq)) {
+               if (r->set(pirq_router_dev, dev, pirq, newirq)) {
                        eisa_set_level_irq(newirq);
                        DBG(" ... OK\n");
                        msg = "Assigned";
@@ -473,9 +504,14 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
 
        /* Update IRQ for all devices with the same pirq value */
        pci_for_each_dev(dev2) {
-               if ((pin = pci_get_interrupt_pin(dev2, &d)) >= 0 &&
-                   (info = pirq_get_info(d, pin)) &&
-                   info->irq[pin].link == pirq) {
+               pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
+               if (!pin)
+                       continue;
+               pin--;
+               info = pirq_get_info(dev2);
+               if (!info)
+                       continue;
+               if (info->irq[pin].link == pirq) {
                        dev2->irq = irq;
                        pirq_penalty[irq]++;
                        if (dev != dev2)
index 04049be7aa56b6f94fb84058575793ccd8b69c4a..6962cc68ed5bf4b4b011f1c391605539071b2c5e 100644 (file)
@@ -1,9 +1,10 @@
-/* $Id: piggyback.c,v 1.3 2000/03/11 00:22:26 zaitcev Exp $
+/* $Id: piggyback.c,v 1.4 2000/12/05 00:48:57 anton Exp $
    Simple utility to make a single-image install kernel with initial ramdisk
    for Sparc tftpbooting without need to set up nfs.
-   
+
    Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
-   
+   Pete Zaitcev <zaitcev@yahoo.com> endian fixes for cross-compiles, 2000.
+
    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
  * as PROM looks for a.out image only.
  */
 
+unsigned short ld2(char *p)
+{
+       return (p[0] << 8) | p[1];
+}
+
+unsigned int ld4(char *p)
+{
+       return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+void st4(char *p, unsigned int x)
+{
+       p[0] = x >> 24;
+       p[1] = x >> 16;
+       p[2] = x >> 8;
+       p[3] = x;
+}
+
 void usage(void)
 {
        /* fs_img.gz is an image of initial ramdisk. */
@@ -50,7 +69,8 @@ void die(char *str)
 
 int main(int argc,char **argv)
 {
-       char buffer [1024], *q, *r;
+       static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 };
+       unsigned char buffer[1024], *q, *r;
        unsigned int i, j, k, start, end, offset;
        FILE *map;
        struct stat s;
@@ -74,21 +94,20 @@ int main(int argc,char **argv)
        }
        if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]);
        if (read(image,buffer,512) != 512) die(argv[1]);
-       if (!memcmp (buffer, "\177ELF", 4)) {
-               unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28));
-           
-               i = p[1] + *(unsigned int *)(buffer + 24) - p[2];
+       if (memcmp (buffer, "\177ELF", 4) == 0) {
+               q = buffer + ld4(buffer + 28);
+               i = ld4(q + 4) + ld4(buffer + 24) - ld4(q + 8);
                if (lseek(image,i,0) < 0) die("lseek");
                if (read(image,buffer,512) != 512) die(argv[1]);
                j = 0;
-       } else if (*(unsigned int *)buffer == 0x01030107) {
+       } else if (memcmp(buffer, aout_magic, 4) == 0) {
                i = j = 32;
        } else {
                fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n");
                exit(1);
        }
        k = i;
-       i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512;
+       i += (ld2(buffer + j + 2)<<2) - 512;
        if (lseek(image,i,0) < 0) die("lseek");
        if (read(image,buffer,1024) != 1024) die(argv[1]);
        for (q = buffer, r = q + 512; q < r; q += 4) {
@@ -101,10 +120,12 @@ int main(int argc,char **argv)
        }
        offset = i + (q - buffer) + 10;
        if (lseek(image, offset, 0) < 0) die ("lseek");
-       *(unsigned *)buffer = 0;
-       *(unsigned *)(buffer + 4) = 0x01000000;
-       *(unsigned *)(buffer + 8) = ((end + 32 + 4095) & ~4095);
-       *(unsigned *)(buffer + 12) = s.st_size;
+
+       st4(buffer, 0);
+       st4(buffer + 4, 0x01000000);
+       st4(buffer + 8, (end + 32 + 4095) & ~4095);
+       st4(buffer + 12, s.st_size);
+
        if (write(image,buffer+2,14) != 14) die (argv[1]);
        if (lseek(image, k - start + ((end + 32 + 4095) & ~4095), 0) < 0) die ("lseek");
        if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]);
index 2c82f4b22a7f85e75c80524f4784b2061540ccd6..41ef9737ea4eb57e11f186754c96176cc00389c7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.41 2000/11/27 07:46:31 anton Exp $
+/* $Id: ioport.c,v 1.42 2000/12/05 00:56:36 anton Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -586,7 +586,8 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba)
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
+dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
+    int direction)
 {
        if (direction == PCI_DMA_NONE)
                BUG();
index e7b4e96de8a5bd27ea4075d44f9181b95487083c..c9ba85b2704cfc1d5bf5e919073cb4de514ff003 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.19 2000/11/08 04:49:17 davem Exp $
+/* $Id: pcic.c,v 1.20 2000/12/05 00:56:36 anton Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -556,8 +556,8 @@ static void pcic_map_pci_device(struct linux_pcic *pcic,
                                 */
                                printk("PCIC: Skipping I/O space at 0x%lx,"
                                    "this will Oops if a driver attaches;"
-                                   "device '%s' (%x,%x)\n", address, namebuf,
-                                   dev->device, dev->vendor);
+                                   "device '%s' at %02x:%02x)\n", address,
+                                   namebuf, dev->bus->number, dev->devfn);
                        }
                }
        }
@@ -568,12 +568,12 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
 {
        struct pcic_ca2irq *p;
        int i, ivec;
-       char namebuf[64];  /* P3 remove */
+       char namebuf[64];
 
        if (node == 0 || node == -1) {
                strcpy(namebuf, "???");
        } else {
-               prom_getstring(node, "name", namebuf, sizeof(namebuf)); /* P3 remove */
+               prom_getstring(node, "name", namebuf, sizeof(namebuf));
        }
 
        if ((p = pcic->pcic_imap) == 0) {
@@ -612,8 +612,8 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
                if (p->irq == 0 || p->irq >= 15) {      /* Corrupted map */
                        printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {}
                }
-               printk("PCIC: setting irq %x for device (%x,%x)\n",
-                   p->irq, dev->device, dev->vendor);
+               printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n",
+                   p->irq, p->pin, dev->bus->number, dev->devfn);
                dev->irq = p->irq;
 
                i = p->pin;
index 997e4d0ced62a8ea5bb2a74a1c307a7eae66d00f..d9883654e5f949076b5665a469afd10bf2276d22 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.104 2000/09/06 05:43:00 anton Exp $
+/* $Id: sparc_ksyms.c,v 1.105 2000/12/11 05:24:25 anton Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -111,6 +111,11 @@ EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
 EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
 EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
 #endif
+/* semaphores */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__down_interruptible);
 /* rw semaphores */
 EXPORT_SYMBOL_NOVERS(___down_read);
 EXPORT_SYMBOL_NOVERS(___down_write);
index dd011c1430e0c0f05da676f7604df2839ba70d8e..498fdb26f4bf0217c9928a33857f0236a491c1b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.66 2000/07/10 20:57:35 davem Exp $
+/* $Id: sys_sparc.c,v 1.67 2000/11/30 08:37:31 anton Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -34,6 +34,8 @@ asmlinkage unsigned long sys_getpagesize(void)
        return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */
 }
 
+#define COLOUR_ALIGN(addr)      (((addr)+SHMLBA-1)&~(SHMLBA-1))
+
 unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
 {
        struct vm_area_struct * vmm;
@@ -45,7 +47,11 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
                return 0;
        if (!addr)
                addr = TASK_UNMAPPED_BASE;
-       addr = PAGE_ALIGN(addr);
+
+       if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+               addr = COLOUR_ALIGN(addr);
+       else
+               addr = PAGE_ALIGN(addr);
 
        for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
                /* At this point:  (!vmm || addr < vmm->vm_end). */
@@ -58,6 +64,8 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
                if (!vmm || addr + len <= vmm->vm_start)
                        return addr;
                addr = vmm->vm_end;
+               if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+                       addr = COLOUR_ALIGN(addr);
        }
 }
 
@@ -224,10 +232,16 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len,
                goto out_putf;
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+       if (flags & MAP_SHARED)
+               current->thread.flags |= SPARC_FLAG_MMAPSHARED;
+
        down(&current->mm->mmap_sem);
        retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
        up(&current->mm->mmap_sem);
 
+       current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
+
 out_putf:
        if (file)
                fput(file);
@@ -259,6 +273,7 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr,
        unsigned long old_len, unsigned long new_len,
        unsigned long flags, unsigned long new_addr)
 {
+       struct vm_area_struct *vma;
        unsigned long ret = -EINVAL;
        if (ARCH_SUN4C_SUN4) {
                if (old_len > 0x20000000 || new_len > 0x20000000)
@@ -270,6 +285,9 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr,
            new_len > TASK_SIZE - PAGE_SIZE)
                goto out;
        down(&current->mm->mmap_sem);
+       vma = find_vma(current->mm, addr);
+       if (vma && (vma->vm_flags & VM_SHARED))
+               current->thread.flags |= SPARC_FLAG_MMAPSHARED;
        if (flags & MREMAP_FIXED) {
                if (ARCH_SUN4C_SUN4 &&
                    new_addr < 0xe0000000 &&
@@ -290,6 +308,7 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr,
        }
        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
+       current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
        up(&current->mm->mmap_sem);
 out:
        return ret;       
@@ -302,12 +321,10 @@ c_sys_nis_syscall (struct pt_regs *regs)
        static int count = 0;
        
        if (count++ > 5) return -ENOSYS;
-       lock_kernel();
        printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]);
 #ifdef DEBUG_UNIMP_SYSCALL     
        show_regs (regs);
 #endif
-       unlock_kernel();
        return -ENOSYS;
 }
 
index 85161a3a6c6c70834fa13c877c21bfeab39f7697..d27495bd6cefc90f51ab533050625a3f81e1c9d0 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.95 2000/11/10 04:49:56 davem Exp $
+/*  $Id: init.c,v 1.96 2000/11/30 08:51:50 anton Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -579,7 +579,8 @@ void si_meminfo(struct sysinfo *val)
 
 void flush_page_to_ram(struct page *page)
 {
-       unsigned long vaddr = (unsigned long) kmap(page);
-       __flush_page_to_ram(vaddr);
-       kunmap(page);
+       unsigned long vaddr = (unsigned long)page_address(page);
+
+       if (vaddr)
+               __flush_page_to_ram(vaddr);
 }
index b32199c13b74cd3788050831a3b2c41d86db113b..0dba7d0a3ee3f5a528d9954077b353330c32b5c2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.224 2000/11/09 22:40:05 davem Exp $
+/* $Id: srmmu.c,v 1.225 2000/11/30 08:37:31 anton Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -51,7 +51,6 @@ enum mbus_module srmmu_modtype;
 unsigned int hwbug_bitmask;
 int vac_cache_size;
 int vac_line_size;
-int vac_badbits;
 
 extern struct resource sparc_iomap;
 
@@ -1286,75 +1285,6 @@ static void srmmu_destroy_context(struct mm_struct *mm)
        }
 }
 
-static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
-                                      unsigned long address, pte_t pte)
-{
-       if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
-               struct vm_area_struct *vmaring;
-               struct file *file;
-               struct address_space *mapping;
-               unsigned long flags, offset, vaddr, start;
-               int alias_found = 0;
-               pgd_t *pgdp;
-               pmd_t *pmdp;
-               pte_t *ptep;
-
-               __save_and_cli(flags);
-
-               file = vma->vm_file;
-               if (!file)
-                       goto done;
-               mapping = file->f_dentry->d_inode->i_mapping;
-               offset = (address & PAGE_MASK) - vma->vm_start;
-               spin_lock(&mapping->i_shared_lock);
-               vmaring = mapping->i_mmap_shared; 
-               if (vmaring != NULL) do {
-                       /* Do not mistake ourselves as another mapping. */
-                       if(vmaring == vma)
-                               continue;
-
-                       vaddr = vmaring->vm_start + offset;
-                       if ((vaddr ^ address) & vac_badbits) {
-                               alias_found++;
-                               start = vmaring->vm_start;
-                               while (start < vmaring->vm_end) {
-                                       pgdp = srmmu_pgd_offset(vmaring->vm_mm, start);
-                                       if(!pgdp) goto next;
-                                       pmdp = srmmu_pmd_offset(pgdp, start);
-                                       if(!pmdp) goto next;
-                                       ptep = srmmu_pte_offset(pmdp, start);
-                                       if(!ptep) goto next;
-
-                                       if((pte_val(*ptep) & SRMMU_ET_MASK) == SRMMU_VALID) {
-#if 0
-                                               printk("Fixing USER/USER alias [%ld:%08lx]\n",
-                                                      vmaring->vm_mm->context, start);
-#endif
-                                               flush_cache_page(vmaring, start);
-                                               srmmu_set_pte(ptep, __pte((pte_val(*ptep) &
-                                                                    ~SRMMU_CACHE)));
-                                               flush_tlb_page(vmaring, start);
-                                       }
-                               next:
-                                       start += PAGE_SIZE;
-                               }
-                       }
-               } while ((vmaring = vmaring->vm_next_share) != NULL);
-               spin_unlock(&mapping->i_shared_lock);
-
-               if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
-                       pgdp = srmmu_pgd_offset(vma->vm_mm, address);
-                       pmdp = srmmu_pmd_offset(pgdp, address);
-                       ptep = srmmu_pte_offset(pmdp, address);
-                       flush_cache_page(vma, address);
-                       srmmu_set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE)));
-                       flush_tlb_page(vma, address);
-               }
-       done:
-               __restore_flags(flags);
-       }
-}
-
 /* Init various srmmu chip types. */
 static void __init srmmu_is_bad(void)
 {
@@ -1389,7 +1319,6 @@ static void __init init_vac_layout(void)
                        }
 
                        vac_cache_size = cache_lines * vac_line_size;
-                       vac_badbits = (vac_cache_size - 1) & PAGE_MASK;
 #ifdef CONFIG_SMP
                        if(vac_cache_size > max_size)
                                max_size = vac_cache_size;
@@ -1410,7 +1339,6 @@ static void __init init_vac_layout(void)
 #ifdef CONFIG_SMP
        vac_cache_size = max_size;
        vac_line_size = min_line_size;
-       vac_badbits = (vac_cache_size - 1) & PAGE_MASK;
 #endif
        printk("SRMMU: Using VAC size of %d bytes, line size %d bytes.\n",
               (int)vac_cache_size, (int)vac_line_size);
@@ -1465,7 +1393,6 @@ static void __init init_hypersparc(void)
        BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP);
 
 
-       BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM);
        poke_srmmu = poke_hypersparc;
 
        hypersparc_setup_blockops();
@@ -1532,7 +1459,6 @@ static void __init init_cypress_common(void)
        BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP);
        BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP);
 
-       BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM);
        poke_srmmu = poke_cypress;
 }
 
index edba89672894e517d627fa0543fdb091c948d0fc..1b32dd8ef8ec4e3fa132da62fc80e0280cc458d3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.201 2000/11/09 22:39:36 davem Exp $
+/* $Id: sun4c.c,v 1.202 2000/12/01 03:17:31 anton Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2373,78 +2373,6 @@ static int sun4c_check_pgt_cache(int low, int high)
        return freed;
 }
 
-/* There are really two cases of aliases to watch out for, and these
- * are:
- *
- *     1) A user's page which can be aliased with the kernels virtual
- *        mapping of the physical page.
- *
- *     2) Multiple user mappings of the same inode/anonymous object
- *        such that two copies of the same data for the same phys page
- *        can live (writable) in the cache at the same time.
- *
- * We handle number 1 by flushing the kernel copy of the page always
- * after COW page operations.
- *
- * NOTE: We are a bit slowed down now because the VMA arg is indeed used
- *       now, so our ref/mod bit tracking quick userfaults eat a few more
- *       cycles than they used to.
- */
-static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-       pgd_t *pgdp;
-       pte_t *ptep;
-
-       if (vma->vm_file) {
-               struct address_space *mapping;
-               unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
-               struct vm_area_struct *vmaring;
-               int alias_found = 0;
-
-               mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
-               spin_lock(&mapping->i_shared_lock);
-               vmaring = mapping->i_mmap_shared; 
-               if (vmaring != NULL) do {
-                       unsigned long vaddr = vmaring->vm_start + offset;
-                       unsigned long start;
-
-                       /* Do not mistake ourselves as another mapping. */
-                       if (vmaring == vma)
-                               continue;
-
-                       if (S4CVAC_BADALIAS(vaddr, address)) {
-                               alias_found++;
-                               start = vmaring->vm_start;
-                               while (start < vmaring->vm_end) {
-                                       pgdp = sun4c_pgd_offset(vmaring->vm_mm, start);
-                                       if (!pgdp)
-                                               goto next;
-                                       ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
-                                       if (!ptep)
-                                               goto next;
-
-                                       if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
-                                               flush_cache_page(vmaring, start);
-                                               *ptep = __pte(pte_val(*ptep) |
-                                                             _SUN4C_PAGE_NOCACHE);
-                                               flush_tlb_page(vmaring, start);
-                                       }
-                               next:
-                                       start += PAGE_SIZE;
-                               }
-                       }
-               } while ((vmaring = vmaring->vm_next_share) != NULL);
-               spin_unlock(&mapping->i_shared_lock);
-
-               if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
-                       pgdp = sun4c_pgd_offset(vma->vm_mm, address);
-                       ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
-                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
-                       pte = *ptep;
-               }
-       }
-}
-
 /* An experiment, turn off by default for now... -DaveM */
 #define SUN4C_PRELOAD_PSEG
 
@@ -2486,8 +2414,6 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p
 #endif
                        start += PAGE_SIZE;
                }
-               if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
-                       sun4c_vac_alias_fixup(vma, address, pte);
 #ifndef SUN4C_PRELOAD_PSEG
                sun4c_put_pte(address, pte_val(pte));
 #endif
@@ -2500,9 +2426,6 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p
                add_lru(entry);
        }
 
-       if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
-               sun4c_vac_alias_fixup(vma, address, pte);
-
        sun4c_put_pte(address, pte_val(pte));
        restore_flags(flags);
 }
index e1ae982bf4b9ad0960b78538c5cb2bd6efbb3afe..a0311626e131f794bb612a1c3edd56eaa7b7f678 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.98 2000/11/13 10:03:32 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.99 2000/12/09 04:15:24 anton Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -179,6 +179,7 @@ EXPORT_SYMBOL(disable_irq);
 
 EXPORT_SYMBOL(__flushw_user);
 
+EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(__flush_dcache_page);
 
 EXPORT_SYMBOL(mstk48t02_regs);
index 235d3488931b160db029887a4bc476c01d8a2e35..391979c87720e437e4d4570b267f4f91f43f51e5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.46 2000/08/29 07:01:54 davem Exp $
+/* $Id: sys_sparc.c,v 1.47 2000/11/29 05:56:12 anton Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -40,6 +40,8 @@ asmlinkage unsigned long sys_getpagesize(void)
        return PAGE_SIZE;
 }
 
+#define COLOUR_ALIGN(addr)     (((addr)+SHMLBA-1)&~(SHMLBA-1))
+
 unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
 {
        struct vm_area_struct * vmm;
@@ -51,7 +53,11 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
                return 0;
        if (!addr)
                addr = TASK_UNMAPPED_BASE;
-       addr = PAGE_ALIGN(addr);
+
+       if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+               addr = COLOUR_ALIGN(addr);
+       else
+               addr = PAGE_ALIGN(addr);
 
        task_size -= len;
 
@@ -66,6 +72,8 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
                if (!vmm || addr + len <= vmm->vm_start)
                        return addr;
                addr = vmm->vm_end;
+               if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+                       addr = COLOUR_ALIGN(addr);
        }
 }
 
@@ -232,10 +240,15 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
                        goto out_putf;
        }
 
+       if (flags & MAP_SHARED)
+               current->thread.flags |= SPARC_FLAG_MMAPSHARED;
+
        down(&current->mm->mmap_sem);
        retval = do_mmap(file, addr, len, prot, flags, off);
        up(&current->mm->mmap_sem);
 
+       current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
+
 out_putf:
        if (file)
                fput(file);
@@ -264,6 +277,7 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
        unsigned long old_len, unsigned long new_len,
        unsigned long flags, unsigned long new_addr)
 {
+       struct vm_area_struct *vma;
        unsigned long ret = -EINVAL;
        if (current->thread.flags & SPARC_FLAG_32BIT)
                goto out;
@@ -272,6 +286,9 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
        if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET)
                goto out;
        down(&current->mm->mmap_sem);
+       vma = find_vma(current->mm, addr);
+       if (vma && (vma->vm_flags & VM_SHARED))
+               current->thread.flags |= SPARC_FLAG_MMAPSHARED;
        if (flags & MREMAP_FIXED) {
                if (new_addr < PAGE_OFFSET &&
                    new_addr + new_len > -PAGE_OFFSET)
@@ -280,13 +297,14 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
                ret = -ENOMEM;
                if (!(flags & MREMAP_MAYMOVE))
                        goto out_sem;
-               new_addr = get_unmapped_area (addr, new_len);
+               new_addr = get_unmapped_area(addr, new_len);
                if (!new_addr)
                        goto out_sem;
                flags |= MREMAP_FIXED;
        }
        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
+       current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
        up(&current->mm->mmap_sem);
 out:
        return ret;       
index 9b211d86d338584f88eec1d624208f9dbed48a97..0964409c9a919b300b6c519cdbeaec9f034b8d78 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.166 2000/11/10 04:49:56 davem Exp $
+/* $Id: sys_sparc32.c,v 1.168 2000/12/11 18:59:35 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -2966,6 +2966,7 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
 
                        err = copy_from_user(kaddr + offset, (char *)A(str),
                                             bytes_to_copy);
+                       flush_dcache_page(page);
                        flush_page_to_ram(page);
                        kunmap(page);
 
@@ -4133,6 +4134,7 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
        unsigned long old_len, unsigned long new_len,
        unsigned long flags, u32 __new_addr)
 {
+       struct vm_area_struct *vma;
        unsigned long ret = -EINVAL;
        unsigned long new_addr = AA(__new_addr);
 
@@ -4141,6 +4143,9 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
        if (addr > 0xf0000000UL - old_len)
                goto out;
        down(&current->mm->mmap_sem);
+       vma = find_vma(current->mm, addr);
+       if (vma && (vma->vm_flags & VM_SHARED))
+               current->thread.flags |= SPARC_FLAG_MMAPSHARED;
        if (flags & MREMAP_FIXED) {
                if (new_addr > 0xf0000000UL - new_len)
                        goto out_sem;
@@ -4148,13 +4153,14 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
                ret = -ENOMEM;
                if (!(flags & MREMAP_MAYMOVE))
                        goto out_sem;
-               new_addr = get_unmapped_area (addr, new_len);
+               new_addr = get_unmapped_area(addr, new_len);
                if (!new_addr)
                        goto out_sem;
                flags |= MREMAP_FIXED;
        }
        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
+       current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
        up(&current->mm->mmap_sem);
 out:
        return ret;       
index 6da2d0b8560d1e66f9742a1f610e8e65b06a57ef..2890927567f6bbce2cf633941141d871871eeb5f 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.159 2000/11/06 06:59:04 davem Exp $
+/*  $Id: init.c,v 1.161 2000/12/09 20:16:58 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -113,6 +113,17 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p
        __update_mmu_cache(vma, address, pte);
 }
 
+/* In arch/sparc64/mm/ultra.S */
+extern void __flush_icache_page(unsigned long);
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+       unsigned long kaddr;
+
+       for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE)
+               __flush_icache_page(__get_phys(kaddr));
+}
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
index b860253d3ac1fc56cb1d9005a5ba3d3e2d079faf..8a24cfb66f662f370a69b4c5f8d27ac15838df1d 100644 (file)
@@ -2397,7 +2397,7 @@ static int __init amb_probe (void) {
       
 #ifdef FILL_RX_POOLS_IN_BH
       // initialise bottom half
-      dev->bh.next = 0;
+      INIT_LIST_HEAD(&dev->bh.list);
       dev->bh.sync = 0;
       dev->bh.routine = (void (*)(void *)) fill_rx_pools;
       dev->bh.data = dev;
index a228034de4d70fa83d178a98992f22279df815a0..20e363b8e62d842a7942be421e2fb0ad43eb674c 100644 (file)
@@ -176,14 +176,15 @@ static int __blk_cleanup_queue(struct list_head *head)
  * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed
  * @q:    the request queue to be released
  *
- * Description:  blk_cleanup_queue is the pair to blk_init_queue().  It should
- *     be called when a request queue is being released; typically when a block
- *     device is being de-registered.
- *     Currently, its primary task it to free all the &struct request structures
- *     that were allocated to the queue.
- * Caveat:
- *     Hopefully the low level driver will have finished any outstanding
- *     requests first...
+ * Description:
+ *     blk_cleanup_queue is the pair to blk_init_queue().  It should
+ *     be called when a request queue is being released; typically
+ *     when a block device is being de-registered.  Currently, its
+ *     primary task it to free all the &struct request structures that
+ *     were allocated to the queue.
+ * Caveat: 
+ *     Hopefully the low level driver will have finished any
+ *     outstanding requests first...
  **/
 void blk_cleanup_queue(request_queue_t * q)
 {
@@ -234,19 +235,21 @@ void blk_queue_headactive(request_queue_t * q, int active)
  * @plug: the function to be called to plug a queue
  *
  * Description:
- *   A request queue will be "plugged" if a request is added to it while it
- *   is empty.  This allows a number of requests to be added before any are
- *   processed, thus providing an opportunity for these requests to be merged
- *   or re-ordered.
- *   The default plugging function (generic_plug_device()) sets the "plugged"
- *   flag for the queue and adds a task to the $tq_disk task queue to unplug
- *   the queue and call the request function at a later time.
+ *   A request queue will be "plugged" if a request is added to it
+ *   while it is empty.  This allows a number of requests to be added
+ *   before any are processed, thus providing an opportunity for these
+ *   requests to be merged or re-ordered.
+ *   The default plugging function (generic_plug_device()) sets the
+ *   "plugged" flag for the queue and adds a task to the $tq_disk task
+ *   queue to unplug the queue and call the request function at a
+ *   later time.
  *
- *   A device driver may provide an alternate plugging function by passing it to
- *   blk_queue_pluggable().   This function should set the "plugged" flag if it
- *   want calls to the request_function to be blocked, and should place a
- *   task on $tq_disk which will unplug the queue.  Alternately it can simply
- *   do nothing and there-by disable plugging of the device.
+ *   A device driver may provide an alternate plugging function by
+ *   passing it to blk_queue_pluggable().  This function should set
+ *   the "plugged" flag if it want calls to the request_function to be
+ *   blocked, and should place a task on $tq_disk which will unplug
+ *   the queue.  Alternately it can simply do nothing and there-by
+ *   disable plugging of the device.
  **/
 
 void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug)
@@ -261,14 +264,21 @@ void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug)
  * @mfn: the alternate make_request function
  *
  * Description:
- *    The normal way for &struct buffer_heads to be passed to a device driver
- *    it to collect into requests on a request queue, and allow the device
- *    driver to select requests off that queue when it is ready.  This works
- *    well for many block devices. However some block devices (typically
- *    virtual devices such as md or lvm) do not benefit from the processes on
- *    the request queue, and are served best by having the requests passed
- *    directly to them.  This can be achieved by providing a function to
- *    blk_queue_make_request().
+ *    The normal way for &struct buffer_heads to be passed to a device
+ *    driver is for them to be collected into requests on a request
+ *    queue, and then to allow the device driver to select requests
+ *    off that queue when it is ready.  This works well for many block
+ *    devices. However some block devices (typically virtual devices
+ *    such as md or lvm) do not benefit from the processing on the
+ *    request queue, and are served best by having the requests passed
+ *    directly to them.  This can be achieved by providing a function
+ *    to blk_queue_make_request().
+ *
+ * Caveat:
+ *    The driver that does this *must* be able to deal appropriately
+ *    with buffers in "highmemory", either by calling bh_kmap() to get
+ *    a kernel mapping, to by calling create_bounce() to create a
+ *    buffer in normal memory.
  **/
 
 void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
@@ -637,7 +647,10 @@ static void attempt_merge(request_queue_t * q,
        next = blkdev_next_request(req);
        if (req->sector + req->nr_sectors != next->sector)
                return;
-       if (req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors || next->sem)
+       if (req->cmd != next->cmd
+           || req->rq_dev != next->rq_dev
+           || req->nr_sectors + next->nr_sectors > max_sectors
+           || next->sem)
                return;
        /*
         * If we are not allowed to merge these requests, then
@@ -749,7 +762,8 @@ again:
                goto get_rq;
        }
 
-       el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments);
+       el_ret = elevator->elevator_merge_fn(q, &req, bh, rw,
+                                            &max_sectors, &max_segments);
        switch (el_ret) {
 
                case ELEVATOR_BACK_MERGE:
@@ -833,6 +847,40 @@ end_io:
        return 0;
 }
 
+/**
+ * generic_make_request: hand a buffer head to it's device driver for I/O
+ * @rw:  READ, WRITE, or READA - what sort of I/O is desired.
+ * @bh:  The buffer head describing the location in memory and on the device.
+ *
+ * generic_make_request() is used to make I/O requests of block
+ * devices. It is passed a &struct buffer_head and a &rw value.  The
+ * %READ and %WRITE options are (hopefully) obvious in meaning.  The
+ * %READA value means that a read is required, but that the driver is
+ * free to fail the request if, for example, it cannot get needed
+ * resources immediately.
+ *
+ * generic_make_request() does not return any status.  The
+ * success/failure status of the request, along with notification of
+ * completion, is delivered asynchronously through the bh->b_end_io
+ * function described (one day) else where.
+ *
+ * The caller of generic_make_request must make sure that b_page,
+ * b_addr, b_size are set to describe the memory buffer, that b_rdev
+ * and b_rsector are set to describe the device address, and the
+ * b_end_io and optionally b_private are set to describe how
+ * completion notification should be signaled.  BH_Mapped should also
+ * be set (to confirm that b_dev and b_blocknr are valid).
+ *
+ * generic_make_request and the drivers it calls may use b_reqnext,
+ * and may change b_rdev and b_rsector.  So the values of these fields
+ * should NOT be depended on after the call to generic_make_request.
+ * Because of this, the caller should record the device address
+ * information in b_dev and b_blocknr.
+ *
+ * Apart from those fields mentioned above, no other fields, and in
+ * particular, no other flags, are changed by generic_make_request or
+ * any lower level drivers.
+ * */
 void generic_make_request (int rw, struct buffer_head * bh)
 {
        int major = MAJOR(bh->b_rdev);
@@ -886,8 +934,18 @@ void generic_make_request (int rw, struct buffer_head * bh)
 }
 
 
-/*
- * Submit a buffer head for IO.
+/**
+ * submit_bh: submit a buffer_head to the block device later for I/O
+ * @rw: whether to %READ or %WRITE, or mayve to %READA (read ahead)
+ * @bh: The &struct buffer_head which describes the I/O
+ *
+ * submit_bh() is very similar in purpose to generic_make_request(), and
+ * uses that function to do most of the work.
+ *
+ * The extra functionality provided by submit_bh is to determine
+ * b_rsector from b_blocknr and b_size, and to set b_rdev from b_dev.
+ * This is is appropriate for IO requests that come from the buffer
+ * cache and page cache which (currently) always use aligned blocks.
  */
 void submit_bh(int rw, struct buffer_head * bh)
 {
@@ -915,9 +973,36 @@ static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
        unlock_buffer(bh);
 }
 
-/* This function can be used to request a number of buffers from a block
-   device. Currently the only restriction is that all buffers must belong to
-   the same device */
+/**
+ * ll_rw_block: low-level access to block devices
+ * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
+ * @nr: number of &struct buffer_heads in the array
+ * @bhs: array of pointers to &struct buffer_head
+ *
+ * ll_rw_block() takes an array of pointers to &struct buffer_heads,
+ * and requests an I/O operation on them, either a %READ or a %WRITE.
+ * The third %READA option is described in the documentation for
+ * generic_make_request() which ll_rw_block() calls.
+ *
+ * This function provides extra functionality that is not in
+ * generic_make_request() that is relevant to buffers in the buffer
+ * cache or page cache.  In particular it drops any buffer that it
+ * cannot get a lock on (with the BH_Lock state bit), any buffer that
+ * appears to be clean when doing a write request, and any buffer that
+ * appears to be up-to-date when doing read request.  Further it marks
+ * as clean buffers that are processed for writing (the buffer cache
+ * wont assume that they are actually clean until the buffer gets
+ * unlocked).
+ *
+ * ll_rw_block sets b_end_io to simple completion handler that marks
+ * the buffer up-to-date (if approriate), unlocks the buffer and wakes
+ * any waiters.  As client that needs a more interesting completion
+ * routine should call submit_bh() (or generic_make_request())
+ * directly.
+ *
+ * Caveat:
+ *  All of the buffers must be for the same device, and must also be
+ *  of the current approved size for the device.  */
 
 void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
 {
index d1155a8aa187756d3ea6ffe4c458b31bb0f75c79..0e1a8d2e5e3b377c94f50d5d056bff2da551f3a6 100644 (file)
@@ -50,7 +50,7 @@ static int ps_nice = 0;
 static spinlock_t ps_spinlock __attribute__((unused)) = SPIN_LOCK_UNLOCKED;
 
 static struct timer_list ps_timer = { function: ps_timer_int };
-static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
+static struct tq_struct ps_tq = { routine: ps_tq_int };
 
 static void ps_set_intr( void (*continuation)(void), 
                         int (*ready)(void),
index 4ab67281ca52485dcd13a65ab41e82c1c17743c9..4854c56d591b5ff0addddec5f3e07aec2e67cd85 100644 (file)
@@ -651,7 +651,7 @@ int gamma_irq_install(drm_device_t *dev, int irq)
        dev->dma->next_queue  = NULL;
        dev->dma->this_buffer = NULL;
 
-       dev->tq.next          = NULL;
+       INIT_LIST_HEAD(&dev->tq.list);
        dev->tq.sync          = 0;
        dev->tq.routine       = gamma_dma_schedule_tq_wrapper;
        dev->tq.data          = dev;
index 26fe0c1c152739df01237291fa9059b5555f31dc..aa824a79cc94b50b17c040e4c4cf7b825e5db2b7 100644 (file)
@@ -924,7 +924,7 @@ int i810_irq_install(drm_device_t *dev, int irq)
        dev->dma->next_queue  = NULL;
        dev->dma->this_buffer = NULL;
 
-       dev->tq.next          = NULL;
+       INIT_LIST_HEAD(&dev->tq.list);
        dev->tq.sync          = 0;
        dev->tq.routine       = i810_dma_task_queue;
        dev->tq.data          = dev;
index 2b293c5ffc0df36c6fc9d8ef9f67d5b20dedff6c..356376ca9cfeaae2cc6dea827c659572b045061e 100644 (file)
@@ -818,7 +818,7 @@ int mga_irq_install(drm_device_t *dev, int irq)
        dev->dma->next_buffer = NULL;
        dev->dma->next_queue  = NULL;
        dev->dma->this_buffer = NULL;
-       dev->tq.next          = NULL;
+       INIT_LIST_HEAD(&dev->tq.list);
        dev->tq.sync          = 0;
        dev->tq.routine       = mga_dma_task_queue;
        dev->tq.data          = dev;
index d916898002b4781e143e2a16cfc7da300fb61785..8a825753a3336ffbd6b8f3049b123efcd64df2a9 100644 (file)
@@ -1157,12 +1157,12 @@ static int r3964_open(struct tty_struct *tty)
     * Add 'on_timer' to timer task queue
     * (will be called from timer bh)
     */
-   pInfo->bh_1.next = NULL;
+   INIT_LIST_HEAD(&pInfo->bh_1.list);
    pInfo->bh_1.sync = 0;
    pInfo->bh_1.routine = &on_timer_1;
    pInfo->bh_1.data = pInfo;
    
-   pInfo->bh_2.next = NULL;
+   INIT_LIST_HEAD(&pInfo->bh_2.list);
    pInfo->bh_2.sync = 0;
    pInfo->bh_2.routine = &on_timer_2;
    pInfo->bh_2.data = pInfo;
@@ -1174,7 +1174,6 @@ static int r3964_open(struct tty_struct *tty)
 
 static void r3964_close(struct tty_struct *tty)
 {
-   struct tq_struct *tq, *prev;
    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
    struct r3964_client_info *pClient, *pNext;
    struct r3964_message *pMsg;
@@ -1187,19 +1186,12 @@ static void r3964_close(struct tty_struct *tty)
      * Make sure that our task queue isn't activated.  If it
      * is, take it out of the linked list.
      */
-    save_flags(flags);
-    cli();
-
-    for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
-         if ((tq == &pInfo->bh_1) || (tq==&pInfo->bh_2)) {
-             if (prev)
-                 prev->next = tq->next;
-             else
-                 tq_timer = tq->next;
-             break;
-         }
-    }
-    restore_flags(flags);
+    spin_lock_irqsave(&tqueue_lock, flags);
+    if (pInfo->bh_1.sync)
+       list_del(&pInfo->bh_1.list);
+    if (pInfo->bh_2.sync)
+       list_del(&pInfo->bh_2.list);
+    spin_unlock_irqrestore(&tqueue_lock, flags);
 
    /* Remove client-structs and message queues: */
     pClient=pInfo->firstClient;
index f2435e9ec1fad8da7b2ec3b0b990785cfbf7ef82..6ba861be26155c492e827507ea8799c5ce821373 100644 (file)
@@ -120,7 +120,7 @@ int register_scan_keyboard(void (*scan)(unsigned char *buffer),
 void __init scan_kbd_init(void)
 {
 
-       task_scan_kbd.next=NULL;
+       INIT_LIST_HEAD(task_scan_kbd.list);
        task_scan_kbd.sync=0;
        task_scan_kbd.routine=scan_kbd;
        task_scan_kbd.data=NULL;
index 662b27ca2aa630186011270fa3627c4f7f86643b..8d77c3c773757591239a8046b3dc6a319e26418b 100644 (file)
@@ -31,7 +31,7 @@ struct sx_port {
   int                     c_dcd;
   struct sx_board         *board;
   int                     line;
-  int                     locks;
+  long                    locks;
 };
 
 struct sx_board {
index 1bc175d16a2fcba8b3c76f694ea9d73784760fd7..4165a37e337a1ad3c31273bf709c78147c9b4066 100644 (file)
@@ -62,7 +62,7 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES];
  */
 unsigned char keyboard_type = KB_101;
 
-#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
+#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
 asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 #endif
 
@@ -472,7 +472,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                ucval = keyboard_type;
                goto setchar;
 
-#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
+#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
                /*
                 * These cannot be implemented on any machine that implements
                 * ioperm() in user level (such as Alpha PCs).
index d47323c9375d341648aa96a80090ad8ae777214a..8b9e4c44813620895eab548b5b051bca282e8e6f 100644 (file)
@@ -112,8 +112,10 @@ static struct i2o_handler i2o_lan_handler = {
 };
 static int lan_context;
 
-static struct tq_struct i2o_post_buckets_task = {
-       0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0
+DECLARE_TASK_QUEUE(i2o_post_buckets_task);
+struct tq_struct run_i2o_post_buckets_task = {
+       routine: (void (*)(void *)) run_task_queue,
+       data: (void *) 0
 };
 
 /* Functions to handle message failures and transaction errors:
@@ -379,8 +381,8 @@ static void i2o_lan_receive_post_reply(struct i2o_handler *h,
        /* If DDM has already consumed bucket_thresh buckets, post new ones */
 
        if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) {
-               i2o_post_buckets_task.data = (void *)dev;
-               queue_task(&i2o_post_buckets_task, &tq_immediate);
+               run_i2o_post_buckets_task.data = (void *)dev;
+               queue_task(&run_i2o_post_buckets_task, &tq_immediate);
                mark_bh(IMMEDIATE_BH);
        }
 
@@ -1401,7 +1403,7 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        atomic_set(&priv->tx_out, 0);
        priv->tx_count = 0;
 
-       priv->i2o_batch_send_task.next    = NULL;
+       INIT_LIST_HEAD(&priv->i2o_batch_send_task.list);
        priv->i2o_batch_send_task.sync    = 0;
        priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send;
        priv->i2o_batch_send_task.data    = (void *)dev;
index 1aa453292e6665074c44b0d6e688e9cfbe79e2ad..6745222f3f92811de8a44b345a25d3aa6aa1001b 100644 (file)
@@ -163,7 +163,7 @@ static void host_reset(struct hpsb_host *host)
                         return;
                 }
 
-                greq->tq.next = NULL;
+                INIT_LIST_HEAD(&greq->tq.list);
                 greq->tq.sync = 0;
                 greq->tq.routine = (void (*)(void*))pkt_complete;
                 greq->tq.data = greq;
index 6dc42555dfdd010e60143f1e1e8b40564cb7be58..3b41afb55a2968a27a67be914476aeb602f6b4ed 100644 (file)
@@ -1585,7 +1585,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
 
         /* initialize bottom handler */
         d->task.sync = 0;
-        d->task.next = NULL;
+        INIT_LIST_HEAD(&d->task.list);
         d->task.routine = dma_rcv_bh;
         d->task.data = (void*)d;
 
index b7812b83002956cd7267a1ac778d4a8c4d8492c6..f25e2a159fa15056ffb9e1f2ae118dbecfe1a787 100644 (file)
@@ -1180,7 +1180,7 @@ checkcard(int cardnr, char *id, int *busy_flag)
        cs->tx_skb = NULL;
        cs->tx_cnt = 0;
        cs->event = 0;
-       cs->tqueue.next = 0;
+       INIT_LIST_HEAD(&cs->tqueue.list);
        cs->tqueue.sync = 0;
        cs->tqueue.data = cs;
 
index 45d89f8b36713fff38b309d25a8b4948a324e2db..cda9e422c7349d15d21f2753265a6d6200f015c9 100644 (file)
@@ -343,7 +343,7 @@ init_bcstate(struct IsdnCardState *cs,
 
        bcs->cs = cs;
        bcs->channel = bc;
-       bcs->tqueue.next = 0;
+       INIT_LIST_HEAD(&bcs->tqueue.list);
        bcs->tqueue.sync = 0;
        bcs->tqueue.routine = (void *) (void *) BChannel_bh;
        bcs->tqueue.data = bcs;
index 2a2d93bfaec1f2addce11008b3f17b48497eb7a8..941a4bfabff21654fae6283212a99b697f793de8 100644 (file)
@@ -458,7 +458,7 @@ ergo_inithardware(hysdn_card * card)
        card->writebootseq = ergo_writebootseq;
        card->waitpofready = ergo_waitpofready;
        card->set_errlog_state = ergo_set_errlog_state;
-       card->irq_queue.next = 0;
+       INIT_LIST_HEAD(&card->irq_queue.list);
        card->irq_queue.sync = 0;
        card->irq_queue.data = card;    /* init task queue for interrupt */
        card->irq_queue.routine = (void *) (void *) ergo_irq_bh;
index 125742e6a8931006d1a0246f6c13ddf560297912..4f421e75c4dadeee35e35e1b92678b9f343f8ead 100644 (file)
@@ -135,7 +135,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
        dev->b2->id = 1;
 
 
-       dev->qdelivery.next = NULL;
+       INIT_LIST_HEAD(&dev->qdelivery.list);
        dev->qdelivery.sync = 0;
        dev->qdelivery.routine = pcbit_deliver;
        dev->qdelivery.data = dev;
index 7e6bdbaf423653ecc5ee5a57c9032b026e513ffc..c37ce84dbac1ba1a95b49a4aa65fc38c5f9ddb26 100644 (file)
@@ -16,10 +16,13 @@ obj-m               :=
 obj-n          :=
 obj-           :=
 
-# NOTE: xor.o must link *before* md.o so that auto-detect
-# of raid5 arrays works (and doesn't Oops).  Fortunately
-# they are both export-objs, so setting the order here
-# works.
+# Note: link order is important.  All raid personalities
+# and xor.o must come before md.o, as they each initialise 
+# themselves, and md.o may use the personalities when it 
+# auto-initialised.
+# The use of MIX_OBJS allows link order to be maintained even
+# though some are export-objs and some aren't.
+
 obj-$(CONFIG_MD_LINEAR)                += linear.o
 obj-$(CONFIG_MD_RAID0)         += raid0.o
 obj-$(CONFIG_MD_RAID1)         += raid1.o
@@ -28,10 +31,11 @@ obj-$(CONFIG_BLK_DEV_MD)    += md.o
 obj-$(CONFIG_BLK_DEV_LVM)      += lvm-mod.o
 
 # Translate to Rules.make lists.
-O_OBJS         := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS                := $(filter     $(export-objs), $(obj-y))
-M_OBJS         := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS                := $(sort $(filter      $(export-objs), $(obj-m)))
+active-objs    := $(sort $(obj-y) $(obj-m))
+
+O_OBJS         := $(obj-y)
+M_OBJS         := $(obj-m)
+MIX_OBJS       := $(filter $(export-objs), $(active-objs))
 
 include $(TOPDIR)/Rules.make
 
index 855bc44dde82d4054c257b5e0f2dccebfaa79d27..e6b50b84d820493e2269f45619b215a1e9e19be5 100644 (file)
@@ -84,21 +84,19 @@ static int linear_run (mddev_t *mddev)
                dev_info_t *disk = conf->disks + j;
 
                if (size < 0) {
-                       table->dev1 = disk;
-                       table++;
+                       table[-1].dev1 = disk;
                }
                size += disk->size;
 
-               while (size) {
+               while (size>0) {
                        table->dev0 = disk;
-                       size -= conf->smallest->size;
-                       if (size < 0)
-                               break;
                        table->dev1 = NULL;
+                       size -= conf->smallest->size;
                        table++;
                }
        }
-       table->dev1 = NULL;
+       if (table-conf->hash_table != nb_zone)
+               BUG();
 
        return 0;
 
@@ -136,7 +134,8 @@ static int linear_make_request (mddev_t *mddev,
                if (!hash->dev1) {
                        printk ("linear_make_request : hash->dev1==NULL for block %ld\n",
                                                block);
-                       return -1;
+                       buffer_IO_error(bh);
+                       return 0;
                }
                tmp_dev = hash->dev1;
        } else
@@ -145,7 +144,8 @@ static int linear_make_request (mddev_t *mddev,
        if (block >= (tmp_dev->size + tmp_dev->offset)
                                || block < tmp_dev->offset) {
                printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset);
-               return -1;
+               buffer_IO_error(bh);
+               return 0;
        }
        bh->b_rdev = tmp_dev->dev;
        bh->b_rsector = bh->b_rsector - (tmp_dev->offset << 1);
@@ -190,24 +190,16 @@ static mdk_personality_t linear_personality=
        status:         linear_status,
 };
 
-#ifndef MODULE
-
-void md__init linear_init (void)
+static int md__init linear_init (void)
 {
-       register_md_personality (LINEAR, &linear_personality);
+       return register_md_personality (LINEAR, &linear_personality);
 }
 
-#else
-
-int init_module (void)
-{
-       return (register_md_personality (LINEAR, &linear_personality));
-}
-
-void cleanup_module (void)
+static void linear_exit (void)
 {
        unregister_md_personality (LINEAR);
 }
 
-#endif
 
+module_init(linear_init);
+module_exit(linear_exit);
index 5aa88df9e4537e4269aeee13293777e59351b46f..f9433232eb9f92cf3dd498fb41693927a410748a 100644 (file)
  *               - avoided inline strings functions lvm_strlen etc.
  *    14/02/2000 - support for 2.3.43
  *               - integrated Andrea Arcangeli's snapshot code
+ *    07/12/2000 - make sure lvm_make_request_fn returns correct value - 0 or 1 - NeilBrown
  *
  */
 
@@ -1488,8 +1489,10 @@ static void lvm_dummy_device_request(request_queue_t * t)
  */
 static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh)
 {
-       lvm_map(bh, rw);
-       return 1;
+       if (lvm_map(bh, rw)<0)
+               return 0; /* failure, buffer_IO_error has been called, don't recurse */
+       else
+               return 1; /* all ok, mapping done, call lower level driver */
 }
 
 /*
index 86664dcd136da7ff38f1bd23438aea88c7ea6f5c..8542bc2b067fe3a976e4a08088aa6e73ea39924c 100644 (file)
@@ -179,7 +179,7 @@ static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
                return mddev->pers->make_request(mddev, rw, bh);
        else {
                buffer_IO_error(bh);
-               return -1;
+               return 0;
        }
 }
 
@@ -203,6 +203,7 @@ static mddev_t * alloc_mddev (kdev_t dev)
        init_MUTEX(&mddev->resync_sem);
        MD_INIT_LIST_HEAD(&mddev->disks);
        MD_INIT_LIST_HEAD(&mddev->all_mddevs);
+       atomic_set(&mddev->active, 0);
 
        /*
         * The 'base' mddev is the one with data NULL.
@@ -656,32 +657,25 @@ static void unbind_rdev_from_array (mdk_rdev_t * rdev)
 static int lock_rdev (mdk_rdev_t *rdev)
 {
        int err = 0;
+       struct block_device *bdev;
 
-       /*
-        * First insert a dummy inode.
-        */
-       if (rdev->inode)
-               MD_BUG();
-       rdev->inode = get_empty_inode();
-       if (!rdev->inode)
+       bdev = bdget(rdev->dev);
+       if (bdev == NULL)
                return -ENOMEM;
-       /*
-        * we dont care about any other fields
-        */
-       rdev->inode->i_dev = rdev->inode->i_rdev = rdev->dev;
-       insert_inode_hash(rdev->inode);
-
-       memset(&rdev->filp, 0, sizeof(rdev->filp));
-       rdev->filp.f_mode = 3; /* read write */
+       err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE);
+       if (!err) {
+               rdev->bdev = bdev;
+       }
        return err;
 }
 
 static void unlock_rdev (mdk_rdev_t *rdev)
 {
-       if (!rdev->inode)
+       if (!rdev->bdev)
                MD_BUG();
-       iput(rdev->inode);
-       rdev->inode = NULL;
+       blkdev_put(rdev->bdev, BDEV_FILE);
+       bdput(rdev->bdev);
+       rdev->bdev = NULL;
 }
 
 static void export_rdev (mdk_rdev_t * rdev)
@@ -1149,7 +1143,7 @@ static int md_import_device (kdev_t newdev, int on_disk)
 
 abort_free:
        if (rdev->sb) {
-               if (rdev->inode)
+               if (rdev->bdev)
                        unlock_rdev(rdev);
                free_disk_sb(rdev);
        }
@@ -1718,12 +1712,20 @@ out:
 
 #define STILL_MOUNTED KERN_WARNING \
 "md: md%d still mounted.\n"
+#define        STILL_IN_USE \
+"md: md%d still in use.\n"
 
 static int do_md_stop (mddev_t * mddev, int ro)
 {
        int err = 0, resync_interrupted = 0;
        kdev_t dev = mddev_to_kdev(mddev);
 
+       if (atomic_read(&mddev->active)>1) {
+               printk(STILL_IN_USE, mdidx(mddev));
+               OUT(-EBUSY);
+       }
+       /* this shouldn't be needed as above would have fired */
        if (!ro && get_super(dev)) {
                printk (STILL_MOUNTED, mdidx(mddev));
                OUT(-EBUSY);
@@ -1859,8 +1861,10 @@ static void autorun_array (mddev_t *mddev)
  * the 'same_array' list. Then order this list based on superblock
  * update time (freshest comes first), kick out 'old' disks and
  * compare superblocks. If everything's fine then run it.
+ *
+ * If "unit" is allocated, then bump its reference count
  */
-static void autorun_devices (void)
+static void autorun_devices (kdev_t countdev)
 {
        struct md_list_head candidates;
        struct md_list_head *tmp;
@@ -1902,6 +1906,12 @@ static void autorun_devices (void)
                        continue;
                }
                mddev = alloc_mddev(md_kdev);
+               if (mddev == NULL) {
+                       printk("md: cannot allocate memory for md drive.\n");
+                       break;
+               }
+               if (md_kdev == countdev)
+                       atomic_inc(&mddev->active);
                printk("created md%d\n", mdidx(mddev));
                ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) {
                        bind_rdev_to_array(rdev, mddev);
@@ -1945,7 +1955,7 @@ static void autorun_devices (void)
 #define AUTORUNNING KERN_INFO \
 "md: auto-running md%d.\n"
 
-static int autostart_array (kdev_t startdev)
+static int autostart_array (kdev_t startdev, kdev_t countdev)
 {
        int err = -EINVAL, i;
        mdp_super_t *sb = NULL;
@@ -2002,7 +2012,7 @@ static int autostart_array (kdev_t startdev)
        /*
         * possibly return codes
         */
-       autorun_devices();
+       autorun_devices(countdev);
        return 0;
 
 abort:
@@ -2077,7 +2087,7 @@ int md__init md_run_setup(void)
                        md_list_add(&rdev->pending, &pending_raid_disks);
                }
 
-               autorun_devices();
+               autorun_devices(-1);
        }
 
        dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */
@@ -2607,6 +2617,8 @@ static int md_ioctl (struct inode *inode, struct file *file,
                                err = -ENOMEM;
                                goto abort;
                        }
+                       atomic_inc(&mddev->active);
+
                        /*
                         * alloc_mddev() should possibly self-lock.
                         */
@@ -2640,7 +2652,7 @@ static int md_ioctl (struct inode *inode, struct file *file,
                        /*
                         * possibly make it lock the array ...
                         */
-                       err = autostart_array((kdev_t)arg);
+                       err = autostart_array((kdev_t)arg, dev);
                        if (err) {
                                printk("autostart %s failed!\n",
                                        partition_name((kdev_t)arg));
@@ -2820,14 +2832,26 @@ abort:
 static int md_open (struct inode *inode, struct file *file)
 {
        /*
-        * Always succeed
+        * Always succeed, but increment the usage count
         */
+       mddev_t *mddev = kdev_to_mddev(inode->i_rdev);
+       if (mddev)
+               atomic_inc(&mddev->active);
        return (0);
 }
 
+static int md_release (struct inode *inode, struct file * file)
+{
+       mddev_t *mddev = kdev_to_mddev(inode->i_rdev);
+       if (mddev)
+               atomic_dec(&mddev->active);
+       return 0;
+}
+
 static struct block_device_operations md_fops=
 {
        open:           md_open,
+       release:        md_release,
        ioctl:          md_ioctl,
 };
 
@@ -3576,12 +3600,6 @@ static void md_geninit (void)
        create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL);
 #endif
 }
-void hsm_init (void);
-void translucent_init (void);
-void linear_init (void);
-void raid0_init (void);
-void raid1_init (void);
-void raid5_init (void);
 
 int md__init md_init (void)
 {
@@ -3617,18 +3635,6 @@ int md__init md_init (void)
        md_register_reboot_notifier(&md_notifier);
        raid_table_header = register_sysctl_table(raid_root_table, 1);
 
-#ifdef CONFIG_MD_LINEAR
-       linear_init ();
-#endif
-#ifdef CONFIG_MD_RAID0
-       raid0_init ();
-#endif
-#ifdef CONFIG_MD_RAID1
-       raid1_init ();
-#endif
-#ifdef CONFIG_MD_RAID5
-       raid5_init ();
-#endif
        md_geninit();
        return (0);
 }
index 09f3f854762f783b946f9431cfaa8810108d6786..576dd3b43a7c5cc1a6d720736603a91deaee041b 100644 (file)
@@ -275,16 +275,18 @@ static int raid0_make_request (mddev_t *mddev,
 
 bad_map:
        printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10);
-       return -1;
+       goto outerr;
 bad_hash:
        printk("raid0_make_request bug: hash==NULL for block %ld\n", block);
-       return -1;
+       goto outerr;
 bad_zone0:
        printk ("raid0_make_request bug: hash->zone0==NULL for block %ld\n", block);
-       return -1;
+       goto outerr;
 bad_zone1:
        printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block);
-       return -1;
+ outerr:
+       buffer_IO_error(bh);
+       return 0;
 }
                           
 static int raid0_status (char *page, mddev_t *mddev)
@@ -333,24 +335,17 @@ static mdk_personality_t raid0_personality=
        status:         raid0_status,
 };
 
-#ifndef MODULE
-
-void raid0_init (void)
-{
-       register_md_personality (RAID0, &raid0_personality);
-}
-
-#else
-
-int init_module (void)
+static int md__init raid0_init (void)
 {
-       return (register_md_personality (RAID0, &raid0_personality));
+       return register_md_personality (RAID0, &raid0_personality);
 }
 
-void cleanup_module (void)
+static void raid0_exit (void)
 {
        unregister_md_personality (RAID0);
 }
 
-#endif
+module_init(raid0_init);
+module_exit(raid0_exit);
+
 
index 85073b564683d5419a9e0173cac89772c3a5cf6b..3a381b6a22fc7fd34ff2f205d3346d7f222ea315 100644 (file)
@@ -463,16 +463,12 @@ static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh)
        if (conf->resync_mirrors)
                goto rb_out;
        
-       if (conf->working_disks < 2) {
-               int i = 0;
-               
-               while( !conf->mirrors[new_disk].operational &&
-                               (i < MD_SB_DISKS) ) {
-                       new_disk = conf->mirrors[new_disk].next;
-                       i++;
-               }
-               
-               if (i >= MD_SB_DISKS) {
+
+       /* make sure that disk is operational */
+       while( !conf->mirrors[new_disk].operational) {
+               if (new_disk <= 0) new_disk = conf->raid_disks;
+               new_disk--;
+               if (new_disk == disk) {
                        /*
                         * This means no working disk was found
                         * Nothing much to do, lets not change anything
@@ -480,11 +476,13 @@ static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh)
                         */
                        
                        new_disk = conf->last_used;
+
+                       goto rb_out;
                }
-               
-               goto rb_out;
        }
-
+       disk = new_disk;
+       /* now disk == new_disk == starting point for search */
+       
        /*
         * Don't touch anything for sequential reads.
         */
@@ -501,16 +499,16 @@ static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh)
        
        if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
                conf->sect_count = 0;
-               
-               while( new_disk != conf->mirrors[new_disk].next ) {
-                       if ((conf->mirrors[new_disk].write_only) ||
-                               (!conf->mirrors[new_disk].operational) )
-                               continue;
-                       
-                       new_disk = conf->mirrors[new_disk].next;
-                       break;
-               }
-               
+
+               do {
+                       if (new_disk<=0)
+                               new_disk = conf->raid_disks;
+                       new_disk--;
+                       if (new_disk == disk)
+                               break;
+               } while ((conf->mirrors[new_disk].write_only) ||
+                        (!conf->mirrors[new_disk].operational));
+
                goto rb_out;
        }
        
@@ -519,8 +517,10 @@ static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh)
        
        /* Find the disk which is closest */
        
-       while( conf->mirrors[disk].next != conf->last_used ) {
-               disk = conf->mirrors[disk].next;
+       do {
+               if (disk <= 0)
+                       disk = conf->raid_disks;
+               disk--;
                
                if ((conf->mirrors[disk].write_only) ||
                                (!conf->mirrors[disk].operational))
@@ -534,7 +534,7 @@ static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh)
                        current_distance = new_distance;
                        new_disk = disk;
                }
-       }
+       } while (disk != conf->last_used);
 
 rb_out:
        conf->mirrors[new_disk].head_position = this_sector + sectors;
@@ -702,16 +702,6 @@ static int raid1_status (char *page, mddev_t *mddev)
        return sz;
 }
 
-static void unlink_disk (raid1_conf_t *conf, int target)
-{
-       int disks = MD_SB_DISKS;
-       int i;
-
-       for (i = 0; i < disks; i++)
-               if (conf->mirrors[i].next == target)
-                       conf->mirrors[i].next = conf->mirrors[target].next;
-}
-
 #define LAST_DISK KERN_ALERT \
 "raid1: only one disk left and IO error.\n"
 
@@ -735,7 +725,6 @@ static void mark_disk_bad (mddev_t *mddev, int failed)
        mdp_super_t *sb = mddev->sb;
 
        mirror->operational = 0;
-       unlink_disk(conf, failed);
        mark_disk_faulty(sb->disks+mirror->number);
        mark_disk_nonsync(sb->disks+mirror->number);
        mark_disk_inactive(sb->disks+mirror->number);
@@ -786,25 +775,6 @@ static int raid1_error (mddev_t *mddev, kdev_t dev)
 #undef DISK_FAILED
 #undef START_SYNCING
 
-/*
- * Insert the spare disk into the drive-ring
- */
-static void link_disk(raid1_conf_t *conf, struct mirror_info *mirror)
-{
-       int j, next;
-       int disks = MD_SB_DISKS;
-       struct mirror_info *p = conf->mirrors;
-
-       for (j = 0; j < disks; j++, p++)
-               if (p->operational && !p->write_only) {
-                       next = p->next;
-                       p->next = mirror->raid_disk;
-                       mirror->next = next;
-                       return;
-               }
-
-       printk("raid1: bug: no read-operational devices\n");
-}
 
 static void print_raid1_conf (raid1_conf_t *conf)
 {
@@ -828,6 +798,32 @@ static void print_raid1_conf (raid1_conf_t *conf)
        }
 }
 
+static void close_sync(raid1_conf_t *conf)
+{
+       mddev_t *mddev = conf->mddev;
+       /* If reconstruction was interrupted, we need to close the "active" and "pending"
+        * holes.
+        * we know that there are no active rebuild requests, os cnt_active == cnt_ready ==0
+        */
+       /* this is really needed when recovery stops too... */
+       spin_lock_irq(&conf->segment_lock);
+       conf->start_active = conf->start_pending;
+       conf->start_ready = conf->start_pending;
+       wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock);
+       conf->start_active =conf->start_ready = conf->start_pending = conf->start_future;
+       conf->start_future = mddev->sb->size+1;
+       conf->cnt_pending = conf->cnt_future;
+       conf->cnt_future = 0;
+       conf->phase = conf->phase ^1;
+       wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock);
+       conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0;
+       conf->phase = 0;
+       conf->cnt_future = conf->cnt_done;;
+       conf->cnt_done = 0;
+       spin_unlock_irq(&conf->segment_lock);
+       wake_up(&conf->wait_done);
+}
+
 static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
 {
        int err = 0;
@@ -940,6 +936,7 @@ static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
         * Deactivate a spare disk:
         */
        case DISKOP_SPARE_INACTIVE:
+               close_sync(conf);
                sdisk = conf->mirrors + spare_disk;
                sdisk->operational = 0;
                sdisk->write_only = 0;
@@ -952,7 +949,7 @@ static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
         * property)
         */
        case DISKOP_SPARE_ACTIVE:
-
+               close_sync(conf);
                sdisk = conf->mirrors + spare_disk;
                fdisk = conf->mirrors + failed_disk;
 
@@ -1017,7 +1014,6 @@ static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
                 */
                fdisk->spare = 0;
                fdisk->write_only = 0;
-               link_disk(conf, fdisk);
 
                /*
                 * if we activate a spare, we definitely replace a
@@ -1244,27 +1240,7 @@ static void raid1syncd (void *data)
                conf->resync_mirrors = 0;
        }
 
-       /* If reconstruction was interrupted, we need to close the "active" and "pending"
-        * holes.
-        * we know that there are no active rebuild requests, os cnt_active == cnt_ready ==0
-        */
-       /* this is really needed when recovery stops too... */
-       spin_lock_irq(&conf->segment_lock);
-       conf->start_active = conf->start_pending;
-       conf->start_ready = conf->start_pending;
-       wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock);
-       conf->start_active =conf->start_ready = conf->start_pending = conf->start_future;
-       conf->start_future = mddev->sb->size+1;
-       conf->cnt_pending = conf->cnt_future;
-       conf->cnt_future = 0;
-       conf->phase = conf->phase ^1;
-       wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock);
-       conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0;
-       conf->phase = 0;
-       conf->cnt_future = conf->cnt_done;;
-       conf->cnt_done = 0;
-       spin_unlock_irq(&conf->segment_lock);
-       wake_up(&conf->wait_done);
+       close_sync(conf);
 
        up(&mddev->recovery_sem);
        raid1_shrink_buffers(conf);
@@ -1325,6 +1301,7 @@ static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr)
        struct raid1_bh *r1_bh;
        struct buffer_head *bh;
        int bsize;
+       int disk;
 
        spin_lock_irq(&conf->segment_lock);
        if (!block_nr) {
@@ -1377,6 +1354,16 @@ static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr)
         * could dedicate one to rebuild and others to
         * service read requests ..
         */
+       disk = conf->last_used;
+       /* make sure disk is operational */
+       while (!conf->mirrors[disk].operational) {
+               if (disk <= 0) disk = conf->raid_disks;
+               disk--;
+               if (disk == conf->last_used)
+                       break;
+       }
+       conf->last_used = disk;
+       
        mirror = conf->mirrors+conf->last_used;
        
        r1_bh = raid1_alloc_buf (conf);
@@ -1396,7 +1383,7 @@ static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr)
        bh->b_list = BUF_LOCKED;
        bh->b_dev = mirror->dev;
        bh->b_rdev = mirror->dev;
-       bh->b_state = (1<<BH_Req) | (1<<BH_Mapped);
+       bh->b_state = (1<<BH_Req) | (1<<BH_Mapped) | (1<<BH_Lock);
        if (!bh->b_page)
                BUG();
        if (!bh->b_data)
@@ -1717,19 +1704,10 @@ static int raid1_run (mddev_t *mddev)
         * find the first working one and use it as a starting point
         * to read balancing.
         */
-       for (j = 0; !conf->mirrors[j].operational; j++)
+       for (j = 0; !conf->mirrors[j].operational && j < MD_SB_DISKS; j++)
                /* nothing */;
        conf->last_used = j;
 
-       /*
-        * initialize the 'working disks' list.
-        */
-       for (i = conf->raid_disks - 1; i >= 0; i--) {
-               if (conf->mirrors[i].operational) {
-                       conf->mirrors[i].next = j;
-                       j = i;
-               }
-       }
 
        if (conf->working_disks != sb->raid_disks) {
                printk(KERN_ALERT "raid1: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev));
@@ -1882,19 +1860,16 @@ static mdk_personality_t raid1_personality=
        sync_request:   raid1_sync_request
 };
 
-int raid1_init (void)
+static int md__init raid1_init (void)
 {
        return register_md_personality (RAID1, &raid1_personality);
 }
 
-#ifdef MODULE
-int init_module (void)
-{
-       return raid1_init();
-}
-
-void cleanup_module (void)
+static void raid1_exit (void)
 {
        unregister_md_personality (RAID1);
 }
-#endif
+
+module_init(raid1_init);
+module_exit(raid1_exit);
+
index 45bc126df74f399138d8e2a4dfe6456f684b1249..55c50c5e7acfa5790facdea7ba4dcd8a6e9e0352 100644 (file)
@@ -2352,19 +2352,16 @@ static mdk_personality_t raid5_personality=
        sync_request:   raid5_sync_request
 };
 
-int raid5_init (void)
+static int md__init raid5_init (void)
 {
        return register_md_personality (RAID5, &raid5_personality);
 }
 
-#ifdef MODULE
-int init_module (void)
-{
-       return raid5_init();
-}
-
-void cleanup_module (void)
+static void raid5_exit (void)
 {
        unregister_md_personality (RAID5);
 }
-#endif
+
+module_init(raid5_init);
+module_exit(raid5_exit);
+
index e500de10dca1d0ba0776e94ff52b52a224e5aea1..571f8e84b58a2dccc4d5b8b7e505303ab0f04af4 100644 (file)
@@ -130,7 +130,7 @@ struct zoran
        int             tuner_type;     /* tuner type, when found       */
        int             running;        /* are we rolling?              */
        rwlock_t        lock;
-       int             state;          /* what is requested of us?     */
+       long            state;          /* what is requested of us?     */
 #define STATE_OVERLAY  0
 #define STATE_VBI      1
        struct vidinfo* workqueue;      /* buffers to grab, head is active */
index c9747479a1f5c60561a4ce8b70713607a429a630..87bf2e9b6857de3ef3aec1270a4d9ee7134438f9 100644 (file)
@@ -1,15 +1,21 @@
 
-# $Id: Config.in,v 1.20 2000/07/13 12:40:46 scote1 Exp $
+# $Id: No. :) $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
 
 tristate 'Memory Technology Device (MTD) support' CONFIG_MTD
 
-if [ "$CONFIG_MTD" != "n" ]; then
-   dep_tristate '  M-Systems Disk-On-Chip 1000 support' CONFIG_MTD_DOC1000 $CONFIG_MTD
-   dep_tristate '  M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD
-   dep_tristate '  M-Systems Disk-On-Chip Millennium' CONFIG_MTD_DOC2001 $CONFIG_MTD
+if [ "$CONFIG_MTD" = "y" -o "$CONFIG_MTD" = "m" ]; then
+   bool 'Debugging' CONFIG_MTD_DEBUG
+   if [ "$CONFIG_MTD_DEBUG" = "y" ]; then
+      int '  Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
+   fi
+
+comment 'Disk-On-Chip Device Drivers'
+   dep_tristate '  M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD
+   dep_tristate '  M-Systems Disk-On-Chip 2000 and Millennium' CONFIG_MTD_DOC2000 $CONFIG_MTD
+   dep_tristate '  M-Systems Disk-On-Chip Millennium-only alternative driver' CONFIG_MTD_DOC2001 $CONFIG_MTD
    if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
       define_tristate CONFIG_MTD_DOCPROBE y
    else
@@ -19,6 +25,13 @@ if [ "$CONFIG_MTD" != "n" ]; then
         define_tristate CONFIG_MTD_DOCPROBE n
       fi
    fi
+   if [ "$CONFIG_MTD_DOCPROBE" = "y" -o "$CONFIG_MTD_DOCPROBE" = "m" ]; then
+      hex  '    Physical address of DiskOnChip' CONFIG_MTD_DOCPROBE_ADDRESS 0x0000
+      bool '    Probe high addresses' CONFIG_MTD_DOCPROBE_HIGH
+      bool '    Probe for 0x55 0xAA BIOS Extension Signature' CONFIG_MTD_DOCPROBE_55AA
+   fi
+
+comment 'RAM/ROM Device Drivers'
    dep_tristate '  Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD
    dep_tristate '  Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI
    if [ "$CONFIG_MTD_PMC551" != "n" ]; then
@@ -31,20 +44,21 @@ if [ "$CONFIG_MTD" != "n" ]; then
       int 'Size of the erase sectors in kB' CONFIG_MTDRAM_ERASE_SIZE 128
    fi
 
-comment 'MTD drivers for mapped chips'
+comment 'Linearly Mapped Flash Device Drivers'
    dep_tristate '  Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
    dep_tristate '    CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI
    dep_tristate '    CFI support for AMD/Fujitsu Standard Command Set chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_CFI
+   dep_tristate '  Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
+   dep_tristate '  Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
 
 # These will later become config-options
 define_bool CONFIG_MTD_JEDEC n
-define_bool CONFIG_MTD_RAM n
-define_bool CONFIG_MTD_ROM n
 
-   dep_tristate '    Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
-   if [ "$CONFIG_MTD_PHYSMAP" != "n" ]; then
-      hex 'Physical start location of flash chip mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
-      hex 'Physical length of flash chip mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
+   dep_tristate '  Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
+   if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
+      hex '    Physical start location of flash chip mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
+      hex '    Physical length of flash chip mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
+      int '    Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
    fi
 
 comment 'Drivers for chip mappings'
@@ -57,11 +71,11 @@ comment 'Drivers for chip mappings'
 
 comment 'User modules and translation layers for MTD devices'
    dep_tristate '  Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
-   dep_tristate '  Pseudo-blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
+   dep_tristate '  Caching blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
    dep_tristate '  FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD
    dep_tristate '  NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD
-   if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFTL" != "n" ]; then
-      bool '    Write support for NFTL (EXPERIMENTAL)' CONFIG_NFTL_RW
+   if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
+      bool '    Write support for NFTL (BETA)' CONFIG_NFTL_RW
    fi
 fi
 
index 3f28868e389939d10d11e33eb3f9321164ac0deb..7fdbf65a4f445cef9dd83d1a981bd7018d387e44 100644 (file)
@@ -44,7 +44,7 @@ SUB_DIRS      :=
 ALL_SUB_DIRS   :=
 MOD_SUB_DIRS   :=
 
-export-objs    :=      mtdcore.o
+export-objs    :=      mtdcore.o mtdpart.o
 list-multi     :=
 
 # MTD devices
@@ -52,7 +52,7 @@ obj-$(CONFIG_MTD)             += mtdcore.o
 obj-$(CONFIG_MTD_DOC1000)      += doc1000.o
 obj-$(CONFIG_MTD_DOC2000)      += doc2000.o
 obj-$(CONFIG_MTD_DOC2001)      += doc2001.o
-obj-$(CONFIG_MTD_DOCPROBE)     += docprobe.o
+obj-$(CONFIG_MTD_DOCPROBE)     += docprobe.o docecc.o
 obj-$(CONFIG_MTD_SLRAM)                += slram.o
 obj-$(CONFIG_MTD_PMC551)       += pmc551.o
 obj-$(CONFIG_MTD_MTDRAM)       += mtdram.o
@@ -70,7 +70,7 @@ obj-$(CONFIG_MTD_PHYSMAP)     += physmap.o
 obj-$(CONFIG_MTD_MIXMEM)       += mixmem.o
 obj-$(CONFIG_MTD_NORA)         += nora.o
 obj-$(CONFIG_MTD_OCTAGON)      += octagon-5066.o
-obj-$(CONFIG_MTD_PNC2000)      += pnc2000.o
+obj-$(CONFIG_MTD_PNC2000)      += pnc2000.o mtdpart.o
 obj-$(CONFIG_MTD_RPXLITE)      += rpxlite.o
 obj-$(CONFIG_MTD_VMAX)         += vmax301.o
 
@@ -78,7 +78,7 @@ obj-$(CONFIG_MTD_VMAX)                += vmax301.o
 obj-$(CONFIG_MTD_CHAR)         += mtdchar.o
 obj-$(CONFIG_MTD_BLOCK)                += mtdblock.o
 obj-$(CONFIG_FTL)              += ftl.o
-obj-$(CONFIG_NFTL)             += nftl.o
+obj-$(CONFIG_NFTL)             += nftl.o nftlmount.o
 
 # Extract lists of the multi-part drivers.
 # The 'int-*' lists are the intermediate files used to build the multi's.
index cef67512b0d7b8c7c9a564378debac8cb93f0f12..22ef68e62fda2cae3b18732f6cace77712cc1292 100644 (file)
@@ -1,8 +1,11 @@
 
-/* Linux driver for Disk-On-Chip 2000       */
-/* (c) 1999 Machine Vision Holdings, Inc.   */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.c,v 1.24 2000/07/13 10:03:31 dwmw2 Exp $ */
+/*
+ * Linux driver for Disk-On-Chip 2000 and Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2000.c,v 1.39 2000/12/01 17:34:29 dwmw2 Exp $
+ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
-//#define PRERELEASE
+#define DOC_SUPPORT_2000
+#define DOC_SUPPORT_MILLENNIUM
 
-static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eecbuf);
-static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
-static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
+#ifdef DOC_SUPPORT_2000
+#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
+#else
+#define DoC_is_2000(doc) (0)
+#endif
 
+#ifdef DOC_SUPPORT_MILLENNIUM
+#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
+#else
+#define DoC_is_Millennium(doc) (0)
+#endif
+
+/* #define ECC_DEBUG */
+
+/* I have no idea why some DoC chips can not use memcpy_from|to_io().
+ * This may be due to the different revisions of the ASIC controller built-in or
+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
+ * this:
+ #undef USE_MEMCPY
+*/
+
+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+                   size_t *retlen, u_char *buf);
+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+                    size_t *retlen, const u_char *buf);
+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf, u_char *eccbuf);
+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
+                        size_t *retlen, const u_char *buf, u_char *eccbuf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+                       size_t *retlen, u_char *buf);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+                        size_t *retlen, const u_char *buf);
+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
 
 static struct mtd_info *doc2klist = NULL;
 
-/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+/* Perform the required delay cycles by reading from the appropriate register */
+static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles)
+{
+       volatile char dummy;
+       int i;
+       
+       for (i = 0; i < cycles; i++) {
+               if (DoC_is_Millennium(doc))
+                       dummy = ReadDOC(doc->virtadr, NOP);
+               else
+                       dummy = ReadDOC(doc->virtadr, DOCStatus);
+       }
+       
+}
 
-static int _DoC_WaitReady (unsigned long docptr)
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(struct DiskOnChip *doc)
 {
-       //long c=-1;
-       short c=-1;
+       unsigned long docptr = doc->virtadr;
+       unsigned short c = 0xffff;
 
-       DEBUG(2,"_DoC_WaitReady called for out-of-line wait\n");
+       DEBUG(MTD_DEBUG_LEVEL3,
+             "_DoC_WaitReady called for out-of-line wait\n");
 
        /* Out-of-line routine to wait for chip response */
        while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)
                ;
 
        if (c == 0)
-               DEBUG(2, "_DoC_WaitReady timed out.\n");
-       
-       return (c==0);
+               DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
+
+       return (c == 0);
 }
 
-static inline int DoC_WaitReady(unsigned long docptr) 
+static inline int DoC_WaitReady(struct DiskOnChip *doc)
 {
+       unsigned long docptr = doc->virtadr;
        /* This is inline, to optimise the common case, where it's ready instantly */
-       volatile char dummy;
        int ret = 0;
 
-        /* Out-of-line routine to wait for chip response */
-        /* TPW: Add 4 reads - see Software Requirement 2.3.2 */
-        dummy = ReadDOC(docptr, CDSNControl);
-        dummy = ReadDOC(docptr, CDSNControl);
-        dummy = ReadDOC(docptr, CDSNControl);
-        dummy = ReadDOC(docptr, CDSNControl);
-       
+       /* 4 read form NOP register should be issued in prior to the read from CDSNControl
+          see Software Requirement 11.4 item 2. */
+       DoC_Delay(doc, 4);
+
        if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
-               ret =  _DoC_WaitReady(docptr); /* Call the out-of-line routine to wait */
-       
-        /* TPW: Add 2 reads - see Software Requirement 2.3.2 */
-        dummy = ReadDOC(docptr, CDSNControl);
-        dummy = ReadDOC(docptr, CDSNControl);
+               /* Call the out-of-line routine to wait */
+               ret = _DoC_WaitReady(doc);
+
+       /* issue 2 read from NOP register after reading from CDSNControl register
+          see Software Requirement 11.4 item 2. */
+       DoC_Delay(doc, 2);
 
        return ret;
 }
 
+/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
 
-/* DoC_Command: Send a flash command to the flash chip */
-
-static inline int DoC_Command(unsigned long docptr, unsigned char command, unsigned char xtraflags)
+static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+                             unsigned char xtraflags)
 {
+       unsigned long docptr = doc->virtadr;
+
+       if (DoC_is_2000(doc))
+               xtraflags |= CDSN_CTRL_FLASH_IO;
+
        /* Assert the CLE (Command Latch Enable) line to the flash chip */
-       WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE,
-                docptr, CDSNControl);
+       WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       if (DoC_is_Millennium(doc))
+               WriteDOC(command, docptr, CDSNSlowIO);
 
        /* Send the command */
-       WriteDOC(command, docptr, 2k_CDSN_IO);
+       WriteDOC_(command, docptr, doc->ioreg);
+
        /* Lower the CLE line */
-       WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+       WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
 
-       /* Wait for the chip to respond */
-       return DoC_WaitReady(docptr);
+       /* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
+       return DoC_WaitReady(doc);
 }
 
-/* DoC_Address: Set the current address for the flash chip */
+/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
 
-static inline int DoC_Address (unsigned long docptr, int numbytes, unsigned long ofs,
-                              unsigned char xtraflags1, unsigned char xtraflags2)
+static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
+                      unsigned char xtraflags1, unsigned char xtraflags2)
 {
-       /* Assert the ALE (Address Latch Enable line to the flash chip */
-       WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE,
-                docptr, CDSNControl);
+       unsigned long docptr;
+       int i;
+
+       docptr = doc->virtadr;
+
+       if (DoC_is_2000(doc))
+               xtraflags1 |= CDSN_CTRL_FLASH_IO;
+
+       /* Assert the ALE (Address Latch Enable) line to the flash chip */
+       WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
 
        /* Send the address */
-       /* Three cases:
-          numbytes == 1: Send single byte, bits 0-7.
-          numbytes == 2: Send bits 9-16 followed by 17-23
-          numbytes == 3: Send 0-7, 9-16, then 17-23 
-       */
-       if (numbytes != 2)
-               WriteDOC(ofs & 0xff, docptr, 2k_CDSN_IO);
-       
-       if (numbytes != 1) {
-               WriteDOC((ofs >> 9) & 0xff, docptr, 2k_CDSN_IO);
-               WriteDOC((ofs >> 17) & 0xff, docptr, 2k_CDSN_IO);
+       /* Devices with 256-byte page are addressed as:
+          Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+          * there is no device on the market with page256
+          and more than 24 bits.
+          Devices with 512-byte page are addressed as:
+          Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+          * 25-31 is sent only if the chip support it.
+          * bit 8 changes the read command to be sent
+          (NAND_CMD_READ0 or NAND_CMD_READ1).
+        */
+
+       if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) {
+               if (DoC_is_Millennium(doc))
+                       WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+               WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
        }
-       /* Lower the ALE line */
-       WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
+
+       if (doc->page256) {
+               ofs = ofs >> 8;
+       } else {
+               ofs = ofs >> 9;
+       }
+
+       if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+               for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) {
+                       if (DoC_is_Millennium(doc))
+                               WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+                       WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+               }
+       }
+
+       DoC_Delay(doc, 2);      /* Needed for some slow flash chips. mf. */
        
-       /* Wait for the chip to respond */
-       return DoC_WaitReady(docptr);
+       /* FIXME: The SlowIO's for millennium could be replaced by 
+          a single WritePipeTerm here. mf. */
+
+       /* Lower the ALE line */
+       WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr,
+                CDSNControl);
+
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
+       /* Wait for the chip to respond - Software requirement 11.4.1 */
+       return DoC_WaitReady(doc);
+}
+
+/* Read a buffer from DoC, taking care of Millennium odditys */
+static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len)
+{
+       int dummy;
+       int modulus = 0xffff;
+       unsigned long docptr;
+       int i;
+
+       docptr = doc->virtadr;
+
+       if (len <= 0)
+               return;
+
+       if (DoC_is_Millennium(doc)) {
+               /* Read the data via the internal pipeline through CDSN IO register,
+                  see Pipelined Read Operations 11.3 */
+               dummy = ReadDOC(docptr, ReadPipeInit);
+
+               /* Millennium should use the LastDataRead register - Pipeline Reads */
+               len--;
+
+               /* This is needed for correctly ECC calculation */
+               modulus = 0xff;
+       }
+
+       for (i = 0; i < len; i++)
+               buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus));
+
+       if (DoC_is_Millennium(doc)) {
+               buf[i] = ReadDOC(docptr, LastDataRead);
+       }
+}
+
+/* Write a buffer to DoC, taking care of Millennium odditys */
+static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len)
+{
+       unsigned long docptr;
+       int i;
+
+       docptr = doc->virtadr;
+
+       if (len <= 0)
+               return;
+
+       for (i = 0; i < len; i++)
+               WriteDOC_(buf[i], docptr, doc->ioreg + i);
+
+       if (DoC_is_Millennium(doc)) {
+               WriteDOC(0x00, docptr, WritePipeTerm);
+       }
 }
 
+
 /* DoC_SelectChip: Select a given flash chip within the current floor */
 
-static inline int DoC_SelectChip(unsigned long docptr, int chip)
+static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
 {
+       unsigned long docptr = doc->virtadr;
+
+       /* Software requirement 11.4.4 before writing DeviceSelect */
+       /* Deassert the CE line to eliminate glitches on the FCE# outputs */
+       WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
        /* Select the individual flash chip requested */
-       WriteDOC( chip, docptr, CDSNDeviceSelect);
-       
+       WriteDOC(chip, docptr, CDSNDeviceSelect);
+       DoC_Delay(doc, 4);
+
+       /* Reassert the CE line */
+       WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr,
+                CDSNControl);
+       DoC_Delay(doc, 4);      /* Software requirement 11.4.3 for Millennium */
+
        /* Wait for it to be ready */
-       return DoC_WaitReady(docptr);
+       return DoC_WaitReady(doc);
 }
 
 /* DoC_SelectFloor: Select a given floor (bank of flash chips) */
 
-static inline int DoC_SelectFloor(unsigned long docptr, int floor)
+static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
 {
+       unsigned long docptr = doc->virtadr;
+
        /* Select the floor (bank) of chips required */
-       WriteDOC( floor, docptr, FloorSelect);
+       WriteDOC(floor, docptr, FloorSelect);
 
        /* Wait for the chip to be ready */
-       return DoC_WaitReady(docptr);
+       return DoC_WaitReady(doc);
 }
-  
+
 /* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
 
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-       int mfr, id, chipshift=0;
-       char *mfrname=NULL, *idname=NULL;
+       int mfr, id, i;
+       volatile char dummy;
 
        /* Page in the required floor/chip */
-       DoC_SelectFloor(doc->virtadr, floor);
-       DoC_SelectChip(doc->virtadr, chip);
+       DoC_SelectFloor(doc, floor);
+       DoC_SelectChip(doc, chip);
 
        /* Reset the chip */
-       if (DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP)) {
-               DEBUG(2, "DoC_Command (reset) for %d,%d returned true\n", floor,chip);
+       if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+               DEBUG(MTD_DEBUG_LEVEL2,
+                     "DoC_Command (reset) for %d,%d returned true\n",
+                     floor, chip);
                return 0;
        }
-  
-       /* Read the NAND chip ID: 1. Send ReadID command */ 
-       if(DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP)) {
-               DEBUG(2,"DoC_Command (ReadID) for %d,%d returned true\n", floor,chip);
+
+
+       /* Read the NAND chip ID: 1. Send ReadID command */
+       if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {
+               DEBUG(MTD_DEBUG_LEVEL2,
+                     "DoC_Command (ReadID) for %d,%d returned true\n",
+                     floor, chip);
                return 0;
        }
 
-       /* Read the NAND chip ID: 2. Send address byte zero 
-        */ 
-       DoC_Address(doc->virtadr, 1, 0, CDSN_CTRL_WP, 0);
+       /* Read the NAND chip ID: 2. Send address byte zero */
+       DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0);
+
        /* Read the manufacturer and device id codes from the device */
-       mfr = ReadDOC(doc->virtadr, 2k_CDSN_IO);
-       id = ReadDOC(doc->virtadr, 2k_CDSN_IO);
-       
+
+       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+       DoC_Delay(doc, 2);
+       mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+       DoC_Delay(doc, 2);
+       id = ReadDOC_(doc->virtadr, doc->ioreg);
+
        /* No response - return failure */
        if (mfr == 0xff || mfr == 0)
                return 0;
-       
+
        /* Check it's the same as the first chip we identified. 
         * M-Systems say that any given DiskOnChip device should only
         * contain _one_ type of flash part, although that's not a 
         * hardware restriction. */
        if (doc->mfr) {
                if (doc->mfr == mfr && doc->id == id)
-                       return 1; /* This is another the same the first */
+                       return 1;       /* This is another the same the first */
                else
-                       printk(KERN_WARNING "Flash chip at floor %d, chip %d is different:\n",
+                       printk(KERN_WARNING
+                              "Flash chip at floor %d, chip %d is different:\n",
                               floor, chip);
        }
-       
-       /* Print (and store if first time) the manufacturer and ID codes. */
-  
-       switch(mfr) {
-       case NAND_MFR_TOSHIBA: /* Toshiba */
-               mfrname = "Toshiba";
-               
-               switch(id) { 
-               case 0x64:
-                       idname = "TC5816BDC";
-                       chipshift = 21;
-                       break;
-                       
-               case 0x6b:
-                       idname = "TC5832DC";
-                       chipshift = 22;
-                       break;
-                       
-               case 0x73: 
-                       idname = "TH58V128DC";
-                       chipshift = 24;
-                       break;
-                       
-               case 0x75: 
-                       idname = "TC58256FT/DC";
-                       chipshift = 25;
-                       break;
-                       
-               case 0xe5:
-                       idname = "TC58V32DC";
-                       chipshift = 22;
-                       break;
-                       
-               case 0xe6: 
-                       idname = "TC58V64DC";
-                       chipshift = 23;
-                       break;
-                       
-               case 0xea:
-                       idname = "TC58V16BDC";
-                       chipshift = 21;
-                       break;
-               }
-               break; /* End of Toshiba parts */
-               
-       case NAND_MFR_SAMSUNG: /* Samsung */
-               mfrname = "Samsung";
-               
-               switch(id) {
-               case 0x64:
-                       idname = "KM29N16000";
-                       chipshift = 21;
-                       
-               case 0x73:
-                       idname = "KM29U128T";
-                       chipshift = 24;
-                       break;
-                       
-               case 0x75:
-                       idname = "KM29U256T";
-                       chipshift = 25;
-                       break;
-
-               case 0xe3:
-                       idname = "KM29W32000";
-                       chipshift = 22;
-                       break;
-                       
-               case 0xe6:
-                       idname = "KM29U64000";
-                       chipshift = 23;
-                       break;
-                       
-               case 0xea:
-                       idname = "KM29W16000";
-                       chipshift = 21;
-                       break;
-               }
-               break; /* End of Samsung parts */
-       }
-       
-       /* If we've identified it fully, print the full names */
-       if (idname) {
-#ifdef PRERELEASE
-               DEBUG(1, "Flash chip found: %2.2X %2.2X (%s %s)\n", 
-                       mfr,id,mfrname,idname);
-#endif
-               /* If this is the first chip, store the id codes */
-               if (!doc->mfr) {
-                       doc->mfr = mfr;
-                       doc->id = id;
-                       doc->chipshift = chipshift;
-                       return 1;
+
+       /* Print and store the manufacturer and ID codes. */
+       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+               if (mfr == nand_flash_ids[i].manufacture_id &&
+                   id == nand_flash_ids[i].model_id) {
+                       printk(KERN_INFO
+                              "Flash chip found: Manufacturer ID: %2.2X, "
+                              "Chip ID: %2.2X (%s)\n", mfr, id,
+                              nand_flash_ids[i].name);
+                       if (!doc->mfr) {
+                               doc->mfr = mfr;
+                               doc->id = id;
+                               doc->chipshift =
+                                   nand_flash_ids[i].chipshift;
+                               doc->page256 = nand_flash_ids[i].page256;
+                               doc->pageadrlen =
+                                   nand_flash_ids[i].pageadrlen;
+                               doc->erasesize =
+                                   nand_flash_ids[i].erasesize;
+                               return 1;
+                       }
+                       return 0;
                }
-               return 0;
        }
 
+
        /* We haven't fully identified the chip. Print as much as we know. */
-       if (mfrname)
-               printk(KERN_WARNING "Unknown %s flash chip found: %2.2X %2.2X\n", mfrname,
-                      id, mfr);
-       else
-               printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", id, mfr);
-       
-       printk(KERN_WARNING "Please report to David.Woodhouse@mvhi.com\n");
+       printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n",
+              id, mfr);
+
+       printk(KERN_WARNING "Please report to dwmw2@infradead.org\n");
        return 0;
-}     
+}
 
 /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
 
@@ -306,18 +406,22 @@ static void DoC_ScanChips(struct DiskOnChip *this)
 {
        int floor, chip;
        int numchips[MAX_FLOORS];
+       int maxchips = MAX_CHIPS;
        int ret = 1;
-       
+
        this->numchips = 0;
        this->mfr = 0;
        this->id = 0;
-       
+
+       if (DoC_is_Millennium(this))
+               maxchips = MAX_CHIPS_MIL;
+
        /* For each floor, find the number of valid chips it contains */
-       for (floor = 0 ; floor < MAX_FLOORS ; floor++) {
+       for (floor = 0; floor < MAX_FLOORS; floor++) {
                ret = 1;
-               numchips[floor]=0;
-               for (chip = 0 ; chip < MAX_CHIPS && ret != 0; chip++ ) {
-                       
+               numchips[floor] = 0;
+               for (chip = 0; chip < maxchips && ret != 0; chip++) {
+
                        ret = DoC_IdentChip(this, floor, chip);
                        if (ret) {
                                numchips[floor]++;
@@ -325,26 +429,26 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                        }
                }
        }
-       
+
        /* If there are none at all that we recognise, bail */
        if (!this->numchips) {
                printk("No flash chips recognised.\n");
                return;
        }
-       
+
        /* Allocate an array to hold the information for each chip */
        this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
-       if (!this->chips){
+       if (!this->chips) {
                printk("No memory for allocating chip info structures\n");
                return;
        }
-       
+
        ret = 0;
-       
+
        /* Fill out the chip array with {floor, chipno} for each 
         * detected chip in the device. */
        for (floor = 0; floor < MAX_FLOORS; floor++) {
-               for (chip = 0 ; chip < numchips[floor] ; chip++) {
+               for (chip = 0; chip < numchips[floor]; chip++) {
                        this->chips[ret].floor = floor;
                        this->chips[ret].chip = chip;
                        this->chips[ret].curadr = 0;
@@ -356,8 +460,9 @@ static void DoC_ScanChips(struct DiskOnChip *this)
        /* Calculate and print the total size of the device */
        this->totlen = this->numchips * (1 << this->chipshift);
 
-       printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mb\n", this->numchips ,
-              this->totlen >> 20);
+       printk(KERN_INFO
+              "%d flash chips found. Total DiskOnChip size: %ld Mb\n",
+              this->numchips, this->totlen >> 20);
 }
 
 
@@ -371,15 +476,15 @@ static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
         * purpose. If it's value is the same on both chips, they might
         * be the same chip, and we write to one and check for a change in
         * the other. It's unclear if this register is usuable in the
-        * DoC 2000 (it's in the Millenium docs), but it seems to work. */
+        * DoC 2000 (it's in the Millennium docs), but it seems to work. */
        tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
        tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
        if (tmp1 != tmp2)
                return 0;
-       
-       WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
+
+       WriteDOC((tmp1 + 1) % 0xff, doc1->virtadr, AliasResolution);
        tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
-       if (tmp2 == (tmp1+1) % 0xff)
+       if (tmp2 == (tmp1 + 1) % 0xff)
                retval = 1;
        else
                retval = 0;
@@ -387,11 +492,10 @@ static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
        /* Restore register contents.  May not be necessary, but do it just to
         * be safe. */
        WriteDOC(tmp1, doc1->virtadr, AliasResolution);
-       
+
        return retval;
 }
 
-
 static const char im_name[] = "DoC2k_init";
 
 /* This routine is made available to other mtd code via
@@ -403,36 +507,48 @@ static const char im_name[] = "DoC2k_init";
  */
 static void DoC2k_init(struct mtd_info *mtd)
 {
-       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+       struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        struct DiskOnChip *old = NULL;
 
        /* We must avoid being called twice for the same device. */
 
        if (doc2klist)
-               old = (struct DiskOnChip *)doc2klist->priv;
+               old = (struct DiskOnChip *) doc2klist->priv;
 
        while (old) {
                if (DoC2k_is_alias(old, this)) {
-                       printk(KERN_NOTICE "Ignoring DiskOnChip 2000 at 0x%lX - already configured\n",
+                       printk(KERN_NOTICE
+                              "Ignoring DiskOnChip 2000 at 0x%lX - already configured\n",
                               this->physadr);
-                       iounmap((void *)this->virtadr);
+                       iounmap((void *) this->virtadr);
                        kfree(mtd);
                        return;
                }
                if (old->nextdoc)
-                       old = (struct DiskOnChip *)old->nextdoc->priv;
+                       old = (struct DiskOnChip *) old->nextdoc->priv;
                else
                        old = NULL;
        }
-                       
-       
-       mtd->name = "DiskOnChip 2000";
-       printk(KERN_NOTICE "DiskOnChip 2000 found at address 0x%lX\n",this->physadr);
+
+
+       switch (this->ChipID) {
+       case DOC_ChipID_Doc2k:
+               mtd->name = "DiskOnChip 2000";
+               this->ioreg = DoC_2k_CDSN_IO;
+               break;
+       case DOC_ChipID_DocMil:
+               mtd->name = "DiskOnChip Millennium";
+               this->ioreg = DoC_Mil_CDSN_IO;
+               break;
+       }
+
+       printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
+              this->physadr);
 
        mtd->type = MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH;
        mtd->size = 0;
-       mtd->erasesize = 0x2000;
+       mtd->erasesize = 0;
        mtd->oobblock = 512;
        mtd->oobsize = 16;
        mtd->module = THIS_MODULE;
@@ -446,131 +562,182 @@ static void DoC2k_init(struct mtd_info *mtd)
        mtd->read_oob = doc_read_oob;
        mtd->write_oob = doc_write_oob;
        mtd->sync = NULL;
-       
+
        this->totlen = 0;
        this->numchips = 0;
-       
+
        this->curfloor = -1;
        this->curchip = -1;
-       
+
        /* Ident all the chips present. */
        DoC_ScanChips(this);
-       
+
        if (!this->totlen) {
                kfree(mtd);
-               iounmap((void *)this->virtadr);
+               iounmap((void *) this->virtadr);
        } else {
                this->nextdoc = doc2klist;
                doc2klist = mtd;
-               mtd->size  = this->totlen;
+               mtd->size = this->totlen;
+               mtd->erasesize = this->erasesize;
                add_mtd_device(mtd);
                return;
        }
 }
 
-
-static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+                   size_t * retlen, u_char * buf)
 {
        /* Just a special case of doc_read_ecc */
        return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
 }
 
-static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf)
+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t * retlen, u_char * buf, u_char * eccbuf)
 {
-       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-       int di=0; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+       struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        unsigned long docptr;
        struct Nand *mychip;
+       unsigned char syndrome[6];
+       volatile char dummy;
+       int i, len256 = 0, ret=0;
 
        docptr = this->virtadr;
 
        /* Don't allow read past end of device */
        if (from >= this->totlen)
                return -EINVAL;
-       
+
        /* Don't allow a single read to cross a 512-byte block boundary */
-       if (from + len > ( (from | 0x1ff) + 1)) 
+       if (from + len > ((from | 0x1ff) + 1))
                len = ((from | 0x1ff) + 1) - from;
 
+       /* The ECC will not be calculated correctly if less than 512 is read */
+       if (len != 0x200 && eccbuf)
+               printk(KERN_WARNING
+                      "ECC needs a full sector read (adr: %lx size %lx)\n",
+                      (long) from, (long) len);
+
+       /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
+
+
        /* Find the chip which is to be used and select it */
        mychip = &this->chips[from >> (this->chipshift)];
-       
+
        if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(docptr, mychip->floor);
-               DoC_SelectChip(docptr, mychip->chip);
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
        }
-       else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(docptr, mychip->chip);
-       }
-       
+
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
-       
+
+       DoC_Command(this,
+                   (!this->page256
+                    && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                   CDSN_CTRL_WP);
+       DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+                   CDSN_CTRL_ECC_IO);
 
        if (eccbuf) {
                /* Prime the ECC engine */
-               WriteDOC ( DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC ( DOC_ECC_EN, docptr, ECCConf);
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+       } else {
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
        }
 
-       DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
-       DoC_Address(docptr, 3, from, CDSN_CTRL_WP , CDSN_CTRL_ECC_IO);
+       /* treat crossing 256-byte sector for 2M x 8bits devices */
+       if (this->page256 && from + len > (from | 0xff) + 1) {
+               len256 = (from | 0xff) + 1 - from;
+               DoC_ReadBuf(this, buf, len256);
 
-       for (di=0; di < len ; di++) {
-               buf[di] = ReadDOC(docptr, 2k_CDSN_IO);
+               DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+               DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+                           CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
        }
 
+       DoC_ReadBuf(this, &buf[len256], len - len256);
+
        /* Let the caller know we completed it */
        *retlen = len;
 
        if (eccbuf) {
                /* Read the ECC data through the DiskOnChip ECC logic */
-               for (di=0; di<6; di++) {
-                       eccbuf[di] = ReadDOC(docptr, 2k_CDSN_IO);
-               }
-               
+               /* Note: this will work even with 2M x 8bit devices as   */
+               /*       they have 8 bytes of OOB per 256 page. mf.      */
+               DoC_ReadBuf(this, eccbuf, 6);
+
                /* Flush the pipeline */
-               (void) ReadDOC(docptr, 2k_ECCStatus);
-               (void) ReadDOC(docptr, 2k_ECCStatus);
-               
+               if (DoC_is_Millennium(this)) {
+                       dummy = ReadDOC(docptr, ECCConf);
+                       dummy = ReadDOC(docptr, ECCConf);
+                       i = ReadDOC(docptr, ECCConf);
+               } else {
+                       dummy = ReadDOC(docptr, 2k_ECCStatus);
+                       dummy = ReadDOC(docptr, 2k_ECCStatus);
+                       i = ReadDOC(docptr, 2k_ECCStatus);
+               }
+
                /* Check the ECC Status */
-               if (ReadDOC(docptr, 2k_ECCStatus) & 0x80) {
+               if (i & 0x80) {
+                       int nb_errors;
                        /* There was an ECC error */
+#ifdef ECC_DEBUG
                        printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+#endif
+                       /* Read the ECC syndrom through the DiskOnChip ECC logic.
+                          These syndrome will be all ZERO when there is no error */
+                       for (i = 0; i < 6; i++) {
+                               syndrome[i] =
+                                   ReadDOC(docptr, ECCSyndrome0 + i);
+                       }
+                        nb_errors = doc_decode_ecc(buf, syndrome);
 
-                       /* FIXME: Implement ECC error correction, don't just whinge */
-
-                       /* We return error, but have actually done the read. Not that
-                          this can be told to user-space, via sys_read(), but at least
-                          MTD-aware stuff can know about it by checking *retlen */
-                       return -EIO;
+#ifdef ECC_DEBUG
+                       printk("Errors corrected: %x\n", nb_errors);
+#endif
+                        if (nb_errors < 0) {
+                               /* We return error, but have actually done the read. Not that
+                                  this can be told to user-space, via sys_read(), but at least
+                                  MTD-aware stuff can know about it by checking *retlen */
+                               ret = -EIO;
+                        }
                }
+
 #ifdef PSYCHO_DEBUG
-               else
-                       printk("ECC OK at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                              (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4],
-                              eccbuf[5]);
+               printk("ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                            (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+                            eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
                
-               /* Reset the ECC engine */
-               WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
-               
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
        }
 
-       return 0;
+       return ret;
 }
 
-static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+                    size_t * retlen, const u_char * buf)
 {
-       static char as[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, as);
+       char eccbuf[6];
+       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
 }
 
-static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf)
+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
+                        size_t * retlen, const u_char * buf,
+                        u_char * eccbuf)
 {
-       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-       int di=0; 
+       struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+       int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
        unsigned long docptr;
+       volatile char dummy;
+       int len256 = 0;
        struct Nand *mychip;
 
        docptr = this->virtadr;
@@ -578,82 +745,118 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *r
        /* Don't allow write past end of device */
        if (to >= this->totlen)
                return -EINVAL;
-#if 0  
+
        /* Don't allow a single write to cross a 512-byte block boundary */
-       if (to + len > ( (to | 0x1ff) + 1)) 
+       if (to + len > ((to | 0x1ff) + 1))
                len = ((to | 0x1ff) + 1) - to;
 
-#else
-       /* Don't allow writes which aren't exactly one block */
-       if (to & 0x1ff || len != 0x200)
-               return -EINVAL;
-#endif
+       /* The ECC will not be calculated correctly if less than 512 is written */
+       if (len != 0x200 && eccbuf)
+               printk(KERN_WARNING
+                      "ECC needs a full sector write (adr: %lx size %lx)\n",
+                      (long) to, (long) len);
+
+       /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
 
        /* Find the chip which is to be used and select it */
        mychip = &this->chips[to >> (this->chipshift)];
-       
+
        if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(docptr, mychip->floor);
-               DoC_SelectChip(docptr, mychip->chip);
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
        }
-       else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(docptr, mychip->chip);
-       }
-       
+
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
-       
+
        /* Set device to main plane of flash */
-       DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
-       DoC_Command(docptr, NAND_CMD_READ0, CDSN_CTRL_WP);
+       DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+       DoC_Command(this,
+                   (!this->page256
+                    && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                   CDSN_CTRL_WP);
+
+       DoC_Command(this, NAND_CMD_SEQIN, 0);
+       DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
 
        if (eccbuf) {
                /* Prime the ECC engine */
-               WriteDOC ( DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC ( DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+       } else {
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
        }
 
-       DoC_Command(docptr, NAND_CMD_SEQIN, 0);
-       DoC_Address(docptr, 3, to, 0, CDSN_CTRL_ECC_IO);
+       /* treat crossing 256-byte sector for 2M x 8bits devices */
+       if (this->page256 && to + len > (to | 0xff) + 1) {
+               len256 = (to | 0xff) + 1 - to;
+               DoC_WriteBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+               DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+               /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
 
-       for (di=0; di < len ; di++) {
-               WriteDOC(buf[di], docptr, 2k_CDSN_IO);
+               if (ReadDOC_(docptr, this->ioreg) & 1) {
+                       printk("Error programming flash\n");
+                       /* Error in programming */
+                       *retlen = 0;
+                       return -EIO;
+               }
+
+               DoC_Command(this, NAND_CMD_SEQIN, 0);
+               DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+                           CDSN_CTRL_ECC_IO);
        }
 
+       DoC_WriteBuf(this, &buf[len256], len - len256);
 
        if (eccbuf) {
-               WriteDOC( CDSN_CTRL_ECC_IO | CDSN_CTRL_CE , docptr, CDSNControl );
-               
-#if 1
-               /* eduardp@m-sys.com says this shouldn't be necessary,
-                * but it doesn't actually work without it, so I've
-                * left it in for now. dwmw2.
-                */
-                
-               WriteDOC( 0, docptr, 2k_CDSN_IO);
-               WriteDOC( 0, docptr, 2k_CDSN_IO);
-               WriteDOC( 0, docptr, 2k_CDSN_IO);
-#endif
+               WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+                        CDSNControl);
+
+               if (DoC_is_Millennium(this)) {
+                       WriteDOC(0, docptr, NOP);
+                       WriteDOC(0, docptr, NOP);
+                       WriteDOC(0, docptr, NOP);
+               } else {
+                       WriteDOC_(0, docptr, this->ioreg);
+                       WriteDOC_(0, docptr, this->ioreg);
+                       WriteDOC_(0, docptr, this->ioreg);
+               }
+
                /* Read the ECC data through the DiskOnChip ECC logic */
-               for (di=0; di<6; di++) {
+               for (di = 0; di < 6; di++) {
                        eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
                }
+
+               /* Reset the ECC engine */
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
 #ifdef PSYCHO_DEBUG
-               printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                      (long) to, eccbuf[0], eccbuf[1], eccbuf[2],
-                      eccbuf[3], eccbuf[4], eccbuf[5]       );
+               printk
+                   ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                    (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+                    eccbuf[4], eccbuf[5]);
 #endif
-               /* Reset the ECC engine */
-               WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
-               
        }
 
-       DoC_Command(docptr, NAND_CMD_PAGEPROG, 0);
+       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
 
-       DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
        /* There's an implicit DoC_WaitReady() in DoC_Command */
 
-       if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+       dummy = ReadDOC(docptr, CDSNSlowIO);
+       DoC_Delay(this, 2);
+
+       if (ReadDOC_(docptr, this->ioreg) & 1) {
                printk("Error programming flash\n");
                /* Error in programming */
                *retlen = 0;
@@ -662,84 +865,155 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *r
 
        /* Let the caller know we completed it */
        *retlen = len;
+               
+       if (eccbuf) {
+               unsigned char x[8];
+               size_t dummy;
+
+               /* Write the ECC data to flash */
+               for (di=0; di<6; di++)
+                       x[di] = eccbuf[di];
+               
+               x[6]=0x55;
+               x[7]=0x55;
+               
+               return doc_write_oob(mtd, to, 8, &dummy, x);
+       }
 
        return 0;
 }
 
-
-
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+                       size_t * retlen, u_char * buf)
 {
-       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-       int i;
+       struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+       int len256 = 0;
        unsigned long docptr;
        struct Nand *mychip;
-       
+
        docptr = this->virtadr;
-       
+
        mychip = &this->chips[ofs >> this->chipshift];
-       
+
        if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(docptr, mychip->floor);
-               DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(docptr, mychip->chip);
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
-       
-       
-       
-       DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
-       DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0);
-       
-       for (i=0; i<len; i++)
-               buf[i] = ReadDOC(docptr, 2k_CDSN_IO);
-       
+
+       /* update address for 2M x 8bit devices. OOB starts on the second */
+       /* page to maintain compatibility with doc_read_ecc. */
+       if (this->page256) {
+               if (!(ofs & 0x8))
+                       ofs += 0x100;
+               else
+                       ofs -= 0x8;
+       }
+
+       DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+       DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0);
+
+       /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+       /* Note: datasheet says it should automaticaly wrap to the */
+       /*       next OOB block, but it didn't work here. mf.      */
+       if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+               len256 = (ofs | 0x7) + 1 - ofs;
+               DoC_ReadBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+               DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff),
+                           CDSN_CTRL_WP, 0);
+       }
+
+       DoC_ReadBuf(this, &buf[len256], len - len256);
+
        *retlen = len;
        return 0;
 
 }
 
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+                        size_t * retlen, const u_char * buf)
 {
-       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-       int i;
-       unsigned long docptr;
-       struct Nand *mychip;
+       struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+       int len256 = 0;
+       unsigned long docptr = this->virtadr;
+       struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+       int dummy;
 
-       //      printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
+       //      printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
        //   buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
 
-       docptr = this->virtadr;
-       
-       mychip = &this->chips[ofs >> this->chipshift];
-       
+       /* Find the chip which is to be used and select it */
        if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(docptr, mychip->floor);
-               DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(docptr, mychip->chip);
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
-       
-       DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
-       DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
 
-       DoC_Command(docptr, NAND_CMD_SEQIN, 0);
-       DoC_Address(docptr, 3, ofs, 0, 0);
-       
-       for (i=0; i<len; i++)
-               WriteDOC(buf[i], docptr, 2k_CDSN_IO);
+       /* disable the ECC engine */
+       WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+       WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+       /* Reset the chip, see Software Requirement 11.4 item 1. */
+       DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
 
-       DoC_Command(docptr, NAND_CMD_PAGEPROG, 0);
-       DoC_Command(docptr, NAND_CMD_STATUS, 0);
+       /* issue the Read2 command to set the pointer to the Spare Data Area. */
+       DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+       /* update address for 2M x 8bit devices. OOB starts on the second */
+       /* page to maintain compatibility with doc_read_ecc. */
+       if (this->page256) {
+               if (!(ofs & 0x8))
+                       ofs += 0x100;
+               else
+                       ofs -= 0x8;
+       }
+
+       /* issue the Serial Data In command to initial the Page Program process */
+       DoC_Command(this, NAND_CMD_SEQIN, 0);
+       DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0);
+
+       /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+       /* Note: datasheet says it should automaticaly wrap to the */
+       /*       next OOB block, but it didn't work here. mf.      */
+       if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+               len256 = (ofs | 0x7) + 1 - ofs;
+               DoC_WriteBuf(this, buf, len256);
+
+               DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+               DoC_Command(this, NAND_CMD_STATUS, 0);
+               /* DoC_WaitReady() is implicit in DoC_Command */
+
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
+
+               if (ReadDOC_(docptr, this->ioreg) & 1) {
+                       printk("Error programming oob data\n");
+                       /* There was an error */
+                       *retlen = 0;
+                       return -EIO;
+               }
+               DoC_Command(this, NAND_CMD_SEQIN, 0);
+               DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0);
+       }
+
+       DoC_WriteBuf(this, &buf[len256], len - len256);
+
+       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+       DoC_Command(this, NAND_CMD_STATUS, 0);
        /* DoC_WaitReady() is implicit in DoC_Command */
 
-       if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+       dummy = ReadDOC(docptr, CDSNSlowIO);
+       DoC_Delay(this, 2);
+
+       if (ReadDOC_(docptr, this->ioreg) & 1) {
                printk("Error programming oob data\n");
                /* There was an error */
                *retlen = 0;
@@ -751,102 +1025,89 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *r
 
 }
 
-
-int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
+int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+       struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        unsigned long ofs = instr->addr;
        unsigned long len = instr->len;
        unsigned long docptr;
        struct Nand *mychip;
-       
-       if(len != mtd->erasesize) 
-               printk(KERN_WARNING "Erase not right size (%lx != %lx)n", len, mtd->erasesize);
-               
+
+       if (len != mtd->erasesize)
+               printk(KERN_WARNING "Erase not right size (%lx != %lx)n",
+                      len, mtd->erasesize);
 
        docptr = this->virtadr;
-       
+
        mychip = &this->chips[ofs >> this->chipshift];
-       
+
        if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(docptr, mychip->floor);
-               DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(docptr, mychip->chip);
+               DoC_SelectFloor(this, mychip->floor);
+               DoC_SelectChip(this, mychip->chip);
+       } else if (this->curchip != mychip->chip) {
+               DoC_SelectChip(this, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
-       
+
        instr->state = MTD_ERASE_PENDING;
 
-       DoC_Command(docptr, NAND_CMD_ERASE1, 0);
-       DoC_Address(docptr, 2, ofs, 0, 0);
-       DoC_Command(docptr, NAND_CMD_ERASE2, 0);
+       DoC_Command(this, NAND_CMD_ERASE1, 0);
+       DoC_Address(this, ADDR_PAGE, ofs, 0, 0);
+       DoC_Command(this, NAND_CMD_ERASE2, 0);
 
        instr->state = MTD_ERASING;
 
-       DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
 
-       if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+       if (ReadDOC_(docptr, this->ioreg) & 1) {
                printk("Error writing\n");
                /* There was an error */
                instr->state = MTD_ERASE_FAILED;
-       }
-       else
+       } else
                instr->state = MTD_ERASE_DONE;
 
-       if (instr->callback) 
+       if (instr->callback)
                instr->callback(instr);
-                       
+
        return 0;
 }
 
 
-
-
-
 /****************************************************************************
  *
  * Module stuff
  *
  ****************************************************************************/
 
-static int __init init_doc2000(void)
-{
-       inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
-       return 0;
-}
-
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define cleanup_doc2000 cleanup_module
-#endif
-#define __exit
+#define init_doc2000 init_module
 #endif
 
+int __init init_doc2000(void)
+{
+       inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
+       return 0;
+}
 
 static void __exit cleanup_doc2000(void)
 {
        struct mtd_info *mtd;
        struct DiskOnChip *this;
 
-       while((mtd=doc2klist)) {
-               this = (struct DiskOnChip *)mtd->priv;
+       while ((mtd = doc2klist)) {
+               this = (struct DiskOnChip *) mtd->priv;
                doc2klist = this->nextdoc;
-                       
+
                del_mtd_device(mtd);
-                       
-               iounmap((void *)this->virtadr);
+
+               iounmap((void *) this->virtadr);
                kfree(this->chips);
                kfree(mtd);
        }
        inter_module_unregister(im_name);
-
 }
 
-module_init(init_doc2000);
-
-#if LINUX_VERSION_CODE > 0x20300
 module_exit(cleanup_doc2000);
-#endif
+module_init(init_doc2000);
index 8a9f032357f40714f8edbd6738ac48c3a407b538..79aa3630dbc30c81f2247d8ed372f2979cefad38 100644 (file)
@@ -1,7 +1,11 @@
-/* Linux driver for Disk-On-Chip Millennium */
-/* (c) 1999 Machine Vision Holdings, Inc.   */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2001.c,v 1.7 2000/07/13 10:41:39 dwmw2 Exp $ */
+
+/*
+ * Linux driver for Disk-On-Chip Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2001.c,v 1.24 2000/12/01 13:11:02 dwmw2 Exp $
+ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
-static struct {
-       char * name;
-       int manufacture_id;
-       int model_id;
-       int chipshift;
-} nand_flash_ids[] = {
-       {"Toshiba TC5816BDC",    NAND_MFR_TOSHIBA, 0x64, 21},
-       {"Toshiba TC5832DC",     NAND_MFR_TOSHIBA, 0x6b, 22},
-       {"Toshiba TH58V128DC",   NAND_MFR_TOSHIBA, 0x73, 24},
-       {"Toshiba TC58256FT/DC", NAND_MFR_TOSHIBA, 0x75, 25},
-       {"Toshiba TC58V32DC",    NAND_MFR_TOSHIBA, 0xe5, 22},
-       {"Toshiba TC58V64DC",    NAND_MFR_TOSHIBA, 0xe6, 23},
-       {"Toshiba TC58V16BDC",   NAND_MFR_TOSHIBA, 0xea, 21},
-       {"Samsung KM29N16000",   NAND_MFR_SAMSUNG, 0x64, 21},
-       {"Samsung KM29U128T",    NAND_MFR_SAMSUNG, 0x73, 24},
-       {"Samsung KM29U256T",    NAND_MFR_SAMSUNG, 0x75, 25},
-       {"Samsung KM29W32000",   NAND_MFR_SAMSUNG, 0xe3, 22},
-       {"Samsung KM29U64000",   NAND_MFR_SAMSUNG, 0xe6, 23},
-       {"Samsung KM29W16000",   NAND_MFR_SAMSUNG, 0xea, 21},
-       {NULL,}
-};
-
-static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
-                    size_t *retlen, u_char *buf);
-static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
-                     size_t *retlen, const u_char *buf);
-static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-                        size_t *retlen, u_char *buf, u_char *eecbuf);
-static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-                         size_t *retlen, const u_char *buf, u_char *eccbuf);
+/* #define ECC_DEBUG */
+
+/* I have no idea why some DoC chips can not use memcop_form|to_io().
+ * This may be due to the different revisions of the ASIC controller built-in or
+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
+ * this:
+ #undef USE_MEMCPY
+*/
+
+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+                   size_t *retlen, u_char *buf);
+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+                    size_t *retlen, const u_char *buf);
+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf, u_char *eccbuf);
+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
+                        size_t *retlen, const u_char *buf, u_char *eccbuf);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -58,6 +50,7 @@ static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
 
 static struct mtd_info *docmillist = NULL;
 
+/* Perform the required delay cycles by reading from the NOP register */
 static void DoC_Delay(unsigned long docptr, unsigned short cycles)
 {
        volatile char dummy;
@@ -72,14 +65,20 @@ static int _DoC_WaitReady(unsigned long docptr)
 {
        unsigned short c = 0xffff;
 
+       DEBUG(MTD_DEBUG_LEVEL3,
+             "_DoC_WaitReady called for out-of-line wait\n");
+
        /* Out-of-line routine to wait for chip response */
        while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)
                ;
 
+       if (c == 0)
+               DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
+
        return (c == 0);
 }
 
-static __inline__ int DoC_WaitReady(unsigned long docptr) 
+static inline int DoC_WaitReady(unsigned long docptr)
 {
        /* This is inline, to optimise the common case, where it's ready instantly */
        int ret = 0;
@@ -99,33 +98,35 @@ static __inline__ int DoC_WaitReady(unsigned long docptr)
        return ret;
 }
 
-/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to bypass
-   the internal pipeline. Each of 4 delay cycles (read from the NOP register) is required after
-   writing to CDSN Control register, see Software Requirement 11.4 item 3. */
-static __inline__ void DoC_Command(unsigned long docptr, unsigned char command,
-                                  unsigned char xtraflags)
+/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static inline void DoC_Command(unsigned long docptr, unsigned char command,
+                              unsigned char xtraflags)
 {
        /* Assert the CLE (Command Latch Enable) line to the flash chip */
-       WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+       WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
        DoC_Delay(docptr, 4);
 
        /* Send the command */
        WriteDOC(command, docptr, CDSNSlowIO);
        WriteDOC(command, docptr, Mil_CDSN_IO);
+
        /* Lower the CLE line */
        WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
        DoC_Delay(docptr, 4);
 }
 
-/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to bypass
-   the internal pipeline. Each of 4 delay cycles (read from the NOP register) is required after
-   writing to CDSN Control register, see Software Requirement 11.4 item 3. */
-static __inline__ void DoC_Address (unsigned long docptr, int numbytes, unsigned long ofs,
+/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
+   bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+   required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static inline void DoC_Address(unsigned long docptr, int numbytes, unsigned long ofs,
                               unsigned char xtraflags1, unsigned char xtraflags2)
 {
-       /* Assert the ALE (Address Latch Enable line to the flash chip */
-       WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+       /* Assert the ALE (Address Latch Enable) line to the flash chip */
+       WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
        DoC_Delay(docptr, 4);
 
        /* Send the address */
@@ -217,11 +218,11 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        if (mfr == 0xff || mfr == 0)
                return 0;
 
-       /* FIXME: to deal with mulit-flash on multi-Millennium case more carefully */
+       /* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
        for (i = 0; nand_flash_ids[i].name != NULL; i++) {
                if (mfr == nand_flash_ids[i].manufacture_id &&
                    id == nand_flash_ids[i].model_id) {
-                       printk(KERN_INFO "Flash chip found: Manufacture ID: %2.2X, "
+                       printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
                               "Chip ID: %2.2X (%s)\n",
                               mfr, id, nand_flash_ids[i].name);
                        doc->mfr = mfr;
@@ -235,7 +236,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                return 0;
        else
                return 1;
-}     
+}
 
 /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
 static void DoC_ScanChips(struct DiskOnChip *this)
@@ -243,11 +244,11 @@ static void DoC_ScanChips(struct DiskOnChip *this)
        int floor, chip;
        int numchips[MAX_FLOORS_MIL];
        int ret;
-       
+
        this->numchips = 0;
        this->mfr = 0;
        this->id = 0;
-       
+
        /* For each floor, find the number of valid chips it contains */
        for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) {
                numchips[floor] = 0;
@@ -264,14 +265,14 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                printk("No flash chips recognised.\n");
                return;
        }
-       
+
        /* Allocate an array to hold the information for each chip */
        this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
        if (!this->chips){
                printk("No memory for allocating chip info structures\n");
                return;
        }
-       
+
        /* Fill out the chip array with {floor, chipno} for each 
         * detected chip in the device. */
        for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) {
@@ -286,7 +287,7 @@ static void DoC_ScanChips(struct DiskOnChip *this)
 
        /* Calculate and print the total size of the device */
        this->totlen = this->numchips * (1 << this->chipshift);
-       printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mbytes\n",
+       printk(KERN_NOTICE "%d flash chips found. Total DiskOnChip size: %ld Mbytes\n",
               this->numchips ,this->totlen >> 20);
 }
 
@@ -317,7 +318,7 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
        /* Restore register contents.  May not be necessary, but do it just to
         * be safe. */
        WriteDOC(tmp1, doc1->virtadr, AliasResolution);
-       
+
        return retval;
 }
 
@@ -330,7 +331,7 @@ static const char im_name[] = "DoCMil_init";
  * this module is non-zero, i.e. between inter_module_get and
  * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
  */
-void DoCMil_init(struct mtd_info *mtd)
+static void DoCMil_init(struct mtd_info *mtd)
 {
        struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
        struct DiskOnChip *old = NULL;
@@ -355,12 +356,15 @@ void DoCMil_init(struct mtd_info *mtd)
 
        mtd->name = "DiskOnChip Millennium";
        printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",
-               this->physadr);
+              this->physadr);
 
        mtd->type = MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH;
        mtd->size = 0;
+
+       /* FIXME: erase size is not always 8kB */
        mtd->erasesize = 0x2000;
+
        mtd->oobblock = 512;
        mtd->oobsize = 16;
        mtd->module = THIS_MODULE;
@@ -374,15 +378,15 @@ void DoCMil_init(struct mtd_info *mtd)
        mtd->read_oob = doc_read_oob;
        mtd->write_oob = doc_write_oob;
        mtd->sync = NULL;
-       
+
        this->totlen = 0;
-       this->numchips = 0;     
+       this->numchips = 0;
        this->curfloor = -1;
        this->curchip = -1;
-       
+
        /* Ident all the chips present. */
        DoC_ScanChips(this);
-       
+
        if (!this->totlen) {
                kfree(mtd);
                iounmap((void *)this->virtadr);
@@ -405,8 +409,9 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
 static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                         size_t *retlen, u_char *buf, u_char *eccbuf)
 {
-       int i;
+       int i, ret;
        volatile char dummy;
+       unsigned char syndrome[6];
        struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
        unsigned long docptr = this->virtadr;
        struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -429,45 +434,55 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
 
+       /* issue the Read0 or Read1 command depend on which half of the page
+          we are accessing. Polling the Flash Ready bit after issue 3 bytes
+          address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/
+       DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
+       DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
+       DoC_WaitReady(docptr);
+
        if (eccbuf) {
                /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
                WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
                WriteDOC (DOC_ECC_EN, docptr, ECCConf);
        } else {
-               /* disable the ECC engine, FIXME: is this correct ?? */
+               /* disable the ECC engine */
                WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC (DOC_ECC_DIS, docptr, ECCConf);        
+               WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
        }
 
-       /* issue the Read0 or Read1 command depend on which half of the page
-          we are accessing. Polling the Flash Ready bit after issue 3 bytes
-          address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/
-       DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
-       DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
-       DoC_WaitReady(docptr);
-
        /* Read the data via the internal pipeline through CDSN IO register,
           see Pipelined Read Operations 11.3 */
        dummy = ReadDOC(docptr, ReadPipeInit);
+#ifndef USE_MEMCPY
        for (i = 0; i < len-1; i++) {
-               buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
+               /* N.B. you have to increase the source address in this way or the
+                  ECC logic will not work properly */
+               buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
        }
-       buf[i] = ReadDOC(docptr, LastDataRead);
+#else
+       memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
+#endif
+       buf[len - 1] = ReadDOC(docptr, LastDataRead);
 
        /* Let the caller know we completed it */
        *retlen = len;
+        ret = 0;
 
        if (eccbuf) {
-               /* FIXME: are we reading the ECC from the ECC logic of DOC or
-                  the spare data space on the flash chip i.e. How do we
-                  control the Spare Area Enable bit of the flash ?? */
-               /* Read the ECC data through the DiskOnChip ECC logic
+               /* Read the ECC data from Spare Data Area,
                   see Reed-Solomon EDC/ECC 11.1 */
                dummy = ReadDOC(docptr, ReadPipeInit);
+#ifndef USE_MEMCPY
                for (i = 0; i < 5; i++) {
-                       eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO);
+                       /* N.B. you have to increase the source address in this way or the
+                          ECC logic will not work properly */
+                       eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
                }
-               eccbuf[i] = ReadDOC(docptr, LastDataRead);
+#else
+               memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
+#endif
+               eccbuf[5] = ReadDOC(docptr, LastDataRead);
 
                /* Flush the pipeline */
                dummy = ReadDOC(docptr, ECCConf);
@@ -475,34 +490,45 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
 
                /* Check the ECC Status */
                if (ReadDOC(docptr, ECCConf) & 0x80) {
+                        int nb_errors;
                        /* There was an ECC error */
+#ifdef ECC_DEBUG
                        printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
-
-                       /* FIXME: Implement ECC error correction, don't just whinge */
-
-                       /* We return error, but have actually done the read. Not that
-                          this can be told to user-space, via sys_read(), but at least
-                          MTD-aware stuff can know about it by checking *retlen */
-                       return -EIO;
+#endif
+                       /* Read the ECC syndrom through the DiskOnChip ECC logic.
+                          These syndrome will be all ZERO when there is no error */
+                       for (i = 0; i < 6; i++) {
+                               syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
+                       }
+                        nb_errors = doc_decode_ecc(buf, syndrome);
+#ifdef ECC_DEBUG
+                       printk("Errors corrected: %x\n", nb_errors);
+#endif
+                        if (nb_errors < 0) {
+                               /* We return error, but have actually done the read. Not that
+                                  this can be told to user-space, via sys_read(), but at least
+                                  MTD-aware stuff can know about it by checking *retlen */
+                               ret = -EIO;
+                        }
                }
+
 #ifdef PSYCHO_DEBUG
-               else
-                       printk("ECC OK at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                              (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-                              eccbuf[4], eccbuf[5]);
+               printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                      (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+                      eccbuf[4], eccbuf[5]);
 #endif
-               /* Reset the ECC engine */
-               WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
+               /* disable the ECC engine */
+               WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
        }
 
-       return 0;
+       return ret;
 }
 
 static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
                      size_t *retlen, const u_char *buf)
 {
-       static char as[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, as);
+       char eccbuf[6];
+       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
 }
 
 static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
@@ -532,42 +558,48 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
        if (this->curfloor != mychip->floor) {
                DoC_SelectFloor(docptr, mychip->floor);
                DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
+       } else if (this->curchip != mychip->chip) {
                DoC_SelectChip(docptr, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
 
        /* Reset the chip, see Software Requirement 11.4 item 1. */
-       DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
+       DoC_Command(docptr, NAND_CMD_RESET, 0x00);
        DoC_WaitReady(docptr);
        /* Set device to main plane of flash */
-       DoC_Command(docptr, NAND_CMD_READ0, CDSN_CTRL_WP);
+       DoC_Command(docptr, NAND_CMD_READ0, 0x00);
+
+       /* issue the Serial Data In command to initial the Page Program process */
+       DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
+       DoC_Address(docptr, 3, to, 0x00, 0x00);
+       DoC_WaitReady(docptr);
 
        if (eccbuf) {
                /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
                WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
                WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
        } else {
-               /* disable the ECC engine, FIXME: is this correct ?? */
+               /* disable the ECC engine */
                WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
                WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
        }
 
-       /* issue the Serial Data In command to initial the Page Program process */
-       DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-       DoC_Address(docptr, 3, to, 0x00, 0x00);
-
        /* Write the data via the internal pipeline through CDSN IO register,
           see Pipelined Write Operations 11.2 */
+#ifndef USE_MEMCPY
        for (i = 0; i < len; i++) {
-               WriteDOC(buf[i], docptr, Mil_CDSN_IO);
+               /* N.B. you have to increase the source address in this way or the
+                  ECC logic will not work properly */
+               WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
        }
+#else
+       memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
+#endif
        WriteDOC(0x00, docptr, WritePipeTerm);
 
        if (eccbuf) {
-               /* Write ECC data to flash, the ECC info is generated by the DiskOnChip DECC logic
+               /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
                   see Reed-Solomon EDC/ECC 11.1 */
                WriteDOC(0, docptr, NOP);
                WriteDOC(0, docptr, NOP);
@@ -578,10 +610,26 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                        eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
                }
 
+               /* ignore the ECC engine */
+               WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+
+#ifndef USE_MEMCPY
                /* Write the ECC data to flash */
                for (i = 0; i < 6; i++) {
-                       WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO);
+                       /* N.B. you have to increase the source address in this way or the
+                          ECC logic will not work properly */
+                       WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
                }
+#else
+               memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
+#endif
+
+               /* write the block status BLOCK_USED (0x5555) at the end of ECC data
+                  FIXME: this is only a hack for programming the IPL area for LinuxBIOS
+                  and should be replace with proper codes in user space utilities */ 
+               WriteDOC(0x55, docptr, Mil_CDSN_IO);
+               WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
+
                WriteDOC(0x00, docptr, WritePipeTerm);
 
 #ifdef PSYCHO_DEBUG
@@ -589,9 +637,6 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                       (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
                       eccbuf[4], eccbuf[5]);
 #endif
-
-               /* Reset the ECC engine */
-               WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
        }
 
        /* Commit the Page Program command and wait for ready
@@ -601,12 +646,13 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
 
        /* Read the status of the flash device through CDSN Slow IO register
           see Software Requirement 11.4 item 5.*/
-       DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
+       DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
        dummy = ReadDOC(docptr, CDSNSlowIO);
        DoC_Delay(docptr, 2);
        if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
                printk("Error programming flash\n");
-               /* Error in programming */
+               /* Error in programming
+                  FIXME: implement Bad Block Replacement (in nftl.c ??) */
                *retlen = 0;
                return -EIO;
        }
@@ -620,31 +666,29 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t *retlen, u_char *buf)
 {
-       volatile char dummy;
+#ifndef USE_MEMCPY
        int i;
+#endif
+       volatile char dummy;
        struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
        unsigned long docptr = this->virtadr;
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
 
-       /* FIXME: should we restrict the access between 512 to 527 ?? */
-
        /* Find the chip which is to be used and select it */
        if (this->curfloor != mychip->floor) {
                DoC_SelectFloor(docptr, mychip->floor);
                DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
+       } else if (this->curchip != mychip->chip) {
                DoC_SelectChip(docptr, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
 
-       /* FIXME: should we disable ECC engine in this way ?? */
-       /* disable the ECC engine, FIXME: is this correct ?? */
+       /* disable the ECC engine */
        WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
        WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
 
-       /* issue the Read2 command to read the Spare Data Area.
+       /* issue the Read2 command to set the pointer to the Spare Data Area.
           Polling the Flash Ready bit after issue 3 bytes address in
           Sequence Read Mode, see Software Requirement 11.4 item 1.*/
        DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
@@ -654,10 +698,17 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
        /* Read the data out via the internal pipeline through CDSN IO register,
           see Pipelined Read Operations 11.3 */
        dummy = ReadDOC(docptr, ReadPipeInit);
+#ifndef USE_MEMCPY
        for (i = 0; i < len-1; i++) {
-               buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
+               /* N.B. you have to increase the source address in this way or the
+                  ECC logic will not work properly */
+               buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
        }
        buf[i] = ReadDOC(docptr, LastDataRead);
+#else
+       memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
+#endif
+       buf[len - 1] = ReadDOC(docptr, LastDataRead);
 
        *retlen = len;
 
@@ -667,32 +718,32 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                         size_t *retlen, const u_char *buf)
 {
+#ifndef USE_MEMCPY
        int i;
+#endif
        volatile char dummy;
        struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
        unsigned long docptr = this->virtadr;
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
 
        /* Find the chip which is to be used and select it */
-       if (this->curfloor != mychip->floor) {
+       if (this->curfloor != mychip->floor) {
                DoC_SelectFloor(docptr, mychip->floor);
                DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
+       } else if (this->curchip != mychip->chip) {
                DoC_SelectChip(docptr, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
 
-       /* FIXME: should we disable ECC engine in this way ?? */
-       /* disable the ECC engine, FIXME: is this correct ?? */
+       /* disable the ECC engine */
        WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
        WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
 
        /* Reset the chip, see Software Requirement 11.4 item 1. */
        DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
        DoC_WaitReady(docptr);
-       /* issue the Read2 command to read the Spare Data Area. */
+       /* issue the Read2 command to set the pointer to the Spare Data Area. */
        DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
 
        /* issue the Serial Data In command to initial the Page Program process */
@@ -701,8 +752,15 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 
        /* Write the data via the internal pipeline through CDSN IO register,
           see Pipelined Write Operations 11.2 */
-       for (i = 0; i < len; i++)
-               WriteDOC(buf[i], docptr, Mil_CDSN_IO);
+#ifndef USE_MEMCPY
+       for (i = 0; i < len; i++) {
+               /* N.B. you have to increase the source address in this way or the
+                  ECC logic will not work properly */
+               WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
+       }
+#else
+       memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
+#endif
        WriteDOC(0x00, docptr, WritePipeTerm);
 
        /* Commit the Page Program command and wait for ready
@@ -717,6 +775,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
        DoC_Delay(docptr, 2);
        if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
                printk("Error programming oob data\n");
+               /* FIXME: implement Bad Block Replacement (in nftl.c ??) */
                *retlen = 0;
                return -EIO;
        }
@@ -743,13 +802,12 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
        if (this->curfloor != mychip->floor) {
                DoC_SelectFloor(docptr, mychip->floor);
                DoC_SelectChip(docptr, mychip->chip);
-       }
-       else if (this->curchip != mychip->chip) {
+       } else if (this->curchip != mychip->chip) {
                DoC_SelectChip(docptr, mychip->chip);
        }
        this->curfloor = mychip->floor;
        this->curchip = mychip->chip;
-       
+
        instr->state = MTD_ERASE_PENDING;
 
        /* issue the Erase Setup command */
@@ -764,13 +822,16 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
        instr->state = MTD_ERASING;
 
        /* Read the status of the flash device through CDSN Slow IO register
-          see Software Requirement 11.4 item 5.*/
+          see Software Requirement 11.4 item 5.
+          FIXME: it seems that we are not wait long enough, some blocks are not
+          erased fully */
        DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
        dummy = ReadDOC(docptr, CDSNSlowIO);
        DoC_Delay(docptr, 2);
        if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
-               printk("Error Erasing\n");
-               /* There was an error */
+               printk("Error Erasing at 0x%lx\n", ofs);
+               /* There was an error
+                  FIXME: implement Bad Block Replacement (in nftl.c ??) */
                instr->state = MTD_ERASE_FAILED;
        } else
                instr->state = MTD_ERASE_DONE;
@@ -787,20 +848,17 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
  *
  ****************************************************************************/
 
-static int __init init_doc2001(void)
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cleanup_doc2001 cleanup_module
+#define init_doc2001 init_module
+#endif
+
+int __init init_doc2001(void)
 {
        inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
        return 0;
 }
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
-#define cleanup_doc2001 cleanup_module
-#endif
-#define __exit
-#endif
-
-
 static void __exit cleanup_doc2001(void)
 {
        struct mtd_info *mtd;
@@ -817,11 +875,9 @@ static void __exit cleanup_doc2001(void)
                kfree(mtd);
        }
        inter_module_unregister(im_name);
-
 }
 
+module_exit(cleanup_doc2001);
 module_init(init_doc2001);
 
-#if LINUX_VERSION_CODE > 0x20300
-module_exit(cleanup_doc2001);
-#endif
+
diff --git a/drivers/mtd/docecc.c b/drivers/mtd/docecc.c
new file mode 100644 (file)
index 0000000..cddc968
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * ECC algorithm for M-systems disk on chip. We use the excellent Reed
+ * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
+ * GNU GPL License. The rest is simply to convert the disk on chip
+ * syndrom into a standard syndom.
+ *
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: docecc.c,v 1.1 2000/11/03 12:43:43 dwmw2 Exp $
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/doc2000.h>
+
+/* need to undef it (from asm/termbits.h) */
+#undef B0
+
+#define MM 10 /* Symbol size in bits */
+#define KK (1023-4) /* Number of data symbols per block */
+#define B0 510 /* First root of generator polynomial, alpha form */
+#define PRIM 1 /* power of alpha used to generate roots of generator poly */
+#define        NN ((1 << MM) - 1)
+
+typedef unsigned short dtype;
+
+/* 1+x^3+x^10 */
+static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
+
+/* This defines the type used to store an element of the Galois Field
+ * used by the code. Make sure this is something larger than a char if
+ * if anything larger than GF(256) is used.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium.
+ */
+typedef int gf;
+
+/* No legal value in index form represents zero, so
+ * we need a special value for this purpose
+ */
+#define A0     (NN)
+
+/* Compute x % NN, where NN is 2**MM - 1,
+ * without a slow divide
+ */
+static inline gf
+modnn(int x)
+{
+  while (x >= NN) {
+    x -= NN;
+    x = (x >> MM) + (x & NN);
+  }
+  return x;
+}
+
+#define        min(a,b)        ((a) < (b) ? (a) : (b))
+
+#define        CLEAR(a,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = 0;\
+}
+
+#define        COPY(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define        COPYDOWN(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define Ldec 1
+
+/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
+   lookup tables:  index->polynomial form   alpha_to[] contains j=alpha**i;
+                   polynomial form -> index form  index_of[j=alpha**i] = i
+   alpha=2 is the primitive element of GF(2**m)
+   HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
+        Let @ represent the primitive element commonly called "alpha" that
+   is the root of the primitive polynomial p(x). Then in GF(2^m), for any
+   0 <= i <= 2^m-2,
+        @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
+   of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
+   example the polynomial representation of @^5 would be given by the binary
+   representation of the integer "alpha_to[5]".
+                   Similarily, index_of[] can be used as follows:
+        As above, let @ represent the primitive element of GF(2^m) that is
+   the root of the primitive polynomial p(x). In order to find the power
+   of @ (alpha) that has the polynomial representation
+        a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   we consider the integer "i" whose binary representation with a(0) being LSB
+   and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
+   "index_of[i]". Now, @^index_of[i] is that element whose polynomial 
+    representation is (a(0),a(1),a(2),...,a(m-1)).
+   NOTE:
+        The element alpha_to[2^m-1] = 0 always signifying that the
+   representation of "@^infinity" = 0 is (0,0,0,...,0).
+        Similarily, the element index_of[0] = A0 always signifying
+   that the power of alpha which has the polynomial representation
+   (0,0,...,0) is "infinity".
+*/
+
+static void
+generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
+{
+  register int i, mask;
+
+  mask = 1;
+  Alpha_to[MM] = 0;
+  for (i = 0; i < MM; i++) {
+    Alpha_to[i] = mask;
+    Index_of[Alpha_to[i]] = i;
+    /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
+    if (Pp[i] != 0)
+      Alpha_to[MM] ^= mask;    /* Bit-wise EXOR operation */
+    mask <<= 1;        /* single left-shift */
+  }
+  Index_of[Alpha_to[MM]] = MM;
+  /*
+   * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
+   * poly-repr of @^i shifted left one-bit and accounting for any @^MM
+   * term that may occur when poly-repr of @^i is shifted.
+   */
+  mask >>= 1;
+  for (i = MM + 1; i < NN; i++) {
+    if (Alpha_to[i - 1] >= mask)
+      Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
+    else
+      Alpha_to[i] = Alpha_to[i - 1] << 1;
+    Index_of[Alpha_to[i]] = i;
+  }
+  Index_of[0] = A0;
+  Alpha_to[NN] = 0;
+}
+
+/*
+ * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
+ * of the feedback shift register after having processed the data and
+ * the ECC.
+ *
+ * Return number of symbols corrected, or -1 if codeword is illegal
+ * or uncorrectable. If eras_pos is non-null, the detected error locations
+ * are written back. NOTE! This array must be at least NN-KK elements long.
+ * The corrected data are written in eras_val[]. They must be xor with the data
+ * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
+ * 
+ * First "no_eras" erasures are declared by the calling program. Then, the
+ * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
+ * If the number of channel errors is not greater than "t_after_eras" the
+ * transmitted codeword will be recovered. Details of algorithm can be found
+ * in R. Blahut's "Theory ... of Error-Correcting Codes".
+
+ * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
+ * will result. The decoder *could* check for this condition, but it would involve
+ * extra time on every decoding operation.
+ * */
+static int
+eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
+            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], 
+            int no_eras)
+{
+  int deg_lambda, el, deg_omega;
+  int i, j, r,k;
+  gf u,q,tmp,num1,num2,den,discr_r;
+  gf lambda[NN-KK + 1], s[NN-KK + 1];  /* Err+Eras Locator poly
+                                        * and syndrome poly */
+  gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
+  gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
+  int syn_error, count;
+
+  syn_error = 0;
+  for(i=0;i<NN-KK;i++)
+      syn_error |= bb[i];
+
+  if (!syn_error) {
+    /* if remainder is zero, data[] is a codeword and there are no
+     * errors to correct. So return data[] unmodified
+     */
+    count = 0;
+    goto finish;
+  }
+  
+  for(i=1;i<=NN-KK;i++){
+    s[i] = bb[0];
+  }
+  for(j=1;j<NN-KK;j++){
+    if(bb[j] == 0)
+      continue;
+    tmp = Index_of[bb[j]];
+    
+    for(i=1;i<=NN-KK;i++)
+      s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
+  }
+
+  /* undo the feedback register implicit multiplication and convert
+     syndromes to index form */
+
+  for(i=1;i<=NN-KK;i++) {
+      tmp = Index_of[s[i]];
+      if (tmp != A0)
+          tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
+      s[i] = tmp;
+  }
+  
+  CLEAR(&lambda[1],NN-KK);
+  lambda[0] = 1;
+
+  if (no_eras > 0) {
+    /* Init lambda to be the erasure locator polynomial */
+    lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
+    for (i = 1; i < no_eras; i++) {
+      u = modnn(PRIM*eras_pos[i]);
+      for (j = i+1; j > 0; j--) {
+       tmp = Index_of[lambda[j - 1]];
+       if(tmp != A0)
+         lambda[j] ^= Alpha_to[modnn(u + tmp)];
+      }
+    }
+#if DEBUG >= 1
+    /* Test code that verifies the erasure locator polynomial just constructed
+       Needed only for decoder debugging. */
+    
+    /* find roots of the erasure location polynomial */
+    for(i=1;i<=no_eras;i++)
+      reg[i] = Index_of[lambda[i]];
+    count = 0;
+    for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+      q = 1;
+      for (j = 1; j <= no_eras; j++)
+       if (reg[j] != A0) {
+         reg[j] = modnn(reg[j] + j);
+         q ^= Alpha_to[reg[j]];
+       }
+      if (q != 0)
+       continue;
+      /* store root and error location number indices */
+      root[count] = i;
+      loc[count] = k;
+      count++;
+    }
+    if (count != no_eras) {
+      printf("\n lambda(x) is WRONG\n");
+      count = -1;
+      goto finish;
+    }
+#if DEBUG >= 2
+    printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+    for (i = 0; i < count; i++)
+      printf("%d ", loc[i]);
+    printf("\n");
+#endif
+#endif
+  }
+  for(i=0;i<NN-KK+1;i++)
+    b[i] = Index_of[lambda[i]];
+  
+  /*
+   * Begin Berlekamp-Massey algorithm to determine error+erasure
+   * locator polynomial
+   */
+  r = no_eras;
+  el = no_eras;
+  while (++r <= NN-KK) {       /* r is the step number */
+    /* Compute discrepancy at the r-th step in poly-form */
+    discr_r = 0;
+    for (i = 0; i < r; i++){
+      if ((lambda[i] != 0) && (s[r - i] != A0)) {
+       discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
+      }
+    }
+    discr_r = Index_of[discr_r];       /* Index form */
+    if (discr_r == A0) {
+      /* 2 lines below: B(x) <-- x*B(x) */
+      COPYDOWN(&b[1],b,NN-KK);
+      b[0] = A0;
+    } else {
+      /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
+      t[0] = lambda[0];
+      for (i = 0 ; i < NN-KK; i++) {
+       if(b[i] != A0)
+         t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
+       else
+         t[i+1] = lambda[i+1];
+      }
+      if (2 * el <= r + no_eras - 1) {
+       el = r + no_eras - el;
+       /*
+        * 2 lines below: B(x) <-- inv(discr_r) *
+        * lambda(x)
+        */
+       for (i = 0; i <= NN-KK; i++)
+         b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
+      } else {
+       /* 2 lines below: B(x) <-- x*B(x) */
+       COPYDOWN(&b[1],b,NN-KK);
+       b[0] = A0;
+      }
+      COPY(lambda,t,NN-KK+1);
+    }
+  }
+
+  /* Convert lambda to index form and compute deg(lambda(x)) */
+  deg_lambda = 0;
+  for(i=0;i<NN-KK+1;i++){
+    lambda[i] = Index_of[lambda[i]];
+    if(lambda[i] != A0)
+      deg_lambda = i;
+  }
+  /*
+   * Find roots of the error+erasure locator polynomial by Chien
+   * Search
+   */
+  COPY(&reg[1],&lambda[1],NN-KK);
+  count = 0;           /* Number of roots of lambda(x) */
+  for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+    q = 1;
+    for (j = deg_lambda; j > 0; j--){
+      if (reg[j] != A0) {
+       reg[j] = modnn(reg[j] + j);
+       q ^= Alpha_to[reg[j]];
+      }
+    }
+    if (q != 0)
+      continue;
+    /* store root (index-form) and error location number */
+    root[count] = i;
+    loc[count] = k;
+    /* If we've already found max possible roots,
+     * abort the search to save time
+     */
+    if(++count == deg_lambda)
+      break;
+  }
+  if (deg_lambda != count) {
+    /*
+     * deg(lambda) unequal to number of roots => uncorrectable
+     * error detected
+     */
+    count = -1;
+    goto finish;
+  }
+  /*
+   * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+   * x**(NN-KK)). in index form. Also find deg(omega).
+   */
+  deg_omega = 0;
+  for (i = 0; i < NN-KK;i++){
+    tmp = 0;
+    j = (deg_lambda < i) ? deg_lambda : i;
+    for(;j >= 0; j--){
+      if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
+       tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
+    }
+    if(tmp != 0)
+      deg_omega = i;
+    omega[i] = Index_of[tmp];
+  }
+  omega[NN-KK] = A0;
+  
+  /*
+   * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+   * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
+   */
+  for (j = count-1; j >=0; j--) {
+    num1 = 0;
+    for (i = deg_omega; i >= 0; i--) {
+      if (omega[i] != A0)
+       num1  ^= Alpha_to[modnn(omega[i] + i * root[j])];
+    }
+    num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
+    den = 0;
+    
+    /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
+    for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
+      if(lambda[i+1] != A0)
+       den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
+    }
+    if (den == 0) {
+#if DEBUG >= 1
+      printf("\n ERROR: denominator = 0\n");
+#endif
+      /* Convert to dual- basis */
+      count = -1;
+      goto finish;
+    }
+    /* Apply error to data */
+    if (num1 != 0) {
+        eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
+    } else {
+        eras_val[j] = 0;
+    }
+  }
+ finish:
+  for(i=0;i<count;i++)
+      eras_pos[i] = loc[i];
+  return count;
+}
+
+/***************************************************************************/
+/* The DOC specific code begins here */
+
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA MM bits words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
+
+/* 
+ * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
+ * content of the feedback shift register applyied to the sector and
+ * the ECC. Return the number of errors corrected (and correct them in
+ * sector), or -1 if error 
+ */
+int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
+{
+    int parity, i, nb_errors;
+    gf bb[NN - KK + 1];
+    gf error_val[NN-KK];
+    int error_pos[NN-KK], pos, bitpos, index, val;
+    dtype *Alpha_to, *Index_of;
+
+    /* init log and exp tables here to save memory. However, it is slower */
+    Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
+    if (!Alpha_to)
+        return -1;
+    
+    Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
+    if (!Index_of) {
+        kfree(Alpha_to);
+        return -1;
+    }
+
+    generate_gf(Alpha_to, Index_of);
+
+    parity = ecc1[1];
+
+    bb[0] =  (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
+    bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
+    bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
+    bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
+
+    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, 
+                            error_val, error_pos, 0);
+    if (nb_errors <= 0)
+        goto the_end;
+
+    /* correct the errors */
+    for(i=0;i<nb_errors;i++) {
+        pos = error_pos[i];
+        if (pos >= NB_DATA && pos < KK) {
+            nb_errors = -1;
+            goto the_end;
+        }
+        if (pos < NB_DATA) {
+            /* extract bit position (MSB first) */
+            pos = 10 * (NB_DATA - 1 - pos) - 6;
+            /* now correct the following 10 bits. At most two bytes
+               can be modified since pos is even */
+            index = (pos >> 3) ^ 1;
+            bitpos = pos & 7;
+            if ((index >= 0 && index < SECTOR_SIZE) || 
+                index == (SECTOR_SIZE + 1)) {
+                val = error_val[i] >> (2 + bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+            index = ((pos >> 3) + 1) ^ 1;
+            bitpos = (bitpos + 10) & 7;
+            if (bitpos == 0)
+                bitpos = 8;
+            if ((index >= 0 && index < SECTOR_SIZE) || 
+                index == (SECTOR_SIZE + 1)) {
+                val = error_val[i] << (8 - bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+        }
+    }
+    
+    /* use parity to test extra errors */
+    if ((parity & 0xff) != 0)
+        nb_errors = -1;
+
+ the_end:
+    kfree(Alpha_to);
+    kfree(Index_of);
+    return nb_errors;
+}
+
index b38b4352dbcf55922a983282e1f5e8fa5956dc7a..c67a3489abaccbb2cfb668d52976992be3ae624f 100644 (file)
@@ -3,7 +3,7 @@
 /* Probe routines common to all DoC devices */
 /* (c) 1999 Machine Vision Holdings, Inc.   */
 /* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: docprobe.c,v 1.10 2000/07/13 14:23:20 dwmw2 Exp $ */
+/* $Id: docprobe.c,v 1.21 2000/12/03 19:32:34 dwmw2 Exp $ */
 
 
 
 #define DOC_PASSIVE_PROBE
 */
 
+
+/* DOC_SINGLE_DRIVER:
+   Millennium driver has been merged into DOC2000 driver.
+
+   The newly-merged driver doesn't appear to work for writing. It's the
+   same with the DiskOnChip 2000 and the Millennium. If you have a 
+   Millennium and you want write support to work, remove the definition
+   of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver.
+
+   Otherwise, it's left on in the hope that it'll annoy someone with
+   a Millennium enough that they go through and work out what the 
+   difference is :)
+*/
+#define DOC_SINGLE_DRIVER
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <asm/errno.h>
 #include <linux/mtd/doc2000.h>
 
 /* Where to look for the devices? */
+#ifndef CONFIG_MTD_DOCPROBE_ADDRESS
+#define CONFIG_MTD_DOCPROBE_ADDRESS 0
+#endif
+
+
+static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
+MODULE_PARM(doc_config_location, "l");
 
+
+static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__)
-static unsigned long __initdata doc_locations[] = { 
-               0xc8000, 0xca000, 0xcc000, 0xce000, 
-               0xd0000, 0xd2000, 0xd4000, 0xd6000,
-               0xd8000, 0xda000, 0xdc000, 0xde000, 
-               0xe0000, 0xe2000, 0xe4000, 0xe6000, 
-               0xe8000, 0xea000, 0xec000, 0xee000, 0 };
+#ifdef CONFIG_MTD_DOCPROBE_HIGH
+       0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
+       0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
+       0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
+       0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
+       0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
+#else /*  CONFIG_MTD_DOCPROBE_HIGH */
+       0xc8000, 0xca000, 0xcc000, 0xce000, 
+       0xd0000, 0xd2000, 0xd4000, 0xd6000,
+       0xd8000, 0xda000, 0xdc000, 0xde000, 
+       0xe0000, 0xe2000, 0xe4000, 0xe6000, 
+       0xe8000, 0xea000, 0xec000, 0xee000,
+#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__ppc__)
-static unsigned long __initdata doc_locations[] = {
-               0xe4000000, 0};
+       0xe4000000,
 #else 
 #warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
-
+       0 };
 
 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
 
@@ -71,10 +101,13 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
 #endif
 
        /* Routine copied from the Linux DOC driver */
-       
-       /* Check for 0x55 0xAA signature at beginning of window */
+
+#ifdef CONFIG_MTD_DOCPROBE_55AA
+       /* Check for 0x55 0xAA signature at beginning of window,
+          this is no longer true once we remove the IPL (for Millennium */
        if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
                return 0;
+#endif /* CONFIG_MTD_DOCPROBE_55AA */
 
 #ifndef DOC_PASSIVE_PROBE      
        /* It's not possible to cleanly detect the DiskOnChip - the
@@ -118,9 +151,10 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                break;
                
        default:
+#ifndef CONFIG_MTD_DOCPROBE_55AA
                printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
                       ChipID, physadr);
-
+#endif
 #ifndef DOC_PASSIVE_PROBE
                /* Put back the contents of the DOCControl register, in case it's not
                 * actually a DiskOnChip.
@@ -177,28 +211,35 @@ static void DoC_Probe(unsigned long physadr)
                this->physadr = physadr;
                this->ChipID = ChipID;
                sprintf(namebuf, "with ChipID %2.2X", ChipID);
-               
+
                switch(ChipID) {
                case DOC_ChipID_Doc2k:
                        name="2000";
                        im_funcname = "DoC2k_init";
                        im_modname = "doc2000";
                        break;
-
+                       
                case DOC_ChipID_DocMil:
                        name="Millennium";
+#ifdef DOC_SINGLE_DRIVER
+                       im_funcname = "DoC2k_init";
+                       im_modname = "doc2000";
+#else
                        im_funcname = "DoCMil_init";
                        im_modname = "doc2001";
+#endif /* DOC_SINGLE_DRIVER */
                        break;
                }
+
                if (im_funcname)
                        initroutine = inter_module_get_request(im_funcname, im_modname);
+
                if (initroutine) {
                        (*initroutine)(mtd);
                        inter_module_put(im_funcname);
                        return;
                }
-               printk("Cannot find driver for DiskOnChip %s at 0x%X\n", name, physadr);
+               printk("Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
        }
        iounmap((void *)docptr);
 }
@@ -210,12 +251,9 @@ static void DoC_Probe(unsigned long physadr)
  *
  ****************************************************************************/
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_doc init_module
 #endif
-#define __exit
-#endif
 
 int __init init_doc(void)
 {
@@ -223,19 +261,22 @@ int __init init_doc(void)
        
        printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n");
 #ifdef PRERELEASE
-       printk(KERN_INFO "$Id: docprobe.c,v 1.10 2000/07/13 14:23:20 dwmw2 Exp $\n");
+       printk(KERN_INFO "$Id: docprobe.c,v 1.21 2000/12/03 19:32:34 dwmw2 Exp $\n");
 #endif
-       
-       for (i=0; doc_locations[i]; i++) {
-               DoC_Probe(doc_locations[i]);
+       if (doc_config_location) {
+               printk("Using configured probe address 0x%lx\n", doc_config_location);
+               DoC_Probe(doc_config_location);
+       } else {
+               for (i=0; doc_locations[i]; i++) {
+                       DoC_Probe(doc_locations[i]);
+               }
        }
-       
+       /* So it looks like we've been used and we get unloaded */
+       MOD_INC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
        return 0;
        
 }
 
-
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_doc);
-#endif
 
index c62515406cea1641118c8e7bc8daf3ba23cda9f4..00c009d7fcb92c449807169b17d028979bb8beb4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Common code to handle map devices which are simple RAM
  * (C) 2000 Red Hat. GPL'd.
- * $Id: map_ram.c,v 1.2 2000/07/03 10:01:38 dwmw2 Exp $
+ * $Id: map_ram.c,v 1.7 2000/12/10 01:39:13 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -29,6 +29,7 @@ static const char im_name[] = "map_ram_probe";
  * this module is non-zero, i.e. between inter_module_get and
  * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
  */
+
 static struct mtd_info *map_ram_probe(struct map_info *map)
 {
        struct mtd_info *mtd;
@@ -59,6 +60,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
 
        memset(mtd, 0, sizeof(*mtd));
 
+       map->im_name = im_name;
        map->fldrv_destroy = mapram_nop;
        mtd->priv = map;
        mtd->name = map->name;
@@ -69,9 +71,9 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
        mtd->read = mapram_read;
        mtd->write = mapram_write;
        mtd->sync = mapram_nop;
-       mtd->im_name = im_name;
        mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
-       
+       mtd->erasesize = PAGE_SIZE;
+
        return mtd;
 }
 
@@ -115,6 +117,11 @@ static void mapram_nop(struct mtd_info *mtd)
        /* Nothing to see here */
 }
 
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define map_ram_init init_module
+#define map_ram_exit cleanup_module
+#endif
+
 static int __init map_ram_init(void)
 {
        inter_module_register(im_name, THIS_MODULE, &map_ram_probe);
index d353938e9457abb9b03812dd524e7295ad872ac5..c976c7ecf54ff54f641c128e4a9066d39330d0b9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Common code to handle map devices which are simple ROM
  * (C) 2000 Red Hat. GPL'd.
- * $Id: map_rom.c,v 1.2 2000/07/03 10:01:38 dwmw2 Exp $
+ * $Id: map_rom.c,v 1.10 2000/12/10 01:39:13 dwmw2 Exp $
  */
 
 #include <linux/module.h>
 
 #include <linux/mtd/map.h>
 
-
 static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static void maprom_nop (struct mtd_info *);
 
-struct mtd_info *map_rom_probe(struct map_info *);
-EXPORT_SYMBOL(map_rom_probe);
+static const char im_name[] = "map_rom_probe";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
 
 struct mtd_info *map_rom_probe(struct map_info *map)
 {
@@ -31,16 +38,18 @@ struct mtd_info *map_rom_probe(struct map_info *map)
 
        memset(mtd, 0, sizeof(*mtd));
 
+       map->im_name = im_name;
        map->fldrv_destroy = maprom_nop;
        mtd->priv = map;
        mtd->name = map->name;
        mtd->type = MTD_ROM;
        mtd->size = map->size;
        mtd->read = maprom_read;
+       mtd->write = maprom_write;
        mtd->sync = maprom_nop;
        mtd->flags = MTD_CAP_ROM;
-       
-       MOD_INC_USE_COUNT;
+       mtd->erasesize = 131072;
+
        return mtd;
 }
 
@@ -58,3 +67,28 @@ static void maprom_nop(struct mtd_info *mtd)
 {
        /* Nothing to see here */
 }
+
+static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+       printk(KERN_NOTICE "maprom_write called\n");
+       return -EIO;
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define map_rom_init init_module
+#define map_rom_exit cleanup_module
+#endif
+
+static int __init map_rom_init(void)
+{
+       inter_module_register(im_name, THIS_MODULE, &map_rom_probe);
+       return 0;
+}
+
+static void __exit map_rom_exit(void)
+{
+       inter_module_unregister(im_name);
+}
+
+module_init(map_rom_init);
+module_exit(map_rom_exit);
index b728ddcd2c240b3ef673076925408dc90a2850bb..0a33ed1cf0e6ed4dadbf449d6cdb6743e8e8d1ac 100644 (file)
@@ -1,16 +1,15 @@
 /* 
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.17 2000/07/13 14:25:54 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.38 2000/11/27 08:50:22 dwmw2 Exp $
+ *
+ * 02-nov-2000 Nicolas Pitre           Added read-modify-write with cache
  */
 
-#ifdef MTDBLOCK_DEBUG
-#define DEBUGLVL debug
-#endif                                                        
-
 #include <linux/types.h>
 #include <linux/module.h>
-
+#include <linux/kernel.h>
+#include <linux/malloc.h>
 #include <linux/mtd/mtd.h>
 
 #define MAJOR_NR MTD_BLOCK_MAJOR
 #define DEVICE_OFF(device)
 #define DEVICE_NO_RANDOM
 #include <linux/blk.h>
-
+/* for old kernels... */
+#ifndef QUEUE_EMPTY
+#define QUEUE_EMPTY  (!CURRENT)
+#endif
 #if LINUX_VERSION_CODE < 0x20300
-#define RQFUNC_ARG void
-#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
+#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
 #else
-#define RQFUNC_ARG request_queue_t *q
+#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
 #endif
 
-#ifdef MTDBLOCK_DEBUG
-static int debug = MTDBLOCK_DEBUG;
-MODULE_PARM(debug, "i");
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+static void mtd_notify_add(struct mtd_info* mtd);
+static void mtd_notify_remove(struct mtd_info* mtd);
+static struct mtd_notifier notifier = {
+        mtd_notify_add,
+        mtd_notify_remove,
+        NULL
+};
+static devfs_handle_t devfs_dir_handle = NULL;
+static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
 #endif
 
-#if 1
-static void mtdblock_end_request(struct request *req, int res)
+static struct mtdblk_dev {
+       struct mtd_info *mtd; /* Locked */
+       int count;
+       struct semaphore cache_sem;
+       unsigned char *cache_data;
+       unsigned long cache_offset;
+       unsigned int cache_size;
+       enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
+} *mtdblks[MAX_MTD_DEVICES];
+
+static spinlock_t mtdblks_lock;
+
+static int mtd_sizes[MAX_MTD_DEVICES];
+static int mtd_blksizes[MAX_MTD_DEVICES];
+
+
+/*
+ * Cache stuff...
+ * 
+ * Since typical flash erasable sectors are much larger than what Linux's
+ * buffer cache can handle, we must implement read-modify-write on flash
+ * sectors for each block write requests.  To avoid over-erasing flash sectors
+ * and to speed things up, we locally cache a whole flash sector while it is
+ * being written to until a different sector is required.
+ */
+
+static void erase_callback(struct erase_info *done)
 {
-       if (end_that_request_first( req, res, "mtdblock" ))
-                return;
-        end_that_request_last( req );
+       wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+       wake_up(wait_q);
 }
-#endif
 
-static int mtd_sizes[MAX_MTD_DEVICES];
+static int erase_write (struct mtd_info *mtd, unsigned long pos, 
+                       int len, const char *buf)
+{
+       struct erase_info erase;
+       DECLARE_WAITQUEUE(wait, current);
+       wait_queue_head_t wait_q;
+       size_t retlen;
+       int ret;
+
+       /*
+        * First, let's erase the flash block.
+        */
+
+       init_waitqueue_head(&wait_q);
+       erase.mtd = mtd;
+       erase.callback = erase_callback;
+       erase.addr = pos;
+       erase.len = len;
+       erase.priv = (u_long)&wait_q;
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&wait_q, &wait);
+
+       ret = MTD_ERASE(mtd, &erase);
+       if (ret) {
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&wait_q, &wait);
+               printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "
+                                    "on \"%s\" failed\n",
+                       pos, len, mtd->name);
+               return ret;
+       }
 
+       schedule();  /* Wait for erase to finish. */
+       remove_wait_queue(&wait_q, &wait);
 
-/* Keeping a separate list rather than just getting stuff directly out of 
-   the MTD core's mtd_table is perhaps not very nice, but I happen
-   to dislike the idea of directly accessing mtd_table even more.
-   dwmw2 31/3/0
-*/
+       /*
+        * Next, writhe data to flash.
+        */
 
-static int mtdblock_open(struct inode *inode, struct file *file)
+       ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
+       if (ret)
+               return ret;
+       if (retlen != len)
+               return -EIO;
+       return 0;
+}
+
+
+static int write_cached_data (struct mtdblk_dev *mtdblk)
+{
+       struct mtd_info *mtd = mtdblk->mtd;
+       int ret;
+
+       if (mtdblk->cache_state != STATE_DIRTY)
+               return 0;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
+                       "at 0x%lx, size 0x%x\n", mtd->name, 
+                       mtdblk->cache_offset, mtdblk->cache_size);
+       
+       ret = erase_write (mtd, mtdblk->cache_offset, 
+                          mtdblk->cache_size, mtdblk->cache_data);
+       if (ret)
+               return ret;
+
+       /*
+        * Here we could argably set the cache state to STATE_CLEAN.
+        * However this could lead to inconsistency since we will not 
+        * be notified if this content is altered on the flash by other 
+        * means.  Let's declare it empty and leave buffering tasks to
+        * the buffer cache instead.
+        */
+       mtdblk->cache_state = STATE_EMPTY;
+       return 0;
+}
+
+
+static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, 
+                           int len, const char *buf)
 {
-       struct mtd_info *mtd = NULL;
+       struct mtd_info *mtd = mtdblk->mtd;
+       unsigned int sect_size = mtd->erasesize;
+       size_t retlen;
+       int ret;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
+               mtd->name, pos, len);
+       
+       while (len > 0) {
+               unsigned long sect_start = (pos/sect_size)*sect_size;
+               unsigned int offset = pos - sect_start;
+               unsigned int size = sect_size - offset;
+               if( size > len ) 
+                       size = len;
+
+               if (size == sect_size) {
+                       /* 
+                        * We are covering a whole sector.  Thus there is no
+                        * need to bother with the cache while it may still be
+                        * useful for other partial writes.
+                        */
+                       ret = erase_write (mtd, pos, size, buf);
+                       if (ret)
+                               return ret;
+               } else {
+                       /* Partial sector: need to use the cache */
+
+                       if (mtdblk->cache_state == STATE_DIRTY &&
+                           mtdblk->cache_offset != sect_start) {
+                               ret = write_cached_data(mtdblk);
+                               if (ret) 
+                                       return ret;
+                       }
+
+                       if (mtdblk->cache_state == STATE_EMPTY ||
+                           mtdblk->cache_offset != sect_start) {
+                               /* fill the cache with the current sector */
+                               mtdblk->cache_state = STATE_EMPTY;
+                               ret = MTD_READ(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data);
+                               if (ret)
+                                       return ret;
+                               if (retlen != sect_size)
+                                       return -EIO;
+
+                               mtdblk->cache_offset = sect_start;
+                               mtdblk->cache_size = sect_size;
+                               mtdblk->cache_state = STATE_CLEAN;
+                       }
+
+                       /* write data to our local cache */
+                       memcpy (mtdblk->cache_data + offset, buf, size);
+                       mtdblk->cache_state = STATE_DIRTY;
+               }
+
+               buf += size;
+               pos += size;
+               len -= size;
+       }
+
+       return 0;
+}
+
+
+static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, 
+                          int len, char *buf)
+{
+       struct mtd_info *mtd = mtdblk->mtd;
+       unsigned int sect_size = mtd->erasesize;
+       size_t retlen;
+       int ret;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", 
+                       mtd->name, pos, len);
+       
+       while (len > 0) {
+               unsigned long sect_start = (pos/sect_size)*sect_size;
+               unsigned int offset = pos - sect_start;
+               unsigned int size = sect_size - offset;
+               if (size > len) 
+                       size = len;
+
+               /*
+                * Check if the requested data is already cached
+                * Read the requested amount of data from our internal cache if it
+                * contains what we want, otherwise we read the data directly
+                * from flash.
+                */
+               if (mtdblk->cache_state != STATE_EMPTY &&
+                   mtdblk->cache_offset == sect_start) {
+                       memcpy (buf, mtdblk->cache_data + offset, size);
+               } else {
+                       ret = MTD_READ (mtd, pos, size, &retlen, buf);
+                       if (ret)
+                               return ret;
+                       if (retlen != size)
+                               return -EIO;
+               }
+
+               buf += size;
+               pos += size;
+               len -= size;
+       }
+
+       return 0;
+}
+
 
+
+static int mtdblock_open(struct inode *inode, struct file *file)
+{
+       struct mtdblk_dev *mtdblk;
        int dev;
 
-       DEBUG(1,"mtdblock_open\n");
+       DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
        
-       if (inode == 0)
+       if (!inode)
                return -EINVAL;
        
        dev = MINOR(inode->i_rdev);
+       if (dev >= MAX_MTD_DEVICES)
+               return -EINVAL;
        
        MOD_INC_USE_COUNT;
 
-       mtd = get_mtd_device(NULL, dev);
+       spin_lock(&mtdblks_lock);
+
+       /* If it's already open, no need to piss about. */
+       if (mtdblks[dev]) {
+               mtdblks[dev]->count++;
+               spin_unlock(&mtdblks_lock);
+               return 0;
+       }
+       
+       /* OK, it's not open. Try to find it */
+
+       /* First we have to drop the lock, because we have to
+          to things which might sleep.
+       */
+       spin_unlock(&mtdblks_lock);
+
+       mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
+       if (!mtdblk) {
+               MOD_DEC_USE_COUNT;
+               return -ENOMEM;
+       }
+       memset(mtdblk, 0, sizeof(*mtdblk));
+       mtdblk->count = 1;
+       mtdblk->mtd = get_mtd_device(NULL, dev);
 
-       if (!mtd) {
+       if (!mtdblk->mtd) {
+               kfree(mtdblk);
                MOD_DEC_USE_COUNT;
                return -ENODEV;
        }
 
-       mtd_sizes[dev] = mtd->size>>9;
+       init_MUTEX (&mtdblk->cache_sem);
+       mtdblk->cache_state = STATE_EMPTY;
+       mtdblk->cache_size = mtdblk->mtd->erasesize;
+       mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
+       if (!mtdblk->cache_data) {
+               put_mtd_device(mtdblk->mtd);
+               kfree(mtdblk);
+               MOD_DEC_USE_COUNT;
+               return -ENOMEM;
+       }
+
+       /* OK, we've created a new one. Add it to the list. */
+
+       spin_lock(&mtdblks_lock);
 
-       DEBUG(1, "ok\n");
+       if (mtdblks[dev]) {
+               /* Another CPU made one at the same time as us. */
+               mtdblks[dev]->count++;
+               spin_unlock(&mtdblks_lock);
+               put_mtd_device(mtdblk->mtd);
+               vfree(mtdblk->cache_data);
+               kfree(mtdblk);
+               return 0;
+       }
+
+       mtdblks[dev] = mtdblk;
+       mtd_sizes[dev] = mtdblk->mtd->size/1024;
+       mtd_blksizes[dev] = mtdblk->mtd->erasesize;
+       if (mtd_blksizes[dev] > PAGE_SIZE)
+               mtd_blksizes[dev] = PAGE_SIZE;
+       set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
+       
+       spin_unlock(&mtdblks_lock);
+       
+       DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
        return 0;
 }
@@ -84,11 +353,11 @@ static int mtdblock_open(struct inode *inode, struct file *file)
 static release_t mtdblock_release(struct inode *inode, struct file *file)
 {
        int dev;
-       struct mtd_info *mtd;
+       struct mtdblk_dev *mtdblk;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
        struct super_block * sb = get_super(inode->i_rdev);
 #endif
-       DEBUG(1, "mtdblock_release\n");
+       DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
        if (inode == NULL)
                release_return(-ENODEV);
@@ -100,150 +369,189 @@ static release_t mtdblock_release(struct inode *inode, struct file *file)
        invalidate_buffers(inode->i_rdev);
 
        dev = MINOR(inode->i_rdev);
-       mtd = __get_mtd_device(NULL, dev);
-
-       if (!mtd) {
-               printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
-               MOD_DEC_USE_COUNT;
-               release_return(-ENODEV);
-               
+       mtdblk = mtdblks[dev];
+
+       down(&mtdblk->cache_sem);
+       write_cached_data(mtdblk);
+       up(&mtdblk->cache_sem);
+
+       spin_lock(&mtdblks_lock);
+       if (!--mtdblk->count) {
+               /* It was the last usage. Free the device */
+               mtdblks[dev] = NULL;
+               spin_unlock(&mtdblks_lock);
+               if (mtdblk->mtd->sync)
+                       mtdblk->mtd->sync(mtdblk->mtd);
+               put_mtd_device(mtdblk->mtd);
+               vfree(mtdblk->cache_data);
+               kfree(mtdblk);
+       } else {
+               spin_unlock(&mtdblks_lock);
        }
-       
-       if (mtd->sync)
-               mtd->sync(mtd);
-
-       put_mtd_device(mtd);
 
-       DEBUG(1, "ok\n");
+       DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
        MOD_DEC_USE_COUNT;
        release_return(0);
 }  
 
 
-static void mtdblock_request(RQFUNC_ARG)
+/* 
+ * This is a special request_fn because it is executed in a process context 
+ * to be able to sleep independently of the caller.  The io_request_lock 
+ * is held upon entry and exit.
+ * The head of our request queue is considered active so there is no need 
+ * to dequeue requests before we are done.
+ */
+static void handle_mtdblock_request(void)
 {
-   struct request *current_request;
-   unsigned int res = 0;
-   struct mtd_info *mtd;
-
-   while (1)
-   {
-      /* Grab the Request and unlink it from the request list, INIT_REQUEST
-                will execute a return if we are done. */
-      INIT_REQUEST;
-      current_request = CURRENT;
-   
-      if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
-      {
-        printk("mtd: Unsupported device!\n");
-        end_request(0);
-        continue;
-      }
-      
-      // Grab our MTD structure
-
-      mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
-      if (!mtd) {
-             printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
-             end_request(0);
-      }
-
-      if (current_request->sector << 9 > mtd->size ||
-         (current_request->sector + current_request->nr_sectors) << 9 > mtd->size)
-      {
-        printk("mtd: Attempt to read past end of device!\n");
-        printk("size: %lx, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors);
-        end_request(0);
-        continue;
-      }
-      
-      /* Remove the request we are handling from the request list so nobody messes
-         with it */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-       blkdev_dequeue_request(current_request);
-      
-      /* Now drop the lock that the ll_rw_blk functions grabbed for us
-         and process the request. This is necessary due to the extreme time
-         we spend processing it. */
-      spin_unlock_irq(&io_request_lock);
-#endif
+       struct request *req;
+       struct mtdblk_dev *mtdblk;
+       unsigned int res;
+
+       for (;;) {
+               INIT_REQUEST;
+               req = CURRENT;
+               spin_unlock_irq(&io_request_lock);
+               mtdblk = mtdblks[MINOR(req->rq_dev)];
+               res = 0;
+
+               if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
+                       panic(__FUNCTION__": minor out of bound");
+
+               if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
+                       goto end_req;
+
+               // Handle the request
+               switch (req->cmd)
+               {
+                       int err;
+
+                       case READ:
+                       down(&mtdblk->cache_sem);
+                       err = do_cached_read (mtdblk, req->sector << 9, 
+                                       req->current_nr_sectors << 9,
+                                       req->buffer);
+                       up(&mtdblk->cache_sem);
+                       if (!err)
+                               res = 1;
+                       break;
+
+                       case WRITE:
+                       // Read only device
+                       if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) 
+                               break;
+
+                       // Do the write
+                       down(&mtdblk->cache_sem);
+                       err = do_cached_write (mtdblk, req->sector << 9,
+                                       req->current_nr_sectors << 9, 
+                                       req->buffer);
+                       up(&mtdblk->cache_sem);
+                       if (!err)
+                               res = 1;
+                       break;
+               }
+
+end_req:
+               spin_lock_irq(&io_request_lock);
+               end_request(res);
+       }
+}
 
-      // Handle the request
-      switch (current_request->cmd)
-      {
-         size_t retlen;
-
-        case READ:
-        if (mtd->read(mtd,current_request->sector<<9, 
-                     current_request->nr_sectors << 9, 
-                     &retlen, current_request->buffer) == 0)
-           res = 1;
-        else
-           res = 0;
-        break;
-        
-        case WRITE:
-//printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
-//     current_request->nr_sectors);
-
-        // Read only device
-        if ((mtd->flags & MTD_CAP_RAM) == 0)
-        {
-           res = 0;
-           break;
-        }
-
-        // Do the write
-        if (mtd->write(mtd,current_request->sector<<9, 
-                      current_request->nr_sectors << 9, 
-                      &retlen, current_request->buffer) == 0)
-           res = 1;
-        else
-           res = 0;
-        break;
-        
-        // Shouldn't happen
-        default:
-        printk("mtd: unknown request\n");
-        break;
-      }
-
-      // Grab the lock and re-thread the item onto the linked list
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-       spin_lock_irq(&io_request_lock);
-       mtdblock_end_request(current_request, res);
+static volatile int leaving = 0;
+#if LINUX_VERSION_CODE > 0x020300
+static DECLARE_MUTEX_LOCKED(thread_sem);
+static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
 #else
-       end_request(res);
+static struct semaphore thread_sem = MUTEX_LOCKED;
+DECLARE_WAIT_QUEUE_HEAD(thr_wq);
 #endif
-   }
+
+int mtdblock_thread(void *dummy)
+{
+       struct task_struct *tsk = current;
+       DECLARE_WAITQUEUE(wait, tsk);
+
+       tsk->session = 1;
+       tsk->pgrp = 1;
+       /* we might get involved when memory gets low, so use PF_MEMALLOC */
+       tsk->flags |= PF_MEMALLOC;
+       strcpy(tsk->comm, "mtdblockd");
+       tsk->tty = NULL;
+       spin_lock_irq(&tsk->sigmask_lock);
+       sigfillset(&tsk->blocked);
+       recalc_sigpending(tsk);
+       spin_unlock_irq(&tsk->sigmask_lock);
+       exit_mm(tsk);
+       exit_files(tsk);
+       exit_sighand(tsk);
+       exit_fs(tsk);
+
+       while (!leaving) {
+               add_wait_queue(&thr_wq, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_lock_irq(&io_request_lock);
+               if (QUEUE_EMPTY || QUEUE_PLUGGED) {
+                       spin_unlock_irq(&io_request_lock);
+                       schedule();
+                       remove_wait_queue(&thr_wq, &wait); 
+               } else {
+                       remove_wait_queue(&thr_wq, &wait); 
+                       set_current_state(TASK_RUNNING);
+                       handle_mtdblock_request();
+                       spin_unlock_irq(&io_request_lock);
+               }
+       }
+
+       up(&thread_sem);
+       return 0;
 }
 
+#if LINUX_VERSION_CODE < 0x20300
+#define RQFUNC_ARG void
+#else
+#define RQFUNC_ARG request_queue_t *q
+#endif
+
+static void mtdblock_request(RQFUNC_ARG)
+{
+       /* Don't do anything, except wake the thread if necessary */
+       wake_up(&thr_wq);
+}
 
 
 static int mtdblock_ioctl(struct inode * inode, struct file * file,
                      unsigned int cmd, unsigned long arg)
 {
-       struct mtd_info *mtd;
+       struct mtdblk_dev *mtdblk;
 
-       mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
+       mtdblk = mtdblks[MINOR(inode->i_rdev)];
 
-       if (!mtd) return -EINVAL;
+#ifdef PARANOIA
+       if (!mtdblk)
+               BUG();
+#endif
 
        switch (cmd) {
        case BLKGETSIZE:   /* Return device size */
-               if (!arg)  return -EFAULT;
-               return put_user((mtd->size >> 9),
-                                (long *) arg);
+               if (!arg)
+                       return -EFAULT;
+               return put_user((mtdblk->mtd->size >> 9),
+                                (long *) arg)?-EFAULT:0;
                
        case BLKFLSBUF:
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-               if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+               if(!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
 #endif
                fsync_dev(inode->i_rdev);
                invalidate_buffers(inode->i_rdev);
-               if (mtd->sync)
-                       mtd->sync(mtd);
+               down(&mtdblk->cache_sem);
+               write_cached_data(mtdblk);
+               up(&mtdblk->cache_sem);
+               if (mtdblk->mtd->sync)
+                       mtdblk->mtd->sync(mtdblk->mtd);
                return 0;
 
        default:
@@ -251,7 +559,6 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
        }
 }
 
-                                                                       /*}}}*/
 #if LINUX_VERSION_CODE < 0x20326
 static struct file_operations mtd_fops =
 {
@@ -270,32 +577,69 @@ static struct block_device_operations mtd_fops =
 };
 #endif
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#ifdef CONFIG_DEVFS_FS
+/* Notification that a new device has been added. Create the devfs entry for
+ * it. */
+
+static void mtd_notify_add(struct mtd_info* mtd)
+{
+        char name[8];
+
+        if (!mtd)
+                return;
+
+        sprintf(name, "%d", mtd->index);
+        devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
+                        DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index,
+                        S_IFBLK | S_IRUGO | S_IWUGO,
+                        &mtd_fops, NULL);
+}
+
+static void mtd_notify_remove(struct mtd_info* mtd)
+{
+        if (!mtd)
+                return;
+
+        devfs_unregister(devfs_rw_handle[mtd->index]);
+}
+#endif
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_mtdblock init_module
 #define cleanup_mtdblock cleanup_module
 #endif
-#define __exit
-#endif
-
 
 int __init init_mtdblock(void)
 {
        int i;
 
+       spin_lock_init(&mtdblks_lock);
+#ifdef CONFIG_DEVFS_FS
+       if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))
+       {
+               printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
+                       MTD_BLOCK_MAJOR);
+               return -EAGAIN;
+       }
+
+       devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
+       register_mtd_user(&notifier);
+#else
        if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
                printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
                       MTD_BLOCK_MAJOR);
                return -EAGAIN;
        }
+#endif
        
        /* We fill it in at open() time. */
        for (i=0; i< MAX_MTD_DEVICES; i++) {
                mtd_sizes[i] = 0;
+               mtd_blksizes[i] = BLOCK_SIZE;
        }
-       
+       init_waitqueue_head(&thr_wq);
        /* Allow the block size to default to BLOCK_SIZE. */
-       blksize_size[MAJOR_NR] = NULL;
+       blksize_size[MAJOR_NR] = mtd_blksizes;
        blk_size[MAJOR_NR] = mtd_sizes;
        
 #if LINUX_VERSION_CODE < 0x20320
@@ -303,15 +647,30 @@ int __init init_mtdblock(void)
 #else
        blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
 #endif
+       kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
        return 0;
 }
 
 static void __exit cleanup_mtdblock(void)
 {
+       leaving = 1;
+       wake_up(&thr_wq);
+       down(&thread_sem);
+#ifdef CONFIG_DEVFS_FS
+       unregister_mtd_user(&notifier);
+       devfs_unregister(devfs_dir_handle);
+       devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
+#else
        unregister_blkdev(MAJOR_NR,DEVICE_NAME);
+#endif
+#if LINUX_VERSION_CODE < 0x20320
+       blk_dev[MAJOR_NR].request_fn = NULL;
+#else
+       blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+#endif
+       blksize_size[MAJOR_NR] = NULL;
+       blk_size[MAJOR_NR] = NULL;
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_mtdblock);
 module_exit(cleanup_mtdblock);
-#endif
index 0bb15a8fc35a5c5bc49dabe1e181fb6793df5391..bccb687c0ae978051a59a5a8121667138c5c5971 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * $Id: mtdchar.c,v 1.7 2000/06/30 15:54:19 dwmw2 Exp $
+ * Almost: $Id: mtdchar.c,v 1.21 2000/12/09 21:15:12 dwmw2 Exp $
+ * (With some of the compatibility for previous kernels taken out)
  *
  * Character-device access to raw MTD devices.
  *
 #include <linux/mtd/mtd.h>
 #include <linux/malloc.h>
 
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+static void mtd_notify_add(struct mtd_info* mtd);
+static void mtd_notify_remove(struct mtd_info* mtd);
+static struct mtd_notifier notifier = {
+       mtd_notify_add,
+       mtd_notify_remove,
+       NULL
+};
+static devfs_handle_t devfs_dir_handle = NULL;
+static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
+static devfs_handle_t devfs_ro_handle[MAX_MTD_DEVICES];
+#endif
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
 #else
@@ -22,11 +37,11 @@ static int mtd_lseek (struct inode *inode, struct file *file, off_t offset, int
        struct mtd_info *mtd=(struct mtd_info *)file->private_data;
 
        switch (orig) {
-       case 0: 
+       case 0:
                /* SEEK_SET */
                file->f_pos = offset;
                break;
-       case 1: 
+       case 1:
                /* SEEK_CUR */
                file->f_pos += offset;
                break;
@@ -34,11 +49,11 @@ static int mtd_lseek (struct inode *inode, struct file *file, off_t offset, int
                /* SEEK_END */
                file->f_pos =mtd->size + offset;
                break;
-       default: 
+       default:
                return -EINVAL;
        }
 
-       if (file->f_pos < 0) 
+       if (file->f_pos < 0)
                file->f_pos = 0;
        else if (file->f_pos >= mtd->size)
                file->f_pos = mtd->size - 1;
@@ -54,7 +69,7 @@ static int mtd_open(struct inode *inode, struct file *file)
        int devnum = minor >> 1;
        struct mtd_info *mtd;
 
-       DEBUG(0, "MTD_open\n");
+       DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n");
 
        if (devnum >= MAX_MTD_DEVICES)
                return -ENODEV;
@@ -86,7 +101,7 @@ static release_t mtd_close(struct inode *inode,
 {
        struct mtd_info *mtd;
 
-       DEBUG(0, "MTD_close\n");
+       DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
 
        mtd = (struct mtd_info *)file->private_data;
        
@@ -115,7 +130,7 @@ static int mtd_read(struct inode *inode,struct file *file, char *buf, int count)
        int ret=0;
        char *kbuf;
        
-       DEBUG(0,"MTD_read\n");
+       DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
 
        if (FILE_POS + count > mtd->size)
                count = mtd->size - FILE_POS;
@@ -124,7 +139,7 @@ static int mtd_read(struct inode *inode,struct file *file, char *buf, int count)
                return 0;
        
        /* FIXME: Use kiovec in 2.3 or 2.2+rawio, or at
-        * least split the IO into smaller chunks. 
+        * least split the IO into smaller chunks.
         */
        
        kbuf = vmalloc(count);
@@ -157,7 +172,7 @@ static read_write_t mtd_write(struct inode *inode,struct file *file, const char
        size_t retlen;
        int ret=0;
 
-       DEBUG(0,"MTD_write\n");
+       DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
        
        if (FILE_POS == mtd->size)
                return -ENOSPC;
@@ -208,7 +223,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        int ret = 0;
        u_long size;
        
-       DEBUG(0, "MTD_ioctl\n");
+       DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
 
        size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
        if (cmd & IOC_IN) {
@@ -222,8 +237,9 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        
        switch (cmd) {
        case MEMGETINFO:
-               copy_to_user((struct mtd_info *)arg, mtd,
-                            sizeof(struct mtd_info_user));
+               if (copy_to_user((struct mtd_info *)arg, mtd,
+                                sizeof(struct mtd_info_user)))
+                       return -EFAULT;
                break;
 
        case MEMERASE:
@@ -238,28 +254,23 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                        init_waitqueue_head(&waitq);
 
                        memset (erase,0,sizeof(struct erase_info));
-                       copy_from_user(&erase->addr, (u_long *)arg,
-                                      2 * sizeof(u_long));
+                       if (copy_from_user(&erase->addr, (u_long *)arg,
+                                          2 * sizeof(u_long))) {
+                               kfree(erase);
+                               return -EFAULT;
+                       }
                        erase->mtd = mtd;
                        erase->callback = mtd_erase_callback;
                        erase->priv = (unsigned long)&waitq;
                        
-                       /* FIXME: Allow INTERRUPTIBLE. Which means
-                          not having the wait_queue head on the stack
-                          
-                          Does it? Why? Who wrote this? Was it my alter 
-                          ago - the intelligent one? Or was it the stupid 
-                          one, and now I'm being clever I don't know what
-                          it was on about?
-
-                          dwmw2.
-
-                          It was the intelligent one. If the wq_head is
-                          on the stack, and we leave because we got 
-                          interrupted, then the wq_head is no longer 
-                          there when the callback routine tries to
-                          wake us up --> BOOM!.
-
+                       /*
+                         FIXME: Allow INTERRUPTIBLE. Which means
+                         not having the wait_queue head on the stack.
+                         
+                         If the wq_head is on the stack, and we
+                         leave because we got interrupted, then the
+                         wq_head is no longer there when the
+                         callback routine tries to wake us up.
                        */
                        current->state = TASK_UNINTERRUPTIBLE;
                        add_wait_queue(&waitq, &wait);
@@ -281,7 +292,8 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                void *databuf;
                ssize_t retlen;
                
-               copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf));
+               if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
+                       return -EFAULT;
                
                if (buf.length > 0x4096)
                        return -EINVAL;
@@ -298,11 +310,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                if (!databuf)
                        return -ENOMEM;
                
-               copy_from_user(databuf, buf.ptr, buf.length);
+               if (copy_from_user(databuf, buf.ptr, buf.length))
+                       return -EFAULT;
 
                ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-               copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t));
+               if (copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t)))
+                       ret = -EFAULT;
 
                kfree(databuf);
                break;
@@ -315,7 +329,8 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                void *databuf;
                ssize_t retlen;
 
-               copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf));
+               if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
+                       return -EFAULT;
                
                if (buf.length > 0x4096)
                        return -EINVAL;
@@ -334,19 +349,42 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                
                ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-               copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t));
-
-               if (retlen)
-                       copy_to_user(buf.ptr, databuf, retlen);
-
+               if (copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t)))
+                       ret = -EFAULT;
+               else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
+                       ret = -EFAULT;
+               
                kfree(databuf);
                break;
        }
-                            
-                            
-               
-               
 
+       case MEMLOCK:
+       {
+               unsigned long adrs[2];
+
+               if (copy_from_user(adrs ,(void *)arg, 2* sizeof(unsigned long)))
+                       return -EFAULT;
+
+               if (!mtd->lock)
+                       ret = -EOPNOTSUPP;
+               else
+                       ret = mtd->lock(mtd, adrs[0], adrs[1]);
+       }
+
+       case MEMUNLOCK:
+       {
+               unsigned long adrs[2];
+
+               if (copy_from_user(adrs, (void *)arg, 2* sizeof(unsigned long)))
+                       return -EFAULT;
+
+               if (!mtd->unlock)
+                       ret = -EOPNOTSUPP;
+               else
+                       ret = mtd->unlock(mtd, adrs[0], adrs[1]);
+       }
+
+               
        default:
          printk("Invalid ioctl %x (MEMGETINFO = %x)\n",cmd, MEMGETINFO);
                ret = -EINVAL;
@@ -366,31 +404,84 @@ static struct file_operations mtd_fops = {
 };
 
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#ifdef CONFIG_DEVFS_FS
+/* Notification that a new device has been added. Create the devfs entry for
+ * it. */
+
+static void mtd_notify_add(struct mtd_info* mtd)
+{
+       char name[8];
+
+       if (!mtd)
+               return;
+
+       sprintf(name, "%d", mtd->index);
+       devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
+                       DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2,
+                       S_IFCHR | S_IRUGO | S_IWUGO,
+                       &mtd_fops, NULL);
+
+       sprintf(name, "%dro", mtd->index);
+       devfs_ro_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
+                       DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1,
+                       S_IFCHR | S_IRUGO | S_IWUGO,
+                       &mtd_fops, NULL);
+}
+
+static void mtd_notify_remove(struct mtd_info* mtd)
+{
+       if (!mtd)
+               return;
+
+       devfs_unregister(devfs_rw_handle[mtd->index]);
+       devfs_unregister(devfs_ro_handle[mtd->index]);
+}
+#endif
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_mtdchar init_module
 #define cleanup_mtdchar cleanup_module
 #endif
-#endif
 
 mod_init_t init_mtdchar(void)
 {
-       
-       if (register_chrdev(MTD_CHAR_MAJOR,"mtd",&mtd_fops)) {
+#ifdef CONFIG_DEVFS_FS
+       int i;
+       char name[8];
+       struct mtd_info* mtd;
+
+       if (devfs_register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
+       {
+               printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
+                      MTD_CHAR_MAJOR);
+               return -EAGAIN;
+       }
+
+       devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL);
+
+       register_mtd_user(&notifier);
+#else
+       if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
+       {
                printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
                       MTD_CHAR_MAJOR);
                return -EAGAIN;
        }
+#endif
 
        return 0;
 }
 
 mod_exit_t cleanup_mtdchar(void)
 {
-       unregister_chrdev(MTD_CHAR_MAJOR,"mtd");
+#ifdef CONFIG_DEVFS_FS
+       unregister_mtd_user(&notifier);
+       devfs_unregister(devfs_dir_handle);
+       devfs_unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
+#else
+       unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
+#endif
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_mtdchar);
 module_exit(cleanup_mtdchar);
-#endif
index b3f0157eba4d655959dad194b1038fc036e0e427..8c30838ba4d2edd0261fd5459f2dfeac7dedcba9 100644 (file)
@@ -1,15 +1,11 @@
 /*
- * $Id: mtdcore.c,v 1.13 2000/07/13 14:27:37 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.27 2000/12/10 01:10:09 dwmw2 Exp $
  *
- * Core registration and callback routines for MTD 
+ * Core registration and callback routines for MTD
  * drivers and users.
  *
  */
 
-#ifdef MTD_DEBUG
-#define DEBUGLVL debug
-#endif
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 
 #include <linux/mtd/mtd.h>
 
-#ifdef MTD_DEBUG
-static int debug = MTD_DEBUG;
-MODULE_PARM(debug, "i");
-#endif
-
-/* Init code required for 2.2 kernels */
-
-#if LINUX_VERSION_CODE < 0x20300
-
-#ifdef CONFIG_MTD_DOC1000
-extern int init_doc1000(void);
-#endif
-#ifdef CONFIG_MTD_DOCPROBE
-extern int init_doc(void);
-#endif
-#ifdef CONFIG_MTD_PHYSMAP
-extern int init_physmap(void);
-#endif
-#ifdef CONFIG_MTD_RPXLITE
-extern int init_rpxlite(void);
-#endif
-#ifdef CONFIG_MTD_OCTAGON
-extern int init_octagon5066(void);
-#endif
-#ifdef CONFIG_MTD_PNC2000
-extern int init_pnc2000(void);
-#endif
-#ifdef CONFIG_MTD_VMAX
-extern int init_vmax301(void);
-#endif
-#ifdef CONFIG_MTD_MIXMEM
-extern int init_mixmem(void);
-#endif
-#ifdef CONFIG_MTD_PMC551
-extern int init_pmc551(void);
-#endif
-#ifdef CONFIG_MTD_NORA
-extern int init_nora(void);
-#endif
-#ifdef CONFIG_FTL
-extern int init_ftl(void);
-#endif
-#ifdef CONFIG_NFTL
-extern int init_nftl(void);
-#endif
-#ifdef CONFIG_MTD_BLOCK
-extern int init_mtdblock(void);
-#endif
-#ifdef CONFIG_MTD_CHAR
-extern int init_mtdchar(void);
-#endif
-
-#endif /* LINUX_VERSION_CODE < 0x20300 */
-
-
 static DECLARE_MUTEX(mtd_table_mutex);
 static struct mtd_info *mtd_table[MAX_MTD_DEVICES];
 static struct mtd_notifier *mtd_notifiers = NULL;
 
 /**
- *     add_mtd_device - register an MTD device 
+ *     add_mtd_device - register an MTD device
  *     @mtd: pointer to new MTD device info structure
  *
  *     Add a device to the list of MTD devices present in the system, and
@@ -110,6 +51,7 @@ int add_mtd_device(struct mtd_info *mtd)
                        struct mtd_notifier *not=mtd_notifiers;
 
                        mtd_table[i] = mtd;
+                       mtd->index = i;
                        DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
                        while (not)
                        {
@@ -126,7 +68,7 @@ int add_mtd_device(struct mtd_info *mtd)
 }
 
 /**
- *     del_mtd_device - unregister an MTD device 
+ *     del_mtd_device - unregister an MTD device
  *     @mtd: pointer to MTD device info structure
  *
  *     Remove a device from the list of MTD devices present in the system,
@@ -194,7 +136,7 @@ void register_mtd_user (struct mtd_notifier *new)
  *     @new: pointer to notifier info structure
  *
  *     Removes a callback function pair from the list of 'users' to be
- *     notified upon addition or removal of MTD devices. Causes the 
+ *     notified upon addition or removal of MTD devices. Causes the
  *     'remove' callback to be immediately invoked for each MTD device
  *     currently present in the system.
  */
@@ -232,7 +174,7 @@ int unregister_mtd_user (struct mtd_notifier *old)
  *     @mtd: last known address of the required MTD device
  *     @num: internal device number of the required MTD device
  *
- *     Given a number and NULL address, return the num'th entry in the device 
+ *     Given a number and NULL address, return the num'th entry in the device
  *     table, if any.  Given an address and num == -1, search the device table
  *     for a device with that address and return if it's still present. Given
  *     both, return the num'th driver only if its address matches. Return NULL
@@ -313,10 +255,10 @@ static inline int mtd_proc_info (char *buf, int i)
 {
        struct mtd_info *this = mtd_table[i];
 
-       if (!this) 
+       if (!this)
                return 0;
 
-       return sprintf(buf, "mtd%d: %8.8lx \"%s\"\n", i, this->size, 
+       return sprintf(buf, "mtd%d: %8.8lx \"%s\"\n", i, this->size,
                       this->name);
 }
 
@@ -330,7 +272,7 @@ static int mtd_read_proc ( char *page, char **start, off_t off,int count
 {
        int len = 0, l, i;
         off_t   begin = 0;
-      
+
        down(&mtd_table_mutex);
 
         for (i=0; i< MAX_MTD_DEVICES; i++) {
@@ -374,79 +316,13 @@ struct proc_dir_entry mtd_proc_entry = {
 /*====================================================================*/
 /* Init code */
 
-#if LINUX_VERSION_CODE < 0x20300
-
-static inline  void init_others(void) 
-{
-       /* Shedloads of calls to init functions of all the
-        * other drivers and users of MTD, which we can
-        * ditch in 2.3 because of the sexy new way of 
-        * finding init routines.
-        */
-#ifdef CONFIG_MTD_DOC1000
-       init_doc1000();
-#endif
-#ifdef CONFIG_MTD_DOCPROBE
-       init_doc(); /* This covers both the DiskOnChip 2000 
-                    * and the DiskOnChip Millennium. 
-                    * Theoretically all other DiskOnChip
-                    * devices too. */
-#endif
-#ifdef CONFIG_MTD_PHYSMAP
-       init_physmap();
-#endif
-#ifdef CONFIG_MTD_RPXLITE
-       init_rpxlite();
-#endif
-#ifdef CONFIG_MTD_OCTAGON
-       init_octagon5066();
-#endif
-#ifdef CONFIG_MTD_PNC2000
-       init_pnc2000();
-#endif
-#ifdef CONFIG_MTD_VMAX
-       init_vmax301();
-#endif
-#ifdef CONFIGF_MTD_MIXMEM
-       init_mixmem();
-#endif
-#ifdef CONFIG_MTD_PMC551
-       init_pmc551();
-#endif
-#ifdef CONFIG_MTD_NORA
-       init_nora();
-#endif
-#ifdef CONFIG_MTD_MTDRAM
-       init_mtdram();
-#endif
-#ifdef CONFIG_FTL
-       init_ftl();
-#endif
-#ifdef CONFIG_NFTL
-       init_nftl();
-#endif
-#ifdef CONFIG_MTD_BLOCK
-       init_mtdblock();
-#endif
-#ifdef CONFIG_MTD_CHAR
-       init_mtdchar();
-#endif
-}
-
-#ifdef MODULE
+#if  LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_mtd init_module
 #define cleanup_mtd cleanup_module
 #endif
 
-#endif /* LINUX_VERSION_CODE < 0x20300 */
-
 mod_init_t init_mtd(void)
 {
-       int i;
-       DEBUG(1, "INIT_MTD:\n");        
-       for (i=0; i<MAX_MTD_DEVICES; i++)
-               mtd_table[i]=NULL;
-
 #ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
        if ((proc_mtd = create_proc_entry( "mtd", 0, 0 )))
@@ -454,12 +330,12 @@ mod_init_t init_mtd(void)
 #else
         proc_register_dynamic(&proc_root,&mtd_proc_entry);
 #endif
-
 #endif
 
-#if LINUX_VERSION_CODE < 0x20300
-       init_others();
+#if LINUX_VERSION_CODE < 0x20212
+       init_mtd_devices();
 #endif
+
 #ifdef CONFIG_PM
        mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback);
 #endif
@@ -468,13 +344,13 @@ mod_init_t init_mtd(void)
 
 mod_exit_t cleanup_mtd(void)
 {
-       unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
 #ifdef CONFIG_PM
        if (mtd_pm_dev) {
                pm_unregister(mtd_pm_dev);
                mtd_pm_dev = NULL;
        }
 #endif
+
 #ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
         if (proc_mtd)
@@ -484,10 +360,8 @@ mod_exit_t cleanup_mtd(void)
 #endif
 #endif
 }
-      
-#if LINUX_VERSION_CODE > 0x20300
+
 module_init(init_mtd);
 module_exit(cleanup_mtd);
-#endif
 
 
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
new file mode 100644 (file)
index 0000000..0135be3
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Simple MTD partitioning layer
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * This code is GPL
+ *
+ * $Id: mtdpart.c,v 1.7 2000/12/09 23:29:47 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/list.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+
+/* Our partition linked list */
+static LIST_HEAD(mtd_partitions);
+
+/* Our partition node structure */
+struct mtd_part {
+       struct mtd_info mtd;
+       struct mtd_info *master;
+       loff_t offset;
+       int index;
+       struct list_head list;
+};
+
+/*
+ * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+ * the pointer to that structure with this macro.
+ */
+#define PART(x)  ((struct mtd_part *)(x))
+
+       
+/* 
+ * MTD methods which simply translate the effective address and pass through
+ * to the _real_ device.
+ */
+
+static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 
+                       size_t *retlen, u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (from >= mtd->size)
+               len = 0;
+       else if (from + len > mtd->size)
+               len = mtd->size - from;
+       return part->master->read (part->master, from + part->offset, 
+                                       len, retlen, buf);
+}
+
+static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (to >= mtd->size)
+               len = 0;
+       else if (to + len > mtd->size)
+               len = mtd->size - to;
+       return part->master->write (part->master, to + part->offset, 
+                                       len, retlen, buf);
+}
+
+static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
+                        unsigned long count, loff_t to, size_t *retlen)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       return part->master->writev (part->master, vecs, count,
+                                       to + part->offset, retlen);
+}
+
+static int part_readv (struct mtd_info *mtd,  struct iovec *vecs,
+                        unsigned long count, loff_t from, size_t *retlen)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->readv (part->master, vecs, count,
+                                       from + part->offset, retlen);
+}
+
+static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (instr->addr >= mtd->size)
+               return -EINVAL;
+       instr->addr += part->offset;
+       return part->master->erase(part->master, instr);
+}
+
+static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->lock(part->master, ofs + part->offset, len);
+}
+
+static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->unlock(part->master, ofs + part->offset, len);
+}
+
+
+/* 
+ * This function unregisters and destroy all slave MTD objects which are 
+ * attached to the given master MTD object.
+ */
+
+int del_mtd_partitions(struct mtd_info *master)
+{
+       struct list_head *node;
+       struct mtd_part *slave;
+
+       for (node = mtd_partitions.next;
+            node != &mtd_partitions;
+            node = node->next) {
+               slave = list_entry(node, struct mtd_part, list);
+               if (slave->master == master) {
+                       struct list_head *prev = node->prev;
+                       __list_del(prev, node->next);
+                       del_mtd_device(&slave->mtd);
+                       kfree(slave);
+                       node = prev;
+                       MOD_DEC_USE_COUNT;
+               }
+       }
+
+       return 0;
+}
+
+
+/*
+ * This function, given a master MTD object and a partition table, creates
+ * and registers slave MTD objects which are bound to the master according to
+ * the partition definitions.
+ * (Q: should we register the master MTD object as well?)
+ */
+
+int add_mtd_partitions(struct mtd_info *master, 
+                      struct mtd_partition *parts,
+                      int nbparts)
+{
+       struct mtd_part *slave;
+       u_long cur_offset = 0;
+       int i;
+
+       for (i = 0; i < nbparts; i++) {
+               /* allocate the partition structure */
+               slave = kmalloc (sizeof(*slave), GFP_KERNEL);
+               if (!slave) {
+                       printk ("memory allocation error while creating partitions for \"%s\"\n",
+                               master->name);
+                       del_mtd_partitions(master);
+                       return -ENOMEM;
+               }
+               list_add(&slave->list, &mtd_partitions);
+
+               /* set up the MTD object for this partition */
+               slave->mtd = *master;
+               slave->mtd.name = parts[i].name;
+               slave->mtd.size = parts[i].size;
+               slave->mtd.flags &= ~parts[i].mask_flags;
+               slave->mtd.read = part_read;
+               slave->mtd.write = part_write;
+               if (slave->mtd.writev)
+                       slave->mtd.writev = part_writev;
+               if (slave->mtd.readv)
+                       slave->mtd.readv = part_readv;
+               if (slave->mtd.lock)
+                       slave->mtd.lock = part_lock;
+               if (slave->mtd.unlock)
+                       slave->mtd.unlock = part_unlock;
+               slave->mtd.erase = part_erase;
+               slave->master = master;
+               slave->offset = parts[i].offset;
+               slave->index = i;
+
+               if (slave->offset == 0)
+                       slave->offset = cur_offset;
+               if (slave->mtd.size == 0)
+                       slave->mtd.size = master->size - slave->offset;
+               cur_offset = slave->offset + slave->mtd.size;
+
+               /* let's do some sanity checks */
+               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+                   (parts[i].offset % master->erasesize)) {
+                       slave->mtd.flags &= ~MTD_WRITEABLE;
+                       printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+                                       parts[i].name);
+               }
+               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+                   (parts[i].size % master->erasesize)) {
+                       slave->mtd.flags &= ~MTD_WRITEABLE;
+                       printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+                                       parts[i].name);
+               }
+               if (parts[i].offset >= master->size) {
+                       /* let's register it anyway to preserve ordering */
+                       slave->offset = 0;
+                       slave->mtd.size = 0;
+                       printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
+                                       parts[i].name);
+               }
+               if (parts[i].offset + parts[i].size > master->size) {
+                       slave->mtd.size = master->size - parts[i].offset;
+                       printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#lx\n",
+                                       parts[i].name, master->name, slave->mtd.size);
+               }
+
+               /* register our partition */
+               add_mtd_device(&slave->mtd);
+               MOD_INC_USE_COUNT;
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL(add_mtd_partitions);
+EXPORT_SYMBOL(del_mtd_partitions);
index e7040863f4694b100898fc3cafb249e393243537..d7e2aeaadc34fdfad684c80a6cef997a269bd0b3 100644 (file)
@@ -1,32 +1,35 @@
-
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftl.c,v 1.36 2000/07/13 14:14:20 dwmw2 Exp $ */
+/* $Id: nftl.c,v 1.57 2000/12/01 17:51:54 dwmw2 Exp $ */
 
 /*
-  The contents of this file are distributed under the GNU Public
-  Licence version 2 ("GPL"). The legal note below refers only to the
-  _use_ of the code in some jurisdictions, and does not in any way
-  affect the copying, distribution and modification of this code,
-  which is permitted under the terms of the GPL.
+  The contents of this file are distributed under the GNU General
+  Public License version 2 ("GPL"). The author places no additional
+  restrictions of any kind on it. However, local legislation in some
+  countries may restrict the use of the algorithms implemented by this
+  code in certain circumstances.
 
-  Section 0 of the GPL says:
+  The legal note below refers only to the _use_ of the code in the 
+  affected jurisdictions, and does not in any way affect the copying,
+  distribution and modification of this code, which are permitted, and
+  indeed required, under the terms of the GPL.
 
+  Section 0 of the GPL says:
  "Activities other than copying, distribution and modification are not
   covered by this License; they are outside its scope."
 
   You may copy, distribute and modify this code to your hearts'
   content - it's just that in some jurisdictions, you may only _use_
-  it under the terms of the licence below. This puts it in a similar
-  situation to the ISDN code, which you may need telco approval to
-  use, and indeed any code which has uses that may be restricted in
-  law. For example, certain malicious uses of the networking stack
-  may be illegal, but that doesn't prevent the networking code from
-  being under GPL.
+  it under the terms of the patent grant below. This puts it in a
+  similar situation to the ISDN code, which you may need telco
+  approval to use, and indeed any code which has uses that may be
+  restricted in law. For example, certain malicious uses of the
+  networking stack may be illegal, but that doesn't prevent the
+  networking code from being under GPL.
 
   In fact the ISDN case is worse than this, because modification of
-  the code automatically invalidates its approval. Modificiation,
+  the code automatically invalidates its approval. Modification,
   unlike usage, _is_ one of the rights which is protected by the
   GPL. Happily, the law in those places where approval is required
   doesn't actually prevent you from modifying the code - it's just
@@ -34,7 +37,7 @@
   because usage isn't addressed by the GPL, that's just fine.
 
   dwmw2@infradead.org
-  6/7/0
+  30/10/0
 
   LEGAL NOTE: The NFTL format is patented by M-Systems.  They have
   granted a licence for its use with their DiskOnChip products:
 
 #define PRERELEASE
 
-#ifdef NFTL_DEBUG
-#define DEBUGLVL debug
-#endif
-
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/malloc.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/blkpg.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/compatmac.h>
 
-#undef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+/* maximum number of loops while examining next block, to have a
+   chance to detect consistency problems (they should never happen
+   because of the checks done in the mounting */
+
+#define MAX_LOOPS 10000
 
 /* NFTL block device stuff */
 #define MAJOR_NR NFTL_MAJOR
 #define DEVICE_REQUEST nftl_request
 #define DEVICE_OFF(device)
-#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
-#define LOCAL_END_REQUEST
-#endif
-#include <linux/blk.h>
-#include <linux/hdreg.h>
-
-
-#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
-
-static void nftl_end_request(struct request *req, int res)
-{
-       req->sector += req->current_nr_sectors;
-       req->nr_sectors -= req->current_nr_sectors;
-
-       if (end_that_request_first( req, res, "nftl" ))
-                return;
-        end_that_request_last( req );
-}
-#endif
-
-#ifdef NFTL_DEBUG
-static int debug = NFTL_DEBUG;
-MODULE_PARM(debug, "i");
-#endif
 
 
+#include <linux/blk.h>
+#include <linux/hdreg.h>
 
 /* Linux-specific block device functions */
 
@@ -110,11 +95,10 @@ MODULE_PARM(debug, "i");
  *  encountered, except ...
  */
 
-static int nftl_sizes[256]={0,};
+static int nftl_sizes[256] = {0,};
 static int nftl_blocksizes[256] = {0,};
 
 /* .. for the Linux partition table handling. */
-
 struct hd_struct part_table[256] = {{0,0},};
 
 #if LINUX_VERSION_CODE < 0x20328
@@ -123,8 +107,8 @@ static void dummy_init (struct gendisk *crap)
 #endif
 
 static struct gendisk nftl_gendisk = {
-        NFTL_MAJOR,     /* Major number */      
-        "nftl",         /* Major name */
+        MAJOR_NR,     /* Major number */      
+        "nftl",          /* Major name */
         4,              /* Bits to shift to get real from partition */
         15,             /* Number of partitions per real */
 #if LINUX_VERSION_CODE < 0x20328
@@ -138,281 +122,129 @@ static struct gendisk nftl_gendisk = {
         NULL            /* next */
 };
 
-
 struct NFTLrecord *NFTLs[MAX_NFTLS] = {NULL};
 
-static void NFTL_setup(struct mtd_info *mtd, unsigned long ofs, 
-               struct NFTLMediaHeader *hdr)
+static void NFTL_setup(struct mtd_info *mtd)
 {
        int i;
-       struct NFTLrecord *thisNFTL;
+       struct NFTLrecord *nftl;
        unsigned long temp;
        int firstfree = -1;
 
-       DEBUG(1,"NFTL_setup\n");
+       DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
 
-       for (i=0; i < MAX_NFTLS; i++) {
-               if (!NFTLs[i] && firstfree==-1)
+       for (i = 0; i < MAX_NFTLS; i++) {
+               if (!NFTLs[i] && firstfree == -1)
                        firstfree = i;
-               else if (NFTLs[i] && NFTLs[i]->mtd == mtd && 
-                        NFTLs[i]->MediaHdr.FirstPhysicalEUN == hdr->FirstPhysicalEUN) {
+               else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
                        /* This is a Spare Media Header for an NFTL we've already found */
-                       DEBUG(1, "Spare Media Header for NFTL %d found at %lx\n",i, ofs);
-                       NFTLs[i]->SpareMediaUnit = ofs / mtd->erasesize;
+                       DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
                        return;
                }
        }
-       
-       
-       /* OK, it's a new one. Set up all the data structures. */
-#ifdef PSYCHO_DEBUG    
-       printk("Found new NFTL nftl%c at offset %lx\n",firstfree + 'a', ofs);
-#endif
-       if (hdr->UnitSizeFactor != 0xff) {
-               printk("Sorry, we don't support UnitSizeFactor of != 1 yet\n");
+        if (firstfree == -1) {
+               printk(KERN_WARNING "No more NFTL slot available\n");
                return;
-       }
-       
-       thisNFTL = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-       if (!thisNFTL) {
+        }
+
+       nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
+       if (!nftl) {
                printk(KERN_WARNING "Out of memory for NFTL data structures\n");
                return;
        }
-       init_MUTEX(&thisNFTL->mutex);
-       thisNFTL->EraseSize = mtd->erasesize;
-       memcpy(&thisNFTL->MediaHdr, hdr, sizeof(*hdr));
-       thisNFTL->mtd = mtd;
-       thisNFTL->MediaUnit = ofs / mtd->erasesize;
-       thisNFTL->SpareMediaUnit = 0xffff;
-       thisNFTL->numvunits = le32_to_cpu(thisNFTL->MediaHdr.FormattedSize) / 8192;
-       thisNFTL->nr_sects = thisNFTL->numvunits  * (thisNFTL->EraseSize / 512);
-       thisNFTL->usecount = 0;
 
-       thisNFTL->cylinders = 1024;
-       thisNFTL->heads = 16;
+       init_MUTEX(&nftl->mutex);
 
-       temp = thisNFTL->cylinders * thisNFTL->heads;
-       thisNFTL->sectors = thisNFTL->nr_sects / temp;
+        /* get physical parameters */
+       nftl->EraseSize = mtd->erasesize;
+        nftl->nb_blocks = mtd->size / mtd->erasesize;
+       nftl->mtd = mtd;
 
-       if (thisNFTL->nr_sects % temp) {
-
-               thisNFTL->sectors++;
-               temp = thisNFTL->cylinders * thisNFTL->sectors;
-               thisNFTL->heads = thisNFTL->nr_sects / temp;
-
-               if (thisNFTL->nr_sects & temp) {
-                       thisNFTL->heads++;
-                       temp = thisNFTL->heads * thisNFTL->sectors;
-
-                       thisNFTL->cylinders = thisNFTL->nr_sects / temp;
-               }
-       }
-       if (thisNFTL->nr_sects != thisNFTL->heads * thisNFTL->cylinders *
-           thisNFTL->sectors) {
-               printk(KERN_WARNING "Cannot calculate an NFTL geometry to match size of 0x%lx.\n", thisNFTL->nr_sects);
-               printk(KERN_WARNING "Using C:%d H:%d S:%d (== %lx sects)\n", 
-                      thisNFTL->cylinders, thisNFTL->heads , 
-                      thisNFTL->sectors, 
-                      (long)thisNFTL->cylinders * (long)thisNFTL->heads * 
-                      (long)thisNFTL->sectors );
-
-               /* Oh no we don't 
-                * thisNFTL->nr_sects = thisNFTL->heads * thisNFTL->cylinders * thisNFTL->sectors;
-                */
-       }
-
-       
-       thisNFTL->EUNtable = kmalloc( 2 * thisNFTL->numvunits,
-                                     GFP_KERNEL);
-       if (!thisNFTL->EUNtable) {
-               printk("ENOMEM\n");
-               kfree(thisNFTL);
+        if (NFTL_mount(nftl) < 0) {
+               printk(KERN_WARNING "Could not mount NFTL device\n");
+               kfree(nftl);
                return;
-       }
-       memset(thisNFTL->EUNtable, 0xff, 2 * thisNFTL->numvunits);
-       
-       thisNFTL->VirtualUnitTable = kmalloc( 2 * le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) , GFP_KERNEL);
-       if (!thisNFTL->VirtualUnitTable) {
-               printk("ENOMEM\n");
-               kfree(thisNFTL->EUNtable);
-               kfree(thisNFTL);
-               return;
-       }
-       memset(thisNFTL->VirtualUnitTable, 0xff, 2 * le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits));
-       
-       thisNFTL->ReplUnitTable = kmalloc( 2 * le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) , GFP_KERNEL);
-       if (!thisNFTL->ReplUnitTable) {
-               printk("ENOMEM\n");
-               kfree(thisNFTL->VirtualUnitTable);
-               kfree(thisNFTL->EUNtable);
-               kfree(thisNFTL);
-               return;
-       }
-       memset(thisNFTL->ReplUnitTable, 0xff, 2 *le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) );
-       
-       /* Ought to check the media header for bad blocks */
-       thisNFTL->lastEUN = le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) + 
-                                       le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN) - 1;
-       thisNFTL->numfreeEUNs = 0;
+        }
 
-       /* Scan each physical Erase Unit for validity and to find the 
-          Virtual Erase Unit Chain to which it belongs */
-       
-       for (i=le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN); 
-            i <= thisNFTL->lastEUN; i++) {
-               
-               union nftl_uci uci;
-               unsigned long ofs;
-               size_t retlen;
-               ofs = i * thisNFTL->EraseSize;
-               
-               MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 512 + 8, 8, &retlen, (char *)&uci);
-               
-               if (uci.b.EraseMark != cpu_to_le16(0x3c69) || 
-                   uci.b.EraseMark1 != cpu_to_le16(0x3c69)) {
-                       printk("EUN %d: EraseMark not 0x3c69 (0x%4.4x 0x%4.4x instead)\n",
-                              i, le16_to_cpu(uci.b.EraseMark), le16_to_cpu(uci.b.EraseMark1));
-                       thisNFTL->VirtualUnitTable[i] = 0x7fff;
-                       thisNFTL->ReplUnitTable[i] = 0xffff;
-                       continue;
-               }
-               
-               MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 8, 8, &retlen, (u_char *)&uci);
-               
-               if (uci.a.VirtUnitNum != uci.a.SpareVirtUnitNum)
-                       printk("EUN %d: VirtualUnitNumber (%x) != SpareVirtualUnitNumber (%x)\n",
-                              i, le16_to_cpu(uci.a.VirtUnitNum), 
-                              le16_to_cpu(uci.a.SpareVirtUnitNum));
-               
-               if (uci.a.ReplUnitNum != uci.a.SpareReplUnitNum)
-                       printk("EUN %d: ReplacementUnitNumber (%x) != SpareReplacementUnitNumber (%x)\n",
-                              i, le16_to_cpu(uci.a.ReplUnitNum), 
-                              le16_to_cpu(uci.a.SpareReplUnitNum));
-               
-               /* We don't actually _do_ anything about the above, just whinge */
-               
-               thisNFTL->VirtualUnitTable[i] = le16_to_cpu(uci.a.VirtUnitNum);
-               thisNFTL->ReplUnitTable[i] = le16_to_cpu(uci.a.ReplUnitNum);
-               
-               /* if (!(VUN & 0x8000) && VUN < (arraybounds)).. optimises to: */
-               if (le16_to_cpu(uci.a.VirtUnitNum) < thisNFTL->numvunits) 
-                       thisNFTL->EUNtable[le16_to_cpu(uci.a.VirtUnitNum) & 0x7fff] = i;
-
-               if (uci.a.VirtUnitNum == 0xffff) {
-                       /* Free block */
-                       thisNFTL->LastFreeEUN = i;
-                       thisNFTL->numfreeEUNs++;
-               }
-               
-       } 
-       NFTLs[firstfree] = thisNFTL;
-       thisNFTL->LastFreeEUN = le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN);
-       
-       //#define PSYCHO_DEBUG  
+       /* OK, it's a new one. Set up all the data structures. */
 #ifdef PSYCHO_DEBUG
-       for (i=0; i < 10/* thisNFTL->numvunits*/; i++) {
-               u16 curEUN = thisNFTL->EUNtable[i];
-               int sillycount=100;
-               
-               printk("Virtual Unit #%d: ",i);
-               if (!curEUN || curEUN == 0xffff) {
-                       printk("Not present\n");
-                       continue;
-               }
-               printk("%d", curEUN);
-               
-               while ((curEUN = thisNFTL->ReplUnitTable[curEUN]) != 0xffff && --sillycount) {
-                       printk(", %d", curEUN & 0xffff);
-                       
+       printk("Found new NFTL nftl%c\n", firstfree + 'a');
+#endif
+
+        /* linux stuff */
+       nftl->usecount = 0;
+       nftl->cylinders = 1024;
+       nftl->heads = 16;
+
+       temp = nftl->cylinders * nftl->heads;
+       nftl->sectors = nftl->nr_sects / temp;
+       if (nftl->nr_sects % temp) {
+               nftl->sectors++;
+               temp = nftl->cylinders * nftl->sectors;
+               nftl->heads = nftl->nr_sects / temp;
+
+               if (nftl->nr_sects % temp) {
+                       nftl->heads++;
+                       temp = nftl->heads * nftl->sectors;
+                       nftl->cylinders = nftl->nr_sects / temp;
                }
-               printk("\n");
        }
-#endif
 
-       /* OK. Now we deal with the fact that we're in the real world. Sometimes 
-          things don't actually happen the way they're supposed to. Find, fix,
-          and whinge about the most common deviations from spec that we have
-          been known to encounter.
-       */
-       /* Except that I haven't implemented that bit yet :) */
+       if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
+               printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
+                      "match size of 0x%lx.\n", nftl->nr_sects);
+               printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 
+                      nftl->cylinders, nftl->heads , nftl->sectors, 
+                      (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
 
+               /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
+       }
+       NFTLs[firstfree] = nftl;
        /* Finally, set up the block device sizes */
-       nftl_sizes[firstfree * 16]=thisNFTL->nr_sects;
-//     nftl_blocksizes[firstfree*16] = 512;
-       part_table[firstfree * 16].nr_sects = thisNFTL->nr_sects;
+       nftl_sizes[firstfree * 16] = nftl->nr_sects;
+       //nftl_blocksizes[firstfree*16] = 512;
+       part_table[firstfree * 16].nr_sects = nftl->nr_sects;
+
+       /* partition check ... */
 #if LINUX_VERSION_CODE < 0x20328
        resetup_one_dev(&nftl_gendisk, firstfree);
 #else
-       grok_partitions(&nftl_gendisk, firstfree, 1<<4, thisNFTL->nr_sects);
+       grok_partitions(&nftl_gendisk, firstfree, 1<<4, nftl->nr_sects);
 #endif
-
 }
 
-
 static void NFTL_unsetup(int i)
 {
-       struct NFTLrecord *thisNFTL = NFTLs[i];
+       struct NFTLrecord *nftl = NFTLs[i];
 
-       DEBUG(1, "NFTL_unsetup %d\n", i);
+       DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
        
        NFTLs[i] = NULL;
        
-       if (thisNFTL->VirtualUnitTable)
-               kfree(thisNFTL->VirtualUnitTable);
-       if (thisNFTL->ReplUnitTable)
-               kfree(thisNFTL->ReplUnitTable);
-       if (thisNFTL->EUNtable)
-               kfree(thisNFTL->EUNtable);
+       if (nftl->ReplUnitTable)
+               kfree(nftl->ReplUnitTable);
+       if (nftl->EUNtable)
+               kfree(nftl->EUNtable);
                      
-       kfree(thisNFTL);
+       kfree(nftl);
 }
 
-
-
-
 /* Search the MTD device for NFTL partitions */
 static void NFTL_notify_add(struct mtd_info *mtd)
 {
-       int i;
-       unsigned long ofs;
-       struct NFTLMediaHeader hdr;
-
-       DEBUG(1, "NFTL_notify_add for %s\n", mtd->name);
+       DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
 
        if (mtd) {
-               if (!mtd->read_oob) /* If this MTD doesn't have out-of-band data,
-                                      then there's no point continuing */
-               {
-                       DEBUG(1, "No OOB data, quitting\n");
+               if (!mtd->read_oob) {
+                       /* If this MTD doesn't have out-of-band data,
+                          then there's no point continuing */
+                       DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
                        return;
                }
-               DEBUG(3, "mtd->read = %p,size = %d, erasesize = %d\n", 
-                                       mtd->read, mtd->size, mtd->erasesize);  
-               for (ofs = 0; ofs < mtd->size ; ofs += mtd->erasesize) {
-                       size_t retlen = 0;
-                       MTD_READ(mtd, ofs, sizeof(hdr), &retlen, (u_char *)&hdr);
-
-                       if (retlen < sizeof(hdr))
-                       {       
-                               continue;
-                       }
-                       
-                       if (!strncmp(hdr.DataOrgID, "ANAND", 6)) {
-                               DEBUG(2, "Valid NFTL partition at ofs %ld\n", ofs);     
-                               NFTL_setup(mtd, ofs, &hdr);
-                       }
-                       else {
-                               DEBUG(3,"No valid NFTL Partition at ofs %d\n", ofs);
-                               for(i = 0; i < 6; i++) {
-                                   DEBUG(3,"%x, ", hdr.DataOrgID[i]);
-                               }
-                               DEBUG(3," = %s\n", hdr.DataOrgID);
-                               DEBUG(3,"%d, %d, %d, %d\n", hdr.NumEraseUnits, hdr.FirstPhysicalEUN,
-                                       hdr.FormattedSize, hdr.UnitSizeFactor);
+               DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", 
+                     mtd->read, mtd->size, mtd->erasesize);
 
-                       }
-               }
-               return;
+                NFTL_setup(mtd);
        }
 }
 
@@ -420,100 +252,101 @@ static void NFTL_notify_remove(struct mtd_info *mtd)
 {
        int i;
 
-       for (i=0; i< MAX_NFTLS; i++) {
+       for (i = 0; i < MAX_NFTLS; i++) {
                if (NFTLs[i] && NFTLs[i]->mtd == mtd)
                        NFTL_unsetup(i);
        }
 }
 
-
 #ifdef CONFIG_NFTL_RW
 
 /* Actual NFTL access routines */
-
-
-static u16 NFTL_findfreeblock( struct NFTLrecord *thisNFTL, int desperate )
+/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
+ *     when the give Virtual Unit Chain
+ */
+static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
 {
        /* For a given Virtual Unit Chain: find or create a free block and
           add it to the chain */
        /* We're passed the number of the last EUN in the chain, to save us from
           having to look it up again */
-       
-       u16 pot = thisNFTL->LastFreeEUN;
+       u16 pot = nftl->LastFreeEUN;
        int silly = -1;
 
        /* Normally, we force a fold to happen before we run out of free blocks completely */
-
-       if (!desperate && thisNFTL->numfreeEUNs < 2) {
-               //              printk("NFTL_findfreeblock: there are too few free EUNs\n");
+       if (!desperate && nftl->numfreeEUNs < 2) {
+               DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
                return 0xffff;
        }
 
        /* Scan for a free block */
-
        do {
-               if (thisNFTL->VirtualUnitTable[pot] == 0xffff) {
-                       thisNFTL->LastFreeEUN = pot;
-                       thisNFTL->numfreeEUNs--;
+               if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
+                       nftl->LastFreeEUN = pot;
+                       nftl->numfreeEUNs--;
                        return pot;
                }
 
-               if (++pot > thisNFTL->lastEUN)
-                       pot = le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN);
+               /* This will probably point to the MediaHdr unit itself,
+                  right at the beginning of the partition. But that unit
+                  (and the backup unit too) should have the UCI set
+                  up so that it's not selected for overwriting */
+               if (++pot > nftl->lastEUN)
+                       pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
 
                if (!silly--) {
-                       printk("Tell Dave he fucked up. LastFreeEUN = %d, FirstEUN = %d\n",
-                              thisNFTL->LastFreeEUN, le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN));
+                       printk("Argh! No free blocks found! LastFreeEUN = %d, "
+                              "FirstEUN = %d\n", nftl->LastFreeEUN, 
+                              le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
                        return 0xffff;
                }
-                       
-       } while (pot != thisNFTL->LastFreeEUN);
+       } while (pot != nftl->LastFreeEUN);
 
        return 0xffff;
 }
 
-
-
-
-
-static u16 NFTL_foldchain (struct NFTLrecord *thisNFTL, u16 thisVUC, unsigned pendingblock )
+static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
 {
-       u16 BlockMap[thisNFTL->EraseSize / 512];
-       unsigned char BlockLastState[thisNFTL->EraseSize / 512];
-       unsigned char BlockFreeFound[thisNFTL->EraseSize / 512];
-       u16 thisEUN;
+       u16 BlockMap[MAX_SECTORS_PER_UNIT];
+       unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
+       unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
+       unsigned int thisEUN;
        int block;
-       int silly = -1;
-       u16 targetEUN = 0xffff;
+       int silly;
+       unsigned int targetEUN;
        struct nftl_oob oob;
        int inplace = 1;
+        size_t retlen;
 
        memset(BlockMap, 0xff, sizeof(BlockMap));
        memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
 
-       thisEUN = thisNFTL->EUNtable[thisVUC];
+       thisEUN = nftl->EUNtable[thisVUC];
 
-       if (thisEUN == 0xffff) {
-               printk(KERN_WARNING "Trying to fold non-existent Virtual Unit Chain %d!\n", thisVUC);
-               return 0xffff;
+       if (thisEUN == BLOCK_NIL) {
+               printk(KERN_WARNING "Trying to fold non-existent "
+                      "Virtual Unit Chain %d!\n", thisVUC);
+               return BLOCK_NIL;
        }
        
        /* Scan to find the Erase Unit which holds the actual data for each
           512-byte block within the Chain.
        */
+        silly = MAX_LOOPS;
+       targetEUN = BLOCK_NIL;
+       while (thisEUN <= nftl->lastEUN ) {
+                unsigned int status, foldmark;
 
-       while( thisEUN <= thisNFTL->lastEUN ) {
-               size_t retlen;
-               
                targetEUN = thisEUN;
-
-               for (block = 0 ; block < thisNFTL->EraseSize / 512; block ++) {
-
-                       MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + (block * 512),16 , &retlen, (char *)&oob);
-
+               for (block = 0; block < nftl->EraseSize / 512; block ++) {
+                       MTD_READOOB(nftl->mtd,
+                                   (thisEUN * nftl->EraseSize) + (block * 512),
+                                   16 , &retlen, (char *)&oob);
                        if (block == 2) {
-                               if (oob.u.c.WriteInh != 0xffffffff) {
-                                       printk("Write Inhibited on EUN %d\n", thisEUN);
+                                foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
+                                if (foldmark == FOLD_MARK_IN_PROGRESS) {
+                                        DEBUG(MTD_DEBUG_LEVEL1, 
+                                              "Write Inhibited on EUN %d\n", thisEUN);
                                        inplace = 0;
                                } else {
                                        /* There's no other reason not to do inplace,
@@ -522,153 +355,139 @@ static u16 NFTL_foldchain (struct NFTLrecord *thisNFTL, u16 thisVUC, unsigned pe
                                        inplace = 1;
                                }
                        }
+                        status = oob.b.Status | oob.b.Status1;
+                       BlockLastState[block] = status;
 
-                       BlockLastState[block] = (unsigned char) oob.b.Status & 0xff;
-
-                       switch(oob.b.Status) {
-                       case __constant_cpu_to_le16(BLOCK_FREE):
-                               BlockFreeFound[block]=1;
+                       switch(status) {
+                       case SECTOR_FREE:
+                               BlockFreeFound[block] = 1;
                                break;
 
-                       case __constant_cpu_to_le16(BLOCK_USED):
+                       case SECTOR_USED:
                                if (!BlockFreeFound[block])
                                        BlockMap[block] = thisEUN;
                                else
-                                       printk(KERN_WARNING "BLOCK_USED found after BLOCK_FREE in Virtual Unit Chain %d for block %d\n", thisVUC, block);
+                                       printk(KERN_WARNING 
+                                              "SECTOR_USED found after SECTOR_FREE "
+                                              "in Virtual Unit Chain %d for block %d\n",
+                                              thisVUC, block);
                                break;
-                       case __constant_cpu_to_le16(BLOCK_IGNORE):
-                       case __constant_cpu_to_le16(BLOCK_DELETED):
+                       case SECTOR_IGNORE:
+                       case SECTOR_DELETED:
                                break;
                        default:
-                               printk("Unknown status for block %d in EUN %d: %x\n",block,thisEUN, oob.b.Status);
+                               printk("Unknown status for block %d in EUN %d: %x\n",
+                                      block, thisEUN, status);
                        }
                }
 
                if (!silly--) {
-                       printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC);
-                       return 0xffff;
+                       printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
+                              thisVUC);
+                       return BLOCK_NIL;
                }
                
-               thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
+               thisEUN = nftl->ReplUnitTable[thisEUN];
        }
 
        if (inplace) {
                /* We're being asked to be a fold-in-place. Check
-                  that all blocks are either present or BLOCK_FREE
+                  that all blocks are either present or SECTOR_FREE
                   in the target block. If not, we're going to have
                   to fold out-of-place anyway.
                */
-
-               for (block = 0; block < thisNFTL->EraseSize / 512 ; block++) {
-               
-                       if (BlockLastState[block] != (unsigned char) (cpu_to_le16(BLOCK_FREE) & 0xff) &&
+               for (block = 0; block < nftl->EraseSize / 512 ; block++) {
+                       if (BlockLastState[block] != SECTOR_FREE &&
                            BlockMap[block] != targetEUN) {
-                               DEBUG(1, "Setting inplace to 0. VUC %d, block %d was %x lastEUN, and is in EUN %d (%s) %d\n",
-                                    thisVUC, block, BlockLastState[block], BlockMap[block] , BlockMap[block]==targetEUN?"==":"!=", targetEUN);
-
+                               DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
+                                     "block %d was %x lastEUN, "
+                                     "and is in EUN %d (%s) %d\n",
+                                     thisVUC, block, BlockLastState[block],
+                                     BlockMap[block], 
+                                     BlockMap[block]== targetEUN ? "==" : "!=",
+                                     targetEUN);
                                inplace = 0;
                                break;
                        }
                }
 
-               if ( pendingblock >= (thisVUC * (thisNFTL->EraseSize / 512)) &&
-                    pendingblock < ((thisVUC + 1)* (thisNFTL->EraseSize / 512)) &&
-                    BlockLastState[ pendingblock - (thisVUC * (thisNFTL->EraseSize / 512))] != 
-                    (unsigned char) (cpu_to_le16(BLOCK_FREE) & 0xff)) {
-                       DEBUG(1, "Pending write not free in EUN %d. Folding out of place.\n", targetEUN);
+               if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
+                   pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
+                   BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
+                   SECTOR_FREE) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
+                             "Folding out of place.\n", targetEUN);
                        inplace = 0;
                }
-
        }
        
        if (!inplace) {
-               DEBUG(1, "Cannot fold Virtual Unit Chain %d in place. Trying out-of-place\n", thisVUC);
+               DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
+                     "Trying out-of-place\n", thisVUC);
                /* We need to find a targetEUN to fold into. */
-               targetEUN = NFTL_findfreeblock(thisNFTL, 1);
-               if (targetEUN == 0xffff) {
-                               /* Ouch. Now we're screwed. We need to do a 
-                                  fold-in-place of another chain to make room
-                                  for this one. We need a better way of selecting
-                                  which chain to fold, because makefreeblock will 
-                                  only ask us to fold the same one again.
-                               */
-                       printk(KERN_WARNING"NFTL_findfreeblock(desperate) returns 0xffff.\n");
-                       return 0xffff;
+               targetEUN = NFTL_findfreeblock(nftl, 1);
+               if (targetEUN == BLOCK_NIL) {
+                       /* Ouch. Now we're screwed. We need to do a 
+                          fold-in-place of another chain to make room
+                          for this one. We need a better way of selecting
+                          which chain to fold, because makefreeblock will 
+                          only ask us to fold the same one again.
+                       */
+                       printk(KERN_WARNING
+                              "NFTL_findfreeblock(desperate) returns 0xffff.\n");
+                       return BLOCK_NIL;
                }
-               
-       } 
-
+       } else {
+            /* We put a fold mark in the chain we are folding only if
+               we fold in place to help the mount check code. If we do
+               not fold in place, it is possible to find the valid
+               chain by selecting the longer one */
+            oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
+            oob.u.c.unused = 0xffffffff;
+            MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
+                         8, &retlen, (char *)&oob.u);
+        }
 
        /* OK. We now know the location of every block in the Virtual Unit Chain,
           and the Erase Unit into which we are supposed to be copying.
           Go for it.
        */
-
-       DEBUG(1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
-
-       for (block = 0; block < thisNFTL->EraseSize / 512 ; block++) {
+       DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
+       for (block = 0; block < nftl->EraseSize / 512 ; block++) {
                unsigned char movebuf[512];
-               struct nftl_oob oob;
-               size_t retlen;
-
-               memset(&oob, 0xff, sizeof(oob));
+               int ret;
 
                /* If it's in the target EUN already, or if it's pending write, do nothing */
-               if (BlockMap[block] == targetEUN ||(pendingblock == (thisVUC * (thisNFTL->EraseSize / 512) + block))) {
-                       /* Except if it's the first block, in which case we have to
-                          set the UnitNumbers */
-                       if (block == 0) { 
-                               
-                               thisNFTL->mtd->read_oob(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) ,
-                                               16, &retlen, (char *)&oob);
-
-                               //                              printk("Setting VirtUnitNum on EUN %d to %x, was %x\n", targetEUN, thisVUC, 
-                               //                             le16_to_cpu(oob.u.a.VirtUnitNum));
-
-                               oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC & 0x7fff);
-
-                               thisNFTL->mtd->write_oob(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) ,
-                                                        16, &retlen, (char *)&oob);
-                       }
+               if (BlockMap[block] == targetEUN ||
+                   (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
                        continue;
                }
 
-               oob.b.Status = BLOCK_USED;
-
-               switch(block) {
-               case 0:
-                       oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC & 0x7fff);
-                       //              printk("Setting VirtUnitNum on EUN %d to %x\n", targetEUN, thisVUC);
-                       
-                       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
-                       break;
-                               
-               case 1:
-                       oob.u.b.WearInfo = cpu_to_le32(3); // We don't use this, but M-Systems' drivers do
-                       oob.u.b.EraseMark = oob.u.b.EraseMark1 = cpu_to_le16(0x3c69);
-                       break;
-                       
-               case 2:
-               default:
-                       oob.u.c.WriteInh = 0xffffffff;
-                       oob.u.c.unused = 0xffffffff;
-               }
-               if (thisNFTL->mtd->read_ecc(thisNFTL->mtd, (thisNFTL->EraseSize * BlockMap[block]) + (block * 512),
-                                           512, &retlen, movebuf, (char *)&oob) == -EIO) {
-                       if (thisNFTL->mtd->read_ecc(thisNFTL->mtd, (thisNFTL->EraseSize * BlockMap[block]) + (block * 512),
-                                                   512, &retlen, movebuf, (char *)&oob) != -EIO) 
-                               printk("Error went away on retry.\n");
-               }                       
-
-               thisNFTL->mtd->write_ecc(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) + (block * 512),
-                                        512, &retlen, movebuf, (char *)&oob);
-
-               
-               /* FIXME: Add some error checking.... */
-               thisNFTL->mtd->write_oob(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) + (block * 512), 
-                                        16, &retlen, (char *)&oob);
-
+                /* copy only in non free block (free blocks can only
+                   happen in case of media errors or deleted blocks) */
+                if (BlockMap[block] == BLOCK_NIL)
+                        continue;
+                
+                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
+                                  + (block * 512), 512, &retlen, movebuf, (char *)&oob); 
+                if (ret < 0) {
+                    ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
+                                      + (block * 512), 512, &retlen,
+                                      movebuf, (char *)&oob); 
+                    if (ret != -EIO) 
+                        printk("Error went away on retry.\n");
+                }
+                MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
+                             512, &retlen, movebuf, (char *)&oob);
        }
+        
+        /* add the header so that it is now a valid chain */
+        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
+                = cpu_to_le16(thisVUC);
+        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+        
+        MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, 
+                     8, &retlen, (char *)&oob.u);
 
        /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
 
@@ -677,78 +496,37 @@ static u16 NFTL_foldchain (struct NFTLrecord *thisNFTL, u16 thisVUC, unsigned pe
           shouldn't actually lose data in this case. It's just that when we load up on a medium which
           has duplicate chains, we need to free one of the chains because it's not necessary any more.
        */
-       
-
-       thisEUN = thisNFTL->EUNtable[thisVUC];
+       thisEUN = nftl->EUNtable[thisVUC];
+       DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
 
-       DEBUG(1,"Want to erase\n");
        /* For each block in the old chain (except the targetEUN of course), 
           free it and make it available for future use */
-
-       while( thisEUN <= thisNFTL->lastEUN && thisEUN != targetEUN) {
-               size_t retlen;
-               struct erase_info *instr;
-               u16 EUNtmp;
-
-               instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
-               if (!instr) {
-                       printk(KERN_WARNING "Out of memory for struct erase_info\n");
-
-                       EUNtmp = thisEUN;
-
-                       thisEUN = thisNFTL->ReplUnitTable[EUNtmp] & 0x7fff;
-                       thisNFTL->VirtualUnitTable[EUNtmp] = 0x7fff;
-                       thisNFTL->ReplUnitTable[EUNtmp] = 0xffff;
-               } else {
-                       memset(instr, 0, sizeof(struct erase_info));
-                       instr->addr = thisEUN * thisNFTL->EraseSize;
-                       instr->len = thisNFTL->EraseSize;
-
-                       MTD_ERASE(thisNFTL->mtd,  instr);
-                       /* This is an async interface. Or will be. At which point
-                          this code will break. */
-                       
-#if 0
-                       MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + 512, 16, &retlen, (char *)&oob);
-
-                       printk("After erasing, EUN %d contains: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", 
-                              thisEUN, oob.b.ECCSig[0],
-                              oob.b.ECCSig[1],
-                              oob.b.ECCSig[2],
-                              oob.b.ECCSig[3],
-                              oob.b.ECCSig[4],
-                              oob.b.ECCSig[5]);
-#endif
-                       memset(&oob, 0xff, sizeof(oob));
-                       oob.u.b.WearInfo = cpu_to_le32(3);
-                       oob.u.b.EraseMark = oob.u.b.EraseMark1 = cpu_to_le16(0x3c69);
-
-                       MTD_WRITEOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + 512, 16, &retlen, (char *)&oob);
-
-                       EUNtmp = thisEUN;
-
-                       thisEUN = thisNFTL->ReplUnitTable[EUNtmp] & 0x7fff;
-                       thisNFTL->VirtualUnitTable[EUNtmp] = 0xffff;
-                       thisNFTL->ReplUnitTable[EUNtmp] = 0xffff;
-
-                       thisNFTL->numfreeEUNs++;
-
-               }
-               
-               // shifted upwards:     thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
-
+       while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
+               unsigned int EUNtmp;
+
+                EUNtmp = nftl->ReplUnitTable[thisEUN];
+
+                if (NFTL_formatblock(nftl, thisEUN) < 0) {
+                       /* could not erase : mark block as reserved
+                        * FixMe: Update Bad Unit Table on disk
+                        */
+                       nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
+                } else {
+                       /* correctly erased : mark it as free */
+                       nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
+                       nftl->numfreeEUNs++;
+                }
+                thisEUN = EUNtmp;
        }
        
        /* Make this the new start of chain for thisVUC */
-       thisNFTL->VirtualUnitTable[targetEUN] = thisVUC;
-       thisNFTL->ReplUnitTable[targetEUN] = 0xffff;
+       nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
+       nftl->EUNtable[thisVUC] = targetEUN;
 
-       thisNFTL->EUNtable[thisVUC] = targetEUN;
        return targetEUN;
-       
 }
 
-u16 NFTL_makefreeblock( struct NFTLrecord *thisNFTL , unsigned pendingblock)
+u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
 {
        /* This is the part that needs some cleverness applied. 
           For now, I'm doing the minimum applicable to actually
@@ -757,23 +535,21 @@ u16 NFTL_makefreeblock( struct NFTLrecord *thisNFTL , unsigned pendingblock)
           and we also need to do some assessment of the results when
           the system loses power half-way through the routine.
        */
-
        u16 LongestChain = 0;
        u16 ChainLength = 0, thislen;
        u16 chain, EUN;
 
-
-       for (chain=0; chain < thisNFTL->MediaHdr.FormattedSize / thisNFTL->EraseSize; chain++) {
-               EUN = thisNFTL->EUNtable[chain];
-
+       for (chain = 0; chain < nftl->MediaHdr.FormattedSize / nftl->EraseSize; chain++) {
+               EUN = nftl->EUNtable[chain];
                thislen = 0;
 
-               while (EUN <= thisNFTL->lastEUN) {
+               while (EUN <= nftl->lastEUN) {
                        thislen++;
-                       //                      printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
-                       EUN = thisNFTL->ReplUnitTable[EUN] & 0x7fff;
+                       //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
+                       EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
                        if (thislen > 0xff00) {
-                               printk("Endless loop in Virtual Chain %d: Unit %x\n", chain, EUN);
+                               printk("Endless loop in Virtual Chain %d: Unit %x\n",
+                                      chain, EUN);
                        }
                        if (thislen > 0xff10) {
                                /* Actually, don't return failure. Just ignore this chain and
@@ -781,42 +557,38 @@ u16 NFTL_makefreeblock( struct NFTLrecord *thisNFTL , unsigned pendingblock)
                                thislen = 0;
                                break;
                        }
-                               
                }
 
-
                if (thislen > ChainLength) {
-                       //                      printk("New longest chain is %d with length %d\n", chain, thislen);
+                       //printk("New longest chain is %d with length %d\n", chain, thislen);
                        ChainLength = thislen;
                        LongestChain = chain;
                }
-       }               
+       }
 
        if (ChainLength < 2) {
-               printk(KERN_WARNING "No Virtual Unit Chains available for folding. Failing request\n");
+               printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
+                      "Failing request\n");
                return 0xffff;
        }
-               
-       return NFTL_foldchain (thisNFTL, LongestChain, pendingblock);
+
+       return NFTL_foldchain (nftl, LongestChain, pendingblock);
 }
 
 /* NFTL_findwriteunit: Return the unit number into which we can write 
                        for this block. Make it available if it isn't already
 */
-
-static inline u16 NFTL_findwriteunit(struct NFTLrecord *thisNFTL, unsigned block)
+static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 {
        u16 lastEUN;
-       u16 thisVUC = block / (thisNFTL->EraseSize / 512);
-       u16 writeEUN;
-       unsigned long blockofs = (block * 512) & (thisNFTL->EraseSize -1);
+       u16 thisVUC = block / (nftl->EraseSize / 512);
+       unsigned int writeEUN;
+       unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
        size_t retlen;
-       int silly = 0x10000, silly2 = 3;
+       int silly, silly2 = 3;
        struct nftl_oob oob;
-       int debug=0;
 
        do {
-
                /* Scan the media to find a unit in the VUC which has
                   a free space for the block in question.
                */
@@ -824,28 +596,30 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *thisNFTL, unsigned block
                /* This condition catches the 0x[7f]fff cases, as well as 
                   being a sanity check for past-end-of-media access
                */
-               lastEUN = 0xffff;
-               writeEUN = thisNFTL->EUNtable[thisVUC];
-
-               while(writeEUN <= thisNFTL->lastEUN) {
+               lastEUN = BLOCK_NIL;
+               writeEUN = nftl->EUNtable[thisVUC];
+                silly = MAX_LOOPS;
+               while (writeEUN <= nftl->lastEUN) {
                        struct nftl_bci bci;
                        size_t retlen;
-                       
+                        unsigned int status;
+
                        lastEUN = writeEUN;
+
+                       MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
+                                   8, &retlen, (char *)&bci);
                        
-                       MTD_READOOB(thisNFTL->mtd, (writeEUN * thisNFTL->EraseSize) 
-                                   + blockofs,8, &retlen, (char *)&bci);
-                       
-                       if (debug) 
-                               printk("Status of block %d in EUN %d is %x\n", block , writeEUN, le16_to_cpu(bci.Status));
+                       DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
+                             block , writeEUN, le16_to_cpu(bci.Status));
 
-                       switch(bci.Status) {
-                       case __constant_cpu_to_le16(BLOCK_FREE):
+                        status = bci.Status | bci.Status1;
+                       switch(status) {
+                       case SECTOR_FREE:
                                return writeEUN;
 
-                       case __constant_cpu_to_le16(BLOCK_DELETED):
-                       case __constant_cpu_to_le16(BLOCK_USED):
-                       case __constant_cpu_to_le16(BLOCK_IGNORE):
+                       case SECTOR_DELETED:
+                       case SECTOR_USED:
+                       case SECTOR_IGNORE:
                                break;
                        default:
                                // Invalid block. Don't use it any more. Must implement.
@@ -853,35 +627,35 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *thisNFTL, unsigned block
                        }
                        
                        if (!silly--) { 
-                               printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC);
+                               printk(KERN_WARNING
+                                      "Infinite loop in Virtual Unit Chain 0x%x\n",
+                                      thisVUC);
                                return 0xffff;
                        }
 
                        /* Skip to next block in chain */
-
-                       writeEUN = thisNFTL->ReplUnitTable[writeEUN] & 0x7fff;
+                       writeEUN = nftl->ReplUnitTable[writeEUN];
                }
 
                /* OK. We didn't find one in the existing chain, or there 
                   is no existing chain. */
 
                /* Try to find an already-free block */
+               writeEUN = NFTL_findfreeblock(nftl, 0);
 
-               writeEUN = NFTL_findfreeblock(thisNFTL, 0);
-
-               if (writeEUN == 0xffff) {
+               if (writeEUN == BLOCK_NIL) {
                        /* That didn't work - there were no free blocks just
                           waiting to be picked up. We're going to have to fold
                           a chain to make room.
                        */
 
                        /* First remember the start of this chain */
-                       //                      u16 startEUN = thisNFTL->EUNtable[thisVUC];
+                       //u16 startEUN = nftl->EUNtable[thisVUC];
                        
                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
-                       writeEUN = NFTL_makefreeblock(thisNFTL, block);
+                       writeEUN = NFTL_makefreeblock(nftl, 0xffff);
                        
-                       if (writeEUN == 0xffff) {
+                       if (writeEUN == BLOCK_NIL) {
                                /* Ouch. This should never happen - we should
                                   always be able to make some room somehow. 
                                   If we get here, we've allocated more storage 
@@ -889,235 +663,223 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *thisNFTL, unsigned block
                                   routine is missing something.
                                */
                                printk(KERN_WARNING "Cannot make free space.\n");
-                               return 0xffff;
+                               return BLOCK_NIL;
                        }                       
-                       //                      printk("Restarting scan\n");
-                       lastEUN = 0xffff;
-                       //                      debug = 1;
+                       //printk("Restarting scan\n");
+                       lastEUN = BLOCK_NIL;
                        continue;
-#if 0
-                       if (startEUN != thisNFTL->EUNtable[thisVUC]) {
-                               /* The fold operation has moved the chain 
-                                  that we're looking at. Start the scan again.
-                               */
-                               continue;
-                       }
-#endif
                }
 
                /* We've found a free block. Insert it into the chain. */
                
-               if (lastEUN != 0xffff) {
-                       /* Addition to an existing chain. Make the previous
-                          last block in the chain point to this one.
-                       */
-
-                       //printk("Linking EUN %d to EUN %d in VUC %d\n", 
-                       //                             lastEUN, writeEUN, thisVUC);
-                       /* Both in our cache... */
-                       thisNFTL->ReplUnitTable[lastEUN] = writeEUN;
-
-
-                       /* ... and on the flash itself */
-                       MTD_READOOB(thisNFTL->mtd, (lastEUN * thisNFTL->EraseSize), 16, &retlen,
-                                   (char *)&oob);
+               if (lastEUN != BLOCK_NIL) {
+                    thisVUC |= 0x8000; /* It's a replacement block */
+               } else {
+                    /* The first block in a new chain */
+                    nftl->EUNtable[thisVUC] = writeEUN;
+               }
 
-                       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = cpu_to_le16(writeEUN);
+               /* set up the actual EUN we're writing into */
+               /* Both in our cache... */
+               nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
 
-                       MTD_WRITEOOB(thisNFTL->mtd, (lastEUN * thisNFTL->EraseSize), 16, &retlen,
-                            (char *)&oob);
+               /* ... and on the flash itself */
+               MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
+                           &retlen, (char *)&oob.u);
 
-                       thisVUC |= 0x8000; /* It's a replacement block */
-               } else {
-                       /* The first block in a new chain */
-                       thisNFTL->EUNtable[thisVUC] = writeEUN;
-               }
+               oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
 
-               /* Now set up the actual EUN we're writing into */
+               MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
+                             &retlen, (char *)&oob.u);
 
+                /* we link the new block to the chain only after the
+                   block is ready. It avoids the case where the chain
+                   could point to a free block */
+                if (lastEUN != BLOCK_NIL) {
                        /* Both in our cache... */
-               thisNFTL->VirtualUnitTable[writeEUN] = thisVUC;
-               thisNFTL->ReplUnitTable[writeEUN] = 0xffff;
-
+                       nftl->ReplUnitTable[lastEUN] = writeEUN;
                        /* ... and on the flash itself */
-               MTD_READOOB(thisNFTL->mtd, writeEUN * thisNFTL->EraseSize, 16,
-                           &retlen, (char *)&oob);
+                       MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
+                                   8, &retlen, (char *)&oob.u);
 
-               oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
+                       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
+                               = cpu_to_le16(writeEUN);
 
-               MTD_WRITEOOB(thisNFTL->mtd, writeEUN * thisNFTL->EraseSize, 16,
-                           &retlen, (char *)&oob);
+                       MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
+                                    8, &retlen, (char *)&oob.u);
+               }
 
                return writeEUN;
 
        } while (silly2--);
 
-       printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n", thisVUC);
+       printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
+              thisVUC);
        return 0xffff;
 }
 
-static int NFTL_writeblock(struct NFTLrecord *thisNFTL, unsigned block,
-                          char *buffer)
+static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
 {
        u16 writeEUN;
-       unsigned long blockofs = (block * 512) & (thisNFTL->EraseSize -1);
+       unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
        size_t retlen;
-       u16 eccbuf[8];
-
-       //      if (thisEUN == 0xffff) thisEUN = 0;
-
-       writeEUN = NFTL_findwriteunit(thisNFTL, block);
+       u8 eccbuf[6];
 
-//     printk("writeblock(%d): Write to Unit %d\n", block, writeEUN);
+       writeEUN = NFTL_findwriteunit(nftl, block);
 
-       if (writeEUN == 0xffff) {
-               printk(KERN_WARNING "NFTL_writeblock(): Cannot find block to write to\n");
+       if (writeEUN == BLOCK_NIL) {
+               printk(KERN_WARNING
+                      "NFTL_writeblock(): Cannot find block to write to\n");
                /* If we _still_ haven't got a block to use, we're screwed */
                return 1;
        }
-//             printk("Writing block %lx to EUN %x\n",block, writeEUN);
 
-
-       thisNFTL->mtd->write_ecc(thisNFTL->mtd, 
-                               (writeEUN * thisNFTL->EraseSize) + blockofs,
-                               512, &retlen, (char *)buffer, (char *)eccbuf);
-       eccbuf[3] = BLOCK_USED;
-       eccbuf[4] = eccbuf[5] = eccbuf[6] = eccbuf[7] = 0xffff;
-
-       thisNFTL->mtd->write_oob(thisNFTL->mtd,
-                                (writeEUN * thisNFTL->EraseSize) + blockofs,
-                                16, &retlen, (char *)eccbuf);
+       MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
+                    512, &retlen, (char *)buffer, (char *)eccbuf);
+        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
 
        return 0;
 }
-
 #endif /* CONFIG_NFTL_RW */
 
-static int NFTL_readblock(struct NFTLrecord *thisNFTL, 
-                         unsigned block, char *buffer)
+static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
 {
-       u16 lastgoodEUN = 0xffff;
-       u16 thisEUN = thisNFTL->EUNtable[block / (thisNFTL->EraseSize / 512)];
-       unsigned long blockofs = (block * 512) & (thisNFTL->EraseSize -1);
-
-       int silly = -1;
+       u16 lastgoodEUN;
+       u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
+       unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
+        unsigned int status;
+       int silly = MAX_LOOPS;
+        size_t retlen;
+        struct nftl_bci bci;
+
+       lastgoodEUN = BLOCK_NIL;
+
+        if (thisEUN != BLOCK_NIL) {
+               while (thisEUN < nftl->nb_blocks) {
+                       if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
+                                       8, &retlen, (char *)&bci) < 0)
+                               status = SECTOR_IGNORE;
+                       else
+                               status = bci.Status | bci.Status1;
+
+                       switch (status) {
+                       case SECTOR_FREE:
+                               /* no modification of a sector should follow a free sector */
+                               goto the_end;
+                       case SECTOR_DELETED:
+                               lastgoodEUN = BLOCK_NIL;
+                               break;
+                       case SECTOR_USED:
+                               lastgoodEUN = thisEUN;
+                               break;
+                       case SECTOR_IGNORE:
+                               break;
+                       default:
+                               printk("Unknown status for block %d in EUN %d: %x\n",
+                                      block, thisEUN, status);
+                               break;
+                       }
 
-       if (thisEUN == 0xffff) thisEUN = 0;
-       
-       while(thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
-               struct nftl_bci bci;
-               size_t retlen;
-               
-               MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + blockofs,8, &retlen, (char *)&bci);
-               
-               switch(bci.Status) {
-               case __constant_cpu_to_le16(BLOCK_FREE):
-                       thisEUN = 0;
-                       break;
-               case __constant_cpu_to_le16(BLOCK_USED):
-                       lastgoodEUN = thisEUN;
-                       break;
-               case __constant_cpu_to_le16(BLOCK_IGNORE):
-               case __constant_cpu_to_le16(BLOCK_DELETED):
-                       break;
-               default:
-                       printk("Unknown status for block %d in EUN %d: %x\n",block,thisEUN, bci.Status);
+                       if (!silly--) {
+                               printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
+                                      block / (nftl->EraseSize / 512));
+                               return 1;
+                       }
+                       thisEUN = nftl->ReplUnitTable[thisEUN];
                }
+        }
 
-               if (!silly--) {
-                       printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",block / (thisNFTL->EraseSize / 512));
-                       return 1;
-               }
-               if (thisEUN)
-                       thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
-       }
-       if (lastgoodEUN == 0xffff) {
+ the_end:
+       if (lastgoodEUN == BLOCK_NIL) {
+               /* the requested block is not on the media, return all 0x00 */
                memset(buffer, 0, 512);
        } else {
-               loff_t ptr = (lastgoodEUN * thisNFTL->EraseSize) + blockofs;
+               loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
                size_t retlen;
                u_char eccbuf[6];
-               thisNFTL->mtd->read_ecc(thisNFTL->mtd, ptr, 512, &retlen, buffer, eccbuf);
+               if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf))
+                       return -EIO;
        }
        return 0;
 }
 
-
-static int nftl_ioctl(struct inode * inode, struct file * file,
-                     unsigned int cmd, unsigned long arg)
+static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
 {
-       struct NFTLrecord *thisNFTL;
-
-       thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
+       struct NFTLrecord *nftl;
 
-       if (!thisNFTL) return -EINVAL;
+       nftl = NFTLs[MINOR(inode->i_rdev) / 16];
 
+       if (!nftl) return -EINVAL;
 
        switch (cmd) {
        case HDIO_GETGEO: {
                struct hd_geometry g;
 
-               g.heads = thisNFTL->heads;
-               g.sectors = thisNFTL->sectors;
-               g.cylinders = thisNFTL->cylinders;
+               g.heads = nftl->heads;
+               g.sectors = nftl->sectors;
+               g.cylinders = nftl->cylinders;
                g.start = part_table[MINOR(inode->i_rdev)].start_sect;
                return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
        }
        case BLKGETSIZE:   /* Return device size */
-               if (!arg)  return -EINVAL;
+               if (!arg) return -EINVAL;
                return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
                                 (long *) arg);
                
        case BLKFLSBUF:
-               if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+               if (!capable(CAP_SYS_ADMIN)) return -EACCES;
                fsync_dev(inode->i_rdev);
                invalidate_buffers(inode->i_rdev);
-               if (thisNFTL->mtd->sync)
-                       thisNFTL->mtd->sync(thisNFTL->mtd);
+               if (nftl->mtd->sync)
+                       nftl->mtd->sync(nftl->mtd);
                return 0;
 
        case BLKRRPART:
                if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-               if (thisNFTL->usecount > 1) {
-                       //                      printk("Use count %d\n", thisNFTL->usecount);
-                       return -EBUSY;
-               }
+               if (nftl->usecount > 1) return -EBUSY;
 #if LINUX_VERSION_CODE < 0x20328
-               resetup_one_dev(&nftl_gendisk, MINOR(inode->i_dev) / 16);
+               resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) / 16);
 #else
-               grok_partitions(&nftl_gendisk, MINOR(inode->i_dev) / 16, 1<<4, thisNFTL->nr_sects);
+               grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) / 16,
+                               1<<4, nftl->nr_sects);
 #endif
                return 0;
-               
-               //        RO_IOCTLS(inode->i_rdev, arg);  /* ref. linux/blk.h */
+
+#if (LINUX_VERSION_CODE < 0x20303)             
+       RO_IOCTLS(inode->i_rdev, arg);  /* ref. linux/blk.h */
+#else
+       case BLKROSET:
+       case BLKROGET:
+       case BLKSSZGET:
+               return blk_ioctl(inode->i_rdev, cmd, arg);
+#endif
+
        default:
                return -EINVAL;
        }
 }
 
-
 void nftl_request(RQFUNC_ARG)
 {
        unsigned int dev, block, nsect;
-       struct NFTLrecord *thisNFTL;
+       struct NFTLrecord *nftl;
        char *buffer;
        struct request *req;
        int res;
 
        while (1) {
                INIT_REQUEST;   /* blk.h */
-               
-               req = CURRENT;
-#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
-               blkdev_dequeue_request(req);
-               spin_unlock_irq(&io_request_lock);
-#else
                req = CURRENT;
-#endif         
                
-               DEBUG(2,"NFTL_request\n");
-               DEBUG(3,"NFTL %d request, %lx, %lx", req->cmd, 
-                      req->sector, req->current_nr_sectors);
+               /* We can do this because the generic code knows not to
+                  touch the request at the head of the queue */
+               spin_unlock_irq(&io_request_lock);
+
+               DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
+               DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
+                     (req->cmd == READ) ? "Read " : "Write",
+                     req->sector, req->current_nr_sectors);
+
                dev = MINOR(req->rq_dev);
                block = req->sector;
                nsect = req->current_nr_sectors;
@@ -1125,21 +887,23 @@ void nftl_request(RQFUNC_ARG)
                res = 1; /* succeed */
 
                if (dev >= MAX_NFTLS * 16) {
-                       printk("fl: bad minor number: device=%s\n",
+                       /* there is no such partition */
+                       printk("nftl: bad minor number: device = %s\n",
                               kdevname(req->rq_dev));
                        res = 0; /* fail */
                        goto repeat;
                }
                
-               thisNFTL = NFTLs[dev / 16];
-               DEBUG(3,"Waiting for mutex\n");
-               down(&thisNFTL->mutex);
-               DEBUG(3,"Got mutex\n");
-               
-               if (block + nsect >= part_table[dev].nr_sects) {
-                       printk("nftl%c%d: bad access: block=%d, count=%d\n",
+               nftl = NFTLs[dev / 16];
+               DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
+               down(&nftl->mutex);
+               DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
+
+               if (block + nsect > part_table[dev].nr_sects) {
+                       /* access past the end of device */
+                       printk("nftl%c%d: bad access: block = %d, count = %d\n",
                               (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
-                       up(&thisNFTL->mutex);
+                       up(&nftl->mutex);
                        res = 0; /* fail */
                        goto repeat;
                }
@@ -1147,75 +911,80 @@ void nftl_request(RQFUNC_ARG)
                block += part_table[dev].start_sect;
                
                if (req->cmd == READ) {
-                       DEBUG(2,"NFTL read\n"); 
-                       for ( ; nsect > 0; nsect-- , block++, buffer+= 512) {
+                       DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
+                             "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
+       
+                       for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
                                /* Read a single sector to req->buffer + (512 * i) */
-                               
-                               if (NFTL_readblock(thisNFTL, block, buffer)) {
-                                       DEBUG(2,"NFTL read request failed\n");
-                                       up(&thisNFTL->mutex);
+                               if (NFTL_readblock(nftl, block, buffer)) {
+                                       DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
+                                       up(&nftl->mutex);
                                        res = 0;
                                        goto repeat;
                                }
                        }
-                       DEBUG(2,"NFTL read request completed OK\n");
-                       up(&thisNFTL->mutex);
+
+                       DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
+                       up(&nftl->mutex);
                        goto repeat;
-               }
-               else if (req->cmd == WRITE) {
-                       DEBUG(2,"NFTL write request of 0x%x sectors @ %x (req->nr_sectors == %lx\n",nsect, block, req->nr_sectors);
+               } else if (req->cmd == WRITE) {
+                       DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
+                             "(req->nr_sectors == %lx)\n", nsect, block,
+                             req->nr_sectors);
 #ifdef CONFIG_NFTL_RW
-                       for ( ; nsect > 0; nsect-- , block++, buffer+= 512) {
+                       for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
                                /* Read a single sector to req->buffer + (512 * i) */
-                               
-                               if (NFTL_writeblock(thisNFTL, block, buffer)) {
-                                       DEBUG(1,"NFTL write request failed\n");
-                                       
-                                       up(&thisNFTL->mutex);
+                               if (NFTL_writeblock(nftl, block, buffer)) {
+                                       DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
+                                       up(&nftl->mutex);
                                        res = 0;
                                        goto repeat;
                                }
                        }
-                       DEBUG(2,"NFTL write request completed OK\n");
+                       DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
 #else
-                       res=0; /* Writes always fail */
+                       res = 0; /* Writes always fail */
 #endif /* CONFIG_NFTL_RW */
-                       up(&thisNFTL->mutex);
+                       up(&nftl->mutex);
                        goto repeat;
-               }
-               else {
-                       DEBUG(0,"NFTL ??? request\n");
-                       up(&thisNFTL->mutex);
+               } else {
+                       DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
+                       up(&nftl->mutex);
                        res = 0;
                        goto repeat;
                }
        repeat: 
-               DEBUG(3,"end_request(%d)\n", res);
-#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+               DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
                spin_lock_irq(&io_request_lock);
-               nftl_end_request(req, res);
-#else
                end_request(res);
-#endif
        }
 }
 
 static int nftl_open(struct inode *ip, struct file *fp)
 {
+       int nftlnum = MINOR(ip->i_rdev) / 16;
        struct NFTLrecord *thisNFTL;
-       thisNFTL = NFTLs[MINOR(ip->i_rdev) / 16];
+       thisNFTL = NFTLs[nftlnum];
 
-       DEBUG(2,"NFTL_open\n");
+       DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
 
+#ifdef CONFIG_KMOD
+       if (!thisNFTL && nftlnum == 0) {
+               request_module("docprobe");
+               thisNFTL = NFTLs[nftlnum];
+       }
+#endif
        if (!thisNFTL) {
-               DEBUG(2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", 
-                     MINOR(ip->i_rdev) / 16,ip->i_rdev,ip, fp);
+               DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", 
+                     nftlnum, ip->i_rdev, ip, fp);
                return -ENODEV;
        }
+
 #ifndef CONFIG_NFTL_RW
        if (fp->f_mode & FMODE_WRITE)
-           return -EROFS;
+               return -EROFS;
 #endif /* !CONFIG_NFTL_RW */
+
        thisNFTL->usecount++;
        MOD_INC_USE_COUNT;
        if (!get_mtd_device(thisNFTL->mtd, -1)) {
@@ -1233,8 +1002,8 @@ static int nftl_release(struct inode *inode, struct file *fp)
 
        thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
 
-       DEBUG(2, "NFTL_release\n");
-       
+       DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
+
        fsync_dev(inode->i_rdev);
        if (sb)
                invalidate_inodes(sb);
@@ -1251,19 +1020,19 @@ static int nftl_release(struct inode *inode, struct file *fp)
 }
 #if LINUX_VERSION_CODE < 0x20326
 static struct file_operations nftl_fops = {
-        read:          block_read,
-        write:         block_write,
-        ioctl:         nftl_ioctl,
-        open:          nftl_open,
-        release:       nftl_release,
-        fsync:         block_fsync,
+       read:           block_read,
+       write:          block_write,
+       ioctl:          nftl_ioctl,
+       open:           nftl_open,
+       release:        nftl_release,
+       fsync:          block_fsync,
 };
 #else
 static struct block_device_operations nftl_fops = 
 {
-       open: nftl_open,
-       release: nftl_release,
-       ioctl: nftl_ioctl
+       open:           nftl_open,
+       release:        nftl_release,
+       ioctl:          nftl_ioctl
 };
 #endif
 
@@ -1275,39 +1044,39 @@ static struct block_device_operations nftl_fops =
  *
  ****************************************************************************/
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_nftl init_module
 #define cleanup_nftl cleanup_module
 #endif
-#define __exit
-#endif
 
 static struct mtd_notifier nftl_notifier = {NFTL_notify_add, NFTL_notify_remove, NULL};
 
-
 /* static int __init init_nftl(void) */
 int __init init_nftl(void)
 {
        int i;
 
-       printk(KERN_NOTICE "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
+       printk(KERN_NOTICE
+              "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
 #ifdef PRERELEASE 
-       printk(KERN_INFO"$Id: nftl.c,v 1.36 2000/07/13 14:14:20 dwmw2 Exp $\n");
+       printk(KERN_INFO"$Id: nftl.c,v 1.57 2000/12/01 17:51:54 dwmw2 Exp $\n");
 #endif
 
-       if (register_blkdev(NFTL_MAJOR, "nftl", &nftl_fops)){
-               printk("unable to register NFTL block device\n");
+       if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
+               printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
+               return -EBUSY;
        } else {
 #if LINUX_VERSION_CODE < 0x20320
-         blk_dev[MAJOR_NR].request_fn = nftl_request;
+               blk_dev[MAJOR_NR].request_fn = nftl_request;
 #else
-         blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
+               blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
 #endif
-               for (i=0; i < 256 ; i++) {
+               /* set block size to 1kB each */
+               for (i = 0; i < 256; i++) {
                        nftl_blocksizes[i] = 1024;
                }
-               blksize_size[NFTL_MAJOR] = nftl_blocksizes;
+               blksize_size[MAJOR_NR] = nftl_blocksizes;
+
                nftl_gendisk.next = gendisk_head;
                gendisk_head = &nftl_gendisk;
        }
@@ -1319,25 +1088,25 @@ int __init init_nftl(void)
 
 static void __exit cleanup_nftl(void)
 {
-  struct gendisk *gd, **gdp;
+       struct gendisk *gd, **gdp;
 
-  unregister_mtd_user(&nftl_notifier);
-
-  unregister_blkdev(NFTL_MAJOR, "nftl");
+       unregister_mtd_user(&nftl_notifier);
+       unregister_blkdev(MAJOR_NR, "nftl");
+       
 #if LINUX_VERSION_CODE < 0x20320
-  blk_dev[MAJOR_NR].request_fn = 0;
+       blk_dev[MAJOR_NR].request_fn = 0;
 #else
-  blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+       blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 #endif 
-  for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-    if (*gdp == &nftl_gendisk) {
-      gd = *gdp; *gdp = gd->next;
-      break;
-    }
-  
+
+       /* remove ourself from generic harddisk list
+          FIXME: why can't I found this partition on /proc/partition */
+       for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+               if (*gdp == &nftl_gendisk) {
+                       gd = *gdp; *gdp = gd->next;
+                       break;
+       }
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_nftl);
 module_exit(cleanup_nftl);
-#endif
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
new file mode 100644 (file)
index 0000000..d1f0593
--- /dev/null
@@ -0,0 +1,678 @@
+/* 
+ * NFTL mount code with extensive checks
+ *
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: nftlmount.c,v 1.11 2000/11/17 12:24:09 ollie Exp $
+ *
+ * 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nftl.h>
+#include <linux/mtd/compatmac.h>
+
+#define SECTORSIZE 512
+
+/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
+ *     various device information of the NFTL partition and Bad Unit Table. Update
+ *     the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
+ *     is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
+ */
+static int find_boot_record(struct NFTLrecord *nftl)
+{
+       struct nftl_uci1 h1;
+       struct nftl_oob oob;
+       unsigned int block, boot_record_count;
+       int retlen;
+       u8 buf[SECTORSIZE];
+       struct NFTLMediaHeader *mh = &nftl->MediaHdr;
+
+       nftl->MediaUnit = BLOCK_NIL;
+       nftl->SpareMediaUnit = BLOCK_NIL;
+       boot_record_count = 0;
+
+       /* search for a valid boot record */
+       for (block = 0; block < nftl->nb_blocks; block++) {
+               unsigned int erase_mark;
+
+               /* read ANAND header. To be safer with BIOS, also use erase mark as discriminant */
+               if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+                               8, &retlen, (char *)&h1) < 0)
+                       continue;
+
+               erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
+               if (erase_mark != ERASE_MARK) 
+                       continue;
+
+               if (MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
+                               &retlen, buf, (char *)&oob) < 0)
+                       continue;
+
+               memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
+               if (memcmp(mh->DataOrgID, "ANAND", 6) == 0) {
+                       /* first boot record */
+                       if (boot_record_count == 0) {
+                               unsigned int i;
+                               /* header found : read the bad block table data */
+                               if (mh->UnitSizeFactor != 0xff) {
+                                       printk("Sorry, we don't support UnitSizeFactor "
+                                              "of != 1 yet\n");
+                                       goto ReplUnitTable;
+                               }
+
+                               nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
+                               if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks)
+                                       goto ReplUnitTable; /* small consistency check */
+
+                               nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
+                               if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2))
+                                       goto ReplUnitTable; /* small consistency check */
+
+                               /* FixMe: with bad blocks, the total size available is not FormattedSize any
+                                  more !!! */
+                               nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
+                               nftl->MediaUnit = block;
+
+                               /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
+                               for (i = 0; i < nftl->nb_blocks; i++) {
+                                       if ((i & (SECTORSIZE - 1)) == 0) {
+                                               /* read one sector for every SECTORSIZE of blocks */
+                                               if (MTD_READECC(nftl->mtd, block * nftl->EraseSize +
+                                                               i + SECTORSIZE, SECTORSIZE,
+                                                               &retlen, buf, (char *)&oob) < 0)
+                                                       goto ReplUnitTable;
+                                       }
+                                       /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
+                                       if (buf[i & (SECTORSIZE - 1)] != 0xff)
+                                               nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+                               }
+
+                               boot_record_count++;
+                       } else if (boot_record_count == 1) {
+                               nftl->SpareMediaUnit = block;
+                               boot_record_count++;
+                               break;
+                       }
+               }
+       ReplUnitTable:
+       }
+
+       if (boot_record_count == 0) {
+               /* no boot record found */
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+static int memcmpb(void *a, int c, int n)
+{
+       int i;
+       for (i = 0; i < n; i++) {
+               if (c != ((unsigned char *)a)[i])
+                       return 1;
+       }
+       return 0;
+}
+
+/* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
+static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, 
+                             int check_oob)
+{
+       int i, retlen;
+       u8 buf[SECTORSIZE];
+
+       for (i = 0; i < len; i += SECTORSIZE) {
+               /* we want to read the sector without ECC check here since a free
+                  sector does not have ECC syndrome on it yet */
+               if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0)
+                       return -1;
+               if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
+                       return -1;
+
+               if (check_oob) {
+                       if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize,
+                                       &retlen, buf) < 0)
+                               return -1;
+                       if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0)
+                               return -1;
+               }
+               address += SECTORSIZE;
+       }
+
+       return 0;
+}
+
+/* NFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase Unit and
+ *              Update NFTL metadata. Each erase operation is checked with check_free_sectors
+ *
+ * Return: 0 when succeed, -1 on error.
+ *
+ *  ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
+ *        2. UnitSizeFactor != 0xFF
+ */
+int NFTL_formatblock(struct NFTLrecord *nftl, int block)
+{
+       int retlen;
+       unsigned int nb_erases, erase_mark;
+       struct nftl_uci1 uci;
+       struct erase_info *instr = &nftl->instr;
+
+       /* Read the Unit Control Information #1 for Wear-Leveling */
+       if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+                       8, &retlen, (char *)&uci) < 0)
+               goto default_uci1;
+
+       erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
+       if (erase_mark != ERASE_MARK) {
+       default_uci1:
+               uci.EraseMark = cpu_to_le16(ERASE_MARK);
+               uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
+               uci.WearInfo = cpu_to_le32(0);
+       }
+
+       memset(instr, 0, sizeof(struct erase_info));
+
+       /* XXX: use async erase interface, XXX: test return code */
+       instr->addr = block * nftl->EraseSize;
+       instr->len = nftl->EraseSize;
+       MTD_ERASE(nftl->mtd, instr);
+
+       if (instr->state == MTD_ERASE_FAILED) {
+               /* could not format, FixMe: We should update the BadUnitTable 
+                  both in memory and on disk */
+               printk("Error while formatting block %d\n", block);
+               return -1;
+       } else {
+               /* increase and write Wear-Leveling info */
+               nb_erases = le32_to_cpu(uci.WearInfo);
+               nb_erases++;
+
+               /* wrap (almost impossible with current flashs) or free block */
+               if (nb_erases == 0)
+                       nb_erases = 1;
+
+               /* check the "freeness" of Erase Unit before updating metadata
+                * FixMe:  is this check really necessary ? since we have check the
+                *         return code after the erase operation. */
+               if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
+                       return -1;
+
+               uci.WearInfo = le32_to_cpu(nb_erases);
+               if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
+                                &retlen, (char *)&uci) < 0)
+                       return -1;
+               return 0;
+       }
+}
+
+/* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
+ *     Mark as 'IGNORE' each incorrect sector. This check is only done if the chain
+ *     was being folded when NFTL was interrupted.
+ *
+ *     The check_free_sectors in this function is neceressary. There is a possible
+ *     situation that after writing the Data area, the Block Control Information is
+ *     not updated according (due to power failure or something) which leaves the block
+ *     in an umconsistent state. So we have to check if a block is really FREE in this
+ *     case. */
+static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
+{
+       unsigned int block, i, status;
+       struct nftl_bci bci;
+       int sectors_per_block, retlen;
+
+       sectors_per_block = nftl->EraseSize / SECTORSIZE;
+       block = first_block;
+       for (;;) {
+               for (i = 0; i < sectors_per_block; i++) {
+                       if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE,
+                                       8, &retlen, (char *)&bci) < 0)
+                               status = SECTOR_IGNORE;
+                       else
+                               status = bci.Status | bci.Status1;
+
+                       switch(status) {
+                       case SECTOR_FREE:
+                               /* verify that the sector is really free. If not, mark
+                                  as ignore */
+                               if (memcmpb(&bci, 0xff, 8) != 0 ||
+                                   check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, 
+                                                      SECTORSIZE, 0) != 0) {
+                                       printk("Incorrect free sector %d in block %d: "
+                                              "marking it as ignored\n",
+                                              i, block);
+
+                                       /* sector not free actually : mark it as SECTOR_IGNORE  */
+                                       bci.Status = SECTOR_IGNORE;
+                                       bci.Status1 = SECTOR_IGNORE;
+                                       MTD_WRITEOOB(nftl->mtd,
+                                                    block * nftl->EraseSize + i * SECTORSIZE,
+                                                    8, &retlen, (char *)&bci);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               /* proceed to next Erase Unit on the chain */
+               block = nftl->ReplUnitTable[block];
+               if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
+                       printk("incorrect ReplUnitTable[] : %d\n", block);
+               if (block == BLOCK_NIL || block >= nftl->nb_blocks)
+                       break;
+       }
+}
+
+/* calc_chain_lenght: Walk through a Virtual Unit Chain and estimate chain length */
+static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
+{
+       unsigned int length = 0, block = first_block;
+
+       for (;;) {
+               length++;
+               /* avoid infinite loops, although this is guaranted not to
+                  happen because of the previous checks */
+               if (length >= nftl->nb_blocks) {
+                       printk("nftl: length too long %d !\n", length);
+                       break;
+               }
+
+               block = nftl->ReplUnitTable[block];
+               if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
+                       printk("incorrect ReplUnitTable[] : %d\n", block);
+               if (block == BLOCK_NIL || block >= nftl->nb_blocks)
+                       break;
+       }
+       return length;
+}
+
+/* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a
+ *     Virtual Unit Chain, i.e. all the units are disconnected.
+ *
+ *     It is not stricly correct to begin from the first block of the chain because
+ *     if we stop the code, we may see again a valid chain if there was a first_block
+ *     flag in a block inside it. But is it really a problem ?
+ *
+ * FixMe: Figure out what the last statesment means. What if power failure when we are
+ *     in the for (;;) loop formatting blocks ??
+ */
+static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
+{
+       unsigned int block = first_block, block1;
+
+       printk("Formatting chain at block %d\n", first_block);
+
+       for (;;) {
+               block1 = nftl->ReplUnitTable[block];
+
+               printk("Formatting block %d\n", block);
+               if (NFTL_formatblock(nftl, block) < 0) {
+                       /* cannot format !!!! Mark it as Bad Unit,
+                          FixMe: update the BadUnitTable on disk */
+                       nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+               } else {
+                       nftl->ReplUnitTable[block] = BLOCK_FREE;
+               }
+
+               /* goto next block on the chain */
+               block = block1;
+
+               if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
+                       printk("incorrect ReplUnitTable[] : %d\n", block);
+               if (block == BLOCK_NIL || block >= nftl->nb_blocks)
+                       break;
+       }
+}
+
+/* check_and_mark_free_block: Verify that a block is free in the NFTL sense (valid erase mark) or
+ *     totally free (only 0xff).
+ *
+ * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the
+ *     following critia:
+ *     1. */
+static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
+{
+       struct nftl_uci1 h1;
+       unsigned int erase_mark;
+       int i, retlen;
+       unsigned char buf[SECTORSIZE];
+
+       /* check erase mark. */
+       if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
+                       &retlen, (char *)&h1) < 0)
+               return -1;
+
+       erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
+       if (erase_mark != ERASE_MARK) {
+               /* if no erase mark, the block must be totally free. This is
+                  possible in two cases : empty filsystem or interrupted erase (very unlikely) */
+               if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)
+                       return -1;
+
+               /* free block : write erase mark */
+               h1.EraseMark = cpu_to_le16(ERASE_MARK);
+               h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
+               h1.WearInfo = cpu_to_le32(0);
+               if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
+                                &retlen, (char *)&h1) < 0)
+                       return -1;
+       } else {
+#if 0
+               /* if erase mark present, need to skip it when doing check */
+               for (i = 0; i < nftl->EraseSize; i += SECTORSIZE) {
+                       /* check free sector */
+                       if (check_free_sectors (nftl, block * nftl->EraseSize + i,
+                                               SECTORSIZE, 0) != 0)
+                               return -1;
+
+                       if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i,
+                                       16, &retlen, buf) < 0)
+                               return -1;
+                       if (i == SECTORSIZE) {
+                               /* skip erase mark */
+                               if (memcmpb(buf, 0xff, 8))
+                                       return -1;
+                       } else {
+                               if (memcmpb(buf, 0xff, 16))
+                                       return -1;
+                       }
+               }
+#endif
+       }
+
+       return 0;
+}
+
+/* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS
+ *     to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2
+ *     is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted
+ *     for some reason. A clean up/check of the VUC is neceressary in this case.
+ *
+ * WARNING: return 0 if read error
+ */
+static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
+{
+       struct nftl_uci2 uci;
+       int retlen;
+
+       if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
+                       8, &retlen, (char *)&uci) < 0)
+               return 0;
+
+       return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
+}
+
+int NFTL_mount(struct NFTLrecord *s)
+{
+       int i;
+       unsigned int first_logical_block, logical_block, rep_block, nb_erases, erase_mark;
+       unsigned int block, first_block, is_first_block;
+       int chain_length, do_format_chain;
+       struct nftl_uci0 h0;
+       struct nftl_uci1 h1;
+       int retlen;
+
+       /* XXX: will be suppressed */
+       s->lastEUN = s->nb_blocks - 1;
+
+       /* memory alloc */
+       s->EUNtable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
+       s->ReplUnitTable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
+       if (!s->EUNtable || !s->ReplUnitTable) {
+       fail:
+               if (s->EUNtable)
+                       kfree(s->EUNtable);
+               if (s->ReplUnitTable)
+                       kfree(s->ReplUnitTable);
+               return -1;
+       }
+
+       /* mark all blocks as potentially containing data */
+       for (i = 0; i < s->nb_blocks; i++) { 
+               s->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
+       }
+
+       /* search for NFTL MediaHeader and Spare NFTL Media Header */
+       if (find_boot_record(s) < 0) {
+               printk("Could not find valid boot record\n");
+               goto fail;
+       }
+
+       /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
+       for (i = 0; i < s->nb_boot_blocks; i++)
+               s->ReplUnitTable[i] = BLOCK_RESERVED;
+
+       /* also mark the boot records (NFTL MediaHeader) blocks as reserved */
+       if (s->MediaUnit != BLOCK_NIL)
+               s->ReplUnitTable[s->MediaUnit] = BLOCK_RESERVED;
+       if (s->SpareMediaUnit != BLOCK_NIL)
+               s->ReplUnitTable[s->SpareMediaUnit] = BLOCK_RESERVED;
+
+       /* init the logical to physical table */
+       for (i = 0; i < s->nb_blocks; i++) {
+               s->EUNtable[i] = BLOCK_NIL;
+       }
+
+       /* first pass : explore each block chain */
+       first_logical_block = 0;
+       for (first_block = 0; first_block < s->nb_blocks; first_block++) {
+               /* if the block was not already explored, we can look at it */
+               if (s->ReplUnitTable[first_block] == BLOCK_NOTEXPLORED) {
+                       block = first_block;
+                       chain_length = 0;
+                       do_format_chain = 0;
+
+                       for (;;) {
+                               /* read the block header. If error, we format the chain */
+                               if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8, 
+                                               &retlen, (char *)&h0) < 0 ||
+                                   MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8, 
+                                               &retlen, (char *)&h1) < 0) {
+                                       s->ReplUnitTable[block] = BLOCK_NIL;
+                                       do_format_chain = 1;
+                                       break;
+                               }
+
+                               logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
+                               rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
+                               nb_erases = le32_to_cpu (h1.WearInfo);
+                               erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
+
+                               is_first_block = !(logical_block >> 15);
+                               logical_block = logical_block & 0x7fff;
+
+                               /* invalid/free block test */
+                               if (erase_mark != ERASE_MARK || logical_block >= s->nb_blocks) {
+                                       if (chain_length == 0) {
+                                               /* if not currently in a chain, we can handle it safely */
+                                               if (check_and_mark_free_block(s, block) < 0) {
+                                                       /* not really free: format it */
+                                                       printk("Formatting block %d\n", block);
+                                                       if (NFTL_formatblock(s, block) < 0) {
+                                                               /* could not format: reserve the block */
+                                                               s->ReplUnitTable[block] = BLOCK_RESERVED;
+                                                       } else {
+                                                               s->ReplUnitTable[block] = BLOCK_FREE;
+                                                       }
+                                               } else {
+                                                       /* free block: mark it */
+                                                       s->ReplUnitTable[block] = BLOCK_FREE;
+                                               }
+                                               /* directly examine the next block. */
+                                               goto examine_ReplUnitTable;
+                                       } else {
+                                               /* the block was in a chain : this is bad. We
+                                                  must format all the chain */
+                                               printk("Block %d: free but referenced in chain %d\n",
+                                                      block, first_block);
+                                               s->ReplUnitTable[block] = BLOCK_NIL;
+                                               do_format_chain = 1;
+                                               break;
+                                       }
+                               }
+
+                               /* we accept only first blocks here */
+                               if (chain_length == 0) {
+                                       /* this block is not the first block in chain :
+                                          ignore it, it will be included in a chain
+                                          later, or marked as not explored */
+                                       if (!is_first_block)
+                                               goto examine_ReplUnitTable;
+                                       first_logical_block = logical_block;
+                               } else {
+                                       if (logical_block != first_logical_block) {
+                                               printk("Block %d: incorrect logical block: %d expected: %d\n", 
+                                                      block, logical_block, first_logical_block);
+                                               /* the chain is incorrect : we must format it,
+                                                  but we need to read it completly */
+                                               do_format_chain = 1;
+                                       }
+                                       if (is_first_block) {
+                                               /* we accept that a block is marked as first
+                                                  block while being last block in a chain
+                                                  only if the chain is being folded */
+                                               if (get_fold_mark(s, block) != FOLD_MARK_IN_PROGRESS ||
+                                                   rep_block != 0xffff) {
+                                                       printk("Block %d: incorrectly marked as first block in chain\n",
+                                                              block);
+                                                       /* the chain is incorrect : we must format it,
+                                                          but we need to read it completly */
+                                                       do_format_chain = 1;
+                                               } else {
+                                                       printk("Block %d: folding in progress - ignoring first block flag\n",
+                                                              block);
+                                               }
+                                       }
+                               }
+                               chain_length++;
+                               if (rep_block == 0xffff) {
+                                       /* no more blocks after */
+                                       s->ReplUnitTable[block] = BLOCK_NIL;
+                                       break;
+                               } else if (rep_block >= s->nb_blocks) {
+                                       printk("Block %d: referencing invalid block %d\n", 
+                                              block, rep_block);
+                                       do_format_chain = 1;
+                                       s->ReplUnitTable[block] = BLOCK_NIL;
+                                       break;
+                               } else if (s->ReplUnitTable[rep_block] != BLOCK_NOTEXPLORED) {
+                                       /* same problem as previous 'is_first_block' test:
+                                          we accept that the last block of a chain has
+                                          the first_block flag set if folding is in
+                                          progress. We handle here the case where the
+                                          last block appeared first */
+                                       if (s->ReplUnitTable[rep_block] == BLOCK_NIL &&
+                                           s->EUNtable[first_logical_block] == rep_block &&
+                                           get_fold_mark(s, first_block) == FOLD_MARK_IN_PROGRESS) {
+                                               /* EUNtable[] will be set after */
+                                               printk("Block %d: folding in progress - ignoring first block flag\n",
+                                                      rep_block);
+                                               s->ReplUnitTable[block] = rep_block;
+                                               s->EUNtable[first_logical_block] = BLOCK_NIL;
+                                       } else {
+                                               printk("Block %d: referencing block %d already in another chain\n", 
+                                                      block, rep_block);
+                                               /* XXX: should handle correctly fold in progress chains */
+                                               do_format_chain = 1;
+                                               s->ReplUnitTable[block] = BLOCK_NIL;
+                                       }
+                                       break;
+                               } else {
+                                       /* this is OK */
+                                       s->ReplUnitTable[block] = rep_block;
+                                       block = rep_block;
+                               }
+                       }
+
+                       /* the chain was completely explored. Now we can decide
+                          what to do with it */
+                       if (do_format_chain) {
+                               /* invalid chain : format it */
+                               format_chain(s, first_block);
+                       } else {
+                               unsigned int first_block1, chain_to_format, chain_length1;
+                               int fold_mark;
+                               
+                               /* valid chain : get foldmark */
+                               fold_mark = get_fold_mark(s, first_block);
+                               if (fold_mark == 0) {
+                                       /* cannot get foldmark : format the chain */
+                                       printk("Could read foldmark at block %d\n", first_block);
+                                       format_chain(s, first_block);
+                               } else {
+                                       if (fold_mark == FOLD_MARK_IN_PROGRESS)
+                                               check_sectors_in_chain(s, first_block);
+
+                                       /* now handle the case where we find two chains at the
+                                          same virtual address : we select the longer one,
+                                          because the shorter one is the one which was being
+                                          folded if the folding was not done in place */
+                                       first_block1 = s->EUNtable[first_logical_block];
+                                       if (first_block1 != BLOCK_NIL) {
+                                               /* XXX: what to do if same length ? */
+                                               chain_length1 = calc_chain_length(s, first_block1);
+                                               printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", 
+                                                      first_block1, chain_length1, first_block, chain_length);
+                                               
+                                               if (chain_length >= chain_length1) {
+                                                       chain_to_format = first_block1;
+                                                       s->EUNtable[first_logical_block] = first_block;
+                                               } else {
+                                                       chain_to_format = first_block;
+                                               }
+                                               format_chain(s, chain_to_format);
+                                       } else {
+                                               s->EUNtable[first_logical_block] = first_block;
+                                       }
+                               }
+                       }
+               }
+       examine_ReplUnitTable:
+       }
+
+       /* second pass to format unreferenced blocks  and init free block count */
+       s->numfreeEUNs = 0;
+       s->LastFreeEUN = BLOCK_NIL;
+
+       for (block = 0; block < s->nb_blocks; block++) {
+               if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
+                       printk("Unreferenced block %d, formatting it\n", block);
+                       if (NFTL_formatblock(s, block) < 0)
+                               s->ReplUnitTable[block] = BLOCK_RESERVED;
+                       else
+                               s->ReplUnitTable[block] = BLOCK_FREE;
+               }
+               if (s->ReplUnitTable[block] == BLOCK_FREE) {
+                       s->numfreeEUNs++;
+                       s->LastFreeEUN = block;
+               }
+       }
+
+       return 0;
+}
index 9304d7e6230ad6ff6c31242b88ce6a95b7a0913e..48da299fc880cc87e16d0aa612210675ec8822cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nora.c,v 1.12 2000/07/13 10:32:33 dwmw2 Exp $
+ * $Id: nora.c,v 1.17 2000/12/03 19:32:21 dwmw2 Exp $
  *
  * This is so simple I love it.
  */
@@ -58,19 +58,17 @@ void nora_copy_to(struct map_info *map, unsigned long to, const void *from, ssiz
 }
 
 struct map_info nora_map = {
-  "NORA",
-  WINDOW_SIZE,
-  2,
-  nora_read8,
-  nora_read16,
-  nora_read32,
-  nora_copy_from,
-  nora_write8,
-  nora_write16,
-  nora_write32,
-  nora_copy_to,
-  0,
-  0
+       name: "NORA",
+       size: WINDOW_SIZE,
+       buswidth: 2,
+       read8: nora_read8,
+       read16: nora_read16,
+       read32: nora_read32,
+       copy_from: nora_copy_from,
+       write8: nora_write8,
+       write16: nora_write16,
+       write32: nora_write32,
+       copy_to: nora_copy_to
 };
 
 
@@ -140,7 +138,7 @@ static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
        {
                type: MTD_NORFLASH,
                flags: MTD_CAP_NORFLASH,
-               size: 0xf00000,
+               size: 0x900000,
                erasesize: 0x20000,
                name: "NORA root filesystem",
                module: THIS_MODULE,
@@ -155,9 +153,9 @@ static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
        {
                type: MTD_NORFLASH,
                flags: MTD_CAP_NORFLASH,
-               size: 0x1000000,
+               size: 0x1600000,
                erasesize: 0x20000,
-               name: "NORA main filesystem",
+               name: "NORA second filesystem",
                module: THIS_MODULE,
                erase: nora_mtd_erase,
                read: nora_mtd_read,
@@ -165,16 +163,15 @@ static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
                suspend: nora_mtd_suspend,
                resume: nora_mtd_resume,
                sync: nora_mtd_sync,
-               priv: (void *)0x1000000
+               priv: (void *)0xa00000
        }
 };
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_nora init_module
 #define cleanup_nora cleanup_module
 #endif
-#endif
 
 int __init init_nora(void)
 {
@@ -186,10 +183,10 @@ int __init init_nora(void)
                mymtd->module = &__this_module;
 #endif
                
-               add_mtd_device(&nora_mtds[3]);
+               add_mtd_device(&nora_mtds[2]);
                add_mtd_device(&nora_mtds[0]);
                add_mtd_device(&nora_mtds[1]);
-               add_mtd_device(&nora_mtds[2]);
+               add_mtd_device(&nora_mtds[3]);
                return 0;
        }
 
@@ -199,10 +196,13 @@ int __init init_nora(void)
 static void __exit cleanup_nora(void)
 {
        if (mymtd) {
-               del_mtd_device(&nora_mtds[2]);
+               del_mtd_device(&nora_mtds[3]);
                del_mtd_device(&nora_mtds[1]);
                del_mtd_device(&nora_mtds[0]);
-               del_mtd_device(&nora_mtds[3]);
+               del_mtd_device(&nora_mtds[2]);
                map_destroy(mymtd);
        }
 }
+
+module_init(init_nora);
+module_exit(cleanup_nora);
index b184cd0e7cc82be07b96c56041b966e3f1d2a557..70e78d7e9c0318a6c55a449ef2177edc74a7d61e 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.10 2000/07/13 14:04:23 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.12 2000/11/27 08:50:22 dwmw2 Exp $
 /* ######################################################################
 
    Octagon 5066 MTD Driver. 
@@ -151,32 +151,32 @@ static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *
 
 static struct map_info oct5066_map[2] = {
        {
-               "Octagon 5066 Socket",
-               512 * 1024,
-               1,
-               oct5066_read8,
-               oct5066_read16,
-               oct5066_read32,
-               oct5066_copy_from,
-               oct5066_write8,
-               oct5066_write16,
-               oct5066_write32,
-               oct5066_copy_to,
-               1<<6
+               name: "Octagon 5066 Socket",
+               size: 512 * 1024,
+               buswidth: 1,
+               read8: oct5066_read8,
+               read16: oct5066_read16,
+               read32: oct5066_read32,
+               copy_from: oct5066_copy_from,
+               write8: oct5066_write8,
+               write16: oct5066_write16,
+               write32: oct5066_write32,
+               copy_to: oct5066_copy_to,
+               map_priv_1: 1<<6
        },
        {
-               "Octagon 5066 Internal Flash",
-               2 * 1024 * 1024,
-               1,
-               oct5066_read8,
-               oct5066_read16,
-               oct5066_read32,
-               oct5066_copy_from,
-               oct5066_write8,
-               oct5066_write16,
-               oct5066_write32,
-               oct5066_copy_to,
-               2<<6
+               name: "Octagon 5066 Internal Flash",
+               size: 2 * 1024 * 1024,
+               buswidth: 1,
+               read8: oct5066_read8,
+               read16: oct5066_read16,
+               read32: oct5066_read32,
+               copy_from: oct5066_copy_from,
+               write8: oct5066_write8,
+               write16: oct5066_write16,
+               write32: oct5066_write32,
+               copy_to: oct5066_copy_to,
+               map_priv_1: 2<<6
        }
 };
 
@@ -213,13 +213,10 @@ static int __init OctProbe()
    return 0;
 }
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_oct5066 init_module
 #define cleanup_oct5066 cleanup_module
 #endif
-#define __exit
-#endif
 
 void cleanup_oct5066(void)
 {
@@ -284,7 +281,5 @@ int __init init_oct5066(void)
        return 0;
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_oct5066);
 module_exit(cleanup_oct5066);
-#endif
index 658b8bf4776ad76406e91af4d16d497a3f0643a5..31ac39310fe218e4d5e9212ba1479282bde0ad65 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: physmap.c,v 1.2 2000/07/11 09:42:32 dwmw2 Exp $
+ * $Id: physmap.c,v 1.8 2000/11/27 08:50:22 dwmw2 Exp $
  *
  * Normal mappings of chips in physical memory
  */
@@ -15,6 +15,7 @@
 
 #define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
 #define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
+#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
 
 static struct mtd_info *mymtd;
 
@@ -59,32 +60,28 @@ void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, s
 }
 
 struct map_info physmap_map = {
-       "Physically mapped flash",
-       WINDOW_SIZE,
-       2,
-       physmap_read8,
-       physmap_read16,
-       physmap_read32,
-       physmap_copy_from,
-       physmap_write8,
-       physmap_write16,
-       physmap_write32,
-       physmap_copy_to,
-       0,
-       0
+       name: "Physically mapped flash",
+       size: WINDOW_SIZE,
+       buswidth: BUSWIDTH,
+       read8: physmap_read8,
+       read16: physmap_read16,
+       read32: physmap_read32,
+       copy_from: physmap_copy_from,
+       write8: physmap_write8,
+       write16: physmap_write16,
+       write32: physmap_write32,
+       copy_to: physmap_copy_to
 };
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_physmap init_module
 #define cleanup_physmap cleanup_module
 #endif
-#endif
 
 int __init init_physmap(void)
 {
                printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-       physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_SIZE, WINDOW_ADDR);
+       physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
        if (!physmap_map.map_priv_1) {
                printk("Failed to ioremap\n");
@@ -99,6 +96,7 @@ int __init init_physmap(void)
                return 0;
        }
 
+       iounmap((void *)physmap_map.map_priv_1);
        return -ENXIO;
 }
 
@@ -113,3 +111,7 @@ static void __exit cleanup_physmap(void)
                physmap_map.map_priv_1 = 0;
        }
 }
+
+module_init(init_physmap);
+module_exit(cleanup_physmap);
+
index 4e4b052a76b96e5e5210121d9cc472ae74ccd379..a93dd354870ef54134a4ab3c471759130847d10d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: pnc2000.c,v 1.1 2000/07/12 09:34:32 dwmw2 Exp $
+ * $Id: pnc2000.c,v 1.4 2000/11/27 08:50:22 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -14,6 +14,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
 
 
 #define WINDOW_ADDR 0xbf000000
@@ -64,136 +65,60 @@ void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize
 }
 
 struct map_info pnc_map = {
-  "PNC-2000",
-  WINDOW_SIZE,
-  4,
-  pnc_read8,
-  pnc_read16,
-  pnc_read32,
-  pnc_copy_from,
-  pnc_write8,
-  pnc_write16,
-  pnc_write32,
-  pnc_copy_to,
-  0,
-  0
+       name: "PNC-2000",
+       size: WINDOW_SIZE,
+       buswidth: 4,
+       read8: pnc_read8,
+       read16: pnc_read16,
+       read32: pnc_read32,
+       copy_from: pnc_copy_from,
+       write8: pnc_write8,
+       write16: pnc_write16,
+       write32: pnc_write32,
+       copy_to: pnc_copy_to
 };
 
 
 /*
  * MTD 'PARTITIONING' STUFF 
  */
-
-/* 
- * This is the _real_ MTD device for which all the others are just
- * auto-relocating aliases.
- */
-static struct mtd_info *mymtd;
-
-/* 
- * MTD methods which simply translate the effective address and pass through
- * to the _real_ device.
- */
-
-static int pnc_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-       return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf);
-}
-
-static int pnc_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
-       return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf);
-}
-
-static int pnc_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-       instr->addr += (unsigned long)mtd->priv;
-       return mymtd->erase(mymtd, instr);
-}
-
-static void pnc_mtd_sync (struct mtd_info *mtd)
-{
-       mymtd->sync(mymtd);
-}
-
-static int pnc_mtd_suspend (struct mtd_info *mtd)
-{
-       return mymtd->suspend(mymtd);
-}
-
-static void pnc_mtd_resume (struct mtd_info *mtd)
-{
-       mymtd->resume(mymtd);
-}
-
-
-static struct mtd_info pnc_mtds[3] = {  /* boot, kernel, fs */
+static struct mtd_partition pnc_partitions[3] = {
        {
-               type: MTD_NORFLASH,
-               flags: MTD_CAP_NORFLASH,
-               size: 0x20000,
-               erasesize: 0x20000,
                name: "PNC-2000 boot firmware",
-               module: THIS_MODULE,
-               erase: pnc_mtd_erase,
-               read: pnc_mtd_read,
-               write: pnc_mtd_write,
-               suspend: pnc_mtd_suspend,
-               resume: pnc_mtd_resume,
-               sync: pnc_mtd_sync,
-               priv: (void *)0
+               size: 0x20000,
+               offset: 0
        },
        {
-               type: MTD_NORFLASH,
-               flags: MTD_CAP_NORFLASH,
-               size: 0x1a0000,
-               erasesize: 0x20000,
                name: "PNC-2000 kernel",
-               module: THIS_MODULE,
-               erase: pnc_mtd_erase,
-               read: pnc_mtd_read,
-               write: pnc_mtd_write,
-               suspend: pnc_mtd_suspend,
-               resume: pnc_mtd_resume,
-               sync: pnc_mtd_sync,
-               priv: (void *)0x20000
+               size: 0x1a0000,
+               offset: 0x20000
        },
        {
-               type: MTD_NORFLASH,
-               flags: MTD_CAP_NORFLASH,
-               size: 0x240000,
-               erasesize: 0x20000,
                name: "PNC-2000 filesystem",
-               module: THIS_MODULE,
-               erase: pnc_mtd_erase,
-               read: pnc_mtd_read,
-               write: pnc_mtd_write,
-               suspend: pnc_mtd_suspend,
-               resume: pnc_mtd_resume,
-               sync: pnc_mtd_sync,
-               priv: (void *)0x1c0000
+               size: 0x240000,
+               offset: 0x1c0000
        }
 };
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+/* 
+ * This is the master MTD device for which all the others are just
+ * auto-relocating aliases.
+ */
+static struct mtd_info *mymtd;
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_pnc init_module
 #define cleanup_pnc cleanup_module
 #endif
-#endif
 
 int __init init_pnc(void)
 {
-               printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+       printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
 
        mymtd = do_cfi_probe(&pnc_map);
        if (mymtd) {
                mymtd->module = THIS_MODULE;
-               
-               add_mtd_device(&pnc_mtds[0]); /* boot */
-               add_mtd_device(&pnc_mtds[1]); /* kernel */
-               add_mtd_device(&pnc_mtds[2]); /* file system */
-               return 0;
+               return add_mtd_partitions(mymtd, pnc_partitions, 3);
        }
 
        return -ENXIO;
@@ -202,9 +127,10 @@ int __init init_pnc(void)
 static void __exit cleanup_pnc(void)
 {
        if (mymtd) {
-               del_mtd_device(&pnc_mtds[2]);
-               del_mtd_device(&pnc_mtds[1]);
-               del_mtd_device(&pnc_mtds[0]);
+               del_mtd_partitions(mymtd);
                map_destroy(mymtd);
        }
 }
+
+module_init(init_pnc);
+module_exit(cleanup_pnc);
index 783c863acf2eae9d76dfb183e715eb57ea406ded..51bcaf8a9e19cbe6094050b9ab8b616dfd46a1d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: rpxlite.c,v 1.2 2000/07/04 12:16:26 dwmw2 Exp $
+ * $Id: rpxlite.c,v 1.8 2000/12/09 22:00:31 dwmw2 Exp $
  *
- * Handle the strange 16-in-32-bit mapping on the RPXLite board
+ * Handle mapping of the flash on the RPX Lite and CLLF boards
  */
 
 #include <linux/module.h>
 #include <linux/mtd/map.h>
 
 
-#define WINDOW_ADDR 0x8000000
-#define WINDOW_SIZE 0x2000000
-
-#define MAP_TO_ADR(x) ( ( ( x & ~1 ) << 1 ) | (x&1) )
+#define WINDOW_ADDR 0xfe000000
+#define WINDOW_SIZE 0x800000
 
 static struct mtd_info *mymtd;
 
 __u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
 {
-       return readb(map->map_priv_1 + MAP_TO_ADR(ofs));
+       return readb(map->map_priv_1 * ofs);
 }
 
 __u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
 {
-       return readw(map->map_priv_1 + MAP_TO_ADR(ofs));
+       return readw(map->map_priv_1 + ofs);
 }
 
 __u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
 {
-       return readl(map->map_priv_1 + MAP_TO_ADR(ofs));
+       return readl(map->map_priv_1 + ofs);
 }
 
 void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
-       if (from & 1) {
-               *(__u8 *)to = readb(map->map_priv_1 + MAP_TO_ADR(from));
-               from++;
-               len--;
-       }
-       /* Can't do this if it's not aligned */
-       if (!((unsigned long)to & 1)) {
-               unsigned long fromadr = MAP_TO_ADR(from);
-
-               while (len > 1) {
-                       *(__u16 *)to = readw(map->map_priv_1 + fromadr);
-                       to += 2;
-                       fromadr += 4;
-                       from += 2;
-                       len -= 2;
-               }
-       }
-       while(len) {
-               *(__u8 *)to = readb(map->map_priv_1 + MAP_TO_ADR(from));
-               to++;
-               from++;
-               len--;
-       }
+       memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
 }
 
 void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-       writeb(d, map->map_priv_1 + MAP_TO_ADR(adr));
+       writeb(d, map->map_priv_1 + adr);
 }
 
 void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-       writew(d, map->map_priv_1 + MAP_TO_ADR(adr));
+       writew(d, map->map_priv_1 + adr);
 }
 
 void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
-       writel(d, map->map_priv_1 + MAP_TO_ADR(adr));
+       writel(d, map->map_priv_1 + adr);
 }
 
 void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
-       if (to & 1) {
-               writeb(*(__u8 *)from, map->map_priv_1 + MAP_TO_ADR(to));
-               from++;
-               len--;
-       }
-       /* Can't do this if it's not aligned */
-       if (!((unsigned long)from & 1)) {
-               unsigned long toadr = map->map_priv_1 + MAP_TO_ADR(to);
-
-               while (len > 1) {
-                       writew(*(__u16 *)from, toadr);
-                       from += 2;
-                       toadr += 4;
-                       to += 2;
-                       len -= 2;
-               }
-       }
-       while(len) {
-               writeb(*(__u8 *)from, map->map_priv_1 + MAP_TO_ADR(to));
-               to++;
-               from++;
-               len--;
-       }
+       memcpy_toio((void *)(map->map_priv_1 + to), from, len);
 }
 
 struct map_info rpxlite_map = {
-       "RPXLITE",
-       WINDOW_SIZE,
-       2,
-       rpxlite_read8,
-       rpxlite_read16,
-       rpxlite_read32,
-       rpxlite_copy_from,
-       rpxlite_write8,
-       rpxlite_write16,
-       rpxlite_write32,
-       rpxlite_copy_to,
-       0,
-       0
+       name: "RPX",
+       size: WINDOW_SIZE,
+       buswidth: 4,
+       read8: rpxlite_read8,
+       read16: rpxlite_read16,
+       read32: rpxlite_read32,
+       copy_from: rpxlite_copy_from,
+       write8: rpxlite_write8,
+       write16: rpxlite_write16,
+       write32: rpxlite_write32,
+       copy_to: rpxlite_copy_to
 };
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_rpxlite init_module
 #define cleanup_rpxlite cleanup_module
 #endif
-#endif
 
 int __init init_rpxlite(void)
 {
-               printk(KERN_NOTICE "rpxlite flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-       rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 2);
+       printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
+       rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
 
        if (!rpxlite_map.map_priv_1) {
                printk("Failed to ioremap\n");
@@ -158,3 +108,6 @@ static void __exit cleanup_rpxlite(void)
                rpxlite_map.map_priv_1 = 0;
        }
 }
+
+module_init(init_rpxlite);
+module_exit(cleanup_rpxlite);
index 553beaad61faa5fed05136d08f528c28ee90b75a..e694604e7afe60f8f8c251e5c6a435a0c0c4357e 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: vmax301.c,v 1.13 2000/07/03 10:01:38 dwmw2 Exp $
+// $Id: vmax301.c,v 1.15 2000/11/27 08:50:22 dwmw2 Exp $
 /* ######################################################################
 
    Tempustech VMAX SBC301 MTD Driver.
@@ -142,46 +142,43 @@ static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *
 
 static struct map_info vmax_map[2] = {
        {
-               "VMAX301 Internal Flash",
-               3*2*1024*1024,
-               1,
-               vmax301_read8,
-               vmax301_read16,
-               vmax301_read32,
-               vmax301_copy_from,
-               vmax301_write8,
-               vmax301_write16,
-               vmax301_write32,
-               vmax301_copy_to,
-               WINDOW_START + WINDOW_LENGTH,
-               0xFFFFFFFF
+               name: "VMAX301 Internal Flash",
+               size: 3*2*1024*1024,
+               buswidth: 1,
+               read8: vmax301_read8,
+               read16: vmax301_read16,
+               read32: vmax301_read32,
+               copy_from: vmax301_copy_from,
+               write8: vmax301_write8,
+               write16: vmax301_write16,
+               write32: vmax301_write32,
+               copy_to: vmax301_copy_to,
+               map_priv_1: WINDOW_START + WINDOW_LENGTH,
+               map_priv_2: 0xFFFFFFFF
        },
        {
-               "VMAX301 Socket",
-               0,
-               1,
-               vmax301_read8,
-               vmax301_read16,
-               vmax301_read32,
-               vmax301_copy_from,
-               vmax301_write8,
-               vmax301_write16,
-               vmax301_write32,
-               vmax301_copy_to,
-               WINDOW_START + (3*WINDOW_LENGTH),
-               0xFFFFFFFF
+               name: "VMAX301 Socket",
+               size: 0,
+               buswidth: 1,
+               read8: vmax301_read8,
+               read16: vmax301_read16,
+               read32: vmax301_read32,
+               copy_from: vmax301_copy_from,
+               write8: vmax301_write8,
+               write16: vmax301_write16,
+               write32: vmax301_write32,
+               copy_to: vmax301_copy_to,
+               map_priv_1: WINDOW_START + (3*WINDOW_LENGTH),
+               map_priv_2: 0xFFFFFFFF
        }
 };
 
 static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
 
-#if LINUX_VERSION_CODE < 0x20300
-#ifdef MODULE
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
 #define init_vmax301 init_module
 #define cleanup_vmax301 cleanup_module
 #endif
-#define __exit
-#endif
 
 static void __exit cleanup_vmax301(void)
 {
@@ -237,7 +234,5 @@ int __init init_vmax301(void)
        return 0;
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 module_init(init_vmax301);
 module_exit(cleanup_vmax301);
-#endif
index f73af08284fa455e635c1f2bc7ad414f9f1e5c18..19bf1ef0fa708ee43ae95bdc31ba0c7eaaa2bd34 100644 (file)
@@ -2223,7 +2223,7 @@ static int ace_open(struct net_device *dev)
        /*
         * Setup the bottom half rx ring refill handler
         */
-       ap->immediate.next = NULL;
+       INIT_LIST_HEAD(&ap->immediate.list);
        ap->immediate.sync = 0;
        ap->immediate.routine = (void *)(void *)ace_bh;
        ap->immediate.data = dev;
index 7d5e67b5c6436cdb727754813a95d28227c71b46..5a06600f0dc7631d03224882c161a9d834267341 100644 (file)
@@ -2868,7 +2868,7 @@ int awc_private_init(struct net_device * dev){
        
        priv->command_semaphore_on = 0;
        priv->unlock_command_postponed = 0;
-       priv->immediate_bh.next         = NULL;
+       INIT_LIST_HEAD(&priv->immediate_bh.list);
        priv->immediate_bh.sync         = 0;
        priv->immediate_bh.routine      = (void *)(void *)awc_bh;
        priv->immediate_bh.data         = dev;
index c8cab206293e229ac6f017534044668674485ce7..a70ab61a38c309c3508e8d38ea9d0c3354837383 100644 (file)
@@ -440,8 +440,10 @@ int __init eth16i_probe(struct net_device *dev)
 {
        int i;
        int ioaddr;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
     
+       SET_MODULE_OWNER(dev);
+
        if(eth16i_debug > 4) 
                printk(KERN_DEBUG "Probing started for %s\n", cardname);
 
@@ -979,8 +981,6 @@ static int eth16i_open(struct net_device *dev)
        outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);  
 
        netif_start_queue(dev);
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -1007,8 +1007,6 @@ static int eth16i_close(struct net_device *dev)
        
        outb(0x00, ioaddr + CONFIG_REG_1);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index a4cfce6aebebba9dd8f48dc7e5783cd0a557f23c..5863998cb8e5df58e9c663028b0a4e1260ab6961 100644 (file)
@@ -67,6 +67,8 @@ struct net_local
  
 int __init ethertap_probe(struct net_device *dev)
 {
+       SET_MODULE_OWNER(dev);
+
        memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6);
        if (dev->mem_start & 0xf)
                ethertap_debug = dev->mem_start & 0x7;
@@ -116,13 +118,9 @@ static int ethertap_open(struct net_device *dev)
        if (ethertap_debug > 2)
                printk("%s: Doing ethertap_open()...", dev->name);
 
-       MOD_INC_USE_COUNT;
-
        lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx);
-       if (lp->nl == NULL) {
-               MOD_DEC_USE_COUNT;
+       if (lp->nl == NULL)
                return -ENOBUFS;
-       }
        netif_start_queue(dev);
        return 0;
 }
@@ -324,7 +322,6 @@ static int ethertap_close(struct net_device *dev)
                sock_release(sk->socket);
        }
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index 60cef746f634301b6ffbad5151987d39a96f9109..b10fe94904b520d3aa3cd08a3771698ed2d05205 100644 (file)
@@ -350,6 +350,8 @@ int __init ewrk3_probe(struct net_device *dev)
        int tmp = num_ewrk3s, status = -ENODEV;
        u_long iobase = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        if ((iobase == 0) && loading_module) {
                printk("Autoprobing is not supported when loading a module based driver.\n");
                status = -EIO;
@@ -681,8 +683,6 @@ static int ewrk3_open(struct net_device *dev)
                return -EINVAL;
        }
 
-       MOD_INC_USE_COUNT;
-
        return status;
 }
 
@@ -1132,8 +1132,6 @@ static int ewrk3_close(struct net_device *dev)
        if (!lp->hard_strapped) {
                free_irq(dev->irq, dev);
        }
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
@@ -1860,15 +1858,7 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 }
 
 #ifdef MODULE
-static char devicename[9] =
-{0,};
-static struct net_device thisEthwrk =
-{
-       devicename,             /* device name is inserted by /linux/drivers/net/net_init.c */
-       0, 0, 0, 0,
-       0x300, 5,               /* I/O address, IRQ */
-       0, 0, 0, NULL, ewrk3_probe};
-
+static struct net_device thisEthwrk;
 static int io = 0x300;         /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
 static int irq = 5;            /* or use the insmod io= irq= options           */
 
@@ -1879,6 +1869,7 @@ int init_module(void)
 {
        thisEthwrk.base_addr = io;
        thisEthwrk.irq = irq;
+       thisEthwrk.init = ewrk3_probe;
        if (register_netdev(&thisEthwrk) != 0)
                return -EIO;
        return 0;
index 9c14239657191cf00e71f3539addc341c24ceeb0..14265574d8ccf60c77373153fde6ff1d6f6acb92 100644 (file)
@@ -134,6 +134,8 @@ int __init fmv18x_probe(struct net_device *dev)
        int i;
        int base_addr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                return fmv18x_probe1(dev, base_addr);
        else if (base_addr != 0)        /* Don't probe at all. */
@@ -319,8 +321,6 @@ static int net_open(struct net_device *dev)
        /* Enable both Tx and Rx interrupts */
        outw(0x8182, ioaddr+TX_INTR);
 
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -569,8 +569,6 @@ static int net_close(struct net_device *dev)
        /* Power-down the chip.  Green, green, green! */
        outb(0x00, ioaddr + CONFIG_1);
 
-       MOD_DEC_USE_COUNT;
-
        /* Set the ethernet adaptor disable IRQ */
        outb(0x00, ioaddr + FJ_CONFIG1);
 
index dda42edd84bb7ea7d72b08247fe35e08c6bd11b0..d4b8e8e37a4454ff2f9529e00761a5cf926cf0e4 100644 (file)
@@ -580,6 +580,7 @@ static int __init hamachi_init_one (struct pci_dev *pdev,
                iounmap((char *)ioaddr);
                return -ENOMEM;
        }
+       SET_MODULE_OWNER(dev);
 
 #ifdef TX_CHECKSUM
        printk("check that skbcopy in ip_queue_xmit isn't happening\n");
@@ -787,12 +788,9 @@ static int hamachi_open(struct net_device *dev)
        u_int32_t rx_int_var, tx_int_var;
        u_int16_t fifo_info;
 
-       MOD_INC_USE_COUNT;
-
-       if (request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EAGAIN;
-       }
+       i = request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev);
+       if (i)
+               return i;
 
        if (hamachi_debug > 1)
                printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n",
@@ -1754,8 +1752,6 @@ static int hamachi_close(struct net_device *dev)
 
        writeb(0x00, ioaddr + LEDCtrl);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 263ae384e083254f5a5664833aa0ec207d224f5e..0e41265fe96fa2660903b74a7f212ebb9a0b4493 100644 (file)
@@ -1023,7 +1023,8 @@ static int epp_open(struct net_device *dev)
        struct baycom_state *bc;
         struct parport *pp;
        const struct tq_struct run_bh = {
-               0, 0, (void *)(void *)epp_bh, dev
+               routine: (void *)(void *)epp_bh,
+               data: dev
        };
        unsigned int i, j;
        unsigned char tmp[128];
index 9ccc0d1b4d2cbbff19095f05c25932107db1fafb..3ec7b1c1d9f256808022a9a2915e77d9a6450d6d 100644 (file)
@@ -287,7 +287,7 @@ void hdlcdrv_receiver(struct net_device *dev, struct hdlcdrv_state *s)
 
 /* ---------------------------------------------------------------------- */
 
-static void inline do_kiss_params(struct hdlcdrv_state *s,
+static inline void do_kiss_params(struct hdlcdrv_state *s,
                                  unsigned char *data, unsigned long len)
 {
 
@@ -889,14 +889,7 @@ EXPORT_SYMBOL(hdlcdrv_unregister_hdlcdrv);
 
 /* --------------------------------------------------------------------- */
 
-#ifdef MODULE
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
-
-/* --------------------------------------------------------------------- */
-
-int __init init_module(void)
+static int __init hdlcdrv_init_driver(void)
 {
        printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n");
        printk(KERN_INFO "hdlcdrv: version 0.8 compiled " __TIME__ " " __DATE__ "\n");
@@ -905,10 +898,16 @@ int __init init_module(void)
 
 /* --------------------------------------------------------------------- */
 
-void cleanup_module(void)
+static void __exit hdlcdrv_cleanup_driver(void)
 {
        printk(KERN_INFO "hdlcdrv: cleanup\n");
 }
 
-#endif /* MODULE */
+/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
+MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
+module_init(hdlcdrv_init_driver);
+module_exit(hdlcdrv_cleanup_driver);
+
 /* --------------------------------------------------------------------- */
index 68fb88261a4419e80e952715bd08ac3a014e17f4..9dbade4275b2cc42fdd9d476cfe14cbb54e91ee2 100644 (file)
@@ -120,7 +120,9 @@ static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hd
 int __init hp_plus_probe(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                return hpp_probe1(dev, base_addr);
@@ -270,7 +272,6 @@ hpp_open(struct net_device *dev)
        outw(Perf_Page, ioaddr + HP_PAGING);
 
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -285,7 +286,6 @@ hpp_close(struct net_device *dev)
        outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
                 ioaddr + HPP_OPTION);
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -402,17 +402,9 @@ hpp_mem_block_output(struct net_device *dev, int count,
 \f
 #ifdef MODULE
 #define MAX_HPP_CARDS  4       /* Max number of HPP cards per module */
-static struct net_device dev_hpp[MAX_HPP_CARDS] = {
-       {
-               "",
-               0, 0, 0, 0,
-               0, 0,
-               0, 0, 0, NULL, NULL
-       },
-};
-
-static int io[MAX_HPP_CARDS] = { 0, };
-static int irq[MAX_HPP_CARDS]  = { 0, };
+static struct net_device dev_hpp[MAX_HPP_CARDS];
+static int io[MAX_HPP_CARDS];
+static int irq[MAX_HPP_CARDS];
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
index 26b92b8c62c7c7dbbb87cb37878bb1c11547e803..60b723bfadee7399fd0a003631b0847d0b1c81e7 100644 (file)
@@ -57,7 +57,7 @@ static unsigned int hppclan_portlist[] __initdata =
 #define HP_16BSTOP_PG  0xFF    /* Same, for 16 bit cards. */
 
 int hp_probe(struct net_device *dev);
-int hp_probe1(struct net_device *dev, int ioaddr);
+static int hp_probe1(struct net_device *dev, int ioaddr);
 
 static int hp_open(struct net_device *dev);
 static int hp_close(struct net_device *dev);
@@ -83,7 +83,9 @@ static char irqmap[16] __initdata= { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0}
 int __init hp_probe(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                return hp_probe1(dev, base_addr);
@@ -97,14 +99,14 @@ int __init hp_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-int __init hp_probe1(struct net_device *dev, int ioaddr)
+static int __init hp_probe1(struct net_device *dev, int ioaddr)
 {
        int i, retval, board_id, wordmode;
        const char *name;
        static unsigned version_printed;
 
        if (!request_region(ioaddr, HP_IO_EXTENT, dev->name))
-               return -ENODEV;
+               return -EBUSY;
 
        /* Check for the HP physical address, 08 00 09 xx xx xx. */
        /* This really isn't good enough: we may pick up HP LANCE boards
@@ -206,7 +208,6 @@ static int
 hp_open(struct net_device *dev)
 {
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -214,7 +215,6 @@ static int
 hp_close(struct net_device *dev)
 {
        ei_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -373,17 +373,9 @@ hp_init_card(struct net_device *dev)
 
 #ifdef MODULE
 #define MAX_HP_CARDS   4       /* Max number of HP cards per module */
-static struct net_device dev_hp[MAX_HP_CARDS] = {
-       {
-               "",
-               0, 0, 0, 0,
-               0, 0,
-               0, 0, 0, NULL, NULL
-       },
-};
-
-static int io[MAX_HP_CARDS] = { 0, };
-static int irq[MAX_HP_CARDS]  = { 0, };
+static struct net_device dev_hp[MAX_HP_CARDS];
+static int io[MAX_HP_CARDS];
+static int irq[MAX_HP_CARDS];
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
index 74938f954f8cf26c5864a42f0ca6166315e91897..6a052e543fd5300f49b0a1cfdf1140061ce7c1c8 100644 (file)
@@ -274,6 +274,17 @@ static struct hp100_pci_id hp100_pci_ids[] = {
 
 #define HP100_PCI_IDS_SIZE     (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id))
 
+#if LINUX_VERSION_CODE >= 0x20400
+static struct pci_device_id hp100_pci_tbl[] __initdata = {
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID, },
+       { }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, hp100_pci_tbl);
+#endif /* LINUX_VERSION_CODE >= 0x20400 */
+
 static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
 static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
 static int hp100_mode = 1;
@@ -761,6 +772,7 @@ static int __init hp100_probe1( struct net_device *dev, int ioaddr, u_char bus,
   /* Reset statistics (counters) */
   hp100_clear_stats( lp, ioaddr );
 
+  SET_MODULE_OWNER(dev);
   ether_setup( dev );
 
   /* If busmaster mode is wanted, a dma-capable memory area is needed for
@@ -1154,8 +1166,6 @@ static int hp100_open( struct net_device *dev )
       return -EAGAIN;
     }
 
-  MOD_INC_USE_COUNT;
-
   dev->trans_start = jiffies;
   netif_start_queue(dev);
 
@@ -1201,7 +1211,6 @@ static int hp100_close( struct net_device *dev )
   printk( "hp100: %s: close LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) );
 #endif
 
-  MOD_DEC_USE_COUNT;
   return 0;
 }
 
index 8f05bb5a0426713138930bde30873f0d949cb463..5f2052feb5392e67e4395de8b475bb51310d0ca0 100644 (file)
@@ -87,9 +87,7 @@ History:
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-#ifdef MODULE
 #include <linux/module.h>
-#endif
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -877,9 +875,6 @@ static int ibmlana_open(struct IBMLANA_NETDEV *dev)
        dev->interrupt = 0;
        dev->tbusy = 0;
        dev->start = 1;
-#endif
-
-#ifdef MODULE
        MOD_INC_USE_COUNT;
 #endif
 
@@ -897,7 +892,7 @@ static int ibmlana_close(struct IBMLANA_NETDEV *dev)
                free_irq(dev->irq, dev);
        dev->irq = 0;
 
-#ifdef MODULE
+#if (LINUX_VERSION_CODE < 0x02032a)
        MOD_DEC_USE_COUNT;
 #endif
 
@@ -1043,6 +1038,10 @@ int ibmlana_probe(struct IBMLANA_NETDEV *dev)
        ibmlana_priv *priv;
        ibmlana_medium medium;
 
+#if (LINUX_VERSION_CODE >= 0x02032a)
+       SET_MODULE_OWNER(dev);
+#endif
+
        /* can't work without an MCA bus ;-) */
 
        if (MCA_bus == 0)
@@ -1192,14 +1191,11 @@ int ibmlana_probe(struct IBMLANA_NETDEV *dev)
 
 #define DEVMAX 5
 
-static struct IBMLANA_NETDEV moddevs[DEVMAX] = {
-       { init: ibmlana_probe }, { init: ibmlana_probe }, 
-       { init: ibmlana_probe }, { init: ibmlana_probe },
-       { init: ibmlana_probe }
-};
-
-int irq = 0;
-int io = 0;
+static struct IBMLANA_NETDEV moddevs[DEVMAX];
+static int irq;
+static int io;
+MODULE_PARM(irq, "i");
+MODULE_PARM(io, "i");
 
 int init_module(void)
 {
@@ -1207,7 +1203,9 @@ int init_module(void)
 
        startslot = 0;
        for (z = 0; z < DEVMAX; z++) {
-               strcpy(moddevs[z].name, "     ");
+               moddevs[z].init = ibmlana_probe;
+               moddevs[z].irq = irq;
+               moddevs[z].base_addr = io;
                res = register_netdev(moddevs + z);
                if (res != 0)
                        return (z > 0) ? 0 : -EIO;
index c39defcd35f54e4d90a39563fcbda5e851a23e38..99093299c4afa518a75a61a5aa7efe5970ff9bd5 100644 (file)
@@ -121,8 +121,8 @@ static void     net_tx_timeout(struct net_device *dev);
 
 /* Example routines you must write ;->. */
 #define tx_done(dev) 1
-extern void    hardware_send_packet(short ioaddr, char *buf, int length);
-extern void    chipset_init(struct net_device *dev, int startp);
+static void    hardware_send_packet(short ioaddr, char *buf, int length);
+static void    chipset_init(struct net_device *dev, int startp);
 
 /*
  * Check for a network adaptor of this type, and return '0' iff one exists.
@@ -135,7 +135,9 @@ int __init
 netcard_probe(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        if (base_addr > 0x1ff)    /* Check a single specified location. */
                return netcard_probe1(dev, base_addr);
@@ -360,8 +362,6 @@ net_open(struct net_device *dev)
         */
        netif_start_queue(dev);
 
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -574,8 +574,6 @@ net_close(struct net_device *dev)
 
        /* Update the statistics here. */
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 
 }
@@ -589,11 +587,8 @@ static struct net_device_stats *net_get_stats(struct net_device *dev)
        struct net_local *lp = (struct net_local *)dev->priv;
        short ioaddr = dev->base_addr;
 
-       cli();
        /* Update the statistics from the device registers. */
        lp->stats.rx_missed_errors = inw(ioaddr+1);
-       sti();
-
        return &lp->stats;
 }
 
@@ -633,7 +628,7 @@ set_multicast_list(struct net_device *dev)
 
 #ifdef MODULE
 
-static struct net_device this_device = { init: netcard_probe };
+static struct net_device this_device;
 static int io = 0x300;
 static int irq;
 static int dma;
@@ -652,6 +647,7 @@ int init_module(void)
        this_device.irq       = irq;
        this_device.dma       = dma;
        this_device.mem_start = mem;
+       this_device.init      = netcard_probe;
 
        if ((result = register_netdev(&this_device)) != 0)
                return result;
index d524b5ef607d5777db1c16ffeac538cdcf4f391d..59ce4f9b7b5497f6e5ae9da98a5840d58ce4a51c 100644 (file)
@@ -50,7 +50,7 @@ static const char *version =
 #include "8390.h"
 
 int lne390_probe(struct net_device *dev);
-int lne390_probe1(struct net_device *dev, int ioaddr);
+static int lne390_probe1(struct net_device *dev, int ioaddr);
 
 static int lne390_open(struct net_device *dev);
 static int lne390_close(struct net_device *dev);
@@ -108,8 +108,10 @@ int __init lne390_probe(struct net_device *dev)
        unsigned short ioaddr = dev->base_addr;
        int ret;
 
+       SET_MODULE_OWNER(dev);
+
        if (ioaddr > 0x1ff) {           /* Check a single specified location. */
-               if (!request_region(ioaddr, LNE390_IO_EXTENT, "lne390"))
+               if (!request_region(ioaddr, LNE390_IO_EXTENT, dev->name))
                        return -EBUSY;
                ret = lne390_probe1(dev, ioaddr);
                if (ret)
@@ -128,7 +130,7 @@ int __init lne390_probe(struct net_device *dev)
 
        /* EISA spec allows for up to 16 slots, but 8 is typical. */
        for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-               if (!request_region(ioaddr, LNE390_IO_EXTENT, "lne390"))
+               if (!request_region(ioaddr, LNE390_IO_EXTENT, dev->name))
                        continue;
                if (lne390_probe1(dev, ioaddr) == 0)
                        return 0;
@@ -138,7 +140,7 @@ int __init lne390_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-int __init lne390_probe1(struct net_device *dev, int ioaddr)
+static int __init lne390_probe1(struct net_device *dev, int ioaddr)
 {
        int i, revision, ret;
        unsigned long eisa_id;
@@ -195,11 +197,11 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr)
        }
        printk(" IRQ %d,", dev->irq);
 
-       if (request_irq(dev->irq, ei_interrupt, 0, "lne390", dev)) {
+       if ((ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
                printk (" unable to get IRQ %d.\n", dev->irq);
                kfree(dev->priv);
                dev->priv = NULL;
-               return -EAGAIN;
+               return ret;
        }
 
        if (dev->mem_start == 0) {
@@ -356,7 +358,6 @@ static void lne390_block_output(struct net_device *dev, int count,
 static int lne390_open(struct net_device *dev)
 {
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -367,21 +368,12 @@ static int lne390_close(struct net_device *dev)
                printk("%s: Shutting down ethercard.\n", dev->name);
 
        ei_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
 #ifdef MODULE
 #define MAX_LNE_CARDS  4       /* Max number of LNE390 cards per module */
-static struct net_device dev_lne[MAX_LNE_CARDS] = {
-       {
-               "",
-               0, 0, 0, 0,
-               0, 0,
-               0, 0, 0, NULL, NULL
-       },
-};
-
+static struct net_device dev_lne[MAX_LNE_CARDS];
 static int io[MAX_LNE_CARDS];
 static int irq[MAX_LNE_CARDS];
 static int mem[MAX_LNE_CARDS];
index fd6744284a1288c98a53b37ce3048695db941ce3..1d2d4c47b3f0966df10f8d1b267f927568770660 100644 (file)
@@ -79,9 +79,11 @@ int __init mvme147lance_probe(struct net_device *dev)
        u_long address;
 
        if (!MACH_IS_MVME147 || called)
-               return(ENODEV);
+               return(-ENODEV);
        called++;
 
+       SET_MODULE_OWNER(dev);
+
        dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL);
        if (dev->priv == NULL)
                return -ENOMEM;
@@ -173,7 +175,6 @@ static int m147lance_open(struct net_device *dev)
        m147_pcc->lan_cntrl=0;       /* clear the interrupts (if any) */
        m147_pcc->lan_cntrl=0x08 | 0x04;     /* Enable irq 4 */
 
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -182,7 +183,6 @@ static int m147lance_close(struct net_device *dev)
        /* disable interrupts at boardlevel */
        m147_pcc->lan_cntrl=0x0; /* disable interrupts */
        lance_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index 254b42880b40f12130dcf6d94b80c88fa373b9c5..34d050f712f7a5743077c85382c800f346ba9c6b 100644 (file)
@@ -386,6 +386,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        dev = init_etherdev(NULL, sizeof (struct netdev_private));
        if (!dev)
                return -ENOMEM;
+       SET_MODULE_OWNER(dev);
 
        {
                void *mmio;
@@ -559,12 +560,8 @@ static int netdev_open(struct net_device *dev)
 
        /* Do we need to reset the chip??? */
 
-       MOD_INC_USE_COUNT;
-
-       if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EAGAIN;
-       }
+       i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+       if (i) return i;
 
        if (debug > 1)
                printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
@@ -1179,8 +1176,6 @@ static int netdev_close(struct net_device *dev)
        writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */
 #endif
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 976dd578120a35bea20f4e00f54b5815c9976898..70004107f45c51c9bf0ba01517484deea8b9c3cf 100644 (file)
@@ -483,7 +483,7 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
     printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
 
     ioaddr = pci_resource_start (pdev, 0);
-    printk(KERN_INFO "  ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
+    printk(KERN_INFO "    ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
     if (!ioaddr) {
         printk (KERN_ERR "no PCI IO resources, aborting\n");
         return -ENODEV;
@@ -627,29 +627,29 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
     /* There is a 16 byte station address PROM at the base address.
        The first six bytes are the station address. */
     for (i = 0; i < 6; i++)
-       printk( KERN_INFO " %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+       printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
     if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
        i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
-       printk(KERN_INFO"\n    tx_start_pt(0x%04x):",i);
+       printk("\n" KERN_INFO "    tx_start_pt(0x%04x):",i);
        switch(i>>10) {
-           case 0: printk(KERN_INFO "  20 bytes,"); break;
-           case 1: printk(KERN_INFO "  64 bytes,"); break;
-           case 2: printk(KERN_INFO " 128 bytes,"); break;
-           case 3: printk(KERN_INFO "~220 bytes,"); break;
+           case 0: printk("  20 bytes,"); break;
+           case 1: printk("  64 bytes,"); break;
+           case 2: printk(" 128 bytes,"); break;
+           case 3: printk("~220 bytes,"); break;
        }
        i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
-       printk(KERN_INFO" BCR18(%x):",i&0xffff);
-       if (i & (1<<5)) printk(KERN_INFO "BurstWrEn ");
-       if (i & (1<<6)) printk(KERN_INFO "BurstRdEn ");
-       if (i & (1<<7)) printk(KERN_INFO "DWordIO ");
-       if (i & (1<<11)) printk(KERN_INFO"NoUFlow ");
+       printk(" BCR18(%x):",i&0xffff);
+       if (i & (1<<5)) printk("BurstWrEn ");
+       if (i & (1<<6)) printk("BurstRdEn ");
+       if (i & (1<<7)) printk("DWordIO ");
+       if (i & (1<<11)) printk("NoUFlow ");
        i = a->read_bcr(ioaddr, 25);
-       printk(KERN_INFO "\n    SRAMSIZE=0x%04x,",i<<8);
+       printk("\n" KERN_INFO "    SRAMSIZE=0x%04x,",i<<8);
        i = a->read_bcr(ioaddr, 26);
-       printk(KERN_INFO " SRAM_BND=0x%04x,",i<<8);
+       printk(" SRAM_BND=0x%04x,",i<<8);
        i = a->read_bcr(ioaddr, 27);
-       if (i & (1<<14)) printk(KERN_INFO "LowLatRx,");
+       if (i & (1<<14)) printk("LowLatRx");
     }
 
     dev->base_addr = ioaddr;
@@ -662,7 +662,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
     memset(lp, 0, sizeof(*lp));
     lp->dma_addr = lp_dma_addr;
     lp->pci_dev = pdev;
-    printk(KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x\n", lp, lp_dma_addr);
+    printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr);
 
     spin_lock_init(&lp->lock);
     
@@ -713,7 +713,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
     }
     
     if (dev->irq >= 2)
-       printk(KERN_INFO " assigned IRQ %d.\n", dev->irq);
+       printk(" assigned IRQ %d.\n", dev->irq);
     else {
        unsigned long irq_mask = probe_irq_on();
        
@@ -728,9 +728,9 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
        
        dev->irq = probe_irq_off (irq_mask);
        if (dev->irq)
-           printk(KERN_INFO ", probed IRQ %d.\n", dev->irq);
+           printk(", probed IRQ %d.\n", dev->irq);
        else {
-           printk(KERN_ERR ", failed to detect IRQ line.\n");
+           printk(", failed to detect IRQ line.\n");
            return -ENODEV;
        }
     }
@@ -978,14 +978,14 @@ pcnet32_tx_timeout (struct net_device *dev)
               lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
               lp->cur_rx);
            for (i = 0 ; i < RX_RING_SIZE; i++)
-           printk(KERN_DEBUG "%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+           printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
                   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
                   lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
            for (i = 0 ; i < TX_RING_SIZE; i++)
-           printk(KERN_DEBUG "%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+           printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
                   lp->tx_ring[i].base, -lp->tx_ring[i].length,
                   lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
-           printk(KERN_DEBUG "\n");
+           printk("\n");
        }
        pcnet32_restart(dev, 0x0042);
 
index 43c0e7bcdb4e0fbc8fbf7044d2228697c6056919..61cdd84d60d783624d082055705456ca4e70c50a 100644 (file)
@@ -349,18 +349,18 @@ plip_init_dev(struct net_device *dev, struct parport *pb)
        nl->nibble      = PLIP_NIBBLE_WAIT;
 
        /* Initialize task queue structures */
-       nl->immediate.next = NULL;
+       INIT_LIST_HEAD(&nl->immediate.list);
        nl->immediate.sync = 0;
        nl->immediate.routine = (void (*)(void *))plip_bh;
        nl->immediate.data = dev;
 
-       nl->deferred.next = NULL;
+       INIT_LIST_HEAD(&nl->deferred.list);
        nl->deferred.sync = 0;
        nl->deferred.routine = (void (*)(void *))plip_kick_bh;
        nl->deferred.data = dev;
 
        if (dev->irq == -1) {
-               nl->timer.next = NULL;
+               INIT_LIST_HEAD(&nl->timer.list);
                nl->timer.sync = 0;
                nl->timer.routine = (void (*)(void *))plip_timer_bh;
                nl->timer.data = dev;
index feb72365193f7bdb0c1e1eb6bdf444bf7176d6f8..8744f618645779e4d178aa44e54f6a8da3dbd094 100644 (file)
@@ -785,8 +785,7 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
        skb_reserve(skb, dev->hard_header_len);
        skb->nh.raw = skb->data;
 
-       skb->rx_dev = skb->dev = dev;
-       dev_hold(skb->rx_dev);
+       skb->dev = dev;
 
        skb->priority = sk->priority;
        skb->protocol = __constant_htons(ETH_P_PPP_SES);
@@ -869,11 +868,7 @@ int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
 
        skb->nh.raw = skb->data;
 
-       /* Change device of skb, update reference counts */
-       if(skb->rx_dev)
-           dev_put(skb->rx_dev);
-       skb->rx_dev = skb->dev = dev;
-       dev_hold(skb->rx_dev);
+       skb->dev = dev;
 
        dev->hard_header(skb, dev, ETH_P_PPP_SES,
                         sk->protinfo.pppox->pppoe_pa.remote,
index 2721cb05e9e2101586037e455af7f43de46e2fa6..1a5f13672b7505e32e65c91b0f8d3c5cd33df343 100644 (file)
@@ -1561,7 +1561,7 @@ RC_RETURN
 RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
 {
     unsigned long off;
-    unsigned long *pMsg;
+    PU32 pMsg;
     PPAB pPab;
     int i;
     long timeout = 0;
index 793af1577f8b68a15ba44d4f005ac547d9ce312c..95a7c864e51f15df4eb6db4a728ac80a331ece2f 100644 (file)
@@ -210,6 +210,9 @@ sb1000_probe(struct net_device *dev)
                                dev->rmem_end, serial_number, dev->irq);
 
                dev = init_etherdev(dev, 0);
+               if (!dev)
+                       return -ENOMEM;
+               SET_MODULE_OWNER(dev);
 
                /* Make up a SB1000-specific-data structure. */
                dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL);
@@ -1004,7 +1007,6 @@ sb1000_open(struct net_device *dev)
 
 
        netif_start_queue(dev);
-       MOD_INC_USE_COUNT;
        return 0;                                       /* Always succeed */
 }
 
@@ -1195,7 +1197,6 @@ static int sb1000_close(struct net_device *dev)
                        dev_kfree_skb(lp->rx_skb[i]);
                }
        }
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1205,14 +1206,9 @@ MODULE_DESCRIPTION("General Instruments SB1000 driver");
 MODULE_PARM(io, "1-2i");
 MODULE_PARM(irq, "i");
 
-static struct net_device dev_sb1000 = {
-        "",
-        0, 0, 0, 0,
-        0, 0,
-        0, 0, 0, NULL, sb1000_probe };
-
-static int io[2]  = {0, 0};
-static int irq = 0;
+static struct net_device dev_sb1000;
+static int io[2];
+static int irq;
 
 int
 init_module(void)
@@ -1226,6 +1222,7 @@ init_module(void)
                printk(KERN_ERR "sb1000: can't register any device cm<n>\n");
                return -ENFILE;
        }
+       dev_sb1000.init = sb1000_probe;
        dev_sb1000.base_addr = io[0];
        /* rmem_end holds the second I/O address - fv */
        dev_sb1000.rmem_end = io[1];
index a8c9e5e46ff5bf5a8b6a3351542baa2b033482de..823836cbbee8f66a01b63339eb587202eda38c3f 100644 (file)
@@ -31,9 +31,7 @@ extern int sdla_c_setup(void);
 extern int comx_init(void);
 extern int lmc_setup(void);
 
-extern int abyss_probe(void);
 extern int madgemc_probe(void);
-extern int tms_pci_probe(void);
 
 /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
 #define __PAD6 "\0\0\0\0\0\0\0\0\0"
@@ -115,16 +113,9 @@ struct net_probe pci_probes[] __initdata = {
 /*
  *     Token Ring Drivers
  */  
-#ifdef CONFIG_ABYSS
-       {abyss_probe, 0},
-#endif
 #ifdef CONFIG_MADGEMC
        {madgemc_probe, 0},
 #endif
-#ifdef CONFIG_TMSPCI
-       {tms_pci_probe, 0},
-#endif
        {NULL, 0},
 };
 
index cc0eae2140eea3bfb2375eb2f19369020ad19139..72949ff74fa2608214e970122f9c7330056f3d26 100644 (file)
@@ -241,6 +241,7 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev
        net_dev = init_etherdev(NULL, sizeof(struct sis900_private));
        if (!net_dev)
                return -ENOMEM;
+       SET_MODULE_OWNER(net_dev);
 
        if (!request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name)) {
                printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%lX\n", ioaddr);
@@ -530,8 +531,7 @@ sis900_open(struct net_device *net_dev)
        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
        long ioaddr = net_dev->base_addr;
        u8  revision;
-
-       MOD_INC_USE_COUNT;
+       int ret;
 
        /* Soft reset the chip. */
        sis900_reset(net_dev);
@@ -541,10 +541,9 @@ sis900_open(struct net_device *net_dev)
        if (revision == SIS630E_REV || revision == SIS630EA1_REV)
                sis630e_set_eq(net_dev);
 
-       if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EAGAIN;
-       }
+       ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev);
+       if (ret)
+               return ret;
 
        sis900_init_rxfilter(net_dev);
 
@@ -1279,8 +1278,6 @@ sis900_close(struct net_device *net_dev)
 
        /* Green! Put the chip in low-power mode. */
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 51688271ac6e3a657c4dc95ac185c073736c0714..49823291a751026f22802953b29eb75679e36f7a 100644 (file)
@@ -879,9 +879,6 @@ static int skmca_open(struct SKMCA_NETDEV *dev)
        dev->interrupt = 0;
        dev->tbusy = 0;
        dev->start = 0;
-#endif
-
-#ifdef MODULE
        MOD_INC_USE_COUNT;
 #endif
 
@@ -900,7 +897,7 @@ static int skmca_close(struct SKMCA_NETDEV *dev)
                free_irq(dev->irq, dev);
        dev->irq = 0;
 
-#ifdef MODULE
+#if (LINUX_VERSION_CODE < 0x02032a)
        MOD_DEC_USE_COUNT;
 #endif
 
@@ -1087,6 +1084,8 @@ int skmca_probe(struct SKMCA_NETDEV *dev)
        if (MCA_bus == 0)
                return -ENODEV;
 
+       SET_MODULE_OWNER(dev);
+
        /* start address of 1 --> forced detection */
 
        if (dev->mem_start == 1)
index af2050833a5471f814d82828d4b2ed922810fcf2..2b5fb3fc410d1115edf0036681db025a452b0ee6 100644 (file)
@@ -91,7 +91,7 @@ struct smc_mca_adapters_t {
        char *name;
 };
 
-const struct smc_mca_adapters_t smc_mca_adapters[] = {
+static const struct smc_mca_adapters_t smc_mca_adapters[] = {
     { 0x61c8, "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)" },
     { 0x61c9, "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)" },
     { 0x6fc0, "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)" },
@@ -114,13 +114,15 @@ int __init ultramca_probe(struct net_device *dev)
        int adapter = 0;
        int tbase = 0;
        int tirq = 0;
-       int base_addr = dev ? dev->base_addr : 0;
-       int irq = dev ? dev->irq : 0;
+       int base_addr = dev->base_addr;
+       int irq = dev->irq;
 
        if (!MCA_bus) {
                return -ENODEV;
        }
 
+       SET_MODULE_OWNER(dev);
+
        if (base_addr || irq) {
                printk(KERN_INFO "Probing for SMC MCA adapter");
                if (base_addr) {
@@ -340,7 +342,6 @@ static int ultramca_open(struct net_device *dev)
         */
 
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -424,8 +425,6 @@ static int ultramca_close_card(struct net_device *dev)
          * "just in case"...
         */
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
@@ -435,18 +434,9 @@ static int ultramca_close_card(struct net_device *dev)
 
 #define MAX_ULTRAMCA_CARDS 4   /* Max number of Ultra cards per module */
 
-static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS] =
-{
-       {
-               "",
-               0, 0, 0, 0,
-               0, 0,
-               0, 0, 0, NULL, NULL
-       },
-};
-
-static int io[MAX_ULTRAMCA_CARDS] = { 0, };
-static int irq[MAX_ULTRAMCA_CARDS]  = { 0, };
+static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS];
+static int io[MAX_ULTRAMCA_CARDS];
+static int irq[MAX_ULTRAMCA_CARDS];
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
index 5e7c7aeae2bb563feddd791516d5fcc5ffad9cb3..ebd3ab2b7b388c21f39f1e67198c1c371efad9e2 100644 (file)
@@ -105,7 +105,9 @@ static int ultra_close_card(struct net_device *dev);
 int __init ultra_probe(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                return ultra_probe1(dev, base_addr);
@@ -272,7 +274,6 @@ ultra_open(struct net_device *dev)
        outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
        outb(0xff, dev->base_addr + EN0_ERWCNT);
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -412,8 +413,6 @@ ultra_close_card(struct net_device *dev)
        /* We should someday disable shared memory and change to 8-bit mode
           "just in case"... */
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index ba387049ce94bcd5c54f7e5a14d987a67eec65c3..3978433b5112ae7311557379d15a8b9fd1f57b0f 100644 (file)
@@ -61,7 +61,7 @@ static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
 #include "8390.h"
 
 int ultra32_probe(struct net_device *dev);
-int ultra32_probe1(struct net_device *dev, int ioaddr);
+static int ultra32_probe1(struct net_device *dev, int ioaddr);
 static int ultra32_open(struct net_device *dev);
 static void ultra32_reset_8390(struct net_device *dev);
 static void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
@@ -105,48 +105,64 @@ static int ultra32_close(struct net_device *dev);
 
 int __init ultra32_probe(struct net_device *dev)
 {
-       const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
-       int ioaddr, edge, media;
+       int ioaddr;
 
        if (!EISA_bus) return -ENODEV;
 
+       SET_MODULE_OWNER(dev);
+
        /* EISA spec allows for up to 16 slots, but 8 is typical. */
        for (ioaddr = 0x1000 + ULTRA32_BASE; ioaddr < 0x9000; ioaddr += 0x1000)
-       if (check_region(ioaddr, ULTRA32_IO_EXTENT) == 0 &&
-           inb(ioaddr + ULTRA32_IDPORT) != 0xff &&
-           inl(ioaddr + ULTRA32_IDPORT) == ULTRA32_ID) {
-               media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
-               edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
-               printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
-                      ioaddr >> 12, ifmap[media],
-                      (edge ? "Edge Triggered" : "Level Sensitive"));
                if (ultra32_probe1(dev, ioaddr) == 0)
-                 return 0;
-       }
+                       return 0;
+
        return -ENODEV;
 }
 
-int __init ultra32_probe1(struct net_device *dev, int ioaddr)
+static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
 {
-       int i;
+       int i, edge, media, retval;
        int checksum = 0;
        const char *model_name;
-       static unsigned version_printed = 0;
+       static unsigned version_printed;
        /* Values from various config regs. */
-       unsigned char idreg = inb(ioaddr + 7);
-       unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
+       unsigned char idreg;
+       unsigned char reg4;
+       const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
+
+       if (!request_region(ioaddr, ULTRA32_IO_EXTENT, dev->name))
+               return -EBUSY;
+
+       if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
+           inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
+       edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
+       printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
+               ioaddr >> 12, ifmap[media],
+               (edge ? "Edge Triggered" : "Level Sensitive"));
+
+       idreg = inb(ioaddr + 7);
+       reg4 = inb(ioaddr + 4) & 0x7f;
 
        /* Check the ID nibble. */
-       if ((idreg & 0xf0) != 0x20)                     /* SMC Ultra */
-               return -ENODEV;
+       if ((idreg & 0xf0) != 0x20) {                   /* SMC Ultra */
+               retval = -ENODEV;
+               goto out;
+       }
 
        /* Select the station address register set. */
        outb(reg4, ioaddr + 4);
 
        for (i = 0; i < 8; i++)
                checksum += inb(ioaddr + 8 + i);
-       if ((checksum & 0xff) != 0xff)
-               return -ENODEV;
+       if ((checksum & 0xff) != 0xff) {
+               retval = -ENODEV;
+               goto out;
+       }
 
        if (ei_debug  &&  version_printed++ == 0)
                printk(version);
@@ -175,7 +191,8 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
        if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) {
                printk("\nsmc-ultra32: Card RAM is disabled!  "
                       "Run EISA config utility.\n");
-               return -ENODEV;
+               retval = -ENODEV;
+               goto out;
        }
        if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0)
                printk("\nsmc-ultra32: Ignoring Bus-Master enable bit.  "
@@ -186,7 +203,8 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
                int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07];
                if (irq == 0) {
                        printk(", failed to detect IRQ line.\n");
-                       return -EAGAIN;
+                       retval = -EAGAIN;
+                       goto out;
                }
                dev->irq = irq;
        }
@@ -194,12 +212,10 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        if (ethdev_init(dev)) {
                printk (", no memory for dev->priv.\n");
-                return -ENOMEM;
+                retval = -ENOMEM;
+               goto out;
         }
 
-       /* OK, we are certain this is going to work.  Setup the device. */
-       request_region(ioaddr, ULTRA32_IO_EXTENT, model_name);
-
        /* The 8390 isn't at the base address, so fake the offset */
        dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET;
 
@@ -229,15 +245,20 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
        NS8390_init(dev, 0);
 
        return 0;
+out:
+       release_region(ioaddr, ULTRA32_IO_EXTENT);
+       return retval;
 }
 
 static int ultra32_open(struct net_device *dev)
 {
        int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
        int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : SA_SHIRQ;
+       int retval;
 
-       if (request_irq(dev->irq, ei_interrupt, irq_flags, ei_status.name, dev))
-               return -EAGAIN;
+       retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
+       if (retval)
+               return retval;
 
        outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
        outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
@@ -248,7 +269,6 @@ static int ultra32_open(struct net_device *dev)
        outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
        outb(0xff, dev->base_addr + EN0_ERWCNT);
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -267,8 +287,6 @@ static int ultra32_close(struct net_device *dev)
 
        NS8390_init(dev, 0);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 201b259f7869d091a1ab39d2ecff26c53bed1c30..199553971104b0be14672754f58edb5dc356ac46 100644 (file)
@@ -256,15 +256,7 @@ inline static void smc_tx( struct net_device * dev );
  . Test if a given location contains a chip, trying to cause as
  . little damage as possible if it's not a SMC chip.
 */
-static int smc_probe( int ioaddr );
-
-/*
- . this routine initializes the cards hardware, prints out the configuration
- . to the system log as well as the vanity message, and handles the setup
- . of a device parameter.
- . It will give an error if it can't initialize the card.
-*/
-static int smc_initcard( struct net_device *, int ioaddr );
+static int smc_probe(struct net_device *dev, int ioaddr);
 
 /*
  . A rather simple routine to print out a packet for debugging purposes.
@@ -714,35 +706,20 @@ static void smc_hardware_send_packet( struct net_device * dev )
 int __init smc_init(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        /*  try a specific location */
-       if (base_addr > 0x1ff)  {
-               int     error;
-               error = smc_probe(base_addr);
-               if ( 0 == error ) {
-                       return smc_initcard( dev, base_addr );
-               }
-               return error;
-       } else {
-               if ( 0 != base_addr ) {
-                       return -ENXIO;
-               }
-       }
+       if (base_addr > 0x1ff)
+               return smc_probe(dev, base_addr);
+       else if (base_addr != 0)
+               return -ENXIO;
 
        /* check every ethernet address */
-       for (i = 0; smc_portlist[i]; i++) {
-               int ioaddr = smc_portlist[i];
-
-               /* check if the area is available */
-               if (check_region( ioaddr , SMC_IO_EXTENT))
-                       continue;
-
-               /* check this specific address */
-               if ( smc_probe( ioaddr ) == 0)  {
-                       return smc_initcard( dev, ioaddr  );
-               }
-       }
+       for (i = 0; smc_portlist[i]; i++)
+               if (smc_probe(dev, smc_portlist[i]) == 0)
+                       return 0;
 
        /* couldn't find anything */
        return -ENODEV;
@@ -837,23 +814,53 @@ int __init smc_findirq( int ioaddr )
  .---------------------------------------------------------------------
  */
 
-static int __init smc_probe( int ioaddr )
+/*---------------------------------------------------------------
+ . Here I do typical initialization tasks.
+ .
+ . o  Initialize the structure if needed
+ . o  print out my vanity message if not done so already
+ . o  print out what type of hardware is detected
+ . o  print out the ethernet address
+ . o  find the IRQ
+ . o  set up my private data
+ . o  configure the dev structure with my subroutines
+ . o  actually GRAB the irq.
+ . o  GRAB the region
+ .-----------------------------------------------------------------
+*/
+static int __init smc_probe(struct net_device *dev, int ioaddr)
 {
-       unsigned int    bank;
-       word    revision_register;
-       word  base_address_register;
+       int i, memory, retval;
+       static unsigned version_printed;
+       unsigned int bank;
+
+       const char *version_string;
+       const char *if_string;
+
+       /* registers */
+       word revision_register;
+       word base_address_register;
+       word configuration_register;
+       word memory_info_register;
+       word memory_cfg_register;
+
+       /* Grab the region so that no one else tries to probe our ioports. */
+       if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))
+               return -EBUSY;
 
        /* First, see if the high byte is 0x33 */
        bank = inw( ioaddr + BANK_SELECT );
        if ( (bank & 0xFF00) != 0x3300 ) {
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_out;
        }
        /* The above MIGHT indicate a device, but I need to write to further
                test this.  */
        outw( 0x0, ioaddr + BANK_SELECT );
        bank = inw( ioaddr + BANK_SELECT );
        if ( (bank & 0xFF00 ) != 0x3300 ) {
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_out;
        }
        /* well, we've already written once, so hopefully another time won't
           hurt.  This time, I need to switch the bank register to bank 1,
@@ -866,7 +873,8 @@ static int __init smc_probe( int ioaddr )
                        ioaddr, base_address_register >> 3 & 0x3E0 );
                /* well, the base address register didn't match.  Must not have
                   been a SMC chip after all. */
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_out;
        }
 
        /*  check if the revision register is something that I recognize.
@@ -879,46 +887,13 @@ static int __init smc_probe( int ioaddr )
                printk(CARDNAME ": IO %x: Unrecognized revision register:"
                        " %x, Contact author. \n", ioaddr, revision_register );
 
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_out;
        }
 
        /* at this point I'll assume that the chip is an SMC9xxx.
           It might be prudent to check a listing of MAC addresses
           against the hardware address, or do some other tests. */
-       return 0;
-}
-
-/*---------------------------------------------------------------
- . Here I do typical initialization tasks.
- .
- . o  Initialize the structure if needed
- . o  print out my vanity message if not done so already
- . o  print out what type of hardware is detected
- . o  print out the ethernet address
- . o  find the IRQ
- . o  set up my private data
- . o  configure the dev structure with my subroutines
- . o  actually GRAB the irq.
- . o  GRAB the region
- .-----------------------------------------------------------------
-*/
-static int __init smc_initcard(struct net_device *dev, int ioaddr)
-{
-       int i;
-
-       static unsigned version_printed = 0;
-
-       /* registers */
-       word    revision_register;
-       word    configuration_register;
-       word    memory_info_register;
-       word    memory_cfg_register;
-
-       const char *    version_string;
-       const char *    if_string;
-       int     memory;
-
-       int   irqval;
 
        if (version_printed++ == 0)
                printk("%s", version);
@@ -956,7 +931,8 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
        version_string = chip_ids[ ( revision_register  >> 4 ) & 0xF  ];
        if ( !version_string ) {
                /* I shouldn't get here because this call was done before.... */
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_out;
        }
 
        /* is it using AUI or 10BaseT ? */
@@ -1003,7 +979,8 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
        }
        if (dev->irq == 0 ) {
                printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n");
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_out;
        }
        if (dev->irq == 2) {
                /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
@@ -1014,7 +991,7 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
 
        /* now, print out the card info, in a short format.. */
 
-       printk(CARDNAME ": %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ",
+       printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name,
                version_string, revision_register & 0xF, ioaddr, dev->irq,
                if_string, memory );
        /*
@@ -1029,8 +1006,10 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
        /* Initialize the private structure. */
        if (dev->priv == NULL) {
                dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL);
-               if (dev->priv == NULL)
-                       return -ENOMEM;
+               if (dev->priv == NULL) {
+                       retval = -ENOMEM;
+                       goto err_out;
+               }
        }
        /* set the private data to zero by default */
        memset(dev->priv, 0, sizeof(struct smc_local));
@@ -1039,16 +1018,15 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
        ether_setup(dev);
 
        /* Grab the IRQ */
-       irqval = request_irq(dev->irq, &smc_interrupt, 0, CARDNAME, dev);
-       if (irqval) {
-                 printk(CARDNAME": unable to get IRQ %d (irqval=%d).\n",
-               dev->irq, irqval);
-                 return -EAGAIN;
+       retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+       if (retval) {
+               printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
+                       dev->irq, retval);
+               kfree(dev->priv);
+               dev->priv = NULL;
+               goto err_out;
        }
 
-       /* Grab the region so that no one else tries to probe our ioports. */
-       request_region(ioaddr, SMC_IO_EXTENT, CARDNAME);
-
        dev->open                       = smc_open;
        dev->stop                       = smc_close;
        dev->hard_start_xmit            = smc_wait_to_send_packet;
@@ -1058,6 +1036,10 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
        dev->set_multicast_list         = smc_set_multicast_list;
 
        return 0;
+
+err_out:
+       release_region(ioaddr, SMC_IO_EXTENT);
+       return retval;
 }
 
 #if SMC_DEBUG > 2
@@ -1112,8 +1094,6 @@ static int smc_open(struct net_device *dev)
        /* clear out all the junk that was put here before... */
        memset(dev->priv, 0, sizeof(struct smc_local));
 
-       MOD_INC_USE_COUNT;
-
        /* reset the hardware */
 
        smc_reset( ioaddr );
@@ -1504,7 +1484,6 @@ static int smc_close(struct net_device *dev)
        smc_shutdown( dev->base_addr );
 
        /* Update the statistics here. */
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1577,8 +1556,7 @@ static void smc_set_multicast_list(struct net_device *dev)
 
 #ifdef MODULE
 
-static struct net_device devSMC9194 = { init: smc_init };
-
+static struct net_device devSMC9194;
 static int io;
 static int irq;
 static int ifport;
@@ -1599,6 +1577,7 @@ int init_module(void)
        devSMC9194.base_addr = io;
        devSMC9194.irq       = irq;
        devSMC9194.if_port      = ifport;
+       devSMC9194.init         = smc_init;
        if ((result = register_netdev(&devSMC9194)) != 0)
                return result;
 
index a6535df79f3f7cf6d1ff3c86ca48f23100e358ba..08527049431971f471604129d1d835c622ecfdbb 100644 (file)
@@ -390,6 +390,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
        dev = init_etherdev(NULL, sizeof(*np));
        if (!dev)
                return -ENOMEM;
+       SET_MODULE_OWNER(dev);
 
 #ifdef USE_IO_OPS
        ioaddr = pci_resource_start(pdev, 0);
@@ -609,12 +610,9 @@ static int netdev_open(struct net_device *dev)
 
        /* Do we need to reset the chip??? */
 
-       MOD_INC_USE_COUNT;
-
-       if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EAGAIN;
-       }
+       i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+       if (i)
+               return i;
 
        if (debug > 1)
                printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
@@ -1224,8 +1222,6 @@ static int netdev_close(struct net_device *dev)
                np->tx_skbuff[i] = 0;
        }
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index bfb0f57dfd00ac169df564cdb5242ee487a424b1..ba436a12b77c0541a331774c6b46ea069d8b2394 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.104 2000/11/17 01:40:00 davem Exp $
+/* $Id: sunhme.c,v 1.105 2000/12/05 02:00:36 anton Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -1492,18 +1492,18 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
 
        /* Shut up the MIF. */
        HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
-            hme_read32(hp, &tregs->int_mask)));
+            hme_read32(hp, tregs + TCVR_IMASK)));
        hme_write32(hp, tregs + TCVR_IMASK, 0xffff);
 
        /* See if we can enable the MIF frame on this card to speak to the DP83840. */
        if (hp->happy_flags & HFLAG_FENABLE) {
                HMD(("use frame old[%08x], ",
-                    hme_read32(hp, &tregs->cfg)));
+                    hme_read32(hp, tregs + TCVR_CFG)));
                hme_write32(hp, tregs + TCVR_CFG,
                            hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE));
        } else {
                HMD(("use bitbang old[%08x], ",
-                    hme_read32(hp, &tregs->cfg)));
+                    hme_read32(hp, tregs + TCVR_CFG)));
                hme_write32(hp, tregs + TCVR_CFG,
                            hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE);
        }
index 33e98c23e776bd1ba6756c42c9b6b4efeb548242..e3aae91119e2930f52410577c5af9acb0cde9425 100644 (file)
@@ -474,6 +474,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
                printk(KERN_ERR "TLAN: Could not allocate memory for device.\n");
                return -ENOMEM;
        }
+       SET_MODULE_OWNER(dev);
        
        priv = dev->priv;
                
@@ -814,14 +815,11 @@ static int TLan_Open( struct net_device *dev )
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
        int             err;
        
-       MOD_INC_USE_COUNT;
-       
        priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
        err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
        
        if ( err ) {
                printk(KERN_ERR "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
-               MOD_DEC_USE_COUNT;
                return err;
        }
        
@@ -1098,8 +1096,6 @@ static int TLan_Close(struct net_device *dev)
        TLan_FreeLists( dev );
        TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name );
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 
 } /* TLan_Close */
index e91f3b0cc610c487744f53145014580f36cb4dce..f5d261027c1f8f11ce4b0369fbcd58e1eb605990 100644 (file)
@@ -52,7 +52,7 @@ const char * const medianame[] = {
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
 #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
-       || defined(__sparc_)
+       || defined(__sparc_) || defined(__ia64__)
 static int rx_copybreak = 1518;
 #else
 static int rx_copybreak = 100;
@@ -71,7 +71,7 @@ static int rx_copybreak = 100;
        ToDo: Non-Intel setting could be better.
 */
 
-#if defined(__alpha__)
+#if defined(__alpha__) || defined(__ia64__)
 static int csr0 = 0x01A00000 | 0xE000;
 #elif defined(__i386__) || defined(__powerpc__)
 static int csr0 = 0x01A00000 | 0x8000;
index 9d0947b058756cb826f3db43d3c593cd8fa4d1a3..a1d4629af1783523e371c88174e120ce3eee8dfe 100644 (file)
@@ -508,6 +508,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
                        card_idx);
                goto err_out_free_dma;
        }
+       SET_MODULE_OWNER(dev);
        
        /* request all PIO and MMIO regions just to make sure
         * noone else attempts to use any portion of our I/O space */
@@ -694,15 +695,12 @@ static int via_rhine_open(struct net_device *dev)
        long ioaddr = dev->base_addr;
        int i;
 
-       MOD_INC_USE_COUNT;
-
        /* Reset the chip. */
        writew(CmdReset, ioaddr + ChipCmd);
 
-       if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
-       }
+       i = request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev);
+       if (i)
+               return i;
 
        if (debug > 1)
                printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
@@ -712,7 +710,6 @@ static int via_rhine_open(struct net_device *dev)
                                                                           &np->tx_bufs_dma);
        if (np->tx_bufs == NULL) {
                free_irq(dev->irq, dev);
-               MOD_DEC_USE_COUNT;
                return -ENOMEM;
        }
 
@@ -1403,8 +1400,6 @@ static int via_rhine_close(struct net_device *dev)
        pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
                                                np->tx_bufs, np->tx_bufs_dma);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 2bf564aba660c52514d475b42cb56d24505b853b..e6a2837b846a3f93485d4200abc3eb41f7f59836 100644 (file)
@@ -76,7 +76,7 @@ static unsigned char* hscx_versions[]={"A1", NULL, "A2", NULL, "A3", "2.1"};
 struct mixcom_privdata {
        u16     clock;
        char    channel;
-       char    txbusy;
+       long    txbusy;
        struct sk_buff *sending;
        unsigned tx_ptr;
        struct sk_buff *recving;
index b343eb4ca0afb25d94cf9499c6351e90cc71664a..1461d5fb18cb40a779bc9c2dee3cf54442c50ade 100644 (file)
@@ -55,12 +55,12 @@ struct comx_channel {
        unsigned char   line_status;
 
        struct timer_list lineup_timer; // against line jitter
-       int             lineup_pending;
+       long int        lineup_pending;
        unsigned char   lineup_delay;
 
 #if 0
        struct timer_list reset_timer; // for board resetting
-       int             reset_pending;
+       long            reset_pending;
        int             reset_timeout;
 #endif
 
index 57f800d03b82396e84bec22fdcd3c0f0be63ac9a..4ab0de121476a1770503957aa0b57e52f296fede 100644 (file)
@@ -106,14 +106,7 @@ static int active;                 /* number of active cards */
 static sdla_t* card_array;     /* adapter data space */
 
 /* Task queue element for creating a 'thread' */
-static struct tq_struct sdla_tq =
-{
-       NULL,           /* .next */
-       0,              /* .sync */
-       &sdla_poll,     /* .routine */
-       NULL            /* .data */
-}; 
-
+static struct tq_struct sdla_tq = { routine: sdla_poll };
 
 /******* Kernel Loadable Module Entry Points ********************************/
 
index 5abeceb2039e06b9e57e8f8320c4361e54a595b3..c54e2ed18e553eba75f2e7aacde602d3d08dc49d 100644 (file)
@@ -42,7 +42,7 @@ struct x25_asy {
   int                  mtu;            /* Our mtu (to spot changes!)   */
   int                   buffsize;       /* Max buffers sizes            */
 
-  unsigned int         flags;          /* Flag values/ mode etc        */
+  unsigned long                flags;          /* Flag values/ mode etc        */
 #define SLF_INUSE      0               /* Channel in use               */
 #define SLF_ESCAPE     1               /* ESC received                 */
 #define SLF_ERROR      2               /* Parity, etc. error           */
index e46844b598dada62683a7906a9c174ccaa99d975..26a26506d7698cb87009c41763bf7cd89ff92792 100644 (file)
@@ -86,7 +86,9 @@ int __init wd_probe(struct net_device *dev)
 {
        int i;
        struct resource *r;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        if (base_addr > 0x1ff) {        /* Check a user specified location. */
                r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
@@ -96,7 +98,7 @@ int __init wd_probe(struct net_device *dev)
                if (i != 0)  
                        release_resource(r);
                else
-                       r->name = ei_status.name;
+                       r->name = dev->name;
                return i;
        }
        else if (base_addr != 0)        /* Don't probe at all. */
@@ -108,7 +110,7 @@ int __init wd_probe(struct net_device *dev)
                if (r == NULL)
                        continue;
                if (wd_probe1(dev, ioaddr) == 0) {
-                       r->name = ei_status.name;
+                       r->name = dev->name;
                        return 0;
                }
                release_resource(r);
@@ -263,11 +265,12 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
 
        /* Snarf the interrupt now.  There's no point in waiting since we cannot
           share and the board will usually be enabled. */
-       if (request_irq(dev->irq, ei_interrupt, 0, model_name, dev)) {
+       i = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+       if (i) {
                printk (" unable to get IRQ %d.\n", dev->irq);
                kfree(dev->priv);
                dev->priv = NULL;
-               return -EAGAIN;
+               return i;
        }
 
        /* OK, were are certain this is going to work.  Setup the device. */
@@ -324,7 +327,6 @@ wd_open(struct net_device *dev)
   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 
   ei_open(dev);
-  MOD_INC_USE_COUNT;
   return 0;
 }
 
@@ -431,8 +433,6 @@ wd_close(struct net_device *dev)
        /* And disable the shared memory. */
        outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 03f79ca2eea04e193b101ec2058bd12eb3636f5b..2996fb6f9951efb4ac0eb67a5914e7185a3b5d3d 100644 (file)
@@ -367,6 +367,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
        dev = init_etherdev(NULL, sizeof(*np));
        if (!dev)
                return -ENOMEM;
+       SET_MODULE_OWNER(dev);
 
 #ifdef USE_IO_OPS
        ioaddr = pci_resource_start(pdev, 0);
@@ -623,12 +624,9 @@ static int netdev_open(struct net_device *dev)
 
        writel(0x00000001, ioaddr + PCIBusCfg);         /* Reset */
 
-       MOD_INC_USE_COUNT;
-
-       if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EAGAIN;
-       }
+       i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+       if (i)
+               return i;
 
        if (debug > 1)
                printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",
@@ -1305,8 +1303,6 @@ static int netdev_close(struct net_device *dev)
                np->tx_skbuff[i] = 0;
        }
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 4e2d6435e87e6f84b4604a6ef389b0d49cadd95f..9cda23333a6fdf8dde8213b546e9d18028b6b6ed 100644 (file)
@@ -305,9 +305,6 @@ struct yellowfin_private {
           for status. */
        struct yellowfin_desc rx_ring[RX_RING_SIZE];
        struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
-       const char *product_name;
-       struct net_device *next_module;
-       void *priv_addr;                                        /* Unaligned address for kfree */
        /* The addresses of receive-in-place skbuffs. */
        struct sk_buff* rx_skbuff[RX_RING_SIZE];
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -426,8 +423,6 @@ static int yellowfin_open(struct net_device *dev)
                printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n",
                           dev->name, dev->irq);
 
-       MOD_INC_USE_COUNT;
-
        yellowfin_init_ring(dev);
 
        YF_OUTL(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);
@@ -1110,8 +1105,6 @@ static int yellowfin_close(struct net_device *dev)
                           dev->name, bogus_rx);
        }
 #endif
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
@@ -1230,24 +1223,19 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
        chip_idx = ent->driver_data;
        flags = chip_info[chip_idx].flags;
 
-       dev = init_etherdev(NULL, 0);
+       dev = init_etherdev(NULL, sizeof(*yp));
        if (!dev) {
                printk (KERN_ERR PFX "cannot allocate ethernet device\n");
                return -ENOMEM;
        }
+       SET_MODULE_OWNER(dev);
 
-       dev->priv = kmalloc(sizeof(*yp) + PRIV_ALIGN, GFP_KERNEL);
-       if (!dev->priv)
-               goto err_out_free_netdev;
-       yp = (void *)(((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
-       memset(yp, 0, sizeof(*yp));
-       yp->priv_addr = dev->priv;      /* store real addr for kfree */
-       dev->priv = yp;                 /* use aligned addr */
+       yp = dev->priv;
 
        if (!request_region (pci_resource_start (pdev, 0),
                             YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
                printk (KERN_ERR PFX "cannot obtain I/O port region\n");
-               goto err_out_free_priv;
+               goto err_out_free_netdev;
        }
        if (!request_mem_region (pci_resource_start (pdev, 1),
                                 YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
@@ -1255,8 +1243,8 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
                goto err_out_free_pio_region;
        }
        
-       /* XXX check enable_device for failure */
-       pci_enable_device (pdev);
+       if (pci_enable_device (pdev))
+               goto err_out_free_mmio_region;
        pci_set_master (pdev);
 
 #ifdef USE_IO_OPS
@@ -1264,7 +1252,8 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
 #else
        real_ioaddr = ioaddr = pci_resource_start (pdev, 1);
        ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);
-       /* XXX check for failure */
+       if (!ioaddr)
+               goto err_out_free_mmio_region;
 #endif
        irq = pdev->irq;
 
@@ -1348,10 +1337,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
        
        return 0;
 
+err_out_free_mmio_region:
+       release_mem_region (pci_resource_start (pdev, 1), YELLOWFIN_SIZE);
 err_out_free_pio_region:
        release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE);
-err_out_free_priv:
-       kfree (dev->priv);
 err_out_free_netdev:
        unregister_netdev (dev);
        kfree (dev);
@@ -1363,23 +1352,18 @@ static void __devexit yellowfin_remove_one (struct pci_dev *pdev)
        struct net_device *dev = pdev->driver_data;
        struct yellowfin_private *np;
 
-       if (!dev) {
-               printk (KERN_ERR "remove non-existent device\n");
-               return;
-       }
-       np = (struct yellowfin_private *) dev->priv;
+       if (!dev)
+               BUG();
+       np = dev->priv;
 
        unregister_netdev (dev);
 
-#ifdef USE_IO_OPS
        release_region (dev->base_addr, YELLOWFIN_SIZE);
-#else
-       iounmap ((void *) dev->base_addr);
        release_mem_region (dev->base_addr, YELLOWFIN_SIZE);
-#endif
 
-       if (np->priv_addr)
-               kfree (np->priv_addr);
+#ifndef USE_IO_OPS
+       iounmap ((void *) dev->base_addr);
+#endif
 
        kfree (dev);
 }
@@ -1398,11 +1382,7 @@ static int __init yellowfin_init (void)
        if (debug)                                      /* Emit version even if no cards detected. */
                printk(KERN_INFO "%s", version);
 
-       if (pci_register_driver (&yellowfin_driver) > 0)
-               return 0;
-
-       pci_unregister_driver (&yellowfin_driver);
-       return -ENODEV;
+       return pci_module_init (&yellowfin_driver);
 }
 
 
index 1314e9f9d0d8f8c82a1598f6816ff7a49a136d76..8d3c572ab4fb2c8942a445338e1563d149b96ff6 100644 (file)
@@ -1,3 +1,9 @@
+2000-11-21  Tim Waugh  <twaugh@redhat.com>
+
+       * parport_pc.c (parport_pc_ecp_write_block_pio): Fix
+       reverse-to-forward logic.  Spotted by Roland Kuck
+       <rci@cityweb.de>.
+
 2000-09-16  Cesar Eduardo Barros  <cesarb@nitnet.com.br>
 
        * parport_pc.c (sio_via_686a_probe): Handle case
index 95a778e96aec347d745f5dee5668f41b8d142d61..f2f7b1d7069f2f5590042d8ffd9df862c020f8f8 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_PARPORT_AMIGA)   += parport_amiga.o
 obj-$(CONFIG_PARPORT_MFC3)     += parport_mfc3.o
 obj-$(CONFIG_PARPORT_ATARI)    += parport_atari.o
 obj-$(CONFIG_PARPORT_SUNBPP)   += parport_sunbpp.o
+obj-$(CONFIG_PARPORT_GSC)      += parport_gsc.o
 
 # Extract lists of the multi-part drivers.
 # The 'int-*' lists are the intermediate files used to build the multi's.
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
new file mode 100644 (file)
index 0000000..8e4b177
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ *      Low-level parallel-support for PC-style hardware integrated in the 
+ *     LASI-Controller (on GSC-Bus) for HP-PARISC Workstations
+ *
+ *     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.
+ *
+ *     by Helge Deller <deller@gmx.de>
+ *
+ * 
+ * based on parport_pc.c by 
+ *         Grant Guenther <grant@torque.net>
+ *         Phil Blundell <Philip.Blundell@pobox.com>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
+ *         Jose Renau <renau@acm.org>
+ *          David Campbell <campbell@torque.net>
+ *          Andrea Arcangeli
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/sysctl.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/parport.h>
+#include <asm/gsc.h>
+#include <asm/pdc.h>
+#include <asm/hardware.h>
+#include <asm/parport_gsc.h>
+
+
+#undef DEBUG   /* undef for production */
+
+#ifdef DEBUG
+#define DPRINTK  printk
+#else
+#define DPRINTK(stuff...)
+#endif
+
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ *
+ * This is also used in SPP detection.
+ */
+static int clear_epp_timeout(struct parport *pb)
+{
+       unsigned char r;
+
+       if (!(parport_gsc_read_status(pb) & 0x01))
+               return 1;
+
+       /* To clear timeout some chips require double read */
+       parport_gsc_read_status(pb);
+       r = parport_gsc_read_status(pb);
+       parport_writeb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
+       parport_writeb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
+       r = parport_gsc_read_status(pb);
+
+       return !(r & 0x01);
+}
+
+/*
+ * Access functions.
+ *
+ * Most of these aren't static because they may be used by the
+ * parport_xxx_yyy macros.  extern __inline__ versions of several
+ * of these are in parport_gsc.h.
+ */
+
+static void parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       DPRINTK(__FILE__ ": got IRQ\n");
+       parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+void parport_gsc_write_data(struct parport *p, unsigned char d)
+{
+       DPRINTK(__FILE__ ": write (0x%02x) %c \n", d, d);
+       parport_writeb (d, DATA (p));
+}
+
+unsigned char parport_gsc_read_data(struct parport *p)
+{
+#ifdef DEBUG
+       unsigned char c = parport_readb (DATA (p));
+       DPRINTK(__FILE__ ": read (0x%02x) %c\n", c,c);
+       return c;
+#else
+       return parport_readb (DATA (p));
+#endif
+}
+
+void parport_gsc_write_control(struct parport *p, unsigned char d)
+{
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to the newer interface. */
+       if (d & 0x20) {
+               printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+                       p->name, p->cad->name);
+               parport_gsc_data_reverse (p);
+       }
+
+       __parport_gsc_frob_control (p, wm, d & wm);
+}
+
+unsigned char parport_gsc_read_control(struct parport *p)
+{
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+       const struct parport_gsc_private *priv = p->physport->private_data;
+       return priv->ctr & wm; /* Use soft copy */
+}
+
+unsigned char parport_gsc_frob_control (struct parport *p, unsigned char mask,
+                                      unsigned char val)
+{
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to the newer interface. */
+       if (mask & 0x20) {
+               printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+                       p->name, p->cad->name,
+                       (val & 0x20) ? "reverse" : "forward");
+               if (val & 0x20)
+                       parport_gsc_data_reverse (p);
+               else
+                       parport_gsc_data_forward (p);
+       }
+
+       /* Restrict mask and val to control lines. */
+       mask &= wm;
+       val &= wm;
+
+       return __parport_gsc_frob_control (p, mask, val);
+}
+
+unsigned char parport_gsc_read_status(struct parport *p)
+{
+       return parport_readb (STATUS (p));
+}
+
+void parport_gsc_disable_irq(struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x10, 0);
+}
+
+void parport_gsc_enable_irq(struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x10, 0x10);
+}
+
+void parport_gsc_data_forward (struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x20, 0);
+}
+
+void parport_gsc_data_reverse (struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x20, 0x20);
+}
+
+void parport_gsc_init_state(struct pardevice *dev, struct parport_state *s)
+{
+       s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+}
+
+void parport_gsc_save_state(struct parport *p, struct parport_state *s)
+{
+       s->u.pc.ctr = parport_readb (CONTROL (p));
+}
+
+void parport_gsc_restore_state(struct parport *p, struct parport_state *s)
+{
+       parport_writeb (s->u.pc.ctr, CONTROL (p));
+}
+
+void parport_gsc_inc_use_count(void)
+{
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+}
+
+void parport_gsc_dec_use_count(void)
+{
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+}
+
+
+struct parport_operations parport_gsc_ops = 
+{
+       write_data:     parport_gsc_write_data,
+       read_data:      parport_gsc_read_data,
+
+       write_control:  parport_gsc_write_control,
+       read_control:   parport_gsc_read_control,
+       frob_control:   parport_gsc_frob_control,
+
+       read_status:    parport_gsc_read_status,
+
+       enable_irq:     parport_gsc_enable_irq,
+       disable_irq:    parport_gsc_disable_irq,
+
+       data_forward:   parport_gsc_data_forward,
+       data_reverse:   parport_gsc_data_reverse,
+
+       init_state:     parport_gsc_init_state,
+       save_state:     parport_gsc_save_state,
+       restore_state:  parport_gsc_restore_state,
+
+       inc_use_count:  parport_gsc_inc_use_count,
+       dec_use_count:  parport_gsc_dec_use_count,
+
+       epp_write_data: parport_ieee1284_epp_write_data,
+       epp_read_data:  parport_ieee1284_epp_read_data,
+       epp_write_addr: parport_ieee1284_epp_write_addr,
+       epp_read_addr:  parport_ieee1284_epp_read_addr,
+
+       ecp_write_data: parport_ieee1284_ecp_write_data,
+       ecp_read_data:  parport_ieee1284_ecp_read_data,
+       ecp_write_addr: parport_ieee1284_ecp_write_addr,
+
+       compat_write_data:      parport_ieee1284_write_compat,
+       nibble_read_data:       parport_ieee1284_read_nibble,
+       byte_read_data:         parport_ieee1284_read_byte,
+};
+
+/* --- Mode detection ------------------------------------- */
+
+/*
+ * Checks for port existence, all ports support SPP MODE
+ */
+static int __devinit parport_SPP_supported(struct parport *pb)
+{
+       unsigned char r, w;
+
+       /*
+        * first clear an eventually pending EPP timeout 
+        * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
+        * that does not even respond to SPP cycles if an EPP
+        * timeout is pending
+        */
+       clear_epp_timeout(pb);
+
+       /* Do a simple read-write test to make sure the port exists. */
+       w = 0xc;
+       parport_writeb (w, CONTROL (pb));
+
+       /* Is there a control register that we can read from?  Some
+        * ports don't allow reads, so read_control just returns a
+        * software copy. Some ports _do_ allow reads, so bypass the
+        * software copy here.  In addition, some bits aren't
+        * writable. */
+       r = parport_readb (CONTROL (pb));
+       if ((r & 0xf) == w) {
+               w = 0xe;
+               parport_writeb (w, CONTROL (pb));
+               r = parport_readb (CONTROL (pb));
+               parport_writeb (0xc, CONTROL (pb));
+               if ((r & 0xf) == w)
+                       return PARPORT_MODE_PCSPP;
+       }
+
+       /* Try the data register.  The data lines aren't tri-stated at
+        * this stage, so we expect back what we wrote. */
+       w = 0xaa;
+       parport_gsc_write_data (pb, w);
+       r = parport_gsc_read_data (pb);
+       if (r == w) {
+               w = 0x55;
+               parport_gsc_write_data (pb, w);
+               r = parport_gsc_read_data (pb);
+               if (r == w)
+                       return PARPORT_MODE_PCSPP;
+       }
+
+       return 0;
+}
+
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines.  In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero.  So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present. 
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal.  Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic. 
+ */
+
+static int __devinit parport_PS2_supported(struct parport *pb)
+{
+       int ok = 0;
+  
+       clear_epp_timeout(pb);
+
+       /* try to tri-state the buffer */
+       parport_gsc_data_reverse (pb);
+       
+       parport_gsc_write_data(pb, 0x55);
+       if (parport_gsc_read_data(pb) != 0x55) ok++;
+
+       parport_gsc_write_data(pb, 0xaa);
+       if (parport_gsc_read_data(pb) != 0xaa) ok++;
+
+       /* cancel input mode */
+       parport_gsc_data_forward (pb);
+
+       if (ok) {
+               pb->modes |= PARPORT_MODE_TRISTATE;
+       } else {
+               struct parport_gsc_private *priv = pb->private_data;
+               priv->ctr_writable &= ~0x20;
+       }
+
+       return ok;
+}
+
+
+/* --- Initialisation code -------------------------------- */
+
+struct parport *__devinit parport_gsc_probe_port (unsigned long base,
+                                                unsigned long base_hi,
+                                                int irq, int dma,
+                                                struct pci_dev *dev)
+{
+       struct parport_gsc_private *priv;
+       struct parport_operations *ops;
+       struct parport tmp;
+       struct parport *p = &tmp;
+
+       if (check_region(base, 3)) 
+           return NULL;
+           
+       priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL);
+       if (!priv) {
+               printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+               return NULL;
+       }
+       ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+       if (!ops) {
+               printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
+                       base);
+               kfree (priv);
+               return NULL;
+       }
+       memcpy (ops, &parport_gsc_ops, sizeof (struct parport_operations));
+       priv->ctr = 0xc;
+       priv->ctr_writable = 0xff;
+       priv->dma_buf = 0;
+       priv->dma_handle = 0;
+       priv->dev = dev;
+       p->base = base;
+       p->base_hi = base_hi;
+       p->irq = irq;
+       p->dma = dma;
+       p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
+       p->ops = ops;
+       p->private_data = priv;
+       p->physport = p;
+       if (!parport_SPP_supported (p)) {
+               /* No port. */
+               kfree (priv);
+               return NULL;
+       }
+       parport_PS2_supported (p);
+
+       if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+                                       PARPORT_DMA_NONE, ops))) {
+               kfree (priv);
+               kfree (ops);
+               return NULL;
+       }
+
+       p->base_hi = base_hi;
+       p->modes = tmp.modes;
+       p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
+       p->private_data = priv;
+
+       printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+       p->irq = irq;
+       if (p->irq == PARPORT_IRQ_AUTO) {
+               p->irq = PARPORT_IRQ_NONE;
+       }
+       if (p->irq != PARPORT_IRQ_NONE) {
+               printk(", irq %d", p->irq);
+
+               if (p->dma == PARPORT_DMA_AUTO) {
+                       p->dma = PARPORT_DMA_NONE;
+               }
+       }
+       if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq
+                                           is mandatory (see above) */
+               p->dma = PARPORT_DMA_NONE;
+
+       printk(" [");
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
+       {
+               int f = 0;
+               printmode(PCSPP);
+               printmode(TRISTATE);
+               printmode(COMPAT)
+               printmode(EPP);
+//             printmode(ECP);
+//             printmode(DMA);
+       }
+#undef printmode
+       printk("]\n");
+       parport_proc_register(p);
+
+       request_region (p->base, 3, p->name);
+       if (p->size > 3)
+               request_region (p->base + 3, p->size - 3, p->name);
+       if (p->modes & PARPORT_MODE_ECP)
+               request_region (p->base_hi, 3, p->name);
+
+       if (p->irq != PARPORT_IRQ_NONE) {
+               if (request_irq (p->irq, parport_gsc_interrupt,
+                                0, p->name, p)) {
+                       printk (KERN_WARNING "%s: irq %d in use, "
+                               "resorting to polled operation\n",
+                               p->name, p->irq);
+                       p->irq = PARPORT_IRQ_NONE;
+                       p->dma = PARPORT_DMA_NONE;
+               }
+       }
+
+       /* Done probing.  Now put the port into a sensible start-up state. */
+
+       parport_gsc_write_data(p, 0);
+       parport_gsc_data_forward (p);
+
+       /* Now that we've told the sharing engine about the port, and
+          found out its characteristics, let the high-level drivers
+          know about it. */
+       parport_announce_port (p);
+
+       return p;
+}
+
+
+#define PARPORT_GSC_OFFSET 0x800
+
+static int __initdata parport_count;
+
+static int __init 
+parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri)
+{
+       unsigned long port;
+       int irq;
+
+       irq = busdevice_alloc_irq(d); 
+
+       if (!irq) {
+           printk("IRQ not found for parallel device at 0x%p\n", d->hpa);
+           return -ENODEV;
+       }
+
+       port = ((unsigned long) d->hpa) + PARPORT_GSC_OFFSET;
+       
+       /* 
+           some older machines with ASP-chip don't support the enhanced parport modes 
+       */
+       if (!pdc_add_valid( (void *)(port+4))) {
+           /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */
+           printk("%s: initialize bidirectional-mode.\n", __FUNCTION__);
+           parport_writeb ( (0x10 + 0x20), port + 4);
+       } else {
+           printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__);
+       }
+       
+       if (parport_gsc_probe_port(port, 0, 
+                   irq, /* PARPORT_IRQ_NONE */
+                   PARPORT_DMA_NONE, NULL))
+           parport_count++;
+
+       return 0;
+}
+
+static struct pa_iodc_driver parport_drivers_for[] __initdata = {
+  {HPHW_FIO, 0x0, 0x0, 0x74, 0x0, 0,                   /* 715/64 */
+       DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+       "parallel device", "HP 7xx - Series", (void *) parport_init_chip},
+  { 0 }
+};
+
+int __init 
+parport_gsc_init ( void )
+{
+       parport_count = 0;
+       
+       register_driver(parport_drivers_for);
+
+       return parport_count;
+}
+
+/* Exported symbols. */
+EXPORT_NO_SYMBOLS;
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
+MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver");
+MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port");
+
+int init_module(void)
+{      
+       return !parport_gsc_init ();
+}
+
+void cleanup_module(void)
+{
+       struct parport *p = parport_enumerate(), *tmp;
+       while (p) {
+               tmp = p->next;
+               if (p->modes & PARPORT_MODE_PCSPP) { 
+                       struct parport_gsc_private *priv = p->private_data;
+                       struct parport_operations *ops = p->ops;
+                       if (p->dma != PARPORT_DMA_NONE)
+                               free_dma(p->dma);
+                       if (p->irq != PARPORT_IRQ_NONE)
+                               free_irq(p->irq, p);
+                       release_region(p->base, 3);
+                       if (p->size > 3)
+                               release_region(p->base + 3, p->size - 3);
+                       if (p->modes & PARPORT_MODE_ECP)
+                               release_region(p->base_hi, 3);
+                       parport_proc_unregister(p);
+                       if (priv->dma_buf)
+                               pci_free_consistent(priv->dev, PAGE_SIZE,
+                                                   priv->dma_buf,
+                                                   priv->dma_handle);
+                       kfree (p->private_data);
+                       parport_unregister_port(p);
+                       kfree (ops); /* hope no-one cached it */
+               }
+               p = tmp;
+       }
+}
+#endif
index 952eaec41f9999d68a0517fb79c302893d3898be..fe6721c34147e6d0200ce8ea1b9190c9f8e64a3b 100644 (file)
@@ -778,9 +778,13 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
        /* Switch to forward mode if necessary. */
        if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
                /* Event 47: Set nInit high. */
-               parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_INIT
+                                     | PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_INIT
+                                     | PARPORT_CONTROL_AUTOFD);
 
-               /* Event 40: PError goes high. */
+               /* Event 49: PError goes high. */
                r = parport_wait_peripheral (port,
                                             PARPORT_STATUS_PAPEROUT,
                                             PARPORT_STATUS_PAPEROUT);
index afcc00a892c375ae9ed1dd448cbc954a6042ca32..a6dc39f437aeb0e522f0a73e30a658c3fbe8aab3 100644 (file)
@@ -582,8 +582,9 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                        pci_write_config_dword(dev, reg+4, ~0);
                        pci_read_config_dword(dev, reg+4, &sz);
                        pci_write_config_dword(dev, reg+4, l);
-                       if (sz)
-                               res->end = res->start + (((unsigned long) ~sz) << 32);
+                       if (~sz)
+                               res->end = res->start + 0xffffffff +
+                                               (((unsigned long) ~sz) << 32);
 #else
                        if (l) {
                                printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
index bf9c82c5a742acb4b9f16add5f26f12c8642c984..ace49456b949219e329f10732614ee9d15dbd396 100644 (file)
@@ -205,7 +205,7 @@ pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
        }
 }
 
-void __init 
+void __init
 pci_assign_unassigned_resources(void)
 {
        struct pbus_set_ranges_data ranges;
@@ -215,8 +215,8 @@ pci_assign_unassigned_resources(void)
        for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
                struct pci_bus *b = pci_bus_b(ln);
 
-               ranges.io_start = b->resource[0]->start;
-               ranges.mem_start = b->resource[1]->start;
+               ranges.io_start = b->resource[0]->start + PCIBIOS_MIN_IO;
+               ranges.mem_start = b->resource[1]->start + PCIBIOS_MIN_MEM;
                ranges.io_end = ranges.io_start;
                ranges.mem_end = ranges.mem_start;
                ranges.found_vga = 0;
index a2e83d751477cf315f98aa7fbf42b71d8ec598e1..1ca56825458aa9694f150d24cfc2e5a33ee0b63b 100644 (file)
@@ -136,6 +136,7 @@ pdev_sort_resources(struct pci_dev *dev,
        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
                struct resource *r;
                struct resource_list *list, *tmp;
+               unsigned long r_size;
 
                /* PCI-PCI bridges may have I/O ports or
                   memory on the primary bus */
@@ -144,15 +145,23 @@ pdev_sort_resources(struct pci_dev *dev,
                        continue;
 
                r = &dev->resource[i];
+               r_size = r->end - r->start;
+               
                if (!(r->flags & type_mask) || r->parent)
                        continue;
+               if (!r_size) {
+                       printk(KERN_WARNING "PCI: Ignore bogus resource %d "
+                                        "[%lx:%lx] of %s\n",
+                                         i, r->start, r->end, dev->name);
+                       continue;
+               }
                for (list = head; ; list = list->next) {
                        unsigned long size = 0;
                        struct resource_list *ln = list->next;
 
                        if (ln)
                                size = ln->res->end - ln->res->start;
-                       if (r->end - r->start > size) {
+                       if (r_size > size) {
                                tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
                                tmp->next = ln;
                                tmp->res = r;
index b8f3664d5b6ce7c212cf76630d5e68585e80146c..7256544ff54c74e1f5d608a97253f0a0dd70123e 100644 (file)
@@ -746,6 +746,25 @@ static void __init isapnp_add_fixed_mem32_resource(struct pci_dev *dev,
                (*res)->mem32 = mem32;
 }
 
+/*
+ *  Parse card name for ISA PnP device.
+ */ 
+static void __init 
+isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
+{
+       if (name[0] == '\0') {
+               unsigned short size1 = *size >= name_max ? (name_max - 1) : *size;
+               isapnp_peek(name, size1);
+               name[size1] = '\0';
+               *size -= size1;
+               
+               /* clean whitespace from end of string */
+               while (size1 > 0  &&  name[--size1] == ' ') 
+                       name[size1] = '\0';
+       }       
+}
+
 /*
  *  Parse resource map for logical device.
  */
@@ -843,12 +862,7 @@ static int __init isapnp_create_device(struct pci_bus *card,
                        size = 0;
                        break;
                case _LTAG_ANSISTR:
-                       if (dev->name[0] == '\0') {
-                               unsigned short size1 = size > 47 ? 47 : size;
-                               isapnp_peek(dev->name, size1);
-                               dev->name[size1] = '\0';
-                               size -= size1;
-                       }
+                       isapnp_parse_name(dev->name, sizeof(dev->name), &size);
                        break;
                case _LTAG_UNICODESTR:
                        /* silently ignore */
@@ -914,12 +928,7 @@ static void __init isapnp_parse_resource_map(struct pci_bus *card)
                case _STAG_VENDOR:
                        break;
                case _LTAG_ANSISTR:
-                       if (card->name[0] == '\0') {
-                               unsigned short size1 = size > 47 ? 47 : size;
-                               isapnp_peek(card->name, size1);
-                               card->name[size1] = '\0';
-                               size -= size1;
-                       }
+                       isapnp_parse_name(card->name, sizeof(card->name), &size);
                        break;
                case _LTAG_UNICODESTR:
                        /* silently ignore */
index 4acc6e5436223591cf803d48723558dd5a993355..699eaba377ddaaa5b89325a755a71733628177da 100644 (file)
@@ -1313,7 +1313,7 @@ static int ctc_open(net_device *dev)
                                 return -ENOMEM;
                 }
                 init_waitqueue_head(&privptr->channel[i].wait);
-                privptr->channel[i].tq.next = NULL;
+                INIT_LIST_HEAD(&privptr->channel[i].tq.list);
                 privptr->channel[i].tq.sync = 0;
                 privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh;
                 privptr->channel[i].tq.data = &privptr->channel[i]; 
index 560134ba21869697662b26a7f2002a1187f0817a..91cc447fb30876d93cfab320c9a2dea57cbc8c23 100644 (file)
@@ -547,7 +547,7 @@ static void dummy_start_output(struct sparcaudio_driver *drv, __u8 * buffer,
         dummy_chip->perchip_info.play.active = 1;
 
         /* fake an "interrupt" to deal with this block */
-        dummy_chip->tqueue.next = NULL;
+        INIT_LIST_HEAD(&dummy_chip->tqueue.list);
         dummy_chip->tqueue.sync = 0;
         dummy_chip->tqueue.routine = dummy_output_done_task;
         dummy_chip->tqueue.data = drv;
index b305ef12710d960b1760e4681b15859fdba6353b..c640c9fe869bede7cd1e89fb78ff45a430f8cd05 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: aurora.c,v 1.9 2000/11/08 05:33:03 davem Exp $
+/*     $Id: aurora.c,v 1.10 2000/12/07 04:35:38 anton Exp $
  *     linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
  *
  *     Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
index 7aa23b8b0bec0910cb5456860657bfb836ed94e2..5de83158b295317997a668e16f2ef5ca8ddcd91f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.53 2000/11/15 07:28:09 davem Exp $
+/* $Id: sab82532.c,v 1.54 2000/12/07 04:35:39 anton Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2134,7 +2134,7 @@ static void __init sab82532_kgdb_hook(int line)
 
 static inline void __init show_serial_version(void)
 {
-       char *revision = "$Revision: 1.53 $";
+       char *revision = "$Revision: 1.54 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
index c2627d106e1db9beaeb9aad8deca74de6d29bf5d..6f262b99865763a1611529d2775f9bc540678cfb 100644 (file)
@@ -30,7 +30,7 @@ CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
 CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
 CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
-obj-$(CONFIG_SCSI)             += scsi_mod.o   scsi_syms.o
+obj-$(CONFIG_SCSI)             += scsi_mod.o
 
 obj-$(CONFIG_A4000T_SCSI)      += amiga7xx.o   53c7xx.o
 obj-$(CONFIG_A4091_SCSI)       += amiga7xx.o   53c7xx.o
@@ -123,6 +123,7 @@ scsi_mod-objs       := scsi.o hosts.o scsi_ioctl.o constants.o \
                        scsicam.o scsi_proc.o scsi_error.o \
                        scsi_obsolete.o scsi_queue.o scsi_lib.o \
                        scsi_merge.o scsi_dma.o scsi_scan.o \
+                       scsi_syms.o
                        
 sr_mod-objs    := sr.o sr_ioctl.o sr_vendor.o
 initio-objs    := ini9100u.o i91uscsi.o
index 61298e9c084a1dff238f35d230fe59341251a045..cdc3f8989b8ae2d390ae80ab317feca9b1e0f5cc 100644 (file)
@@ -51,7 +51,7 @@ typedef struct {
        mode:           IMM_AUTODETECT, \
        host:           -1,             \
        cur_cmd:        NULL,           \
-       imm_tq:         {0, 0, imm_interrupt, NULL},    \
+       imm_tq:         { routine: imm_interrupt },    \
        jstart:         0,              \
        failed:         0,              \
        dp:             0,              \
@@ -122,7 +122,14 @@ int imm_detect(Scsi_Host_Template * host)
     struct Scsi_Host *hreg;
     int ports;
     int i, nhosts, try_again;
-    struct parport *pb = parport_enumerate();
+    struct parport *pb;
+
+    /*
+     * unlock to allow the lowlevel parport driver to probe
+     * the irqs
+     */
+    spin_unlock_irq(&io_request_lock);
+    pb = parport_enumerate();
 
     printk("imm: Version %s\n", IMM_VERSION);
     nhosts = 0;
@@ -130,6 +137,7 @@ int imm_detect(Scsi_Host_Template * host)
 
     if (!pb) {
        printk("imm: parport reports no devices.\n");
+       spin_lock_irq(&io_request_lock);
        return 0;
     }
   retry_entry:
@@ -154,6 +162,7 @@ int imm_detect(Scsi_Host_Template * host)
                    printk(KERN_ERR "imm%d: failed to claim parport because a "
                      "pardevice is owning the port for too longtime!\n",
                           i);
+                   spin_lock_irq(&io_request_lock);
                    return 0;
                }
            }
@@ -208,12 +217,16 @@ int imm_detect(Scsi_Host_Template * host)
        nhosts++;
     }
     if (nhosts == 0) {
-       if (try_again == 1)
+       if (try_again == 1) {
+           spin_lock_irq(&io_request_lock);
            return 0;
+       }
        try_again = 1;
        goto retry_entry;
-    } else
+    } else {
+       spin_lock_irq (&io_request_lock);
        return 1;               /* return number of hosts detected */
+    }
 }
 
 /* This is to give the imm driver a way to modify the timings (and other
index 7b8c9df55f87e6bddabb63cd4ce9b5d75c3d6c83..8c3d65bb89ce7a289874b42a0e5b879c2b6e3625 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef _IMM_H
 #define _IMM_H
 
-#define   IMM_VERSION   "2.04 (for Linux 2.4.0)"
+#define   IMM_VERSION   "2.05 (for Linux 2.4.0)"
 
 /* 
  * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega.
@@ -60,6 +60,9 @@
  *    added CONFIG_SCSI_IZIP_SLOW_CTR option
  *                                                      [2.03]
  *  Fix kernel panic on scsi timeout.          20Aug00 [2.04]
+ *
+ *  Avoid io_request_lock problems.
+ *  John Cavan <johncavan@home.com>            16Nov00 [2.05]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
index e55b26a0e72ddb1df19911257fa69d2e7b655b90..4d84fabc9b1231a3d28af99811cb9b72d1165d15 100644 (file)
@@ -929,7 +929,7 @@ typedef struct ips_ha {
    char              *ioctl_data;         /* IOCTL data area            */
    u32                ioctl_datasize;     /* IOCTL data size            */
    u32                cmd_in_progress;    /* Current command in progress*/
-   u32                flags;              /* HA flags                   */
+   long               flags;              /* HA flags                   */
    u8                 waitflag;           /* are we waiting for cmd     */
    u8                 active;
    u16                reset_count;        /* number of resets           */
index 661316cacea4aba8800cae70772f12a7dcbe2718..e85391bd1ed4aa521413d03d82bbad66b7b17680 100644 (file)
@@ -41,7 +41,7 @@ typedef struct {
        mode:           PPA_AUTODETECT, \
        host:           -1,             \
        cur_cmd:        NULL,           \
-       ppa_tq:         {0, 0, ppa_interrupt, NULL},    \
+       ppa_tq:         { routine: ppa_interrupt },     \
        jstart:         0,              \
        failed:         0,              \
        p_busy:         0               \
@@ -111,7 +111,14 @@ int ppa_detect(Scsi_Host_Template * host)
     struct Scsi_Host *hreg;
     int ports;
     int i, nhosts, try_again;
-    struct parport *pb = parport_enumerate();
+    struct parport *pb;
+
+    /*
+     * unlock to allow the lowlevel parport driver to probe
+     * the irqs
+     */
+    spin_unlock_irq(&io_request_lock);
+    pb = parport_enumerate();
 
     printk("ppa: Version %s\n", PPA_VERSION);
     nhosts = 0;
@@ -119,6 +126,7 @@ int ppa_detect(Scsi_Host_Template * host)
 
     if (!pb) {
        printk("ppa: parport reports no devices.\n");
+       spin_lock_irq(&io_request_lock);
        return 0;
     }
   retry_entry:
@@ -143,6 +151,7 @@ int ppa_detect(Scsi_Host_Template * host)
                    printk(KERN_ERR "ppa%d: failed to claim parport because a "
                      "pardevice is owning the port for too longtime!\n",
                           i);
+                   spin_lock_irq(&io_request_lock);
                    return 0;
                }
            }
@@ -212,11 +221,14 @@ int ppa_detect(Scsi_Host_Template * host)
            printk("  cable is marked with \"AutoDetect\", this is what has\n");
            printk("  happened.\n");
            return 0;
+           spin_lock_irq(&io_request_lock);
        }
        try_again = 1;
        goto retry_entry;
-    } else
+    } else {
+       spin_lock_irq(&io_request_lock);
        return 1;               /* return number of hosts detected */
+    }
 }
 
 /* This is to give the ppa driver a way to modify the timings (and other
index 74147c3299a9f04f83ec644f6cbf823e0753e3f7..0c03366dceb6a085c3433b3c16a3e97be85edb1f 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef _PPA_H
 #define _PPA_H
 
-#define   PPA_VERSION   "2.05 (for Linux 2.2.x)"
+#define   PPA_VERSION   "2.06 (for Linux 2.2.x)"
 
 /* 
  * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
@@ -58,6 +58,9 @@
  *     Tim Waugh <twaugh@redhat.com>
  *                                                      [2.04]
  * Fix kernel panic on scsi timeout, 2000-08-18                [2.05]
+ *
+ * Avoid io_request_lock problems.
+ * John Cavan <johncavan@home.com>                     [2.06]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
index b79ce2b328171fee3825c4b9aaec2d1c06743654..4db994a45e9d4e0f0b98af8b19bbbe7695a14cc4 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 
+#include <linux/sched.h>
+#include <linux/semaphore.h>
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
index e970737d1c41b090b3ac5d74c5358713250114d8..a8cdc58f2fd37ab6de1af7c342a7bf37698fca0f 100644 (file)
@@ -32,6 +32,9 @@
  *      ? merge ymf_pcm and state
  *      ? pcm interrupt no pointer
  *      ? underused structure members
+ *      - Remove remaining P3 tags (debug messages).
+ *  - Resolve XXX tagged questions.
+ *  - Cannot play 5133Hz.
  */
 
 #include <linux/module.h>
@@ -59,7 +62,7 @@ static int ymfpci_voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type,
     int pair, ymfpci_voice_t **rvoice);
 static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice);
 static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state);
-static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance);
+static int ymf_state_alloc(ymfpci_t *unit, int nvirt);
 
 static LIST_HEAD(ymf_devs);
 
@@ -602,11 +605,9 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
        char silence;
 
        if ((ypcm = voice->ypcm) == NULL) {
-/* P3 */ printk("ymf_pcm_interrupt: voice %d: no ypcm\n", voice->number);
                return;
        }
        if ((state = ypcm->state) == NULL) {
-/* P3 */ printk("ymf_pcm_interrupt: voice %d: no state\n", voice->number);
                ypcm->running = 0;      // lock it
                return;
        }
@@ -628,7 +629,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
                if (pos < 0 || pos >= dmabuf->dmasize) {        /* ucode bug */
                        printk(KERN_ERR
                            "ymfpci%d: %d: runaway: hwptr %d dmasize %d\n",
-                           codec->inst, voice->number,
+                           codec->dev_audio, voice->number,
                            dmabuf->hwptr, dmabuf->dmasize);
                        pos = 0;
                }
@@ -645,7 +646,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
 
                if (dmabuf->count == 0) {
                        printk("ymfpci%d: %d: strain: hwptr %d\n",
-                           codec->inst, voice->number, dmabuf->hwptr);
+                           codec->dev_audio, voice->number, dmabuf->hwptr);
                        ymf_playback_trigger(codec, ypcm, 0);
                }
 
@@ -664,7 +665,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
                                 */
                                printk("ymfpci%d: %d: lost: delta %d"
                                    " hwptr %d swptr %d distance %d count %d\n",
-                                   codec->inst, voice->number, delta,
+                                   codec->dev_audio, voice->number, delta,
                                    dmabuf->hwptr, swptr, distance, dmabuf->count);
                        } else {
                                /*
@@ -672,7 +673,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
                                 */
 //                             printk("ymfpci%d: %d: done: delta %d"
 //                                 " hwptr %d swptr %d distance %d count %d\n",
-//                                 codec->inst, voice->number, delta,
+//                                 codec->dev_audio, voice->number, delta,
 //                                 dmabuf->hwptr, swptr, distance, dmabuf->count);
                        }
                        played = dmabuf->count;
@@ -738,7 +739,6 @@ static int ymf_playback_trigger(ymfpci_t *codec, ymfpci_pcm_t *ypcm, int cmd)
 {
 
        if (ypcm->voices[0] == NULL) {
-/* P3 */ printk("ymfpci: trigger %d no voice\n", cmd);
                return -EINVAL;
        }
        if (cmd != 0) {
@@ -911,7 +911,7 @@ static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state)
        if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
                /* Cannot be unless we leak voices in ymf_release! */
                printk(KERN_ERR "ymfpci%d: cannot allocate voice!\n",
-                   codec->inst);
+                   codec->dev_audio);
                return err;
        }
 
@@ -1052,7 +1052,7 @@ static void ymf_pcm_free_substream(ymfpci_pcm_t *ypcm)
        }
 }
 
-static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance)
+static int ymf_state_alloc(ymfpci_t *unit, int nvirt)
 {
        ymfpci_pcm_t *ypcm;
        struct ymf_state *state;
@@ -1062,7 +1062,6 @@ static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance)
        }
        memset(state, 0, sizeof(struct ymf_state));
 
-       init_waitqueue_head(&state->open_wait);
        init_waitqueue_head(&state->dmabuf.wait);
 
        ypcm = &state->ypcm;
@@ -1541,12 +1540,13 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                return put_user(SOUND_VERSION, (int *)arg);
 
        case SNDCTL_DSP_RESET:
-               /* FIXME: spin_lock ? */
                if (file->f_mode & FMODE_WRITE) {
                        ymf_wait_dac(state);
+                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                        dmabuf->ready = 0;
                        dmabuf->swptr = dmabuf->hwptr = 0;
                        dmabuf->count = dmabuf->total_bytes = 0;
+                       spin_unlock_irqrestore(&state->unit->reg_lock, flags);
                }
 #if HAVE_RECORD
                if (file->f_mode & FMODE_READ) {
@@ -1576,9 +1576,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
        case SNDCTL_DSP_SPEED: /* set smaple rate */
                if (get_user(val, (int *)arg))
                        return -EFAULT;
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SPEED %d\n", val); */
                if (val >= 8000 && val <= 48000) {
-                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                        if (file->f_mode & FMODE_WRITE) {
                                ymf_wait_dac(state);
                        }
@@ -1587,6 +1585,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                                stop_adc(state);
                        }
 #endif
+                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                        dmabuf->ready = 0;
                        state->format.rate = val;
                        ymf_pcm_update_shift(&state->format);
@@ -1603,7 +1602,6 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
        case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
                if (get_user(val, (int *)arg))
                        return -EFAULT;
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_STEREO %d\n", val); */
                if (file->f_mode & FMODE_WRITE) {
                        ymf_wait_dac(state); 
                        spin_lock_irqsave(&state->unit->reg_lock, flags);
@@ -1625,7 +1623,6 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case SNDCTL_DSP_GETBLKSIZE:
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETBLKSIZE\n"); */
                if (file->f_mode & FMODE_WRITE) {
                        if ((val = prog_dmabuf(state, 0)))
                                return val;
@@ -1639,15 +1636,12 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                return -EINVAL;
 
        case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETFMTS\n"); */
                return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 
        case SNDCTL_DSP_SETFMT: /* Select sample format */
                if (get_user(val, (int *)arg))
                        return -EFAULT;
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SETFMT 0x%x\n", val); */
                if (val == AFMT_S16_LE || val == AFMT_U8) {
-                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                        if (file->f_mode & FMODE_WRITE) {
                                ymf_wait_dac(state);
                        }
@@ -1656,6 +1650,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                                stop_adc(state);
                        }
 #endif
+                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                        dmabuf->ready = 0;
                        state->format.format = val;
                        ymf_pcm_update_shift(&state->format);
@@ -1668,22 +1663,24 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                        return -EFAULT;
        /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_CHANNELS 0x%x\n", val); */
                if (val != 0) {
-                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                        if (file->f_mode & FMODE_WRITE) {
                                ymf_wait_dac(state);
                                if (val == 1 || val == 2) {
+                                       spin_lock_irqsave(&state->unit->reg_lock, flags);
                                        dmabuf->ready = 0;
                                        state->format.voices = val;
                                        ymf_pcm_update_shift(&state->format);
+                                       spin_unlock_irqrestore(&state->unit->reg_lock, flags);
                                }
                        }
 #if HAVE_RECORD
                        if (file->f_mode & FMODE_READ) {
+                               spin_lock_irqsave(&state->unit->reg_lock, flags);
                                stop_adc(state);
                                dmabuf->ready = 0;
+                               spin_unlock_irqrestore(&state->unit->reg_lock, flags);
                        }
 #endif
-                       spin_unlock_irqrestore(&state->unit->reg_lock, flags);
                }
                return put_user(state->format.voices, (int *)arg);
 
@@ -1737,7 +1734,6 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case SNDCTL_DSP_GETOSPACE:
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETOSPACE\n"); */
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
                if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
@@ -1768,12 +1764,10 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
 #endif
 
        case SNDCTL_DSP_NONBLOCK:
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_NONBLOCK\n"); */
                file->f_flags |= O_NONBLOCK;
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETCAPS\n"); */
                /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
                            (int *)arg); */
                return put_user(0, (int *)arg);
@@ -1826,7 +1820,6 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
 #endif
 
        case SNDCTL_DSP_GETOPTR:
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETOPTR\n"); */
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
                spin_lock_irqsave(&state->unit->reg_lock, flags);
@@ -1840,7 +1833,6 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
        case SNDCTL_DSP_SETDUPLEX:      /* XXX TODO */
-       /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SETDUPLEX\n"); */
                return -EINVAL;
 
 #if 0 /* old */
@@ -1871,7 +1863,6 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                return -ENOTTY;
 
        default:
-       /* P3 */ printk(KERN_WARNING "ymfpci: unknown ioctl cmd 0x%x\n", cmd);
                /*
                 * Some programs mix up audio devices and ioctls
                 * or perhaps they expect "universal" ioctls,
@@ -1886,7 +1877,7 @@ static int ymf_open(struct inode *inode, struct file *file)
 {
        struct list_head *list;
        ymfpci_t *unit;
-       int minor, instance;
+       int minor;
        struct ymf_state *state;
        int nvirt;
        int err;
@@ -1903,24 +1894,24 @@ static int ymf_open(struct inode *inode, struct file *file)
        } else {
                return -ENXIO;
        }
-       instance = (minor >> 4) & 0x0F;
        nvirt = 0;                      /* Such is the partitioning of minor */
 
-       /* XXX Semaphore here! */
        for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {
                unit = list_entry(list, ymfpci_t, ymf_devs);
-               if (unit->inst == instance)
+               if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
                        break;
        }
        if (list == &ymf_devs)
                return -ENODEV;
 
+       down(&unit->open_sem);
        if (unit->states[nvirt] != NULL) {
-               /* P3 */ printk("ymfpci%d: busy\n", unit->inst);
+               up(&unit->open_sem);
                return -EBUSY;
        }
 
-       if ((err = ymf_state_alloc(unit, nvirt, instance)) != 0) {
+       if ((err = ymf_state_alloc(unit, nvirt)) != 0) {
+               up(&unit->open_sem);
                return err;
        }
        state = unit->states[nvirt];
@@ -1940,6 +1931,7 @@ static int ymf_open(struct inode *inode, struct file *file)
                unit->states[state->virt] = NULL;
                kfree(state);
 
+               up(&unit->open_sem);
                return err;
        }
 
@@ -1948,6 +1940,8 @@ static int ymf_open(struct inode *inode, struct file *file)
        ymfpci_writeb(codec, YDSXGR_TIMERCTRL,
            (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
 #endif
+       up(&unit->open_sem);
+       /* XXX Is it correct to have MOD_INC_USE_COUNT outside of sem.? */
 
        MOD_INC_USE_COUNT;
        return 0;
@@ -1962,14 +1956,14 @@ static int ymf_release(struct inode *inode, struct file *file)
        ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
 #endif
 
-       /* XXX Use the semaphore to unrace us with opens */
-
        if (state != codec->states[state->virt]) {
                printk(KERN_ERR "ymfpci%d.%d: state mismatch\n",
-                   state->unit->inst, state->virt);
+                   state->unit->dev_audio, state->virt);
                return -EIO;
        }
 
+       down(&codec->open_sem);
+
        /*
         * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
         * Deallocate when unloading the driver and we can wait.
@@ -1981,6 +1975,8 @@ static int ymf_release(struct inode *inode, struct file *file)
        codec->states[state->virt] = NULL;
        kfree(state);
 
+       up(&codec->open_sem);
+
        MOD_DEC_USE_COUNT;
        return 0;
 }
@@ -2235,7 +2231,6 @@ static int ymf_ac97_init(ymfpci_t *card, int num_ac97)
        codec->codec_write = ymfpci_codec_write;
 
        if (ac97_probe_codec(codec) == 0) {
-               /* Alan does not have this printout. P3 */
                printk("ymfpci: ac97_probe_codec failed\n");
                goto out_kfree;
        }
@@ -2264,7 +2259,6 @@ static int ymf_ac97_init(ymfpci_t *card, int num_ac97)
 static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
        u16 ctrl;
-       static int ymf_instance; /* = 0 */
        ymfpci_t *codec;
 
        int err;
@@ -2282,13 +2276,13 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
 
        spin_lock_init(&codec->reg_lock);
        spin_lock_init(&codec->voice_lock);
+       init_MUTEX(&codec->open_sem);
        codec->pci = pcidev;
-       codec->inst = ymf_instance;
 
-       pci_read_config_byte(pcidev, PCI_REVISION_ID, (u8 *)&codec->rev);
+       pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
        codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);
 
-       printk(KERN_INFO "ymfpci%d: %s at 0x%lx IRQ %d\n", ymf_instance,
+       printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
            (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);
 
        ymfpci_aclink_reset(pcidev);
@@ -2306,13 +2300,14 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
 
        if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) {
                printk(KERN_ERR "ymfpci%d: unable to request IRQ %d\n",
-                      codec->inst, pcidev->irq);
+                      codec->dev_audio, pcidev->irq);
                goto out_memfree;
        }
 
        /* register /dev/dsp */
        if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
-               printk(KERN_ERR "ymfpci%d: unable to register dsp\n", codec->inst);
+               printk(KERN_ERR "ymfpci%d: unable to register dsp\n",
+                   codec->dev_audio);
                goto out_free_irq;
        }
 
@@ -2325,7 +2320,6 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi
        /* put it into driver list */
        list_add_tail(&codec->ymf_devs, &ymf_devs);
        pci_set_drvdata(pcidev, codec);
-       ymf_instance++;
 
        return 0;
 
index 7ea633ca09b245f68d5dc1a82f447981e0b23479..6e1a8d5f396730001559b85752534da53b463ac8 100644 (file)
@@ -247,7 +247,7 @@ struct ymf_pcm {
 };
 
 struct ymf_unit {
-       unsigned int rev;       /* PCI revision */
+       u8 rev;                         /* PCI revision */
        void *reg_area_virt;
        void *work_ptr;                         // +
 
@@ -275,13 +275,13 @@ struct ymf_unit {
        u16 ac97_features;
 
        struct pci_dev *pci;
-       int inst;               /* Unit number (instance) */
 
        spinlock_t reg_lock;
        spinlock_t voice_lock;
 
        /* soundcore stuff */
        int dev_audio;
+       struct semaphore open_sem;
 
        struct list_head ymf_devs;
        struct ymf_state *states[1];                    // *
@@ -332,10 +332,6 @@ struct ymf_pcm_format {
 struct ymf_state {
        struct ymf_unit *unit;                  /* backpointer */
 
-       /* single open lock mechanism, only used for recording */
-       struct semaphore open_sem;
-       wait_queue_head_t open_wait;
-
        /* virtual channel number */
        int virt;                               // * unused a.t.m.
 
index 0592297dc4b955a860d3c8c7241dc587b818b690..060ee5a69cf6a189313593d55c3157a7f387d8a5 100644 (file)
@@ -1738,7 +1738,7 @@ dbg( "digi_startup: TOP" );
                init_waitqueue_head( &priv->dp_flush_wait );
                priv->dp_in_close = 0;
                init_waitqueue_head( &priv->dp_close_wait );
-               priv->dp_wakeup_task.next = NULL;
+               INIT_LIST_HEAD(&priv->dp_wakeup_task.list);
                priv->dp_wakeup_task.sync = 0;
                priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock;
                priv->dp_wakeup_task.data = (void *)(&serial->port[i]);
index b4ee5fdc111d12dd64c136fa126dbde8a2ab76a1..8d7c9c035ca566f9d538735d9a65ab951d052ac6 100644 (file)
@@ -49,7 +49,6 @@
 */
 
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
index 0d7b4545ae324f24f3e46494c106d9125e7e0ffd..0cd2a70b0579529c713d31c30b2d15a4d7c94efb 100644 (file)
@@ -34,6 +34,7 @@
 #ifndef __LINUX_USB_SERIAL_KEYSPAN_H
 #define __LINUX_USB_SERIAL_KEYSPAN_H
 
+#include <linux/config.h>
 
        /* Function prototypes for Keyspan serial converter */
 static int  keyspan_open               (struct usb_serial_port *port,
index b614a6d7e5c2c077afd40936e1ddd832e5b17536..b94c9766a3db4fda2067898d6f274240c7cfe8f0 100644 (file)
@@ -742,11 +742,11 @@ static int keyspan_pda_startup (struct usb_serial *serial)
        if (!priv)
                return (1); /* error */
        init_waitqueue_head(&serial->port[0].write_wait);
-       priv->wakeup_task.next = NULL;
+       INIT_LIST_HEAD(&priv->wakeup_task.list);
        priv->wakeup_task.sync = 0;
        priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write;
        priv->wakeup_task.data = (void *)(&serial->port[0]);
-       priv->unthrottle_task.next = NULL;
+       INIT_LIST_HEAD(&priv->unthrottle_task.list);
        priv->unthrottle_task.sync = 0;
        priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle;
        priv->unthrottle_task.data = (void *)(serial);
index d988d9e399844638409b91309eb252fd8bfe3ec3..98e58b46c628b3876ba8c8762b3041e23a60fced 100644 (file)
@@ -77,10 +77,8 @@ static int   mda_last_vc  = 16;
 
 static struct vc_data  *mda_display_fg = NULL;
 
-#ifdef MODULE_PARM
 MODULE_PARM(mda_first_vc, "1-255i");
 MODULE_PARM(mda_last_vc,  "1-255i");
-#endif
 
 /* MDA register values
  */
@@ -200,11 +198,7 @@ void __init mdacon_setup(char *str, int *ints)
 }
 #endif
 
-#ifdef MODULE
-static int mda_detect(void)
-#else
 static int __init mda_detect(void)
-#endif
 {
        int count=0;
        u16 *p, p_save;
@@ -287,11 +281,7 @@ static int __init mda_detect(void)
        return 1;
 }
 
-#ifdef MODULE
-static void mda_initialize(void)
-#else
 static void __init mda_initialize(void)
-#endif
 {
        write_mda_b(97, 0x00);          /* horizontal total */
        write_mda_b(80, 0x01);          /* horizontal displayed */
@@ -316,11 +306,7 @@ static void __init mda_initialize(void)
        outb_p(0x00, mda_gfx_port);
 }
 
-#ifdef MODULE
-static const char *mdacon_startup(void)
-#else
 static const char __init *mdacon_startup(void)
-#endif
 {
        mda_num_columns = 80;
        mda_num_lines   = 25;
@@ -605,11 +591,7 @@ const struct consw mda_con = {
        con_invert_region:      mdacon_invert_region,
 };
 
-#ifdef MODULE
-void mda_console_init(void)
-#else
 void __init mda_console_init(void)
-#endif
 {
        if (mda_first_vc > mda_last_vc)
                return;
index dbe463e0502faa59da8592525548469923f3a749..8e2a382c371372ab306a8cd78f3015e1142b8ee7 100644 (file)
@@ -2040,7 +2040,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
        int             pageind;
        int             bhind;
        int             offset;
-       int             sectors = size>>9;
        unsigned long   blocknr;
        struct kiobuf * iobuf = NULL;
        struct page *   map;
@@ -2092,9 +2091,8 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
                                tmp->b_this_page = tmp;
 
                                init_buffer(tmp, end_buffer_io_kiobuf, iobuf);
-                               tmp->b_rdev = tmp->b_dev = dev;
+                               tmp->b_dev = dev;
                                tmp->b_blocknr = blocknr;
-                               tmp->b_rsector = blocknr*sectors;
                                tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req);
 
                                if (rw == WRITE) {
@@ -2108,7 +2106,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
 
                                atomic_inc(&iobuf->io_count);
 
-                               generic_make_request(rw, tmp);
+                               submit_bh(rw, tmp);
                                /* 
                                 * Wait for IO if we have got too much 
                                 */
index 104f5a3c739f095d121bfa847246a550f93ee40d..1f1eb12787f7c402699753131972a1313a85a766 100644 (file)
@@ -7,7 +7,5 @@ dep_mbool '  Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG $CONFI
 dep_mbool '  Use NFS namespace if available' CONFIG_NCPFS_NFS_NS $CONFIG_NCP_FS
 dep_mbool '  Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS $CONFIG_NCP_FS
 dep_mbool '  Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS $CONFIG_NCP_FS
-dep_mbool '  Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR $CONFIG_NCP_FS
-dep_mbool '  NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS $CONFIG_NCP_FS
 dep_mbool '  Use Native Language Support' CONFIG_NCPFS_NLS $CONFIG_NCP_FS
 dep_mbool '  Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS $CONFIG_NCP_FS
index 4b6afe2e9c61400ffbad68e8c8c14aed03058cd1..37c87f8b203c96d249e66f5eb11bf368ffcd2887 100644 (file)
@@ -165,7 +165,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                        return 0;
                }
 
-#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
        case NCP_IOC_GETROOT:
                {
                        struct ncp_setroot_ioctl sr;
@@ -241,7 +240,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
 
                        return 0;
                }
-#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
 
 #ifdef CONFIG_NCPFS_PACKET_SIGNING     
        case NCP_IOC_SIGN_INIT:
@@ -374,7 +372,6 @@ outrel:
                }
 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
 
-#ifdef CONFIG_NCPFS_NDS_DOMAINS
        case NCP_IOC_GETOBJECTNAME:
                if (current->uid != server->m.mounted_uid) {
                        return -EACCES;
@@ -503,7 +500,6 @@ outrel:
                        if (old) ncp_kfree_s(old, oldlen);
                        return 0;
                }
-#endif /* CONFIG_NCPFS_NDS_DOMAINS */
 
 #ifdef CONFIG_NCPFS_NLS
 /* Here we are select the iocharset and the codepage for NLS.
index 6d07ead736e135bfbf46b09ab2178cac7b9b1207..162c89b4b4f42bf01abf4fe45d4d9bf2359e17a6 100644 (file)
@@ -96,16 +96,14 @@ ncp_ClearPhysicalRecord(struct ncp_server *server,
                        __u32 offset, __u32 length);
 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
 
-#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
 int
 ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *,
                        __u8, __u8, __u32);
-#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
 
 #ifdef CONFIG_NCPFS_NLS
 
-inline unsigned char ncp__tolower(struct nls_table *, unsigned char);
-inline unsigned char ncp__toupper(struct nls_table *, unsigned char);
+unsigned char ncp__tolower(struct nls_table *, unsigned char);
+unsigned char ncp__toupper(struct nls_table *, unsigned char);
 int ncp__io2vol(struct ncp_server *, unsigned char *, unsigned int *,
                                const unsigned char *, unsigned int, int);
 int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
index 029b673f50dc6c70276a37def603ed5d7142a8fb..f741cb6ddfe2b3570a5de0b8b4f25be93d15140e 100644 (file)
@@ -594,6 +594,11 @@ nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
        nfs_refresh_inode(inode, fattr);
 }
 
+struct nfs_find_desc {
+       struct nfs_fh           *fh;
+       struct nfs_fattr        *fattr;
+};
+
 /*
  * In NFSv3 we can have 64bit inode numbers. In order to support
  * this, and re-exported directories (also seen in NFSv2)
@@ -603,13 +608,16 @@ nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 static int
 nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
 {
-       struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+       struct nfs_find_desc    *desc = (struct nfs_find_desc *)opaque;
+       struct nfs_fh           *fh = desc->fh;
+       struct nfs_fattr        *fattr = desc->fattr;
 
        if (NFS_FSID(inode) != fattr->fsid)
                return 0;
        if (NFS_FILEID(inode) != fattr->fileid)
                return 0;
-
+       if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
+               return 0;
        return 1;
 }
 
@@ -640,8 +648,6 @@ nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fat
  * the vfs read_inode function because there is no way to pass the
  * file handle or current attributes into the read_inode function.
  *
- * We provide a special check for NetApp .snapshot directories to avoid
- * inode aliasing problems. All snapshot inodes are anonymous (unhashed).
  */
 struct inode *
 nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
@@ -652,41 +658,16 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
        dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
                (long long)fattr->fileid);
-
-#ifdef CONFIG_NFS_SNAPSHOT
-       /*
-        * Check for NetApp snapshot dentries, and get an 
-        * unhashed inode to avoid aliasing problems.
-        */
-       if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
-           (dentry->d_name.len == 9 &&
-            memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
-               struct inode *inode = new_inode(sb);
-               if (!inode)
-                       goto out;
-               inode->i_ino = nfs_fattr_to_ino_t(fattr);
-               nfs_read_inode(inode);
-               nfs_fill_inode(inode, fhandle, fattr);
-               inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
-               dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
-       out:
-               return inode;
-       }
-#endif
        return __nfs_fhget(sb, fhandle, fattr);
 }
 
 /*
  * Look up the inode by super block and fattr->fileid.
- *
- * Note carefully the special handling of busy inodes (i_count > 1).
- * With the kernel 2.1.xx dcache all inodes except hard links must
- * have i_count == 1 after iget(). Otherwise, it indicates that the
- * server has reused a fileid (i_ino) and we have a stale inode.
  */
 static struct inode *
 __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+       struct nfs_find_desc desc = { fh, fattr };
        struct inode *inode = NULL;
        unsigned long ino;
 
@@ -700,29 +681,7 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
        ino = nfs_fattr_to_ino_t(fattr);
 
-       while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
-
-               /*
-                * Check for busy inodes, and attempt to get rid of any
-                * unused local references. If successful, we release the
-                * inode and try again.
-                *
-                * Note that the busy test uses the values in the fattr,
-                * as the inode may have become a different object.
-                * (We can probably handle modes changes here, too.)
-                */
-               if (!nfs_inode_is_stale(inode, fh, fattr))
-                       break;
-
-               dprintk("__nfs_fhget: inode (%x/%Ld) still busy, i_count=%d\n",
-                       inode->i_dev, (long long)NFS_FILEID(inode),
-                       atomic_read(&inode->i_count));
-               nfs_zap_caches(inode);
-               remove_inode_hash(inode);
-               iput(inode);
-       }
-
-       if (!inode)
+       if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
                goto out_no_inode;
 
        nfs_fill_inode(inode, fh, fattr);
index 0e850ba3e33b7c592869a5666cf5bfdb834c7e26..e0f7313be780aa068da45a903555e0bbd6d22657 100644 (file)
@@ -116,8 +116,8 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
                lock_kernel();
                result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
                                                offset, rsize, buffer, &eof);
-               unlock_kernel();
                nfs_refresh_inode(inode, &fattr);
+               unlock_kernel();
 
                /*
                 * Even if we had a partial success we can't mark the page
index 96509df07dd591386a8afabbc025a35413bda1ae..e46ef0b25fc7d46126e77e507e83ad8fd85402f2 100644 (file)
@@ -43,7 +43,7 @@ static struct file_operations proc_file_operations = {
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-/* 4K page size but our output routines use some slack for overruns */
+/* buffer size is one page but our output routines use some slack for overruns */
 #define PROC_BLOCK_SIZE        (PAGE_SIZE - 1024)
 
 static ssize_t
index cd8f7ad3d4d9ec2854c2ca45434db1d339c2737a..16eba638327b6d93fa357c1b1fb24861f94d3311 100644 (file)
@@ -325,4 +325,3 @@ out_putf:
 out:
        return error;
 }
-
index 9e6b8222b1ffc94478f02c44505de5919aceb06d..cb1e697fc131a2b6c106ff6506ec2faa93991e18 100644 (file)
@@ -163,7 +163,7 @@ smb_data_ready(struct sock *sk, int len)
                found_data(sk);
                return;
        }
-       job->cb.next = NULL;
+       INIT_LIST_HEAD(&job->cb.list);
        job->cb.sync = 0;
        job->cb.routine = smb_data_callback;
        job->cb.data = job;
index a655468204c88728bdeccf175ccf4e746887b070..b98102522d0d03c386b2d27550ddbaff9064b578 100644 (file)
@@ -26,7 +26,7 @@ static inline pte_t ptep_get_and_clear(pte_t *ptep)
        return pte;
 }
 
-static inline void ptep_clear_wrprotect(pte_t *ptep)
+static inline void ptep_set_wrprotect(pte_t *ptep)
 {
        pte_t old_pte = *ptep;
        set_pte(ptep, pte_wrprotect(old_pte));
index 733ec4cc05977a8a67da30dae57530535b8b7188..abb627a4128056c57c3abf385effa04477d116c6 100644 (file)
@@ -10,7 +10,7 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 
 #if APIC_DEBUG
-#define Dprintk(x...) printk(##x)
+#define Dprintk(x...) printk(x)
 #else
 #define Dprintk(x...)
 #endif
index 515a8dc5ccb218f5043cadf52ca2985e3b840134..72bf155e92cab6f9b895d5489f2281094ff0d8a3 100644 (file)
@@ -30,3 +30,7 @@
                          : "=a" (low), "=d" (high) \
                          : "c" (counter))
 
+/* symbolic names for some interesting MSRs */
+#define MSR_IA32_PLATFORM_ID   0x17
+#define MSR_IA32_UCODE_WRITE   0x79
+#define MSR_IA32_UCODE_REV     0x8B
index 1fc0a0b9ac1daad602a8d74afa81fed6d2e95997..5d7d5717a63c6e7aa3113747bbf64a5fafcb3200 100644 (file)
@@ -283,7 +283,7 @@ static inline pte_t pte_mkwrite(pte_t pte)  { (pte).pte_low |= _PAGE_RW; return p
 
 static inline  int ptep_test_and_clear_dirty(pte_t *ptep)      { return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep); }
 static inline  int ptep_test_and_clear_young(pte_t *ptep)      { return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
-static inline void ptep_clear_wrprotect(pte_t *ptep)           { clear_bit(_PAGE_BIT_RW, ptep); }
+static inline void ptep_set_wrprotect(pte_t *ptep)             { clear_bit(_PAGE_BIT_RW, ptep); }
 static inline void ptep_mkdirty(pte_t *ptep)                   { set_bit(_PAGE_BIT_RW, ptep); }
 
 /*
index 9e8e8c5effde83ad25670462e57ef3befab23c8e..a03dd00275efb0aec230b07393c6484eac517245 100644 (file)
@@ -464,7 +464,8 @@ struct microcode {
        unsigned int bits[500];
 };
 
-#define MICROCODE_IOCFREE      _IO('6',0) /* because it is for P6 */
+/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
+#define MICROCODE_IOCFREE      _IO('6',0)
 
 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
 extern inline void rep_nop(void)
index 1c321c3e7d2c7fc93e459833778984d046829850..8df7a4693fb652955f053396e4b0c1c8462a4395 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hdreg.h,v 1.1 2000/01/21 04:56:27 zaitcev Exp $
+/* $Id: hdreg.h,v 1.2 2000/12/05 00:56:36 anton Exp $
  * hdreg.h: SPARC PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,6 @@
 #ifndef __SPARC_HDREG_H
 #define __SPARC_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __SPARC_HDREG_H */
index 278c15c801f9af9e8e3298a29fa36f3bd9c575aa..41b96727ad85a016b27556ad5709131492684f17 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.77 2000/01/21 11:39:17 jj Exp $
+/* $Id: processor.h,v 1.78 2000/11/30 08:37:31 anton Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -90,6 +90,7 @@ struct thread_struct {
 
 #define SPARC_FLAG_KTHREAD      0x1    /* task is a kernel thread */
 #define SPARC_FLAG_UNALIGNED    0x2    /* is allowed to do unaligned accesses */
+#define SPARC_FLAG_MMAPSHARED  0x4    /* task wants a shared mmap */
 
 #define INIT_MMAP { &init_mm, (0), (0), \
                    NULL, __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
index 23603f287510fe5a4a2ce118770ede25e0b54742..45e1f1828a4dca7a555d31192b07d47855665afe 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.13 2000/11/06 06:59:04 davem Exp $ */
+/* $Id: pgalloc.h,v 1.14 2000/12/09 04:15:24 anton Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
 #define flush_cache_page(vma, page) \
        flush_cache_mm((vma)->vm_mm)
 
-/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_icache_range(start, end)         do { } while (0)
+/* This is unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_page_to_ram(page)                        do { } while (0)
 
+/* 
+ * icache doesnt snoop local stores and we don't use block commit stores
+ * (which invalidate icache lines) during module load, so we need this.
+ */
+extern void flush_icache_range(unsigned long start, unsigned long end);
+
 extern void __flush_dcache_page(void *addr, int flush_icache);
 #define flush_dcache_page(page) \
 do {   if ((page)->mapping && !(page)->mapping->i_mmap && !(page)->mapping->i_mmap_shared) \
index eae8b7bdb62b13f3cc0fed3a9719ab0a09e39c08..562cf4ba8237cc6b0ddcebf7e0aa91e773a43f27 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.65 2000/08/09 00:00:17 davem Exp $
+/* $Id: processor.h,v 1.66 2000/11/29 05:56:12 anton Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -80,6 +80,7 @@ struct thread_struct {
 #define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary         */
 #define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process  */
 #define SPARC_FLAG_PERFCTR     0x10    /* task has performance counters active */
+#define SPARC_FLAG_MMAPSHARED  0x20    /* task wants a shared mmap             */
 
 #define FAULT_CODE_WRITE       0x01    /* Write access, implies D-TLB          */
 #define FAULT_CODE_DTLB                0x02    /* Miss happened in D-TLB               */
index 4d5ada52b6e03bd50a5b8ff5fc67076ad00e4c0a..d169bf7f22c902f90641aade9c59bdd60d99bdd6 100644 (file)
@@ -257,7 +257,7 @@ enum {
 #define ATM_ATMOPT_CLP 1       /* set CLP bit */
 
 
-typedef struct { unsigned int bits; } atm_vcc_flags_t;
+typedef struct { unsigned long bits; } atm_vcc_flags_t;
 
 
 struct atm_vcc {
index 61cbe14d80e5b858100f137d34e78f1e39473507..7f416d7fb9b73eb47ed463decb01e54643d0623c 100644 (file)
@@ -168,6 +168,7 @@ struct module_info
  * Keith Owens <kaos@ocs.com.au> 28 Oct 2000.
  */
 
+#ifdef __KERNEL__
 #define HAVE_INTER_MODULE
 extern void inter_module_register(const char *, struct module *, const void *);
 extern void inter_module_unregister(const char *);
@@ -183,6 +184,7 @@ struct inter_module_entry {
 };
 
 extern int try_inc_mod_count(struct module *mod);
+#endif /* __KERNEL__ */
 
 #if defined(MODULE) && !defined(__GENKSYMS__)
 
index 0ed87cdb4fa52e6ae85270369754779ae55fda04..696938aa1853c1830c7f1e6721d63fed05a8bb84 100644 (file)
@@ -2,7 +2,7 @@
 /* Linux driver for Disk-On-Chip 2000       */
 /* (c) 1999 Machine Vision Holdings, Inc.   */
 /* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.h,v 1.8 2000/07/10 15:46:29 dwmw2 Exp $ */
+/* $Id: doc2000.h,v 1.12 2000/11/03 12:43:43 dwmw2 Exp $ */
 
 #ifndef __MTD_DOC2000_H__
 #define __MTD_DOC2000_H__
  * Others use readb/writeb 
  */
 #if defined(__arm__) 
-#define ReadDOC(adr, reg)      ((unsigned char)(*(__u32 *)(((unsigned long)adr)+(DoC_##reg<<2))))
-#define WriteDOC(d, adr, reg)  do{ *(__u32 *)(((unsigned long)adr)+(DoC_##reg<<2)) = (__u32)d} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u32 *)(((unsigned long)adr)+(reg<<2))))
+#define WriteDOC_(d, adr, reg)  do{ *(__u32 *)(((unsigned long)adr)+(reg<<2)) = (__u32)d} while(0)
 #elif defined(__ppc__)
-#define ReadDOC(adr, reg)      ((unsigned char)(*(__u16 *)(((unsigned long)adr)+(DoC_##reg<<1))))
-#define WriteDOC(d, adr, reg)  do{ *(__u16 *)(((unsigned long)adr)+(DoC_##reg<<1)) = (__u16)d} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u16 *)(((unsigned long)adr)+(reg<<1))))
+#define WriteDOC_(d, adr, reg)  do{ *(__u16 *)(((unsigned long)adr)+(reg<<1)) = (__u16)d} while(0)
 #else
-#define ReadDOC(adr, reg)      readb(((unsigned long)adr) + DoC_##reg)
-#define WriteDOC(d, adr, reg)  writeb(d, ((unsigned long)adr) + DoC_##reg)
+#define ReadDOC_(adr, reg)      readb(((unsigned long)adr) + reg)
+#define WriteDOC_(d, adr, reg)  writeb(d, ((unsigned long)adr) + reg)
 #endif
 
+#if defined(__i386__)
+#define USE_MEMCPY
+#endif
+
+/* These are provided to directly use the DoC_xxx defines */
+#define ReadDOC(adr, reg)      ReadDOC_(adr,DoC_##reg)
+#define WriteDOC(d, adr, reg)  WriteDOC_(d,adr,DoC_##reg)
+
 #define DOC_MODE_RESET                 0
 #define DOC_MODE_NORMAL        1
 #define DOC_MODE_RESERVED1     2
 #define DOC_TOGGLE_BIT                 0x04
 #define DOC_ECC_RESV           0x02
 #define DOC_ECC_IGNORE         0x01
+
 /* We have to also set the reserved bit 1 for enable */
 #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
-#define DOC_ECC_DIS (DOC_ECC_IGNORE | DOC_ECC_RESV)
+#define DOC_ECC_DIS (DOC_ECC_RESV)
 
 struct Nand {
        char floor, chip;
@@ -97,15 +106,23 @@ struct Nand {
 #define MAX_FLOORS_MIL 4
 #define MAX_CHIPS_MIL 1
 
+#define ADDR_COLUMN 1
+#define ADDR_PAGE 2
+#define ADDR_COLUMN_PAGE 3
+
 struct DiskOnChip {
        unsigned long physadr;
        unsigned long virtadr;
        unsigned long totlen;
        char ChipID; /* Type of DiskOnChip */
+       int ioreg;
        
        unsigned long mfr; /* Flash IDs - only one type of flash per device */
        unsigned long id;
        int chipshift;
+       char page256;
+       char pageadrlen;
+       unsigned long erasesize;
        
        int curfloor;
        int curchip;
@@ -115,5 +132,6 @@ struct DiskOnChip {
        struct mtd_info *nextdoc;
 };
 
+int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
 
 #endif /* __MTD_DOC2000_H__ */
index ebb41c973a8bd464d21156b563b0c4d47c10729e..7051698000d9319618154fadb72e6aacdcff1a77 100644 (file)
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.5 2000/06/26 16:18:58 dwmw2 Exp $ */
+/* $Id: map.h,v 1.10 2000/12/04 13:18:33 dwmw2 Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
@@ -42,6 +42,8 @@ struct map_info {
        void (*write16)(struct map_info *, __u16, unsigned long);
        void (*write32)(struct map_info *, __u32, unsigned long);
        void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
+
+       void (*set_vpp)(int);
        /* We put these two here rather than a single void *map_priv, 
           because we want mappers to be able to have quickly-accessible
           cache for the 'currently-mapped page' without the _extra_
@@ -54,6 +56,7 @@ struct map_info {
        const char *im_name;
 };
 
+#ifdef CONFIG_MODULES
 /* 
  * Probe for the contents of a map device and make an MTD structure
  * if anything is recognised. Doesn't register it because the calling
@@ -78,6 +81,18 @@ static inline struct mtd_info *do_map_probe(struct map_info *map, const char *fu
 #define do_jedec_probe(x) do_map_probe(x, "jedec_probe", "jedec_probe")
 #define do_ram_probe(x) do_map_probe(x, "map_ram_probe", "map_ram")
 #define do_rom_probe(x) do_map_probe(x, "map_rom_probe", "map_rom")
+#else
+       /* without module support, call probe function directly */
+extern struct mtd_info *cfi_probe(struct map_info *);
+extern struct mtd_info *jedec_probe(struct map_info *);
+extern struct mtd_info *map_ram_probe(struct map_info *);
+extern struct mtd_info *map_rom_probe(struct map_info *);
+
+#define do_cfi_probe(x) cfi_probe(x)
+#define do_jedec_probe(x) jedec_probe(x)
+#define do_ram_probe(x) map_ram_probe(x)
+#define do_rom_probe(x) map_rom_probe(x)
+#endif
 
 /*
  * Destroy an MTD device which was created for a map device.
@@ -92,5 +107,7 @@ static inline void map_destroy(struct mtd_info *mtd)
        kfree(mtd);
 }
 
+#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(1); } while(0)
+#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(0); } while(0)
 
 #endif /* __LINUX_MTD_MAP_H__ */
index a7bc521c21967177106577e425cb6f90ef71188f..708f4f203091b3217a9a643d0f18570afbd1bfa8 100644 (file)
@@ -1,5 +1,5 @@
 
-/* $Id: mtd.h,v 1.17 2000/07/04 07:24:49 jgg Exp $ */
+/* $Id: mtd.h,v 1.26 2000/10/30 17:18:04 sjhill Exp $ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/mtd/compatmac.h>
 #include <linux/module.h>
+#include <linux/uio.h>
 
 #endif /* __KERNEL__ */
 
@@ -61,7 +62,8 @@ struct mtd_oob_buf {
 
 // Types of automatic ECC/Checksum available
 #define MTD_ECC_NONE           0       // No automatic ECC available
-#define MTD_ECC_RS_DiskOnChip   1       // Automatic ECC on DiskOnChip
+#define MTD_ECC_RS_DiskOnChip  1       // Automatic ECC on DiskOnChip
+#define MTD_ECC_SW             2       // SW ECC for Toshiba & Samsung devices
 
 struct mtd_info_user {
        u_char type;
@@ -78,6 +80,8 @@ struct mtd_info_user {
 #define MEMERASE                _IOW('M', 2, struct erase_info_user)
 #define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf)
 #define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
 
 #ifndef __KERNEL__
 
@@ -123,6 +127,7 @@ struct mtd_info {
 
        // Kernel-only stuff starts here.
        char *name;
+       int index;
 
        u_long bank_size;
 
@@ -144,9 +149,22 @@ struct mtd_info {
 
        int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-       
+
+       /* iovec-based read/write methods. We need these especially for NAND flash,
+          with its limited number of write cycles per erase.
+          NB: The 'count' parameter is the number of _vectors_, each of 
+          which contains an (ofs, len) tuple.
+       */
+       int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
+       int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+
+       /* Sync */
        void (*sync) (struct mtd_info *mtd);
 
+       /* Chip-supported device locking */
+       int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
+       int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
+
        /* Power Management functions */
        int (*suspend) (struct mtd_info *mtd);
        void (*resume) (struct mtd_info *mtd);
@@ -198,20 +216,32 @@ extern int unregister_mtd_user (struct mtd_notifier *old);
 #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg)
 #define MTD_READ(mtd, args...) (*(mtd->read))(mtd, args)
 #define MTD_WRITE(mtd, args...) (*(mtd->write))(mtd, args)
+#define MTD_READV(mtd, args...) (*(mtd->readv))(mtd, args)
+#define MTD_WRITEV(mtd, args...) (*(mtd->writev))(mtd, args)
+#define MTD_READECC(mtd, args...) (*(mtd->read_ecc))(mtd, args)
+#define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args)
 #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args)
 #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
 #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd);  } while (0) 
 #endif /* MTDC */
 
-/* Debugging macros */
-
-#ifdef DEBUGLVL
-#define DEBUG(n, args...) if (DEBUGLVL>(n)) printk(KERN_DEBUG args)
-#else
+/*
+ * Debugging macro and defines
+ */
+#define MTD_DEBUG_LEVEL0       (0)     /* Quiet   */
+#define MTD_DEBUG_LEVEL1       (1)     /* Audible */
+#define MTD_DEBUG_LEVEL2       (2)     /* Loud    */
+#define MTD_DEBUG_LEVEL3       (3)     /* Noisy   */
+
+#ifdef CONFIG_MTD_DEBUG
+#define DEBUG(n, args...)                      \
+       if (n <=  CONFIG_MTD_DEBUG_VERBOSE) {   \
+               printk(KERN_INFO args); \
+       }
+#else /* CONFIG_MTD_DEBUG */
 #define DEBUG(n, args...)
-#endif
+#endif /* CONFIG_MTD_DEBUG */
 
 #endif /* __KERNEL__ */
 
-
 #endif /* __MTD_MTD_H__ */
index 79ca1843c176c5e7f88fa62fc46f2e697d015507..8c678ab9761a83183cf18f0893d72904a551b2c9 100644 (file)
+/*
+ *  linux/include/linux/mtd/nand.h
+ *
+ *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
+ *                     Steven J. Hill <sjhill@cotw.com>
+ *
+ * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $
+ *
+ * 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.
+ *
+ *  Info:
+ *   Contains standard defines and IDs for NAND flash devices
+ *
+ *  Changelog:
+ *   01-31-2000 DMW     Created
+ *   09-18-2000 SJH     Moved structure out of the Disk-On-Chip drivers
+ *                     so it can be used by other NAND flash device
+ *                     drivers. I also changed the copyright since none
+ *                     of the original contents of this file are specific
+ *                     to DoC devices. David can whack me with a baseball
+ *                     bat later if I did something naughty.
+ *   10-11-2000 SJH     Added private NAND flash structure for driver
+ *   10-24-2000 SJH     Added prototype for 'nand_scan' function
+ */
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
 
-/* Defines for NAND flash devices           */
-/* (c) 1999 Machine Vision Holdings, Inc.   */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: nand.h,v 1.2 1999/08/17 22:57:08 dwmw2 Exp $ */
+#include <linux/config.h>
+#include <linux/sched.h>
 
-#ifndef __MTD_NAND_H__
-#define __MTD_NAND_H__
-
-#define NAND_CMD_READ0 0
-#define NAND_CMD_READ1 1
-#define NAND_CMD_PAGEPROG 0x10
-#define NAND_CMD_READOOB 0x50
-#define NAND_CMD_ERASE1 0x60
-#define NAND_CMD_STATUS 0x70
-#define NAND_CMD_SEQIN 0x80
-#define NAND_CMD_READID 0x90
-#define NAND_CMD_ERASE2 0xd0
-#define NAND_CMD_RESET 0xff
-
-#define NAND_MFR_TOSHIBA 0x98
-#define NAND_MFR_SAMSUNG 0xec
-
-
-#endif /* __MTD_NAND_H__ */
+/*
+ * Searches for a NAND device
+ */
+extern int nand_scan (struct mtd_info *mtd);
 
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0         0
+#define NAND_CMD_READ1         1
+#define NAND_CMD_PAGEPROG      0x10
+#define NAND_CMD_READOOB       0x50
+#define NAND_CMD_ERASE1                0x60
+#define NAND_CMD_STATUS                0x70
+#define NAND_CMD_SEQIN         0x80
+#define NAND_CMD_READID                0x90
+#define NAND_CMD_ERASE2                0xd0
+#define NAND_CMD_RESET         0xff
 
+/*
+ * Enumeration for NAND flash chip state
+ */
+typedef enum {
+       FL_READY,
+       FL_READING,
+       FL_WRITING,
+       FL_ERASING,
+       FL_SYNCING
+} nand_state_t;
 
+/*
+ * NAND Private Flash Chip Data
+ *
+ * Structure overview:
+ *
+ *  IO_ADDR - address to access the 8 I/O lines to the flash device
+ *
+ *  CTRL_ADDR - address where ALE, CLE and CE control bits are accessed
+ *
+ *  CLE - location in control word for Command Latch Enable bit
+ *
+ *  ALE - location in control word for Address Latch Enable bit
+ *
+ *  NCE - location in control word for nChip Enable bit
+ *
+ *  chip_lock - spinlock used to protect access to this structure
+ *
+ *  wq - wait queue to sleep on if a NAND operation is in progress
+ *
+ *  state - give the current state of the NAND device
+ *
+ *  page_shift - number of address bits in a page (column address bits)
+ *
+ *  data_buf - data buffer passed to/from MTD user modules
+ *
+ *  ecc_code_buf - used only for holding calculated or read ECCs for
+ *                 a page read or written when ECC is in use
+ *
+ *  reserved - padding to make structure fall on word boundary if
+ *             when ECC is in use
+ */
+struct nand_chip {
+       unsigned long IO_ADDR;
+       unsigned long CTRL_ADDR;
+       unsigned int CLE;
+       unsigned int ALE;
+       unsigned int NCE;
+       spinlock_t chip_lock;
+       wait_queue_head_t wq;
+       nand_state_t state;
+       int page_shift;
+       u_char *data_buf;
+#ifdef CONFIG_MTD_NAND_ECC
+       u_char ecc_code_buf[6];
+       u_char reserved[2];
+#endif
+};
 
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_TOSHIBA       0x98
+#define NAND_MFR_SAMSUNG       0xec
 
+/*
+ * NAND Flash Device ID Structure
+ *
+ * Structure overview:
+ *
+ *  name - Complete name of device
+ *
+ *  manufacture_id - manufacturer ID code of device.
+ *
+ *  model_id - model ID code of device.
+ *
+ *  chipshift - total number of address bits for the device which
+ *              is used to calculate address offsets and the total
+ *              number of bytes the device is capable of.
+ *
+ *  page256 - denotes if flash device has 256 byte pages or not.
+ *
+ *  pageadrlen - number of bytes minus one needed to hold the
+ *               complete address into the flash array. Keep in
+ *               mind that when a read or write is done to a
+ *               specific address, the address is input serially
+ *               8 bits at a time. This structure member is used
+ *               by the read/write routines as a loop index for
+ *               shifting the address out 8 bits at a time.
+ *
+ *  erasesize - size of an erase block in the flash device.
+ */
+struct nand_flash_dev {
+       char * name;
+       int manufacture_id;
+       int model_id;
+       int chipshift;
+       char page256;
+       char pageadrlen;
+       unsigned long erasesize;
+};
 
+#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/nand_ids.h b/include/linux/mtd/nand_ids.h
new file mode 100644 (file)
index 0000000..0918b8c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  linux/include/linux/mtd/nand_ids.h
+ *
+ *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
+ *                     Steven J. Hill <sjhill@cotw.com>
+ *
+ * $Id: nand_ids.h,v 1.1 2000/10/13 16:16:26 mdeans Exp $
+ *
+ * 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.
+ *
+ *  Info:
+ *   Contains standard defines and IDs for NAND flash devices
+ *
+ *  Changelog:
+ *   01-31-2000 DMW     Created
+ *   09-18-2000 SJH     Moved structure out of the Disk-On-Chip drivers
+ *                     so it can be used by other NAND flash device
+ *                     drivers. I also changed the copyright since none
+ *                     of the original contents of this file are specific
+ *                     to DoC devices. David can whack me with a baseball
+ *                     bat later if I did something naughty.
+ *   10-11-2000 SJH     Added private NAND flash structure for driver
+ *   2000-10-13 BE      Moved out of 'nand.h' - avoids duplication.
+ */
+
+#ifndef __LINUX_MTD_NAND_IDS_H
+#define __LINUX_MTD_NAND_IDS_H
+
+static struct nand_flash_dev nand_flash_ids[] = {
+       {"Toshiba TC5816BDC",     NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000},
+       {"Toshiba TC5832DC",      NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000},
+       {"Toshiba TH58V128DC",    NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000},
+       {"Toshiba TC58256FT/DC",  NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000},
+       {"Toshiba TH58512FT",     NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000},
+       {"Toshiba TC58V32DC",     NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000},
+       {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000},
+       {"Toshiba TC58V16BDC",    NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000},
+       {"Samsung KM29N16000",    NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000},
+       {"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000},
+       {"Samsung KM29U128T",     NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000},
+       {"Samsung KM29U256T",     NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000},
+       {"Samsung unknown 64Mb",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000},
+       {"Samsung KM29W32000",    NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000},
+       {"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000},
+       {"Samsung KM29U64000",    NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000},
+       {"Samsung KM29W16000",    NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000},
+       {NULL,}
+};
+
+#endif /* __LINUX_MTD_NAND_IDS_H */
index 153fa5c6a76eb6cfce2af7ddc7c27d0d6a2d4b0d..ae00ceb0ba2a70bbc6418dc68e41b413274d2d85 100644 (file)
@@ -2,18 +2,21 @@
 /* Defines for NAND Flash Translation Layer  */
 /* (c) 1999 Machine Vision Holdings, Inc.    */
 /* Author: David Woodhouse <dwmw2@mvhi.com>  */
-/* $Id: nftl.h,v 1.6 2000/03/31 15:12:20 dwmw2 Exp $ */
+/* $Id: nftl.h,v 1.9 2000/11/07 05:48:49 ollie Exp $ */
 
 #ifndef __MTD_NFTL_H__
 #define __MTD_NFTL_H__
 
+#ifndef __BOOT__
 #include <linux/mtd/mtd.h>
+#endif
 
 /* Block Control Information */
 
 struct nftl_bci {
        unsigned char ECCSig[6];
-       __u16 Status;
+       __u8 Status;
+       __u8 Status1;
 }__attribute__((packed));
 
 /* Unit Control Information */
@@ -32,7 +35,8 @@ struct nftl_uci1 {
 } __attribute__((packed));
 
 struct nftl_uci2 {
-       __u32 WriteInh;
+        __u16 FoldMark;
+        __u16 FoldMark1;
        __u32 unused;
 } __attribute__((packed));
 
@@ -60,10 +64,12 @@ struct NFTLMediaHeader {
 #define MAX_ERASE_ZONES (8192 - 512)
 
 #define ERASE_MARK 0x3c69
-#define BLOCK_FREE 0xffff
-#define BLOCK_USED 0x5555
-#define BLOCK_IGNORE 0x1111
-#define BLOCK_DELETED 0x0000
+#define SECTOR_FREE 0xff
+#define SECTOR_USED 0x55
+#define SECTOR_IGNORE 0x11
+#define SECTOR_DELETED 0x00
+
+#define FOLD_MARK_IN_PROGRESS 0x5555
 
 #define ZONE_GOOD 0xff
 #define ZONE_BAD_ORIGINAL 0
@@ -71,6 +77,11 @@ struct NFTLMediaHeader {
 
 #ifdef __KERNEL__
 
+/* these info are used in ReplUnitTable */
+#define BLOCK_NIL          0xffff /* last block of a chain */
+#define BLOCK_FREE         0xfffe /* free block */
+#define BLOCK_NOTEXPLORED  0xfffd /* non explored block, only used during mounting */
+#define BLOCK_RESERVED     0xfffc /* bios block or bad block */
 
 struct NFTLrecord {
        struct mtd_info *mtd;
@@ -83,18 +94,27 @@ struct NFTLrecord {
        unsigned char sectors;
        unsigned short cylinders;
        __u16 numvunits;
-       __u16 lastEUN;
+       __u16 lastEUN;                  /* should be suppressed */
        __u16 numfreeEUNs;
-       __u16 LastFreeEUN; /* To speed up finding a free EUN */
+       __u16 LastFreeEUN;              /* To speed up finding a free EUN */
        __u32 long nr_sects;
        int head,sect,cyl;
-       __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit  */
-       __u16 *VirtualUnitTable; /* [numEUNs]: VirtualUnitNumber for each */
-       __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */
+       __u16 *EUNtable;                /* [numvunits]: First EUN for each virtual unit  */
+       __u16 *ReplUnitTable;           /* [numEUNs]: ReplUnitNumber for each */
+        unsigned int nb_blocks;                /* number of physical blocks */
+        unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
+        struct erase_info instr;
 };
 
+int NFTL_mount(struct NFTLrecord *s);
+int NFTL_formatblock(struct NFTLrecord *s, int block);
+
+#ifndef NFTL_MAJOR
 #define NFTL_MAJOR 93
+#endif
+
 #define MAX_NFTLS 16
+#define MAX_SECTORS_PER_UNIT 32
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
new file mode 100644 (file)
index 0000000..a920238
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * MTD partitioning layer definitions
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * This code is GPL
+ *
+ * $Id: partitions.h,v 1.3 2000/11/10 23:35:12 nico Exp $
+ */
+
+#ifndef MTD_PARTITIONS_H
+#define MTD_PARTITIONS_H
+
+#include <linux/types.h>
+
+
+/*
+ * Partition definition structure:
+ * 
+ * An array of struct partition is passed along with a MTD object to
+ * add_mtd_partitions() to create them.
+ *
+ * For each partition, these fields are available:
+ * name: string that will be used to label the partition's MTD device.
+ * size: the partition size; if 0, the partition will extend to the end of the 
+ *     master MTD device.
+ * offset: absolute starting position within the master MTD device; if 0,
+ *     partition will start where the previous one ended.
+ * mask_flags: contains flags that have to be masked (removed) from the 
+ *     master MTD flag set for the corresponding MTD partition.
+ *     For example, to force a read-only partition, simply adding 
+ *     MTD_WRITEABLE to the mask_flags will do the trick.
+ *
+ * Note: writeable partitions require their size and offset be 
+ * erasesize aligned.
+ */ 
+
+struct mtd_partition {
+       char *name;             /* identifier string */
+       u_long size;            /* partition size */
+       u_long offset;          /* offset within the master MTD space */
+       u_long mask_flags;      /* master MTD flags to mask out for this partition */
+};
+
+
+int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
+int del_mtd_partitions(struct mtd_info *);
+
+#endif
+
index a7330e249407ebc77eef4274f58ecd6bf5ab454b..cc8abab1f95c793ee271c75128e006c93d06504b 100644 (file)
@@ -270,7 +270,7 @@ static inline int
 nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
        if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-               return 0;
+               return NFS_STALE(inode) ? -ESTALE : 0;
        return __nfs_revalidate_inode(server, inode);
 }
 
index 07d821239a4cf188e24ac17a5e3373841f14bc20..8c260c63d5985b8a9045ccc6f14312053133595a 100644 (file)
@@ -165,8 +165,7 @@ struct mdk_rdev_s
        mddev_t *mddev;                 /* RAID array if running */
        unsigned long last_events;      /* IO event timestamp */
 
-       struct inode *inode;            /* Lock inode */
-       struct file filp;               /* Lock file */
+       struct block_device *bdev;      /* block device handle */
 
        mdp_super_t *sb;
        unsigned long sb_offset;
@@ -206,6 +205,7 @@ struct mddev_s
        struct semaphore                reconfig_sem;
        struct semaphore                recovery_sem;
        struct semaphore                resync_sem;
+       atomic_t                        active;
 
        atomic_t                        recovery_active; /* blocks scheduled, but not written */
        md_wait_queue_head_t            recovery_wait;
index aa17b8472ae1920775c19a4868f8cd6314f672a7..a9a9d3e8edb86f6a17337aaf6d67ad8a3c252f28 100644 (file)
@@ -7,7 +7,6 @@ struct mirror_info {
        int             number;
        int             raid_disk;
        kdev_t          dev;
-       int             next;
        int             sect_limit;
        int             head_position;
 
index c67f8c85abf65fd74d49a10eed31791d1723ad82..17e48d0e937e5a9d3f0a3c325499ffb9053d4ea8 100644 (file)
@@ -65,8 +65,7 @@ struct sk_buff {
        struct sk_buff_head * list;             /* List we are on                               */
        struct sock     *sk;                    /* Socket we are owned by                       */
        struct timeval  stamp;                  /* Time we arrived                              */
-       struct net_device       *dev;                   /* Device we arrived on/are leaving by          */
-       struct net_device       *rx_dev;
+       struct net_device       *dev;           /* Device we arrived on/are leaving by          */
 
        /* Transport layer header */
        union
@@ -110,8 +109,7 @@ struct sk_buff {
        unsigned int    len;                    /* Length of actual data                        */
        unsigned int    csum;                   /* Checksum                                     */
        volatile char   used;                   /* Data moved to user and not MSG_PEEK          */
-       unsigned char   is_clone,               /* We are a clone                               */
-                       cloned,                 /* head may be cloned (check refcnt to be sure). */
+       unsigned char   cloned,                 /* head may be cloned (check refcnt to be sure). */
                        pkt_type,               /* Packet class                                 */
                        ip_summed;              /* Driver fed us an IP checksum                 */
        __u32           priority;               /* Packet queueing priority                     */
index 8ba581f5ba38050955fc043f977916b0f19fd291..8bb2d1c5d10dc1771dd2daec1fbf6f98558b62e1 100644 (file)
@@ -65,7 +65,7 @@
 #elif (DEBUG_SPINLOCKS < 2)
 
 typedef struct {
-       volatile unsigned int lock;
+       volatile unsigned long lock;
 } spinlock_t;
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
@@ -80,7 +80,7 @@ typedef struct {
 #else /* (DEBUG_SPINLOCKS >= 2) */
 
 typedef struct {
-       volatile unsigned int lock;
+       volatile unsigned long lock;
        volatile unsigned int babble;
        const char *module;
 } spinlock_t;
index 4b3a82bef1dcd19991cab02537eabdaa992349d2..8550282cbf45b4973e5a49de634ef2dad976b039 100644 (file)
@@ -1169,6 +1169,7 @@ static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        }
 #endif /* CONFIG_FILTER */
 
+       skb->dev = NULL;
        skb_set_owner_r(skb, sk);
        skb_queue_tail(&sk->receive_queue, skb);
        if (!sk->dead)
index 8f4c218f332e47b7a1c95ed3085dd7a1ac342a38..311d66cb85cf93b962670d843262a2704e7fbbfe 100644 (file)
@@ -26,6 +26,13 @@ ifeq ($(CONFIG_PM),y)
 OX_OBJS += pm.o
 endif
 
+ifneq ($(CONFIG_IA64),y)
+# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+# needed for x86 only.  Why this used to be enabled for all architectures is beyond
+# me.  I suspect most platforms don't need this, but until we know that for sure
+# I turn this off for IA-64 only.  Andreas Schwab says it's also needed on m68k
+# to get a correct value for the wait-channel (WCHAN in ps). --davidm
 CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer
+endif
 
 include $(TOPDIR)/Rules.make
index 68f72370946ff8257e475e22d0b2591ed57a5f00..bf3e36cfb797dca9846c36de27eebb29d024c841 100644 (file)
@@ -542,7 +542,7 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
  * arch/ia64/kernel/process.c.
  */
 int do_fork(unsigned long clone_flags, unsigned long stack_start,
-           struct pt_regs *regs, unsigned long stack_top)
+           struct pt_regs *regs, unsigned long stack_size)
 {
        int retval = -ENOMEM;
        struct task_struct *p;
@@ -637,7 +637,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
                goto bad_fork_cleanup_fs;
        if (copy_mm(clone_flags, p))
                goto bad_fork_cleanup_sighand;
-       retval = copy_thread(0, clone_flags, stack_start, stack_top, p, regs);
+       retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
        if (retval)
                goto bad_fork_cleanup_sighand;
        p->semundo = NULL;
index fda0940e07cde99edf3c259e986abeb4e2ed6136..13dad21a06caf129a1172280ccbcacba972a6ccf 100644 (file)
@@ -227,7 +227,7 @@ skip_copy_pte_range:                address = (address + PMD_SIZE) & PMD_MASK;
 
                                /* If it's a COW mapping, write protect it both in the parent and the child */
                                if (cow) {
-                                       ptep_clear_wrprotect(src_pte);
+                                       ptep_set_wrprotect(src_pte);
                                        pte = *src_pte;
                                }
 
@@ -887,45 +887,6 @@ bad_wp_page:
        return -1;
 }
 
-/*
- * This function zeroes out partial mmap'ed pages at truncation time..
- */
-static void partial_clear(struct vm_area_struct *vma, unsigned long address)
-{
-       unsigned int offset;
-       struct page *page;
-       pgd_t *page_dir;
-       pmd_t *page_middle;
-       pte_t *page_table, pte;
-
-       page_dir = pgd_offset(vma->vm_mm, address);
-       if (pgd_none(*page_dir))
-               return;
-       if (pgd_bad(*page_dir)) {
-               pgd_ERROR(*page_dir);
-               pgd_clear(page_dir);
-               return;
-       }
-       page_middle = pmd_offset(page_dir, address);
-       if (pmd_none(*page_middle))
-               return;
-       if (pmd_bad(*page_middle)) {
-               pmd_ERROR(*page_middle);
-               pmd_clear(page_middle);
-               return;
-       }
-       page_table = pte_offset(page_middle, address);
-       pte = *page_table;
-       if (!pte_present(pte))
-               return;
-       flush_cache_page(vma, address);
-       page = pte_page(pte);
-       if ((!VALID_PAGE(page)) || PageReserved(page))
-               return;
-       offset = address & ~PAGE_MASK;
-       memclear_highpage_flush(page, offset, PAGE_SIZE - offset);
-}
-
 static void vmtruncate_list(struct vm_area_struct *mpnt,
                            unsigned long pgoff, unsigned long partial)
 {
@@ -953,10 +914,6 @@ static void vmtruncate_list(struct vm_area_struct *mpnt,
                /* Ok, partially affected.. */
                start += diff << PAGE_SHIFT;
                len = (len - diff) << PAGE_SHIFT;
-               if (start & ~PAGE_MASK) {
-                       partial_clear(mpnt, start);
-                       start = (start + ~PAGE_MASK) & PAGE_MASK;
-               }
                flush_cache_range(mm, start, end);
                zap_page_range(mm, start, len);
                flush_tlb_range(mm, start, end);
index da649f2a240d46d33cab59ce4363b942f5d5b1af..648cc520875de5edd9e41da30d671d35395e7bef 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -354,11 +354,11 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
        lock_vma_mappings(vma);
        spin_lock(&mm->page_table_lock);
        __insert_vm_struct(mm, vma);
+       unlock_vma_mappings(vma);
        if (correct_wcount)
                atomic_inc(&file->f_dentry->d_inode->i_writecount);
        merge_segments(mm, vma->vm_start, vma->vm_end);
        spin_unlock(&mm->page_table_lock);
-       unlock_vma_mappings(vma);
        
        mm->total_vm += len >> PAGE_SHIFT;
        if (flags & VM_LOCKED) {
@@ -858,9 +858,9 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        lock_vma_mappings(vma);
        spin_lock(&mm->page_table_lock);
        __insert_vm_struct(mm, vma);
+       unlock_vma_mappings(vma);
        merge_segments(mm, vma->vm_start, vma->vm_end);
        spin_unlock(&mm->page_table_lock);
-       unlock_vma_mappings(vma);
        
        mm->total_vm += len >> PAGE_SHIFT;
        if (flags & VM_LOCKED) {
@@ -1034,20 +1034,23 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
                        avl_remove(mpnt, &mm->mmap_avl);
                prev->vm_end = mpnt->vm_end;
                prev->vm_next = mpnt->vm_next;
+               mm->map_count--;
                if (mpnt->vm_ops && mpnt->vm_ops->close) {
                        mpnt->vm_pgoff += (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
                        mpnt->vm_start = mpnt->vm_end;
                        spin_unlock(&mm->page_table_lock);
-                       unlock_vma_mappings(mpnt);
                        mpnt->vm_ops->close(mpnt);
-                       lock_vma_mappings(mpnt);
-                       spin_lock(&mm->page_table_lock);
-               }
-               mm->map_count--;
+               } else
+                       spin_unlock(&mm->page_table_lock);
+
+               lock_vma_mappings(mpnt);
                __remove_shared_vm_struct(mpnt);
+               unlock_vma_mappings(mpnt);
                if (mpnt->vm_file)
                        fput(mpnt->vm_file);
                kmem_cache_free(vm_area_cachep, mpnt);
                mpnt = prev;
+
+               spin_lock(&mm->page_table_lock);
        }
 }
index 764cfabb8ea429f2b33b60883312467ef6ba1255..bdbcf4841e589784dcfa4944dd29935b8ff62c17 100644 (file)
@@ -144,9 +144,9 @@ static inline unsigned long move_vma(struct vm_area_struct * vma,
                        lock_vma_mappings(vma);
                        spin_lock(&current->mm->page_table_lock);
                        __insert_vm_struct(current->mm, new_vma);
+                       unlock_vma_mappings(vma);
                        merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
                        spin_unlock(&current->mm->page_table_lock);
-                       unlock_vma_mappings(vma);
                        do_munmap(current->mm, addr, old_len);
                        current->mm->total_vm += new_len >> PAGE_SHIFT;
                        if (new_vma->vm_flags & VM_LOCKED) {
index 4a016d08becd63ae392490c287480b67f8a954c4..e8d3170bef0c7795325144d3ca2f252bd278a3ab 100644 (file)
@@ -220,7 +220,7 @@ static void vc_info(struct atm_vcc *vcc,char *buf)
                default:
                        here += sprintf(here,"%3d",vcc->family);
        }
-       here += sprintf(here," %04x  %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
+       here += sprintf(here," %04x  %5ld %7d/%7d %7d/%7d\n",vcc->flags.bits,
            vcc->reply,
            atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
            atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
index c49ae2ff694caa4632afcc1f73ae5a4a111e6bac..cf4dcf8cd0225b0053a559a3c45ccd7b55c5f87c 100644 (file)
@@ -623,7 +623,7 @@ void netdev_state_change(struct net_device *dev)
 
 void dev_load(const char *name)
 {
-       if (!__dev_get_by_name(name) && capable(CAP_SYS_MODULE))
+       if (!dev_get(name) && capable(CAP_SYS_MODULE))
                request_module(name);
 }
 
@@ -881,8 +881,6 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 
                        skb2->h.raw = skb2->nh.raw;
                        skb2->pkt_type = PACKET_OUTGOING;
-                       skb2->rx_dev = skb->dev;
-                       dev_hold(skb2->rx_dev);
                        ptype->func(skb2, skb->dev, ptype);
                }
        }
@@ -1135,10 +1133,7 @@ int netif_rx(struct sk_buff *skb)
                                goto drop;
 
 enqueue:
-                       if (skb->rx_dev)
-                               dev_put(skb->rx_dev);
-                       skb->rx_dev = skb->dev;
-                       dev_hold(skb->rx_dev);
+                       dev_hold(skb->dev);
                        __skb_queue_tail(&queue->input_pkt_queue,skb);
                        __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
                        local_irq_restore(flags);
@@ -1212,11 +1207,11 @@ static int deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int
  */
 static __inline__ void skb_bond(struct sk_buff *skb)
 {
-       struct net_device *dev = skb->rx_dev;
+       struct net_device *dev = skb->dev;
        
        if (dev->master) {
                dev_hold(dev->master);
-               skb->dev = skb->rx_dev = dev->master;
+               skb->dev = dev->master;
                dev_put(dev);
        }
 }
@@ -1326,6 +1321,7 @@ static void net_rx_action(struct softirq_action *h)
 
        for (;;) {
                struct sk_buff *skb;
+               struct net_device *rx_dev;
 
                local_irq_disable();
                skb = __skb_dequeue(&queue->input_pkt_queue);
@@ -1336,10 +1332,13 @@ static void net_rx_action(struct softirq_action *h)
 
                skb_bond(skb);
 
+               rx_dev = skb->dev;
+
 #ifdef CONFIG_NET_FASTROUTE
                if (skb->pkt_type == PACKET_FASTROUTE) {
                        netdev_rx_stat[this_cpu].fastroute_deferred_out++;
                        dev_queue_xmit(skb);
+                       dev_put(rx_dev);
                        continue;
                }
 #endif
@@ -1375,6 +1374,7 @@ static void net_rx_action(struct softirq_action *h)
                        if (skb->dev->br_port != NULL &&
                            br_handle_frame_hook != NULL) {
                                handle_bridge(skb, pt_prev);
+                               dev_put(rx_dev);
                                continue;
                        }
 #endif
@@ -1405,6 +1405,8 @@ static void net_rx_action(struct softirq_action *h)
                                kfree_skb(skb);
                }
 
+               dev_put(rx_dev);
+
                if (bugdet-- < 0 || jiffies - start_time > 1)
                        goto softnet_break;
 
@@ -2313,6 +2315,12 @@ int register_netdevice(struct net_device *dev)
 #endif
 
        if (dev_boot_phase) {
+#ifdef CONFIG_NET_DIVERT
+               ret = alloc_divert_blk(dev);
+               if (ret)
+                       return ret;
+#endif /* CONFIG_NET_DIVERT */
+               
                /* This is NOT bug, but I am not sure, that all the
                   devices, initialized before netdev module is started
                   are sane. 
@@ -2338,12 +2346,6 @@ int register_netdevice(struct net_device *dev)
                dev_hold(dev);
                write_unlock_bh(&dev_base_lock);
 
-#ifdef CONFIG_NET_DIVERT
-               ret = alloc_divert_blk(dev);
-               if (ret)
-                       return ret;
-#endif /* CONFIG_NET_DIVERT */
-               
                /*
                 *      Default initial state at registry is that the
                 *      device is present.
@@ -2354,6 +2356,12 @@ int register_netdevice(struct net_device *dev)
                return 0;
        }
 
+#ifdef CONFIG_NET_DIVERT
+       ret = alloc_divert_blk(dev);
+       if (ret)
+               return ret;
+#endif /* CONFIG_NET_DIVERT */
+       
        dev->iflink = -1;
 
        /* Init, if this function is available */
@@ -2393,12 +2401,6 @@ int register_netdevice(struct net_device *dev)
        dev->deadbeaf = 0;
        write_unlock_bh(&dev_base_lock);
 
-#ifdef CONFIG_NET_DIVERT
-       ret = alloc_divert_blk(dev);
-       if (ret)
-               return ret;
-#endif /* CONFIG_NET_DIVERT */
-
        /* Notify protocols, that a new device appeared. */
        notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
index 4df7747b87a059640f2a53b0844f50dc45e4d996..0e5b3e671620524655cb5d3e27dbefa6ab43ef27 100644 (file)
@@ -62,7 +62,7 @@ int alloc_divert_blk(struct net_device *dev)
                if (dev->divert == NULL) {
                        printk(KERN_DEBUG "divert: unable to allocate divert_blk for %s\n",
                               dev->name);
-                       return -EFAULT;
+                       return -ENOMEM;
                } else {
                        memset(dev->divert, 0, sizeof(struct divert_blk));
                }
index ca7433f9bf9b5dae685bbe4850d4b6e68fc18502..c5dcecfb358edd4bde502691f0295148ca3d8c47 100644 (file)
@@ -4,7 +4,7 @@
  *     Authors:        Alan Cox <iiitac@pyr.swan.ac.uk>
  *                     Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *     Version:        $Id: skbuff.c,v 1.73 2000/05/22 07:29:44 davem Exp $
+ *     Version:        $Id: skbuff.c,v 1.75 2000/12/08 17:15:53 davem Exp $
  *
  *     Fixes:  
  *             Alan Cox        :       Fixed the worst of the load balancer bugs.
@@ -202,7 +202,6 @@ struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
 
        /* Set up other state */
        skb->len = 0;
-       skb->is_clone = 0;
        skb->cloned = 0;
 
        atomic_set(&skb->users, 1); 
@@ -233,7 +232,6 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache,
        skb->ip_summed = 0;
        skb->security = 0;      /* By default packets are insecure */
        skb->dst = NULL;
-       skb->rx_dev = NULL;
 #ifdef CONFIG_NETFILTER
        skb->nfmark = skb->nfcache = 0;
        skb->nfct = NULL;
@@ -287,10 +285,6 @@ void __kfree_skb(struct sk_buff *skb)
 #ifdef CONFIG_NETFILTER
        nf_conntrack_put(skb->nfct);
 #endif
-#ifdef CONFIG_NET              
-       if(skb->rx_dev)
-               dev_put(skb->rx_dev);
-#endif         
        skb_headerinit(skb, NULL, 0);  /* clean state */
        kfree_skbmem(skb);
 }
@@ -325,12 +319,10 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
        skb->cloned = 1;
        
        dst_clone(n->dst);
-       n->rx_dev = NULL;
        n->cloned = 1;
        n->next = n->prev = NULL;
        n->list = NULL;
        n->sk = NULL;
-       n->is_clone = 1;
        atomic_set(&n->users, 1);
        n->destructor = NULL;
 #ifdef CONFIG_NETFILTER
@@ -349,7 +341,6 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->list=NULL;
        new->sk=NULL;
        new->dev=old->dev;
-       new->rx_dev=NULL;
        new->priority=old->priority;
        new->protocol=old->protocol;
        new->dst=dst_clone(old->dst);
@@ -358,7 +349,6 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->mac.raw=old->mac.raw+offset;
        memcpy(new->cb, old->cb, sizeof(old->cb));
        new->used=old->used;
-       new->is_clone=0;
        atomic_set(&new->users, 1);
        new->pkt_type=old->pkt_type;
        new->stamp=old->stamp;
index 4754cd85012292793d8dd9f77278af21792a4592..361729458ada07c5da6a9d00fedb48690c9c932f 100644 (file)
@@ -78,9 +78,9 @@ extern int decnet_log_martians;
 static void dn_log_martian(struct sk_buff *skb, const char *msg)
 {
        if (decnet_log_martians && net_ratelimit()) {
-               char *devname = skb->rx_dev ? skb->rx_dev->name : "???";
+               char *devname = skb->dev ? skb->dev->name : "???";
                struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
-               printk(KERN_INFO "DECnet: Martian packet (%s) rx_dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port);
+               printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port);
        }
 }
 
@@ -782,7 +782,7 @@ free_out:
 
 int dn_nsp_rx(struct sk_buff *skb)
 {
-       return NF_HOOK(PF_DECnet, NF_DN_LOCAL_IN, skb, skb->rx_dev, NULL, dn_nsp_rx_packet);
+       return NF_HOOK(PF_DECnet, NF_DN_LOCAL_IN, skb, skb->dev, NULL, dn_nsp_rx_packet);
 }
 
 /*
index 20ec07acc922bd51117b77822525e8c12d3ce6fc..70646fc11d2a033c29fb7102b499bee35075ce33 100644 (file)
@@ -526,6 +526,7 @@ static int dn_forward(struct sk_buff *skb)
 {
        struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
        struct dst_entry *dst = skb->dst;
+       struct net_device *dev = skb->dev;
        struct neighbour *neigh;
        int err = -EINVAL;
 
@@ -551,7 +552,7 @@ static int dn_forward(struct sk_buff *skb)
        else
                cb->rt_flags &= ~DN_RT_F_IE;
 
-       return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, skb->rx_dev, skb->dev, neigh->output);
+       return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
 
 
 error:
@@ -985,7 +986,6 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
                }
                skb->protocol = __constant_htons(ETH_P_DNA_RT);
                skb->dev = dev;
-               skb->rx_dev = dev;
                cb->src = src;
                cb->dst = dst;
                local_bh_disable();
@@ -1002,7 +1002,6 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
        if (skb->dev)
                dev_put(skb->dev);
        skb->dev = NULL;
-       skb->rx_dev = NULL;
        if (err)
                goto out_free;
        skb->dst = &rt->u.dst;
index 276f7bd4f0f177ed0b95a736ec56a7536fb76a29..6b980e3f34bc7258a01ea6ccc3267a8b32fcdc9b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     NET3    IP device support routines.
  *
- *     Version: $Id: devinet.c,v 1.38 2000/08/19 23:22:56 davem Exp $
+ *     Version: $Id: devinet.c,v 1.39 2000/12/10 22:24:11 davem Exp $
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
index 121a1ac7a38b414071190106ccdf212198cc672c..7091bf82ca5229bf2ae7bec1aa4802b6e32bf4b1 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP fragmentation functionality.
  *             
- * Version:    $Id: ip_fragment.c,v 1.52 2000/11/28 13:32:54 davem Exp $
+ * Version:    $Id: ip_fragment.c,v 1.53 2000/12/08 17:15:53 davem Exp $
  *
  * Authors:    Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *             Alan Cox <Alan.Cox@linux.org>
@@ -83,7 +83,7 @@ struct ipq {
        atomic_t        refcnt;
        struct timer_list timer;        /* when will this queue expire?         */
        struct ipq      **pprev;
-       struct net_device       *dev;   /* Device - for icmp replies */
+       int             iif;            /* Device index - for icmp replies      */
 };
 
 /* Hash table. */
@@ -255,8 +255,13 @@ static void ip_expire(unsigned long arg)
        IP_INC_STATS_BH(IpReasmFails);
 
        if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
+               struct sk_buff *head = qp->fragments;
+
                /* Send an ICMP "Fragment Reassembly Timeout" message. */
-               icmp_send(qp->fragments, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+               if ((head->dev = dev_get_by_index(qp->iif)) != NULL) {
+                       icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+                       dev_put(head->dev);
+               }
        }
 out:
        spin_unlock(&qp->lock);
@@ -480,7 +485,8 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
        else
                qp->fragments = skb;
 
-       qp->dev = skb->dev;
+       qp->iif = skb->dev->ifindex;
+       skb->dev = NULL;
        qp->meat += skb->len;
        atomic_add(skb->truesize, &ip_frag_mem);
        if (offset == 0)
@@ -499,7 +505,7 @@ err:
  * of bits on input. Until the new skb data handling is in I'm not going
  * to touch this with a bargepole. 
  */
-static struct sk_buff *ip_frag_reasm(struct ipq *qp)
+static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 {
        struct sk_buff *skb;
        struct iphdr *iph;
@@ -546,7 +552,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp)
        skb->dst = dst_clone(head->dst);
        skb->pkt_type = head->pkt_type;
        skb->protocol = head->protocol;
-       skb->dev = qp->dev;
+       skb->dev = dev;
 
        /*
        *  Clearly bogus, because security markings of the individual
@@ -595,6 +601,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
 {
        struct iphdr *iph = skb->nh.iph;
        struct ipq *qp;
+       struct net_device *dev;
        
        IP_INC_STATS_BH(IpReasmReqds);
 
@@ -602,6 +609,8 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
        if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
                ip_evictor();
 
+       dev = skb->dev;
+
        /* Lookup (or create) queue header */
        if ((qp = ip_find(iph)) != NULL) {
                struct sk_buff *ret = NULL;
@@ -612,7 +621,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
 
                if (qp->last_in == (FIRST_IN|LAST_IN) &&
                    qp->meat == qp->len)
-                       ret = ip_frag_reasm(qp);
+                       ret = ip_frag_reasm(qp, dev);
 
                spin_unlock(&qp->lock);
                ipq_put(qp);
index 873030d0a1e4be4475794237d1633229dc6fefd5..be5df4c26d9f49c4d8c4e8e234629c8c850d7f36 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) module.
  *
- * Version:    $Id: ip_input.c,v 1.50 2000/10/24 22:54:26 davem Exp $
+ * Version:    $Id: ip_input.c,v 1.51 2000/12/08 17:15:53 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -225,12 +225,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
        nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
-       /* Free rx_dev before enqueueing to sockets */
-       if (skb->rx_dev) {
-               dev_put(skb->rx_dev);
-               skb->rx_dev = NULL;
-       }
-
         /* Point into the IP datagram, just past the header. */
         skb->h.raw = skb->nh.raw + iph->ihl*4;
 
index 73fd4eaf73d5d49a9b2d103e375bdbb3d3ce72e4..9c8d493b59172c52edcf03cf19738f178f365779 100644 (file)
@@ -400,13 +400,6 @@ static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
        if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
        else pm->outdev_name[0] = '\0';
        pm->hw_protocol = e->skb->protocol;
-       if (e->skb->rx_dev) {
-               pm->hw_type = e->skb->rx_dev->type;
-               if (e->skb->rx_dev->hard_header_parse)
-                       pm->hw_addrlen =
-                               e->skb->rx_dev->hard_header_parse(e->skb,
-                                                                 pm->hw_addr);
-       }
        if (data_len)
                memcpy(pm->payload, e->skb->data, data_len);
        nlh->nlmsg_len = skb->tail - old_tail;
index cb5362dc2a19cecdd1a6fbf73d3d8d72ddf9b343..9449c51286911194dbf5b5386e95fea49b6af1f7 100644 (file)
@@ -50,7 +50,7 @@ static int route_mirror(struct sk_buff *skb)
 
        /* check if the interface we are leaving by is the same as the
            one we arrived on */
-       if (skb->rx_dev == rt->u.dst.dev) {
+       if (skb->dev == rt->u.dst.dev) {
                /* Drop old route. */
                dst_release(skb->dst);
                skb->dst = &rt->u.dst;
index 2cbb20fcfad2d156fa1bdb595180f86c53c68545..c2cc4815bc2a3d937b89ee9ffc00309621e02efa 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.221 2000/11/28 17:04:10 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.222 2000/12/08 17:15:53 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -1649,6 +1649,8 @@ process:
        if (sk->state == TCP_TIME_WAIT)
                goto do_time_wait;
 
+       skb->dev = NULL;
+
        bh_lock_sock(sk);
        ret = 0;
        if (!sk->lock.users) {
index 6c6ae227f53d0b13655c255c66097160e1f79fe2..c4e3f6f1a99ad32e9e117f1db98b7776940bcd42 100644 (file)
@@ -6,7 +6,7 @@
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *     Ian P. Morris           <I.P.Morris@soton.ac.uk>
  *
- *     $Id: ip6_input.c,v 1.17 2000/02/27 19:42:53 davem Exp $
+ *     $Id: ip6_input.c,v 1.18 2000/12/08 17:15:54 davem Exp $
  *
  *     Based in linux/net/ipv4/ip_input.c
  *
@@ -146,11 +146,6 @@ static inline int ip6_input_finish(struct sk_buff *skb)
        }
        len = skb->tail - skb->h.raw;
 
-       if (skb->rx_dev) {
-               dev_put(skb->rx_dev);
-               skb->rx_dev = NULL;
-       }
-
        raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
        if (raw_sk)
                raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
index 75eb9f5594b8ed251b45e7abcd106462715dd69a..0529aa480ef706711a5b6e045d563b3d85741b7f 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: reassembly.c,v 1.20 2000/11/28 13:48:03 davem Exp $
+ *     $Id: reassembly.c,v 1.22 2000/12/08 17:41:54 davem Exp $
  *
  *     Based on: net/ipv4/ip_fragment.c
  *
@@ -78,7 +78,6 @@ struct frag_queue
        struct sk_buff          *fragments;
        int                     len;
        int                     meat;
-       struct net_device       *dev;
        int                     iif;
        __u8                    last_in;        /* has first/last segment arrived? */
 #define COMPLETE               4
@@ -476,8 +475,8 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
        else
                fq->fragments = skb;
 
-       fq->dev = skb->dev;
        fq->iif = skb->dev->ifindex;
+       skb->dev = NULL;
        fq->meat += skb->len;
        atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -507,7 +506,8 @@ err:
  *     queue is eligible for reassembly i.e. it is not COMPLETE,
  *     the last and the first frames arrived and all the bits are here.
  */
-static u8* ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in)
+static u8 *ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
+                         struct net_device *dev)
 {
        struct sk_buff *fp, *head = fq->fragments;
        struct sk_buff *skb;
@@ -541,7 +541,7 @@ static u8* ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in)
 
        skb->mac.raw = skb->data;
        skb->nh.ipv6h = (struct ipv6hdr *) skb->data;
-       skb->dev = fq->dev;
+       skb->dev = dev;
        skb->protocol = __constant_htons(ETH_P_IPV6);
        skb->pkt_type = head->pkt_type;
        FRAG6_CB(skb)->h = FRAG6_CB(head)->h;
@@ -579,6 +579,7 @@ u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr)
 {
        struct sk_buff *skb = *skbp; 
        struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw);
+       struct net_device *dev = skb->dev;
        struct frag_queue *fq;
        struct ipv6hdr *hdr;
 
@@ -616,7 +617,7 @@ u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr)
 
                if (fq->last_in == (FIRST_IN|LAST_IN) &&
                    fq->meat == fq->len)
-                       ret = ip6_frag_reasm(fq, skbp);
+                       ret = ip6_frag_reasm(fq, skbp, dev);
 
                spin_unlock(&fq->lock);
                fq_put(fq);
index b78e56d15c8dbc5e7799efa1eb01fd3170766229..1b068498703860a12589f176c52837241de18916 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.127 2000/11/28 17:04:10 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.128 2000/12/08 17:15:54 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -1576,6 +1576,8 @@ process:
        if(sk->state == TCP_TIME_WAIT)
                goto do_time_wait;
 
+       skb->dev = NULL;
+
        bh_lock_sock(sk);
        ret = 0;
        if (!sk->lock.users) {
index 6b4c77854e2b16536fa04ed9936d67378312e518..576d6400e8c57a15dd809d8689913e36813dc2c9 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             PACKET - implements raw packet sockets.
  *
- * Version:    $Id: af_packet.c,v 1.46 2000/10/24 21:26:19 davem Exp $
+ * Version:    $Id: af_packet.c,v 1.47 2000/12/08 17:15:54 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -264,11 +264,6 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct
        strncpy(spkt->spkt_device, dev->name, sizeof(spkt->spkt_device));
        spkt->spkt_protocol = skb->protocol;
 
-       if (skb->rx_dev) {
-               dev_put(skb->rx_dev);
-               skb->rx_dev = NULL;
-       }
-
        /*
         *      Charge the memory to the socket. This is done specifically
         *      to prevent sockets using all the memory up.
@@ -482,17 +477,13 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,  struct packe
        if (dev->hard_header_parse)
                sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
 
-       if (skb->rx_dev) {
-               dev_put(skb->rx_dev);
-               skb->rx_dev = NULL;
-       }
-
 #ifdef CONFIG_FILTER
        if (skb->len > snaplen)
                __skb_trim(skb, snaplen);
 #endif
 
        skb_set_owner_r(skb, sk);
+       skb->dev = NULL;
        spin_lock(&sk->receive_queue.lock);
        po->stats.tp_packets++;
        __skb_queue_tail(&sk->receive_queue, skb);
index 0242b12e5c5cf0639cea4cafc1763b0721958a0d..8d42109d8819793f8350b1ebdfbf7ef4c3333eca 100644 (file)
@@ -520,6 +520,7 @@ static struct sock *x25_make_new(struct sock *osk)
        sk->state       = TCP_ESTABLISHED;
        sk->sleep       = osk->sleep;
        sk->zapped      = osk->zapped;
+       sk->backlog_rcv = osk->backlog_rcv;
 
        x25->t21        = osk->protinfo.x25->t21;
        x25->t22        = osk->protinfo.x25->t22;
@@ -867,7 +868,7 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
                return -EINVAL;
 
        /* we currently don't support segmented records at the user interface */
-       if (!(msg->msg_flags & MSG_EOR))
+       if (!(msg->msg_flags & (MSG_EOR|MSG_OOB)))
                return -EINVAL;
 
        if (sk->zapped)
index eb4c33cc144f32a9c63e31b612899f1253f4edfb..77dba8e220c6177068bdad67469aa83027b332cc 100644 (file)
@@ -2,10 +2,15 @@
 
 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
 ## Copyright (C) 2000  Tim Waugh <twaugh@redhat.com>             ##
+##                                                              ##
+## #define enhancements by Armin Kuster <akuster@mvista.com>    ## 
+## Copyright (c) 2000 MontaVista Software, Inc.                         ##   
 ##                                                               ##
 ## This software falls under the GNU General Public License.     ##
 ## Please read the COPYING file for more information             ##
 
+# w.o. 03-11-2000: added the '-filelist' option.
+
 #
 # This will read a 'c' file and scan for embedded comments in the
 # style of gnome comments (+minor extensions - see below).
@@ -150,6 +155,8 @@ $output_mode = "man";
 $blankline = $blankline_man;
 $modulename = "API Documentation";
 $function_only = 0;
+$filelist = '';
+
 while ($ARGV[0] =~ m/^-(.*)/) {
     $cmd = shift @ARGV;
     if ($cmd eq "-html") {
@@ -186,6 +193,8 @@ while ($ARGV[0] =~ m/^-(.*)/) {
        $verbose = 1;
     } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
        usage();
+    } elsif ($cmd eq '-filelist') {
+           $filelist = shift @ARGV;
     }
 }
 
@@ -663,8 +672,14 @@ sub dump_function {
     $prototype =~ s/^extern+ //;
     $prototype =~ s/^inline+ //;
     $prototype =~ s/^__inline__+ //;
-
-    if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+    $prototype =~ s/^#define+ //; #ak added
+
+    if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
        $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
        $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
        $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
@@ -781,13 +796,28 @@ $section_default = "Description"; # default section
 $section_intro = "Introduction";
 $section = $section_default;
 
-$lineno = 0;
+if( $filelist ne '' ) {
+       open(FLIST,"<$filelist") or die "Can't open file list $filelist";
+       while(<FLIST>) {
+               chop;
+               process_file($_);
+       }
+}
+
 foreach $file (@ARGV) {
     chomp($file);
+    process_file($file);
+}
+
+sub process_file($) {
+    my ($file) = @_;
+
     if (!open(IN,"<$file")) {
        print STDERR "Error: Cannot open file $file\n";
-       next;
+       return;
     }
+
+    $lineno = 0;
     while (<IN>) {
        $lineno++;
 
@@ -877,7 +907,7 @@ foreach $file (@ARGV) {
            elsif (/([^\{]*)/) {
                $prototype .= $1;
            }
-           if (/\{/) {
+           if (/\{/ || /\#/) { # added for #define AK
                $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
                $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
                $prototype =~ s@^ +@@gos; # strip leading spaces